From a1383cb18611f5b06ac8a86c0338969ee71ccc67 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 5 Dec 2023 14:30:58 -0800 Subject: [PATCH 001/700] 10007: WIP add login form --- web-client/src/presenter/presenter-public.ts | 2 + .../sequences/Public/goToLoginSequence.ts | 5 + web-client/src/routerPublic.ts | 5 + web-client/src/views/AppComponentPublic.tsx | 2 + web-client/src/views/Public/Login/Login.tsx | 113 ++++++++++++++++++ 5 files changed, 127 insertions(+) create mode 100644 web-client/src/presenter/sequences/Public/goToLoginSequence.ts create mode 100644 web-client/src/views/Public/Login/Login.tsx diff --git a/web-client/src/presenter/presenter-public.ts b/web-client/src/presenter/presenter-public.ts index ad98e19dad7..4426c6869ab 100644 --- a/web-client/src/presenter/presenter-public.ts +++ b/web-client/src/presenter/presenter-public.ts @@ -10,6 +10,7 @@ import { closeModalAndNavigateToMaintenanceSequence } from './sequences/closeMod import { confirmSignUpLocalSequence } from '@web-client/presenter/sequences/confirmSignUpLocalSequence'; import { dismissModalSequence } from './sequences/dismissModalSequence'; import { goToCreatePetitionerAccountSequence } from '@web-client/presenter/sequences/Public/goToCreatePetitionerAccountSequence'; +import { goToLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { goToVerificationSentSequence } from '@web-client/presenter/sequences/goToVerificationSentSequence'; import { gotoContactSequence } from './sequences/gotoContactSequence'; import { gotoHealthCheckSequence } from './sequences/gotoHealthCheckSequence'; @@ -67,6 +68,7 @@ export const presenterSequences = { confirmSignUpLocalSequence, dismissModalSequence, goToCreatePetitionerAccountSequence, + goToLoginSequence, goToVerificationSentSequence, gotoContactSequence: showMaintenancePageDecorator(gotoContactSequence), gotoHealthCheckSequence: showMaintenancePageDecorator( diff --git a/web-client/src/presenter/sequences/Public/goToLoginSequence.ts b/web-client/src/presenter/sequences/Public/goToLoginSequence.ts new file mode 100644 index 00000000000..dff8ebe2375 --- /dev/null +++ b/web-client/src/presenter/sequences/Public/goToLoginSequence.ts @@ -0,0 +1,5 @@ +import { setupCurrentPageAction } from '../../actions/setupCurrentPageAction'; + +export const goToLoginSequence = [ + setupCurrentPageAction('Login'), +] as unknown as () => void; diff --git a/web-client/src/routerPublic.ts b/web-client/src/routerPublic.ts index 797694b5aef..4be3551ce8a 100644 --- a/web-client/src/routerPublic.ts +++ b/web-client/src/routerPublic.ts @@ -36,6 +36,11 @@ const router = { app.getSequence('goToCreatePetitionerAccountSequence')(); }); + route('/login', () => { + setPageTitle('Login'); + app.getSequence('goToLoginSequence')(); + }); + route('/create-account/verification-sent', () => { setPageTitle('Verification Sent'); app.getSequence('goToVerificationSentSequence')(); diff --git a/web-client/src/views/AppComponentPublic.tsx b/web-client/src/views/AppComponentPublic.tsx index 487de003ae7..9b95ade1f53 100644 --- a/web-client/src/views/AppComponentPublic.tsx +++ b/web-client/src/views/AppComponentPublic.tsx @@ -9,6 +9,7 @@ import { HeaderPublic } from './Header/HeaderPublic'; import { HealthCheck } from './Health/HealthCheck'; import { Interstitial } from './Interstitial'; import { Loading } from './Loading'; +import { Login } from '@web-client/views/Public/Login/Login'; import { Privacy } from './Privacy'; import { PublicCaseDetail } from './Public/PublicCaseDetail'; import { PublicPrintableDocketRecord } from './Public/PublicPrintableDocketRecord'; @@ -40,6 +41,7 @@ const pages = { const floatingCards = { CreatePetitionerAccount, + Login, VerificationSent, }; diff --git a/web-client/src/views/Public/Login/Login.tsx b/web-client/src/views/Public/Login/Login.tsx new file mode 100644 index 00000000000..00f8ff76f76 --- /dev/null +++ b/web-client/src/views/Public/Login/Login.tsx @@ -0,0 +1,113 @@ +import { Button } from '@web-client/ustc-ui/Button/Button'; +import { connect } from '@cerebral/react'; +import { state } from '@web-client/presenter/app-public.cerebral'; +import React from 'react'; + +export const Login = connect( + { + alertError: state.alertError, + }, + ({ alertError }) => { + return ( + <> +
+ {alertError && ( +
+ {/* */} +
+ )} +
+
+

Log in to DAWSON

+ Email address and password are case sensitive. + +
+ + { + // setInFocusEmail(false); + }} + onChange={e => { + // updateFormValueSequence({ + // key: 'email', + // value: e.target.value, + // }); + }} + // onFocus={() => setInFocusEmail(true)} + /> + + { + // updateFormValueSequence({ + // key: 'password', + // value: e.target.value, + // }); + }} + /> + + +
+ +
+ +
+ +
+ Don't have an account?{' '} + +
+
+
+
+ + ); + }, +); + +Login.displayName = 'Login'; From b6314d82612981fd4cee1e06b56fbf450f3133f3 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 5 Dec 2023 14:51:20 -0800 Subject: [PATCH 002/700] 10007: WIP style login form --- web-client/src/views/Public/Login/Login.tsx | 156 +++++++------------- 1 file changed, 53 insertions(+), 103 deletions(-) diff --git a/web-client/src/views/Public/Login/Login.tsx b/web-client/src/views/Public/Login/Login.tsx index 00f8ff76f76..9cd0351f0e7 100644 --- a/web-client/src/views/Public/Login/Login.tsx +++ b/web-client/src/views/Public/Login/Login.tsx @@ -1,113 +1,63 @@ import { Button } from '@web-client/ustc-ui/Button/Button'; import { connect } from '@cerebral/react'; -import { state } from '@web-client/presenter/app-public.cerebral'; import React from 'react'; -export const Login = connect( - { - alertError: state.alertError, - }, - ({ alertError }) => { - return ( - <> -
- {alertError && ( -
- {/* */} +export const Login = connect({}, () => { + return ( + <> +
+
+
+

Log in to DAWSON

+ Email address and password are case sensitive. +
+ + + + + + +
+
+
- )} -
-
-

Log in to DAWSON

- Email address and password are case sensitive. - -
- - { - // setInFocusEmail(false); - }} - onChange={e => { - // updateFormValueSequence({ - // key: 'email', - // value: e.target.value, - // }); - }} - // onFocus={() => setInFocusEmail(true)} - /> - - { - // updateFormValueSequence({ - // key: 'password', - // value: e.target.value, - // }); - }} - /> - - -
- -
- -
- -
- Don't have an account?{' '} - -
+
+ Don't have an account?{' '} +
- - ); - }, -); +
+ + ); +}); Login.displayName = 'Login'; From 05472f611f7501400c2c997010cd727f49babfc9 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Wed, 6 Dec 2023 11:34:32 -0800 Subject: [PATCH 003/700] 10007: Remove mockCognito, lean on localCognito exclusively. --- .gitignore | 3 +- esbuildHelper.mjs | 1 - package.json | 4 +- run-local.sh | 11 ++- shared/src/sharedAppContext.ts | 4 - web-api/src/applicationContext.ts | 82 ++--------------- web-api/src/getPersistenceGateway.ts | 5 +- web-api/src/persistence/cognito/getCognito.ts | 90 +++++++++++++++++++ .../createOrUpdatePractitionerUser.test.ts | 37 -------- web-client/src/app.tsx | 2 - web-client/src/applicationContext.ts | 2 - web-client/src/views/LogIn.tsx | 55 +++++------- 12 files changed, 128 insertions(+), 168 deletions(-) create mode 100644 web-api/src/persistence/cognito/getCognito.ts diff --git a/.gitignore b/.gitignore index 562bb2f3951..066108260d7 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,5 @@ bulk-import-log.txt metadata.json metadata-public.json stats.html -other/ \ No newline at end of file +other/ +.cognito/db/ \ No newline at end of file diff --git a/esbuildHelper.mjs b/esbuildHelper.mjs index ede564cb12d..5781d5489cb 100644 --- a/esbuildHelper.mjs +++ b/esbuildHelper.mjs @@ -42,7 +42,6 @@ const env = { SESSION_TIMEOUT: process.env.SESSION_TIMEOUT, SKIP_VIRUS_SCAN: process.env.SKIP_VIRUS_SCAN, STAGE: process.env.STAGE, - USE_COGNITO_LOCAL: process.env.USE_COGNITO_LOCAL, USTC_ENV: process.env.USTC_ENV, WS_URL: process.env.WS_URL, }; diff --git a/package.json b/package.json index cccdaae0771..5dff1f6b97f 100644 --- a/package.json +++ b/package.json @@ -198,12 +198,12 @@ "start:api:resume": "RESUME=true npm run start:api", "start:api": "USTC_ENV=dev ./run-local.sh", "start:api:docker": "USTC_ENV=dev ./run-api.sh", - "start:api:cognito-local": "USTC_ENV=dev USE_COGNITO_LOCAL=true ./run-local.sh", + "start:api:cognito-local": "USTC_ENV=dev ./run-local.sh", "start:api:cognito-local:ci": "CI=true npm run start:api:cognito-local", "start:client:ci": "CI=true SKIP_VIRUS_SCAN=true NODE_ENV=production npm run start:client", "start:client:no-scanner": "NO_SCANNER=true npm run start:client", "start:client": "npm run start:client-host && WATCH=true IS_LOCAL=true FILE_UPLOAD_MODAL_TIMEOUT=1 USTC_ENV=dev PDF_EXPRESS_LICENSE_KEY=OjkUB41bl1hJg6jvUEfn npm run start:client:esbuild", - "start:client:cognito-local": "USE_COGNITO_LOCAL=true npm run start:client", + "start:client:cognito-local": "npm run start:client", "start:client-host": "servor dist index.html 1234 &", "start:client:esbuild": "node esbuild.config.mjs", "start:cognito-triggers-local": "cd cognito-triggers-sls && npx sls offline", diff --git a/run-local.sh b/run-local.sh index 7a2051ef9f0..2279d38deec 100755 --- a/run-local.sh +++ b/run-local.sh @@ -49,12 +49,11 @@ else fi fi -if [ -n "${USE_COGNITO_LOCAL}" ]; then - echo "Starting local lambda for cognito triggers" - npm run start:cognito-triggers-local & - echo "Starting cognito-local" - CODE=123456 npx cognito-local & -fi +echo "Starting local lambda for cognito triggers" +npm run start:cognito-triggers-local & +echo "Starting cognito-local" +CODE=123456 npx cognito-local & + nodemon --delay 1 -e js,ts --ignore web-client/ --ignore dist/ --ignore dist-public/ --ignore cypress-integration/ --ignore cypress/helpers/ --ignore cypress-smoketests/ --ignore cypress-readonly --exec "npx ts-node --transpile-only web-api/src/app-local.ts" diff --git a/shared/src/sharedAppContext.ts b/shared/src/sharedAppContext.ts index d14c81e281c..df4f321f515 100644 --- a/shared/src/sharedAppContext.ts +++ b/shared/src/sharedAppContext.ts @@ -28,10 +28,6 @@ export const getUniqueId = (): string => { return uuidv4(); }; -export const getCognitoLocalEnabled = () => { - return !!process.env.USE_COGNITO_LOCAL; -}; - export const clerkOfCourtNameForSigning = 'Stephanie A. Servoss'; export const ERROR_MAP_429 = { diff --git a/web-api/src/applicationContext.ts b/web-api/src/applicationContext.ts index da7dfa5ad60..527fc64084e 100644 --- a/web-api/src/applicationContext.ts +++ b/web-api/src/applicationContext.ts @@ -43,7 +43,6 @@ import { getEnvironment, getUniqueId, } from '../../shared/src/sharedAppContext'; -import { cognitoLocalWrapper } from './cognitoLocalWrapper'; import { createLogger } from './createLogger'; import { documentUrlTranslator } from '../../shared/src/business/utilities/documentUrlTranslator'; import { exec } from 'child_process'; @@ -52,6 +51,10 @@ import { getChromiumBrowser, getChromiumBrowserAWS, } from '../../shared/src/business/utilities/getChromiumBrowser'; +import { + getCognito, + getLocalCognito, +} from '@web-api/persistence/cognito/getCognito'; import { getDocumentGenerators } from './getDocumentGenerators'; import { getPersistenceGateway } from './getPersistenceGateway'; import { getUseCaseHelpers } from './getUseCaseHelpers'; @@ -60,7 +63,6 @@ import { getUtilities } from './getUtilities'; import { isAuthorized } from '../../shared/src/authorization/authorizationClientService'; import { isCurrentColorActive } from './persistence/dynamo/helpers/isCurrentColorActive'; import { retrySendNotificationToConnections } from '../../shared/src/notifications/retrySendNotificationToConnections'; -import { scan } from './persistence/dynamodbClientService'; import { sendBulkTemplatedEmail } from './dispatchers/ses/sendBulkTemplatedEmail'; import { sendEmailEventToQueue } from './persistence/messages/sendEmailEventToQueue'; import { sendNotificationOfSealing } from './dispatchers/sns/sendNotificationOfSealing'; @@ -70,9 +72,8 @@ import { sendSetTrialSessionCalendarEvent } from './persistence/messages/sendSet import { sendSlackNotification } from './dispatchers/slack/sendSlackNotification'; import { sendUpdatePetitionerCasesMessage } from './persistence/messages/sendUpdatePetitionerCasesMessage'; import { updatePetitionerCasesInteractor } from '../../shared/src/business/useCases/users/updatePetitionerCasesInteractor'; -import { v4 as uuidv4 } from 'uuid'; import type { ClientApplicationContext } from '../../web-client/src/applicationContext'; -const { CognitoIdentityServiceProvider, DynamoDB, S3, SES, SQS } = AWS; +const { DynamoDB, S3, SES, SQS } = AWS; const execPromise = util.promisify(exec); const environment = { @@ -229,78 +230,9 @@ export const createApplicationContext = ( }, getCognito: () => { if (environment.stage === 'local') { - if (process.env.USE_COGNITO_LOCAL === 'true') { - return cognitoLocalWrapper( - new CognitoIdentityServiceProvider({ - endpoint: 'http://localhost:9229/', - httpOptions: { - connectTimeout: 3000, - timeout: 5000, - }, - maxRetries: 3, - region: 'local', - }), - ); - } else { - return { - adminCreateUser: () => ({ - promise: () => ({ - User: { - Username: uuidv4(), - }, - }), - }), - adminDisableUser: () => ({ - promise: () => {}, - }), - adminGetUser: ({ Username }) => ({ - promise: async () => { - // TODO: this scan might become REALLY slow while doing a full integration - // test run. - const items = await scan({ - applicationContext: { - environment, - getDocumentClient, - }, - }); - const users = items.filter( - ({ pk, sk }) => - pk.startsWith('user|') && sk.startsWith('user|'), - ); - const foundUser = users.find(({ email }) => email === Username); - if (foundUser) { - return { - UserAttributes: [], - Username: foundUser.userId, - }; - } else { - const error = new Error(); - error.code = 'UserNotFoundException'; - throw error; - } - }, - }), - adminUpdateUserAttributes: () => ({ - promise: () => {}, - }), - listUsers: () => ({ - promise: () => { - throw new Error( - 'Please use cognito locally by running npm run start:api:cognito-local', - ); - }, - }), - }; - } + return getLocalCognito(); } else { - return new CognitoIdentityServiceProvider({ - httpOptions: { - connectTimeout: 3000, - timeout: 5000, - }, - maxRetries: 3, - region: 'us-east-1', - }); + return getCognito(); } }, getConstants: () => ({ diff --git a/web-api/src/getPersistenceGateway.ts b/web-api/src/getPersistenceGateway.ts index 3d16618d486..49e76163eef 100644 --- a/web-api/src/getPersistenceGateway.ts +++ b/web-api/src/getPersistenceGateway.ts @@ -10,7 +10,6 @@ import { caseAdvancedSearch } from './persistence/elasticsearch/caseAdvancedSear import { casePublicSearch as casePublicSearchPersistence } from './persistence/elasticsearch/casePublicSearch'; import { confirmAuthCode } from './persistence/cognito/confirmAuthCode'; import { confirmAuthCodeCognitoLocal } from '@web-api/persistence/cognito/confirmAuthCodeCognitoLocal'; -import { confirmAuthCodeLocal } from './persistence/cognito/confirmAuthCodeLocal'; import { createCase } from './persistence/dynamo/cases/createCase'; import { createCaseDeadline } from './persistence/dynamo/caseDeadlines/createCaseDeadline'; import { createCaseTrialSortMappingRecords } from './persistence/dynamo/cases/createCaseTrialSortMappingRecords'; @@ -276,9 +275,7 @@ const gatewayMethods = { caseAdvancedSearch, casePublicSearch: casePublicSearchPersistence, confirmAuthCode: process.env.IS_LOCAL - ? process.env.USE_COGNITO_LOCAL - ? confirmAuthCodeCognitoLocal - : confirmAuthCodeLocal + ? confirmAuthCodeCognitoLocal : confirmAuthCode, createChangeOfAddressJob, createLock, diff --git a/web-api/src/persistence/cognito/getCognito.ts b/web-api/src/persistence/cognito/getCognito.ts new file mode 100644 index 00000000000..cc0038db634 --- /dev/null +++ b/web-api/src/persistence/cognito/getCognito.ts @@ -0,0 +1,90 @@ +import { CognitoIdentityServiceProvider } from 'aws-sdk'; +import { cognitoLocalWrapper } from '@web-api/cognitoLocalWrapper'; + +let cognitoClientCache: CognitoIdentityServiceProvider; + +export function getCognito() { + if (!cognitoClientCache) { + cognitoClientCache = new CognitoIdentityServiceProvider({ + httpOptions: { + connectTimeout: 3000, + timeout: 5000, + }, + maxRetries: 3, + region: 'us-east-1', + }); + } + return cognitoClientCache; +} + +export function getMockCognito() { + if (!cognitoClientCache) { + cognitoClientCache = { + adminCreateUser: () => ({ + promise: () => ({ + User: { + Username: uuidv4(), + }, + }), + }), + adminDisableUser: () => ({ + promise: () => {}, + }), + adminGetUser: ({ Username }) => ({ + promise: async () => { + // TODO: this scan might become REALLY slow while doing a full integration + // test run. + const items = await scan({ + applicationContext: { + environment, + getDocumentClient, + }, + }); + const users = items.filter( + ({ pk, sk }) => pk.startsWith('user|') && sk.startsWith('user|'), + ); + const foundUser = users.find(({ email }) => email === Username); + if (foundUser) { + return { + UserAttributes: [], + Username: foundUser.userId, + }; + } else { + const error = new Error(); + error.code = 'UserNotFoundException'; + throw error; + } + }, + }), + adminUpdateUserAttributes: () => ({ + promise: () => {}, + }), + listUsers: () => ({ + promise: () => { + throw new Error( + 'Please use cognito locally by running npm run start:api:cognito-local', + ); + }, + }), + }; + } + + return cognitoClientCache; +} + +export function getLocalCognito() { + if (!cognitoClientCache) { + cognitoClientCache = cognitoLocalWrapper( + new CognitoIdentityServiceProvider({ + endpoint: 'http://localhost:9229/', + httpOptions: { + connectTimeout: 3000, + timeout: 5000, + }, + maxRetries: 3, + region: 'local', + }), + ); + } + return cognitoClientCache; +} diff --git a/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.test.ts b/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.test.ts index 108f5657ba8..f8e4481e57d 100644 --- a/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.test.ts +++ b/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.test.ts @@ -318,43 +318,6 @@ describe('createOrUpdatePractitionerUser', () => { }); }); - it('should call adminCreateUser with the correct params when USE_COGNITO_LOCAL is true', async () => { - process.env.USE_COGNITO_LOCAL = 'true'; - process.env.USER_POOL_ID = 'localUserPoolId'; - - // setupNonExistingUserMock(); - - await createOrUpdatePractitionerUser({ - applicationContext, - user: privatePractitionerUser as any, - }); - - expect( - applicationContext.getCognito().adminCreateUser, - ).toHaveBeenCalledWith({ - UserAttributes: [ - { - Name: 'email_verified', - Value: 'True', - }, - { - Name: 'email', - Value: 'test@example.com', - }, - { - Name: 'custom:role', - Value: 'privatePractitioner', - }, - { - Name: 'name', - Value: 'Test Private Practitioner', - }, - ], - UserPoolId: 'localUserPoolId', - Username: 'test@example.com', - }); - }); - describe('createUserRecords', () => { it('attempts to persist a private practitioner user with name and barNumber mapping records', async () => { await createUserRecords({ diff --git a/web-client/src/app.tsx b/web-client/src/app.tsx index ceee7199052..e17b6f782cb 100644 --- a/web-client/src/app.tsx +++ b/web-client/src/app.tsx @@ -146,8 +146,6 @@ const app = { }); presenter.state.cognitoLoginUrl = applicationContext.getCognitoLoginUrl(); presenter.state.constants = applicationContext.getConstants(); - presenter.state.cognitoLocalEnabled = - applicationContext.getCognitoLocalEnabled(); const shouldRefreshToken = !wasAppLoadedFromACognitoLogin(window.location.href) && diff --git a/web-client/src/applicationContext.ts b/web-client/src/applicationContext.ts index 0a2c32b79e7..1e49938f2b7 100644 --- a/web-client/src/applicationContext.ts +++ b/web-client/src/applicationContext.ts @@ -25,7 +25,6 @@ import { import { ERROR_MAP_429, clerkOfCourtNameForSigning, - getCognitoLocalEnabled, getCognitoLoginUrl, getEnvironment, getPublicSiteUrl, @@ -639,7 +638,6 @@ const applicationContext = { getCognitoClientId: () => { return process.env.COGNITO_CLIENT_ID || '6tu6j1stv5ugcut7dqsqdurn8q'; }, - getCognitoLocalEnabled, getCognitoLoginUrl, getCognitoRedirectUrl: () => { return process.env.COGNITO_REDIRECT_URI || 'http://localhost:1234/log-in'; diff --git a/web-client/src/views/LogIn.tsx b/web-client/src/views/LogIn.tsx index 453e91936a9..bc2a3cc1f7f 100644 --- a/web-client/src/views/LogIn.tsx +++ b/web-client/src/views/LogIn.tsx @@ -10,16 +10,12 @@ const Button = getView('Button'); export const LogIn = connect( { - cognitoLocalEnabled: state.cognitoLocalEnabled, form: state.form, - loginWithCodeSequence: sequences.loginWithCodeSequence, loginWithCognitoLocalSequence: sequences.loginWithCognitoLocalSequence, updateFormValueSequence: sequences.updateFormValueSequence, }, function LogIn({ - cognitoLocalEnabled, form, - loginWithCodeSequence, loginWithCognitoLocalSequence, updateFormValueSequence, }) { @@ -33,15 +29,10 @@ export const LogIn = connect( id="log-in" onSubmit={event => { event.preventDefault(); - !cognitoLocalEnabled && - loginWithCodeSequence({ - code: form.email, - }); - cognitoLocalEnabled && - loginWithCognitoLocalSequence({ - code: form.email, - password: form.password, - }); + loginWithCognitoLocalSequence({ + code: form.email, + password: form.password, + }); }} >
@@ -63,27 +54,23 @@ export const LogIn = connect( }); }} /> - {cognitoLocalEnabled && ( - <> - - { - updateFormValueSequence({ - key: e.target.name, - value: e.target.value, - }); - }} - /> - - )} + + { + updateFormValueSequence({ + key: e.target.name, + value: e.target.value, + }); + }} + />
@@ -81,7 +81,7 @@ export const HeaderPublic = connect(
diff --git a/web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx b/web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx index 5452bd24e33..bf426effa42 100644 --- a/web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx +++ b/web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx @@ -9,7 +9,7 @@ export const CreatePetitionerAccountForm = connect( confirmPassword: state.form.confirmPassword, createAccountHelper: state.createAccountHelper, - navigateToCognitoSequence: sequences.navigateToCognitoSequence, + gotoLoginSequence: sequences.gotoLoginSequence, password: state.form.password, showConfirmPassword: state.showConfirmPassword, showPassword: state.showPassword, @@ -21,7 +21,7 @@ export const CreatePetitionerAccountForm = connect( ({ confirmPassword, createAccountHelper, - navigateToCognitoSequence, + gotoLoginSequence, password, showConfirmPassword, showPassword, @@ -259,7 +259,7 @@ export const CreatePetitionerAccountForm = connect( Already have an account?{' '} diff --git a/web-client/src/views/Public/EmailVerificationInstructions.tsx b/web-client/src/views/Public/EmailVerificationInstructions.tsx index c1f6e8cb4f7..3e0636fac58 100644 --- a/web-client/src/views/Public/EmailVerificationInstructions.tsx +++ b/web-client/src/views/Public/EmailVerificationInstructions.tsx @@ -6,9 +6,9 @@ import React from 'react'; export const EmailVerificationInstructions = connect( { - navigateToCognitoSequence: sequences.navigateToCognitoSequence, + gotoLoginSequence: sequences.gotoLoginSequence, }, - function EmailVerificationInstructions({ navigateToCognitoSequence }) { + function EmailVerificationInstructions({ gotoLoginSequence }) { return ( <> @@ -21,7 +21,7 @@ export const EmailVerificationInstructions = connect( Click the Verify Email link from your new email - +
diff --git a/web-client/src/views/Public/EmailVerificationSuccess.tsx b/web-client/src/views/Public/EmailVerificationSuccess.tsx index f502f87887c..a682bf13d63 100644 --- a/web-client/src/views/Public/EmailVerificationSuccess.tsx +++ b/web-client/src/views/Public/EmailVerificationSuccess.tsx @@ -6,16 +6,16 @@ import React from 'react'; export const EmailVerificationSuccess = connect( { - navigateToCognitoSequence: sequences.navigateToCognitoSequence, + gotoLoginSequence: sequences.gotoLoginSequence, }, - function EmailVerificationSuccess({ navigateToCognitoSequence }) { + function EmailVerificationSuccess({ gotoLoginSequence }) { return ( <>

You can now log in with your new email address.

- +
From 143d7526940ce4c9b420c1a9b88d06561cea9243 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Thu, 7 Dec 2023 13:21:49 -0800 Subject: [PATCH 013/700] 10007: Delete actions used to route to hosted cognito login page --- docs/frontend.md | 2 +- .../test/createTestApplicationContext.ts | 2 -- shared/src/sharedAppContext.ts | 11 -------- web-client/src/app.tsx | 5 ++-- web-client/src/appPublic.tsx | 1 - web-client/src/applicationContext.ts | 2 -- web-client/src/applicationContextPublic.ts | 2 -- .../createNewPetitionerUserAction.test.ts | 4 +-- .../actions/createNewPetitionerUserAction.ts | 9 +++---- .../actions/navigateToCognitoAction.test.ts | 25 ------------------- .../actions/navigateToCognitoAction.ts | 13 ---------- web-client/src/presenter/presenter.ts | 2 +- .../sequences/confirmSignUpLocalSequence.ts | 20 +++------------ .../sequences/goToVerificationSentSequence.ts | 4 +-- .../presenter/sequences/signOutSequence.ts | 4 +-- web-client/src/presenter/state-public.ts | 1 - web-client/src/presenter/state.ts | 1 - web-client/src/router.ts | 3 +-- .../createClientTestApplicationContext.ts | 2 -- 19 files changed, 17 insertions(+), 96 deletions(-) delete mode 100644 web-client/src/presenter/actions/navigateToCognitoAction.test.ts delete mode 100644 web-client/src/presenter/actions/navigateToCognitoAction.ts diff --git a/docs/frontend.md b/docs/frontend.md index db6c8d727c8..c95b7e77350 100644 --- a/docs/frontend.md +++ b/docs/frontend.md @@ -126,7 +126,7 @@ export const signOutSequence = [ clearUserAction, clearMaintenanceModeAction, clearLoginFormAction, - navigateToCognitoAction, + gotoLoginSequence, ]; ``` diff --git a/shared/src/business/test/createTestApplicationContext.ts b/shared/src/business/test/createTestApplicationContext.ts index 63e289da446..b307de0458f 100644 --- a/shared/src/business/test/createTestApplicationContext.ts +++ b/shared/src/business/test/createTestApplicationContext.ts @@ -20,7 +20,6 @@ import { import { DocketEntry, getServedPartiesCode } from '../entities/DocketEntry'; import { ERROR_MAP_429, - getCognitoLoginUrl, getCognitoRequestPasswordResetUrl, getPublicSiteUrl, getUniqueId, @@ -609,7 +608,6 @@ export const createTestApplicationContext = ({ }), }), getCognitoClientId: jest.fn(), - getCognitoLoginUrl, getCognitoRedirectUrl: jest.fn(), getCognitoRequestPasswordResetUrl, getCognitoTokenUrl: jest.fn(), diff --git a/shared/src/sharedAppContext.ts b/shared/src/sharedAppContext.ts index 35335894d57..c66a7efed52 100644 --- a/shared/src/sharedAppContext.ts +++ b/shared/src/sharedAppContext.ts @@ -1,16 +1,5 @@ import { v4 as uuidv4 } from 'uuid'; -export const getCognitoLoginUrl = () => { - if (process.env.COGNITO) { - return 'https://auth-dev-flexion-efcms.auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=6tu6j1stv5ugcut7dqsqdurn8q&redirect_uri=http%3A//localhost:1234/log-in'; - } else { - return ( - process.env.COGNITO_LOGIN_URL || - 'http://localhost:1234/mock-login?redirect_uri=http%3A//localhost%3A1234/log-in' - ); - } -}; - export const getCognitoRequestPasswordResetUrl = () => { return process.env.COGNITO_PASSWORD_RESET_REQUEST_URL || '/'; }; diff --git a/web-client/src/app.tsx b/web-client/src/app.tsx index e17b6f782cb..c208f1f3d78 100644 --- a/web-client/src/app.tsx +++ b/web-client/src/app.tsx @@ -144,7 +144,6 @@ const app = { } return value; }); - presenter.state.cognitoLoginUrl = applicationContext.getCognitoLoginUrl(); presenter.state.constants = applicationContext.getConstants(); const shouldRefreshToken = @@ -160,7 +159,7 @@ const app = { presenter.state.token = response.token; applicationContext.setCurrentUserToken(response.token); } catch (err) { - window.location.href = presenter.state.cognitoLoginUrl; + // window.location.href = presenter.state.cognitoLoginUrl; TODO 10007: ROUTE TO LOGIN } const user = await applicationContext @@ -177,7 +176,7 @@ const app = { .getMaintenanceModeInteractor(applicationContext); presenter.state.maintenanceMode = maintenanceMode; } catch (err) { - window.location.href = presenter.state.cognitoLoginUrl; + // window.location.href = presenter.state.cognitoLoginUrl; TODO 10007: redirect to login } } diff --git a/web-client/src/appPublic.tsx b/web-client/src/appPublic.tsx index 38b7c3c89af..1a307216019 100644 --- a/web-client/src/appPublic.tsx +++ b/web-client/src/appPublic.tsx @@ -86,7 +86,6 @@ const appPublic = { ); presenter.providers.applicationContext = applicationContext; - presenter.state.cognitoLoginUrl = applicationContext.getCognitoLoginUrl(); presenter.state.cognitoRequestPasswordResetUrl = applicationContext.getCognitoRequestPasswordResetUrl(); diff --git a/web-client/src/applicationContext.ts b/web-client/src/applicationContext.ts index 62a61b9a5fb..2c72c190313 100644 --- a/web-client/src/applicationContext.ts +++ b/web-client/src/applicationContext.ts @@ -24,7 +24,6 @@ import { } from '../../shared/src/business/entities/DocketEntry'; import { ERROR_MAP_429, - getCognitoLoginUrl, getEnvironment, getPublicSiteUrl, getUniqueId, @@ -637,7 +636,6 @@ const applicationContext = { getCognitoClientId: () => { return process.env.COGNITO_CLIENT_ID || '6tu6j1stv5ugcut7dqsqdurn8q'; }, - getCognitoLoginUrl, getCognitoRedirectUrl: () => { return process.env.COGNITO_REDIRECT_URI || 'http://localhost:1234/log-in'; }, diff --git a/web-client/src/applicationContextPublic.ts b/web-client/src/applicationContextPublic.ts index 734b59c0d3e..e12c62b9bbf 100644 --- a/web-client/src/applicationContextPublic.ts +++ b/web-client/src/applicationContextPublic.ts @@ -38,7 +38,6 @@ import { } from '../../shared/src/business/entities/cases/Case'; import { ERROR_MAP_429, - getCognitoLoginUrl, getCognitoRequestPasswordResetUrl, getEnvironment, getPublicSiteUrl, @@ -165,7 +164,6 @@ const applicationContextPublic = { return process.env.API_URL || 'http://localhost:5000'; }, getCaseTitle: Case.getCaseTitle, - getCognitoLoginUrl, getCognitoRequestPasswordResetUrl, getConstants: () => frozenConstants, getCurrentUser: () => ({}), diff --git a/web-client/src/presenter/actions/createNewPetitionerUserAction.test.ts b/web-client/src/presenter/actions/createNewPetitionerUserAction.test.ts index a4cda23e155..a75fef7891c 100644 --- a/web-client/src/presenter/actions/createNewPetitionerUserAction.test.ts +++ b/web-client/src/presenter/actions/createNewPetitionerUserAction.test.ts @@ -143,7 +143,6 @@ describe('createNewPetitionerUserAction', () => { password: TEST_PASSWORD, }; - const cognitoLoginUrl = 'cognitoLoginUrl'; const cognitoRequestPasswordResetUrl = 'cognitoRequestPasswordResetUrl'; await runAction(createNewPetitionerUserAction, { @@ -151,7 +150,6 @@ describe('createNewPetitionerUserAction', () => { presenter, }, state: { - cognitoLoginUrl, cognitoRequestPasswordResetUrl, form: FORM, }, @@ -174,7 +172,7 @@ describe('createNewPetitionerUserAction', () => { expect(mockErrorPath.mock.calls[0][0]).toEqual({ alertError: { alertType: 'warning', - message: `This email address is already associated with an account. You can log in here. If you forgot your password, you can request a password reset.`, + message: `This email address is already associated with an account. You can log in here. If you forgot your password, you can request a password reset.`, title: 'Email address already has an account', }, }); diff --git a/web-client/src/presenter/actions/createNewPetitionerUserAction.ts b/web-client/src/presenter/actions/createNewPetitionerUserAction.ts index d829b3ecdf1..a00ab01161a 100644 --- a/web-client/src/presenter/actions/createNewPetitionerUserAction.ts +++ b/web-client/src/presenter/actions/createNewPetitionerUserAction.ts @@ -14,7 +14,6 @@ export const createNewPetitionerUserAction = async ({ get(state.form), ).toRawObject(); - const cognitoLoginUrl = get(state.cognitoLoginUrl); const cognitoRequestPasswordResetUrl = get( state.cognitoRequestPasswordResetUrl, ); @@ -27,9 +26,7 @@ export const createNewPetitionerUserAction = async ({ .then(authenticationResults => responseHandler(authenticationResults, petitionerAccountForm.email), ) - .catch(e => - errorHandler(e, cognitoLoginUrl, cognitoRequestPasswordResetUrl), - ); + .catch(e => errorHandler(e, cognitoRequestPasswordResetUrl)); if (response.alertError) { return path.error(response); @@ -37,13 +34,13 @@ export const createNewPetitionerUserAction = async ({ return path.success(response); }; -const errorHandler = (e, cognitoLoginUrl, cognitoRequestPasswordResetUrl) => { +const errorHandler = (e, cognitoRequestPasswordResetUrl) => { const originalErrorMessage = e?.originalError?.response?.data; if (originalErrorMessage === 'User already exists') { return { alertError: { alertType: 'warning', - message: `This email address is already associated with an account. You can log in here. If you forgot your password, you can request a password reset.`, + message: `This email address is already associated with an account. You can log in here. If you forgot your password, you can request a password reset.`, title: 'Email address already has an account', }, }; diff --git a/web-client/src/presenter/actions/navigateToCognitoAction.test.ts b/web-client/src/presenter/actions/navigateToCognitoAction.test.ts deleted file mode 100644 index 1ee6d3577dc..00000000000 --- a/web-client/src/presenter/actions/navigateToCognitoAction.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { navigateToCognitoAction } from './navigateToCognitoAction'; -import { presenter } from '../presenter-mock'; -import { runAction } from '@web-client/presenter/test.cerebral'; - -describe('navigateToCognitoAction', () => { - let externalRouteMock; - - beforeAll(() => { - externalRouteMock = jest.fn(); - presenter.providers.router = { - externalRoute: externalRouteMock, - }; - }); - - it('should call the router to navigate to the cognito url from state', async () => { - await runAction(navigateToCognitoAction, { - modules: { - presenter, - }, - state: { cognitoLoginUrl: 'http://example.com' }, - }); - - expect(externalRouteMock).toHaveBeenCalledWith('http://example.com'); - }); -}); diff --git a/web-client/src/presenter/actions/navigateToCognitoAction.ts b/web-client/src/presenter/actions/navigateToCognitoAction.ts deleted file mode 100644 index 08edc5d6eb3..00000000000 --- a/web-client/src/presenter/actions/navigateToCognitoAction.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { state } from '@web-client/presenter/app.cerebral'; - -/** - * changes the route to view the cognito url from state - * @param {object} providers the providers object - * @param {object} providers.router the riot.router object that is used for changing the route - * @param {object} providers.get the cerebral get method - * @returns {Promise} async action - */ -export const navigateToCognitoAction = async ({ get, router }: ActionProps) => { - const path = get(state.cognitoLoginUrl); - await router.externalRoute(path); -}; diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 81aa0328dc9..9274b666bf6 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -166,7 +166,7 @@ import { gotoFileDocumentSequence } from './sequences/gotoFileDocumentSequence'; import { gotoFilePetitionSuccessSequence } from './sequences/gotoFilePetitionSuccessSequence'; import { gotoIdleLogoutSequence } from './sequences/gotoIdleLogoutSequence'; import { gotoJudgeActivityReportSequence } from './sequences/JudgeActivityReport/gotoJudgeActivityReportSequence'; -import { gotoLoginSequence } from './sequences/gotoLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { gotoMaintenanceSequence } from './sequences/gotoMaintenanceSequence'; import { gotoMessageDetailSequence } from './sequences/gotoMessageDetailSequence'; import { gotoMessagesSequence } from './sequences/gotoMessagesSequence'; diff --git a/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts b/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts index ba449d84851..f22a66d3740 100644 --- a/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts +++ b/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts @@ -1,25 +1,13 @@ import { confirmSignUpLocalAction } from '../actions/confirmSignUpLocalAction'; -import { navigateToCognitoAction } from '@web-client/presenter/actions/navigateToCognitoAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { setAlertErrorAction } from '../actions/setAlertErrorAction'; import { setAlertSuccessAction } from '../actions/setAlertSuccessAction'; -import { setSaveAlertsForNavigationAction } from '../actions/setSaveAlertsForNavigationAction'; -import { sleep } from '@shared/tools/helpers'; export const confirmSignUpLocalSequence = [ confirmSignUpLocalAction, { - no: [ - setAlertErrorAction, - setSaveAlertsForNavigationAction, - navigateToCognitoAction, - ], - yes: [ - setAlertSuccessAction, - setSaveAlertsForNavigationAction, - async () => { - await sleep(3000); - }, - navigateToCognitoAction, - ], + no: [setAlertErrorAction], + yes: [setAlertSuccessAction], }, + gotoLoginSequence, ]; diff --git a/web-client/src/presenter/sequences/goToVerificationSentSequence.ts b/web-client/src/presenter/sequences/goToVerificationSentSequence.ts index d369d78fabe..1fe0d7bfac8 100644 --- a/web-client/src/presenter/sequences/goToVerificationSentSequence.ts +++ b/web-client/src/presenter/sequences/goToVerificationSentSequence.ts @@ -1,11 +1,11 @@ import { checkIfCognitoEmailInState } from '@web-client/presenter/actions/checkIfCognitoEmailInState'; -import { navigateToCognitoAction } from '@web-client/presenter/actions/navigateToCognitoAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { setupCurrentPageAction } from '@web-client/presenter/actions/setupCurrentPageAction'; export const goToVerificationSentSequence = [ checkIfCognitoEmailInState, { - doesNotExist: [navigateToCognitoAction], + doesNotExist: [gotoLoginSequence], exists: [setupCurrentPageAction('VerificationSent')], }, ]; diff --git a/web-client/src/presenter/sequences/signOutSequence.ts b/web-client/src/presenter/sequences/signOutSequence.ts index e5067eae1ac..016939203c6 100644 --- a/web-client/src/presenter/sequences/signOutSequence.ts +++ b/web-client/src/presenter/sequences/signOutSequence.ts @@ -4,7 +4,7 @@ import { clearLoginFormAction } from '../actions/clearLoginFormAction'; import { clearMaintenanceModeAction } from '../actions/clearMaintenanceModeAction'; import { clearUserAction } from '../actions/clearUserAction'; import { deleteAuthCookieAction } from '../actions/deleteAuthCookieAction'; -import { navigateToCognitoAction } from '../actions/navigateToCognitoAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { stopWebSocketConnectionAction } from '../actions/WebSocketConnection/stopWebSocketConnectionAction'; @@ -17,5 +17,5 @@ export const signOutSequence = [ clearUserAction, clearMaintenanceModeAction, clearLoginFormAction, - navigateToCognitoAction, + gotoLoginSequence, ]; diff --git a/web-client/src/presenter/state-public.ts b/web-client/src/presenter/state-public.ts index a8b2dcecb1c..950f0a38c61 100644 --- a/web-client/src/presenter/state-public.ts +++ b/web-client/src/presenter/state-public.ts @@ -36,7 +36,6 @@ export const baseState = { alertSuccess: null, caseDetail: {} as RawPublicCase, cognito: { email: '' }, - cognitoLoginUrl: '', cognitoRequestPasswordResetUrl: '', cognitoResendVerificationLinkUrl: '', commonUI: { diff --git a/web-client/src/presenter/state.ts b/web-client/src/presenter/state.ts index 30a1ce38825..4c9cd3a3fa9 100644 --- a/web-client/src/presenter/state.ts +++ b/web-client/src/presenter/state.ts @@ -553,7 +553,6 @@ export const baseState = { clientConnectionId: '', closedCases: [] as TAssociatedCase[], cognito: {} as any, - cognitoLoginUrl: null, completeForm: {}, constants: {} as ReturnType, currentJudges: [], diff --git a/web-client/src/router.ts b/web-client/src/router.ts index 20b06a3b585..cb025e2c5e0 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -69,8 +69,7 @@ const gotoMaintenancePage = app => { }); }; const gotoLoginPage = app => { - const path = app.getState('cognitoLoginUrl'); - externalRoute(path); + return app.getSequence('gotoLoginSequence')(); }; const goto404 = app => { return app.getSequence('navigateToPathSequence')({ diff --git a/web-client/src/test/createClientTestApplicationContext.ts b/web-client/src/test/createClientTestApplicationContext.ts index 55138ffc440..dfc78bee7b4 100644 --- a/web-client/src/test/createClientTestApplicationContext.ts +++ b/web-client/src/test/createClientTestApplicationContext.ts @@ -22,7 +22,6 @@ import { } from '@shared/business/entities/DocketEntry'; import { ERROR_MAP_429, - getCognitoLoginUrl, getCognitoRequestPasswordResetUrl, getPublicSiteUrl, getUniqueId, @@ -567,7 +566,6 @@ const createTestApplicationContext = () => { }), }), getCognitoClientId: jest.fn(), - getCognitoLoginUrl, getCognitoRedirectUrl: jest.fn(), getCognitoRequestPasswordResetUrl, getCognitoTokenUrl: jest.fn(), From 4e7306466740db59f748101be11e6df54bc326a0 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Thu, 7 Dec 2023 13:34:08 -0800 Subject: [PATCH 014/700] 10007: Replace redirectToCognito with gotoLoginSequence --- .../actions/redirectToCognitoAction.test.ts | 25 ------------------- .../actions/redirectToCognitoAction.ts | 5 ---- .../gotoJudgeActivityReportSequence.ts | 4 +-- .../gotoAddCourtIssuedDocketEntrySequence.ts | 4 +-- .../gotoAddDeficiencyStatisticsSequence.ts | 4 +-- .../gotoAddOtherStatisticsSequence.ts | 4 +-- .../sequences/gotoAddPaperFilingSequence.ts | 4 +-- .../gotoAddPetitionerToCaseSequence.ts | 4 +-- .../sequences/gotoAddTrialSessionSequence.ts | 4 +-- .../sequences/gotoApplyStampSequence.ts | 4 +-- .../gotoBeforeYouFileDocumentSequence.ts | 4 +-- .../gotoBlockedCasesReportSequence.ts | 4 +-- .../gotoCaseDeadlineReportSequence.ts | 4 +-- .../gotoCaseInventoryReportSequence.ts | 4 +-- .../sequences/gotoContactEditSequence.ts | 4 +-- .../sequences/gotoCreateOrderSequence.ts | 4 +-- .../sequences/gotoCustomCaseReportSequence.ts | 4 +-- .../sequences/gotoDashboardSequence.ts | 4 +-- .../sequences/gotoDocketEntryQcSequence.ts | 4 +-- .../gotoEditCorrespondenceDocumentSequence.ts | 4 +-- .../gotoEditCourtIssuedDocketEntrySequence.ts | 4 +-- .../gotoEditDeficiencyStatisticSequence.ts | 4 +-- .../gotoEditDocketEntryMetaSequence.ts | 4 +-- .../sequences/gotoEditOrderSequence.ts | 4 +-- .../gotoEditOtherStatisticsSequence.ts | 4 +-- .../sequences/gotoEditPaperFilingSequence.ts | 4 +-- .../sequences/gotoEditTrialSessionSequence.ts | 4 +-- ...toEditUploadCourtIssuedDocumentSequence.ts | 4 +-- .../sequences/gotoFileDocumentSequence.ts | 4 +-- .../sequences/gotoMessageDetailSequence.ts | 4 +-- .../sequences/gotoMessagesSequence.ts | 4 +-- .../sequences/gotoPendingReportSequence.ts | 4 +-- .../gotoPractitionerAddDocumentSequence.ts | 4 +-- .../gotoPractitionerDetailSequence.ts | 4 +-- .../gotoPractitionerDocumentationSequence.ts | 4 +-- .../gotoPractitionerEditDocumentSequence.ts | 4 +-- .../sequences/gotoRequestAccessSequence.ts | 4 +-- .../gotoTrialSessionDetailSequence.ts | 4 +-- .../gotoTrialSessionPlanningReportSequence.ts | 4 +-- .../gotoTrialSessionWorkingCopySequence.ts | 4 +-- .../sequences/gotoTrialSessionsSequence.ts | 4 +-- ...otoUploadCorrespondenceDocumentSequence.ts | 4 +-- .../gotoUploadCourtIssuedDocumentSequence.ts | 4 +-- .../sequences/gotoWorkQueueSequence.ts | 4 +-- .../sequences/redirectToLoginSequence.ts | 4 +-- .../sequences/unauthorizedErrorSequence.ts | 4 +-- .../unidentifiedUserErrorSequence.ts | 4 +-- 47 files changed, 90 insertions(+), 120 deletions(-) delete mode 100644 web-client/src/presenter/actions/redirectToCognitoAction.test.ts delete mode 100644 web-client/src/presenter/actions/redirectToCognitoAction.ts diff --git a/web-client/src/presenter/actions/redirectToCognitoAction.test.ts b/web-client/src/presenter/actions/redirectToCognitoAction.test.ts deleted file mode 100644 index 01109cfb182..00000000000 --- a/web-client/src/presenter/actions/redirectToCognitoAction.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; -import { presenter } from '../presenter-mock'; -import { redirectToCognitoAction } from './redirectToCognitoAction'; -import { runAction } from '@web-client/presenter/test.cerebral'; - -describe('redirectToCognitoAction', () => { - const externalRoute = jest.fn(); - - beforeAll(() => { - presenter.providers.applicationContext = applicationContext; - presenter.providers.router = { externalRoute }; - }); - - it('should redirect the app to the cognito url', async () => { - await runAction(redirectToCognitoAction, { - modules: { - presenter, - }, - state: { - cognitoLoginUrl: 'http://example.com', - }, - }); - expect(externalRoute.mock.calls[0][0]).toEqual('http://example.com'); - }); -}); diff --git a/web-client/src/presenter/actions/redirectToCognitoAction.ts b/web-client/src/presenter/actions/redirectToCognitoAction.ts deleted file mode 100644 index b0ff9a07d53..00000000000 --- a/web-client/src/presenter/actions/redirectToCognitoAction.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { state } from '@web-client/presenter/app.cerebral'; - -export const redirectToCognitoAction = ({ get, router }: ActionProps) => { - router.externalRoute(get(state.cognitoLoginUrl)); -}; diff --git a/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts b/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts index b17e8f26cf9..f8d96d02836 100644 --- a/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts +++ b/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts @@ -2,8 +2,8 @@ import { clearErrorAlertsAction } from '../../actions/clearErrorAlertsAction'; import { clearScreenMetadataAction } from '../../actions/clearScreenMetadataAction'; import { closeMobileMenuAction } from '../../actions/closeMobileMenuAction'; import { getUsersInSectionAction } from '../../actions/getUsersInSectionAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../../actions/redirectToCognitoAction'; import { resetJudgeActivityReportStateAction } from '../../actions/resetJudgeActivityReportStateAction'; import { setAllAndCurrentJudgesAction } from '../../actions/setAllAndCurrentJudgesAction'; import { setJudgeLastNameOnJudgeActivityReportAction } from '../../actions/JudgeActivityReport/setJudgeLastNameOnJudgeActivityReportAction'; @@ -30,6 +30,6 @@ export const gotoJudgeActivityReportSequence = [ isLoggedIn: startWebSocketConnectionSequenceDecorator( gotoJudgeActivityReport, ), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts b/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts index 92e9e115864..05dc48e1c58 100644 --- a/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts +++ b/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts @@ -3,8 +3,8 @@ import { generateCourtIssuedDocumentTitleAction } from '../actions/CourtIssuedDo import { getCaseAction } from '../actions/getCaseAction'; import { getFilterCurrentJudgeUsersAction } from '../actions/getFilterCurrentJudgeUsersAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setCourtIssuedDocumentInitialDataAction } from '../actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction'; import { setDefaultServiceStampAction } from '../actions/CourtIssuedDocketEntry/setDefaultServiceStampAction'; @@ -36,6 +36,6 @@ export const gotoAddCourtIssuedDocketEntrySequence = [ setIsEditingDocketEntryAction(false), setupCurrentPageAction('CourtIssuedDocketEntry'), ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts b/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts index 03ac2d0b587..ffab2ace071 100644 --- a/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts @@ -1,8 +1,8 @@ import { clearConfirmationTextAction } from '../actions/clearConfirmationTextAction'; import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultFormForAddDeficiencyStatisticsAction } from '../actions/setDefaultFormForAddDeficiencyStatisticsAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -22,6 +22,6 @@ export const gotoAddDeficiencyStatisticsSequence = [ setDefaultFormForAddDeficiencyStatisticsAction, setupCurrentPageAction('AddDeficiencyStatistics'), ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts b/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts index 59b1c6d3c71..83f64434c1b 100644 --- a/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -18,6 +18,6 @@ export const gotoAddOtherStatisticsSequence = [ setCaseAction, setupCurrentPageAction('AddOtherStatistics'), ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts b/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts index 75f41bd050f..cad59c761a8 100644 --- a/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts @@ -2,8 +2,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { resetAddPaperFilingAction } from '../actions/resetAddPaperFilingAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -28,6 +28,6 @@ export const gotoAddPaperFilingSequence = [ isLoggedInAction, { isLoggedIn: startWebSocketConnectionSequenceDecorator(gotoAddPaperFiling), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts b/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts index fa740a656af..ec73f73d814 100644 --- a/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultAddPetitionerToCaseFormAction } from '../actions/setDefaultAddPetitionerToCaseFormAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -20,6 +20,6 @@ export const gotoAddPetitionerToCaseSequence = [ setDefaultAddPetitionerToCaseFormAction, setupCurrentPageAction('AddPetitionerToCase'), ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts b/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts index 77dda8e99c1..a781fcdaf33 100644 --- a/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts @@ -3,9 +3,9 @@ import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction' import { getSetJudgesSequence } from './getSetJudgesSequence'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { parallel } from 'cerebral/factories'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setDefaultTrialSessionFormValuesAction } from '../actions/setDefaultTrialSessionFormValuesAction'; import { setTrialSessionsAction } from '../actions/TrialSession/setTrialSessionsAction'; import { setUsersByKeyAction } from '../actions/setUsersByKeyAction'; @@ -34,6 +34,6 @@ export const gotoAddTrialSessionSequence = [ isLoggedInAction, { isLoggedIn: startWebSocketConnectionSequenceDecorator(gotoAddTrialSession), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoApplyStampSequence.ts b/web-client/src/presenter/sequences/gotoApplyStampSequence.ts index 3b389fc5dbc..b23c9737e15 100644 --- a/web-client/src/presenter/sequences/gotoApplyStampSequence.ts +++ b/web-client/src/presenter/sequences/gotoApplyStampSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearPDFStampDataAction } from '../actions/StampMotion/clearPDFStampDataAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; import { setDocketEntrySelectedFromMessageAction } from '../actions/setDocketEntrySelectedFromMessageAction'; @@ -28,6 +28,6 @@ export const goToApplyStampSequence = [ setPDFPageForSigningAction, setupCurrentPageAction('ApplyStamp'), ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts b/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts index 1c18609a2da..5852fa66fa4 100644 --- a/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts @@ -1,6 +1,6 @@ import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -18,6 +18,6 @@ export const gotoBeforeYouFileDocumentSequence = [ isLoggedInAction, { isLoggedIn: gotoBeforeYouFileDocument, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts b/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts index ef6ab86092f..c38128478dd 100644 --- a/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts @@ -2,8 +2,8 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -20,6 +20,6 @@ export const gotoBlockedCasesReportSequence = [ isLoggedInAction, { isLoggedIn: [gotoBlockedCasesReport], - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts b/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts index a570e23303a..c83b5a4f204 100644 --- a/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts @@ -4,9 +4,9 @@ import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction' import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { getCaseDeadlinesAction } from '../actions/CaseDeadline/getCaseDeadlinesAction'; import { getSetJudgesSequence } from './getSetJudgesSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { parallel } from 'cerebral/factories'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseDeadlinesAction } from '../actions/CaseDeadline/setCaseDeadlinesAction'; import { setDefaultCaseDeadlinesReportDatesAction } from '../actions/CaseDeadline/setDefaultCaseDeadlinesReportDatesAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -35,6 +35,6 @@ export const gotoCaseDeadlineReportSequence = [ isLoggedInAction, { isLoggedIn: gotoCaseDeadlineReport, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts b/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts index 0c111d927bd..6bb9ac16d05 100644 --- a/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts @@ -2,12 +2,12 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { fetchUserNotificationsSequence } from './fetchUserNotificationsSequence'; import { getSetJudgesSequence } from './getSetJudgesSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { hasCaseInventoryReportFilterSelectedAction } from '../actions/CaseInventoryReport/hasCaseInventoryReportFilterSelectedAction'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToDashboardAction } from '../actions/navigateToDashboardAction'; import { openCaseInventoryReportModalSequence } from './openCaseInventoryReportModalSequence'; import { parallel } from 'cerebral/factories'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -37,6 +37,6 @@ export const gotoCaseInventoryReportSequence = [ ]), }, ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoContactEditSequence.ts b/web-client/src/presenter/sequences/gotoContactEditSequence.ts index 5f61b3826a2..214dfece603 100644 --- a/web-client/src/presenter/sequences/gotoContactEditSequence.ts +++ b/web-client/src/presenter/sequences/gotoContactEditSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setupContactFormAction } from '../actions/setupContactFormAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -22,6 +22,6 @@ export const gotoContactEditSequence = [ isLoggedInAction, { isLoggedIn: gotoContactEdit, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts b/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts index 2e36b8513fb..31b7281b39c 100644 --- a/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts +++ b/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts @@ -1,11 +1,11 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearModalAction } from '../actions/clearModalAction'; import { convertHtml2PdfSequence } from './convertHtml2PdfSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { hasOrderTypeSelectedAction } from '../actions/CourtIssuedOrder/hasOrderTypeSelectedAction'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToCaseDetailAction } from '../actions/navigateToCaseDetailAction'; import { openCreateOrderChooseTypeModalSequence } from './openCreateOrderChooseTypeModalSequence'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCreateOrderModalDataOnFormAction } from '../actions/CourtIssuedOrder/setCreateOrderModalDataOnFormAction'; import { setIsCreatingOrderAction } from '../actions/setIsCreatingOrderAction'; import { setRedirectUrlAction } from '../actions/setRedirectUrlAction'; @@ -40,6 +40,6 @@ export const gotoCreateOrderSequence = [ ], }, ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts b/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts index e87a7088084..aa7b9f5ccad 100644 --- a/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts @@ -1,6 +1,6 @@ import { getSetJudgesSequence } from './getSetJudgesSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { resetCustomCaseReportStateAction } from '../actions/resetCustomCaseReportStateAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -16,6 +16,6 @@ export const gotoCustomCaseReportSequence = [ isLoggedInAction, { isLoggedIn: [gotoCustomCaseReport], - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoDashboardSequence.ts b/web-client/src/presenter/sequences/gotoDashboardSequence.ts index 5e494055582..dd3150136d1 100644 --- a/web-client/src/presenter/sequences/gotoDashboardSequence.ts +++ b/web-client/src/presenter/sequences/gotoDashboardSequence.ts @@ -9,13 +9,13 @@ import { getMaintenanceModeAction } from '../actions/getMaintenanceModeAction'; import { getOpenAndClosedCasesForUserAction } from '../actions/Dashboard/getOpenAndClosedCasesForUserAction'; import { getSubmittedAndCavCasesForCurrentJudgeAction } from '@web-client/presenter/actions/CaseWorksheet/getSubmittedAndCavCasesForCurrentJudgeAction'; import { getTrialSessionsForJudgeAction } from '../actions/TrialSession/getTrialSessionsForJudgeAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { gotoMaintenanceSequence } from './gotoMaintenanceSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToMessagesAction } from '../actions/navigateToMessagesAction'; import { navigateToSectionDocumentQCAction } from '../actions/navigateToSectionDocumentQCAction'; import { parallel } from 'cerebral'; import { passAlongJudgeUserAction } from '@web-client/presenter/actions/passAlongJudgeUserAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { runPathForUserRoleAction } from '../actions/runPathForUserRoleAction'; import { setCasesAction } from '../actions/setCasesAction'; import { setDefaultCaseTypeToDisplayAction } from '../actions/setDefaultCaseTypeToDisplayAction'; @@ -132,6 +132,6 @@ export const gotoDashboardSequence = [ isLoggedInAction, { isLoggedIn: [goToDashboard], - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts b/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts index 9b470a8d7de..445e72a18a2 100644 --- a/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts +++ b/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts @@ -4,9 +4,9 @@ import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; import { getShouldMarkReadAction } from '../actions/getShouldMarkReadAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { isWorkItemAlreadyCompletedAction } from '../actions/isWorkItemAlreadyCompletedAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryFormForDocketEditAction } from '../actions/EditDocketRecord/setDocketEntryFormForDocketEditAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; @@ -52,6 +52,6 @@ export const gotoDocketEntryQcSequence = [ isLoggedInAction, { isLoggedIn: gotoDocketEntryQc, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts b/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts index 700e862587d..1512353e6bd 100644 --- a/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryIdFromCorrespondenceAction } from '../actions/setDocketEntryIdFromCorrespondenceAction'; import { setDocumentToFormFromCorrespondenceAction } from '../actions/EditUploadCourtIssuedDocument/setDocumentToFormFromCorrespondenceAction'; @@ -29,6 +29,6 @@ export const gotoEditCorrespondenceDocumentSequence = [ isLoggedInAction, { isLoggedIn: gotoEditCorrespondenceDocument, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts b/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts index c4735a88bfa..3b766de9778 100644 --- a/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts +++ b/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts @@ -4,8 +4,8 @@ import { generateCourtIssuedDocumentTitleAction } from '../actions/CourtIssuedDo import { getCaseAction } from '../actions/getCaseAction'; import { getFilterCurrentJudgeUsersAction } from '../actions/getFilterCurrentJudgeUsersAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryFormForDocketEditAction } from '../actions/EditDocketRecord/setDocketEntryFormForDocketEditAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; @@ -39,6 +39,6 @@ export const gotoEditCourtIssuedDocketEntrySequence = [ isLoggedInAction, { isLoggedIn: gotoEditCourtIssuedDocketEntry, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts b/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts index 6a69e5d0284..9bbfac9e012 100644 --- a/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts @@ -1,8 +1,8 @@ import { clearConfirmationTextAction } from '../actions/clearConfirmationTextAction'; import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setEditDeficiencyStatisticFormAction } from '../actions/setEditDeficiencyStatisticFormAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -22,6 +22,6 @@ export const gotoEditDeficiencyStatisticSequence = [ setEditDeficiencyStatisticFormAction, setupCurrentPageAction('EditDeficiencyStatistic'), ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts b/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts index f1f040771b6..d9e4d76fd45 100644 --- a/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts @@ -8,9 +8,9 @@ import { generateTitlePreviewAction } from '../actions/EditDocketRecordEntry/gen import { getCaseAction } from '../actions/getCaseAction'; import { getFilterCurrentJudgeUsersAction } from '../actions/getFilterCurrentJudgeUsersAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { initCourtIssuedOrderFormPropsFromEventCodeAction } from '../actions/EditDocketRecordEntry/initCourtIssuedOrderFormPropsFromEventCodeAction'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultEditDocketEntryMetaTabAction } from '../actions/setDefaultEditDocketEntryMetaTabAction'; import { setDocketEntryMetaFormForEditAction } from '../actions/EditDocketRecordEntry/setDocketEntryMetaFormForEditAction'; @@ -53,6 +53,6 @@ export const gotoEditDocketEntryMetaSequence = [ isLoggedInAction, { isLoggedIn: gotoEditDocketEntryMeta, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditOrderSequence.ts b/web-client/src/presenter/sequences/gotoEditOrderSequence.ts index a6a39cede4d..169965d550a 100644 --- a/web-client/src/presenter/sequences/gotoEditOrderSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditOrderSequence.ts @@ -3,8 +3,8 @@ import { clearModalAction } from '../actions/clearModalAction'; import { convertHtml2PdfSequence } from './convertHtml2PdfSequence'; import { getCaseAction } from '../actions/getCaseAction'; import { getDocumentContentsAction } from '../actions/getDocumentContentsAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setAddedDocketNumbersAction } from '../actions/setAddedDocketNumbersAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultTabStateAction } from '../actions/setDefaultTabStateAction'; @@ -40,6 +40,6 @@ export const gotoEditOrderSequence = [ isLoggedInAction, { isLoggedIn: gotoEditOrder, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts b/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts index e691c2ad535..5c1d0e2564e 100644 --- a/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setEditOtherStatisticsFormAction } from '../actions/setEditOtherStatisticsFormAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -20,6 +20,6 @@ export const gotoEditOtherStatisticsSequence = [ setEditOtherStatisticsFormAction, setupCurrentPageAction('EditOtherStatistics'), ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts b/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts index 0501a82ebc7..28bbe4ff92d 100644 --- a/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts @@ -2,8 +2,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryFormForDocketEditAction } from '../actions/EditDocketRecord/setDocketEntryFormForDocketEditAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; @@ -36,6 +36,6 @@ export const gotoEditPaperFilingSequence = [ isLoggedInAction, { isLoggedIn: startWebSocketConnectionSequenceDecorator(gotoEditPaperFiling), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts b/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts index c63e2e4708e..0876a378a89 100644 --- a/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts @@ -5,8 +5,8 @@ import { getSetJudgesSequence } from './getSetJudgesSequence'; import { getTrialSessionDetailsAction } from '../actions/TrialSession/getTrialSessionDetailsAction'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setTrialSessionDetailsAction } from '../actions/TrialSession/setTrialSessionDetailsAction'; import { setTrialSessionDetailsOnFormAction } from '../actions/TrialSession/setTrialSessionDetailsOnFormAction'; import { setTrialSessionsAction } from '../actions/TrialSession/setTrialSessionsAction'; @@ -38,6 +38,6 @@ export const gotoEditTrialSessionSequence = [ isLoggedInAction, { isLoggedIn: gotoEditTrialSession, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts b/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts index 5632a515ed4..142e34d0a96 100644 --- a/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; import { setDocumentToFormAction } from '../actions/EditUploadCourtIssuedDocument/setDocumentToFormAction'; @@ -29,6 +29,6 @@ export const gotoEditUploadCourtIssuedDocumentSequence = [ isLoggedInAction, { isLoggedIn: gotoEditUploadCourtIssuedDocument, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts b/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts index 294c504597a..8bba9220581 100644 --- a/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultFilersMapAction } from '../actions/setDefaultFilersMapAction'; import { setWizardStepAction } from '../actions/setWizardStepAction'; @@ -26,6 +26,6 @@ export const gotoFileDocumentSequence = [ isLoggedInAction, { isLoggedIn: gotoFileDocument, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts b/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts index 140babe6e1a..cc8dbafb8b8 100644 --- a/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts +++ b/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts @@ -6,8 +6,8 @@ import { getJudgesCaseNoteForCaseAction } from '@web-client/presenter/actions/Tr import { getMessageThreadAction } from '../actions/getMessageThreadAction'; import { getMostRecentMessageInThreadAction } from '../actions/getMostRecentMessageInThreadAction'; import { getShouldMarkMessageAsReadAction } from '../actions/getShouldMarkMessageAsReadAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setCaseDetailPageTabActionGenerator } from '../actions/setCaseDetailPageTabActionGenerator'; import { setDefaultIsExpandedAction } from '../actions/setDefaultIsExpandedAction'; @@ -52,6 +52,6 @@ export const gotoMessageDetailSequence = [ isLoggedInAction, { isLoggedIn: gotoMessageDetail, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoMessagesSequence.ts b/web-client/src/presenter/sequences/gotoMessagesSequence.ts index efa0883b359..174ce9a4299 100644 --- a/web-client/src/presenter/sequences/gotoMessagesSequence.ts +++ b/web-client/src/presenter/sequences/gotoMessagesSequence.ts @@ -9,9 +9,9 @@ import { getInboxMessagesForSectionAction } from '../actions/getInboxMessagesFor import { getInboxMessagesForUserAction } from '../actions/getInboxMessagesForUserAction'; import { getOutboxMessagesForSectionAction } from '../actions/getOutboxMessagesForSectionAction'; import { getOutboxMessagesForUserAction } from '../actions/getOutboxMessagesForUserAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { parallel } from 'cerebral'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { resetCacheKeyAction } from '../actions/resetCacheKeyAction'; import { setDefaultTableSortAction } from '../actions/setDefaultTableSortAction'; import { setMessageCountsAction } from '../actions/setMessageCountsAction'; @@ -50,6 +50,6 @@ export const gotoMessagesSequence = [ isLoggedInAction, { isLoggedIn: goToMessages, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoPendingReportSequence.ts b/web-client/src/presenter/sequences/gotoPendingReportSequence.ts index 63d115dafd1..d1ebd817f1b 100644 --- a/web-client/src/presenter/sequences/gotoPendingReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoPendingReportSequence.ts @@ -4,8 +4,8 @@ import { clearPendingReportsAction } from '../actions/PendingItems/clearPendingR import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { getSetJudgesSequence } from './getSetJudgesSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -24,6 +24,6 @@ export const gotoPendingReportSequence = [ isLoggedInAction, { isLoggedIn: gotoPendingReport, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts index c29e84b3855..2b17752e609 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -22,6 +22,6 @@ export const gotoPractitionerAddDocumentSequence = [ isLoggedIn: startWebSocketConnectionSequenceDecorator( gotoPractitionerAddDocument, ), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts index 762e20bb13b..c2b16eb0303 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts @@ -1,7 +1,7 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setInitialTableSortAction } from '../actions/setInitialTableSortAction'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setTabFromPropsAction } from '../actions/setTabFromPropsAction'; @@ -21,7 +21,7 @@ export const gotoPractitionerDetailSequence = [ setPractitionerDetailAction, setupCurrentPageAction('PractitionerInformation'), ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]), ]; diff --git a/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts index 5b31613c173..667874a977d 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts @@ -1,8 +1,8 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; import { getPractitionerDocumentsAction } from '../actions/getPractitionerDocumentsAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setPractitionerDocumentsAction } from '../actions/setPractitionerDocumentsAction'; import { setTabFromPropsAction } from '../actions/setTabFromPropsAction'; @@ -23,7 +23,7 @@ export const gotoPractitionerDocumentationSequence = [ setPractitionerDocumentsAction, setupCurrentPageAction('PractitionerInformation'), ]), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]), ]; diff --git a/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts index fbcc146dbca..8561b33a8d9 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; import { getPractitionerDocumentAction } from '../actions/getPractitionerDocumentAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setPractitionerDocumentFormForEditAction } from '../actions/Practitioners/setPractitionerDocumentFormForEditAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -26,6 +26,6 @@ export const gotoPractitionerEditDocumentSequence = [ isLoggedIn: startWebSocketConnectionSequenceDecorator( gotoPractitionerEditDocument, ), - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts b/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts index e8dfb7311c6..c66a9645e35 100644 --- a/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts +++ b/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts @@ -3,9 +3,9 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; import { getCaseAssociationAction } from '../actions/getCaseAssociationAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToCaseDetailAction } from '../actions/navigateToCaseDetailAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { runPathForUserRoleAction } from '../actions/runPathForUserRoleAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setCaseAssociationAction } from '../actions/setCaseAssociationAction'; @@ -51,6 +51,6 @@ export const gotoRequestAccessSequence = [ isLoggedInAction, { isLoggedIn: gotoRequestAccess, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts index c2fc46380a5..2a4d3aa1b53 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts @@ -3,12 +3,12 @@ import { getCalendaredCasesForTrialSessionAction } from '../actions/TrialSession import { getEligibleCasesForTrialSessionAction } from '../actions/TrialSession/getEligibleCasesForTrialSessionAction'; import { getTrialSessionDetailsAction } from '../actions/TrialSession/getTrialSessionDetailsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { isTrialSessionCalendaredAction } from '../actions/TrialSession/isTrialSessionCalendaredAction'; import { mergeCaseOrderIntoCalendaredCasesAction } from '../actions/TrialSession/mergeCaseOrderIntoCalendaredCasesAction'; import { mergeCaseOrderIntoEligibleCasesAction } from '../actions/TrialSession/mergeCaseOrderIntoEligibleCasesAction'; import { parallel } from 'cerebral/factories'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCalendaredCasesOnTrialSessionAction } from '../actions/TrialSession/setCalendaredCasesOnTrialSessionAction'; import { setDefaultTrialSessionDetailTabAction } from '../actions/TrialSession/setDefaultTrialSessionDetailTabAction'; import { setEligibleCasesOnTrialSessionAction } from '../actions/TrialSession/setEligibleCasesOnTrialSessionAction'; @@ -50,6 +50,6 @@ export const gotoTrialSessionDetailSequence = [ isLoggedInAction, { isLoggedIn: gotoTrialSessionDetails, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts index ade6663fd5a..23805fcebc8 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts @@ -1,5 +1,5 @@ +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -12,6 +12,6 @@ export const gotoTrialSessionPlanningReportSequence = [ isLoggedInAction, { isLoggedIn: gotoTrialSessionPlanningReport, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts index df793f1995e..6b86761c125 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts @@ -7,12 +7,12 @@ import { getTrialSessionDetailsAction } from '../actions/TrialSession/getTrialSe import { getTrialSessionWorkingCopyAction } from '../actions/TrialSession/getTrialSessionWorkingCopyAction'; import { getUserCaseNoteForCasesAction } from '../actions/TrialSession/getUserCaseNoteForCasesAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { gotoTrialSessionDetailSequence } from './gotoTrialSessionDetailSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { isTrialSessionCalendaredAction } from '../actions/TrialSession/isTrialSessionCalendaredAction'; import { isUserAssociatedWithTrialSessionAction } from '../actions/TrialSession/isUserAssociatedWithTrialSessionAction'; import { mergeCaseOrderIntoCalendaredCasesAction } from '../actions/TrialSession/mergeCaseOrderIntoCalendaredCasesAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { runPathForUserRoleAction } from '../actions/runPathForUserRoleAction'; import { setCalendaredCasesOnTrialSessionAction } from '../actions/TrialSession/setCalendaredCasesOnTrialSessionAction'; import { setCaseNotesOntoCalendaredCasesAction } from '../actions/TrialSession/setCaseNotesOntoCalendaredCasesAction'; @@ -87,6 +87,6 @@ export const gotoTrialSessionWorkingCopySequence = [ isLoggedInAction, { isLoggedIn: gotoTrialSessionDetails, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts index f02f9cbcc8a..d82cf29a2bc 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts @@ -5,9 +5,9 @@ import { getJudgeForCurrentUserAction } from '../actions/getJudgeForCurrentUserA import { getNotificationsAction } from '../actions/getNotificationsAction'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { parallel } from 'cerebral/factories'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setAllAndCurrentJudgesAction } from '../actions/setAllAndCurrentJudgesAction'; import { setJudgeUserAction } from '../actions/setJudgeUserAction'; import { setNotificationsAction } from '../actions/setNotificationsAction'; @@ -38,6 +38,6 @@ export const gotoTrialSessionsSequence = [ isLoggedInAction, { isLoggedIn: [gotoTrialSessions], - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts b/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts index 2400b47d72e..a5728362778 100644 --- a/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts @@ -2,8 +2,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { resetAddCorrespondenceAction } from '../actions/resetAddCorrespondenceAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -27,6 +27,6 @@ export const gotoUploadCorrespondenceDocumentSequence = [ isLoggedInAction, { isLoggedIn: [gotoUploadCorrespondenceDocument], - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts b/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts index daed3e27d78..7dc8e725476 100644 --- a/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -24,6 +24,6 @@ export const gotoUploadCourtIssuedDocumentSequence = [ isLoggedInAction, { isLoggedIn: [gotoUploadCourtIssuedDocument], - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts b/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts index 9921f72466a..8dc4513c6c8 100644 --- a/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts +++ b/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts @@ -6,9 +6,9 @@ import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { getConstants } from '../../getConstants'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { parallel } from 'cerebral/factories'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; import { runPathForUserRoleAction } from '../actions/runPathForUserRoleAction'; import { setSectionForWorkQueueAction } from '../actions/setSectionForWorkQueueAction'; import { setTrialSessionsAction } from '../actions/TrialSession/setTrialSessionsAction'; @@ -73,6 +73,6 @@ export const gotoWorkQueueSequence = [ isLoggedInAction, { isLoggedIn: goToWorkQueue, - unauthorized: [redirectToCognitoAction], + unauthorized: [gotoLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/redirectToLoginSequence.ts b/web-client/src/presenter/sequences/redirectToLoginSequence.ts index 1da406bd931..20cea6d3dcf 100644 --- a/web-client/src/presenter/sequences/redirectToLoginSequence.ts +++ b/web-client/src/presenter/sequences/redirectToLoginSequence.ts @@ -1,3 +1,3 @@ -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; -export const redirectToLoginSequence = [redirectToCognitoAction]; +export const redirectToLoginSequence = [gotoLoginSequence]; diff --git a/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts b/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts index 04e51ac6baf..6a4783d6c79 100644 --- a/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts +++ b/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts @@ -1,5 +1,5 @@ import { clearModalAction } from '../actions/clearModalAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { setAlertFromExceptionAction } from '../actions/setAlertFromExceptionAction'; import { unsetWaitingForResponseOnErrorAction } from '../actions/unsetWaitingForResponseOnErrorAction'; @@ -7,5 +7,5 @@ export const unauthorizedErrorSequence = [ unsetWaitingForResponseOnErrorAction, setAlertFromExceptionAction, clearModalAction, - redirectToCognitoAction, + gotoLoginSequence, ]; diff --git a/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts b/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts index a5e5edfb576..2ab8545d002 100644 --- a/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts +++ b/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts @@ -1,5 +1,5 @@ import { clearModalAction } from '../actions/clearModalAction'; -import { redirectToCognitoAction } from '../actions/redirectToCognitoAction'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; import { setAlertFromExceptionAction } from '../actions/setAlertFromExceptionAction'; import { unsetWaitingForResponseOnErrorAction } from '../actions/unsetWaitingForResponseOnErrorAction'; @@ -7,5 +7,5 @@ export const unidentifiedUserErrorSequence = [ unsetWaitingForResponseOnErrorAction, setAlertFromExceptionAction, clearModalAction, - redirectToCognitoAction, + gotoLoginSequence, ]; From 5d5fff48f03d520ffd83b8782e41ddc6d0f08694 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Thu, 7 Dec 2023 13:36:13 -0800 Subject: [PATCH 015/700] 10007: Replace redirectToLoginSequence with gotoLoginSequence --- web-client/src/presenter/presenter.ts | 2 -- .../src/presenter/sequences/redirectToLoginSequence.ts | 3 --- web-client/src/views/IdleLogout.tsx | 6 +++--- 3 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 web-client/src/presenter/sequences/redirectToLoginSequence.ts diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 9274b666bf6..0d2d81df085 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -305,7 +305,6 @@ import { paperServiceCompleteSequence } from './sequences/paperServiceCompleteSe import { printPaperServiceForTrialCompleteSequence } from './sequences/printPaperServiceForTrialCompleteSequence'; import { printTrialCalendarSequence } from './sequences/printTrialCalendarSequence'; import { prioritizeCaseSequence } from './sequences/prioritizeCaseSequence'; -import { redirectToLoginSequence } from './sequences/redirectToLoginSequence'; import { refreshPdfSequence } from './sequences/refreshPdfSequence'; import { refreshStatisticsSequence } from './sequences/refreshStatisticsSequence'; import { removeBatchSequence } from './sequences/removeBatchSequence'; @@ -1069,7 +1068,6 @@ export const presenterSequences = { printPaperServiceForTrialCompleteSequence as unknown as Function, printTrialCalendarSequence: printTrialCalendarSequence as unknown as Function, prioritizeCaseSequence: prioritizeCaseSequence as unknown as Function, - redirectToLoginSequence: redirectToLoginSequence as unknown as Function, refreshPdfSequence: refreshPdfSequence as unknown as Function, refreshStatisticsSequence: refreshStatisticsSequence as unknown as Function, removeBatchSequence: removeBatchSequence as unknown as Function, diff --git a/web-client/src/presenter/sequences/redirectToLoginSequence.ts b/web-client/src/presenter/sequences/redirectToLoginSequence.ts deleted file mode 100644 index 20cea6d3dcf..00000000000 --- a/web-client/src/presenter/sequences/redirectToLoginSequence.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; - -export const redirectToLoginSequence = [gotoLoginSequence]; diff --git a/web-client/src/views/IdleLogout.tsx b/web-client/src/views/IdleLogout.tsx index b1062496ca9..ee9cd644b3e 100644 --- a/web-client/src/views/IdleLogout.tsx +++ b/web-client/src/views/IdleLogout.tsx @@ -4,8 +4,8 @@ import { sequences } from '@web-client/presenter/app.cerebral'; import React from 'react'; export const IdleLogout = connect( - { redirectToLoginSequence: sequences.redirectToLoginSequence }, - function IdleLogout({ redirectToLoginSequence }) { + { gotoLoginSequence: sequences.gotoLoginSequence }, + function IdleLogout({ gotoLoginSequence }) { return (

Session Timeout

@@ -16,7 +16,7 @@ export const IdleLogout = connect( United States Tax Court website for information on court services and contact information.

- + From 8a969597a9b138aa71a5560dd65383a0fd3fe8d2 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Thu, 7 Dec 2023 14:27:08 -0800 Subject: [PATCH 016/700] 10007: Delete unused env variable --- esbuildHelper.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/esbuildHelper.mjs b/esbuildHelper.mjs index 5781d5489cb..cd2250426ec 100644 --- a/esbuildHelper.mjs +++ b/esbuildHelper.mjs @@ -21,7 +21,6 @@ const env = { CHECK_DEPLOY_DATE_INTERVAL: process.env.CHECK_DEPLOY_DATE_INTERVAL, CI: process.env.CI, CIRCLE_SHA1: process.env.CIRCLE_SHA1, - COGNITO: process.env.COGNITO, COGNITO_CLIENT_ID: process.env.COGNITO_CLIENT_ID, COGNITO_LOGIN_URL: process.env.COGNITO_LOGIN_URL, COGNITO_PASSWORD_RESET_REQUEST_URL: From 895280297b4ae157e634b579e6bcdba779402be1 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 7 Dec 2023 14:58:52 -0800 Subject: [PATCH 017/700] 10007: WIP move gotoLoginSequence --- web-client/src/presenter/presenter-public.ts | 2 +- web-client/src/presenter/presenter.ts | 2 +- .../JudgeActivityReport/gotoJudgeActivityReportSequence.ts | 2 +- .../sequences/{Public => Login}/goToLoginSequence.ts | 0 .../src/presenter/sequences/confirmSignUpLocalSequence.ts | 2 +- .../src/presenter/sequences/goToVerificationSentSequence.ts | 2 +- .../sequences/gotoAddCourtIssuedDocketEntrySequence.ts | 2 +- .../sequences/gotoAddDeficiencyStatisticsSequence.ts | 2 +- .../presenter/sequences/gotoAddOtherStatisticsSequence.ts | 2 +- .../src/presenter/sequences/gotoAddPaperFilingSequence.ts | 2 +- .../presenter/sequences/gotoAddPetitionerToCaseSequence.ts | 2 +- .../src/presenter/sequences/gotoAddTrialSessionSequence.ts | 2 +- web-client/src/presenter/sequences/gotoApplyStampSequence.ts | 2 +- .../presenter/sequences/gotoBeforeYouFileDocumentSequence.ts | 2 +- .../presenter/sequences/gotoBlockedCasesReportSequence.ts | 2 +- .../presenter/sequences/gotoCaseDeadlineReportSequence.ts | 2 +- .../presenter/sequences/gotoCaseInventoryReportSequence.ts | 2 +- .../src/presenter/sequences/gotoContactEditSequence.ts | 2 +- .../src/presenter/sequences/gotoCreateOrderSequence.ts | 2 +- .../src/presenter/sequences/gotoCustomCaseReportSequence.ts | 2 +- web-client/src/presenter/sequences/gotoDashboardSequence.ts | 2 +- .../src/presenter/sequences/gotoDocketEntryQcSequence.ts | 2 +- .../sequences/gotoEditCorrespondenceDocumentSequence.ts | 2 +- .../sequences/gotoEditCourtIssuedDocketEntrySequence.ts | 2 +- .../sequences/gotoEditDeficiencyStatisticSequence.ts | 2 +- .../presenter/sequences/gotoEditDocketEntryMetaSequence.ts | 2 +- web-client/src/presenter/sequences/gotoEditOrderSequence.ts | 2 +- .../presenter/sequences/gotoEditOtherStatisticsSequence.ts | 2 +- .../src/presenter/sequences/gotoEditPaperFilingSequence.ts | 2 +- .../src/presenter/sequences/gotoEditTrialSessionSequence.ts | 2 +- .../sequences/gotoEditUploadCourtIssuedDocumentSequence.ts | 2 +- .../src/presenter/sequences/gotoFileDocumentSequence.ts | 2 +- .../src/presenter/sequences/gotoMessageDetailSequence.ts | 2 +- web-client/src/presenter/sequences/gotoMessagesSequence.ts | 2 +- .../src/presenter/sequences/gotoPendingReportSequence.ts | 2 +- .../sequences/gotoPractitionerAddDocumentSequence.ts | 2 +- .../presenter/sequences/gotoPractitionerDetailSequence.ts | 2 +- .../sequences/gotoPractitionerDocumentationSequence.ts | 2 +- .../sequences/gotoPractitionerEditDocumentSequence.ts | 2 +- .../src/presenter/sequences/gotoRequestAccessSequence.ts | 2 +- .../presenter/sequences/gotoTrialSessionDetailSequence.ts | 2 +- .../sequences/gotoTrialSessionPlanningReportSequence.ts | 2 +- .../sequences/gotoTrialSessionWorkingCopySequence.ts | 2 +- .../src/presenter/sequences/gotoTrialSessionsSequence.ts | 2 +- .../sequences/gotoUploadCorrespondenceDocumentSequence.ts | 2 +- .../sequences/gotoUploadCourtIssuedDocumentSequence.ts | 2 +- web-client/src/presenter/sequences/gotoWorkQueueSequence.ts | 2 +- web-client/src/presenter/sequences/signOutSequence.ts | 2 +- .../src/presenter/sequences/unauthorizedErrorSequence.ts | 2 +- .../src/presenter/sequences/unidentifiedUserErrorSequence.ts | 2 +- web-client/src/router.ts | 5 +++++ 51 files changed, 54 insertions(+), 49 deletions(-) rename web-client/src/presenter/sequences/{Public => Login}/goToLoginSequence.ts (100%) diff --git a/web-client/src/presenter/presenter-public.ts b/web-client/src/presenter/presenter-public.ts index 4dc0fe2b924..90b7b26cb8e 100644 --- a/web-client/src/presenter/presenter-public.ts +++ b/web-client/src/presenter/presenter-public.ts @@ -13,7 +13,7 @@ import { goToCreatePetitionerAccountSequence } from '@web-client/presenter/seque import { goToVerificationSentSequence } from '@web-client/presenter/sequences/goToVerificationSentSequence'; import { gotoContactSequence } from './sequences/gotoContactSequence'; import { gotoHealthCheckSequence } from './sequences/gotoHealthCheckSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { gotoMaintenanceSequence } from './sequences/gotoMaintenanceSequence'; import { gotoPrivacySequence } from './sequences/gotoPrivacySequence'; import { gotoPublicCaseDetailSequence } from './sequences/Public/gotoPublicCaseDetailSequence'; diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 0d2d81df085..8c80fe75502 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -166,7 +166,7 @@ import { gotoFileDocumentSequence } from './sequences/gotoFileDocumentSequence'; import { gotoFilePetitionSuccessSequence } from './sequences/gotoFilePetitionSuccessSequence'; import { gotoIdleLogoutSequence } from './sequences/gotoIdleLogoutSequence'; import { gotoJudgeActivityReportSequence } from './sequences/JudgeActivityReport/gotoJudgeActivityReportSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { gotoMaintenanceSequence } from './sequences/gotoMaintenanceSequence'; import { gotoMessageDetailSequence } from './sequences/gotoMessageDetailSequence'; import { gotoMessagesSequence } from './sequences/gotoMessagesSequence'; diff --git a/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts b/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts index f8d96d02836..b0c3876225b 100644 --- a/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts +++ b/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts @@ -2,7 +2,7 @@ import { clearErrorAlertsAction } from '../../actions/clearErrorAlertsAction'; import { clearScreenMetadataAction } from '../../actions/clearScreenMetadataAction'; import { closeMobileMenuAction } from '../../actions/closeMobileMenuAction'; import { getUsersInSectionAction } from '../../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../../actions/isLoggedInAction'; import { resetJudgeActivityReportStateAction } from '../../actions/resetJudgeActivityReportStateAction'; import { setAllAndCurrentJudgesAction } from '../../actions/setAllAndCurrentJudgesAction'; diff --git a/web-client/src/presenter/sequences/Public/goToLoginSequence.ts b/web-client/src/presenter/sequences/Login/goToLoginSequence.ts similarity index 100% rename from web-client/src/presenter/sequences/Public/goToLoginSequence.ts rename to web-client/src/presenter/sequences/Login/goToLoginSequence.ts diff --git a/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts b/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts index f22a66d3740..da629b7522f 100644 --- a/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts +++ b/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts @@ -1,5 +1,5 @@ import { confirmSignUpLocalAction } from '../actions/confirmSignUpLocalAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { setAlertErrorAction } from '../actions/setAlertErrorAction'; import { setAlertSuccessAction } from '../actions/setAlertSuccessAction'; diff --git a/web-client/src/presenter/sequences/goToVerificationSentSequence.ts b/web-client/src/presenter/sequences/goToVerificationSentSequence.ts index 1fe0d7bfac8..64b6631db80 100644 --- a/web-client/src/presenter/sequences/goToVerificationSentSequence.ts +++ b/web-client/src/presenter/sequences/goToVerificationSentSequence.ts @@ -1,5 +1,5 @@ import { checkIfCognitoEmailInState } from '@web-client/presenter/actions/checkIfCognitoEmailInState'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { setupCurrentPageAction } from '@web-client/presenter/actions/setupCurrentPageAction'; export const goToVerificationSentSequence = [ diff --git a/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts b/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts index 05dc48e1c58..580001bd4c9 100644 --- a/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts +++ b/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts @@ -3,7 +3,7 @@ import { generateCourtIssuedDocumentTitleAction } from '../actions/CourtIssuedDo import { getCaseAction } from '../actions/getCaseAction'; import { getFilterCurrentJudgeUsersAction } from '../actions/getFilterCurrentJudgeUsersAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setCourtIssuedDocumentInitialDataAction } from '../actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction'; diff --git a/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts b/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts index ffab2ace071..0fc72d0d8b7 100644 --- a/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts @@ -1,7 +1,7 @@ import { clearConfirmationTextAction } from '../actions/clearConfirmationTextAction'; import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultFormForAddDeficiencyStatisticsAction } from '../actions/setDefaultFormForAddDeficiencyStatisticsAction'; diff --git a/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts b/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts index 83f64434c1b..3a7b950f7e3 100644 --- a/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts @@ -1,6 +1,6 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; diff --git a/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts b/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts index cad59c761a8..3c004e6e2eb 100644 --- a/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts @@ -2,7 +2,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { resetAddPaperFilingAction } from '../actions/resetAddPaperFilingAction'; import { setCaseAction } from '../actions/setCaseAction'; diff --git a/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts b/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts index ec73f73d814..340ed614aaa 100644 --- a/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts @@ -1,6 +1,6 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultAddPetitionerToCaseFormAction } from '../actions/setDefaultAddPetitionerToCaseFormAction'; diff --git a/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts b/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts index a781fcdaf33..0180260e6c0 100644 --- a/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts @@ -3,7 +3,7 @@ import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction' import { getSetJudgesSequence } from './getSetJudgesSequence'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { parallel } from 'cerebral/factories'; import { setDefaultTrialSessionFormValuesAction } from '../actions/setDefaultTrialSessionFormValuesAction'; diff --git a/web-client/src/presenter/sequences/gotoApplyStampSequence.ts b/web-client/src/presenter/sequences/gotoApplyStampSequence.ts index b23c9737e15..54de9e1b6c8 100644 --- a/web-client/src/presenter/sequences/gotoApplyStampSequence.ts +++ b/web-client/src/presenter/sequences/gotoApplyStampSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearPDFStampDataAction } from '../actions/StampMotion/clearPDFStampDataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; diff --git a/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts b/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts index 5852fa66fa4..c4b194c60ba 100644 --- a/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts @@ -1,5 +1,5 @@ import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; diff --git a/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts b/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts index c38128478dd..44542a9569b 100644 --- a/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts @@ -2,7 +2,7 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; diff --git a/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts b/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts index c83b5a4f204..f75695e0b4c 100644 --- a/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts @@ -4,7 +4,7 @@ import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction' import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { getCaseDeadlinesAction } from '../actions/CaseDeadline/getCaseDeadlinesAction'; import { getSetJudgesSequence } from './getSetJudgesSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { parallel } from 'cerebral/factories'; import { setCaseDeadlinesAction } from '../actions/CaseDeadline/setCaseDeadlinesAction'; diff --git a/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts b/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts index 6bb9ac16d05..c06ca757251 100644 --- a/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts @@ -2,7 +2,7 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { fetchUserNotificationsSequence } from './fetchUserNotificationsSequence'; import { getSetJudgesSequence } from './getSetJudgesSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { hasCaseInventoryReportFilterSelectedAction } from '../actions/CaseInventoryReport/hasCaseInventoryReportFilterSelectedAction'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToDashboardAction } from '../actions/navigateToDashboardAction'; diff --git a/web-client/src/presenter/sequences/gotoContactEditSequence.ts b/web-client/src/presenter/sequences/gotoContactEditSequence.ts index 214dfece603..6eff9091544 100644 --- a/web-client/src/presenter/sequences/gotoContactEditSequence.ts +++ b/web-client/src/presenter/sequences/gotoContactEditSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setupContactFormAction } from '../actions/setupContactFormAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; diff --git a/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts b/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts index 31b7281b39c..4333c52afaa 100644 --- a/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts +++ b/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearModalAction } from '../actions/clearModalAction'; import { convertHtml2PdfSequence } from './convertHtml2PdfSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { hasOrderTypeSelectedAction } from '../actions/CourtIssuedOrder/hasOrderTypeSelectedAction'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToCaseDetailAction } from '../actions/navigateToCaseDetailAction'; diff --git a/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts b/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts index aa7b9f5ccad..96024838e62 100644 --- a/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts @@ -1,5 +1,5 @@ import { getSetJudgesSequence } from './getSetJudgesSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { resetCustomCaseReportStateAction } from '../actions/resetCustomCaseReportStateAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; diff --git a/web-client/src/presenter/sequences/gotoDashboardSequence.ts b/web-client/src/presenter/sequences/gotoDashboardSequence.ts index dd3150136d1..19ce94a3338 100644 --- a/web-client/src/presenter/sequences/gotoDashboardSequence.ts +++ b/web-client/src/presenter/sequences/gotoDashboardSequence.ts @@ -9,7 +9,7 @@ import { getMaintenanceModeAction } from '../actions/getMaintenanceModeAction'; import { getOpenAndClosedCasesForUserAction } from '../actions/Dashboard/getOpenAndClosedCasesForUserAction'; import { getSubmittedAndCavCasesForCurrentJudgeAction } from '@web-client/presenter/actions/CaseWorksheet/getSubmittedAndCavCasesForCurrentJudgeAction'; import { getTrialSessionsForJudgeAction } from '../actions/TrialSession/getTrialSessionsForJudgeAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { gotoMaintenanceSequence } from './gotoMaintenanceSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToMessagesAction } from '../actions/navigateToMessagesAction'; diff --git a/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts b/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts index 445e72a18a2..b1266fc3dce 100644 --- a/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts +++ b/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts @@ -4,7 +4,7 @@ import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; import { getShouldMarkReadAction } from '../actions/getShouldMarkReadAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { isWorkItemAlreadyCompletedAction } from '../actions/isWorkItemAlreadyCompletedAction'; import { setCaseAction } from '../actions/setCaseAction'; diff --git a/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts b/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts index 1512353e6bd..ded14ec7229 100644 --- a/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryIdFromCorrespondenceAction } from '../actions/setDocketEntryIdFromCorrespondenceAction'; diff --git a/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts b/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts index 3b766de9778..ef876481f3b 100644 --- a/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts +++ b/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts @@ -4,7 +4,7 @@ import { generateCourtIssuedDocumentTitleAction } from '../actions/CourtIssuedDo import { getCaseAction } from '../actions/getCaseAction'; import { getFilterCurrentJudgeUsersAction } from '../actions/getFilterCurrentJudgeUsersAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryFormForDocketEditAction } from '../actions/EditDocketRecord/setDocketEntryFormForDocketEditAction'; diff --git a/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts b/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts index 9bbfac9e012..e6a14e25c9c 100644 --- a/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts @@ -1,7 +1,7 @@ import { clearConfirmationTextAction } from '../actions/clearConfirmationTextAction'; import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setEditDeficiencyStatisticFormAction } from '../actions/setEditDeficiencyStatisticFormAction'; diff --git a/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts b/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts index d9e4d76fd45..c51d2dd61b0 100644 --- a/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts @@ -8,7 +8,7 @@ import { generateTitlePreviewAction } from '../actions/EditDocketRecordEntry/gen import { getCaseAction } from '../actions/getCaseAction'; import { getFilterCurrentJudgeUsersAction } from '../actions/getFilterCurrentJudgeUsersAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { initCourtIssuedOrderFormPropsFromEventCodeAction } from '../actions/EditDocketRecordEntry/initCourtIssuedOrderFormPropsFromEventCodeAction'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; diff --git a/web-client/src/presenter/sequences/gotoEditOrderSequence.ts b/web-client/src/presenter/sequences/gotoEditOrderSequence.ts index 169965d550a..8be7995df07 100644 --- a/web-client/src/presenter/sequences/gotoEditOrderSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditOrderSequence.ts @@ -3,7 +3,7 @@ import { clearModalAction } from '../actions/clearModalAction'; import { convertHtml2PdfSequence } from './convertHtml2PdfSequence'; import { getCaseAction } from '../actions/getCaseAction'; import { getDocumentContentsAction } from '../actions/getDocumentContentsAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setAddedDocketNumbersAction } from '../actions/setAddedDocketNumbersAction'; import { setCaseAction } from '../actions/setCaseAction'; diff --git a/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts b/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts index 5c1d0e2564e..cbf446fd872 100644 --- a/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts @@ -1,6 +1,6 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setEditOtherStatisticsFormAction } from '../actions/setEditOtherStatisticsFormAction'; diff --git a/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts b/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts index 28bbe4ff92d..e403677d9cd 100644 --- a/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts @@ -2,7 +2,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryFormForDocketEditAction } from '../actions/EditDocketRecord/setDocketEntryFormForDocketEditAction'; diff --git a/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts b/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts index 0876a378a89..5467659f49d 100644 --- a/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts @@ -5,7 +5,7 @@ import { getSetJudgesSequence } from './getSetJudgesSequence'; import { getTrialSessionDetailsAction } from '../actions/TrialSession/getTrialSessionDetailsAction'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setTrialSessionDetailsAction } from '../actions/TrialSession/setTrialSessionDetailsAction'; import { setTrialSessionDetailsOnFormAction } from '../actions/TrialSession/setTrialSessionDetailsOnFormAction'; diff --git a/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts b/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts index 142e34d0a96..f28b00cbcf8 100644 --- a/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; diff --git a/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts b/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts index 8bba9220581..0b0e8cf5587 100644 --- a/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultFilersMapAction } from '../actions/setDefaultFilersMapAction'; diff --git a/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts b/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts index cc8dbafb8b8..15c3bccffc3 100644 --- a/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts +++ b/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts @@ -6,7 +6,7 @@ import { getJudgesCaseNoteForCaseAction } from '@web-client/presenter/actions/Tr import { getMessageThreadAction } from '../actions/getMessageThreadAction'; import { getMostRecentMessageInThreadAction } from '../actions/getMostRecentMessageInThreadAction'; import { getShouldMarkMessageAsReadAction } from '../actions/getShouldMarkMessageAsReadAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setCaseDetailPageTabActionGenerator } from '../actions/setCaseDetailPageTabActionGenerator'; diff --git a/web-client/src/presenter/sequences/gotoMessagesSequence.ts b/web-client/src/presenter/sequences/gotoMessagesSequence.ts index 174ce9a4299..cb174580434 100644 --- a/web-client/src/presenter/sequences/gotoMessagesSequence.ts +++ b/web-client/src/presenter/sequences/gotoMessagesSequence.ts @@ -9,7 +9,7 @@ import { getInboxMessagesForSectionAction } from '../actions/getInboxMessagesFor import { getInboxMessagesForUserAction } from '../actions/getInboxMessagesForUserAction'; import { getOutboxMessagesForSectionAction } from '../actions/getOutboxMessagesForSectionAction'; import { getOutboxMessagesForUserAction } from '../actions/getOutboxMessagesForUserAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { parallel } from 'cerebral'; import { resetCacheKeyAction } from '../actions/resetCacheKeyAction'; diff --git a/web-client/src/presenter/sequences/gotoPendingReportSequence.ts b/web-client/src/presenter/sequences/gotoPendingReportSequence.ts index d1ebd817f1b..e09933acddf 100644 --- a/web-client/src/presenter/sequences/gotoPendingReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoPendingReportSequence.ts @@ -4,7 +4,7 @@ import { clearPendingReportsAction } from '../actions/PendingItems/clearPendingR import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { getSetJudgesSequence } from './getSetJudgesSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; diff --git a/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts index 2b17752e609..0e1753b0646 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts @@ -1,6 +1,6 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; diff --git a/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts index c2b16eb0303..50d7c8588f7 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts @@ -1,6 +1,6 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setInitialTableSortAction } from '../actions/setInitialTableSortAction'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; diff --git a/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts index 667874a977d..bf084e2f9d0 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts @@ -1,7 +1,7 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; import { getPractitionerDocumentsAction } from '../actions/getPractitionerDocumentsAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setPractitionerDocumentsAction } from '../actions/setPractitionerDocumentsAction'; diff --git a/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts index 8561b33a8d9..844b067642b 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; import { getPractitionerDocumentAction } from '../actions/getPractitionerDocumentAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setPractitionerDocumentFormForEditAction } from '../actions/Practitioners/setPractitionerDocumentFormForEditAction'; diff --git a/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts b/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts index c66a9645e35..58a6d2ed4ed 100644 --- a/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts +++ b/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts @@ -3,7 +3,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; import { getCaseAssociationAction } from '../actions/getCaseAssociationAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToCaseDetailAction } from '../actions/navigateToCaseDetailAction'; import { runPathForUserRoleAction } from '../actions/runPathForUserRoleAction'; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts index 2a4d3aa1b53..a5aebfc0530 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts @@ -3,7 +3,7 @@ import { getCalendaredCasesForTrialSessionAction } from '../actions/TrialSession import { getEligibleCasesForTrialSessionAction } from '../actions/TrialSession/getEligibleCasesForTrialSessionAction'; import { getTrialSessionDetailsAction } from '../actions/TrialSession/getTrialSessionDetailsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { isTrialSessionCalendaredAction } from '../actions/TrialSession/isTrialSessionCalendaredAction'; import { mergeCaseOrderIntoCalendaredCasesAction } from '../actions/TrialSession/mergeCaseOrderIntoCalendaredCasesAction'; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts index 23805fcebc8..33bd7edc297 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts @@ -1,4 +1,4 @@ -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts index 6b86761c125..08e8feb9b81 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts @@ -7,7 +7,7 @@ import { getTrialSessionDetailsAction } from '../actions/TrialSession/getTrialSe import { getTrialSessionWorkingCopyAction } from '../actions/TrialSession/getTrialSessionWorkingCopyAction'; import { getUserCaseNoteForCasesAction } from '../actions/TrialSession/getUserCaseNoteForCasesAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { gotoTrialSessionDetailSequence } from './gotoTrialSessionDetailSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { isTrialSessionCalendaredAction } from '../actions/TrialSession/isTrialSessionCalendaredAction'; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts index d82cf29a2bc..cece6ae4d6a 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts @@ -5,7 +5,7 @@ import { getJudgeForCurrentUserAction } from '../actions/getJudgeForCurrentUserA import { getNotificationsAction } from '../actions/getNotificationsAction'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { parallel } from 'cerebral/factories'; import { setAllAndCurrentJudgesAction } from '../actions/setAllAndCurrentJudgesAction'; diff --git a/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts b/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts index a5728362778..6f9c3d9e5be 100644 --- a/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts @@ -2,7 +2,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { resetAddCorrespondenceAction } from '../actions/resetAddCorrespondenceAction'; import { setCaseAction } from '../actions/setCaseAction'; diff --git a/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts b/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts index 7dc8e725476..fc57ea90f82 100644 --- a/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; diff --git a/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts b/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts index 8dc4513c6c8..ddda0440c37 100644 --- a/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts +++ b/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts @@ -6,7 +6,7 @@ import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { getConstants } from '../../getConstants'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { parallel } from 'cerebral/factories'; import { runPathForUserRoleAction } from '../actions/runPathForUserRoleAction'; diff --git a/web-client/src/presenter/sequences/signOutSequence.ts b/web-client/src/presenter/sequences/signOutSequence.ts index 016939203c6..d678feffe96 100644 --- a/web-client/src/presenter/sequences/signOutSequence.ts +++ b/web-client/src/presenter/sequences/signOutSequence.ts @@ -4,7 +4,7 @@ import { clearLoginFormAction } from '../actions/clearLoginFormAction'; import { clearMaintenanceModeAction } from '../actions/clearMaintenanceModeAction'; import { clearUserAction } from '../actions/clearUserAction'; import { deleteAuthCookieAction } from '../actions/deleteAuthCookieAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { stopWebSocketConnectionAction } from '../actions/WebSocketConnection/stopWebSocketConnectionAction'; diff --git a/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts b/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts index 6a4783d6c79..81284d6e93a 100644 --- a/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts +++ b/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts @@ -1,5 +1,5 @@ import { clearModalAction } from '../actions/clearModalAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { setAlertFromExceptionAction } from '../actions/setAlertFromExceptionAction'; import { unsetWaitingForResponseOnErrorAction } from '../actions/unsetWaitingForResponseOnErrorAction'; diff --git a/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts b/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts index 2ab8545d002..d3e5e18b8bf 100644 --- a/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts +++ b/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts @@ -1,5 +1,5 @@ import { clearModalAction } from '../actions/clearModalAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { setAlertFromExceptionAction } from '../actions/setAlertFromExceptionAction'; import { unsetWaitingForResponseOnErrorAction } from '../actions/unsetWaitingForResponseOnErrorAction'; diff --git a/web-client/src/router.ts b/web-client/src/router.ts index cb025e2c5e0..36e84664504 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -1148,6 +1148,11 @@ const router = { } }); + registerRoute('/login', () => { + setPageTitle('Login'); + app.getSequence('gotoLoginSequence')(); + }); + registerRoute( '/before-filing-a-petition', ifHasAccess({ app }, () => { From 13de5806d7fd9c9d48f6b9ecf17cb828f467565c Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 7 Dec 2023 15:40:33 -0800 Subject: [PATCH 018/700] 10007: WIP Add submitLoginSequence. --- web-client/src/presenter/presenter-public.ts | 2 + web-client/src/presenter/presenter.ts | 2 + .../sequences/Login/submitLoginSequence.ts | 8 + .../sequences/changePasswordLocalSequence.ts | 2 +- web-client/src/views/AppComponent.tsx | 4 +- web-client/src/views/Public/Login/Login.tsx | 137 +++++++++++------- 6 files changed, 97 insertions(+), 58 deletions(-) create mode 100644 web-client/src/presenter/sequences/Login/submitLoginSequence.ts diff --git a/web-client/src/presenter/presenter-public.ts b/web-client/src/presenter/presenter-public.ts index 90b7b26cb8e..ba7867ec6ac 100644 --- a/web-client/src/presenter/presenter-public.ts +++ b/web-client/src/presenter/presenter-public.ts @@ -38,6 +38,7 @@ import { showMaintenancePageDecorator } from './utilities/showMaintenancePageDec import { showMoreResultsSequence } from './sequences/showMoreResultsSequence'; import { sortTodaysOrdersSequence } from './sequences/Public/sortTodaysOrdersSequence'; import { submitCreatePetitionerAccountFormSequence } from '@web-client/presenter/sequences/submitCreatePetitionerAccountFormSequence'; +import { submitLoginSequence } from '@web-client/presenter/sequences/Login/submitLoginSequence'; import { submitPublicCaseAdvancedSearchSequence } from './sequences/Public/submitPublicCaseAdvancedSearchSequence'; import { submitPublicCaseDocketNumberSearchSequence } from './sequences/Public/submitPublicCaseDocketNumberSearchSequence'; import { submitPublicOpinionAdvancedSearchSequence } from './sequences/Public/submitPublicOpinionAdvancedSearchSequence'; @@ -106,6 +107,7 @@ export const presenterSequences = { showMoreResultsSequence, sortTodaysOrdersSequence, submitCreatePetitionerAccountFormSequence, + submitLoginSequence, submitPublicCaseAdvancedSearchSequence, submitPublicCaseDocketNumberSearchSequence, submitPublicOpinionAdvancedSearchSequence, diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 8c80fe75502..15c96a73176 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -416,6 +416,7 @@ import { submitExternalDocumentSequence } from './sequences/submitExternalDocume import { submitFilePetitionSequence } from './sequences/submitFilePetitionSequence'; import { submitJudgeActivityReportSequence } from './sequences/JudgeActivityReport/submitJudgeActivityReportSequence'; import { submitLocalLoginSequence } from './sequences/submitLocalLoginSequence'; +import { submitLoginSequence } from '@web-client/presenter/sequences/Login/submitLoginSequence'; import { submitOpinionAdvancedSearchSequence } from './sequences/submitOpinionAdvancedSearchSequence'; import { submitOrderAdvancedSearchSequence } from './sequences/submitOrderAdvancedSearchSequence'; import { submitPaperFilingSequence } from './sequences/submitPaperFilingSequence'; @@ -1252,6 +1253,7 @@ export const presenterSequences = { submitJudgeActivityReportSequence: submitJudgeActivityReportSequence as unknown as Function, submitLocalLoginSequence: submitLocalLoginSequence as unknown as Function, + submitLoginSequence, submitOpinionAdvancedSearchSequence: submitOpinionAdvancedSearchSequence as unknown as Function, submitOrderAdvancedSearchSequence: diff --git a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts new file mode 100644 index 00000000000..2e8828af3c0 --- /dev/null +++ b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts @@ -0,0 +1,8 @@ +import { state } from '@web-client/presenter/app-public.cerebral'; + +export const submitLoginSequence = [ + ({ get }) => { + console.log('in submitLoginSequence'); + console.log(get(state.form)); + }, +] as unknown as (props) => void; diff --git a/web-client/src/presenter/sequences/changePasswordLocalSequence.ts b/web-client/src/presenter/sequences/changePasswordLocalSequence.ts index 19c1d1194ff..7f05f3d8860 100644 --- a/web-client/src/presenter/sequences/changePasswordLocalSequence.ts +++ b/web-client/src/presenter/sequences/changePasswordLocalSequence.ts @@ -1,5 +1,5 @@ import { changePasswordLocalAction } from '../actions/changePasswordLocalAction'; -import { gotoLoginSequence } from './gotoLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { setAlertSuccessAction } from '../actions/setAlertSuccessAction'; import { setSaveAlertsForNavigationAction } from '../actions/setSaveAlertsForNavigationAction'; import { showProgressSequenceDecorator } from '../utilities/showProgressSequenceDecorator'; diff --git a/web-client/src/views/AppComponent.tsx b/web-client/src/views/AppComponent.tsx index 78bb772d868..fb9d70bff5f 100644 --- a/web-client/src/views/AppComponent.tsx +++ b/web-client/src/views/AppComponent.tsx @@ -56,7 +56,7 @@ import { IdleLogout } from './IdleLogout'; import { Interstitial } from './Interstitial'; import { JudgeActivityReport } from './JudgeActivityReport/JudgeActivityReport'; import { Loading } from './Loading'; -import { LogIn } from './LogIn'; +import { Login } from '@web-client/views/Public/Login/Login'; import { MessageDetail } from './Messages/MessageDetail'; import { Messages } from './Messages/Messages'; import { MyAccount } from './MyAccount'; @@ -150,7 +150,7 @@ const pages = { Interstitial, JudgeActivityReport, Loading, - LogIn, + Login, MessageDetail, Messages, MyAccount, diff --git a/web-client/src/views/Public/Login/Login.tsx b/web-client/src/views/Public/Login/Login.tsx index 9cd0351f0e7..f75a6041888 100644 --- a/web-client/src/views/Public/Login/Login.tsx +++ b/web-client/src/views/Public/Login/Login.tsx @@ -1,63 +1,90 @@ import { Button } from '@web-client/ustc-ui/Button/Button'; -import { connect } from '@cerebral/react'; +import { connect } from '@web-client/presenter/shared.cerebral'; +import { sequences, state } from '@web-client/presenter/app-public.cerebral'; import React from 'react'; -export const Login = connect({}, () => { - return ( - <> -
-
-
-

Log in to DAWSON

- Email address and password are case sensitive. -
- - - - - - -
-
- -
-
- Don't have an account?{' '} - +export const Login = connect( + { + form: state.form, + submitLoginSequence: sequences.submitLoginSequence, + updateFormValueSequence: sequences.updateFormValueSequence, + }, + ({ form, submitLoginSequence, updateFormValueSequence }) => { + return ( + <> +
+
+
+

Log in to DAWSON

+ Email address and password are case sensitive. +
+ + { + updateFormValueSequence({ + key: e.target.name, + value: e.target.value, + }); + }} + /> + + { + updateFormValueSequence({ + key: e.target.name, + value: e.target.value, + }); + }} + /> + + +
+
+ +
+
+ Don't have an account?{' '} + +
-
- - ); -}); + + ); + }, +); Login.displayName = 'Login'; From e89c54335b84855c6ca6316a39e2c20a215a3869 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Fri, 8 Dec 2023 10:18:28 -0700 Subject: [PATCH 019/700] 10007: WIP save --- .cognito/db/local_2pHzece7.json | 3 +- web-client/src/applicationContextPublic.ts | 3 ++ .../sequences/Login/submitLoginSequence.ts | 31 +++++++++++++++++-- web-client/src/views/Public/Login/Login.tsx | 5 ++- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/.cognito/db/local_2pHzece7.json b/.cognito/db/local_2pHzece7.json index 84114ffeda4..7d6ea17f430 100644 --- a/.cognito/db/local_2pHzece7.json +++ b/.cognito/db/local_2pHzece7.json @@ -59,7 +59,8 @@ "UserCreateDate": "2023-01-24T23:54:42.392Z", "UserLastModifiedDate": "2023-02-21T18:41:41.466Z", "RefreshTokens": [ - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiaWF0IjoxNjc0NjA3NjUxLCJqdGkiOiI2YTFlNDJjMy03YjQ1LTQ2YzQtYThjNy1mNmQzYzc0ZjJiZGYiLCJleHAiOjE2NzUyMTI0NTEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyOS9sb2NhbF8ycEh6ZWNlNyJ9.BzhL5QDiMCwQNnrFCxcOses-vXAmZ_OsHaGTiI-zlcKRue4Qrqe3nC4HeCjqMEAe-VYjiU3rfw5yColhATG0ng41G2blGvmhMFqsqfQDV0XbISJFaE25OwmVzUegnTVXBMBu5H7UKZSHuivmbznh_Zb6dcZ1Rt3OEZuQOxjP9B0qDRj6M0T3wLfNcIWOjQCZWKM4ZgGmQUiwWOsiDkJWgp1LmAOmukie_SdDyLO6xUbJnrKBFYzGJaEECgkAevBI9kFgZ9eN4E9ineZN8S8U71ClTpyOQ4bZ5PeQdeKmDYlyB0truKEv-sh-WwJtUYvvXMqLns6nSXuw_Oq3Mb3vmg" + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiaWF0IjoxNjc0NjA3NjUxLCJqdGkiOiI2YTFlNDJjMy03YjQ1LTQ2YzQtYThjNy1mNmQzYzc0ZjJiZGYiLCJleHAiOjE2NzUyMTI0NTEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyOS9sb2NhbF8ycEh6ZWNlNyJ9.BzhL5QDiMCwQNnrFCxcOses-vXAmZ_OsHaGTiI-zlcKRue4Qrqe3nC4HeCjqMEAe-VYjiU3rfw5yColhATG0ng41G2blGvmhMFqsqfQDV0XbISJFaE25OwmVzUegnTVXBMBu5H7UKZSHuivmbznh_Zb6dcZ1Rt3OEZuQOxjP9B0qDRj6M0T3wLfNcIWOjQCZWKM4ZgGmQUiwWOsiDkJWgp1LmAOmukie_SdDyLO6xUbJnrKBFYzGJaEECgkAevBI9kFgZ9eN4E9ineZN8S8U71ClTpyOQ4bZ5PeQdeKmDYlyB0truKEv-sh-WwJtUYvvXMqLns6nSXuw_Oq3Mb3vmg", + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoicGV0aXRpb25lckBleGFtcGxlLmNvbSIsImVtYWlsIjoicGV0aXRpb25lckBleGFtcGxlLmNvbSIsImlhdCI6MTcwMjA1NTc5NCwianRpIjoiNTI2OTI4N2QtNmRiNy00OWMwLTgzYzItYWQyNTgxNzE4Mzc3IiwiZXhwIjoxNzAyNjYwNTk0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkyMjkvbG9jYWxfMnBIemVjZTcifQ.wPElGk14XyDcq2HMx6tEvOs1Ht62Xyca508hE85f8M9WOZfTGWBZOH3VfgoTvo-Bjz3IdtSRHRASviP8gtttubHT-bQ4EraGzZ1yKBJ6bD0JPK-zudq0HSDUZGO73f96y479gPQb6EgmlgveqMVv1vvSUcNfHOon2U_56JzxHto9AIk_F6EQWTUZdOJLMosY6HmcXpGNstKaSMeg08Zvf9I7zeadnLVoucxwT17PWZVZHKrBdM72q5JUB9CUfzZiquDm8C3dXIoYu9vBaiHzeFolhv-CNF1ZBLQx3l1a7ul_VAoBn5_637GjB75LDscRsXET6Uibc99645RH3VY05A" ] }, "petitioner1@example.com": { diff --git a/web-client/src/applicationContextPublic.ts b/web-client/src/applicationContextPublic.ts index e12c62b9bbf..52f1097d375 100644 --- a/web-client/src/applicationContextPublic.ts +++ b/web-client/src/applicationContextPublic.ts @@ -164,6 +164,9 @@ const applicationContextPublic = { return process.env.API_URL || 'http://localhost:5000'; }, getCaseTitle: Case.getCaseTitle, + getCognitoClientId: () => { + return process.env.COGNITO_CLIENT_ID || 'bvjrggnd3co403c0aahscinne'; + }, getCognitoRequestPasswordResetUrl, getConstants: () => frozenConstants, getCurrentUser: () => ({}), diff --git a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts index 2e8828af3c0..0a3bb7e7812 100644 --- a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts @@ -1,8 +1,35 @@ +import { CognitoIdentityServiceProvider } from 'aws-sdk'; import { state } from '@web-client/presenter/app-public.cerebral'; export const submitLoginSequence = [ - ({ get }) => { + async ({ applicationContext, get }: ActionProps) => { + const { email, password } = get(state.form); console.log('in submitLoginSequence'); - console.log(get(state.form)); + console.log(email, password); + + // Call Cognito + const cognito = new CognitoIdentityServiceProvider({ + endpoint: 'http://localhost:9229/', + httpOptions: { + connectTimeout: 3000, + timeout: 5000, + }, + maxRetries: 3, + region: 'local', + }); + + const result = await cognito + .initiateAuth({ + AuthFlow: 'USER_PASSWORD_AUTH', + AuthParameters: { + PASSWORD: password, + USERNAME: email, + }, + ClientId: applicationContext.getCognitoClientId(), + }) + .promise(); + + console.log('result from cognito: ', result); + // Call some endpoint to get token & refresh token }, ] as unknown as (props) => void; diff --git a/web-client/src/views/Public/Login/Login.tsx b/web-client/src/views/Public/Login/Login.tsx index f75a6041888..8b22f180ad8 100644 --- a/web-client/src/views/Public/Login/Login.tsx +++ b/web-client/src/views/Public/Login/Login.tsx @@ -63,7 +63,10 @@ export const Login = connect( From 8ffb14a4d6215c05fd44a78c1b5e16e30f88227f Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 8 Dec 2023 10:18:20 -0800 Subject: [PATCH 020/700] 10007: redirect to auth site on login --- web-client/src/applicationContextPublic.ts | 3 --- .../sequences/Login/submitLoginSequence.ts | 27 ++++++++++--------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/web-client/src/applicationContextPublic.ts b/web-client/src/applicationContextPublic.ts index 52f1097d375..e12c62b9bbf 100644 --- a/web-client/src/applicationContextPublic.ts +++ b/web-client/src/applicationContextPublic.ts @@ -164,9 +164,6 @@ const applicationContextPublic = { return process.env.API_URL || 'http://localhost:5000'; }, getCaseTitle: Case.getCaseTitle, - getCognitoClientId: () => { - return process.env.COGNITO_CLIENT_ID || 'bvjrggnd3co403c0aahscinne'; - }, getCognitoRequestPasswordResetUrl, getConstants: () => frozenConstants, getCurrentUser: () => ({}), diff --git a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts index 0a3bb7e7812..502057cfc3a 100644 --- a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts @@ -1,23 +1,22 @@ import { CognitoIdentityServiceProvider } from 'aws-sdk'; import { state } from '@web-client/presenter/app-public.cerebral'; +const cognito = new CognitoIdentityServiceProvider({ + endpoint: 'http://localhost:9229/', + httpOptions: { + connectTimeout: 3000, + timeout: 5000, + }, + maxRetries: 3, + region: 'local', +}); + export const submitLoginSequence = [ - async ({ applicationContext, get }: ActionProps) => { + async ({ get, router }) => { const { email, password } = get(state.form); console.log('in submitLoginSequence'); console.log(email, password); - // Call Cognito - const cognito = new CognitoIdentityServiceProvider({ - endpoint: 'http://localhost:9229/', - httpOptions: { - connectTimeout: 3000, - timeout: 5000, - }, - maxRetries: 3, - region: 'local', - }); - const result = await cognito .initiateAuth({ AuthFlow: 'USER_PASSWORD_AUTH', @@ -25,9 +24,11 @@ export const submitLoginSequence = [ PASSWORD: password, USERNAME: email, }, - ClientId: applicationContext.getCognitoClientId(), + ClientId: 'bvjrggnd3co403c0aahscinne', }) .promise(); + const accessToken = result.AuthenticationResult?.AccessToken; + router.externalRoute(`http://localhost:1234/log-in?token=${accessToken}`); console.log('result from cognito: ', result); // Call some endpoint to get token & refresh token From 0d8fd7a25904b628efeb0dbf10869974b46dc8b8 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 8 Dec 2023 12:34:34 -0800 Subject: [PATCH 021/700] 10007: Use idToken to authenticate users --- .cognito/db/local_2pHzece7.json | 113 ++++++------------ .../sequences/Login/submitLoginSequence.ts | 4 +- 2 files changed, 38 insertions(+), 79 deletions(-) diff --git a/.cognito/db/local_2pHzece7.json b/.cognito/db/local_2pHzece7.json index 7d6ea17f430..fdf52a1d21d 100644 --- a/.cognito/db/local_2pHzece7.json +++ b/.cognito/db/local_2pHzece7.json @@ -29,6 +29,37 @@ "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiaWF0IjoxNjc0NjA3NjUxLCJqdGkiOiI2YTFlNDJjMy03YjQ1LTQ2YzQtYThjNy1mNmQzYzc0ZjJiZGYiLCJleHAiOjE2NzUyMTI0NTEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyOS9sb2NhbF8ycEh6ZWNlNyJ9.BzhL5QDiMCwQNnrFCxcOses-vXAmZ_OsHaGTiI-zlcKRue4Qrqe3nC4HeCjqMEAe-VYjiU3rfw5yColhATG0ng41G2blGvmhMFqsqfQDV0XbISJFaE25OwmVzUegnTVXBMBu5H7UKZSHuivmbznh_Zb6dcZ1Rt3OEZuQOxjP9B0qDRj6M0T3wLfNcIWOjQCZWKM4ZgGmQUiwWOsiDkJWgp1LmAOmukie_SdDyLO6xUbJnrKBFYzGJaEECgkAevBI9kFgZ9eN4E9ineZN8S8U71ClTpyOQ4bZ5PeQdeKmDYlyB0truKEv-sh-WwJtUYvvXMqLns6nSXuw_Oq3Mb3vmg" ] }, + "docketclerk1@example.com": { + "Username": "docketclerk1@example.com", + "Password": "Pa$$word!", + "Attributes": [ + { + "Name": "sub", + "Value": "2805d1ab-18d0-43ec-bafb-654e83405416" + }, + { + "Name": "custom:userId", + "Value": "2805d1ab-18d0-43ec-bafb-654e83405416" + }, + { + "Name": "email", + "Value": "docketclerk1@example.com" + }, + { + "Name": "email_verified", + "Value": "True" + }, + { + "Name": "custom:role", + "Value": "docketclerk" + } + ], + "Enabled": false, + "UserStatus": "CONFIRMED", + "UserCreateDate": "2023-01-24T23:54:42.392Z", + "UserLastModifiedDate": "2023-02-21T18:41:41.466Z", + "RefreshTokens": [] + }, "petitioner@example.com": { "Username": "petitioner@example.com", "Password": "Pa$$word!", @@ -59,8 +90,7 @@ "UserCreateDate": "2023-01-24T23:54:42.392Z", "UserLastModifiedDate": "2023-02-21T18:41:41.466Z", "RefreshTokens": [ - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiaWF0IjoxNjc0NjA3NjUxLCJqdGkiOiI2YTFlNDJjMy03YjQ1LTQ2YzQtYThjNy1mNmQzYzc0ZjJiZGYiLCJleHAiOjE2NzUyMTI0NTEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyOS9sb2NhbF8ycEh6ZWNlNyJ9.BzhL5QDiMCwQNnrFCxcOses-vXAmZ_OsHaGTiI-zlcKRue4Qrqe3nC4HeCjqMEAe-VYjiU3rfw5yColhATG0ng41G2blGvmhMFqsqfQDV0XbISJFaE25OwmVzUegnTVXBMBu5H7UKZSHuivmbznh_Zb6dcZ1Rt3OEZuQOxjP9B0qDRj6M0T3wLfNcIWOjQCZWKM4ZgGmQUiwWOsiDkJWgp1LmAOmukie_SdDyLO6xUbJnrKBFYzGJaEECgkAevBI9kFgZ9eN4E9ineZN8S8U71ClTpyOQ4bZ5PeQdeKmDYlyB0truKEv-sh-WwJtUYvvXMqLns6nSXuw_Oq3Mb3vmg", - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoicGV0aXRpb25lckBleGFtcGxlLmNvbSIsImVtYWlsIjoicGV0aXRpb25lckBleGFtcGxlLmNvbSIsImlhdCI6MTcwMjA1NTc5NCwianRpIjoiNTI2OTI4N2QtNmRiNy00OWMwLTgzYzItYWQyNTgxNzE4Mzc3IiwiZXhwIjoxNzAyNjYwNTk0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkyMjkvbG9jYWxfMnBIemVjZTcifQ.wPElGk14XyDcq2HMx6tEvOs1Ht62Xyca508hE85f8M9WOZfTGWBZOH3VfgoTvo-Bjz3IdtSRHRASviP8gtttubHT-bQ4EraGzZ1yKBJ6bD0JPK-zudq0HSDUZGO73f96y479gPQb6EgmlgveqMVv1vvSUcNfHOon2U_56JzxHto9AIk_F6EQWTUZdOJLMosY6HmcXpGNstKaSMeg08Zvf9I7zeadnLVoucxwT17PWZVZHKrBdM72q5JUB9CUfzZiquDm8C3dXIoYu9vBaiHzeFolhv-CNF1ZBLQx3l1a7ul_VAoBn5_637GjB75LDscRsXET6Uibc99645RH3VY05A" + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiaWF0IjoxNjc0NjA3NjUxLCJqdGkiOiI2YTFlNDJjMy03YjQ1LTQ2YzQtYThjNy1mNmQzYzc0ZjJiZGYiLCJleHAiOjE2NzUyMTI0NTEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyOS9sb2NhbF8ycEh6ZWNlNyJ9.BzhL5QDiMCwQNnrFCxcOses-vXAmZ_OsHaGTiI-zlcKRue4Qrqe3nC4HeCjqMEAe-VYjiU3rfw5yColhATG0ng41G2blGvmhMFqsqfQDV0XbISJFaE25OwmVzUegnTVXBMBu5H7UKZSHuivmbznh_Zb6dcZ1Rt3OEZuQOxjP9B0qDRj6M0T3wLfNcIWOjQCZWKM4ZgGmQUiwWOsiDkJWgp1LmAOmukie_SdDyLO6xUbJnrKBFYzGJaEECgkAevBI9kFgZ9eN4E9ineZN8S8U71ClTpyOQ4bZ5PeQdeKmDYlyB0truKEv-sh-WwJtUYvvXMqLns6nSXuw_Oq3Mb3vmg" ] }, "petitioner1@example.com": { @@ -93,7 +123,8 @@ "UserCreateDate": "2023-01-24T23:54:42.392Z", "UserLastModifiedDate": "2023-02-21T18:41:41.466Z", "RefreshTokens": [ - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiaWF0IjoxNjc0NjA3NjUxLCJqdGkiOiI2YTFlNDJjMy03YjQ1LTQ2YzQtYThjNy1mNmQzYzc0ZjJiZGYiLCJleHAiOjE2NzUyMTI0NTEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyOS9sb2NhbF8ycEh6ZWNlNyJ9.BzhL5QDiMCwQNnrFCxcOses-vXAmZ_OsHaGTiI-zlcKRue4Qrqe3nC4HeCjqMEAe-VYjiU3rfw5yColhATG0ng41G2blGvmhMFqsqfQDV0XbISJFaE25OwmVzUegnTVXBMBu5H7UKZSHuivmbznh_Zb6dcZ1Rt3OEZuQOxjP9B0qDRj6M0T3wLfNcIWOjQCZWKM4ZgGmQUiwWOsiDkJWgp1LmAOmukie_SdDyLO6xUbJnrKBFYzGJaEECgkAevBI9kFgZ9eN4E9ineZN8S8U71ClTpyOQ4bZ5PeQdeKmDYlyB0truKEv-sh-WwJtUYvvXMqLns6nSXuw_Oq3Mb3vmg" + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiaWF0IjoxNjc0NjA3NjUxLCJqdGkiOiI2YTFlNDJjMy03YjQ1LTQ2YzQtYThjNy1mNmQzYzc0ZjJiZGYiLCJleHAiOjE2NzUyMTI0NTEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyOS9sb2NhbF8ycEh6ZWNlNyJ9.BzhL5QDiMCwQNnrFCxcOses-vXAmZ_OsHaGTiI-zlcKRue4Qrqe3nC4HeCjqMEAe-VYjiU3rfw5yColhATG0ng41G2blGvmhMFqsqfQDV0XbISJFaE25OwmVzUegnTVXBMBu5H7UKZSHuivmbznh_Zb6dcZ1Rt3OEZuQOxjP9B0qDRj6M0T3wLfNcIWOjQCZWKM4ZgGmQUiwWOsiDkJWgp1LmAOmukie_SdDyLO6xUbJnrKBFYzGJaEECgkAevBI9kFgZ9eN4E9ineZN8S8U71ClTpyOQ4bZ5PeQdeKmDYlyB0truKEv-sh-WwJtUYvvXMqLns6nSXuw_Oq3Mb3vmg", + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoicGV0aXRpb25lcjFAZXhhbXBsZS5jb20iLCJlbWFpbCI6InBldGl0aW9uZXIxQGV4YW1wbGUuY29tIiwiaWF0IjoxNzAyMDY2OTA2LCJqdGkiOiJiNTcwMGRlYy01OTI3LTQ5ODktYjhmYy0xNGY0YjNjMDU0M2YiLCJleHAiOjE3MDI2NzE3MDYsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyOS9sb2NhbF8ycEh6ZWNlNyJ9.W3sIoVhybGPSfgRKNBiiGf1JMEM8Epnevz_Vu7NDzo-tnIY_8n6RqLmV8AA2Dw41ysWf2OHZiJmNVvZfVVuHdIlxladsfK7LRDMOy9GBeXhd6QN-lA-KRfq2XpQ7edkkp21YH3IB1yFcdAose2e-HUxAuXk3rLs1CIZhiilsrJrhqTVqzqcXyFyoPSLIf2stFCxvnuxkFx9EqBi5_m6bcuGDsA-svFiSiTe8kNZXMofGnFlLBBfSx6VFWxK1DsQja4AQwlA34c4J5np7AmOE7yvWmyLfkKwIbTHQm7In49xXbujxkQQeBJKoXP2vl8-7W0r5tEiT35TF_iBCIlxWAw" ] }, "petitioner2@example.com": { @@ -491,76 +522,6 @@ "RefreshTokens": [ "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2duaXRvOnVzZXJuYW1lIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiaWF0IjoxNjc0NjA3NjUxLCJqdGkiOiI2YTFlNDJjMy03YjQ1LTQ2YzQtYThjNy1mNmQzYzc0ZjJiZGYiLCJleHAiOjE2NzUyMTI0NTEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyOS9sb2NhbF8ycEh6ZWNlNyJ9.BzhL5QDiMCwQNnrFCxcOses-vXAmZ_OsHaGTiI-zlcKRue4Qrqe3nC4HeCjqMEAe-VYjiU3rfw5yColhATG0ng41G2blGvmhMFqsqfQDV0XbISJFaE25OwmVzUegnTVXBMBu5H7UKZSHuivmbznh_Zb6dcZ1Rt3OEZuQOxjP9B0qDRj6M0T3wLfNcIWOjQCZWKM4ZgGmQUiwWOsiDkJWgp1LmAOmukie_SdDyLO6xUbJnrKBFYzGJaEECgkAevBI9kFgZ9eN4E9ineZN8S8U71ClTpyOQ4bZ5PeQdeKmDYlyB0truKEv-sh-WwJtUYvvXMqLns6nSXuw_Oq3Mb3vmg" ] - }, - "new0.4011072087502434@example.com": { - "Username": "new0.4011072087502434@example.com", - "Password": "123456", - "Attributes": [ - { - "Name": "sub", - "Value": "a835229d-b8da-4c2a-b078-d5d49ae83742" - }, - { - "Name": "email_verified", - "Value": "True" - }, - { - "Name": "email", - "Value": "new0.4011072087502434@example.com" - }, - { - "Name": "custom:role", - "Value": "petitioner" - }, - { - "Name": "name", - "Value": "Mona Schultz" - }, - { - "Name": "custom:userId", - "Value": "d3e1941f-230a-47bb-80ec-6b561c1765cd" - } - ], - "Enabled": true, - "UserStatus": "FORCE_CHANGE_PASSWORD", - "UserCreateDate": "2023-12-06T23:16:39.598Z", - "UserLastModifiedDate": "2023-12-06T23:16:39.598Z", - "RefreshTokens": [] - }, - "new0.9537567565459484@example.com": { - "Username": "new0.9537567565459484@example.com", - "Password": "123456", - "Attributes": [ - { - "Name": "sub", - "Value": "de5433db-7f7c-43d8-8400-05a8fec34438" - }, - { - "Name": "email_verified", - "Value": "True" - }, - { - "Name": "email", - "Value": "new0.9537567565459484@example.com" - }, - { - "Name": "custom:role", - "Value": "petitioner" - }, - { - "Name": "name", - "Value": "Mona Schultz" - }, - { - "Name": "custom:userId", - "Value": "d3e1941f-230a-47bb-80ec-6b561c1765cd" - } - ], - "Enabled": true, - "UserStatus": "FORCE_CHANGE_PASSWORD", - "UserCreateDate": "2023-12-06T23:21:55.294Z", - "UserLastModifiedDate": "2023-12-06T23:21:55.294Z", - "RefreshTokens": [] } }, "Options": { @@ -670,13 +631,11 @@ "AllowAdminCreateUserOnly": false, "UnusedAccountValidityDays": 7 }, - "UsernameAttributes": [ - "email" - ], + "UsernameAttributes": ["email"], "Arn": "arn:aws:cognito-idp:local:local:userpool/local_2pHzece7", "CreationDate": "2023-01-24T22:34:48.100Z", "Id": "local_2pHzece7", "LastModifiedDate": "2023-01-24T22:34:48.100Z", "Name": "MyUserPool" } -} \ No newline at end of file +} diff --git a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts index 502057cfc3a..5a38d3d86e1 100644 --- a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts @@ -27,8 +27,8 @@ export const submitLoginSequence = [ ClientId: 'bvjrggnd3co403c0aahscinne', }) .promise(); - const accessToken = result.AuthenticationResult?.AccessToken; - router.externalRoute(`http://localhost:1234/log-in?token=${accessToken}`); + const idToken = result.AuthenticationResult?.IdToken; + router.externalRoute(`http://localhost:1234/log-in?token=${idToken}`); console.log('result from cognito: ', result); // Call some endpoint to get token & refresh token From 441cf1ec670363b0607504fe96cb6c55d8703eb7 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 8 Dec 2023 13:31:32 -0800 Subject: [PATCH 022/700] 10007 - WIP remove unnecessary files from previous login + auth --- .../auth/authenticateUserInteractor.test.ts | 27 ----- .../auth/authenticateUserInteractor.ts | 16 --- .../src/proxies/auth/authenticateUserProxy.ts | 22 ---- web-api/src/app.ts | 6 +- web-api/src/getPersistenceGateway.ts | 5 - web-api/src/getUseCases.ts | 2 - .../lambdas/auth/authenticateUserLambda.ts | 42 ------- .../cognito/confirmAuthCode.test.ts | 41 ------- .../persistence/cognito/confirmAuthCode.ts | 22 ---- .../confirmAuthCodeCognitoLocal.test.ts | 95 --------------- .../cognito/confirmAuthCodeCognitoLocal.ts | 68 ----------- .../cognito/confirmAuthCodeLocal.test.ts | 35 ------ .../cognito/confirmAuthCodeLocal.ts | 24 ---- ...onsClerkCreatesPractitionerAccount.test.ts | 23 ++-- .../petitionerCreatesAccount.test.ts | 18 +-- web-client/src/applicationContext.ts | 2 - .../actions/authenticateUserAction.test.ts | 114 ------------------ .../actions/authenticateUserAction.ts | 40 ------ web-client/src/presenter/presenter.ts | 5 - .../sequences/loginWithCodeSequence.test.ts | 52 -------- .../sequences/loginWithCodeSequence.ts | 41 ------- .../loginWithCognitoLocalSequence.ts | 32 ----- web-client/src/router.ts | 11 +- web-client/src/views/LogIn.tsx | 85 ------------- 24 files changed, 26 insertions(+), 802 deletions(-) delete mode 100644 shared/src/business/useCases/auth/authenticateUserInteractor.test.ts delete mode 100644 shared/src/business/useCases/auth/authenticateUserInteractor.ts delete mode 100644 shared/src/proxies/auth/authenticateUserProxy.ts delete mode 100644 web-api/src/lambdas/auth/authenticateUserLambda.ts delete mode 100644 web-api/src/persistence/cognito/confirmAuthCode.test.ts delete mode 100644 web-api/src/persistence/cognito/confirmAuthCode.ts delete mode 100644 web-api/src/persistence/cognito/confirmAuthCodeCognitoLocal.test.ts delete mode 100644 web-api/src/persistence/cognito/confirmAuthCodeCognitoLocal.ts delete mode 100644 web-api/src/persistence/cognito/confirmAuthCodeLocal.test.ts delete mode 100644 web-api/src/persistence/cognito/confirmAuthCodeLocal.ts delete mode 100644 web-client/src/presenter/actions/authenticateUserAction.test.ts delete mode 100644 web-client/src/presenter/actions/authenticateUserAction.ts delete mode 100644 web-client/src/presenter/sequences/loginWithCodeSequence.test.ts delete mode 100644 web-client/src/presenter/sequences/loginWithCodeSequence.ts delete mode 100644 web-client/src/presenter/sequences/loginWithCognitoLocalSequence.ts delete mode 100644 web-client/src/views/LogIn.tsx diff --git a/shared/src/business/useCases/auth/authenticateUserInteractor.test.ts b/shared/src/business/useCases/auth/authenticateUserInteractor.test.ts deleted file mode 100644 index 1b88764de3d..00000000000 --- a/shared/src/business/useCases/auth/authenticateUserInteractor.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { applicationContext } from '../../test/createTestApplicationContext'; -import { authenticateUserInteractor } from './authenticateUserInteractor'; - -describe('authenticateUserInteractor', () => { - const refreshTokenAndToken = { - refreshToken: 'abc', - token: '123', - }; - - beforeEach(() => { - applicationContext - .getPersistenceGateway() - .confirmAuthCode.mockReturnValue(refreshTokenAndToken); - }); - - it('attempts to hit cognito and get an id token and refresh token', async () => { - const expectedCode = 'codecode'; - const result = await authenticateUserInteractor(applicationContext, { - code: expectedCode, - }); - expect( - applicationContext.getPersistenceGateway().confirmAuthCode.mock - .calls[0][0], - ).toEqual({ applicationContext, code: expectedCode }); - expect(result).toEqual(refreshTokenAndToken); - }); -}); diff --git a/shared/src/business/useCases/auth/authenticateUserInteractor.ts b/shared/src/business/useCases/auth/authenticateUserInteractor.ts deleted file mode 100644 index 19ea0c854ba..00000000000 --- a/shared/src/business/useCases/auth/authenticateUserInteractor.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * authenticateUserInteractor - * - * @param {object} applicationContext the application context - * @param {object} auth an object - * @param {string} auth.code the OAuth2 authorization code generated by our AuthN/AuthZ provider - * @returns {Promise} the promise of both the refresh token and the auth token - */ -export const authenticateUserInteractor = async ( - applicationContext: IApplicationContext, - { code, password }: { code: string; password?: string }, -) => { - return await applicationContext - .getPersistenceGateway() - .confirmAuthCode({ applicationContext, code, password }); -}; diff --git a/shared/src/proxies/auth/authenticateUserProxy.ts b/shared/src/proxies/auth/authenticateUserProxy.ts deleted file mode 100644 index 4bd994a9563..00000000000 --- a/shared/src/proxies/auth/authenticateUserProxy.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { post } from '../requests'; - -/** - * authenticateUserInteractor - * @param {object} applicationContext the application context - * @param {object} auth the auth object - * @param {object} auth.code the OAuth2 authorization code - * @returns {Promise<*>} the promise of the api call - */ -export const authenticateUserInteractor = ( - applicationContext, - { code, password }, -) => { - return post({ - applicationContext, - body: { code, password }, - endpoint: '/auth/login', - options: { - withCredentials: true, - }, - }); -}; diff --git a/web-api/src/app.ts b/web-api/src/app.ts index 9268e248c46..4837f5898a4 100644 --- a/web-api/src/app.ts +++ b/web-api/src/app.ts @@ -12,7 +12,6 @@ import { archiveDraftDocumentLambda } from './lambdas/documents/archiveDraftDocu import { assignWorkItemsLambda } from './lambdas/workitems/assignWorkItemsLambda'; import { associateIrsPractitionerWithCaseLambda } from './lambdas/manualAssociation/associateIrsPractitionerWithCaseLambda'; import { associatePrivatePractitionerWithCaseLambda } from './lambdas/manualAssociation/associatePrivatePractitionerWithCaseLambda'; -import { authenticateUserLambda } from './lambdas/auth/authenticateUserLambda'; import { batchDownloadTrialSessionLambda } from './lambdas/trialSessions/batchDownloadTrialSessionLambda'; import { blockCaseFromTrialLambda } from './lambdas/cases/blockCaseFromTrialLambda'; import { caseAdvancedSearchLambda } from './lambdas/cases/caseAdvancedSearchLambda'; @@ -1003,10 +1002,7 @@ app.get( * Authentication/Authorization */ { - app - .route('/auth/login') - .post(lambdaWrapper(authenticateUserLambda)) - .delete(lambdaWrapper(deleteAuthCookieLambda)); + app.route('/auth/login').delete(lambdaWrapper(deleteAuthCookieLambda)); app.post('/auth/refresh', lambdaWrapper(refreshAuthTokenLambda)); } diff --git a/web-api/src/getPersistenceGateway.ts b/web-api/src/getPersistenceGateway.ts index 49e76163eef..801537bceaa 100644 --- a/web-api/src/getPersistenceGateway.ts +++ b/web-api/src/getPersistenceGateway.ts @@ -8,8 +8,6 @@ import { bulkDeleteRecords } from './persistence/elasticsearch/bulkDeleteRecords import { bulkIndexRecords } from './persistence/elasticsearch/bulkIndexRecords'; import { caseAdvancedSearch } from './persistence/elasticsearch/caseAdvancedSearch'; import { casePublicSearch as casePublicSearchPersistence } from './persistence/elasticsearch/casePublicSearch'; -import { confirmAuthCode } from './persistence/cognito/confirmAuthCode'; -import { confirmAuthCodeCognitoLocal } from '@web-api/persistence/cognito/confirmAuthCodeCognitoLocal'; import { createCase } from './persistence/dynamo/cases/createCase'; import { createCaseDeadline } from './persistence/dynamo/caseDeadlines/createCaseDeadline'; import { createCaseTrialSortMappingRecords } from './persistence/dynamo/cases/createCaseTrialSortMappingRecords'; @@ -274,9 +272,6 @@ const gatewayMethods = { advancedDocumentSearch, caseAdvancedSearch, casePublicSearch: casePublicSearchPersistence, - confirmAuthCode: process.env.IS_LOCAL - ? confirmAuthCodeCognitoLocal - : confirmAuthCode, createChangeOfAddressJob, createLock, decrementJobCounter, diff --git a/web-api/src/getUseCases.ts b/web-api/src/getUseCases.ts index c52c97da35d..6fc76552a8e 100644 --- a/web-api/src/getUseCases.ts +++ b/web-api/src/getUseCases.ts @@ -12,7 +12,6 @@ import { archiveDraftDocumentInteractor } from '../../shared/src/business/useCas import { assignWorkItemsInteractor } from '../../shared/src/business/useCases/workitems/assignWorkItemsInteractor'; import { associateIrsPractitionerWithCaseInteractor } from '../../shared/src/business/useCases/manualAssociation/associateIrsPractitionerWithCaseInteractor'; import { associatePrivatePractitionerWithCaseInteractor } from '../../shared/src/business/useCases/manualAssociation/associatePrivatePractitionerWithCaseInteractor'; -import { authenticateUserInteractor } from '../../shared/src/business/useCases/auth/authenticateUserInteractor'; import { batchDownloadTrialSessionInteractor } from '../../shared/src/business/useCases/trialSessions/batchDownloadTrialSessionInteractor'; import { blockCaseFromTrialInteractor } from '../../shared/src/business/useCases/blockCaseFromTrialInteractor'; import { caseAdvancedSearchInteractor } from '../../shared/src/business/useCases/caseAdvancedSearchInteractor'; @@ -221,7 +220,6 @@ const useCases = { assignWorkItemsInteractor, associateIrsPractitionerWithCaseInteractor, associatePrivatePractitionerWithCaseInteractor, - authenticateUserInteractor, batchDownloadTrialSessionInteractor, blockCaseFromTrialInteractor, caseAdvancedSearchInteractor, diff --git a/web-api/src/lambdas/auth/authenticateUserLambda.ts b/web-api/src/lambdas/auth/authenticateUserLambda.ts deleted file mode 100644 index 3fd5e916b1f..00000000000 --- a/web-api/src/lambdas/auth/authenticateUserLambda.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { createCookieString } from '../../utilities/cookieFormatting'; -import { genericHandler } from '../../genericHandler'; - -/** - * Sets the authentication cookie based on the OAuth code - * - * @param {object} event the AWS event object - * @returns {Promise<*|undefined>} the api gateway response object containing the statusCode, body, and headers - */ -export const authenticateUserLambda = event => - genericHandler( - event, - async ({ applicationContext }) => { - const { alertError, refreshToken, sessionId, token } = - await applicationContext - .getUseCases() - .authenticateUserInteractor( - applicationContext, - JSON.parse(event.body), - ); - const expiresAt = applicationContext.getUtilities().calculateISODate({ - dateString: applicationContext.getUtilities().createISODateString(), - howMuch: 29, - units: 'days', - }); - - return { - body: JSON.stringify({ alertError, sessionId, token }), - headers: { - 'Set-Cookie': createCookieString( - 'refreshToken', - refreshToken, - expiresAt, - process.env.EFCMS_DOMAIN, - !process.env.IS_LOCAL, - ), - }, - statusCode: 200, - }; - }, - { bypassMaintenanceCheck: true }, - ); diff --git a/web-api/src/persistence/cognito/confirmAuthCode.test.ts b/web-api/src/persistence/cognito/confirmAuthCode.test.ts deleted file mode 100644 index 732646327ab..00000000000 --- a/web-api/src/persistence/cognito/confirmAuthCode.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; -import { applicationContext } from '../../../../shared/src/business/test/createTestApplicationContext'; -import { confirmAuthCode } from './confirmAuthCode'; - -jest.mock('@aws-sdk/client-cognito-identity-provider'); - -describe('confirmAuthCode', () => { - const mockAxios = { - post: jest.fn().mockReturnValue({ - data: { - id_token: '123', - refresh_token: 'abc', - }, - }), - }; - - beforeEach(() => { - const expectedClientId = '82b35e7c-9830-4104-bb15-24a2eda7f84e'; - (CognitoIdentityProvider as jest.Mock).mockReturnValue({ - listUserPoolClients: jest.fn().mockReturnValue({ - promise: () => - Promise.resolve({ - UserPoolClients: [{ ClientId: expectedClientId }], - }), - }), - }); - - (applicationContext as any).getHttpClient = () => mockAxios; - }); - - it('returns the first clientId from the list of user pool clients', async () => { - const result = await confirmAuthCode({ applicationContext, code: 'abc' }); - - expect(mockAxios.post).toHaveBeenCalled(); - - expect(result).toEqual({ - refreshToken: 'abc', - token: '123', - }); - }); -}); diff --git a/web-api/src/persistence/cognito/confirmAuthCode.ts b/web-api/src/persistence/cognito/confirmAuthCode.ts deleted file mode 100644 index c581c5f7870..00000000000 --- a/web-api/src/persistence/cognito/confirmAuthCode.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { getClientId } from './getClientId'; - -export const confirmAuthCode = async ({ applicationContext, code }) => { - const { COGNITO_SUFFIX, EFCMS_DOMAIN, STAGE } = process.env; - - const clientId = await getClientId({ userPoolId: process.env.USER_POOL_ID }); - - const response = await applicationContext.getHttpClient().post( - `https://auth-${STAGE}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/oauth2/token`, - new URLSearchParams({ - client_id: clientId, - code, - grant_type: 'authorization_code', - redirect_uri: `https://app.${EFCMS_DOMAIN}/log-in`, - }), - ); - - return { - refreshToken: response.data.refresh_token, - token: response.data.id_token, - }; -}; diff --git a/web-api/src/persistence/cognito/confirmAuthCodeCognitoLocal.test.ts b/web-api/src/persistence/cognito/confirmAuthCodeCognitoLocal.test.ts deleted file mode 100644 index e7a810459cc..00000000000 --- a/web-api/src/persistence/cognito/confirmAuthCodeCognitoLocal.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { applicationContext } from '../../../../shared/src/business/test/createTestApplicationContext'; -import { confirmAuthCodeCognitoLocal } from './confirmAuthCodeCognitoLocal'; -import { sign } from 'jsonwebtoken'; - -jest.mock('jsonwebtoken'); - -describe('confirmAuthCodeCognitoLocal', () => { - const AuthenticationResult = { - IdToken: '123', - }; - const loginInfo = { - code: 'userName', - password: 'password', - }; - - beforeAll(() => { - applicationContext.getCognito().initiateAuth.mockReturnValue({ - promise: () => { - return { AuthenticationResult }; - }, - }); - }); - - it('returns a token with the login if login is valid', async () => { - await confirmAuthCodeCognitoLocal({ - applicationContext, - code: 'docketclerk1@example.com', - }); - - expect(sign).toHaveBeenCalled(); - - expect(sign.mock.calls[0][0]).toEqual({ - 'custom:role': 'docketclerk', - email: 'docketclerk1@example.com', - name: 'Test Docketclerk1', - sub: '2805d1ab-18d0-43ec-bafb-654e83405416', - userId: '2805d1ab-18d0-43ec-bafb-654e83405416', - }); - }); - - it('returns an alertError when the login is invalid', async () => { - applicationContext.getCognito().initiateAuth.mockReturnValueOnce({ - promise: () => { - throw new Error('User not authorized.'); - }, - }); - const result = await confirmAuthCodeCognitoLocal({ - applicationContext, - code: 'not a valid login', - }); - - expect(result).toMatchObject({ - alertError: { - message: 'User not authorized.', - title: 'User not authorized.', - }, - }); - }); - - it('calls cognitoLocal initiateAuth when user is not found in usermap', async () => { - const result = await confirmAuthCodeCognitoLocal({ - applicationContext, - ...loginInfo, - }); - expect(applicationContext.getCognito().initiateAuth).toHaveBeenCalled(); - expect(result).toMatchObject({ - refreshToken: '123', - token: '123', - }); - }); - - it('returns an alert with authentication challenge information when password must be reset', async () => { - applicationContext.getCognito().initiateAuth.mockReturnValueOnce({ - promise: () => { - return { - ChallengeName: 'NEW_PASSWORD_REQUIRED', - Session: 'abc123', - }; - }, - }); - - const result = await confirmAuthCodeCognitoLocal({ - applicationContext, - ...loginInfo, - }); - expect(applicationContext.getCognito().initiateAuth).toHaveBeenCalled(); - expect(result).toMatchObject({ - alertError: { - message: 'NEW_PASSWORD_REQUIRED', - sessionId: 'abc123', - title: 'NEW_PASSWORD_REQUIRED', - }, - }); - }); -}); diff --git a/web-api/src/persistence/cognito/confirmAuthCodeCognitoLocal.ts b/web-api/src/persistence/cognito/confirmAuthCodeCognitoLocal.ts deleted file mode 100644 index 6f156212550..00000000000 --- a/web-api/src/persistence/cognito/confirmAuthCodeCognitoLocal.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { sign } from 'jsonwebtoken'; -import { userMap } from '../../../../shared/src/test/mockUserTokenMap'; - -export const confirmAuthCodeCognitoLocal = async ({ - applicationContext, - code, - password, -}: { - applicationContext: IApplicationContext; - code: string; - password?: string; -}) => { - // fallback to allow current local user to be assumed - if (userMap[code.toLowerCase()]) { - const user = { - ...userMap[code.toLowerCase()], - sub: userMap[code.toLowerCase()].userId, - }; - const token = sign(user, 'secret'); - return { - refreshToken: token, - token, - }; - } - - const params = { - AuthFlow: 'USER_PASSWORD_AUTH', - AuthParameters: { - PASSWORD: password, - USERNAME: code, - }, - ClientId: process.env.COGNITO_CLIENT_ID, - }; - - let result; - - try { - result = await applicationContext - .getCognito() - .initiateAuth(params) - .promise(); - } catch (e) { - return { - alertError: { - message: (e as Error).message, - title: (e as Error).message, - }, - }; - } - - if ( - result.ChallengeName && - result.ChallengeName === 'NEW_PASSWORD_REQUIRED' - ) { - return { - alertError: { - message: 'NEW_PASSWORD_REQUIRED', - sessionId: result.Session, - title: 'NEW_PASSWORD_REQUIRED', - }, - }; - } - - return { - refreshToken: result.AuthenticationResult.IdToken, - token: result.AuthenticationResult.IdToken, - }; -}; diff --git a/web-api/src/persistence/cognito/confirmAuthCodeLocal.test.ts b/web-api/src/persistence/cognito/confirmAuthCodeLocal.test.ts deleted file mode 100644 index f1504ddbbc8..00000000000 --- a/web-api/src/persistence/cognito/confirmAuthCodeLocal.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { confirmAuthCodeLocal } from './confirmAuthCodeLocal'; -import { sign } from 'jsonwebtoken'; - -jest.mock('jsonwebtoken'); - -describe('testing confirmAuthCodeLocal', () => { - it('returns a token with the login if login is valid', () => { - confirmAuthCodeLocal({ - code: 'docketclerk1@example.com', - }); - - expect(sign).toHaveBeenCalled(); - - expect(sign.mock.calls[0][0]).toEqual({ - 'custom:role': 'docketclerk', - email: 'docketclerk1@example.com', - name: 'Test Docketclerk1', - sub: '2805d1ab-18d0-43ec-bafb-654e83405416', - userId: '2805d1ab-18d0-43ec-bafb-654e83405416', - }); - }); - - it('returns an alertError when the login is invalid', () => { - const result = confirmAuthCodeLocal({ - code: 'not a valid login', - }); - - expect(result).toMatchObject({ - alertError: { - message: 'Login credentials not found.', - title: 'Login error!', - }, - }); - }); -}); diff --git a/web-api/src/persistence/cognito/confirmAuthCodeLocal.ts b/web-api/src/persistence/cognito/confirmAuthCodeLocal.ts deleted file mode 100644 index 6049c1e435d..00000000000 --- a/web-api/src/persistence/cognito/confirmAuthCodeLocal.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { sign } from 'jsonwebtoken'; -import { userMap } from '../../../../shared/src/test/mockUserTokenMap'; - -export const confirmAuthCodeLocal = ({ code }) => { - const email = code.toLowerCase(); - if (userMap[email]) { - const user = { - ...userMap[email], - sub: userMap[email].userId, - }; - const token = sign(user, 'secret'); - return { - refreshToken: token, - token, - }; - } else { - return { - alertError: { - message: 'Login credentials not found.', - title: 'Login error!', - }, - }; - } -}; diff --git a/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts b/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts index 231773bc013..6d49255d5b9 100644 --- a/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts +++ b/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts @@ -28,10 +28,11 @@ describe('Admissions clerk creates practitioner account', () => { value: standardizedTemporaryPassword, }); - await cerebralTest.runSequence('loginWithCognitoLocalSequence', { - code: emailAddress, - password: standardizedTemporaryPassword, - }); + // TODO 10007 + // await cerebralTest.runSequence('loginWithCognitoLocalSequence', { + // code: emailAddress, + // password: standardizedTemporaryPassword, + // }); await waitForLoadingComponentToHide({ cerebralTest }); @@ -49,9 +50,10 @@ describe('Admissions clerk creates practitioner account', () => { value: password, }); + // TODO 10070 await cerebralTest.runSequence('changePasswordLocalSequence'); - expect(cerebralTest.getState('currentPage')).toEqual('LogIn'); + expect(cerebralTest.getState('currentPage')).toEqual('Login'); expect(cerebralTest.getState('alertSuccess')).toMatchObject({ message: 'Password successfully changed.', @@ -68,12 +70,13 @@ describe('Admissions clerk creates practitioner account', () => { value: 'invalidPassword', }); - await cerebralTest.runSequence('loginWithCognitoLocalSequence', { - code: emailAddress, - password: 'invalidPassword', - }); + // TODO 10007: put new login sequence + // await cerebralTest.runSequence('loginWithCognitoLocalSequence', { + // code: emailAddress, + // password: 'invalidPassword', + // }); - expect(cerebralTest.getState('currentPage')).toEqual('LogIn'); + expect(cerebralTest.getState('currentPage')).toEqual('Login'); expect(cerebralTest.getState('alertError')).toEqual({ message: 'Invalid password', title: 'Invalid password', diff --git a/web-client/integration-tests/petitionerCreatesAccount.test.ts b/web-client/integration-tests/petitionerCreatesAccount.test.ts index b85a73bfac9..259324d0b68 100644 --- a/web-client/integration-tests/petitionerCreatesAccount.test.ts +++ b/web-client/integration-tests/petitionerCreatesAccount.test.ts @@ -83,10 +83,11 @@ describe('Petitioner creates new account', () => { value: password, }); - await cerebralTestPrivate.runSequence('loginWithCognitoLocalSequence', { - code: userName, - password, - }); + // TODO 10007 + // await cerebralTestPrivate.runSequence('loginWithCognitoLocalSequence', { + // code: userName, + // password, + // }); expect(cerebralTestPrivate.getState('currentPage')).toEqual( 'DashboardPetitioner', @@ -114,10 +115,11 @@ describe('Petitioner creates new account', () => { value: password, }); - await cerebralTestPrivate.runSequence('loginWithCognitoLocalSequence', { - code: updatedEmailAddress, - password, - }); + // TODO 10007 + // await cerebralTestPrivate.runSequence('loginWithCognitoLocalSequence', { + // code: updatedEmailAddress, + // password, + // }); expect(cerebralTestPrivate.getState('currentPage')).toEqual( 'DashboardPetitioner', diff --git a/web-client/src/applicationContext.ts b/web-client/src/applicationContext.ts index 2c72c190313..96fe6c0781a 100644 --- a/web-client/src/applicationContext.ts +++ b/web-client/src/applicationContext.ts @@ -46,7 +46,6 @@ import { archiveDraftDocumentInteractor } from '../../shared/src/proxies/archive import { assignWorkItemsInteractor } from '../../shared/src/proxies/workitems/assignWorkItemsProxy'; import { associateIrsPractitionerWithCaseInteractor } from '../../shared/src/proxies/manualAssociation/associateIrsPractitionerWithCaseProxy'; import { associatePrivatePractitionerWithCaseInteractor } from '../../shared/src/proxies/manualAssociation/associatePrivatePractitionerWithCaseProxy'; -import { authenticateUserInteractor } from '../../shared/src/proxies/auth/authenticateUserProxy'; import { batchDownloadTrialSessionInteractor } from '../../shared/src/proxies/trialSessions/batchDownloadTrialSessionProxy'; import { blockCaseFromTrialInteractor } from '../../shared/src/proxies/blockCaseFromTrialProxy'; import { calculateDaysElapsedSinceLastStatusChange } from '../../shared/src/business/utilities/calculateDaysElapsedSinceLastStatusChange'; @@ -390,7 +389,6 @@ const allUseCases = { assignWorkItemsInteractor, associateIrsPractitionerWithCaseInteractor, associatePrivatePractitionerWithCaseInteractor, - authenticateUserInteractor, batchDownloadTrialSessionInteractor, blockCaseFromTrialInteractor, canConsolidateInteractor, diff --git a/web-client/src/presenter/actions/authenticateUserAction.test.ts b/web-client/src/presenter/actions/authenticateUserAction.test.ts deleted file mode 100644 index 00ad386a4d0..00000000000 --- a/web-client/src/presenter/actions/authenticateUserAction.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; -import { authenticateUserAction } from './authenticateUserAction'; -import { presenter } from '../presenter-mock'; -import { runAction } from '@web-client/presenter/test.cerebral'; - -describe('authenticateUserAction', () => { - let mockYes; - let mockNo; - let mockNewPasswordRequired; - - beforeAll(() => { - mockYes = jest.fn(); - mockNo = jest.fn(); - mockNewPasswordRequired = jest.fn(); - - presenter.providers.path = { - newPasswordRequired: mockNewPasswordRequired, - no: mockNo, - yes: mockYes, - }; - - applicationContext - .getUseCases() - .authenticateUserInteractor.mockImplementation((appContext, { code }) => { - return { - token: `token-${code}`, - }; - }); - presenter.providers.applicationContext = applicationContext; - }); - - it('calls the authenticateUserInteractor with the given code from props, returns its response tokens, and calls mockYes path', async () => { - await runAction(authenticateUserAction, { - modules: { - presenter, - }, - props: { - code: '123', - }, - state: {}, - }); - - expect( - applicationContext.getUseCases().authenticateUserInteractor.mock.calls - .length, - ).toEqual(1); - - expect(mockYes.mock.calls[0][0]).toMatchObject({ - token: 'token-123', - }); - }); - - it('finds an alert error and calls mockNo path when login is invalid', async () => { - const mockAlertError = { - alertError: { - message: 'login is invalid', - title: 'invalid', - }, - }; - applicationContext - .getUseCases() - .authenticateUserInteractor.mockImplementationOnce(() => { - return mockAlertError; - }); - - await runAction(authenticateUserAction, { - modules: { - presenter, - }, - props: { - code: '123', - }, - state: {}, - }); - - expect(mockNo.mock.calls[0][0]).toMatchObject(mockAlertError); - }); - - describe('cognitoLocal', () => { - it('should prepare state for the change password form when authenticateUserInteractor returns NEW_PASSWORD_REQUIRED', async () => { - const code = 'abc@efg.com'; - const password = 'Password!'; - const sessionId = 'asd4wd2csdfsd'; - - const mockAlertError = { - alertError: { message: 'NEW_PASSWORD_REQUIRED', sessionId }, - }; - - applicationContext - .getUseCases() - .authenticateUserInteractor.mockImplementationOnce(() => { - return mockAlertError; - }); - - const { state } = await runAction(authenticateUserAction, { - modules: { - presenter, - }, - props: { - code, - password, - }, - state: {}, - }); - - expect(state.login.userEmail).toEqual(code); - expect(state.login.sessionId).toEqual(sessionId); - - expect(mockNewPasswordRequired.mock.calls[0][0]).toMatchObject({ - path: '/change-password-local', - }); - }); - }); -}); diff --git a/web-client/src/presenter/actions/authenticateUserAction.ts b/web-client/src/presenter/actions/authenticateUserAction.ts deleted file mode 100644 index 08ccd8713ad..00000000000 --- a/web-client/src/presenter/actions/authenticateUserAction.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { state } from '@web-client/presenter/app.cerebral'; - -/** - * Gets the JWT token and refresh token using the cognito authorization code. - * @param {object} providers the providers object - * @param {object} providers.applicationContext the applicationContext - * @param {Function} providers.props the cerebral props argument stream containing 'code' - * @returns {Promise} async action - */ -export const authenticateUserAction = async ({ - applicationContext, - path, - props, - store, -}: ActionProps) => { - const { code, password } = props; - - const response = await applicationContext - .getUseCases() - .authenticateUserInteractor(applicationContext, { - code, - password, - }); - - if (response.alertError) { - if (response.alertError.message === 'NEW_PASSWORD_REQUIRED') { - store.set(state.login.userEmail, code); - store.set(state.login.sessionId, response.alertError.sessionId); - - return path.newPasswordRequired({ - path: '/change-password-local', - }); - } - return path.no({ - alertError: response.alertError, - }); - } else { - return path.yes({ token: response.token }); - } -}; diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 15c96a73176..9c5977a1703 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -212,8 +212,6 @@ import { loadDefaultViewerCorrespondenceSequence } from './sequences/loadDefault import { loadMoreCaseDeadlinesSequence } from './sequences/loadMoreCaseDeadlinesSequence'; import { loadMorePendingItemsSequence } from './sequences/loadMorePendingItemsSequence'; import { loadPdfSequence } from './sequences/PDFPreviewModal/loadPdfSequence'; -import { loginWithCodeSequence } from './sequences/loginWithCodeSequence'; -import { loginWithCognitoLocalSequence } from './sequences/loginWithCognitoLocalSequence'; import { loginWithTokenSequence } from './sequences/loginWithTokenSequence'; import { navigateBackSequence } from './sequences/navigateBackSequence'; import { navigateToCaseDetailFromPaperServiceSequence } from './sequences/navigateToCaseDetailFromPaperServiceSequence'; @@ -893,9 +891,6 @@ export const presenterSequences = { loadMorePendingItemsSequence: loadMorePendingItemsSequence as unknown as Function, loadPdfSequence: loadPdfSequence as unknown as Function, - loginWithCodeSequence: loginWithCodeSequence as unknown as Function, - loginWithCognitoLocalSequence: - loginWithCognitoLocalSequence as unknown as Function, loginWithTokenSequence: loginWithTokenSequence as unknown as Function, navigateBackSequence: navigateBackSequence as unknown as Function, navigateToCaseDetailFromPaperServiceSequence: diff --git a/web-client/src/presenter/sequences/loginWithCodeSequence.test.ts b/web-client/src/presenter/sequences/loginWithCodeSequence.test.ts deleted file mode 100644 index d1fcefe431b..00000000000 --- a/web-client/src/presenter/sequences/loginWithCodeSequence.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { CerebralTest } from 'cerebral/test'; -import { ROLES } from '../../../../shared/src/business/entities/EntityConstants'; -import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; -import { loginWithCodeSequence } from '../sequences/loginWithCodeSequence'; -import { presenter } from '../presenter-mock'; - -describe('loginWithCodeSequence', () => { - let cerebralTest; - - const TOKEN = - 'eyJraWQiOiJ2U2pTa3FZVkJjVkJOWk5qZ1gzWFNzcERZSjU4QmQ3OGYrSzlDSXhtck44PSIsImFsZyI6IlJTMjU2In0.eyJhdF9oYXNoIjoiRk5mZ2tQZlVmTTBRRWtuak5Ic1lWQSIsInN1YiI6Ijc0YzA2NDBjLTljYjQtNGE0Ny04OWMyLThjOGU5YmFiMmUyNiIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAudXMtZWFzdC0xLmFtYXpvbmF3cy5jb21cL3VzLWVhc3QtMV83dVJrRjBBeG4iLCJjb2duaXRvOnVzZXJuYW1lIjoiNzRjMDY0MGMtOWNiNC00YTQ3LTg5YzItOGM4ZTliYWIyZTI2IiwiYXVkIjoiNnR1Nmoxc3R2NXVnY3V0N2Rxc3FkdXJuOHEiLCJldmVudF9pZCI6ImQ5MGRjMGJlLTZhYjYtMTFlOS04YWI2LWMzNTYyYjI5YmEwOCIsInRva2VuX3VzZSI6ImlkIiwiYXV0aF90aW1lIjoxNTU2NTY2OTE3LCJuYW1lIjoiVGVzdCBwZXRpdGlvbnNjbGVyazEiLCJleHAiOjE1NTY1NzA1MTcsImN1c3RvbTpyb2xlIjoicGV0aXRpb25zY2xlcmsiLCJpYXQiOjE1NTY1NjY5MTcsImVtYWlsIjoicGV0aXRpb25zY2xlcmsxQGV4YW1wbGUuY29tIn0.mXE2yMgVhP_wHqpohtBHHcmL5WrxXxLB2KzvNMlldLRF-WcuGHIwhL1yXuYCp1Jobi1j823nYeXhAhPF4mzQLB6weXUga3UVT1op-KENSxvpfJJvuty2AGCBcjx6j85UDtA3KE9nx-xqWJkRpVHvfTVezMMc_v3QpmVuiPyfdO1gPCDUNiMpndVrBZW6iA6ANhMsud7IHx3R9ENauoDzohJBl_Zb1O-S34J-JjhbN6_fGKguzW8Hxwb3h-WImF_qZgKsR5B5gMzvhQhMAcSjltZI7a88L2OBwbTZjggxp5RAeju6GT_zY7xC_5vpUnJka8p4NwdLJyATi2GMXTSVDg'; - const NEW_TOKEN = - 'eyJraWQiOiJ2U2pTa3FZVkJjVkJOWk5qZ1gzWFNzcERZSjU4QmQ3OGYrSzlDSXhtck44PSIsImFsZyI6IlJTMjU2In0.eyJhdF9oYXNoIjoiRk5mZ2tQZlVmTTBRRWtuak5Ic1lWQSIsInN1YiI6Ijc0YzA2NDBjLTljYjQtNGE0Ny04OWMyLThjOGU5YmFiMmUyNiIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAudXMtZWFzdC0xLmFtYXpvbmF3cy5jb21cL3VzLWVhc3QtMV83dVJrRjBBeG4iLCJjb2duaXRvOnVzZXJuYW1lIjoiNzRjMDY0MGMtOWNiNC00YTQ3LTg5YzItOGM4ZTliYWIyZTI2IiwiYXVkIjoiNnR1Nmoxc3R2NXVnY3V0N2Rxc3FkdXJuOHEiLCJldmVudF9pZCI6ImQ5MGRjMGJlLTZhYjYtMTFlOS04YWI2LWMzNTYyYjI5YmEwOCIsInRva2VuX3VzZSI6ImlkIiwiYXV0aF90aW1lIjoxNTU2NTY2OTE3LCJuYW1lIjoiVGVzdCBwZXRpdGlvbnNjbGVyazEiLCJleHAiOjE1NTY1NzA1MTcsImN1c3RvbTpyb2xlIjoicGV0aXRpb25zY2xlcmsiLCJpYXQiOjE1NTY1NjY5MTcsImVtYWlsIjoicGV0aXRpb25zY2xlcmsxQGV4YW1wbGUuY29tIn0.mXE2yMgVhP_wHqpohtBHHcmL5WrxXxLB2KzvNMlldLRF-WcuGHIwhL1yXuYCp1Jobi1j823nYeXhAhPF4mzQLB6weXUga3UVT1op-KENSxvpfJJvuty2AGCBcjx6j85UDtA3KE9nx-xqWJkRpVHvfTVezMMc_v3QpmVuiPyfdO1gPCDUNiMpndVrBZW6iA6ANhMsud7IHx3R9ENauoDzohJBl_Zb1O-S34J-JjhbN6_fGKguzW8Hxwb3h-WImF_qZgKsR5B5gMzvhQhMAcSjltZI7a88L2OBwbTZjggxp5RAeju6GT_zY7xC_5vpUnJka8p4NwdLJyATi2GMXTSVDg'; - const USER = { - role: ROLES.petitionsClerk, - }; - beforeAll(() => { - applicationContext - .getUseCases() - .authenticateUserInteractor.mockReturnValue({ - token: TOKEN, - }); - applicationContext.getUseCases().getUserInteractor.mockReturnValue(USER); - applicationContext.getUseCases().setItemInteractor.mockReturnValue(null); - - applicationContext.getUseCases().refreshTokenInteractor.mockReturnValue({ - token: TOKEN, - }); - jest.spyOn(global, 'setInterval').mockImplementation(cb => cb()); - presenter.providers.applicationContext = applicationContext; - presenter.providers.router = { - route: () => null, - }; - presenter.sequences = { - loginWithCodeSequence, - }; - cerebralTest = CerebralTest(presenter); - }); - - afterAll(() => { - jest.restoreAllMocks(); - }); - - it('should use the code to fetch the token and put it onto the store', async () => { - await cerebralTest.runSequence('loginWithCodeSequence', { - code: 'abc', - }); - expect(cerebralTest.getState('token')).toEqual(NEW_TOKEN); - expect(cerebralTest.getState('user')).toEqual(USER); - expect(cerebralTest.getState('refreshTokenInterval')).toBeDefined(); - }); -}); diff --git a/web-client/src/presenter/sequences/loginWithCodeSequence.ts b/web-client/src/presenter/sequences/loginWithCodeSequence.ts deleted file mode 100644 index 905ea2c30c6..00000000000 --- a/web-client/src/presenter/sequences/loginWithCodeSequence.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { authenticateUserAction } from '../actions/authenticateUserAction'; -import { decodeTokenAction } from '../actions/decodeTokenAction'; -import { getAllFeatureFlagsAction } from '../actions/getAllFeatureFlagsAction'; -import { getMaintenanceModeAction } from '../actions/getMaintenanceModeAction'; -import { getUserAction } from '../actions/getUserAction'; -import { navigateToMaintenanceAction } from '../actions/navigateToMaintenanceAction'; -import { navigateToPathAction } from '../actions/navigateToPathAction'; -import { setAlertErrorAction } from '../actions/setAlertErrorAction'; -import { setTokenAction } from '../actions/setTokenAction'; -import { setUserAction } from '../actions/setUserAction'; -import { setUserPermissionsAction } from '../actions/setUserPermissionsAction'; -import { startRefreshIntervalAction } from '../actions/startRefreshIntervalAction'; - -/** - * Combine several sequences; set login value, and - * continue with other sequences used when submitting login form - * and navigating to dashboard - * - */ -export const loginWithCodeSequence = [ - authenticateUserAction, - { - no: [setAlertErrorAction], - yes: [ - decodeTokenAction, - setTokenAction, - startRefreshIntervalAction, - getMaintenanceModeAction, - { - maintenanceOff: [ - getUserAction, - setUserAction, - setUserPermissionsAction, - getAllFeatureFlagsAction, - navigateToPathAction, - ], - maintenanceOn: [navigateToMaintenanceAction], - }, - ], - }, -]; diff --git a/web-client/src/presenter/sequences/loginWithCognitoLocalSequence.ts b/web-client/src/presenter/sequences/loginWithCognitoLocalSequence.ts deleted file mode 100644 index 91d750ef2c1..00000000000 --- a/web-client/src/presenter/sequences/loginWithCognitoLocalSequence.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { authenticateUserAction } from '../actions/authenticateUserAction'; -import { clearAlertsAction } from '../actions/clearAlertsAction'; -import { decodeTokenAction } from '../actions/decodeTokenAction'; -import { getMaintenanceModeAction } from '../actions/getMaintenanceModeAction'; -import { getUserAction } from '../actions/getUserAction'; -import { navigateToMaintenanceAction } from '../actions/navigateToMaintenanceAction'; -import { navigateToPathAction } from '../actions/navigateToPathAction'; -import { setAlertErrorAction } from '../actions/setAlertErrorAction'; -import { setTokenAction } from '../actions/setTokenAction'; -import { setUserAction } from '../actions/setUserAction'; -import { setUserPermissionsAction } from '../actions/setUserPermissionsAction'; -import { showProgressSequenceDecorator } from '../utilities/showProgressSequenceDecorator'; - -export const loginWithCognitoLocalSequence = showProgressSequenceDecorator([ - authenticateUserAction, - { - newPasswordRequired: [navigateToPathAction], - no: [setAlertErrorAction], - yes: [ - decodeTokenAction, - setTokenAction, - getUserAction, - setUserAction, - setUserPermissionsAction, - getMaintenanceModeAction, - { - maintenanceOff: [clearAlertsAction, navigateToPathAction], - maintenanceOn: [navigateToMaintenanceAction], - }, - ], - }, -]); diff --git a/web-client/src/router.ts b/web-client/src/router.ts index 36e84664504..c6fdec86b8d 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -1137,15 +1137,8 @@ const router = { }); registerRoute('/log-in...', () => { - const { code, path, token } = queryStringDecoder(); - if (code) { - return app.getSequence('loginWithCodeSequence')({ - code, - path, - }); - } else { - return app.getSequence('loginWithTokenSequence')({ path, token }); - } + const { path, token } = queryStringDecoder(); + return app.getSequence('loginWithTokenSequence')({ path, token }); }); registerRoute('/login', () => { diff --git a/web-client/src/views/LogIn.tsx b/web-client/src/views/LogIn.tsx deleted file mode 100644 index f406f1991f6..00000000000 --- a/web-client/src/views/LogIn.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { connect } from '@web-client/presenter/shared.cerebral'; -import { getView } from './viewFactory'; -import { sequences } from '@web-client/presenter/app.cerebral'; -import { state } from '@web-client/presenter/app.cerebral'; -import React from 'react'; - -const ErrorNotification = getView('ErrorNotification'); -const SuccessNotification = getView('SuccessNotification'); -const Button = getView('Button'); - -export const LogIn = connect( - { - form: state.form, - loginWithCognitoLocalSequence: sequences.loginWithCognitoLocalSequence, - updateFormValueSequence: sequences.updateFormValueSequence, - }, - function LogIn({ - form, - loginWithCognitoLocalSequence, - updateFormValueSequence, - }) { - return ( -
-

Log in

- - -
{ - event.preventDefault(); - loginWithCognitoLocalSequence({ - code: form.email, - password: form.password, - }); - }} - > -
-
- - { - updateFormValueSequence({ - key: e.target.name, - value: e.target.value, - }); - }} - /> - - { - updateFormValueSequence({ - key: e.target.name, - value: e.target.value, - }); - }} - /> -
-
- -
-
- ); - }, -); - -LogIn.displayName = 'LogIn'; From 3f98b0722622a73e2b3a28033aac3b24352a216e Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 8 Dec 2023 14:35:29 -0800 Subject: [PATCH 023/700] 10007 - WIP remove Login from Private domain --- web-client/src/router.ts | 5 ----- web-client/src/views/AppComponent.tsx | 2 -- 2 files changed, 7 deletions(-) diff --git a/web-client/src/router.ts b/web-client/src/router.ts index c6fdec86b8d..2c6c58c51c1 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -1141,11 +1141,6 @@ const router = { return app.getSequence('loginWithTokenSequence')({ path, token }); }); - registerRoute('/login', () => { - setPageTitle('Login'); - app.getSequence('gotoLoginSequence')(); - }); - registerRoute( '/before-filing-a-petition', ifHasAccess({ app }, () => { diff --git a/web-client/src/views/AppComponent.tsx b/web-client/src/views/AppComponent.tsx index fb9d70bff5f..e2d7b845eb4 100644 --- a/web-client/src/views/AppComponent.tsx +++ b/web-client/src/views/AppComponent.tsx @@ -56,7 +56,6 @@ import { IdleLogout } from './IdleLogout'; import { Interstitial } from './Interstitial'; import { JudgeActivityReport } from './JudgeActivityReport/JudgeActivityReport'; import { Loading } from './Loading'; -import { Login } from '@web-client/views/Public/Login/Login'; import { MessageDetail } from './Messages/MessageDetail'; import { Messages } from './Messages/Messages'; import { MyAccount } from './MyAccount'; @@ -150,7 +149,6 @@ const pages = { Interstitial, JudgeActivityReport, Loading, - Login, MessageDetail, Messages, MyAccount, From 10ddc01ce4d7bebf8f39d8c1f0460cb60edac25a Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 8 Dec 2023 14:49:07 -0800 Subject: [PATCH 024/700] 10007 - WIP rename gotoLoginSequence navigateToLoginSequence. --- docs/frontend.md | 2 +- web-client/src/presenter/presenter-public.ts | 4 +++- web-client/src/presenter/presenter.ts | 4 ++-- .../JudgeActivityReport/gotoJudgeActivityReportSequence.ts | 4 ++-- .../presenter/sequences/Login/navigateToLoginSequence.ts | 5 +++++ .../goToLoginSequence.ts => Public/gotoLoginSequence.ts} | 0 .../src/presenter/sequences/changePasswordLocalSequence.ts | 4 ++-- .../src/presenter/sequences/confirmSignUpLocalSequence.ts | 4 ++-- .../src/presenter/sequences/goToVerificationSentSequence.ts | 4 ++-- .../sequences/gotoAddCourtIssuedDocketEntrySequence.ts | 4 ++-- .../sequences/gotoAddDeficiencyStatisticsSequence.ts | 4 ++-- .../presenter/sequences/gotoAddOtherStatisticsSequence.ts | 4 ++-- .../src/presenter/sequences/gotoAddPaperFilingSequence.ts | 4 ++-- .../presenter/sequences/gotoAddPetitionerToCaseSequence.ts | 4 ++-- .../src/presenter/sequences/gotoAddTrialSessionSequence.ts | 4 ++-- .../src/presenter/sequences/gotoApplyStampSequence.ts | 4 ++-- .../sequences/gotoBeforeYouFileDocumentSequence.ts | 4 ++-- .../presenter/sequences/gotoBlockedCasesReportSequence.ts | 4 ++-- .../presenter/sequences/gotoCaseDeadlineReportSequence.ts | 4 ++-- .../presenter/sequences/gotoCaseInventoryReportSequence.ts | 4 ++-- .../src/presenter/sequences/gotoContactEditSequence.ts | 4 ++-- .../src/presenter/sequences/gotoCreateOrderSequence.ts | 4 ++-- .../src/presenter/sequences/gotoCustomCaseReportSequence.ts | 4 ++-- web-client/src/presenter/sequences/gotoDashboardSequence.ts | 4 ++-- .../src/presenter/sequences/gotoDocketEntryQcSequence.ts | 4 ++-- .../sequences/gotoEditCorrespondenceDocumentSequence.ts | 4 ++-- .../sequences/gotoEditCourtIssuedDocketEntrySequence.ts | 4 ++-- .../sequences/gotoEditDeficiencyStatisticSequence.ts | 4 ++-- .../presenter/sequences/gotoEditDocketEntryMetaSequence.ts | 4 ++-- web-client/src/presenter/sequences/gotoEditOrderSequence.ts | 4 ++-- .../presenter/sequences/gotoEditOtherStatisticsSequence.ts | 4 ++-- .../src/presenter/sequences/gotoEditPaperFilingSequence.ts | 4 ++-- .../src/presenter/sequences/gotoEditTrialSessionSequence.ts | 4 ++-- .../sequences/gotoEditUploadCourtIssuedDocumentSequence.ts | 4 ++-- .../src/presenter/sequences/gotoFileDocumentSequence.ts | 4 ++-- .../src/presenter/sequences/gotoMessageDetailSequence.ts | 4 ++-- web-client/src/presenter/sequences/gotoMessagesSequence.ts | 4 ++-- .../src/presenter/sequences/gotoPendingReportSequence.ts | 4 ++-- .../sequences/gotoPractitionerAddDocumentSequence.ts | 4 ++-- .../presenter/sequences/gotoPractitionerDetailSequence.ts | 4 ++-- .../sequences/gotoPractitionerDocumentationSequence.ts | 4 ++-- .../sequences/gotoPractitionerEditDocumentSequence.ts | 4 ++-- .../src/presenter/sequences/gotoRequestAccessSequence.ts | 4 ++-- .../presenter/sequences/gotoTrialSessionDetailSequence.ts | 4 ++-- .../sequences/gotoTrialSessionPlanningReportSequence.ts | 4 ++-- .../sequences/gotoTrialSessionWorkingCopySequence.ts | 4 ++-- .../src/presenter/sequences/gotoTrialSessionsSequence.ts | 4 ++-- .../sequences/gotoUploadCorrespondenceDocumentSequence.ts | 4 ++-- .../sequences/gotoUploadCourtIssuedDocumentSequence.ts | 4 ++-- web-client/src/presenter/sequences/gotoWorkQueueSequence.ts | 4 ++-- web-client/src/presenter/sequences/signOutSequence.ts | 4 ++-- .../src/presenter/sequences/unauthorizedErrorSequence.ts | 4 ++-- .../presenter/sequences/unidentifiedUserErrorSequence.ts | 4 ++-- web-client/src/router.ts | 2 +- web-client/src/views/IdleLogout.tsx | 6 +++--- 55 files changed, 111 insertions(+), 104 deletions(-) create mode 100644 web-client/src/presenter/sequences/Login/navigateToLoginSequence.ts rename web-client/src/presenter/sequences/{Login/goToLoginSequence.ts => Public/gotoLoginSequence.ts} (100%) diff --git a/docs/frontend.md b/docs/frontend.md index c95b7e77350..bd066f0f70c 100644 --- a/docs/frontend.md +++ b/docs/frontend.md @@ -126,7 +126,7 @@ export const signOutSequence = [ clearUserAction, clearMaintenanceModeAction, clearLoginFormAction, - gotoLoginSequence, + navigateToLoginSequence, ]; ``` diff --git a/web-client/src/presenter/presenter-public.ts b/web-client/src/presenter/presenter-public.ts index ba7867ec6ac..1e9acd584ce 100644 --- a/web-client/src/presenter/presenter-public.ts +++ b/web-client/src/presenter/presenter-public.ts @@ -13,7 +13,7 @@ import { goToCreatePetitionerAccountSequence } from '@web-client/presenter/seque import { goToVerificationSentSequence } from '@web-client/presenter/sequences/goToVerificationSentSequence'; import { gotoContactSequence } from './sequences/gotoContactSequence'; import { gotoHealthCheckSequence } from './sequences/gotoHealthCheckSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; +import { gotoLoginSequence } from '@web-client/presenter/sequences/Public/gotoLoginSequence'; import { gotoMaintenanceSequence } from './sequences/gotoMaintenanceSequence'; import { gotoPrivacySequence } from './sequences/gotoPrivacySequence'; import { gotoPublicCaseDetailSequence } from './sequences/Public/gotoPublicCaseDetailSequence'; @@ -27,6 +27,7 @@ import { initialPublicState } from './state-public'; import { loadMoreTodaysOrdersSequence } from './sequences/loadMoreTodaysOrdersSequence'; import { navigateBackSequence } from './sequences/navigateBackSequence'; import { navigateToCreatePetitionerAccountSequence } from '@web-client/presenter/sequences/navigateToCreatePetitionerAccountSequence'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { navigateToPublicSiteSequence } from './sequences/Public/navigateToPublicSiteSequence'; import { notFoundErrorSequence } from './sequences/notFoundErrorSequence'; import { openAppMaintenanceModalSequence } from './sequences/openAppMaintenanceModalSequence'; @@ -98,6 +99,7 @@ export const presenterSequences = { loadMoreTodaysOrdersSequence, navigateBackSequence, navigateToCreatePetitionerAccountSequence, + navigateToLoginSequence, navigateToPublicSiteSequence, notFoundErrorSequence, openAppMaintenanceModalSequence, diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 9c5977a1703..0424262d546 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -166,7 +166,6 @@ import { gotoFileDocumentSequence } from './sequences/gotoFileDocumentSequence'; import { gotoFilePetitionSuccessSequence } from './sequences/gotoFilePetitionSuccessSequence'; import { gotoIdleLogoutSequence } from './sequences/gotoIdleLogoutSequence'; import { gotoJudgeActivityReportSequence } from './sequences/JudgeActivityReport/gotoJudgeActivityReportSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { gotoMaintenanceSequence } from './sequences/gotoMaintenanceSequence'; import { gotoMessageDetailSequence } from './sequences/gotoMessageDetailSequence'; import { gotoMessagesSequence } from './sequences/gotoMessagesSequence'; @@ -218,6 +217,7 @@ import { navigateToCaseDetailFromPaperServiceSequence } from './sequences/naviga import { navigateToCaseDetailSequence } from './sequences/navigateToCaseDetailSequence'; import { navigateToCaseDetailWithDraftDocumentSequence } from './sequences/navigateToCaseDetailWithDraftDocumentSequence'; import { navigateToEditOrderSequence } from './sequences/navigateToEditOrderSequence'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { navigateToPathAndSetRedirectUrlSequence } from './sequences/navigateToPathAndSetRedirectUrlSequence'; import { navigateToPathSequence } from './sequences/navigateToPathSequence'; import { navigateToPrintPaperServiceSequence } from './sequences/navigateToPrintPaperServiceSequence'; @@ -818,7 +818,6 @@ export const presenterSequences = { gotoIdleLogoutSequence: gotoIdleLogoutSequence as unknown as Function, gotoJudgeActivityReportSequence: gotoJudgeActivityReportSequence as unknown as Function, - gotoLoginSequence: gotoLoginSequence as unknown as Function, gotoMaintenanceSequence: gotoMaintenanceSequence as unknown as Function, gotoMessageDetailSequence: gotoMessageDetailSequence as unknown as Function, gotoMessagesSequence: gotoMessagesSequence as unknown as Function, @@ -901,6 +900,7 @@ export const presenterSequences = { navigateToCaseDetailWithDraftDocumentSequence as unknown as Function, navigateToEditOrderSequence: navigateToEditOrderSequence as unknown as Function, + navigateToLoginSequence, navigateToPathAndSetRedirectUrlSequence: navigateToPathAndSetRedirectUrlSequence as unknown as Function, navigateToPathSequence: navigateToPathSequence as unknown as Function, diff --git a/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts b/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts index b0c3876225b..d65629905b8 100644 --- a/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts +++ b/web-client/src/presenter/sequences/JudgeActivityReport/gotoJudgeActivityReportSequence.ts @@ -2,8 +2,8 @@ import { clearErrorAlertsAction } from '../../actions/clearErrorAlertsAction'; import { clearScreenMetadataAction } from '../../actions/clearScreenMetadataAction'; import { closeMobileMenuAction } from '../../actions/closeMobileMenuAction'; import { getUsersInSectionAction } from '../../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { resetJudgeActivityReportStateAction } from '../../actions/resetJudgeActivityReportStateAction'; import { setAllAndCurrentJudgesAction } from '../../actions/setAllAndCurrentJudgesAction'; import { setJudgeLastNameOnJudgeActivityReportAction } from '../../actions/JudgeActivityReport/setJudgeLastNameOnJudgeActivityReportAction'; @@ -30,6 +30,6 @@ export const gotoJudgeActivityReportSequence = [ isLoggedIn: startWebSocketConnectionSequenceDecorator( gotoJudgeActivityReport, ), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/Login/navigateToLoginSequence.ts b/web-client/src/presenter/sequences/Login/navigateToLoginSequence.ts new file mode 100644 index 00000000000..2edc530a2bf --- /dev/null +++ b/web-client/src/presenter/sequences/Login/navigateToLoginSequence.ts @@ -0,0 +1,5 @@ +export const navigateToLoginSequence = [ + ({ router }) => { + router.externalRoute('http://localhost:5678/login'); + }, +] as unknown as () => void; diff --git a/web-client/src/presenter/sequences/Login/goToLoginSequence.ts b/web-client/src/presenter/sequences/Public/gotoLoginSequence.ts similarity index 100% rename from web-client/src/presenter/sequences/Login/goToLoginSequence.ts rename to web-client/src/presenter/sequences/Public/gotoLoginSequence.ts diff --git a/web-client/src/presenter/sequences/changePasswordLocalSequence.ts b/web-client/src/presenter/sequences/changePasswordLocalSequence.ts index 7f05f3d8860..b6b79d2832b 100644 --- a/web-client/src/presenter/sequences/changePasswordLocalSequence.ts +++ b/web-client/src/presenter/sequences/changePasswordLocalSequence.ts @@ -1,5 +1,5 @@ import { changePasswordLocalAction } from '../actions/changePasswordLocalAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setAlertSuccessAction } from '../actions/setAlertSuccessAction'; import { setSaveAlertsForNavigationAction } from '../actions/setSaveAlertsForNavigationAction'; import { showProgressSequenceDecorator } from '../utilities/showProgressSequenceDecorator'; @@ -11,7 +11,7 @@ export const changePasswordLocalSequence = showProgressSequenceDecorator([ yes: [ setAlertSuccessAction, setSaveAlertsForNavigationAction, - gotoLoginSequence, + navigateToLoginSequence, ], }, ]); diff --git a/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts b/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts index da629b7522f..9f84940112f 100644 --- a/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts +++ b/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts @@ -1,5 +1,5 @@ import { confirmSignUpLocalAction } from '../actions/confirmSignUpLocalAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setAlertErrorAction } from '../actions/setAlertErrorAction'; import { setAlertSuccessAction } from '../actions/setAlertSuccessAction'; @@ -9,5 +9,5 @@ export const confirmSignUpLocalSequence = [ no: [setAlertErrorAction], yes: [setAlertSuccessAction], }, - gotoLoginSequence, + navigateToLoginSequence, ]; diff --git a/web-client/src/presenter/sequences/goToVerificationSentSequence.ts b/web-client/src/presenter/sequences/goToVerificationSentSequence.ts index 64b6631db80..5ef4ca941e6 100644 --- a/web-client/src/presenter/sequences/goToVerificationSentSequence.ts +++ b/web-client/src/presenter/sequences/goToVerificationSentSequence.ts @@ -1,11 +1,11 @@ import { checkIfCognitoEmailInState } from '@web-client/presenter/actions/checkIfCognitoEmailInState'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setupCurrentPageAction } from '@web-client/presenter/actions/setupCurrentPageAction'; export const goToVerificationSentSequence = [ checkIfCognitoEmailInState, { - doesNotExist: [gotoLoginSequence], + doesNotExist: [navigateToLoginSequence], exists: [setupCurrentPageAction('VerificationSent')], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts b/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts index 580001bd4c9..8725a7f1406 100644 --- a/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts +++ b/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts @@ -3,8 +3,8 @@ import { generateCourtIssuedDocumentTitleAction } from '../actions/CourtIssuedDo import { getCaseAction } from '../actions/getCaseAction'; import { getFilterCurrentJudgeUsersAction } from '../actions/getFilterCurrentJudgeUsersAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setCourtIssuedDocumentInitialDataAction } from '../actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction'; import { setDefaultServiceStampAction } from '../actions/CourtIssuedDocketEntry/setDefaultServiceStampAction'; @@ -36,6 +36,6 @@ export const gotoAddCourtIssuedDocketEntrySequence = [ setIsEditingDocketEntryAction(false), setupCurrentPageAction('CourtIssuedDocketEntry'), ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts b/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts index 0fc72d0d8b7..62efe3b5b39 100644 --- a/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddDeficiencyStatisticsSequence.ts @@ -1,8 +1,8 @@ import { clearConfirmationTextAction } from '../actions/clearConfirmationTextAction'; import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultFormForAddDeficiencyStatisticsAction } from '../actions/setDefaultFormForAddDeficiencyStatisticsAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -22,6 +22,6 @@ export const gotoAddDeficiencyStatisticsSequence = [ setDefaultFormForAddDeficiencyStatisticsAction, setupCurrentPageAction('AddDeficiencyStatistics'), ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts b/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts index 3a7b950f7e3..2827432aedf 100644 --- a/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddOtherStatisticsSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -18,6 +18,6 @@ export const gotoAddOtherStatisticsSequence = [ setCaseAction, setupCurrentPageAction('AddOtherStatistics'), ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts b/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts index 3c004e6e2eb..e6f63ad0138 100644 --- a/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddPaperFilingSequence.ts @@ -2,8 +2,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { resetAddPaperFilingAction } from '../actions/resetAddPaperFilingAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -28,6 +28,6 @@ export const gotoAddPaperFilingSequence = [ isLoggedInAction, { isLoggedIn: startWebSocketConnectionSequenceDecorator(gotoAddPaperFiling), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts b/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts index 340ed614aaa..ec7da357d1d 100644 --- a/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddPetitionerToCaseSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultAddPetitionerToCaseFormAction } from '../actions/setDefaultAddPetitionerToCaseFormAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -20,6 +20,6 @@ export const gotoAddPetitionerToCaseSequence = [ setDefaultAddPetitionerToCaseFormAction, setupCurrentPageAction('AddPetitionerToCase'), ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts b/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts index 0180260e6c0..059c6207fd7 100644 --- a/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts +++ b/web-client/src/presenter/sequences/gotoAddTrialSessionSequence.ts @@ -3,8 +3,8 @@ import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction' import { getSetJudgesSequence } from './getSetJudgesSequence'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { parallel } from 'cerebral/factories'; import { setDefaultTrialSessionFormValuesAction } from '../actions/setDefaultTrialSessionFormValuesAction'; import { setTrialSessionsAction } from '../actions/TrialSession/setTrialSessionsAction'; @@ -34,6 +34,6 @@ export const gotoAddTrialSessionSequence = [ isLoggedInAction, { isLoggedIn: startWebSocketConnectionSequenceDecorator(gotoAddTrialSession), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoApplyStampSequence.ts b/web-client/src/presenter/sequences/gotoApplyStampSequence.ts index 54de9e1b6c8..6596a2e9db9 100644 --- a/web-client/src/presenter/sequences/gotoApplyStampSequence.ts +++ b/web-client/src/presenter/sequences/gotoApplyStampSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearPDFStampDataAction } from '../actions/StampMotion/clearPDFStampDataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; import { setDocketEntrySelectedFromMessageAction } from '../actions/setDocketEntrySelectedFromMessageAction'; @@ -28,6 +28,6 @@ export const goToApplyStampSequence = [ setPDFPageForSigningAction, setupCurrentPageAction('ApplyStamp'), ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts b/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts index c4b194c60ba..b243cbdfd59 100644 --- a/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoBeforeYouFileDocumentSequence.ts @@ -1,6 +1,6 @@ import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -18,6 +18,6 @@ export const gotoBeforeYouFileDocumentSequence = [ isLoggedInAction, { isLoggedIn: gotoBeforeYouFileDocument, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts b/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts index 44542a9569b..9aee35fa5e4 100644 --- a/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoBlockedCasesReportSequence.ts @@ -2,8 +2,8 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -20,6 +20,6 @@ export const gotoBlockedCasesReportSequence = [ isLoggedInAction, { isLoggedIn: [gotoBlockedCasesReport], - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts b/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts index f75695e0b4c..5f9d7abeb4d 100644 --- a/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoCaseDeadlineReportSequence.ts @@ -4,8 +4,8 @@ import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction' import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { getCaseDeadlinesAction } from '../actions/CaseDeadline/getCaseDeadlinesAction'; import { getSetJudgesSequence } from './getSetJudgesSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { parallel } from 'cerebral/factories'; import { setCaseDeadlinesAction } from '../actions/CaseDeadline/setCaseDeadlinesAction'; import { setDefaultCaseDeadlinesReportDatesAction } from '../actions/CaseDeadline/setDefaultCaseDeadlinesReportDatesAction'; @@ -35,6 +35,6 @@ export const gotoCaseDeadlineReportSequence = [ isLoggedInAction, { isLoggedIn: gotoCaseDeadlineReport, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts b/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts index c06ca757251..77e6a029dde 100644 --- a/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoCaseInventoryReportSequence.ts @@ -2,10 +2,10 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { fetchUserNotificationsSequence } from './fetchUserNotificationsSequence'; import { getSetJudgesSequence } from './getSetJudgesSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { hasCaseInventoryReportFilterSelectedAction } from '../actions/CaseInventoryReport/hasCaseInventoryReportFilterSelectedAction'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToDashboardAction } from '../actions/navigateToDashboardAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { openCaseInventoryReportModalSequence } from './openCaseInventoryReportModalSequence'; import { parallel } from 'cerebral/factories'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -37,6 +37,6 @@ export const gotoCaseInventoryReportSequence = [ ]), }, ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoContactEditSequence.ts b/web-client/src/presenter/sequences/gotoContactEditSequence.ts index 6eff9091544..09f4c3e0d55 100644 --- a/web-client/src/presenter/sequences/gotoContactEditSequence.ts +++ b/web-client/src/presenter/sequences/gotoContactEditSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setupContactFormAction } from '../actions/setupContactFormAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -22,6 +22,6 @@ export const gotoContactEditSequence = [ isLoggedInAction, { isLoggedIn: gotoContactEdit, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts b/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts index 4333c52afaa..ab50b80b160 100644 --- a/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts +++ b/web-client/src/presenter/sequences/gotoCreateOrderSequence.ts @@ -1,10 +1,10 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearModalAction } from '../actions/clearModalAction'; import { convertHtml2PdfSequence } from './convertHtml2PdfSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { hasOrderTypeSelectedAction } from '../actions/CourtIssuedOrder/hasOrderTypeSelectedAction'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToCaseDetailAction } from '../actions/navigateToCaseDetailAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { openCreateOrderChooseTypeModalSequence } from './openCreateOrderChooseTypeModalSequence'; import { setCreateOrderModalDataOnFormAction } from '../actions/CourtIssuedOrder/setCreateOrderModalDataOnFormAction'; import { setIsCreatingOrderAction } from '../actions/setIsCreatingOrderAction'; @@ -40,6 +40,6 @@ export const gotoCreateOrderSequence = [ ], }, ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts b/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts index 96024838e62..fb88e32ee66 100644 --- a/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoCustomCaseReportSequence.ts @@ -1,6 +1,6 @@ import { getSetJudgesSequence } from './getSetJudgesSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { resetCustomCaseReportStateAction } from '../actions/resetCustomCaseReportStateAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -16,6 +16,6 @@ export const gotoCustomCaseReportSequence = [ isLoggedInAction, { isLoggedIn: [gotoCustomCaseReport], - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoDashboardSequence.ts b/web-client/src/presenter/sequences/gotoDashboardSequence.ts index 19ce94a3338..0c7178462ff 100644 --- a/web-client/src/presenter/sequences/gotoDashboardSequence.ts +++ b/web-client/src/presenter/sequences/gotoDashboardSequence.ts @@ -9,9 +9,9 @@ import { getMaintenanceModeAction } from '../actions/getMaintenanceModeAction'; import { getOpenAndClosedCasesForUserAction } from '../actions/Dashboard/getOpenAndClosedCasesForUserAction'; import { getSubmittedAndCavCasesForCurrentJudgeAction } from '@web-client/presenter/actions/CaseWorksheet/getSubmittedAndCavCasesForCurrentJudgeAction'; import { getTrialSessionsForJudgeAction } from '../actions/TrialSession/getTrialSessionsForJudgeAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { gotoMaintenanceSequence } from './gotoMaintenanceSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { navigateToMessagesAction } from '../actions/navigateToMessagesAction'; import { navigateToSectionDocumentQCAction } from '../actions/navigateToSectionDocumentQCAction'; import { parallel } from 'cerebral'; @@ -132,6 +132,6 @@ export const gotoDashboardSequence = [ isLoggedInAction, { isLoggedIn: [goToDashboard], - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts b/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts index b1266fc3dce..1943f54bd5d 100644 --- a/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts +++ b/web-client/src/presenter/sequences/gotoDocketEntryQcSequence.ts @@ -4,9 +4,9 @@ import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; import { getShouldMarkReadAction } from '../actions/getShouldMarkReadAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { isWorkItemAlreadyCompletedAction } from '../actions/isWorkItemAlreadyCompletedAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryFormForDocketEditAction } from '../actions/EditDocketRecord/setDocketEntryFormForDocketEditAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; @@ -52,6 +52,6 @@ export const gotoDocketEntryQcSequence = [ isLoggedInAction, { isLoggedIn: gotoDocketEntryQc, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts b/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts index ded14ec7229..f4ee1df55db 100644 --- a/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditCorrespondenceDocumentSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryIdFromCorrespondenceAction } from '../actions/setDocketEntryIdFromCorrespondenceAction'; import { setDocumentToFormFromCorrespondenceAction } from '../actions/EditUploadCourtIssuedDocument/setDocumentToFormFromCorrespondenceAction'; @@ -29,6 +29,6 @@ export const gotoEditCorrespondenceDocumentSequence = [ isLoggedInAction, { isLoggedIn: gotoEditCorrespondenceDocument, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts b/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts index ef876481f3b..31e7e9c70e4 100644 --- a/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts +++ b/web-client/src/presenter/sequences/gotoEditCourtIssuedDocketEntrySequence.ts @@ -4,8 +4,8 @@ import { generateCourtIssuedDocumentTitleAction } from '../actions/CourtIssuedDo import { getCaseAction } from '../actions/getCaseAction'; import { getFilterCurrentJudgeUsersAction } from '../actions/getFilterCurrentJudgeUsersAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryFormForDocketEditAction } from '../actions/EditDocketRecord/setDocketEntryFormForDocketEditAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; @@ -39,6 +39,6 @@ export const gotoEditCourtIssuedDocketEntrySequence = [ isLoggedInAction, { isLoggedIn: gotoEditCourtIssuedDocketEntry, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts b/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts index e6a14e25c9c..6deee9214a1 100644 --- a/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditDeficiencyStatisticSequence.ts @@ -1,8 +1,8 @@ import { clearConfirmationTextAction } from '../actions/clearConfirmationTextAction'; import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setEditDeficiencyStatisticFormAction } from '../actions/setEditDeficiencyStatisticFormAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -22,6 +22,6 @@ export const gotoEditDeficiencyStatisticSequence = [ setEditDeficiencyStatisticFormAction, setupCurrentPageAction('EditDeficiencyStatistic'), ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts b/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts index c51d2dd61b0..d24f6a35b00 100644 --- a/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditDocketEntryMetaSequence.ts @@ -8,9 +8,9 @@ import { generateTitlePreviewAction } from '../actions/EditDocketRecordEntry/gen import { getCaseAction } from '../actions/getCaseAction'; import { getFilterCurrentJudgeUsersAction } from '../actions/getFilterCurrentJudgeUsersAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { initCourtIssuedOrderFormPropsFromEventCodeAction } from '../actions/EditDocketRecordEntry/initCourtIssuedOrderFormPropsFromEventCodeAction'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultEditDocketEntryMetaTabAction } from '../actions/setDefaultEditDocketEntryMetaTabAction'; import { setDocketEntryMetaFormForEditAction } from '../actions/EditDocketRecordEntry/setDocketEntryMetaFormForEditAction'; @@ -53,6 +53,6 @@ export const gotoEditDocketEntryMetaSequence = [ isLoggedInAction, { isLoggedIn: gotoEditDocketEntryMeta, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditOrderSequence.ts b/web-client/src/presenter/sequences/gotoEditOrderSequence.ts index 8be7995df07..a78e5b81ddc 100644 --- a/web-client/src/presenter/sequences/gotoEditOrderSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditOrderSequence.ts @@ -3,8 +3,8 @@ import { clearModalAction } from '../actions/clearModalAction'; import { convertHtml2PdfSequence } from './convertHtml2PdfSequence'; import { getCaseAction } from '../actions/getCaseAction'; import { getDocumentContentsAction } from '../actions/getDocumentContentsAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setAddedDocketNumbersAction } from '../actions/setAddedDocketNumbersAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultTabStateAction } from '../actions/setDefaultTabStateAction'; @@ -40,6 +40,6 @@ export const gotoEditOrderSequence = [ isLoggedInAction, { isLoggedIn: gotoEditOrder, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts b/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts index cbf446fd872..394c5a2a103 100644 --- a/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditOtherStatisticsSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setEditOtherStatisticsFormAction } from '../actions/setEditOtherStatisticsFormAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -20,6 +20,6 @@ export const gotoEditOtherStatisticsSequence = [ setEditOtherStatisticsFormAction, setupCurrentPageAction('EditOtherStatistics'), ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts b/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts index e403677d9cd..af941125a8a 100644 --- a/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditPaperFilingSequence.ts @@ -2,8 +2,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryFormForDocketEditAction } from '../actions/EditDocketRecord/setDocketEntryFormForDocketEditAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; @@ -36,6 +36,6 @@ export const gotoEditPaperFilingSequence = [ isLoggedInAction, { isLoggedIn: startWebSocketConnectionSequenceDecorator(gotoEditPaperFiling), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts b/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts index 5467659f49d..72f3883c73d 100644 --- a/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditTrialSessionSequence.ts @@ -5,8 +5,8 @@ import { getSetJudgesSequence } from './getSetJudgesSequence'; import { getTrialSessionDetailsAction } from '../actions/TrialSession/getTrialSessionDetailsAction'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setTrialSessionDetailsAction } from '../actions/TrialSession/setTrialSessionDetailsAction'; import { setTrialSessionDetailsOnFormAction } from '../actions/TrialSession/setTrialSessionDetailsOnFormAction'; import { setTrialSessionsAction } from '../actions/TrialSession/setTrialSessionsAction'; @@ -38,6 +38,6 @@ export const gotoEditTrialSessionSequence = [ isLoggedInAction, { isLoggedIn: gotoEditTrialSession, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts b/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts index f28b00cbcf8..5624cf56a4b 100644 --- a/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoEditUploadCourtIssuedDocumentSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setDocketEntryIdAction } from '../actions/setDocketEntryIdAction'; import { setDocumentToFormAction } from '../actions/EditUploadCourtIssuedDocument/setDocumentToFormAction'; @@ -29,6 +29,6 @@ export const gotoEditUploadCourtIssuedDocumentSequence = [ isLoggedInAction, { isLoggedIn: gotoEditUploadCourtIssuedDocument, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts b/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts index 0b0e8cf5587..9f7d561551e 100644 --- a/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoFileDocumentSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setDefaultFilersMapAction } from '../actions/setDefaultFilersMapAction'; import { setWizardStepAction } from '../actions/setWizardStepAction'; @@ -26,6 +26,6 @@ export const gotoFileDocumentSequence = [ isLoggedInAction, { isLoggedIn: gotoFileDocument, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts b/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts index 15c3bccffc3..4dcfaaa6280 100644 --- a/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts +++ b/web-client/src/presenter/sequences/gotoMessageDetailSequence.ts @@ -6,8 +6,8 @@ import { getJudgesCaseNoteForCaseAction } from '@web-client/presenter/actions/Tr import { getMessageThreadAction } from '../actions/getMessageThreadAction'; import { getMostRecentMessageInThreadAction } from '../actions/getMostRecentMessageInThreadAction'; import { getShouldMarkMessageAsReadAction } from '../actions/getShouldMarkMessageAsReadAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setCaseDetailPageTabActionGenerator } from '../actions/setCaseDetailPageTabActionGenerator'; import { setDefaultIsExpandedAction } from '../actions/setDefaultIsExpandedAction'; @@ -52,6 +52,6 @@ export const gotoMessageDetailSequence = [ isLoggedInAction, { isLoggedIn: gotoMessageDetail, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoMessagesSequence.ts b/web-client/src/presenter/sequences/gotoMessagesSequence.ts index cb174580434..0f4b1f8dd0b 100644 --- a/web-client/src/presenter/sequences/gotoMessagesSequence.ts +++ b/web-client/src/presenter/sequences/gotoMessagesSequence.ts @@ -9,8 +9,8 @@ import { getInboxMessagesForSectionAction } from '../actions/getInboxMessagesFor import { getInboxMessagesForUserAction } from '../actions/getInboxMessagesForUserAction'; import { getOutboxMessagesForSectionAction } from '../actions/getOutboxMessagesForSectionAction'; import { getOutboxMessagesForUserAction } from '../actions/getOutboxMessagesForUserAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { parallel } from 'cerebral'; import { resetCacheKeyAction } from '../actions/resetCacheKeyAction'; import { setDefaultTableSortAction } from '../actions/setDefaultTableSortAction'; @@ -50,6 +50,6 @@ export const gotoMessagesSequence = [ isLoggedInAction, { isLoggedIn: goToMessages, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoPendingReportSequence.ts b/web-client/src/presenter/sequences/gotoPendingReportSequence.ts index e09933acddf..1bfc49d136e 100644 --- a/web-client/src/presenter/sequences/gotoPendingReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoPendingReportSequence.ts @@ -4,8 +4,8 @@ import { clearPendingReportsAction } from '../actions/PendingItems/clearPendingR import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { getSetJudgesSequence } from './getSetJudgesSequence'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -24,6 +24,6 @@ export const gotoPendingReportSequence = [ isLoggedInAction, { isLoggedIn: gotoPendingReport, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts index 0e1753b0646..35c1e27a670 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerAddDocumentSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -22,6 +22,6 @@ export const gotoPractitionerAddDocumentSequence = [ isLoggedIn: startWebSocketConnectionSequenceDecorator( gotoPractitionerAddDocument, ), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts index 50d7c8588f7..0e07945e1db 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerDetailSequence.ts @@ -1,7 +1,7 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setInitialTableSortAction } from '../actions/setInitialTableSortAction'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setTabFromPropsAction } from '../actions/setTabFromPropsAction'; @@ -21,7 +21,7 @@ export const gotoPractitionerDetailSequence = [ setPractitionerDetailAction, setupCurrentPageAction('PractitionerInformation'), ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]), ]; diff --git a/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts index bf084e2f9d0..acef8611fe0 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerDocumentationSequence.ts @@ -1,8 +1,8 @@ import { clearErrorAlertsAction } from '../actions/clearErrorAlertsAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; import { getPractitionerDocumentsAction } from '../actions/getPractitionerDocumentsAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setPractitionerDocumentsAction } from '../actions/setPractitionerDocumentsAction'; import { setTabFromPropsAction } from '../actions/setTabFromPropsAction'; @@ -23,7 +23,7 @@ export const gotoPractitionerDocumentationSequence = [ setPractitionerDocumentsAction, setupCurrentPageAction('PractitionerInformation'), ]), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]), ]; diff --git a/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts b/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts index 844b067642b..bac48560444 100644 --- a/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoPractitionerEditDocumentSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { getPractitionerDetailAction } from '../actions/getPractitionerDetailAction'; import { getPractitionerDocumentAction } from '../actions/getPractitionerDocumentAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setPractitionerDetailAction } from '../actions/setPractitionerDetailAction'; import { setPractitionerDocumentFormForEditAction } from '../actions/Practitioners/setPractitionerDocumentFormForEditAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -26,6 +26,6 @@ export const gotoPractitionerEditDocumentSequence = [ isLoggedIn: startWebSocketConnectionSequenceDecorator( gotoPractitionerEditDocument, ), - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts b/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts index 58a6d2ed4ed..91fefa44f6a 100644 --- a/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts +++ b/web-client/src/presenter/sequences/gotoRequestAccessSequence.ts @@ -3,9 +3,9 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; import { getCaseAssociationAction } from '../actions/getCaseAssociationAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { navigateToCaseDetailAction } from '../actions/navigateToCaseDetailAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { runPathForUserRoleAction } from '../actions/runPathForUserRoleAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setCaseAssociationAction } from '../actions/setCaseAssociationAction'; @@ -51,6 +51,6 @@ export const gotoRequestAccessSequence = [ isLoggedInAction, { isLoggedIn: gotoRequestAccess, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts index a5aebfc0530..74a162e8561 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionDetailSequence.ts @@ -3,11 +3,11 @@ import { getCalendaredCasesForTrialSessionAction } from '../actions/TrialSession import { getEligibleCasesForTrialSessionAction } from '../actions/TrialSession/getEligibleCasesForTrialSessionAction'; import { getTrialSessionDetailsAction } from '../actions/TrialSession/getTrialSessionDetailsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { isTrialSessionCalendaredAction } from '../actions/TrialSession/isTrialSessionCalendaredAction'; import { mergeCaseOrderIntoCalendaredCasesAction } from '../actions/TrialSession/mergeCaseOrderIntoCalendaredCasesAction'; import { mergeCaseOrderIntoEligibleCasesAction } from '../actions/TrialSession/mergeCaseOrderIntoEligibleCasesAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { parallel } from 'cerebral/factories'; import { setCalendaredCasesOnTrialSessionAction } from '../actions/TrialSession/setCalendaredCasesOnTrialSessionAction'; import { setDefaultTrialSessionDetailTabAction } from '../actions/TrialSession/setDefaultTrialSessionDetailTabAction'; @@ -50,6 +50,6 @@ export const gotoTrialSessionDetailSequence = [ isLoggedInAction, { isLoggedIn: gotoTrialSessionDetails, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts index 33bd7edc297..931692481c8 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionPlanningReportSequence.ts @@ -1,5 +1,5 @@ -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -12,6 +12,6 @@ export const gotoTrialSessionPlanningReportSequence = [ isLoggedInAction, { isLoggedIn: gotoTrialSessionPlanningReport, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts index 08e8feb9b81..519aa8f428c 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionWorkingCopySequence.ts @@ -7,12 +7,12 @@ import { getTrialSessionDetailsAction } from '../actions/TrialSession/getTrialSe import { getTrialSessionWorkingCopyAction } from '../actions/TrialSession/getTrialSessionWorkingCopyAction'; import { getUserCaseNoteForCasesAction } from '../actions/TrialSession/getUserCaseNoteForCasesAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { gotoTrialSessionDetailSequence } from './gotoTrialSessionDetailSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; import { isTrialSessionCalendaredAction } from '../actions/TrialSession/isTrialSessionCalendaredAction'; import { isUserAssociatedWithTrialSessionAction } from '../actions/TrialSession/isUserAssociatedWithTrialSessionAction'; import { mergeCaseOrderIntoCalendaredCasesAction } from '../actions/TrialSession/mergeCaseOrderIntoCalendaredCasesAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { runPathForUserRoleAction } from '../actions/runPathForUserRoleAction'; import { setCalendaredCasesOnTrialSessionAction } from '../actions/TrialSession/setCalendaredCasesOnTrialSessionAction'; import { setCaseNotesOntoCalendaredCasesAction } from '../actions/TrialSession/setCaseNotesOntoCalendaredCasesAction'; @@ -87,6 +87,6 @@ export const gotoTrialSessionWorkingCopySequence = [ isLoggedInAction, { isLoggedIn: gotoTrialSessionDetails, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts b/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts index cece6ae4d6a..79bd05bd9cd 100644 --- a/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts +++ b/web-client/src/presenter/sequences/gotoTrialSessionsSequence.ts @@ -5,8 +5,8 @@ import { getJudgeForCurrentUserAction } from '../actions/getJudgeForCurrentUserA import { getNotificationsAction } from '../actions/getNotificationsAction'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { parallel } from 'cerebral/factories'; import { setAllAndCurrentJudgesAction } from '../actions/setAllAndCurrentJudgesAction'; import { setJudgeUserAction } from '../actions/setJudgeUserAction'; @@ -38,6 +38,6 @@ export const gotoTrialSessionsSequence = [ isLoggedInAction, { isLoggedIn: [gotoTrialSessions], - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts b/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts index 6f9c3d9e5be..394f56e458e 100644 --- a/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoUploadCorrespondenceDocumentSequence.ts @@ -2,8 +2,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScansAction } from '../actions/clearScansAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { resetAddCorrespondenceAction } from '../actions/resetAddCorrespondenceAction'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; @@ -27,6 +27,6 @@ export const gotoUploadCorrespondenceDocumentSequence = [ isLoggedInAction, { isLoggedIn: [gotoUploadCorrespondenceDocument], - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts b/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts index fc57ea90f82..0cd81fdeabb 100644 --- a/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts +++ b/web-client/src/presenter/sequences/gotoUploadCourtIssuedDocumentSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '../actions/clearFormAction'; import { clearScreenMetadataAction } from '../actions/clearScreenMetadataAction'; import { getCaseAction } from '../actions/getCaseAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setCaseAction } from '../actions/setCaseAction'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { startWebSocketConnectionSequenceDecorator } from '../utilities/startWebSocketConnectionSequenceDecorator'; @@ -24,6 +24,6 @@ export const gotoUploadCourtIssuedDocumentSequence = [ isLoggedInAction, { isLoggedIn: [gotoUploadCourtIssuedDocument], - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts b/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts index ddda0440c37..79cfa62802f 100644 --- a/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts +++ b/web-client/src/presenter/sequences/gotoWorkQueueSequence.ts @@ -6,8 +6,8 @@ import { closeMobileMenuAction } from '../actions/closeMobileMenuAction'; import { getConstants } from '../../getConstants'; import { getTrialSessionsAction } from '../actions/TrialSession/getTrialSessionsAction'; import { getUsersInSectionAction } from '../actions/getUsersInSectionAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; import { isLoggedInAction } from '../actions/isLoggedInAction'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { parallel } from 'cerebral/factories'; import { runPathForUserRoleAction } from '../actions/runPathForUserRoleAction'; import { setSectionForWorkQueueAction } from '../actions/setSectionForWorkQueueAction'; @@ -73,6 +73,6 @@ export const gotoWorkQueueSequence = [ isLoggedInAction, { isLoggedIn: goToWorkQueue, - unauthorized: [gotoLoginSequence], + unauthorized: [navigateToLoginSequence], }, ]; diff --git a/web-client/src/presenter/sequences/signOutSequence.ts b/web-client/src/presenter/sequences/signOutSequence.ts index d678feffe96..c36b399c98f 100644 --- a/web-client/src/presenter/sequences/signOutSequence.ts +++ b/web-client/src/presenter/sequences/signOutSequence.ts @@ -4,7 +4,7 @@ import { clearLoginFormAction } from '../actions/clearLoginFormAction'; import { clearMaintenanceModeAction } from '../actions/clearMaintenanceModeAction'; import { clearUserAction } from '../actions/clearUserAction'; import { deleteAuthCookieAction } from '../actions/deleteAuthCookieAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; import { stopWebSocketConnectionAction } from '../actions/WebSocketConnection/stopWebSocketConnectionAction'; @@ -17,5 +17,5 @@ export const signOutSequence = [ clearUserAction, clearMaintenanceModeAction, clearLoginFormAction, - gotoLoginSequence, + navigateToLoginSequence, ]; diff --git a/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts b/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts index 81284d6e93a..5e7a1cf1c31 100644 --- a/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts +++ b/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts @@ -1,5 +1,5 @@ import { clearModalAction } from '../actions/clearModalAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setAlertFromExceptionAction } from '../actions/setAlertFromExceptionAction'; import { unsetWaitingForResponseOnErrorAction } from '../actions/unsetWaitingForResponseOnErrorAction'; @@ -7,5 +7,5 @@ export const unauthorizedErrorSequence = [ unsetWaitingForResponseOnErrorAction, setAlertFromExceptionAction, clearModalAction, - gotoLoginSequence, + navigateToLoginSequence, ]; diff --git a/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts b/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts index d3e5e18b8bf..949bc0dd2ac 100644 --- a/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts +++ b/web-client/src/presenter/sequences/unidentifiedUserErrorSequence.ts @@ -1,5 +1,5 @@ import { clearModalAction } from '../actions/clearModalAction'; -import { gotoLoginSequence } from '@web-client/presenter/sequences/Login/goToLoginSequence'; +import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setAlertFromExceptionAction } from '../actions/setAlertFromExceptionAction'; import { unsetWaitingForResponseOnErrorAction } from '../actions/unsetWaitingForResponseOnErrorAction'; @@ -7,5 +7,5 @@ export const unidentifiedUserErrorSequence = [ unsetWaitingForResponseOnErrorAction, setAlertFromExceptionAction, clearModalAction, - gotoLoginSequence, + navigateToLoginSequence, ]; diff --git a/web-client/src/router.ts b/web-client/src/router.ts index 2c6c58c51c1..f4406f6d810 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -69,7 +69,7 @@ const gotoMaintenancePage = app => { }); }; const gotoLoginPage = app => { - return app.getSequence('gotoLoginSequence')(); + return app.getSequence('navigateToLoginSequence')(); }; const goto404 = app => { return app.getSequence('navigateToPathSequence')({ diff --git a/web-client/src/views/IdleLogout.tsx b/web-client/src/views/IdleLogout.tsx index ee9cd644b3e..1ec9128e56d 100644 --- a/web-client/src/views/IdleLogout.tsx +++ b/web-client/src/views/IdleLogout.tsx @@ -4,8 +4,8 @@ import { sequences } from '@web-client/presenter/app.cerebral'; import React from 'react'; export const IdleLogout = connect( - { gotoLoginSequence: sequences.gotoLoginSequence }, - function IdleLogout({ gotoLoginSequence }) { + { navigateToLoginSequence: sequences.navigateToLoginSequence }, + function IdleLogout({ navigateToLoginSequence }) { return (

Session Timeout

@@ -16,7 +16,7 @@ export const IdleLogout = connect( United States Tax Court website for information on court services and contact information.

- + From edd55f03883c32cd49c24f372797cdf71ce2a591 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 8 Dec 2023 14:59:15 -0800 Subject: [PATCH 025/700] 10007 - TODO doc --- temp_delete_me.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 temp_delete_me.md diff --git a/temp_delete_me.md b/temp_delete_me.md new file mode 100644 index 00000000000..63b99880bf4 --- /dev/null +++ b/temp_delete_me.md @@ -0,0 +1,36 @@ +::: STUFF TO DELETE ::: +- + + +::: STUFF TO UPDATE ::: +- web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts +- web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts +- web-client/integration-tests/petitionerCreatesAccount.test.ts + + +::: STUFF TO DO ::: +- Add refresh token cookie in the browser. +- add test accounts to cognito local +- Figure out what to do with cognitoLocal.json +- error handling +- make it work for hosted envs (remove hard-coded ) + + + + + +What is public and private? +Public/Private +- Public - anyone that is unauthenticated and on the public website domain, localhost:5678 +- private - someone that is authenticated and on the private website domain, localhost:1234 + +DAWSON +- Public - irsPractitioner, privatePractitioner, petitioner +- Private - court employee + + +Local Cognito Fixes +- Script which cleans up the .cognito/db/local_2pHzece7.json +- research cognito-local to see if we can define our users in. +- generate the .cognito/db/local_2pHzece7.json file everytime on startup using users.json as the seeds. gitignore .cognito/db/local_2pHzece7.json . +- make a golden copy which populates the .cognito/db/local_2pHzece7.json \ No newline at end of file From b525e54204b8e4b08920dea7146ab2efb85b908c Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Mon, 11 Dec 2023 10:40:18 -0700 Subject: [PATCH 026/700] 10007 - WIP set cookie with refreshToken --- .../src/presenter/actions/setTokenAction.ts | 20 +++++++++++-------- .../sequences/Login/submitLoginSequence.ts | 9 ++++++++- .../sequences/loginWithTokenSequence.ts | 6 ------ web-client/src/router.ts | 8 ++++++-- .../src/utilities/queryStringDecoder.ts | 3 +++ 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/web-client/src/presenter/actions/setTokenAction.ts b/web-client/src/presenter/actions/setTokenAction.ts index 829ec639298..f3728f70789 100644 --- a/web-client/src/presenter/actions/setTokenAction.ts +++ b/web-client/src/presenter/actions/setTokenAction.ts @@ -1,17 +1,21 @@ import { state } from '@web-client/presenter/app.cerebral'; -/** - * sets the token on the state - * @param {object} providers the providers object - * @param {object} providers.store the cerebral store used for setting state.user - * @param {object} providers.props the cerebral props object used for getting the props.user - * @param {object} providers.applicationContext the application context needed for getting the setCurrentUser method - */ export const setTokenAction = ({ applicationContext, props, store, -}: ActionProps) => { +}: ActionProps<{ token: string; refreshToken: string }>): void => { + const expiresAt = applicationContext.getUtilities().calculateISODate({ + dateString: applicationContext.getUtilities().createISODateString(), + howMuch: 29, + units: 'days', + }); + // eslint-disable-next-line @miovision/disallow-date/no-new-date + const expires = new Date(expiresAt); + const path = '/auth'; + const httpOnly = false; // TODO should be true if not local + window.document.cookie = `refreshToken=${props.refreshToken}; expires=${expires}; path=${path}; secure=true; httpOnly=${httpOnly}`; + store.set(state.token, props.token); store.set(state.refreshToken, props.refreshToken || null); applicationContext.setCurrentUserToken(props.token); diff --git a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts index 5a38d3d86e1..72b39973d13 100644 --- a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts @@ -28,7 +28,14 @@ export const submitLoginSequence = [ }) .promise(); const idToken = result.AuthenticationResult?.IdToken; - router.externalRoute(`http://localhost:1234/log-in?token=${idToken}`); + const refreshToken = result.AuthenticationResult?.RefreshToken; + console.log( + `http://localhost:1234/log-in?token=${idToken}&refreshToken=${refreshToken}` + .length, + ); + router.externalRoute( + `http://localhost:1234/log-in?token=${idToken}&refreshToken=${refreshToken}`, + ); console.log('result from cognito: ', result); // Call some endpoint to get token & refresh token diff --git a/web-client/src/presenter/sequences/loginWithTokenSequence.ts b/web-client/src/presenter/sequences/loginWithTokenSequence.ts index 3ef8f70a356..fb0e8513f2d 100644 --- a/web-client/src/presenter/sequences/loginWithTokenSequence.ts +++ b/web-client/src/presenter/sequences/loginWithTokenSequence.ts @@ -7,12 +7,6 @@ import { setTokenAction } from '../actions/setTokenAction'; import { setUserAction } from '../actions/setUserAction'; import { setUserPermissionsAction } from '../actions/setUserPermissionsAction'; -/** - * Combine several sequences; set login value, and - * continue with other sequences used when submitting login form - * and navigating to dashboard - * - */ export const loginWithTokenSequence = [ decodeTokenAction, setTokenAction, diff --git a/web-client/src/router.ts b/web-client/src/router.ts index f4406f6d810..d86e85841f7 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -1137,8 +1137,12 @@ const router = { }); registerRoute('/log-in...', () => { - const { path, token } = queryStringDecoder(); - return app.getSequence('loginWithTokenSequence')({ path, token }); + const { path, refreshToken, token } = queryStringDecoder(); + return app.getSequence('loginWithTokenSequence')({ + path, + refreshToken, + token, + }); }); registerRoute( diff --git a/web-client/src/utilities/queryStringDecoder.ts b/web-client/src/utilities/queryStringDecoder.ts index 6e0960fab21..4093e6d61ce 100644 --- a/web-client/src/utilities/queryStringDecoder.ts +++ b/web-client/src/utilities/queryStringDecoder.ts @@ -1,15 +1,18 @@ import qs from 'qs'; export const queryStringDecoder = () => { + //TODO: 10007 clean me up! const query = qs.parse((window.location.search || '').substring(1)); const hash = qs.parse((window.location.hash || '').substring(1)); // cognito uses a # instead of ? const { code } = query; const token = hash.id_token || query.token; + const { refreshToken } = query; const path = query.path || '/'; return { code, path, + refreshToken, token, }; }; From 908932368c94e62dfdd523419d163a86543c61d8 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Mon, 11 Dec 2023 11:37:32 -0700 Subject: [PATCH 027/700] 10007 - WIP Add alert messaging, adding toggle password, start on errors. --- .../sequences/Login/submitLoginSequence.ts | 67 +++++++++++++------ web-client/src/views/Public/Login/Login.tsx | 26 ++++++- 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts index 72b39973d13..1b02fca0974 100644 --- a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts @@ -1,4 +1,6 @@ import { CognitoIdentityServiceProvider } from 'aws-sdk'; +import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertErrorAction'; +//import { setAlertSuccessAction } from '@web-client/presenter/actions/setAlertSuccessAction'; import { state } from '@web-client/presenter/app-public.cerebral'; const cognito = new CognitoIdentityServiceProvider({ @@ -12,32 +14,57 @@ const cognito = new CognitoIdentityServiceProvider({ }); export const submitLoginSequence = [ - async ({ get, router }) => { + async ({ get, path, router }) => { const { email, password } = get(state.form); console.log('in submitLoginSequence'); console.log(email, password); - const result = await cognito - .initiateAuth({ - AuthFlow: 'USER_PASSWORD_AUTH', - AuthParameters: { - PASSWORD: password, - USERNAME: email, + try { + const result = await cognito + .initiateAuth({ + AuthFlow: 'USER_PASSWORD_AUTH', + AuthParameters: { + PASSWORD: password, + USERNAME: email, + }, + ClientId: 'bvjrggnd3co403c0aahscinne', + }) + .promise(); + + console.log('result from cognito: ', result); + + const idToken = result.AuthenticationResult?.IdToken; + const refreshToken = result.AuthenticationResult?.RefreshToken; + console.log( + `http://localhost:1234/log-in?token=${idToken}&refreshToken=${refreshToken}` + .length, + ); + router.externalRoute( + `http://localhost:1234/log-in?token=${idToken}&refreshToken=${refreshToken}`, + ); + } catch (e) { + console.log('an error occurred'); + return path.error({ + alertError: { + alertType: 'error', + message: 'The email address or password you entered is invalid.', + title: 'Please correct the following errors:', }, - ClientId: 'bvjrggnd3co403c0aahscinne', - }) - .promise(); - const idToken = result.AuthenticationResult?.IdToken; - const refreshToken = result.AuthenticationResult?.RefreshToken; - console.log( - `http://localhost:1234/log-in?token=${idToken}&refreshToken=${refreshToken}` - .length, - ); - router.externalRoute( - `http://localhost:1234/log-in?token=${idToken}&refreshToken=${refreshToken}`, - ); + }); + } - console.log('result from cognito: ', result); // Call some endpoint to get token & refresh token + + // TODO: Return Alert Success if User Verifies Account + // return { + // alertSuccess: { + // message: '', + // title: '', + // }, + // }; + }, + { + error: [setAlertErrorAction], + //success: [setAlertSuccessAction], }, ] as unknown as (props) => void; diff --git a/web-client/src/views/Public/Login/Login.tsx b/web-client/src/views/Public/Login/Login.tsx index 8b22f180ad8..7e01f40217e 100644 --- a/web-client/src/views/Public/Login/Login.tsx +++ b/web-client/src/views/Public/Login/Login.tsx @@ -1,18 +1,36 @@ import { Button } from '@web-client/ustc-ui/Button/Button'; +import { MessageAlert } from '@web-client/views/Public/MessageAlert/MessageAlert'; import { connect } from '@web-client/presenter/shared.cerebral'; import { sequences, state } from '@web-client/presenter/app-public.cerebral'; import React from 'react'; export const Login = connect( { + alertError: state.alertError, form: state.form, + showPassword: state.showPassword, submitLoginSequence: sequences.submitLoginSequence, + toggleShowPasswordSequence: sequences.toggleShowPasswordSequence, updateFormValueSequence: sequences.updateFormValueSequence, }, - ({ form, submitLoginSequence, updateFormValueSequence }) => { + ({ + alertError, + form, + showPassword, + submitLoginSequence, + toggleShowPasswordSequence, + updateFormValueSequence, + }) => { return ( <>
+ {alertError && ( + + )}

Log in to DAWSON

@@ -45,6 +63,7 @@ export const Login = connect( className="usa-input" id="password" name="password" + type={showPassword ? 'text' : 'password'} value={form.password} onChange={e => { updateFormValueSequence({ @@ -58,8 +77,11 @@ export const Login = connect( data-hide-text="Hide password" data-show-text="Show password" type="button" + onClick={() => + toggleShowPasswordSequence({ passwordType: 'showPassword' }) + } > - Show password + {showPassword ? 'Hide Password' : 'Show password'} @@ -81,7 +81,7 @@ export const HeaderPublic = connect(
diff --git a/web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx b/web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx index bf426effa42..d9d11d58e3f 100644 --- a/web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx +++ b/web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx @@ -9,8 +9,8 @@ export const CreatePetitionerAccountForm = connect( confirmPassword: state.form.confirmPassword, createAccountHelper: state.createAccountHelper, - gotoLoginSequence: sequences.gotoLoginSequence, password: state.form.password, + redirectToLoginSequence: sequences.redirectToLoginSequence, showConfirmPassword: state.showConfirmPassword, showPassword: state.showPassword, submitCreatePetitionerAccountFormSequence: @@ -21,8 +21,8 @@ export const CreatePetitionerAccountForm = connect( ({ confirmPassword, createAccountHelper, - gotoLoginSequence, password, + redirectToLoginSequence, showConfirmPassword, showPassword, submitCreatePetitionerAccountFormSequence, @@ -259,7 +259,7 @@ export const CreatePetitionerAccountForm = connect( Already have an account?{' '} diff --git a/web-client/src/views/Public/EmailVerificationInstructions.tsx b/web-client/src/views/Public/EmailVerificationInstructions.tsx index 3e0636fac58..019e7c7cdad 100644 --- a/web-client/src/views/Public/EmailVerificationInstructions.tsx +++ b/web-client/src/views/Public/EmailVerificationInstructions.tsx @@ -6,9 +6,9 @@ import React from 'react'; export const EmailVerificationInstructions = connect( { - gotoLoginSequence: sequences.gotoLoginSequence, + redirectToLoginSequence: sequences.redirectToLoginSequence, }, - function EmailVerificationInstructions({ gotoLoginSequence }) { + function EmailVerificationInstructions({ redirectToLoginSequence }) { return ( <> @@ -21,7 +21,7 @@ export const EmailVerificationInstructions = connect( Click the Verify Email link from your new email - +
diff --git a/web-client/src/views/Public/EmailVerificationSuccess.tsx b/web-client/src/views/Public/EmailVerificationSuccess.tsx index a682bf13d63..a96496b3d22 100644 --- a/web-client/src/views/Public/EmailVerificationSuccess.tsx +++ b/web-client/src/views/Public/EmailVerificationSuccess.tsx @@ -6,16 +6,16 @@ import React from 'react'; export const EmailVerificationSuccess = connect( { - gotoLoginSequence: sequences.gotoLoginSequence, + redirectToLoginSequence: sequences.redirectToLoginSequence, }, - function EmailVerificationSuccess({ gotoLoginSequence }) { + function EmailVerificationSuccess({ redirectToLoginSequence }) { return ( <>

You can now log in with your new email address.

- +
From 1e84edc938f92619185a83a977ed4844f2b8bf21 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 19 Dec 2023 11:21:49 -0800 Subject: [PATCH 047/700] 10007: Add notes on what to do next --- temp_delete_me.md | 5 +++++ .../src/presenter/actions/Login/navigateToLoginAction.ts | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 web-client/src/presenter/actions/Login/navigateToLoginAction.ts diff --git a/temp_delete_me.md b/temp_delete_me.md index e58ea42b4b4..7b067d69af8 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -33,3 +33,8 @@ - Revoke Refresh Token after Use - How are going to make sure our auth is secure? Run scanners or pen testing? + + +::: IDEAS ::: +- when navigating to login sequence try and exchange idToken +- ifHasAccess only does static checks and redirects. Create an initSequence which is responsible for doing all fetching for app. (exchange idToken, get feature flags, get maintenance mode, get user, startRefreshIntervalSequence) diff --git a/web-client/src/presenter/actions/Login/navigateToLoginAction.ts b/web-client/src/presenter/actions/Login/navigateToLoginAction.ts new file mode 100644 index 00000000000..8e0e32abfcc --- /dev/null +++ b/web-client/src/presenter/actions/Login/navigateToLoginAction.ts @@ -0,0 +1,3 @@ +export const navigateToLoginAction = ({ router }) => { + router.route('/login'); +}; From e11959af2a70cac89d33379adf9879b985f9e819 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 19 Dec 2023 11:24:10 -0800 Subject: [PATCH 048/700] 10007: WIP --- .../sequences/Login/navigateToLoginSequence.ts | 6 +++--- web-client/src/router.ts | 14 +++----------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/web-client/src/presenter/sequences/Login/navigateToLoginSequence.ts b/web-client/src/presenter/sequences/Login/navigateToLoginSequence.ts index 5e4dcc403b0..20a1251f96d 100644 --- a/web-client/src/presenter/sequences/Login/navigateToLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/navigateToLoginSequence.ts @@ -1,5 +1,5 @@ +import { navigateToLoginAction } from '@web-client/presenter/actions/Login/navigateToLoginAction'; + export const navigateToLoginSequence = [ - ({ router }) => { - router.route('/login'); - }, + navigateToLoginAction, ] as unknown as () => void; diff --git a/web-client/src/router.ts b/web-client/src/router.ts index c1720ba953c..2922fca90ee 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -68,15 +68,12 @@ const gotoMaintenancePage = app => { path: '/maintenance', }); }; -const gotoLoginPage = app => { - return app.getSequence('navigateToLoginSequence')(); -}; const goto404 = app => { return app.getSequence('navigateToPathSequence')({ path: '404', }); }; -const accessRedirects = { goto404, gotoLoginPage, gotoMaintenancePage }; +const accessRedirects = { goto404, gotoMaintenancePage }; const ifHasAccess = ( { @@ -92,14 +89,9 @@ const ifHasAccess = ( }, cb, ) => { - return async function () { + return function () { if (!app.getState('token')) { - try { - await app.getSequence('refreshTokenSequence')(); - return cb.apply(null, arguments); - } catch (err) { - return redirect.gotoLoginPage(app); - } + return app.getSequence('navigateToLoginSequence')(); } else if (app.getState('maintenanceMode')) { if (!skipMaintenanceCheck) { return redirect.gotoMaintenancePage(app); From caf481e7dde6e96af2d50c2dd853e03d7d47b177 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 19 Dec 2023 12:15:06 -0800 Subject: [PATCH 049/700] 10007: Add sequence that runs when app initializes to setup user data, return unauthorized error when no refreshToken --- .../useCases/auth/refreshAuthTokenInteractor.ts | 3 --- temp_delete_me.md | 2 ++ .../src/lambdas/auth/refreshAuthTokenLambda.ts | 5 ++++- web-client/src/app.tsx | 2 +- web-client/src/presenter/presenter.ts | 2 ++ .../presenter/sequences/Init/initAppSequence.ts | 16 ++++++++++++++++ .../sequences/Login/refreshTokenSequence.ts | 2 +- .../sequences/unauthorizedErrorSequence.ts | 2 -- 8 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 web-client/src/presenter/sequences/Init/initAppSequence.ts diff --git a/shared/src/business/useCases/auth/refreshAuthTokenInteractor.ts b/shared/src/business/useCases/auth/refreshAuthTokenInteractor.ts index 48ecab66d0c..e27d6c19936 100644 --- a/shared/src/business/useCases/auth/refreshAuthTokenInteractor.ts +++ b/shared/src/business/useCases/auth/refreshAuthTokenInteractor.ts @@ -4,9 +4,6 @@ export const refreshAuthTokenInteractor = async ( ): Promise<{ token: string; }> => { - if (!refreshToken) { - throw new Error('refreshToken is required'); - } const { token } = await applicationContext .getPersistenceGateway() .renewIdToken(applicationContext, { refreshToken }); diff --git a/temp_delete_me.md b/temp_delete_me.md index 7b067d69af8..e3737ba674d 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -5,6 +5,8 @@ - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - web-client/integration-tests/petitionerCreatesAccount.test.ts +- web-client/src/presenter/sequences/loginWithTokenSequence.ts +- web-client/src/presenter/sequences/Login/refreshTokenSequence.ts ::: STUFF TO DO ::: diff --git a/web-api/src/lambdas/auth/refreshAuthTokenLambda.ts b/web-api/src/lambdas/auth/refreshAuthTokenLambda.ts index 8d481d788a3..a88b9578503 100644 --- a/web-api/src/lambdas/auth/refreshAuthTokenLambda.ts +++ b/web-api/src/lambdas/auth/refreshAuthTokenLambda.ts @@ -1,3 +1,4 @@ +import { UnauthorizedError } from '@web-api/errors/errors'; import { genericHandler } from '../../genericHandler'; import { parseCookieString } from '../../utilities/cookieFormatting'; @@ -6,15 +7,17 @@ export const refreshAuthTokenLambda = event => event, async ({ applicationContext }) => { if (!event.headers.cookie) { - throw new Error('Cookie header is missing'); + throw new UnauthorizedError('refreshToken is required'); } const { refreshToken } = parseCookieString(event.headers.cookie); + const { token } = await applicationContext .getUseCases() .refreshAuthTokenInteractor(applicationContext, { refreshToken, }); + return { token, }; diff --git a/web-client/src/app.tsx b/web-client/src/app.tsx index 4e2bd803166..e5e36820145 100644 --- a/web-client/src/app.tsx +++ b/web-client/src/app.tsx @@ -276,7 +276,7 @@ const app = { const cerebralApp = App(presenter, debugTools); - await cerebralApp.getSequence('startRefreshIntervalSequence')(); + await cerebralApp.getSequence('initAppSequence')(); initializeSocketProvider(cerebralApp, applicationContext); diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 71645caa731..465ad3357ab 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -205,6 +205,7 @@ import { gotoVerifyEmailSequence } from './sequences/gotoVerifyEmailSequence'; import { gotoViewAllDocumentsSequence } from './sequences/gotoViewAllDocumentsSequence'; import { gotoWorkQueueSequence } from './sequences/gotoWorkQueueSequence'; import { handleIdleLogoutSequence } from './sequences/handleIdleLogoutSequence'; +import { initAppSequence } from '@web-client/presenter/sequences/Init/initAppSequence'; import { initialState } from '@web-client/presenter/state'; import { leaveCaseForLaterServiceSequence } from './sequences/leaveCaseForLaterServiceSequence'; import { loadDefaultDocketViewerDocumentToDisplaySequence } from './sequences/DocketEntry/loadDefaultDocketViewerDocumentToDisplaySequence'; @@ -885,6 +886,7 @@ export const presenterSequences = { gotoViewAllDocumentsSequence as unknown as Function, gotoWorkQueueSequence: gotoWorkQueueSequence as unknown as Function, handleIdleLogoutSequence: handleIdleLogoutSequence as unknown as Function, + initAppSequence, leaveCaseForLaterServiceSequence: leaveCaseForLaterServiceSequence as unknown as Function, loadDefaultDocketViewerDocumentToDisplaySequence: diff --git a/web-client/src/presenter/sequences/Init/initAppSequence.ts b/web-client/src/presenter/sequences/Init/initAppSequence.ts new file mode 100644 index 00000000000..a551253f8ba --- /dev/null +++ b/web-client/src/presenter/sequences/Init/initAppSequence.ts @@ -0,0 +1,16 @@ +import { getUserAction } from '@web-client/presenter/actions/getUserAction'; +import { parallel } from 'cerebral/factories'; +import { refreshTokenAction } from '@web-client/presenter/actions/Login/refreshTokenAction'; +import { setTokenAction } from '@web-client/presenter/actions/Login/setTokenAction'; +import { setUserAction } from '@web-client/presenter/actions/setUserAction'; +import { setUserPermissionsAction } from '@web-client/presenter/actions/setUserPermissionsAction'; +import { startRefreshIntervalSequence } from '@web-client/presenter/sequences/startRefreshIntervalSequence'; + +export const initAppSequence = [ + refreshTokenAction, + setTokenAction, + parallel([ + [getUserAction, setUserAction, setUserPermissionsAction], + startRefreshIntervalSequence, + ]), +] as unknown as () => void; diff --git a/web-client/src/presenter/sequences/Login/refreshTokenSequence.ts b/web-client/src/presenter/sequences/Login/refreshTokenSequence.ts index 4253889feeb..0509e87566e 100644 --- a/web-client/src/presenter/sequences/Login/refreshTokenSequence.ts +++ b/web-client/src/presenter/sequences/Login/refreshTokenSequence.ts @@ -6,6 +6,6 @@ import { setUserAction } from '@web-client/presenter/actions/setUserAction'; export const refreshTokenSequence = [ refreshTokenAction, setTokenAction, - getUserAction, // TODO 10007: this seems odd + getUserAction, setUserAction, ] as unknown as () => void; diff --git a/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts b/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts index 5e7a1cf1c31..dd652c3f96d 100644 --- a/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts +++ b/web-client/src/presenter/sequences/unauthorizedErrorSequence.ts @@ -1,11 +1,9 @@ import { clearModalAction } from '../actions/clearModalAction'; import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; -import { setAlertFromExceptionAction } from '../actions/setAlertFromExceptionAction'; import { unsetWaitingForResponseOnErrorAction } from '../actions/unsetWaitingForResponseOnErrorAction'; export const unauthorizedErrorSequence = [ unsetWaitingForResponseOnErrorAction, - setAlertFromExceptionAction, clearModalAction, navigateToLoginSequence, ]; From c7c2e66ffadba0dfcd40149513295872e36cdf3f Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 19 Dec 2023 17:01:10 -0800 Subject: [PATCH 050/700] 10007: Make refresh auth return 403 if the validation fails. --- .../auth/refreshAuthTokenInteractor.ts | 23 ++++++++++++++----- temp_delete_me.md | 1 + web-client/src/app.tsx | 5 ---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/shared/src/business/useCases/auth/refreshAuthTokenInteractor.ts b/shared/src/business/useCases/auth/refreshAuthTokenInteractor.ts index e27d6c19936..a108a6f6da8 100644 --- a/shared/src/business/useCases/auth/refreshAuthTokenInteractor.ts +++ b/shared/src/business/useCases/auth/refreshAuthTokenInteractor.ts @@ -1,14 +1,25 @@ +import { AWSError } from 'aws-sdk'; +import { UnauthorizedError } from '@web-api/errors/errors'; + export const refreshAuthTokenInteractor = async ( applicationContext: IApplicationContext, { refreshToken }: { refreshToken: string }, ): Promise<{ token: string; }> => { - const { token } = await applicationContext - .getPersistenceGateway() - .renewIdToken(applicationContext, { refreshToken }); + try { + const { token } = await applicationContext + .getPersistenceGateway() + .renewIdToken(applicationContext, { refreshToken }); + + return { + token, + }; + } catch (err) { + if ((err as AWSError).code === 'NotAuthorizedException') { + throw new UnauthorizedError('Invalid refresh token'); + } - return { - token, - }; + throw err; + } }; diff --git a/temp_delete_me.md b/temp_delete_me.md index e3737ba674d..7472c465ffc 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -21,6 +21,7 @@ - invalidate old refreshToken and idToken upon refresh. - Ensure idToken lasts longer than how often we are refreshing the idToken (REFRESH_INTERVAL) - Make app-local.ts not create another webserver just to listen to incoming requests from cognito-local. +- cognit to V3 ::: SOLO TO DO ::: - consistent (LoginInteractor). Lets go with Login. diff --git a/web-client/src/app.tsx b/web-client/src/app.tsx index e5e36820145..d2cd55e9aff 100644 --- a/web-client/src/app.tsx +++ b/web-client/src/app.tsx @@ -156,11 +156,6 @@ const app = { presenter.state.clientConnectionId = applicationContext.getUniqueId(); - const userPermissions = applicationContext.getCurrentUserPermissions(); - if (userPermissions) { - presenter.state.permissions = userPermissions; - } - config.autoAddCss = false; library.add( faArrowAltCircleLeftRegular, From 7c085f03c55063070c00343e0c2310efea59fe7d Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 19 Dec 2023 17:27:28 -0800 Subject: [PATCH 051/700] 10007: Update how cypress is logging in --- cypress/cypress-integration/support/commands.ts | 17 +++++++++++------ web-client/src/views/Login/Login.tsx | 3 +++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cypress/cypress-integration/support/commands.ts b/cypress/cypress-integration/support/commands.ts index 98e3f22d237..58357ab3f8c 100644 --- a/cypress/cypress-integration/support/commands.ts +++ b/cypress/cypress-integration/support/commands.ts @@ -25,12 +25,17 @@ Cypress.Commands.add('showsSuccessMessage', (shows = true) => { }); Cypress.Commands.add('login', (username, route = '/') => { - const url = `/log-in?code=${username}@example.com&path=${route}`; - cy.visit(url); - cy.waitUntilSettled(50); - cy.url().should('include', route); - cy.showsErrorMessage(false); - cy.url().should('not.include', '/mock-login'); + cy.visit('/login'); + + cy.get('[data-testid="email-input"]').type(`${username}@example.com`); + + cy.get('[data-testid="password-input"]').type('Testing1234$', { log: false }); + + cy.get('[data-testid="login-button"]').click(); + + cy.get('[data-testid="account-menu-button"]'); + + cy.visit(route); }); Cypress.Commands.add('goToRoute', (...args) => { diff --git a/web-client/src/views/Login/Login.tsx b/web-client/src/views/Login/Login.tsx index 7e01f40217e..11f09b5b590 100644 --- a/web-client/src/views/Login/Login.tsx +++ b/web-client/src/views/Login/Login.tsx @@ -44,6 +44,7 @@ export const Login = connect( autoCapitalize="off" autoCorrect="off" className="usa-input" + data-testid="email-input" id="email" name="email" type="text" @@ -61,6 +62,7 @@ export const Login = connect( -

-

From 1c42135e58db6846c330257e3f295203487ad157 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Fri, 29 Dec 2023 11:29:34 -0800 Subject: [PATCH 076/700] 10007: Register login route correctly --- web-client/src/router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-client/src/router.ts b/web-client/src/router.ts index 876f4c6a55e..eab35401a2f 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -1116,7 +1116,7 @@ const router = { return app.getSequence('gotoIdleLogoutSequence')(); }); - route('/login', () => { + registerRoute('/login', () => { setPageTitle('Login'); app.getSequence('gotoLoginSequence')(); }); From 8f051e1ce319fd24c58b8ddf2197044f09c831e3 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 29 Dec 2023 11:35:57 -0800 Subject: [PATCH 077/700] 10007: await when routing --- .../src/presenter/actions/Login/navigateToLoginAction.ts | 4 ++-- .../actions/navigateToPractitionerDocumentsPageAction.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web-client/src/presenter/actions/Login/navigateToLoginAction.ts b/web-client/src/presenter/actions/Login/navigateToLoginAction.ts index 8e0e32abfcc..cc89242932b 100644 --- a/web-client/src/presenter/actions/Login/navigateToLoginAction.ts +++ b/web-client/src/presenter/actions/Login/navigateToLoginAction.ts @@ -1,3 +1,3 @@ -export const navigateToLoginAction = ({ router }) => { - router.route('/login'); +export const navigateToLoginAction = async ({ router }) => { + await router.route('/login'); }; diff --git a/web-client/src/presenter/actions/navigateToPractitionerDocumentsPageAction.ts b/web-client/src/presenter/actions/navigateToPractitionerDocumentsPageAction.ts index 0d9302c1d75..af393830878 100644 --- a/web-client/src/presenter/actions/navigateToPractitionerDocumentsPageAction.ts +++ b/web-client/src/presenter/actions/navigateToPractitionerDocumentsPageAction.ts @@ -5,12 +5,12 @@ import { state } from '@web-client/presenter/app.cerebral'; * @returns {void} */ -export const navigateToPractitionerDocumentsPageAction = ({ +export const navigateToPractitionerDocumentsPageAction = async ({ get, router, }: ActionProps) => { const practitionerDetail = get(state.practitionerDetail); - router.route( + await router.route( `/practitioner-detail/${practitionerDetail.barNumber}?tab=practitioner-documentation`, ); }; From 0c4a4b6e3eb96bc3370b010f9a4843878f3edab7 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 29 Dec 2023 14:11:54 -0800 Subject: [PATCH 078/700] 10007: add custom:name for cognito-local as we are unable to use 'name' in the idToken. --- .cognito/seedCognitoLocal.ts | 10 +++++++--- web-api/src/applicationContext.ts | 2 ++ web-api/src/middleware/apiGatewayHelper.ts | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.cognito/seedCognitoLocal.ts b/.cognito/seedCognitoLocal.ts index 8e56f7b5ae9..416df5e7a01 100644 --- a/.cognito/seedCognitoLocal.ts +++ b/.cognito/seedCognitoLocal.ts @@ -1,6 +1,6 @@ import users from '../web-api/storage/fixtures/seed/users.json'; import fs from 'fs'; -import path from 'path' +import path from 'path'; type CognitoLocalJSON = { Users: { @@ -103,11 +103,11 @@ const cognitoLocalJSON: CognitoLocalJSON = { }, }, { - Name: 'name', + Name: 'custom:name', AttributeDataType: 'String', DeveloperOnlyAttribute: false, Mutable: true, - Required: false, + Required: true, StringAttributeConstraints: { MinLength: '0', MaxLength: '2048', @@ -214,6 +214,10 @@ users.forEach(user => { Name: 'custom:role', Value: user.role, }, + { + Name: 'custom:name', + Value: user.name, + }, ], Enabled: false, UserStatus: 'CONFIRMED', diff --git a/web-api/src/applicationContext.ts b/web-api/src/applicationContext.ts index 2b234d77278..3bbec9d69eb 100644 --- a/web-api/src/applicationContext.ts +++ b/web-api/src/applicationContext.ts @@ -127,6 +127,8 @@ export const createApplicationContext = ( const getCurrentUser = (): { role: string; userId: string; + email: string; + name: string; } => { return user; }; diff --git a/web-api/src/middleware/apiGatewayHelper.ts b/web-api/src/middleware/apiGatewayHelper.ts index 631271918f0..e6e13cd2b5c 100644 --- a/web-api/src/middleware/apiGatewayHelper.ts +++ b/web-api/src/middleware/apiGatewayHelper.ts @@ -182,6 +182,7 @@ export const getUserFromAuthHeader = event => { decoded.token = token; decoded.role = decoded['custom:role']; decoded.userId = decoded['custom:userId'] || decoded.sub; + decoded.name = decoded.name || decoded['custom:name']; // custom:name only exists locally. This is a workaround for cognito-local. return decoded; } else { return null; From 540b73b03805c5e9586e870625eaf50cb6214d87 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 29 Dec 2023 14:27:17 -0800 Subject: [PATCH 079/700] 10007: temporarily skip tests for new user account creation. Will move tests to cypress once new user account flow is implemented. --- ...onsClerkCreatesPractitionerAccount.test.ts | 4 +- .../authenticationCookies.test.ts | 29 +----------- ...ketClerkEditsPetitionerInformation.test.ts | 8 +--- .../petitionerCreatesAccount.test.ts | 3 +- .../actions/createTokenAction.test.ts | 45 ------------------- .../presenter/actions/createTokenAction.ts | 36 --------------- 6 files changed, 8 insertions(+), 117 deletions(-) delete mode 100644 web-client/src/presenter/actions/createTokenAction.test.ts delete mode 100644 web-client/src/presenter/actions/createTokenAction.ts diff --git a/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts b/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts index 6d49255d5b9..428aefb3786 100644 --- a/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts +++ b/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts @@ -2,7 +2,8 @@ import { admissionsClerkAddsNewPractitioner } from './journey/admissionsClerkAdd import { faker } from '@faker-js/faker'; import { loginAs, setupTest, waitForLoadingComponentToHide } from './helpers'; -describe('Admissions clerk creates practitioner account', () => { +// TODO 10007: Need to implement new account creation flow when user is forced to change password. +describe.skip('Admissions clerk creates practitioner account', () => { const cerebralTest = setupTest(); afterAll(() => { @@ -28,7 +29,6 @@ describe('Admissions clerk creates practitioner account', () => { value: standardizedTemporaryPassword, }); - // TODO 10007 // await cerebralTest.runSequence('loginWithCognitoLocalSequence', { // code: emailAddress, // password: standardizedTemporaryPassword, diff --git a/web-client/integration-tests/authenticationCookies.test.ts b/web-client/integration-tests/authenticationCookies.test.ts index 5083c171acb..f0e1d748c49 100644 --- a/web-client/integration-tests/authenticationCookies.test.ts +++ b/web-client/integration-tests/authenticationCookies.test.ts @@ -1,31 +1,6 @@ import axios from 'axios'; -describe('checks the /auth endpoints to verify the cookies are set and cleared correctly', () => { - let cookie = null; - - it('should get back a token in the header when hitting the login endpoint', async () => { - const response = await axios.post('http://localhost:4000/auth/login', { - code: 'petitionsclerk@example.com', - }); - cookie = response.headers['set-cookie']; - expect(cookie).toBeDefined(); - expect(response.data.token).toBeDefined(); - }); - - it('should be able to hit the refresh endpoint get a new token', async () => { - const response = await axios.post( - 'http://localhost:4000/auth/refresh', - null, - { - headers: { - Cookie: cookie, - }, - }, - ); - - expect(response.data.token).toBeDefined(); - }); - +describe('checks the /auth endpoints to verify the cookies are cleared correctly', () => { it('after hitting DELETE@/auth/login, the refresh endpoint should no longer return a new token', async () => { const response = await axios.delete('http://localhost:4000/auth/login'); expect(response.headers['set-cookie'][0]).toContain( @@ -33,6 +8,6 @@ describe('checks the /auth endpoints to verify the cookies are set and cleared c ); await expect( axios.post('http://localhost:4000/auth/refresh'), - ).rejects.toThrow('Request failed with status code 400'); + ).rejects.toThrow('Request failed with status code 403'); }); }); diff --git a/web-client/integration-tests/docketClerkEditsPetitionerInformation.test.ts b/web-client/integration-tests/docketClerkEditsPetitionerInformation.test.ts index 1c162f2c707..11c0097d94d 100644 --- a/web-client/integration-tests/docketClerkEditsPetitionerInformation.test.ts +++ b/web-client/integration-tests/docketClerkEditsPetitionerInformation.test.ts @@ -7,13 +7,9 @@ import { } from './helpers'; import { petitionsClerkServesElectronicCaseToIrs } from './journey/petitionsClerkServesElectronicCaseToIrs'; -const cerebralTest = setupTest(); -const { COUNTRY_TYPES, PARTY_TYPES } = applicationContext.getConstants(); - describe('docket clerk edits the petitioner information', () => { - beforeEach(() => { - jest.setTimeout(50000); - }); + const cerebralTest = setupTest(); + const { COUNTRY_TYPES, PARTY_TYPES } = applicationContext.getConstants(); afterAll(() => { cerebralTest.closeSocket(); diff --git a/web-client/integration-tests/petitionerCreatesAccount.test.ts b/web-client/integration-tests/petitionerCreatesAccount.test.ts index 259324d0b68..4060b896b73 100644 --- a/web-client/integration-tests/petitionerCreatesAccount.test.ts +++ b/web-client/integration-tests/petitionerCreatesAccount.test.ts @@ -4,7 +4,8 @@ import { setupTest as setupTestPublic } from '../integration-tests-public/helper import { userSuccessfullyUpdatesEmailAddress } from './journey/userSuccessfullyUpdatesEmailAddress'; import { userVerifiesUpdatedEmailAddress } from './journey/userVerifiesUpdatedEmailAddress'; -describe('Petitioner creates new account', () => { +// TODO: 10007 - we need to implement force password change +describe.skip('Petitioner creates new account', () => { const cerebralTestPrivate = setupTestPrivate(); const cerebralTestPublic = setupTestPublic(); diff --git a/web-client/src/presenter/actions/createTokenAction.test.ts b/web-client/src/presenter/actions/createTokenAction.test.ts deleted file mode 100644 index bc0d6f681bd..00000000000 --- a/web-client/src/presenter/actions/createTokenAction.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; -import { createTokenAction } from './createTokenAction'; -import { presenter } from '../presenter-mock'; -import { runAction } from '@web-client/presenter/test.cerebral'; - -describe('createTokenAction', () => { - beforeAll(() => { - presenter.providers.applicationContext = applicationContext; - }); - - it('should create a token for a valid username', async () => { - const result = await runAction(createTokenAction, { - modules: { - presenter, - }, - state: { form: { name: 'petitioner@example.com' } }, - }); - - expect(result.output.token).toBeDefined(); - }); - - it('should throw an error if the username is not in the mock logins', async () => { - await expect( - runAction(createTokenAction, { - modules: { - presenter, - }, - state: { form: { name: 'nachos' } }, - }), - ).rejects.toThrow('Username "nachos" not found in mock logins.'); - }); - - it('should throw an error if the user is a legacyJudge due to legacy judges not allowed to login (no account)', async () => { - await expect( - runAction(createTokenAction, { - modules: { - presenter, - }, - state: { form: { name: 'judgefieri@example.com' } }, - }), - ).rejects.toThrow( - 'The legacy judge "judgefieri@example.com" cannot login.', - ); - }); -}); diff --git a/web-client/src/presenter/actions/createTokenAction.ts b/web-client/src/presenter/actions/createTokenAction.ts deleted file mode 100644 index 0f91a3c9c1c..00000000000 --- a/web-client/src/presenter/actions/createTokenAction.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ActionError } from '../errors/ActionError'; -import { state } from '@web-client/presenter/app.cerebral'; -import { userMap } from '../../../../shared/src/test/mockUserTokenMap'; -import jwt from 'jsonwebtoken'; - -/** - * this is used for creating a jwt token to login locally only - * @param {object} providers the providers object - * @param {Function} providers.applicationContext the application context - * @param {Function} providers.get the cerebral get function - * @param {object} providers.props the cerebral props object - * @returns {object} the jwt token - */ -export const createTokenAction = ({ - applicationContext, - get, - props, -}: ActionProps) => { - const name = props.token || get(state.form.name); - if (!userMap[name]) { - throw new ActionError(`Username "${name}" not found in mock logins.`); - } - - const { USER_ROLES } = applicationContext.getConstants(); - if (userMap[name]['custom:role'] === USER_ROLES.legacyJudge) { - throw new ActionError(`The legacy judge "${name}" cannot login.`); - } - - const user = { - ...userMap[name], - sub: userMap[name].userId, - }; - return { - token: jwt.sign(user, 'secret'), - }; -}; From d212d65556b3ba4d12c7f2755c1b18b11c81d769 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 1 Jan 2024 20:21:35 -0800 Subject: [PATCH 080/700] 10007: Add error handling for logging in --- .../business/useCases/auth/loginInteractor.ts | 39 ++++++++++++------- .../actions/Login/submitLoginAction.ts | 31 +++++++++++---- .../sequences/Login/submitLoginSequence.ts | 20 ++++++---- 3 files changed, 60 insertions(+), 30 deletions(-) diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index c72de5f38b4..d70be0c8a32 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -1,4 +1,5 @@ import { ServerApplicationContext } from '@web-api/applicationContext'; +import { UnknownUserError } from '@web-api/errors/errors'; export const loginInteractor = async ( applicationContext: ServerApplicationContext, @@ -6,20 +7,28 @@ export const loginInteractor = async ( ): Promise<{ idToken: string; accessToken: string; refreshToken: string }> => { const cognito = applicationContext.getCognito(); - const result = await cognito - .initiateAuth({ - AuthFlow: 'USER_PASSWORD_AUTH', - AuthParameters: { - PASSWORD: password, - USERNAME: email, - }, - ClientId: applicationContext.environment.cognitoClientId, - }) - .promise(); // TODO 10007: Update cognito to v3 + try { + const result = await cognito + .initiateAuth({ + AuthFlow: 'USER_PASSWORD_AUTH', + AuthParameters: { + PASSWORD: password, + USERNAME: email, + }, + ClientId: applicationContext.environment.cognitoClientId, + }) + .promise(); // TODO 10007: Update cognito to v3 - return { - accessToken: result.AuthenticationResult!.AccessToken!, - idToken: result.AuthenticationResult!.IdToken!, - refreshToken: result.AuthenticationResult!.RefreshToken!, - }; + return { + accessToken: result.AuthenticationResult!.AccessToken!, + idToken: result.AuthenticationResult!.IdToken!, + refreshToken: result.AuthenticationResult!.RefreshToken!, + }; + } catch (err: any) { + // AWS Cognito InvalidPasswordException + if (err.code === 'InvalidPasswordException') { + throw new UnknownUserError('Invalid Username or Password'); + } + throw err; + } }; diff --git a/web-client/src/presenter/actions/Login/submitLoginAction.ts b/web-client/src/presenter/actions/Login/submitLoginAction.ts index c3ab688703b..f6e744108da 100644 --- a/web-client/src/presenter/actions/Login/submitLoginAction.ts +++ b/web-client/src/presenter/actions/Login/submitLoginAction.ts @@ -3,6 +3,7 @@ import { state } from '@web-client/presenter/app.cerebral'; export const submitLoginAction = async ({ applicationContext, get, + path, }: ActionProps): Promise<{ accessToken: string; idToken: string; @@ -10,13 +11,27 @@ export const submitLoginAction = async ({ }> => { const { email, password } = get(state.form); - const { accessToken, idToken, refreshToken } = await applicationContext - .getUseCases() - .loginInteractor(applicationContext, { email, password }); + try { + const { accessToken, idToken, refreshToken } = await applicationContext + .getUseCases() + .loginInteractor(applicationContext, { email, password }); - return { - accessToken, - idToken, - refreshToken, - }; + return path.success({ accessToken, idToken, refreshToken }); + } catch (err: any) { + if (err.responseCode === 401) { + return path.error({ + alertError: { + message: 'The email address or password you entered is invalid.', + title: 'Please correct the following errors:', + }, + }); + } + + return path.error({ + alertError: { + title: + 'There was an unexpected error when logging in. Please try again.', + }, + }); + } }; diff --git a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts index e2687d42c21..cbd4b25d65a 100644 --- a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts @@ -2,6 +2,7 @@ import { clearFormAction } from '@web-client/presenter/actions/clearFormAction'; import { decodeTokenAction } from '@web-client/presenter/actions/decodeTokenAction'; import { getUserAction } from '@web-client/presenter/actions/getUserAction'; import { navigateToPathAction } from '@web-client/presenter/actions/navigateToPathAction'; +import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertErrorAction'; import { setTokenAction } from '@web-client/presenter/actions/Login/setTokenAction'; import { setUserAction } from '@web-client/presenter/actions/setUserAction'; import { setUserPermissionsAction } from '@web-client/presenter/actions/setUserPermissionsAction'; @@ -9,11 +10,16 @@ import { submitLoginAction } from '@web-client/presenter/actions/Login/submitLog export const submitLoginSequence = [ submitLoginAction, - clearFormAction, - decodeTokenAction, - setTokenAction, - getUserAction, - setUserAction, - setUserPermissionsAction, - navigateToPathAction, + { + error: [setAlertErrorAction], + success: [ + clearFormAction, + decodeTokenAction, + setTokenAction, + getUserAction, + setUserAction, + setUserPermissionsAction, + navigateToPathAction, + ], + }, ] as unknown as () => void; From 4603b600a857cbbafd146c5e47b0cbf3ea374876 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 1 Jan 2024 20:36:44 -0800 Subject: [PATCH 081/700] 10007: Disable login button when there is not a password or email address. --- web-api/src/business/useCases/auth/loginInteractor.ts | 5 ++++- web-client/src/presenter/computeds/Login/loginHelper.ts | 9 +++++++++ .../presenter/sequences/toggleShowPasswordSequence.ts | 2 +- web-client/src/presenter/state.ts | 2 ++ web-client/src/views/Login/Login.tsx | 5 +++-- 5 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 web-client/src/presenter/computeds/Login/loginHelper.ts diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index d70be0c8a32..deaf5612790 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -26,7 +26,10 @@ export const loginInteractor = async ( }; } catch (err: any) { // AWS Cognito InvalidPasswordException - if (err.code === 'InvalidPasswordException') { + if ( + err.code === 'InvalidPasswordException' || + err.code === 'NotAuthorizedException' + ) { throw new UnknownUserError('Invalid Username or Password'); } throw err; diff --git a/web-client/src/presenter/computeds/Login/loginHelper.ts b/web-client/src/presenter/computeds/Login/loginHelper.ts new file mode 100644 index 00000000000..233a6e851f2 --- /dev/null +++ b/web-client/src/presenter/computeds/Login/loginHelper.ts @@ -0,0 +1,9 @@ +import { Get } from 'cerebral'; +import { state } from '@web-client/presenter/app.cerebral'; + +export const loginHelper = (get: Get): { disableLoginButton: boolean } => { + const { email, password } = get(state.form); + + const disableLoginButton = !email || !password; + return { disableLoginButton }; +}; diff --git a/web-client/src/presenter/sequences/toggleShowPasswordSequence.ts b/web-client/src/presenter/sequences/toggleShowPasswordSequence.ts index 548637f5ea4..c9c8d07ecc9 100644 --- a/web-client/src/presenter/sequences/toggleShowPasswordSequence.ts +++ b/web-client/src/presenter/sequences/toggleShowPasswordSequence.ts @@ -2,4 +2,4 @@ import { toggleShowPasswordAction } from '@web-client/presenter/actions/toggleSh export const toggleShowPasswordSequence = [ toggleShowPasswordAction, -] as unknown as (passwordType: string) => void; +] as unknown as (props: { passwordType: string }) => void; diff --git a/web-client/src/presenter/state.ts b/web-client/src/presenter/state.ts index c49135e16ae..26e71acd7d8 100644 --- a/web-client/src/presenter/state.ts +++ b/web-client/src/presenter/state.ts @@ -90,6 +90,7 @@ import { internalPetitionPartiesHelper } from './computeds/internalPetitionParti import { internalTypesHelper } from './computeds/internalTypesHelper'; import { judgeActivityReportHelper } from './computeds/JudgeActivityReport/judgeActivityReportHelper'; import { loadingHelper } from './computeds/loadingHelper'; +import { loginHelper } from '@web-client/presenter/computeds/Login/loginHelper'; import { menuHelper } from './computeds/menuHelper'; import { messageDocumentHelper } from './computeds/messageDocumentHelper'; import { messageModalHelper } from './computeds/messageModalHelper'; @@ -383,6 +384,7 @@ export const computeds = { typeof judgeActivityReportHelper >, loadingHelper: loadingHelper as unknown as ReturnType, + loginHelper: loginHelper as unknown as ReturnType, menuHelper: menuHelper as unknown as ReturnType, messageDocumentHelper: messageDocumentHelper as unknown as ReturnType< typeof messageDocumentHelper diff --git a/web-client/src/views/Login/Login.tsx b/web-client/src/views/Login/Login.tsx index 4e2707820aa..8d04caae604 100644 --- a/web-client/src/views/Login/Login.tsx +++ b/web-client/src/views/Login/Login.tsx @@ -8,6 +8,7 @@ export const Login = connect( { alertError: state.alertError, form: state.form, + loginHelper: state.loginHelper, showPassword: state.showPassword, submitLoginSequence: sequences.submitLoginSequence, toggleShowPasswordSequence: sequences.toggleShowPasswordSequence, @@ -16,6 +17,7 @@ export const Login = connect( ({ alertError, form, + loginHelper, showPassword, submitLoginSequence, toggleShowPasswordSequence, @@ -88,6 +90,7 @@ export const Login = connect( - - -
- -
-
- Don't have an account?{' '} - +
+
+
+
+
+

Log in to DAWSON

+ + Email address and password are case sensitive. + +
+ + { + updateFormValueSequence({ + key: e.target.name, + value: e.target.value, + }); + }} + /> + + { + updateFormValueSequence({ + key: e.target.name, + value: e.target.value, + }); + }} + /> + + +
+
+ +
+
+ Don't have an account?{' '} + +
+
+
-
+
); }, From 1b96a3c4bece749811e2d5c833569b7bb7845aa9 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Tue, 2 Jan 2024 13:32:33 -0800 Subject: [PATCH 085/700] 10007: WIP convert to cognito v3 --- .../test/createTestApplicationContext.ts | 14 ++---- .../auth/confirmSignUpLocalInteractor.ts | 18 +++----- .../useCases/auth/renewIdTokenInteractor.ts | 4 +- .../useCases/users/signUpUserInteractor.ts | 30 ++++++------- web-api/src/applicationContext.ts | 3 +- .../business/useCases/auth/loginInteractor.ts | 18 ++++---- web-api/src/cognitoLocalWrapper.ts | 4 +- web-api/src/persistence/cognito/getCognito.ts | 43 ++++++++++--------- .../src/persistence/cognito/renewIdToken.ts | 17 +++----- 9 files changed, 64 insertions(+), 87 deletions(-) diff --git a/shared/src/business/test/createTestApplicationContext.ts b/shared/src/business/test/createTestApplicationContext.ts index 03e6e68dd0d..3865e8f84e2 100644 --- a/shared/src/business/test/createTestApplicationContext.ts +++ b/shared/src/business/test/createTestApplicationContext.ts @@ -601,15 +601,9 @@ export const createTestApplicationContext = ({ return mockGetChromiumBrowserReturnValue; }), getCognito: appContextProxy({ - adminCreateUser: jest.fn().mockReturnValue({ - promise: jest.fn(), - }), - adminUpdateUserAttributes: jest.fn().mockReturnValue({ - promise: jest.fn(), - }), - initiateAuth: jest.fn().mockReturnValue({ - promise: jest.fn(), - }), + adminCreateUser: jest.fn(), + adminUpdateUserAttributes: jest.fn(), + initiateAuth: jest.fn(), }), getCognitoRequestPasswordResetUrl, getConstants: jest.fn().mockImplementation(() => { @@ -697,5 +691,3 @@ export const createTestApplicationContext = ({ }; return applicationContext; }; - -export const applicationContext = createTestApplicationContext(); diff --git a/shared/src/business/useCases/auth/confirmSignUpLocalInteractor.ts b/shared/src/business/useCases/auth/confirmSignUpLocalInteractor.ts index 1d5f5a3e79f..c081bf88161 100644 --- a/shared/src/business/useCases/auth/confirmSignUpLocalInteractor.ts +++ b/shared/src/business/useCases/auth/confirmSignUpLocalInteractor.ts @@ -1,11 +1,5 @@ -/** - * confirmSignUpLocalInteractor - * @param {object} applicationContext the application context - * @param {object} auth an object - * @param {string} auth.confirmationCode the email confirmation code provided by cognito - * @param {string} auth.userEmail the email of the user confirming their account - * @returns {Promise} the promise of both the refresh token and the auth token - */ +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; + export const confirmSignUpLocalInteractor = async ( applicationContext: IApplicationContext, { @@ -13,11 +7,11 @@ export const confirmSignUpLocalInteractor = async ( userEmail, }: { confirmationCode: string; userEmail: string }, ) => { - const params = { + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + + return await cognito.confirmSignUp({ ClientId: process.env.COGNITO_CLIENT_ID, ConfirmationCode: confirmationCode, Username: userEmail, - }; - - return await applicationContext.getCognito().confirmSignUp(params).promise(); + }); }; diff --git a/shared/src/business/useCases/auth/renewIdTokenInteractor.ts b/shared/src/business/useCases/auth/renewIdTokenInteractor.ts index 9a1a49f5753..fc1fcf2e865 100644 --- a/shared/src/business/useCases/auth/renewIdTokenInteractor.ts +++ b/shared/src/business/useCases/auth/renewIdTokenInteractor.ts @@ -1,4 +1,4 @@ -import { AWSError } from 'aws-sdk'; +import { NotAuthorizedException } from '@aws-sdk/client-cognito-identity-provider'; import { UnauthorizedError } from '@web-api/errors/errors'; export const renewIdTokenInteractor = async ( @@ -16,7 +16,7 @@ export const renewIdTokenInteractor = async ( idToken, }; } catch (err) { - if ((err as AWSError).code === 'NotAuthorizedException') { + if (err instanceof NotAuthorizedException) { throw new UnauthorizedError('Invalid refresh token'); } diff --git a/shared/src/business/useCases/users/signUpUserInteractor.ts b/shared/src/business/useCases/users/signUpUserInteractor.ts index 22e76589c0a..effdd85ad33 100644 --- a/shared/src/business/useCases/users/signUpUserInteractor.ts +++ b/shared/src/business/useCases/users/signUpUserInteractor.ts @@ -1,7 +1,4 @@ -import { - type AdminCreateUserResponse, - UsersListType, -} from 'aws-sdk/clients/cognitoidentityserviceprovider'; +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; export const signUpUserInteractor = async ( @@ -16,13 +13,13 @@ export const signUpUserInteractor = async ( confirmPassword: string; }; }, -): Promise => { +) => { const existingUsers = await checkUserAlreadyExists( applicationContext, user.email, ); - if (existingUsers.length) { + if (existingUsers?.length) { const accountUnconfirmed = existingUsers.some( acct => acct.UserStatus === 'UNCONFIRMED', ); @@ -36,7 +33,9 @@ export const signUpUserInteractor = async ( const newUser = new NewPetitionerUser(user).validate().toRawObject(); - const params = { + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + + return await cognito.signUp({ ClientId: process.env.COGNITO_CLIENT_ID, Password: newUser.password, UserAttributes: [ @@ -50,25 +49,20 @@ export const signUpUserInteractor = async ( }, ], Username: newUser.email, - }; - - return await applicationContext.getCognito().signUp(params).promise(); + }); }; const checkUserAlreadyExists = async ( applicationContext: IApplicationContext, email: string, -): Promise => { - const filters = { +) => { + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + + const inCognito = await cognito.listUsers({ AttributesToGet: ['email'], Filter: `email = "${email}"`, UserPoolId: process.env.USER_POOL_ID, - }; - - const inCognito = await applicationContext - .getCognito() - .listUsers(filters) - .promise(); + }); return inCognito.Users; }; diff --git a/web-api/src/applicationContext.ts b/web-api/src/applicationContext.ts index 3bbec9d69eb..3927118fbe7 100644 --- a/web-api/src/applicationContext.ts +++ b/web-api/src/applicationContext.ts @@ -18,6 +18,7 @@ import { import { Case } from '../../shared/src/business/entities/cases/Case'; import { CaseDeadline } from '../../shared/src/business/entities/CaseDeadline'; import { Client } from '@opensearch-project/opensearch'; +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { Correspondence } from '../../shared/src/business/entities/Correspondence'; import { DocketEntry } from '../../shared/src/business/entities/DocketEntry'; import { IrsPractitioner } from '../../shared/src/business/entities/IrsPractitioner'; @@ -156,7 +157,7 @@ export const createApplicationContext = ( process.env.NODE_ENV === 'production' ? getChromiumBrowserAWS : getChromiumBrowser, - getCognito: () => { + getCognito: (): CognitoIdentityProvider => { if (environment.stage === 'local') { return getLocalCognito(); } else { diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index deaf5612790..2e99ca58351 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -8,16 +8,14 @@ export const loginInteractor = async ( const cognito = applicationContext.getCognito(); try { - const result = await cognito - .initiateAuth({ - AuthFlow: 'USER_PASSWORD_AUTH', - AuthParameters: { - PASSWORD: password, - USERNAME: email, - }, - ClientId: applicationContext.environment.cognitoClientId, - }) - .promise(); // TODO 10007: Update cognito to v3 + const result = await cognito.initiateAuth({ + AuthFlow: 'USER_PASSWORD_AUTH', + AuthParameters: { + PASSWORD: password, + USERNAME: email, + }, + ClientId: applicationContext.environment.cognitoClientId, + }); return { accessToken: result.AuthenticationResult!.AccessToken!, diff --git a/web-api/src/cognitoLocalWrapper.ts b/web-api/src/cognitoLocalWrapper.ts index e24e5961be7..8ba70d8362d 100644 --- a/web-api/src/cognitoLocalWrapper.ts +++ b/web-api/src/cognitoLocalWrapper.ts @@ -22,9 +22,7 @@ export const cognitoLocalWrapper = cognito => { if (methodName === 'adminCreateUser') { params.DesiredDeliveryMediums = ['EMAIL']; } - const response = await originalMethod - .call(this, params) - .promise(); + const response = await originalMethod.call(this, params); return new Promise(resolve => { if (response.User) { diff --git a/web-api/src/persistence/cognito/getCognito.ts b/web-api/src/persistence/cognito/getCognito.ts index e3e9ea1a708..1ee444827b3 100644 --- a/web-api/src/persistence/cognito/getCognito.ts +++ b/web-api/src/persistence/cognito/getCognito.ts @@ -1,35 +1,38 @@ -import { CognitoIdentityServiceProvider } from 'aws-sdk'; -import { cognitoLocalWrapper } from '@web-api/cognitoLocalWrapper'; +import { Agent } from 'https'; +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; +import { NodeHttpHandler } from '@smithy/node-http-handler'; -let cognitoClientCache: CognitoIdentityServiceProvider; +let cognitoClientCache: CognitoIdentityProvider; export function getCognito() { if (!cognitoClientCache) { - cognitoClientCache = new CognitoIdentityServiceProvider({ - httpOptions: { - connectTimeout: 3000, - timeout: 5000, - }, - maxRetries: 3, + cognitoClientCache = new CognitoIdentityProvider({ + maxAttempts: 3, region: 'us-east-1', + requestHandler: new NodeHttpHandler({ + connectionTimeout: 3000, + httpsAgent: new Agent({ keepAlive: true, maxSockets: 75 }), + requestTimeout: 5000, + }), }); } + return cognitoClientCache; } export function getLocalCognito() { if (!cognitoClientCache) { - cognitoClientCache = cognitoLocalWrapper( - new CognitoIdentityServiceProvider({ - endpoint: 'http://localhost:9229/', - httpOptions: { - connectTimeout: 3000, - timeout: 5000, - }, - maxRetries: 3, - region: 'local', - }), - ); + cognitoClientCache = new CognitoIdentityProvider({ + endpoint: 'http://localhost:9229/', + maxAttempts: 3, + region: 'local', + // requestHandler: new NodeHttpHandler({ + // connectionTimeout: 3000, + // httpsAgent: new Agent({ keepAlive: true, maxSockets: 75 }), + // requestTimeout: 5000, + // }), + }); } + return cognitoClientCache; } diff --git a/web-api/src/persistence/cognito/renewIdToken.ts b/web-api/src/persistence/cognito/renewIdToken.ts index d745047c2e9..a21f6e1c950 100644 --- a/web-api/src/persistence/cognito/renewIdToken.ts +++ b/web-api/src/persistence/cognito/renewIdToken.ts @@ -6,16 +6,13 @@ export const renewIdToken = async ( ): Promise<{ idToken: string }> => { const clientId = applicationContext.environment.cognitoClientId; - const result = await applicationContext - .getCognito() - .initiateAuth({ - AuthFlow: 'REFRESH_TOKEN_AUTH', - AuthParameters: { - REFRESH_TOKEN: refreshToken, - }, - ClientId: clientId, - }) - .promise(); + const result = await applicationContext.getCognito().initiateAuth({ + AuthFlow: 'REFRESH_TOKEN_AUTH', + AuthParameters: { + REFRESH_TOKEN: refreshToken, + }, + ClientId: clientId, + }); return { idToken: result.AuthenticationResult?.IdToken!, From bd23fbcd1e206b13ae310472d717974f402730ec Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Tue, 2 Jan 2024 13:55:22 -0800 Subject: [PATCH 086/700] 10007: Finish upgrading cognito to AWS SDK v3 --- .../resendVerificationLinkInteractor.ts | 12 +-- .../cognito/getCognitoUserIdByEmail.ts | 16 ++-- .../dynamo/users/createNewPetitionerUser.ts | 11 ++- .../dynamo/users/createNewPractitionerUser.ts | 58 +++++++------- .../users/createOrUpdatePractitionerUser.ts | 48 +++++------- .../dynamo/users/createOrUpdateUser.ts | 78 ++++++++----------- .../dynamo/users/updatePractitionerUser.ts | 25 +++--- .../dynamo/users/updateUserEmail.ts | 34 ++++---- 8 files changed, 135 insertions(+), 147 deletions(-) diff --git a/shared/src/business/useCases/public/resendVerificationLinkInteractor.ts b/shared/src/business/useCases/public/resendVerificationLinkInteractor.ts index 6004a07b333..03e2785e3c3 100644 --- a/shared/src/business/useCases/public/resendVerificationLinkInteractor.ts +++ b/shared/src/business/useCases/public/resendVerificationLinkInteractor.ts @@ -1,13 +1,13 @@ +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; + export const resendVerificationLinkInteractor = async ( applicationContext: IApplicationContext, { email }: { email: string }, ) => { - const params = { + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + + return await cognito.resendConfirmationCode({ ClientId: process.env.COGNITO_CLIENT_ID, Username: email, - }; - return await applicationContext - .getCognito() - .resendConfirmationCode(params) - .promise(); + }); }; diff --git a/web-api/src/persistence/cognito/getCognitoUserIdByEmail.ts b/web-api/src/persistence/cognito/getCognitoUserIdByEmail.ts index ca914d1e4fa..8d1e5ce54fb 100644 --- a/web-api/src/persistence/cognito/getCognitoUserIdByEmail.ts +++ b/web-api/src/persistence/cognito/getCognitoUserIdByEmail.ts @@ -1,18 +1,18 @@ +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; + export const getCognitoUserIdByEmail = async ({ applicationContext, email, }) => { try { - const userFromCognito = await applicationContext - .getCognito() - .adminGetUser({ - UserPoolId: process.env.USER_POOL_ID, - Username: email, - }) - .promise(); + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + const userFromCognito = await cognito.adminGetUser({ + UserPoolId: process.env.USER_POOL_ID, + Username: email, + }); const customUserId = ( - userFromCognito.UserAttributes.find( + userFromCognito.UserAttributes?.find( attribute => attribute.Name === 'custom:userId', ) || {} ).Value; diff --git a/web-api/src/persistence/dynamo/users/createNewPetitionerUser.ts b/web-api/src/persistence/dynamo/users/createNewPetitionerUser.ts index b200f4d0e94..07a0e8e3ab6 100644 --- a/web-api/src/persistence/dynamo/users/createNewPetitionerUser.ts +++ b/web-api/src/persistence/dynamo/users/createNewPetitionerUser.ts @@ -1,5 +1,8 @@ import * as client from '../../dynamodbClientService'; -import { type AdminCreateUserRequest } from 'aws-sdk/clients/cognitoidentityserviceprovider'; +import { + AdminCreateUserCommandInput, + CognitoIdentityProvider, +} from '@aws-sdk/client-cognito-identity-provider'; import { ROLES } from '../../../../../shared/src/business/entities/EntityConstants'; import { RawUser } from '@shared/business/entities/User'; @@ -37,7 +40,7 @@ export const createNewPetitionerUser = async ({ }) => { const { userId } = user; - const input: AdminCreateUserRequest = { + const input: AdminCreateUserCommandInput = { UserAttributes: [ { Name: 'email_verified', @@ -68,7 +71,9 @@ export const createNewPetitionerUser = async ({ input.TemporaryPassword = process.env.DEFAULT_ACCOUNT_PASS; } - await applicationContext.getCognito().adminCreateUser(input).promise(); + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + + await cognito.adminCreateUser(input); const newUser: RawUser = await createUserRecords({ applicationContext, diff --git a/web-api/src/persistence/dynamo/users/createNewPractitionerUser.ts b/web-api/src/persistence/dynamo/users/createNewPractitionerUser.ts index 346c90531b9..57c22e9c794 100644 --- a/web-api/src/persistence/dynamo/users/createNewPractitionerUser.ts +++ b/web-api/src/persistence/dynamo/users/createNewPractitionerUser.ts @@ -1,3 +1,4 @@ +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { RawPractitioner } from '@shared/business/entities/Practitioner'; import { put } from '../../dynamodbClientService'; @@ -51,35 +52,34 @@ export const createNewPractitionerUser = async ({ }) => { const { userId } = user; - await applicationContext - .getCognito() - .adminCreateUser({ - UserAttributes: [ - { - Name: 'email_verified', - Value: 'True', - }, - { - Name: 'email', - Value: user.pendingEmail, - }, - { - Name: 'custom:role', - Value: user.role, - }, - { - Name: 'name', - Value: user.name, - }, - { - Name: 'custom:userId', - Value: user.userId, - }, - ], - UserPoolId: process.env.USER_POOL_ID, - Username: user.pendingEmail, - }) - .promise(); + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + + await cognito.adminCreateUser({ + UserAttributes: [ + { + Name: 'email_verified', + Value: 'True', + }, + { + Name: 'email', + Value: user.pendingEmail, + }, + { + Name: 'custom:role', + Value: user.role, + }, + { + Name: 'name', + Value: user.name, + }, + { + Name: 'custom:userId', + Value: user.userId, + }, + ], + UserPoolId: process.env.USER_POOL_ID, + Username: user.pendingEmail, + }); const updatedUser = await updateUserRecords({ applicationContext, diff --git a/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.ts b/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.ts index 3e55332207a..436ad23ae87 100644 --- a/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.ts +++ b/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.ts @@ -1,4 +1,5 @@ import * as client from '../../dynamodbClientService'; +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { ROLES } from '../../../../../shared/src/business/entities/EntityConstants'; import { RawUser } from '@shared/business/entities/User'; import { isUserAlreadyCreated } from './createOrUpdateUser'; @@ -89,6 +90,8 @@ export const createOrUpdatePractitionerUser = async ({ userPoolId: process.env.USER_POOL_ID as string, }); + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + if (!userExists) { let params = { UserAttributes: [ @@ -113,38 +116,29 @@ export const createOrUpdatePractitionerUser = async ({ Username: userEmail, }; - const response = await applicationContext - .getCognito() - .adminCreateUser(params) - .promise(); + const response = await cognito.adminCreateUser(params); if (response && response.User && response.User.Username) { userId = response.User.Username; } } else { - const response = await applicationContext - .getCognito() - .adminGetUser({ - UserPoolId: process.env.USER_POOL_ID, - Username: userEmail, - }) - .promise(); - - await applicationContext - .getCognito() - .adminUpdateUserAttributes({ - UserAttributes: [ - { - Name: 'custom:role', - Value: user.role, - }, - ], - UserPoolId: process.env.USER_POOL_ID, - Username: response.Username, - }) - .promise(); - - userId = response.Username; + const response = await cognito.adminGetUser({ + UserPoolId: process.env.USER_POOL_ID, + Username: userEmail, + }); + + await cognito.adminUpdateUserAttributes({ + UserAttributes: [ + { + Name: 'custom:role', + Value: user.role, + }, + ], + UserPoolId: process.env.USER_POOL_ID, + Username: response.Username, + }); + + userId = response.Username!; } return await createUserRecords({ diff --git a/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts b/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts index 528c3732568..90acc7991a0 100644 --- a/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts +++ b/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts @@ -1,4 +1,8 @@ import * as client from '../../dynamodbClientService'; +import { + CognitoIdentityProvider, + UserNotFoundException, +} from '@aws-sdk/client-cognito-identity-provider'; import { DOCKET_SECTION, PETITIONS_SECTION, @@ -117,17 +121,16 @@ export const isUserAlreadyCreated = async ({ email: string; userPoolId: string; }) => { + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + try { - await applicationContext - .getCognito() - .adminGetUser({ - UserPoolId: userPoolId, - Username: email, - }) - .promise(); + await cognito.adminGetUser({ + UserPoolId: userPoolId, + Username: email, + }); return true; } catch (e) { - if (e.code.includes('UserNotFoundException')) { + if (e instanceof UserNotFoundException) { return false; } else { throw e; @@ -158,8 +161,10 @@ export const createOrUpdateUser = async ({ userPoolId: userPoolId as string, }); + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + if (!userExists) { - const params = { + const response = await cognito.adminCreateUser({ MessageAction: 'SUPPRESS', TemporaryPassword: password, UserAttributes: [ @@ -182,48 +187,33 @@ export const createOrUpdateUser = async ({ ], UserPoolId: userPoolId, Username: user.email, - }; - - const response = await applicationContext - .getCognito() - .adminCreateUser(params) - .promise(); + }); - userId = response.User.Username; + userId = response.User!.Username; } else { - const response = await applicationContext - .getCognito() - .adminGetUser({ - UserPoolId: userPoolId, - Username: user.email, - }) - .promise(); - - await applicationContext - .getCognito() - .adminUpdateUserAttributes({ - UserAttributes: [ - { - Name: 'custom:role', - Value: user.role, - }, - ], - UserPoolId: userPoolId, - Username: response.Username, - }) - .promise(); + const response = await cognito.adminGetUser({ + UserPoolId: userPoolId, + Username: user.email, + }); + await cognito.adminUpdateUserAttributes({ + UserAttributes: [ + { + Name: 'custom:role', + Value: user.role, + }, + ], + UserPoolId: userPoolId, + Username: response.Username, + }); userId = response.Username; } if (disableCognitoUser) { - await applicationContext - .getCognito() - .adminDisableUser({ - UserPoolId: userPoolId, - Username: userId, - }) - .promise(); + await cognito.adminDisableUser({ + UserPoolId: userPoolId, + Username: userId, + }); } return await createUserRecords({ diff --git a/web-api/src/persistence/dynamo/users/updatePractitionerUser.ts b/web-api/src/persistence/dynamo/users/updatePractitionerUser.ts index 47b924d65b8..4ff0f2198d0 100644 --- a/web-api/src/persistence/dynamo/users/updatePractitionerUser.ts +++ b/web-api/src/persistence/dynamo/users/updatePractitionerUser.ts @@ -1,3 +1,4 @@ +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { RawUser } from '@shared/business/entities/User'; import { getUserById } from './getUserById'; import { updateUserRecords } from './updateUserRecords'; @@ -17,19 +18,17 @@ export const updatePractitionerUser = async ({ }); try { - await applicationContext - .getCognito() - .adminUpdateUserAttributes({ - UserAttributes: [ - { - Name: 'custom:role', - Value: user.role, - }, - ], - UserPoolId: process.env.USER_POOL_ID, - Username: user.email ? user.email : user.pendingEmail, - }) - .promise(); + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + await cognito.adminUpdateUserAttributes({ + UserAttributes: [ + { + Name: 'custom:role', + Value: user.role, + }, + ], + UserPoolId: process.env.USER_POOL_ID, + Username: user.email ? user.email : user.pendingEmail, + }); } catch (error) { applicationContext.logger.error(error); throw error; diff --git a/web-api/src/persistence/dynamo/users/updateUserEmail.ts b/web-api/src/persistence/dynamo/users/updateUserEmail.ts index b3ff27f3beb..0908f309f6f 100644 --- a/web-api/src/persistence/dynamo/users/updateUserEmail.ts +++ b/web-api/src/persistence/dynamo/users/updateUserEmail.ts @@ -1,3 +1,4 @@ +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { RawUser } from '@shared/business/entities/User'; export const updateUserEmail = async ({ @@ -8,23 +9,22 @@ export const updateUserEmail = async ({ user: RawUser; }) => { try { - await applicationContext - .getCognito() - .adminUpdateUserAttributes({ - UserAttributes: [ - { - Name: 'email', - Value: user.pendingEmail, - }, - { - Name: 'email_verified', - Value: 'true', - }, - ], - UserPoolId: process.env.USER_POOL_ID, - Username: user.email, - }) - .promise(); + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + + await cognito.adminUpdateUserAttributes({ + UserAttributes: [ + { + Name: 'email', + Value: user.pendingEmail, + }, + { + Name: 'email_verified', + Value: 'true', + }, + ], + UserPoolId: process.env.USER_POOL_ID, + Username: user.email, + }); } catch (err) { applicationContext.logger.error( `Error updating user with original email ${user.email}`, From 5493c0f0b5da071c4019aff87249a335597f9e97 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Tue, 2 Jan 2024 14:35:00 -0800 Subject: [PATCH 087/700] 10007: Remove change password local code --- .../changePasswordLocalInteractor.test.ts | 35 -------- .../auth/changePasswordLocalInteractor.ts | 34 -------- .../proxies/auth/changePasswordLocalProxy.ts | 25 ------ web-api/src/app.ts | 3 - web-api/src/auth/changePasswordLocalLambda.ts | 19 ----- web-api/src/getUseCases.ts | 2 - web-client/src/applicationContext.ts | 2 - .../actions/changePasswordLocalAction.test.ts | 82 ------------------- .../actions/changePasswordLocalAction.ts | 37 --------- web-client/src/presenter/presenter.ts | 6 -- .../sequences/changePasswordLocalSequence.ts | 17 ---- .../gotoChangePasswordLocalSequence.ts | 7 -- web-client/src/router.ts | 5 -- web-client/src/views/AppComponent.tsx | 2 - web-client/src/views/ChangePasswordLocal.tsx | 76 ----------------- 15 files changed, 352 deletions(-) delete mode 100644 shared/src/business/useCases/auth/changePasswordLocalInteractor.test.ts delete mode 100644 shared/src/business/useCases/auth/changePasswordLocalInteractor.ts delete mode 100644 shared/src/proxies/auth/changePasswordLocalProxy.ts delete mode 100644 web-api/src/auth/changePasswordLocalLambda.ts delete mode 100644 web-client/src/presenter/actions/changePasswordLocalAction.test.ts delete mode 100644 web-client/src/presenter/actions/changePasswordLocalAction.ts delete mode 100644 web-client/src/presenter/sequences/changePasswordLocalSequence.ts delete mode 100644 web-client/src/presenter/sequences/gotoChangePasswordLocalSequence.ts delete mode 100644 web-client/src/views/ChangePasswordLocal.tsx diff --git a/shared/src/business/useCases/auth/changePasswordLocalInteractor.test.ts b/shared/src/business/useCases/auth/changePasswordLocalInteractor.test.ts deleted file mode 100644 index 4bc2cd5c364..00000000000 --- a/shared/src/business/useCases/auth/changePasswordLocalInteractor.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { applicationContext } from '../../test/createTestApplicationContext'; -import { changePasswordLocalInteractor } from './changePasswordLocalInteractor'; - -describe('changePasswordLocalInteractor', () => { - const authenticationResult = { - AccessToken: 'abc', - IdToken: '123', - }; - - beforeEach(() => { - applicationContext.getCognito().respondToAuthChallenge.mockReturnValue({ - promise: () => { - return { AuthenticationResult: authenticationResult }; - }, - }); - }); - - it('attempts to respond to cognito authentication challenge', async () => { - const result = await changePasswordLocalInteractor(applicationContext, { - newPassword: 'newPassword', - sessionId: '1', - userEmail: 'userEmail@example.com', - }); - - expect( - applicationContext.getCognito().respondToAuthChallenge.mock.calls[0][0] - .ChallengeResponses, - ).toMatchObject({ - NEW_PASSWORD: 'newPassword', - USERNAME: 'userEmail@example.com', - }); - - expect(result.AuthenticationResult).toEqual(authenticationResult); - }); -}); diff --git a/shared/src/business/useCases/auth/changePasswordLocalInteractor.ts b/shared/src/business/useCases/auth/changePasswordLocalInteractor.ts deleted file mode 100644 index c2220f608ab..00000000000 --- a/shared/src/business/useCases/auth/changePasswordLocalInteractor.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * changePasswordLocalInteractor - * @param {object} applicationContext the application context - * @param {object} auth an object - * @param {string} auth.newPassword the new password provided by a local user - * @param {string} auth.sessionId the cognito (local) session id - * @param {string} auth.userEmail the email of the user changing passwords - * @returns {Promise} the promise of a Cognito AuthenticationResult - */ -export const changePasswordLocalInteractor = async ( - applicationContext: IApplicationContext, - { - newPassword, - sessionId, - userEmail, - }: { newPassword: string; sessionId: string; userEmail: string }, -) => { - const params = { - ChallengeName: 'NEW_PASSWORD_REQUIRED', - ChallengeResponses: { - NEW_PASSWORD: newPassword, - USERNAME: userEmail, - }, - ClientId: process.env.COGNITO_CLIENT_ID, - Session: sessionId, - }; - - const result = await applicationContext - .getCognito() - .respondToAuthChallenge(params) - .promise(); - - return result; -}; diff --git a/shared/src/proxies/auth/changePasswordLocalProxy.ts b/shared/src/proxies/auth/changePasswordLocalProxy.ts deleted file mode 100644 index 4f09fbdc513..00000000000 --- a/shared/src/proxies/auth/changePasswordLocalProxy.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { post } from '../requests'; - -/** - * changePasswordLocalInteractor - * - * @param {object} applicationContext the application context - * @param {object} auth the auth object - * @param {string} auth.newPassword the new password provided by a local user - * @param {string} auth.sessionId the cognito (local) session id - * @param {string} auth.userEmail the email of the user changing passwords - * @returns {Promise<*>} the promise of the api call - */ -export const changePasswordLocalInteractor = ( - applicationContext, - { newPassword, sessionId, userEmail }, -) => { - return post({ - applicationContext, - body: { newPassword, sessionId, userEmail }, - endpoint: '/change-password-local', - options: { - withCredentials: false, - }, - }); -}; diff --git a/web-api/src/app.ts b/web-api/src/app.ts index f77f26c3ff7..4b1b222e8ea 100644 --- a/web-api/src/app.ts +++ b/web-api/src/app.ts @@ -15,7 +15,6 @@ import { associatePrivatePractitionerWithCaseLambda } from './lambdas/manualAsso import { batchDownloadTrialSessionLambda } from './lambdas/trialSessions/batchDownloadTrialSessionLambda'; import { blockCaseFromTrialLambda } from './lambdas/cases/blockCaseFromTrialLambda'; import { caseAdvancedSearchLambda } from './lambdas/cases/caseAdvancedSearchLambda'; -import { changePasswordLocalLambda } from './auth/changePasswordLocalLambda'; import { checkEmailAvailabilityLambda } from './lambdas/users/checkEmailAvailabilityLambda'; import { checkForReadyForTrialCasesLambda } from './lambdas/cases/checkForReadyForTrialCasesLambda'; import { closeTrialSessionLambda } from './lambdas/trialSessions/closeTrialSessionLambda'; @@ -1040,7 +1039,5 @@ if (process.env.IS_LOCAL) { lambdaWrapper(checkForReadyForTrialCasesLambda), ); - app.post('/change-password-local', lambdaWrapper(changePasswordLocalLambda)); - app.post('/confirm-signup-local', lambdaWrapper(confirmSignUpLocalLambda)); } diff --git a/web-api/src/auth/changePasswordLocalLambda.ts b/web-api/src/auth/changePasswordLocalLambda.ts deleted file mode 100644 index fa641c8bd78..00000000000 --- a/web-api/src/auth/changePasswordLocalLambda.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { genericHandler } from '../genericHandler'; - -/** - * - * @param {object} event the AWS event object - * @returns {Promise<*|undefined>} the api gateway response object containing the statusCode, body, and headers - */ -export const changePasswordLocalLambda = event => - genericHandler( - event, - async ({ applicationContext }) => { - return await applicationContext - .getUseCases() - .changePasswordLocalInteractor(applicationContext, { - ...JSON.parse(event.body), - }); - }, - { logResults: true }, - ); diff --git a/web-api/src/getUseCases.ts b/web-api/src/getUseCases.ts index 17de77de024..c74cf79c320 100644 --- a/web-api/src/getUseCases.ts +++ b/web-api/src/getUseCases.ts @@ -16,7 +16,6 @@ import { batchDownloadTrialSessionInteractor } from '../../shared/src/business/u import { blockCaseFromTrialInteractor } from '../../shared/src/business/useCases/blockCaseFromTrialInteractor'; import { caseAdvancedSearchInteractor } from '../../shared/src/business/useCases/caseAdvancedSearchInteractor'; import { casePublicSearchInteractor } from '../../shared/src/business/useCases/public/casePublicSearchInteractor'; -import { changePasswordLocalInteractor } from '../../shared/src/business/useCases/auth/changePasswordLocalInteractor'; import { checkEmailAvailabilityInteractor } from '../../shared/src/business/useCases/users/checkEmailAvailabilityInteractor'; import { checkForReadyForTrialCasesInteractor } from '../../shared/src/business/useCases/checkForReadyForTrialCasesInteractor'; import { closeTrialSessionInteractor } from '../../shared/src/business/useCases/trialSessions/closeTrialSessionInteractor'; @@ -230,7 +229,6 @@ const useCases = { blockCaseFromTrialInteractor, caseAdvancedSearchInteractor, casePublicSearchInteractor, - changePasswordLocalInteractor, checkEmailAvailabilityInteractor, checkForReadyForTrialCasesInteractor, closeTrialSessionInteractor, diff --git a/web-client/src/applicationContext.ts b/web-client/src/applicationContext.ts index e68e64a8437..6a0178c5bea 100644 --- a/web-client/src/applicationContext.ts +++ b/web-client/src/applicationContext.ts @@ -72,7 +72,6 @@ import { canConsolidateInteractor } from '../../shared/src/business/useCases/cas import { canSetTrialSessionAsCalendaredInteractor } from '../../shared/src/business/useCases/trialSessions/canSetTrialSessionAsCalendaredInteractor'; import { caseAdvancedSearchInteractor } from '../../shared/src/proxies/caseAdvancedSearchProxy'; import { caseStatusWithTrialInformation } from '@shared/business/utilities/caseStatusWithTrialInformation'; -import { changePasswordLocalInteractor } from '../../shared/src/proxies/auth/changePasswordLocalProxy'; import { checkEmailAvailabilityInteractor } from '../../shared/src/proxies/users/checkEmailAvailabilityProxy'; import { closeTrialSessionInteractor } from '../../shared/src/proxies/trialSessions/closeTrialSessionProxy'; import { @@ -403,7 +402,6 @@ const allUseCases = { canConsolidateInteractor, canSetTrialSessionAsCalendaredInteractor, caseAdvancedSearchInteractor, - changePasswordLocalInteractor, checkEmailAvailabilityInteractor, closeTrialSessionInteractor, completeDocketEntryQCInteractor, diff --git a/web-client/src/presenter/actions/changePasswordLocalAction.test.ts b/web-client/src/presenter/actions/changePasswordLocalAction.test.ts deleted file mode 100644 index 91577d2691f..00000000000 --- a/web-client/src/presenter/actions/changePasswordLocalAction.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; -import { changePasswordLocalAction } from './changePasswordLocalAction'; -import { presenter } from '../presenter-mock'; -import { runAction } from '@web-client/presenter/test.cerebral'; - -describe('changePasswordLocalAction', () => { - const userEmail = 'someone@example.com'; - const newPassword = 'Pa$$word!'; - const sessionId = 'fdb445rg4efvbd4'; - - const noStub = jest.fn(); - const yesStub = jest.fn(); - - beforeAll(() => { - presenter.providers.applicationContext = applicationContext; - - applicationContext - .getUseCases() - .changePasswordLocalInteractor.mockReturnValue({}); - - presenter.providers.path = { - no: noStub, - yes: yesStub, - }; - }); - - it('should call changePasswordLocalInteractor with the sessionId, the userEmail, and the new password', async () => { - await runAction(changePasswordLocalAction, { - modules: { - presenter, - }, - state: { - form: { newPassword }, - login: { sessionId, userEmail }, - }, - }); - - expect( - applicationContext.getUseCases().changePasswordLocalInteractor.mock - .calls[0][1], - ).toMatchObject({ newPassword, sessionId, userEmail }); - }); - - it('should call path.yes with an alert success when changePasswordLocalInteractor returns an AuthenticationResult', async () => { - applicationContext - .getUseCases() - .changePasswordLocalInteractor.mockReturnValueOnce({ - AuthenticationResult: { IdToken: 'abc', RefreshToken: '123' }, - }); - - await runAction(changePasswordLocalAction, { - modules: { - presenter, - }, - state: { - form: { newPassword }, - login: { sessionId, userEmail }, - }, - }); - - expect(yesStub).toHaveBeenCalled(); - expect(yesStub.mock.calls[0][0]).toMatchObject({ - alertSuccess: { - message: 'Password successfully changed.', - }, - }); - }); - - it('should call path.no with an error when changePasswordLocalInteractor returns no AuthenticationResult', async () => { - await runAction(changePasswordLocalAction, { - modules: { - presenter, - }, - state: { - form: { newPassword }, - login: { sessionId, userEmail }, - }, - }); - - expect(noStub).toHaveBeenCalled(); - }); -}); diff --git a/web-client/src/presenter/actions/changePasswordLocalAction.ts b/web-client/src/presenter/actions/changePasswordLocalAction.ts deleted file mode 100644 index f1a38b9d6a4..00000000000 --- a/web-client/src/presenter/actions/changePasswordLocalAction.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { state } from '@web-client/presenter/app.cerebral'; - -/** - * Updates the user's password in cognito, locally - * - * @param {object} providers the providers object - * @param {object} providers.applicationContext the applicationContext - * @param {object} providers.path the cerebral path function - * @param {object} providers.get the cerebral get function - * @returns {Promise} async action - */ -export const changePasswordLocalAction = async ({ - applicationContext, - get, - path, -}) => { - const { sessionId, userEmail } = get(state.login); - const newPassword = get(state.form.newPassword); - - const response = await applicationContext - .getUseCases() - .changePasswordLocalInteractor(applicationContext, { - newPassword, - sessionId, - userEmail, - }); - - if (response.AuthenticationResult) { - return path.yes({ - alertSuccess: { - message: 'Password successfully changed.', - }, - }); - } else { - return path.no(); - } -}; diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index b045ed799cf..11cbe7bf036 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -39,7 +39,6 @@ import { cancelRemovePetitionerSequence } from './sequences/cancelRemovePetition import { caseDetailPrimaryTabChangeSequence } from './sequences/caseDetailPrimaryTabChangeSequence'; import { caseInventoryReportLoadMoreSequence } from './sequences/caseInventoryReportLoadMoreSequence'; import { cerebralBindSimpleSetStateSequence } from './sequences/cerebralBindSimpleSetStateSequence'; -import { changePasswordLocalSequence } from './sequences/changePasswordLocalSequence'; import { changeTabAndSetViewerDocumentToDisplaySequence } from './sequences/changeTabAndSetViewerDocumentToDisplaySequence'; import { checkForNegativeValueSequence } from './sequences/checkForNegativeValueSequence'; import { chooseModalWizardStepSequence } from './sequences/chooseModalWizardStepSequence'; @@ -140,7 +139,6 @@ import { gotoCaseDetailSequence } from './sequences/gotoCaseDetailSequence'; import { gotoCaseInventoryReportSequence } from './sequences/gotoCaseInventoryReportSequence'; import { gotoCaseSearchNoMatchesSequence } from './sequences/gotoCaseSearchNoMatchesSequence'; import { gotoChangeLoginAndServiceEmailSequence } from './sequences/gotoChangeLoginAndServiceEmailSequence'; -import { gotoChangePasswordLocalSequence } from './sequences/gotoChangePasswordLocalSequence'; import { gotoCompleteDocketEntryQCSequence } from './sequences/gotoCompleteDocketEntryQCSequence'; import { gotoContactEditSequence } from './sequences/gotoContactEditSequence'; import { gotoContactSequence } from './sequences/gotoContactSequence'; @@ -611,8 +609,6 @@ export const presenterSequences = { caseInventoryReportLoadMoreSequence as unknown as Function, cerebralBindSimpleSetStateSequence: cerebralBindSimpleSetStateSequence as unknown as Function, - changePasswordLocalSequence: - changePasswordLocalSequence as unknown as Function, changeTabAndSetViewerDocumentToDisplaySequence: changeTabAndSetViewerDocumentToDisplaySequence as unknown as Function, checkForNegativeValueSequence: @@ -779,8 +775,6 @@ export const presenterSequences = { gotoCaseSearchNoMatchesSequence as unknown as Function, gotoChangeLoginAndServiceEmailSequence: gotoChangeLoginAndServiceEmailSequence as unknown as Function, - gotoChangePasswordLocalSequence: - gotoChangePasswordLocalSequence as unknown as Function, gotoCompleteDocketEntryQCSequence: gotoCompleteDocketEntryQCSequence as unknown as Function, gotoContactEditSequence: gotoContactEditSequence as unknown as Function, diff --git a/web-client/src/presenter/sequences/changePasswordLocalSequence.ts b/web-client/src/presenter/sequences/changePasswordLocalSequence.ts deleted file mode 100644 index b6b79d2832b..00000000000 --- a/web-client/src/presenter/sequences/changePasswordLocalSequence.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { changePasswordLocalAction } from '../actions/changePasswordLocalAction'; -import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; -import { setAlertSuccessAction } from '../actions/setAlertSuccessAction'; -import { setSaveAlertsForNavigationAction } from '../actions/setSaveAlertsForNavigationAction'; -import { showProgressSequenceDecorator } from '../utilities/showProgressSequenceDecorator'; - -export const changePasswordLocalSequence = showProgressSequenceDecorator([ - changePasswordLocalAction, - { - no: [], - yes: [ - setAlertSuccessAction, - setSaveAlertsForNavigationAction, - navigateToLoginSequence, - ], - }, -]); diff --git a/web-client/src/presenter/sequences/gotoChangePasswordLocalSequence.ts b/web-client/src/presenter/sequences/gotoChangePasswordLocalSequence.ts deleted file mode 100644 index 30ee8ac982a..00000000000 --- a/web-client/src/presenter/sequences/gotoChangePasswordLocalSequence.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { clearFormAction } from '../actions/clearFormAction'; -import { setupCurrentPageAction } from '../actions/setupCurrentPageAction'; - -export const gotoChangePasswordLocalSequence = [ - clearFormAction, - setupCurrentPageAction('ChangePasswordLocal'), -]; diff --git a/web-client/src/router.ts b/web-client/src/router.ts index eab35401a2f..932e978c262 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -835,11 +835,6 @@ const router = { }), ); - // TODO 10007: this can probably be unified with the other change password stuff - registerRoute('/change-password-local', () => { - return app.getSequence('gotoChangePasswordLocalSequence')(); - }); - registerRoute('/confirm-signup-local?..', () => { const { confirmationCode, email } = route.query(); return app.getSequence('confirmSignUpLocalSequence')({ diff --git a/web-client/src/views/AppComponent.tsx b/web-client/src/views/AppComponent.tsx index fc5ba110321..3635bca0732 100644 --- a/web-client/src/views/AppComponent.tsx +++ b/web-client/src/views/AppComponent.tsx @@ -19,7 +19,6 @@ import { CaseInventoryReport } from './CaseInventoryReport/CaseInventoryReport'; import { CaseInventoryReportModal } from './CaseInventoryReport/CaseInventoryReportModal'; import { CaseSearchNoMatches } from './CaseSearchNoMatches'; import { ChangeLoginAndServiceEmail } from './ChangeLoginAndServiceEmail'; -import { ChangePasswordLocal } from './ChangePasswordLocal'; import { Contact } from './Contact'; import { ContactEdit } from './ContactEdit'; import { CourtIssuedDocketEntry } from './CourtIssuedDocketEntry/CourtIssuedDocketEntry'; @@ -118,7 +117,6 @@ const pages = { CaseInventoryReport, CaseSearchNoMatches, ChangeLoginAndServiceEmail, - ChangePasswordLocal, Contact, ContactEdit, CourtIssuedDocketEntry, diff --git a/web-client/src/views/ChangePasswordLocal.tsx b/web-client/src/views/ChangePasswordLocal.tsx deleted file mode 100644 index 412911f7867..00000000000 --- a/web-client/src/views/ChangePasswordLocal.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { connect } from '@web-client/presenter/shared.cerebral'; -import { getView } from './viewFactory'; -import { sequences, state } from '@web-client/presenter/app.cerebral'; -import React from 'react'; - -const ErrorNotification = getView('ErrorNotification'); -const Button = getView('Button'); - -export const ChangePasswordLocal = connect( - { - changePasswordLocalSequence: sequences.changePasswordLocalSequence, - form: state.form, - updateFormValueSequence: sequences.updateFormValueSequence, - userEmail: state.login.userEmail, - }, - function CreateNewAccountLocal({ - changePasswordLocalSequence, - form, - updateFormValueSequence, - userEmail, - }) { - return ( -
-

New Password Required

- -
{ - event.preventDefault(); - changePasswordLocalSequence(); - }} - > -
-
- - - - { - updateFormValueSequence({ - key: e.target.name, - value: e.target.value, - }); - }} - /> -
-
- -
-
- ); - }, -); - -ChangePasswordLocal.displayName = 'ChangePasswordLocal'; From a4238b2ae7241bb1de28c5fdc3a383519a2299ab Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Wed, 3 Jan 2024 09:22:02 -0800 Subject: [PATCH 088/700] 10007: WIP confirm signup is no longer cognito hosted. --- .../test/createTestApplicationContext.ts | 2 + .../auth/confirmSignUpLocalInteractor.test.ts | 48 ----- .../auth/confirmSignUpLocalInteractor.ts | 17 -- .../auth/renewIdTokenInteractor.test.ts | 31 ---- .../proxies/auth/confirmSignUpLocalProxy.ts | 23 --- shared/src/proxies/auth/confirmSignUpProxy.ts | 19 ++ web-api/src/app-public.ts | 165 ++++++++++-------- web-api/src/app.ts | 6 +- web-api/src/auth/confirmSignUpLocalLambda.ts | 19 -- .../auth/confirmSignUpInteractor.test.ts | 40 +++++ .../useCases/auth/confirmSignUpInteractor.ts | 15 ++ .../auth/renewIdTokenInteractor.test.ts | 40 +++++ .../useCases/auth/renewIdTokenInteractor.ts | 3 +- web-api/src/getUseCases.ts | 6 +- .../src/lambdas/auth/confirmSignUpLambda.ts | 15 ++ .../petitionerCreatesAccount.test.ts | 4 +- web-client/src/applicationContext.ts | 4 +- web-client/src/applicationContextPublic.ts | 5 +- ...on.test.ts => confirmSignUpAction.test.ts} | 9 +- ...pLocalAction.ts => confirmSignUpAction.ts} | 17 +- ...est.ts => createConfirmLinkAction.test.ts} | 10 +- ...alAction.ts => createConfirmLinkAction.ts} | 5 +- web-client/src/presenter/presenter-public.ts | 4 +- web-client/src/presenter/presenter.ts | 4 +- ...alSequence.ts => confirmSignUpSequence.ts} | 6 +- ...bmitCreatePetitionerAccountFormSequence.ts | 4 +- web-client/src/router.ts | 4 +- web-client/src/routerPublic.ts | 4 +- 28 files changed, 271 insertions(+), 258 deletions(-) delete mode 100644 shared/src/business/useCases/auth/confirmSignUpLocalInteractor.test.ts delete mode 100644 shared/src/business/useCases/auth/confirmSignUpLocalInteractor.ts delete mode 100644 shared/src/business/useCases/auth/renewIdTokenInteractor.test.ts delete mode 100644 shared/src/proxies/auth/confirmSignUpLocalProxy.ts create mode 100644 shared/src/proxies/auth/confirmSignUpProxy.ts delete mode 100644 web-api/src/auth/confirmSignUpLocalLambda.ts create mode 100644 web-api/src/business/useCases/auth/confirmSignUpInteractor.test.ts create mode 100644 web-api/src/business/useCases/auth/confirmSignUpInteractor.ts create mode 100644 web-api/src/business/useCases/auth/renewIdTokenInteractor.test.ts rename {shared => web-api}/src/business/useCases/auth/renewIdTokenInteractor.ts (83%) create mode 100644 web-api/src/lambdas/auth/confirmSignUpLambda.ts rename web-client/src/presenter/actions/{confirmSignUpLocalAction.test.ts => confirmSignUpAction.test.ts} (90%) rename web-client/src/presenter/actions/{confirmSignUpLocalAction.ts => confirmSignUpAction.ts} (54%) rename web-client/src/presenter/actions/{createConfirmLinkLocalAction.test.ts => createConfirmLinkAction.test.ts} (78%) rename web-client/src/presenter/actions/{createConfirmLinkLocalAction.ts => createConfirmLinkAction.ts} (77%) rename web-client/src/presenter/sequences/{confirmSignUpLocalSequence.ts => confirmSignUpSequence.ts} (74%) diff --git a/shared/src/business/test/createTestApplicationContext.ts b/shared/src/business/test/createTestApplicationContext.ts index 3865e8f84e2..96207b8617e 100644 --- a/shared/src/business/test/createTestApplicationContext.ts +++ b/shared/src/business/test/createTestApplicationContext.ts @@ -691,3 +691,5 @@ export const createTestApplicationContext = ({ }; return applicationContext; }; + +export const applicationContext = createTestApplicationContext(); diff --git a/shared/src/business/useCases/auth/confirmSignUpLocalInteractor.test.ts b/shared/src/business/useCases/auth/confirmSignUpLocalInteractor.test.ts deleted file mode 100644 index 8a5f2be2afd..00000000000 --- a/shared/src/business/useCases/auth/confirmSignUpLocalInteractor.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { applicationContext } from '../../test/createTestApplicationContext'; -import { confirmSignUpLocalInteractor } from './confirmSignUpLocalInteractor'; - -describe('confirmSignUpLocalInteractor', () => { - const confirmationCode = '123456'; - const userEmail = 'example@example.com'; - - // cognito returns an empty 200 on success - const confirmSignUpResult = {}; - beforeAll(() => { - applicationContext.getCognito().confirmSignUp.mockReturnValue({ - promise: () => confirmSignUpResult, - }); - }); - - it('should call cognito confirmSignUp with correctly formatted parameters and return the result', async () => { - const result = await confirmSignUpLocalInteractor(applicationContext, { - confirmationCode, - userEmail, - }); - - expect( - applicationContext.getCognito().confirmSignUp.mock.calls[0][0], - ).toMatchObject({ - ConfirmationCode: confirmationCode, - Username: userEmail, - }); - - expect(result).toEqual({}); - }); - - it('should return an error if confirmSignUp fails', async () => { - applicationContext.getCognito().confirmSignUp.mockReturnValueOnce({ - promise: () => { - throw new Error(); - }, - }); - - await expect( - confirmSignUpLocalInteractor(applicationContext, { - confirmationCode, - userEmail, - }), - ).rejects.toThrow(); - - expect(applicationContext.getCognito().confirmSignUp).toHaveBeenCalled(); - }); -}); diff --git a/shared/src/business/useCases/auth/confirmSignUpLocalInteractor.ts b/shared/src/business/useCases/auth/confirmSignUpLocalInteractor.ts deleted file mode 100644 index c081bf88161..00000000000 --- a/shared/src/business/useCases/auth/confirmSignUpLocalInteractor.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; - -export const confirmSignUpLocalInteractor = async ( - applicationContext: IApplicationContext, - { - confirmationCode, - userEmail, - }: { confirmationCode: string; userEmail: string }, -) => { - const cognito: CognitoIdentityProvider = applicationContext.getCognito(); - - return await cognito.confirmSignUp({ - ClientId: process.env.COGNITO_CLIENT_ID, - ConfirmationCode: confirmationCode, - Username: userEmail, - }); -}; diff --git a/shared/src/business/useCases/auth/renewIdTokenInteractor.test.ts b/shared/src/business/useCases/auth/renewIdTokenInteractor.test.ts deleted file mode 100644 index 3532e31c54d..00000000000 --- a/shared/src/business/useCases/auth/renewIdTokenInteractor.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { applicationContext } from '../../test/createTestApplicationContext'; -import { renewIdTokenInteractor } from './renewIdTokenInteractor'; - -describe('renewIdTokenInteractor', () => { - beforeEach(() => { - applicationContext.getPersistenceGateway().refreshToken.mockReturnValue({ - token: 'abc', - }); - }); - - it('attempts to hit cognito and get an id token and refresh token', async () => { - const expectedRefresh = 'sometoken'; - const result = await renewIdTokenInteractor(applicationContext, { - refreshToken: expectedRefresh, - }); - expect( - applicationContext.getPersistenceGateway().refreshToken.mock.calls[0][1], - ).toEqual({ refreshToken: expectedRefresh }); - expect(result).toEqual({ - token: 'abc', - }); - }); - - it('throws an exception if not refresh token is passed in', async () => { - await expect( - renewIdTokenInteractor(applicationContext, { - refreshToken: undefined, - }), - ).rejects.toThrow('refreshToken is required'); - }); -}); diff --git a/shared/src/proxies/auth/confirmSignUpLocalProxy.ts b/shared/src/proxies/auth/confirmSignUpLocalProxy.ts deleted file mode 100644 index 7051d06aeb6..00000000000 --- a/shared/src/proxies/auth/confirmSignUpLocalProxy.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { post } from '../requests'; - -/** - * confirmSignUpLocalInteractor - * @param {object} applicationContext the application context - * @param {object} auth an object - * @param {string} auth.confirmationCode the email confirmation code provided by cognito - * @param {string} auth.userEmail the email of the user confirming their account - * @returns {Promise<*>} the promise of the api call - */ -export const confirmSignUpLocalInteractor = ( - applicationContext, - { confirmationCode, userEmail }, -) => { - return post({ - applicationContext, - body: { confirmationCode, userEmail }, - endpoint: '/confirm-signup-local', - options: { - withCredentials: false, - }, - }); -}; diff --git a/shared/src/proxies/auth/confirmSignUpProxy.ts b/shared/src/proxies/auth/confirmSignUpProxy.ts new file mode 100644 index 00000000000..9ffb768ccae --- /dev/null +++ b/shared/src/proxies/auth/confirmSignUpProxy.ts @@ -0,0 +1,19 @@ +import { ClientApplicationContext } from '@web-client/applicationContext'; +import { post } from '../requests'; + +export const confirmSignUpInteractor = ( + applicationContext: ClientApplicationContext, + { + confirmationCode, + userEmail, + }: { confirmationCode: string; userEmail: string }, +) => { + return post({ + applicationContext, + body: { confirmationCode, userEmail }, + endpoint: '/confirm-signup', + options: { + withCredentials: false, + }, + }); +}; diff --git a/web-api/src/app-public.ts b/web-api/src/app-public.ts index a095f636cae..14d164e31c1 100644 --- a/web-api/src/app-public.ts +++ b/web-api/src/app-public.ts @@ -52,7 +52,7 @@ app.use(logger()); import { advancedQueryLimiter } from './middleware/advancedQueryLimiter'; import { casePublicSearchLambda } from './lambdas/public-api/casePublicSearchLambda'; -import { confirmSignUpLocalLambda } from '@web-api/auth/confirmSignUpLocalLambda'; +import { confirmSignUpLambda } from '@web-api/lambdas/auth/confirmSignUpLambda'; import { generatePublicDocketRecordPdfLambda } from './lambdas/public-api/generatePublicDocketRecordPdfLambda'; import { getAllFeatureFlagsLambda } from './lambdas/featureFlag/getAllFeatureFlagsLambda'; import { getCachedHealthCheckLambda } from '@web-api/lambdas/health/getCachedHealthCheckLambda'; @@ -71,79 +71,102 @@ import { signUpUserLambda } from '@web-api/users/signUpUserLambda'; import { todaysOpinionsLambda } from './lambdas/public-api/todaysOpinionsLambda'; import { todaysOrdersLambda } from './lambdas/public-api/todaysOrdersLambda'; -/** - * public-api - */ -app.get('/public-api/search', lambdaWrapper(casePublicSearchLambda)); -app.head( - '/public-api/cases/:docketNumber', - lambdaWrapper(getPublicCaseExistsLambda), -); -app.get('/public-api/cases/:docketNumber', lambdaWrapper(getPublicCaseLambda)); - -app.get( - '/public-api/order-search', - ipLimiter({ - applicationContext, - key: applicationContext.getConstants().ADVANCED_DOCUMENT_IP_LIMITER_KEY, - }), - advancedQueryLimiter({ - applicationContext, - key: applicationContext.getConstants().ADVANCED_DOCUMENT_LIMITER_KEY, - }), - lambdaWrapper(orderPublicSearchLambda), -); - -app.get( - '/public-api/opinion-search', - ipLimiter({ - applicationContext, - key: applicationContext.getConstants().ADVANCED_DOCUMENT_IP_LIMITER_KEY, - }), - advancedQueryLimiter({ - applicationContext, - key: applicationContext.getConstants().ADVANCED_DOCUMENT_LIMITER_KEY, - }), - lambdaWrapper(opinionPublicSearchLambda), -); +/** Case */ +{ + app.head( + '/public-api/cases/:docketNumber', + lambdaWrapper(getPublicCaseExistsLambda), + ); + app.get( + '/public-api/cases/:docketNumber', + lambdaWrapper(getPublicCaseLambda), + ); + app.get( + '/public-api/:docketNumber/:key/public-document-download-url', + lambdaWrapper(getPublicDocumentDownloadUrlLambda), + ); + app.post( + '/public-api/cases/:docketNumber/generate-docket-record', + lambdaWrapper(generatePublicDocketRecordPdfLambda), + ); +} app.get('/public-api/judges', lambdaWrapper(getPublicJudgesLambda)); -app.get('/public-api/todays-opinions', lambdaWrapper(todaysOpinionsLambda)); -app.get( - '/public-api/todays-orders/:page/:todaysOrdersSort', - lambdaWrapper(todaysOrdersLambda), -); - -app.get( - '/public-api/docket-number-search/:docketNumber', - lambdaWrapper(getCaseForPublicDocketSearchLambda), -); - -app.post( - '/public-api/cases/:docketNumber/generate-docket-record', - lambdaWrapper(generatePublicDocketRecordPdfLambda), -); -app.get( - '/public-api/:docketNumber/:key/public-document-download-url', - lambdaWrapper(getPublicDocumentDownloadUrlLambda), -); -app.get('/public-api/health', lambdaWrapper(getHealthCheckLambda)); -app.get('/public-api/cached-health', lambdaWrapper(getCachedHealthCheckLambda)); -app.get( - '/public-api/maintenance-mode', - lambdaWrapper(getMaintenanceModeLambda), -); - -app.get('/feature-flag', lambdaWrapper(getAllFeatureFlagsLambda)); - -app.post('/public-api/account/create', lambdaWrapper(signUpUserLambda)); +/** + * Reports + */ +{ + app.get('/public-api/todays-opinions', lambdaWrapper(todaysOpinionsLambda)); + app.get( + '/public-api/todays-orders/:page/:todaysOrdersSort', + lambdaWrapper(todaysOrdersLambda), + ); +} + +/** Search */ +{ + app.get('/public-api/search', lambdaWrapper(casePublicSearchLambda)); + app.get( + '/public-api/order-search', + ipLimiter({ + applicationContext, + key: applicationContext.getConstants().ADVANCED_DOCUMENT_IP_LIMITER_KEY, + }), + advancedQueryLimiter({ + applicationContext, + key: applicationContext.getConstants().ADVANCED_DOCUMENT_LIMITER_KEY, + }), + lambdaWrapper(orderPublicSearchLambda), + ); + app.get( + '/public-api/opinion-search', + ipLimiter({ + applicationContext, + key: applicationContext.getConstants().ADVANCED_DOCUMENT_IP_LIMITER_KEY, + }), + advancedQueryLimiter({ + applicationContext, + key: applicationContext.getConstants().ADVANCED_DOCUMENT_LIMITER_KEY, + }), + lambdaWrapper(opinionPublicSearchLambda), + ); + app.get( + '/public-api/docket-number-search/:docketNumber', + lambdaWrapper(getCaseForPublicDocketSearchLambda), + ); +} -app.post( - '/account/resend-verification', - lambdaWrapper(resendVerificationLinkLambda), -); +/** + * Application Health + */ +{ + app.get('/public-api/health', lambdaWrapper(getHealthCheckLambda)); + app.get( + '/public-api/cached-health', + lambdaWrapper(getCachedHealthCheckLambda), + ); + app.get( + '/public-api/maintenance-mode', + lambdaWrapper(getMaintenanceModeLambda), + ); +} -// This following endpoint is used only by cognito-local +/** + * Feature flags + */ +{ + app.get('/feature-flag', lambdaWrapper(getAllFeatureFlagsLambda)); +} -app.post('/confirm-signup-local', lambdaWrapper(confirmSignUpLocalLambda)); +/** + * Accounts + */ +{ + app.post('/public-api/account/create', lambdaWrapper(signUpUserLambda)); + app.post( + '/account/resend-verification', + lambdaWrapper(resendVerificationLinkLambda), + ); + app.post('/confirm-signup', lambdaWrapper(confirmSignUpLambda)); +} diff --git a/web-api/src/app.ts b/web-api/src/app.ts index 4b1b222e8ea..b8e272d4a11 100644 --- a/web-api/src/app.ts +++ b/web-api/src/app.ts @@ -21,7 +21,7 @@ import { closeTrialSessionLambda } from './lambdas/trialSessions/closeTrialSessi import { completeDocketEntryQCLambda } from './lambdas/documents/completeDocketEntryQCLambda'; import { completeMessageLambda } from './lambdas/messages/completeMessageLambda'; import { completeWorkItemLambda } from './lambdas/workitems/completeWorkItemLambda'; -import { confirmSignUpLocalLambda } from './auth/confirmSignUpLocalLambda'; +import { confirmSignUpLambda } from './lambdas/auth/confirmSignUpLambda'; import { createApplicationContext } from './applicationContext'; import { createCaseDeadlineLambda } from './lambdas/caseDeadline/createCaseDeadlineLambda'; import { createCaseFromPaperLambda } from './lambdas/cases/createCaseFromPaperLambda'; @@ -1031,6 +1031,8 @@ app.get( app.post('/auth/refresh', lambdaWrapper(renewIdTokenLambda)); } +app.post('/confirm-signup', lambdaWrapper(confirmSignUpLambda)); + // This endpoint is used for testing purpose only which exposes the // CRON lambda which runs nightly to update cases to be ready for trial. if (process.env.IS_LOCAL) { @@ -1038,6 +1040,4 @@ if (process.env.IS_LOCAL) { '/run-check-ready-for-trial', lambdaWrapper(checkForReadyForTrialCasesLambda), ); - - app.post('/confirm-signup-local', lambdaWrapper(confirmSignUpLocalLambda)); } diff --git a/web-api/src/auth/confirmSignUpLocalLambda.ts b/web-api/src/auth/confirmSignUpLocalLambda.ts deleted file mode 100644 index 4e747100df2..00000000000 --- a/web-api/src/auth/confirmSignUpLocalLambda.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { genericHandler } from '../genericHandler'; - -/** - * - * @param {object} event the AWS event object - * @returns {Promise<*|undefined>} the api gateway response object containing the statusCode, body, and headers - */ -export const confirmSignUpLocalLambda = event => - genericHandler( - event, - async ({ applicationContext }) => { - return await applicationContext - .getUseCases() - .confirmSignUpLocalInteractor(applicationContext, { - ...JSON.parse(event.body), - }); - }, - { logResults: true }, - ); diff --git a/web-api/src/business/useCases/auth/confirmSignUpInteractor.test.ts b/web-api/src/business/useCases/auth/confirmSignUpInteractor.test.ts new file mode 100644 index 00000000000..1c434c357bf --- /dev/null +++ b/web-api/src/business/useCases/auth/confirmSignUpInteractor.test.ts @@ -0,0 +1,40 @@ +import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; +import { confirmSignUpInteractor } from './confirmSignUpInteractor'; + +describe('confirmSignUpInteractor', () => { + const confirmationCode = '123456'; + const userEmail = 'example@example.com'; + + beforeAll(() => { + applicationContext.getCognito().confirmSignUp.mockResolvedValue({}); + }); + + it('should call cognito confirmSignUp with correctly formatted parameters and return the result', async () => { + const result = await confirmSignUpInteractor(applicationContext, { + confirmationCode, + userEmail, + }); + + expect( + applicationContext.getCognito().confirmSignUp.mock.calls[0][0], + ).toMatchObject({ + ConfirmationCode: confirmationCode, + Username: userEmail, + }); + expect(result).toEqual({}); + }); + + it('should return an error when confirmSignUp fails', async () => { + applicationContext + .getCognito() + .confirmSignUp.mockRejectedValue(new Error()); + + await expect( + confirmSignUpInteractor(applicationContext, { + confirmationCode, + userEmail, + }), + ).rejects.toThrow(); + expect(applicationContext.getCognito().confirmSignUp).toHaveBeenCalled(); + }); +}); diff --git a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts new file mode 100644 index 00000000000..959228ced5e --- /dev/null +++ b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts @@ -0,0 +1,15 @@ +import { ServerApplicationContext } from '@web-api/applicationContext'; + +export const confirmSignUpInteractor = async ( + applicationContext: ServerApplicationContext, + { + confirmationCode, + userEmail, + }: { confirmationCode: string; userEmail: string }, +) => { + return await applicationContext.getCognito().confirmSignUp({ + ClientId: process.env.COGNITO_CLIENT_ID, + ConfirmationCode: confirmationCode, + Username: userEmail, + }); +}; diff --git a/web-api/src/business/useCases/auth/renewIdTokenInteractor.test.ts b/web-api/src/business/useCases/auth/renewIdTokenInteractor.test.ts new file mode 100644 index 00000000000..7db0e2b2f00 --- /dev/null +++ b/web-api/src/business/useCases/auth/renewIdTokenInteractor.test.ts @@ -0,0 +1,40 @@ +import { NotAuthorizedException } from '@aws-sdk/client-cognito-identity-provider'; +import { UnauthorizedError } from '@web-api/errors/errors'; +import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; +import { renewIdTokenInteractor } from './renewIdTokenInteractor'; + +describe('renewIdTokenInteractor', () => { + it('should throw an UnauthorizedError when the id token cannot be renewed because the refresh token has expired', async () => { + const mockError = new NotAuthorizedException({ + $metadata: {}, + message: 'Refresh token is expired', + }); + applicationContext + .getPersistenceGateway() + .renewIdToken.mockRejectedValue(mockError); + + await expect( + renewIdTokenInteractor(applicationContext, { + refreshToken: undefined as any, + }), + ).rejects.toThrow(UnauthorizedError); + }); + + it('should make a call to get an id token and refresh token', async () => { + const expectedRefresh = 'sometoken'; + applicationContext.getPersistenceGateway().renewIdToken.mockResolvedValue({ + idToken: 'abc', + }); + + const result = await renewIdTokenInteractor(applicationContext, { + refreshToken: expectedRefresh, + }); + + expect( + applicationContext.getPersistenceGateway().renewIdToken.mock.calls[0][1], + ).toEqual({ refreshToken: expectedRefresh }); + expect(result).toEqual({ + idToken: 'abc', + }); + }); +}); diff --git a/shared/src/business/useCases/auth/renewIdTokenInteractor.ts b/web-api/src/business/useCases/auth/renewIdTokenInteractor.ts similarity index 83% rename from shared/src/business/useCases/auth/renewIdTokenInteractor.ts rename to web-api/src/business/useCases/auth/renewIdTokenInteractor.ts index fc1fcf2e865..bce2c45f6b2 100644 --- a/shared/src/business/useCases/auth/renewIdTokenInteractor.ts +++ b/web-api/src/business/useCases/auth/renewIdTokenInteractor.ts @@ -1,8 +1,9 @@ import { NotAuthorizedException } from '@aws-sdk/client-cognito-identity-provider'; +import { ServerApplicationContext } from '@web-api/applicationContext'; import { UnauthorizedError } from '@web-api/errors/errors'; export const renewIdTokenInteractor = async ( - applicationContext: IApplicationContext, + applicationContext: ServerApplicationContext, { refreshToken }: { refreshToken: string }, ): Promise<{ idToken: string; diff --git a/web-api/src/getUseCases.ts b/web-api/src/getUseCases.ts index c74cf79c320..c1cb9c00b23 100644 --- a/web-api/src/getUseCases.ts +++ b/web-api/src/getUseCases.ts @@ -22,7 +22,7 @@ import { closeTrialSessionInteractor } from '../../shared/src/business/useCases/ import { completeDocketEntryQCInteractor } from '../../shared/src/business/useCases/editDocketEntry/completeDocketEntryQCInteractor'; import { completeMessageInteractor } from '../../shared/src/business/useCases/messages/completeMessageInteractor'; import { completeWorkItemInteractor } from '../../shared/src/business/useCases/workitems/completeWorkItemInteractor'; -import { confirmSignUpLocalInteractor } from '../../shared/src/business/useCases/auth/confirmSignUpLocalInteractor'; +import { confirmSignUpInteractor } from './business/useCases/auth/confirmSignUpInteractor'; import { createCaseDeadlineInteractor } from '../../shared/src/business/useCases/caseDeadline/createCaseDeadlineInteractor'; import { createCaseFromPaperInteractor } from '../../shared/src/business/useCases/createCaseFromPaperInteractor'; import { createCaseInteractor } from '../../shared/src/business/useCases/createCaseInteractor'; @@ -153,7 +153,7 @@ import { removeConsolidatedCasesInteractor } from '../../shared/src/business/use import { removePdfFromDocketEntryInteractor } from '../../shared/src/business/useCases/removePdfFromDocketEntryInteractor'; import { removePetitionerAndUpdateCaptionInteractor } from '../../shared/src/business/useCases/removePetitionerAndUpdateCaptionInteractor'; import { removeSignatureFromDocumentInteractor } from '../../shared/src/business/useCases/removeSignatureFromDocumentInteractor'; -import { renewIdTokenInteractor } from '../../shared/src/business/useCases/auth/renewIdTokenInteractor'; +import { renewIdTokenInteractor } from './business/useCases/auth/renewIdTokenInteractor'; import { replyToMessageInteractor } from '../../shared/src/business/useCases/messages/replyToMessageInteractor'; import { resendVerificationLinkInteractor } from '@shared/business/useCases/public/resendVerificationLinkInteractor'; import { runTrialSessionPlanningReportInteractor } from '../../shared/src/business/useCases/trialSessions/runTrialSessionPlanningReportInteractor'; @@ -235,7 +235,7 @@ const useCases = { completeDocketEntryQCInteractor, completeMessageInteractor, completeWorkItemInteractor, - confirmSignUpLocalInteractor, + confirmSignUpInteractor, createCaseDeadlineInteractor, createCaseFromPaperInteractor, createCaseInteractor, diff --git a/web-api/src/lambdas/auth/confirmSignUpLambda.ts b/web-api/src/lambdas/auth/confirmSignUpLambda.ts new file mode 100644 index 00000000000..a03e9ab64cb --- /dev/null +++ b/web-api/src/lambdas/auth/confirmSignUpLambda.ts @@ -0,0 +1,15 @@ +import { APIGatewayProxyEvent } from 'aws-lambda'; +import { genericHandler } from '../../genericHandler'; + +export const confirmSignUpLambda = (event: APIGatewayProxyEvent) => + genericHandler( + event, + async ({ applicationContext }) => { + return await applicationContext + .getUseCases() + .confirmSignUpInteractor(applicationContext, { + ...JSON.parse(event.body), + }); + }, + { logResults: true }, + ); diff --git a/web-client/integration-tests/petitionerCreatesAccount.test.ts b/web-client/integration-tests/petitionerCreatesAccount.test.ts index 4060b896b73..211f54cc5b0 100644 --- a/web-client/integration-tests/petitionerCreatesAccount.test.ts +++ b/web-client/integration-tests/petitionerCreatesAccount.test.ts @@ -18,7 +18,7 @@ describe.skip('Petitioner creates new account', () => { const name = 'Test Petitioner Cognito'; const password = 'aA1!aaaa'; const standardizedConfirmationCode = '123456'; - const expectedVerificationLink = `/confirm-signup-local?confirmationCode=${standardizedConfirmationCode}&email=${userName}`; + const expectedVerificationLink = `/confirm-signup?confirmationCode=${standardizedConfirmationCode}&email=${userName}`; it('petitioner creates a new account', async () => { await cerebralTestPublic.runSequence('goToCreatePetitionerAccountSequence'); @@ -60,7 +60,7 @@ describe.skip('Petitioner creates new account', () => { }); it('petitioner follows verification link to confirm new account', async () => { - await cerebralTestPublic.runSequence('confirmSignUpLocalSequence', { + await cerebralTestPublic.runSequence('confirmSignUpSequence', { confirmationCode: standardizedConfirmationCode, userEmail: userName, }); diff --git a/web-client/src/applicationContext.ts b/web-client/src/applicationContext.ts index 6a0178c5bea..98f1cf2acb8 100644 --- a/web-client/src/applicationContext.ts +++ b/web-client/src/applicationContext.ts @@ -86,7 +86,7 @@ import { import { completeDocketEntryQCInteractor } from '../../shared/src/proxies/editDocketEntry/completeDocketEntryQCProxy'; import { completeMessageInteractor } from '../../shared/src/proxies/messages/completeMessageProxy'; import { completeWorkItemInteractor } from '../../shared/src/proxies/workitems/completeWorkItemProxy'; -import { confirmSignUpLocalInteractor } from '../../shared/src/proxies/auth/confirmSignUpLocalProxy'; +import { confirmSignUpInteractor } from '../../shared/src/proxies/auth/confirmSignUpProxy'; import { createCaseDeadlineInteractor } from '../../shared/src/proxies/caseDeadline/createCaseDeadlineProxy'; import { createCaseFromPaperInteractor } from '../../shared/src/proxies/createCaseFromPaperProxy'; import { createCaseInteractor } from '../../shared/src/proxies/createCaseProxy'; @@ -407,7 +407,7 @@ const allUseCases = { completeDocketEntryQCInteractor, completeMessageInteractor, completeWorkItemInteractor, - confirmSignUpLocalInteractor, + confirmSignUpInteractor, createCaseDeadlineInteractor, createCaseFromPaperInteractor, createCaseInteractor, diff --git a/web-client/src/applicationContextPublic.ts b/web-client/src/applicationContextPublic.ts index 837069e3a52..17b59af5ade 100644 --- a/web-client/src/applicationContextPublic.ts +++ b/web-client/src/applicationContextPublic.ts @@ -45,7 +45,7 @@ import { import { User } from '../../shared/src/business/entities/User'; import { casePublicSearchInteractor } from '../../shared/src/proxies/casePublicSearchProxy'; import { compareCasesByDocketNumber } from '../../shared/src/business/utilities/getFormattedTrialSessionDetails'; -import { confirmSignUpLocalInteractor } from '@shared/proxies/auth/confirmSignUpLocalProxy'; +import { confirmSignUpInteractor } from '@shared/proxies/auth/confirmSignUpProxy'; import { createISODateString, formatDateString, @@ -89,6 +89,7 @@ import { validateOpinionAdvancedSearchInteractor } from '../../shared/src/busine import { validateOrderAdvancedSearchInteractor } from '../../shared/src/business/useCases/validateOrderAdvancedSearchInteractor'; import axios from 'axios'; import deepFreeze from 'deep-freeze'; + const ADVANCED_SEARCH_TABS = { CASE: 'case', OPINION: 'opinion', @@ -97,7 +98,7 @@ const ADVANCED_SEARCH_TABS = { const allUseCases = { casePublicSearchInteractor, - confirmSignUpLocalInteractor, + confirmSignUpInteractor, generatePublicDocketRecordPdfInteractor, getAllFeatureFlagsInteractor, getCaseExistsInteractor: getPublicCaseExistsInteractor, diff --git a/web-client/src/presenter/actions/confirmSignUpLocalAction.test.ts b/web-client/src/presenter/actions/confirmSignUpAction.test.ts similarity index 90% rename from web-client/src/presenter/actions/confirmSignUpLocalAction.test.ts rename to web-client/src/presenter/actions/confirmSignUpAction.test.ts index 82778bc2eda..f7ccd7c384b 100644 --- a/web-client/src/presenter/actions/confirmSignUpLocalAction.test.ts +++ b/web-client/src/presenter/actions/confirmSignUpAction.test.ts @@ -1,9 +1,9 @@ import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; -import { confirmSignUpLocalAction } from './confirmSignUpLocalAction'; +import { confirmSignUpAction } from './confirmSignUpAction'; import { presenter } from '../presenter-mock'; import { runAction } from '@web-client/presenter/test.cerebral'; -describe('confirmSignUpLocalAction', () => { +describe('confirmSignUpAction', () => { const confirmationCode = '123456'; const userEmail = 'someone@example.com'; @@ -24,7 +24,7 @@ describe('confirmSignUpLocalAction', () => { }); it('should call the confirmSignUpLocalInteractor with the user email and confirmation code from props and return path.yes when confirmSignUpLocalInteractor returns a response', async () => { - await runAction(confirmSignUpLocalAction, { + await runAction(confirmSignUpAction, { modules: { presenter, }, @@ -39,7 +39,6 @@ describe('confirmSignUpLocalAction', () => { applicationContext.getUseCases().confirmSignUpLocalInteractor.mock .calls[0][1], ).toMatchObject({ confirmationCode, userEmail }); - expect(mockYes.mock.calls[0][0]).toEqual({ alertSuccess: { alertType: 'success', @@ -57,7 +56,7 @@ describe('confirmSignUpLocalAction', () => { throw new Error(); }); - await runAction(confirmSignUpLocalAction, { + await runAction(confirmSignUpAction, { modules: { presenter, }, diff --git a/web-client/src/presenter/actions/confirmSignUpLocalAction.ts b/web-client/src/presenter/actions/confirmSignUpAction.ts similarity index 54% rename from web-client/src/presenter/actions/confirmSignUpLocalAction.ts rename to web-client/src/presenter/actions/confirmSignUpAction.ts index 5743eddf9a4..a8316efcbb5 100644 --- a/web-client/src/presenter/actions/confirmSignUpLocalAction.ts +++ b/web-client/src/presenter/actions/confirmSignUpAction.ts @@ -1,25 +1,19 @@ -/** - * Confirms the user's account in cognito, locally - * @param {object} providers the providers object - * @param {object} providers.applicationContext the applicationContext - * @param {object} providers.path the cerebral path function - * @param {object} providers.get the cerebral get function - * @returns {Promise} async action - */ -export const confirmSignUpLocalAction = async ({ +export const confirmSignUpAction = async ({ applicationContext, path, props, -}: ActionProps) => { +}: ActionProps<{ confirmationCode: string; userEmail: string }>) => { const { confirmationCode, userEmail } = props; try { await applicationContext .getUseCases() - .confirmSignUpLocalInteractor(applicationContext, { + .confirmSignUpInteractor(applicationContext, { confirmationCode, userEmail, }); + + // 10007 TODO: make path.success return path.yes({ alertSuccess: { alertType: 'success', @@ -29,6 +23,7 @@ export const confirmSignUpLocalAction = async ({ }, }); } catch (e) { + // 10007 TODO: make path.error return path.no({ alertError: { message: 'Error confirming account', diff --git a/web-client/src/presenter/actions/createConfirmLinkLocalAction.test.ts b/web-client/src/presenter/actions/createConfirmLinkAction.test.ts similarity index 78% rename from web-client/src/presenter/actions/createConfirmLinkLocalAction.test.ts rename to web-client/src/presenter/actions/createConfirmLinkAction.test.ts index 9c97c5ed6d6..c8184f62c27 100644 --- a/web-client/src/presenter/actions/createConfirmLinkLocalAction.test.ts +++ b/web-client/src/presenter/actions/createConfirmLinkAction.test.ts @@ -1,9 +1,9 @@ import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; -import { createConfirmLinkLocalAction } from '@web-client/presenter/actions/createConfirmLinkLocalAction'; +import { createConfirmLinkAction } from '@web-client/presenter/actions/createConfirmLinkAction'; import { presenter } from '../presenter-mock'; import { runAction } from '@web-client/presenter/test.cerebral'; -describe('createConfirmLinkLocalAction', () => { +describe('createConfirmLinkAction', () => { const email = 'something@example.com'; const oldEnv = process.env; @@ -17,7 +17,7 @@ describe('createConfirmLinkLocalAction', () => { it('should return immediately if IS_LOCAL is not defined', async () => { delete process.env.IS_LOCAL; - const result = await runAction(createConfirmLinkLocalAction, { + const result = await runAction(createConfirmLinkAction, { modules: { presenter, }, @@ -30,7 +30,7 @@ describe('createConfirmLinkLocalAction', () => { it('should construct an alertSuccess message when IS_LOCAL is "true"', async () => { process.env.IS_LOCAL = 'true'; - const result = await runAction(createConfirmLinkLocalAction, { + const result = await runAction(createConfirmLinkAction, { modules: { presenter, }, @@ -40,7 +40,7 @@ describe('createConfirmLinkLocalAction', () => { }); const confirmationLink = - '/confirm-signup-local?confirmationCode=123456&email=something@example.com'; + '/confirm-signup?confirmationCode=123456&email=something@example.com'; const { alertType, message, title } = result.output!.alertSuccess; expect(alertType).toEqual('success'); diff --git a/web-client/src/presenter/actions/createConfirmLinkLocalAction.ts b/web-client/src/presenter/actions/createConfirmLinkAction.ts similarity index 77% rename from web-client/src/presenter/actions/createConfirmLinkLocalAction.ts rename to web-client/src/presenter/actions/createConfirmLinkAction.ts index 8a055bc0edc..9b3976b8098 100644 --- a/web-client/src/presenter/actions/createConfirmLinkLocalAction.ts +++ b/web-client/src/presenter/actions/createConfirmLinkAction.ts @@ -1,18 +1,19 @@ import qs from 'qs'; -export const createConfirmLinkLocalAction = ({ props }: ActionProps) => { +export const createConfirmLinkAction = ({ props }: ActionProps) => { if (!process.env.IS_LOCAL) return; const { email } = props; // confirmation code is currently intentionally hard-coded in cognitoLocal + // ^^ it is not, have to set process.env.CODE const confirmationCode = '123456'; const queryString = qs.stringify( { confirmationCode, email }, { encode: false }, ); - const confirmationLink = `/confirm-signup-local?${queryString}`; + const confirmationLink = `/confirm-signup?${queryString}`; return { alertSuccess: { diff --git a/web-client/src/presenter/presenter-public.ts b/web-client/src/presenter/presenter-public.ts index c586d4448d3..9f940f09954 100644 --- a/web-client/src/presenter/presenter-public.ts +++ b/web-client/src/presenter/presenter-public.ts @@ -7,7 +7,7 @@ import { cerebralBindSimpleSetStateSequence } from './sequences/cerebralBindSimp import { clearAdvancedSearchFormSequence } from './sequences/clearAdvancedSearchFormSequence'; import { clearPdfPreviewUrlSequence } from './sequences/clearPdfPreviewUrlSequence'; import { closeModalAndNavigateToMaintenanceSequence } from './sequences/closeModalAndNavigateToMaintenanceSequence'; -import { confirmSignUpLocalSequence } from '@web-client/presenter/sequences/confirmSignUpLocalSequence'; +import { confirmSignUpSequence } from '@web-client/presenter/sequences/confirmSignUpSequence'; import { dismissModalSequence } from './sequences/dismissModalSequence'; import { goToCreatePetitionerAccountSequence } from '@web-client/presenter/sequences/Public/goToCreatePetitionerAccountSequence'; import { goToVerificationSentSequence } from '@web-client/presenter/sequences/goToVerificationSentSequence'; @@ -66,7 +66,7 @@ export const presenterSequences = { clearAdvancedSearchFormSequence, clearPdfPreviewUrlSequence, closeModalAndNavigateToMaintenanceSequence, - confirmSignUpLocalSequence, + confirmSignUpSequence, dismissModalSequence, goToCreatePetitionerAccountSequence, goToVerificationSentSequence, diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 11cbe7bf036..a8c4312e40f 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -77,7 +77,7 @@ import { completeDocumentSelectSequence } from './sequences/completeDocumentSele import { completeMessageSequence } from './sequences/completeMessageSequence'; import { completePrintPaperPetitionReceiptSequence } from './sequences/completePrintPaperPetitionReceiptSequence'; import { completeStartCaseWizardStepSequence } from './sequences/completeStartCaseWizardStepSequence'; -import { confirmSignUpLocalSequence } from './sequences/confirmSignUpLocalSequence'; +import { confirmSignUpSequence } from './sequences/confirmSignUpSequence'; import { confirmStayLoggedInSequence } from './sequences/confirmStayLoggedInSequence'; import { confirmWorkItemAlreadyCompleteSequence } from './sequences/confirmWorkItemAlreadyCompleteSequence'; import { consolidatedCaseCheckboxAllChangeSequence } from './sequences/consolidatedCaseCheckboxAllChangeSequence'; @@ -674,7 +674,7 @@ export const presenterSequences = { completePrintPaperPetitionReceiptSequence as unknown as Function, completeStartCaseWizardStepSequence: completeStartCaseWizardStepSequence as unknown as Function, - confirmSignUpLocalSequence: confirmSignUpLocalSequence as unknown as Function, + confirmSignUpSequence: confirmSignUpSequence as unknown as Function, confirmStayLoggedInSequence: confirmStayLoggedInSequence as unknown as Function, confirmWorkItemAlreadyCompleteSequence: diff --git a/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts b/web-client/src/presenter/sequences/confirmSignUpSequence.ts similarity index 74% rename from web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts rename to web-client/src/presenter/sequences/confirmSignUpSequence.ts index 08a7c6b65b9..12527293ea1 100644 --- a/web-client/src/presenter/sequences/confirmSignUpLocalSequence.ts +++ b/web-client/src/presenter/sequences/confirmSignUpSequence.ts @@ -1,11 +1,11 @@ -import { confirmSignUpLocalAction } from '../actions/confirmSignUpLocalAction'; +import { confirmSignUpAction } from '../actions/confirmSignUpAction'; import { navigateToLoginSequence } from '@web-client/presenter/sequences/Login/navigateToLoginSequence'; import { setAlertErrorAction } from '../actions/setAlertErrorAction'; import { setAlertSuccessAction } from '../actions/setAlertSuccessAction'; // TODO 10007: this can probably be unified with the other change password stuff -export const confirmSignUpLocalSequence = [ - confirmSignUpLocalAction, +export const confirmSignUpSequence = [ + confirmSignUpAction, { no: [setAlertErrorAction], yes: [setAlertSuccessAction], diff --git a/web-client/src/presenter/sequences/submitCreatePetitionerAccountFormSequence.ts b/web-client/src/presenter/sequences/submitCreatePetitionerAccountFormSequence.ts index 07eea1faac7..eda162065ac 100644 --- a/web-client/src/presenter/sequences/submitCreatePetitionerAccountFormSequence.ts +++ b/web-client/src/presenter/sequences/submitCreatePetitionerAccountFormSequence.ts @@ -1,6 +1,6 @@ import { clearAlertsAction } from '@web-client/presenter/actions/clearAlertsAction'; import { clearFormAction } from '@web-client/presenter/actions/clearFormAction'; -import { createConfirmLinkLocalAction } from '@web-client/presenter/actions/createConfirmLinkLocalAction'; +import { createConfirmLinkAction } from '@web-client/presenter/actions/createConfirmLinkAction'; import { createNewPetitionerUserAction } from '@web-client/presenter/actions/createNewPetitionerUserAction'; import { navigateToVerificationSentAction } from '@web-client/presenter/actions/navigateToVerificationSentAction'; import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertErrorAction'; @@ -14,7 +14,7 @@ export const submitCreatePetitionerAccountFormSequence = [ { error: [setAlertErrorAction], success: showProgressSequenceDecorator([ - createConfirmLinkLocalAction, + createConfirmLinkAction, setAlertSuccessAction, clearFormAction, setNewAccountEmailInStateAction, diff --git a/web-client/src/router.ts b/web-client/src/router.ts index 932e978c262..b211b23f890 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -835,9 +835,9 @@ const router = { }), ); - registerRoute('/confirm-signup-local?..', () => { + registerRoute('/confirm-signup?..', () => { const { confirmationCode, email } = route.query(); - return app.getSequence('confirmSignUpLocalSequence')({ + return app.getSequence('confirmSignUpSequence')({ confirmationCode, userEmail: email, }); diff --git a/web-client/src/routerPublic.ts b/web-client/src/routerPublic.ts index f51ffb1a1d7..f36b6e87df8 100644 --- a/web-client/src/routerPublic.ts +++ b/web-client/src/routerPublic.ts @@ -95,9 +95,9 @@ const router = { return app.getSequence('gotoMaintenanceSequence')(); }); - route('/confirm-signup-local?..', () => { + route('/confirm-signup?..', () => { const { confirmationCode, email } = route.query(); - return app.getSequence('confirmSignUpLocalSequence')({ + return app.getSequence('confirmSignUpSequence')({ confirmationCode, userEmail: email, }); From e33d97e7e946adcff021074b9134ac09cf314898 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Wed, 3 Jan 2024 09:52:18 -0800 Subject: [PATCH 089/700] 10007: Update error handling for cognito v3 --- web-api/src/business/useCases/auth/loginInteractor.ts | 10 ++++------ .../business/useCases/auth/renewIdTokenInteractor.ts | 5 ++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 2e99ca58351..5c121b2c453 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -5,10 +5,8 @@ export const loginInteractor = async ( applicationContext: ServerApplicationContext, { email, password }: { email: string; password: string }, ): Promise<{ idToken: string; accessToken: string; refreshToken: string }> => { - const cognito = applicationContext.getCognito(); - try { - const result = await cognito.initiateAuth({ + const result = await applicationContext.getCognito().initiateAuth({ AuthFlow: 'USER_PASSWORD_AUTH', AuthParameters: { PASSWORD: password, @@ -23,13 +21,13 @@ export const loginInteractor = async ( refreshToken: result.AuthenticationResult!.RefreshToken!, }; } catch (err: any) { - // AWS Cognito InvalidPasswordException if ( - err.code === 'InvalidPasswordException' || - err.code === 'NotAuthorizedException' + err.name === 'InvalidPasswordException' || + err.name === 'NotAuthorizedException' ) { throw new UnknownUserError('Invalid Username or Password'); } + throw err; } }; diff --git a/web-api/src/business/useCases/auth/renewIdTokenInteractor.ts b/web-api/src/business/useCases/auth/renewIdTokenInteractor.ts index bce2c45f6b2..ece131637c8 100644 --- a/web-api/src/business/useCases/auth/renewIdTokenInteractor.ts +++ b/web-api/src/business/useCases/auth/renewIdTokenInteractor.ts @@ -1,4 +1,3 @@ -import { NotAuthorizedException } from '@aws-sdk/client-cognito-identity-provider'; import { ServerApplicationContext } from '@web-api/applicationContext'; import { UnauthorizedError } from '@web-api/errors/errors'; @@ -16,8 +15,8 @@ export const renewIdTokenInteractor = async ( return { idToken, }; - } catch (err) { - if (err instanceof NotAuthorizedException) { + } catch (err: any) { + if (err.name === 'NotAuthorizedException') { throw new UnauthorizedError('Invalid refresh token'); } From e4cb7cb04d852afb98615d77c2875c82bbfd87f3 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Wed, 3 Jan 2024 12:06:02 -0800 Subject: [PATCH 090/700] 10007: WIP display success when confirming new account --- run-local.sh | 2 +- .../src/presenter/actions/confirmSignUpAction.ts | 4 ++-- .../presenter/actions/createConfirmLinkAction.ts | 4 ++-- web-client/src/views/Login/Login.tsx | 16 +++++++++------- .../views/Public/MessageAlert/MessageAlert.tsx | 1 + 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/run-local.sh b/run-local.sh index e50060bd41e..039432700a1 100755 --- a/run-local.sh +++ b/run-local.sh @@ -53,7 +53,7 @@ echo "Seeding cognito-local users" npx ts-node .cognito/seedCognitoLocal.ts --transpile-only echo "Starting cognito-local" -npx cognito-local & +CODE="COGNITO_LOCAL_CONFIRMATION_CODE" npx cognito-local & COGNITO_PID=$! diff --git a/web-client/src/presenter/actions/confirmSignUpAction.ts b/web-client/src/presenter/actions/confirmSignUpAction.ts index a8316efcbb5..7d5cdff2349 100644 --- a/web-client/src/presenter/actions/confirmSignUpAction.ts +++ b/web-client/src/presenter/actions/confirmSignUpAction.ts @@ -18,8 +18,8 @@ export const confirmSignUpAction = async ({ alertSuccess: { alertType: 'success', message: - 'Your registration has been confirmed! You will be redirected shortly!', - title: 'Account Confirmed Locally', + 'Your email address is verified. You can now sign in to DAWSON.', + title: 'Email address verified', }, }); } catch (e) { diff --git a/web-client/src/presenter/actions/createConfirmLinkAction.ts b/web-client/src/presenter/actions/createConfirmLinkAction.ts index 9b3976b8098..66760a2b812 100644 --- a/web-client/src/presenter/actions/createConfirmLinkAction.ts +++ b/web-client/src/presenter/actions/createConfirmLinkAction.ts @@ -7,13 +7,13 @@ export const createConfirmLinkAction = ({ props }: ActionProps) => { // confirmation code is currently intentionally hard-coded in cognitoLocal // ^^ it is not, have to set process.env.CODE - const confirmationCode = '123456'; + const confirmationCode = 'COGNITO_LOCAL_CONFIRMATION_CODE'; const queryString = qs.stringify( { confirmationCode, email }, { encode: false }, ); - const confirmationLink = `/confirm-signup?${queryString}`; + const confirmationLink = `http://localhost:1234/confirm-signup?${queryString}`; return { alertSuccess: { diff --git a/web-client/src/views/Login/Login.tsx b/web-client/src/views/Login/Login.tsx index 75b1ee4b103..696a62f73a7 100644 --- a/web-client/src/views/Login/Login.tsx +++ b/web-client/src/views/Login/Login.tsx @@ -1,5 +1,6 @@ import { Button } from '@web-client/ustc-ui/Button/Button'; import { MessageAlert } from '@web-client/views/Public/MessageAlert/MessageAlert'; +import { SuccessNotification } from '@web-client/views/SuccessNotification'; import { connect } from '@web-client/presenter/shared.cerebral'; import { sequences, state } from '@web-client/presenter/app.cerebral'; import React from 'react'; @@ -26,15 +27,16 @@ export const Login = connect( return ( <>
- {alertError && ( - - )}
+ + {alertError && ( + + )}
diff --git a/web-client/src/views/Public/MessageAlert/MessageAlert.tsx b/web-client/src/views/Public/MessageAlert/MessageAlert.tsx index ad8af64e6f6..5b2469f4c78 100644 --- a/web-client/src/views/Public/MessageAlert/MessageAlert.tsx +++ b/web-client/src/views/Public/MessageAlert/MessageAlert.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useRef } from 'react'; +// 10007 TODO: Do we need this? Can we use ErrorNotification? export const MessageAlert = ({ alertType = 'error', message, title }) => { const alertTypeClassName = { error: 'usa-alert--error', From f1b166be54a73b53b3998068b15790ae1b524b5f Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Wed, 3 Jan 2024 14:07:42 -0800 Subject: [PATCH 091/700] 10007: Fail silently when token can't be refreshed so that router can take user where they need to go --- .../actions/Login/refreshTokenAction.ts | 13 +++++++---- .../sequences/Init/initAppSequence.ts | 22 +++++++++++-------- web-client/src/routerPublic.ts | 8 ------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/web-client/src/presenter/actions/Login/refreshTokenAction.ts b/web-client/src/presenter/actions/Login/refreshTokenAction.ts index 9508732a155..e714a34b221 100644 --- a/web-client/src/presenter/actions/Login/refreshTokenAction.ts +++ b/web-client/src/presenter/actions/Login/refreshTokenAction.ts @@ -1,9 +1,14 @@ export const refreshTokenAction = async ({ applicationContext, + path, }: ActionProps): Promise<{ idToken: string }> => { - const { idToken } = await applicationContext - .getUseCases() - .renewIdTokenInteractor(applicationContext); + try { + const { idToken } = await applicationContext + .getUseCases() + .renewIdTokenInteractor(applicationContext); - return { idToken }; + return path.userIsLoggedIn({ idToken }); + } catch (err) { + return path.userIsNotLoggedIn(); + } }; diff --git a/web-client/src/presenter/sequences/Init/initAppSequence.ts b/web-client/src/presenter/sequences/Init/initAppSequence.ts index cee08bd31f1..0544a955154 100644 --- a/web-client/src/presenter/sequences/Init/initAppSequence.ts +++ b/web-client/src/presenter/sequences/Init/initAppSequence.ts @@ -2,7 +2,6 @@ import { getMaintenanceModeAction } from '@web-client/presenter/actions/Maintena import { getUserAction } from '@web-client/presenter/actions/getUserAction'; import { isMaintenanceModeEngagedAction } from '@web-client/presenter/actions/Maintenance/isMaintenanceModeEngagedAction'; import { navigateToMaintenanceAction } from '@web-client/presenter/actions/navigateToMaintenanceAction'; -import { parallel } from 'cerebral/factories'; import { refreshTokenAction } from '@web-client/presenter/actions/Login/refreshTokenAction'; import { setMaintenanceModeAction } from '@web-client/presenter/actions/setMaintenanceModeAction'; import { setTokenAction } from '@web-client/presenter/actions/Login/setTokenAction'; @@ -11,17 +10,22 @@ import { setUserPermissionsAction } from '@web-client/presenter/actions/setUserP import { startRefreshIntervalSequence } from '@web-client/presenter/sequences/startRefreshIntervalSequence'; export const initAppSequence = [ - parallel([ - [refreshTokenAction, setTokenAction], - [getMaintenanceModeAction, setMaintenanceModeAction], - ]), + getMaintenanceModeAction, + setMaintenanceModeAction, isMaintenanceModeEngagedAction, { maintenanceModeOff: [ - parallel([ - [getUserAction, setUserAction, setUserPermissionsAction], - startRefreshIntervalSequence, - ]), + startRefreshIntervalSequence, + refreshTokenAction, + { + userIsLoggedIn: [ + setTokenAction, + getUserAction, + setUserAction, + setUserPermissionsAction, + ], + userIsNotLoggedIn: [], + }, ], maintenanceModeOn: [navigateToMaintenanceAction], }, diff --git a/web-client/src/routerPublic.ts b/web-client/src/routerPublic.ts index f36b6e87df8..e5c5ae012d3 100644 --- a/web-client/src/routerPublic.ts +++ b/web-client/src/routerPublic.ts @@ -95,14 +95,6 @@ const router = { return app.getSequence('gotoMaintenanceSequence')(); }); - route('/confirm-signup?..', () => { - const { confirmationCode, email } = route.query(); - return app.getSequence('confirmSignUpSequence')({ - confirmationCode, - userEmail: email, - }); - }); - route('/login', () => { return app.getSequence('redirectToLoginSequence')(); }); From f428fe1823e28f7c988764829da951fd8e9babae Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Wed, 3 Jan 2024 15:28:43 -0800 Subject: [PATCH 092/700] 10007: Make success notification dismissable --- .../presenter/actions/confirmSignUpAction.ts | 1 - web-client/src/views/Login/Login.tsx | 2 +- web-client/src/views/SuccessNotification.tsx | 50 +++++++++++++------ 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/web-client/src/presenter/actions/confirmSignUpAction.ts b/web-client/src/presenter/actions/confirmSignUpAction.ts index 7d5cdff2349..3bd1d1ee6ed 100644 --- a/web-client/src/presenter/actions/confirmSignUpAction.ts +++ b/web-client/src/presenter/actions/confirmSignUpAction.ts @@ -16,7 +16,6 @@ export const confirmSignUpAction = async ({ // 10007 TODO: make path.success return path.yes({ alertSuccess: { - alertType: 'success', message: 'Your email address is verified. You can now sign in to DAWSON.', title: 'Email address verified', diff --git a/web-client/src/views/Login/Login.tsx b/web-client/src/views/Login/Login.tsx index 696a62f73a7..c4c13f8eaf8 100644 --- a/web-client/src/views/Login/Login.tsx +++ b/web-client/src/views/Login/Login.tsx @@ -29,7 +29,7 @@ export const Login = connect(
- + {alertError && ( ( + successNotificationDeps, + function SuccessNotification({ + alertSuccess, + dismissAlertSequence, + isDismissable = true, + }) { const notificationRef = useRef(null); const isMessageOnly = alertSuccess && alertSuccess.message && !alertSuccess.title; @@ -37,6 +50,9 @@ export const SuccessNotification = connect( role="alert" >
+ {alertSuccess.title && ( +

{alertSuccess.title}

+ )}
@@ -55,16 +71,18 @@ export const SuccessNotification = connect( )}
-
- -
+ {isDismissable && ( +
+ +
+ )}
From 26f8182b6816b3a381c2fc1d0f4ec33a78126e05 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 4 Jan 2024 11:56:16 -0800 Subject: [PATCH 093/700] 10007: docs --- temp_delete_me.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 536a077f67b..69301c156e9 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -11,14 +11,14 @@ - finish all todos (review together - KS) - ensure back works right (public to private and back) - fix tests -- email verification flow (just after verifying, are we going to new login with verification success message) ++ email verification flow (just after verifying, are we going to new login with verification success message) - create account (move to private - client site) - Refactor ifHasAccess Function to be handled by router + initSequence - Refactor maintenance mode to be handled by router + initSequence. No other sequence needs to branch because of it. - invalidate old refreshToken and idToken upon refresh. - Ensure idToken lasts longer than how often we are refreshing the idToken (REFRESH_INTERVAL) - We need to handle temporary password changes on login screen. This happens when cognito forces a password update. -- cognito to V3 + ::: SOLO TO DO ::: From c40a5a3d51c94dd5a736c79c20e4da4cfd7cfaf9 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Thu, 4 Jan 2024 13:39:54 -0800 Subject: [PATCH 094/700] 10007: WIP attempt to send confirmation email manually. --- .circleci/config.yml | 70 ++++----- .../useCases/users/signUpUserInteractor.ts | 68 --------- .../auth}/signUpUserInteractor.test.ts | 2 +- .../useCases/auth/signUpUserInteractor.ts | 135 ++++++++++++++++++ web-api/src/getUseCases.ts | 2 +- web-api/terraform/template/cognito.tf | 64 ++++----- 6 files changed, 204 insertions(+), 137 deletions(-) delete mode 100644 shared/src/business/useCases/users/signUpUserInteractor.ts rename {shared/src/business/useCases/users => web-api/src/business/useCases/auth}/signUpUserInteractor.test.ts (97%) create mode 100644 web-api/src/business/useCases/auth/signUpUserInteractor.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 164d3090f13..33a055d828e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -883,44 +883,44 @@ workflows: jobs: - deploy: <<: *only-deployed-lower-environments - - migrate: - <<: *only-deployed-lower-environments - requires: - - deploy - - wait-for-migration: - <<: *only-deployed-lower-environments - type: approval - requires: - - migrate - - prepare-for-reindex: - <<: *only-deployed-lower-environments - requires: - - wait-for-migration - - wait-for-reindex: - <<: *only-deployed-lower-environments - type: approval - requires: - - prepare-for-reindex - - disable-reindex-cron: - <<: *only-deployed-lower-environments - requires: - - wait-for-reindex - - smoketests: - <<: *only-deployed-lower-environments - requires: - - disable-reindex-cron - - loadtests: - <<: *only-deployed-lower-environments - requires: - - smoketests - - smoketests-readonly: - <<: *only-deployed-lower-environments - requires: - - loadtests + # - migrate: + # <<: *only-deployed-lower-environments + # requires: + # - deploy + # - wait-for-migration: + # <<: *only-deployed-lower-environments + # type: approval + # requires: + # - migrate + # - prepare-for-reindex: + # <<: *only-deployed-lower-environments + # requires: + # - wait-for-migration + # - wait-for-reindex: + # <<: *only-deployed-lower-environments + # type: approval + # requires: + # - prepare-for-reindex + # - disable-reindex-cron: + # <<: *only-deployed-lower-environments + # requires: + # - wait-for-reindex + # - smoketests: + # <<: *only-deployed-lower-environments + # requires: + # - disable-reindex-cron + # - loadtests: + # <<: *only-deployed-lower-environments + # requires: + # - smoketests + # - smoketests-readonly: + # <<: *only-deployed-lower-environments + # requires: + # - loadtests - switch-colors: <<: *only-deployed-lower-environments requires: - - smoketests-readonly + - deploy - delete-api-mappings: <<: *only-deployed-lower-environments requires: diff --git a/shared/src/business/useCases/users/signUpUserInteractor.ts b/shared/src/business/useCases/users/signUpUserInteractor.ts deleted file mode 100644 index effdd85ad33..00000000000 --- a/shared/src/business/useCases/users/signUpUserInteractor.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; -import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; - -export const signUpUserInteractor = async ( - applicationContext: IApplicationContext, - { - user, - }: { - user: { - password: string; - name: string; - email: string; - confirmPassword: string; - }; - }, -) => { - const existingUsers = await checkUserAlreadyExists( - applicationContext, - user.email, - ); - - if (existingUsers?.length) { - const accountUnconfirmed = existingUsers.some( - acct => acct.UserStatus === 'UNCONFIRMED', - ); - - const errorMessage = accountUnconfirmed - ? 'User exists, email unconfirmed' - : 'User already exists'; - - throw new Error(errorMessage); - } - - const newUser = new NewPetitionerUser(user).validate().toRawObject(); - - const cognito: CognitoIdentityProvider = applicationContext.getCognito(); - - return await cognito.signUp({ - ClientId: process.env.COGNITO_CLIENT_ID, - Password: newUser.password, - UserAttributes: [ - { - Name: 'email', - Value: newUser.email, - }, - { - Name: 'name', - Value: newUser.name, - }, - ], - Username: newUser.email, - }); -}; - -const checkUserAlreadyExists = async ( - applicationContext: IApplicationContext, - email: string, -) => { - const cognito: CognitoIdentityProvider = applicationContext.getCognito(); - - const inCognito = await cognito.listUsers({ - AttributesToGet: ['email'], - Filter: `email = "${email}"`, - UserPoolId: process.env.USER_POOL_ID, - }); - - return inCognito.Users; -}; diff --git a/shared/src/business/useCases/users/signUpUserInteractor.test.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.test.ts similarity index 97% rename from shared/src/business/useCases/users/signUpUserInteractor.test.ts rename to web-api/src/business/useCases/auth/signUpUserInteractor.test.ts index 45b5c98ac33..4bbe9467df3 100644 --- a/shared/src/business/useCases/users/signUpUserInteractor.test.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.test.ts @@ -1,4 +1,4 @@ -import { applicationContext } from '../../test/createTestApplicationContext'; +import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; import { signUpUserInteractor } from './signUpUserInteractor'; describe('signUpUserInteractor', () => { diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts new file mode 100644 index 00000000000..8098af67762 --- /dev/null +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -0,0 +1,135 @@ +import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; +import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; +import { ServerApplicationContext } from '@web-api/applicationContext'; +import { SES } from 'aws-sdk'; +import qs from 'qs'; + +export const signUpUserInteractor = async ( + applicationContext: ServerApplicationContext, + { + user, + }: { + user: { + password: string; + name: string; + email: string; + confirmPassword: string; + }; + }, +) => { + console.log('**** signUpUserInteractor'); + + const cognito: CognitoIdentityProvider = applicationContext.getCognito(); + + const { Users: existingAccounts } = await cognito.listUsers({ + AttributesToGet: ['email'], + Filter: `email = "${user.email}"`, + UserPoolId: process.env.USER_POOL_ID, + }); + + if (existingAccounts?.length) { + const accountUnconfirmed = existingAccounts.some( + acct => acct.UserStatus === 'UNCONFIRMED', + ); + + const errorMessage = accountUnconfirmed + ? 'User exists, email unconfirmed' + : 'User already exists'; + + throw new Error(errorMessage); + } + + const newUser = new NewPetitionerUser(user).validate().toRawObject(); + + await cognito.signUp({ + ClientId: process.env.COGNITO_CLIENT_ID, + Password: newUser.password, + UserAttributes: [ + { + Name: 'email', + Value: newUser.email, + }, + { + Name: 'name', + Value: newUser.name, + }, + ], + Username: newUser.email, + }); + + // generate a confirmation code + // What rules do we want to apply to a code? Right now, cognito generates a 6 digit code. Are we OK with that? + console.log( + '**** signUpUserInteractor, done signing up, about to send email', + ); + + const code = '123456'; + + // send confirmation email with code + await sendAccountCreationConfirmation({ + applicationContext, + email: newUser.email, + code, + }); + + console.log('**** signUpUserInteractor, done signing up, done sending email'); + + // return + + // Things to think about... + // 1. What happens if we need to resend the user's confirmation code??? +}; + +export const sendAccountCreationConfirmation = async ({ + applicationContext, + email, + code, +}) => { + console.log('**** sendAccountCreationConfirmation'); + + const queryString = qs.stringify({ code, email }, { encode: false }); + const verificationLink = `https://app.${process.env.EFCMS_DOMAIN}/confirm-signup?${queryString}`; + + const emailBody = + `Welcome to DAWSON! Your account with DAWSON has been created. Use the` + + ` button below to verify your email address.` + + `` + + `


If you did not create an account with DAWSON, please contact support at ` + + `dawson.support@ustaxcourt.gov.`; + + const SES: SES = applicationContext.getEmailClient(); + + console.log( + '**** sendAccountCreationConfirmation, about to send email to: ', + email, + ); + + return await SES.sendEmail({ + Destination: { + ToAddresses: [email], + }, + Message: { + Body: { + Html: { + Data: emailBody, + }, + }, + Subject: { + Data: 'U.S. Tax Court DAWSON Account Verification', + }, + }, + Source: process.env.EMAIL_SOURCE!, + }).promise(); +}; diff --git a/web-api/src/getUseCases.ts b/web-api/src/getUseCases.ts index c1cb9c00b23..a4b0e32d242 100644 --- a/web-api/src/getUseCases.ts +++ b/web-api/src/getUseCases.ts @@ -176,7 +176,7 @@ import { setNoticesForCalendaredTrialSessionInteractor } from '../../shared/src/ import { setTrialSessionCalendarInteractor } from '../../shared/src/business/useCases/trialSessions/setTrialSessionCalendarInteractor'; import { setUserEmailFromPendingEmailInteractor } from '../../shared/src/business/useCases/users/setUserEmailFromPendingEmailInteractor'; import { setWorkItemAsReadInteractor } from '../../shared/src/business/useCases/workitems/setWorkItemAsReadInteractor'; -import { signUpUserInteractor } from '../../shared/src/business/useCases/users/signUpUserInteractor'; +import { signUpUserInteractor } from './business/useCases/auth/signUpUserInteractor'; import { strikeDocketEntryInteractor } from '../../shared/src/business/useCases/docketEntry/strikeDocketEntryInteractor'; import { submitCaseAssociationRequestInteractor } from '../../shared/src/business/useCases/caseAssociationRequest/submitCaseAssociationRequestInteractor'; import { submitPendingCaseAssociationRequestInteractor } from '../../shared/src/business/useCases/caseAssociationRequest/submitPendingCaseAssociationRequestInteractor'; diff --git a/web-api/terraform/template/cognito.tf b/web-api/terraform/template/cognito.tf index 2337616d07f..31e5b4ef030 100644 --- a/web-api/terraform/template/cognito.tf +++ b/web-api/terraform/template/cognito.tf @@ -5,38 +5,38 @@ resource "aws_cognito_user_pool" "pool" { username_attributes = ["email"] - verification_message_template { - default_email_option = "CONFIRM_WITH_LINK" - email_message_by_link = < -

Welcome to DAWSON!

- -

Your account with DAWSON has been created. Use the button below to verify your email address.

- - {####} - - -

If you did not create an account with DAWSON, contact dawson.support@ustaxcourt.gov.

- -
- -

This is an automated email. We are unable to respond to any messages to this email address.

- - EMAILMESSAGE - email_subject_by_link = "U.S. Tax Court DAWSON Account Verification" - } + # verification_message_template { + # default_email_option = "CONFIRM_WITH_LINK" + # email_message_by_link = < + #

Welcome to DAWSON!

+ + #

Your account with DAWSON has been created. Use the button below to verify your email address.

+ + # {####} + # + + #

If you did not create an account with DAWSON, contact dawson.support@ustaxcourt.gov.

+ + #
+ + #

This is an automated email. We are unable to respond to any messages to this email address.

+ # + # EMAILMESSAGE + # email_subject_by_link = "U.S. Tax Court DAWSON Account Verification" + # } account_recovery_setting { recovery_mechanism { From cf49b7936af7d778c906815c3b74f11d4d6a67cd Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 4 Jan 2024 16:04:56 -0800 Subject: [PATCH 095/700] 10007: WIP store and generate our own confirmation code. --- .../useCases/auth/confirmSignUpInteractor.ts | 30 ++++++++++++----- .../useCases/auth/signUpUserInteractor.ts | 32 ++++++++----------- web-api/src/getPersistenceGateway.ts | 4 +++ web-api/src/persistence/dynamo/dynamoTypes.ts | 5 +++ .../users/generateAccountConfirmationCode.ts | 31 ++++++++++++++++++ .../users/getAccountConfirmationCode.ts | 24 ++++++++++++++ 6 files changed, 100 insertions(+), 26 deletions(-) create mode 100644 web-api/src/persistence/dynamo/users/generateAccountConfirmationCode.ts create mode 100644 web-api/src/persistence/dynamo/users/getAccountConfirmationCode.ts diff --git a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts index 959228ced5e..4335859dcda 100644 --- a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts +++ b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts @@ -2,14 +2,28 @@ import { ServerApplicationContext } from '@web-api/applicationContext'; export const confirmSignUpInteractor = async ( applicationContext: ServerApplicationContext, - { - confirmationCode, - userEmail, - }: { confirmationCode: string; userEmail: string }, + { confirmationCode, userId }: { confirmationCode: string; userId: string }, ) => { - return await applicationContext.getCognito().confirmSignUp({ - ClientId: process.env.COGNITO_CLIENT_ID, - ConfirmationCode: confirmationCode, - Username: userEmail, + const accountConfirmationRecord = await applicationContext + .getPersistenceGateway() + .getAccountConfirmationCode(applicationContext, { userId }); + if (accountConfirmationRecord.confirmationCode !== confirmationCode) { + throw new Error('confirmation code does not match'); + } + + const cognito = applicationContext.getCognito(); + const foundUsers = await cognito.listUsers({ + AttributesToGet: ['sub', 'username'], + Filter: `sub = "${userId}"`, + UserPoolId: process.env.USER_POOL_ID, + }); + const userName = foundUsers?.Users?.[0]?.Username; + if (!userName) { + throw new Error(`No user found in cognito with given ID: ${userId}`); + } + + await cognito.adminConfirmSignUp({ + Username: userName, + UserPoolId: process.env.USER_POOL_ID, }); }; diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 8098af67762..52ed37ac96d 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -41,7 +41,7 @@ export const signUpUserInteractor = async ( const newUser = new NewPetitionerUser(user).validate().toRawObject(); - await cognito.signUp({ + const result = await cognito.signUp({ ClientId: process.env.COGNITO_CLIENT_ID, Password: newUser.password, UserAttributes: [ @@ -57,34 +57,30 @@ export const signUpUserInteractor = async ( Username: newUser.email, }); + const userId = result.UserSub!; + // generate a confirmation code // What rules do we want to apply to a code? Right now, cognito generates a 6 digit code. Are we OK with that? console.log( '**** signUpUserInteractor, done signing up, about to send email', ); - const code = '123456'; + const { confirmationCode } = await applicationContext + .getPersistenceGateway() + .generateAccountConfirmationCode(applicationContext, { userId }); - // send confirmation email with code - await sendAccountCreationConfirmation({ - applicationContext, - email: newUser.email, - code, - }); + await sendAccountCreationConfirmation(applicationContext, { + email: newUser.email, + code: confirmationCode, + }); console.log('**** signUpUserInteractor, done signing up, done sending email'); - - // return - - // Things to think about... - // 1. What happens if we need to resend the user's confirmation code??? }; -export const sendAccountCreationConfirmation = async ({ - applicationContext, - email, - code, -}) => { +const sendAccountCreationConfirmation = async ( + applicationContext: ServerApplicationContext, + { email, code }: { email: string; code: string }, +) => { console.log('**** sendAccountCreationConfirmation'); const queryString = qs.stringify({ code, email }, { encode: false }); diff --git a/web-api/src/getPersistenceGateway.ts b/web-api/src/getPersistenceGateway.ts index bab3c2b71f4..fe27b1d21c5 100644 --- a/web-api/src/getPersistenceGateway.ts +++ b/web-api/src/getPersistenceGateway.ts @@ -50,6 +50,8 @@ import { deleteWorkItem } from './persistence/dynamo/workitems/deleteWorkItem'; import { editPractitionerDocument } from './persistence/dynamo/practitioners/editPractitionerDocument'; import { fetchEventCodesCountForJudges } from './persistence/elasticsearch/fetchEventCodesCountForJudges'; import { fetchPendingItems } from './persistence/elasticsearch/fetchPendingItems'; +import { generateAccountConfirmationCode } from '@web-api/persistence/dynamo/users/generateAccountConfirmationCode'; +import { getAccountConfirmationCode } from '@web-api/persistence/dynamo/users/getAccountConfirmationCode'; import { getAllPendingMotionDocketEntriesForJudge } from '@web-api/persistence/elasticsearch/docketEntry/getAllPendingMotionDocketEntriesForJudge'; import { getAllUsersByRole } from '@web-api/persistence/elasticsearch/users/getAllUsersByRole'; import { getAllWebSocketConnections } from './persistence/dynamo/notifications/getAllWebSocketConnections'; @@ -275,6 +277,8 @@ const gatewayMethods = { }), // methods below are not known to create or update "entity" records advancedDocumentSearch, + generateAccountConfirmationCode, + getAccountConfirmationCode, caseAdvancedSearch, casePublicSearch: casePublicSearchPersistence, createChangeOfAddressJob, diff --git a/web-api/src/persistence/dynamo/dynamoTypes.ts b/web-api/src/persistence/dynamo/dynamoTypes.ts index 536cc9369b9..be187d13c28 100644 --- a/web-api/src/persistence/dynamo/dynamoTypes.ts +++ b/web-api/src/persistence/dynamo/dynamoTypes.ts @@ -46,3 +46,8 @@ export type TrialSessionPaperPdfRecord = TDynamoRecord<{ fileId: string; title: string; }>; + +export type AccountConfirmationRecord = TDynamoRecord<{ + userId: string; + confirmationCode: string; +}>; diff --git a/web-api/src/persistence/dynamo/users/generateAccountConfirmationCode.ts b/web-api/src/persistence/dynamo/users/generateAccountConfirmationCode.ts new file mode 100644 index 00000000000..b0d2a6d82d8 --- /dev/null +++ b/web-api/src/persistence/dynamo/users/generateAccountConfirmationCode.ts @@ -0,0 +1,31 @@ +import { ServerApplicationContext } from '@web-api/applicationContext'; +import { put } from '../../dynamodbClientService'; +import { AccountConfirmationRecord } from '@web-api/persistence/dynamo/dynamoTypes'; + +export const generateAccountConfirmationCode = async ( + applicationContext: ServerApplicationContext, + { + userId, + }: { + userId: string; + }, +): Promise<{ confirmationCode: string }> => { + const confirmationCode = applicationContext.getUniqueId(); + const expireInOneDay = Date.now() / 1000 + 24 * 60 * 60; + const accountConfirmationRecord: AccountConfirmationRecord = { + pk: `user|${userId}`, + sk: `account-confirmation-code`, + confirmationCode, + userId, + ttl: expireInOneDay, + }; + + await put({ + Item: accountConfirmationRecord, + applicationContext, + }); + + return { + confirmationCode, + }; +}; diff --git a/web-api/src/persistence/dynamo/users/getAccountConfirmationCode.ts b/web-api/src/persistence/dynamo/users/getAccountConfirmationCode.ts new file mode 100644 index 00000000000..4df7bf7eb72 --- /dev/null +++ b/web-api/src/persistence/dynamo/users/getAccountConfirmationCode.ts @@ -0,0 +1,24 @@ +import { ServerApplicationContext } from '@web-api/applicationContext'; +import { get } from '../../dynamodbClientService'; +import { AccountConfirmationRecord } from '@web-api/persistence/dynamo/dynamoTypes'; + +export const getAccountConfirmationCode = async ( + applicationContext: ServerApplicationContext, + { + userId, + }: { + userId: string; + }, +): Promise<{ confirmationCode?: string }> => { + const result: AccountConfirmationRecord = await get({ + Key: { + pk: `user|${userId}`, + sk: `account-confirmation-code`, + }, + applicationContext, + }); + + return { + confirmationCode: result?.confirmationCode, + }; +}; From 01db5d430431bd9c51e35141569acd3cdd73ce6f Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 5 Jan 2024 08:29:55 -0800 Subject: [PATCH 096/700] 10007: WIP store and generate our own confirmation code. --- shared/src/proxies/auth/confirmSignUpProxy.ts | 6 ++-- shared/src/proxies/signUpUserProxy.ts | 3 +- .../useCases/auth/signUpUserInteractor.ts | 28 +++++++++++++++---- .../presenter/actions/confirmSignUpAction.ts | 6 ++-- .../actions/createConfirmLinkAction.ts | 5 ++-- .../actions/createNewPetitionerUserAction.ts | 22 +-------------- .../sequences/confirmSignUpSequence.ts | 2 +- web-client/src/router.ts | 4 +-- 8 files changed, 36 insertions(+), 40 deletions(-) diff --git a/shared/src/proxies/auth/confirmSignUpProxy.ts b/shared/src/proxies/auth/confirmSignUpProxy.ts index 9ffb768ccae..62f694dea8e 100644 --- a/shared/src/proxies/auth/confirmSignUpProxy.ts +++ b/shared/src/proxies/auth/confirmSignUpProxy.ts @@ -5,12 +5,12 @@ export const confirmSignUpInteractor = ( applicationContext: ClientApplicationContext, { confirmationCode, - userEmail, - }: { confirmationCode: string; userEmail: string }, + userId, + }: { confirmationCode: string; userId: string }, ) => { return post({ applicationContext, - body: { confirmationCode, userEmail }, + body: { confirmationCode, userId }, endpoint: '/confirm-signup', options: { withCredentials: false, diff --git a/shared/src/proxies/signUpUserProxy.ts b/shared/src/proxies/signUpUserProxy.ts index a3c8f21bc80..cca26e50b6d 100644 --- a/shared/src/proxies/signUpUserProxy.ts +++ b/shared/src/proxies/signUpUserProxy.ts @@ -1,10 +1,11 @@ import { type AdminCreateUserResponse } from 'aws-sdk/clients/cognitoidentityserviceprovider'; import { post } from './requests'; +import { SignUpUserResponse } from '@web-api/business/useCases/auth/signUpUserInteractor'; export const signUpUserInteractor = ( applicationContext, { user }, -): Promise => { +): Promise => { return post({ applicationContext, body: user, diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 52ed37ac96d..935358e08cc 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -4,6 +4,12 @@ import { ServerApplicationContext } from '@web-api/applicationContext'; import { SES } from 'aws-sdk'; import qs from 'qs'; +export type SignUpUserResponse = { + email: string; + userId: string; + confirmationCode: string; +}; + export const signUpUserInteractor = async ( applicationContext: ServerApplicationContext, { @@ -16,7 +22,7 @@ export const signUpUserInteractor = async ( confirmPassword: string; }; }, -) => { +): Promise => { console.log('**** signUpUserInteractor'); const cognito: CognitoIdentityProvider = applicationContext.getCognito(); @@ -63,18 +69,28 @@ export const signUpUserInteractor = async ( // What rules do we want to apply to a code? Right now, cognito generates a 6 digit code. Are we OK with that? console.log( '**** signUpUserInteractor, done signing up, about to send email', + userId, ); const { confirmationCode } = await applicationContext .getPersistenceGateway() .generateAccountConfirmationCode(applicationContext, { userId }); - await sendAccountCreationConfirmation(applicationContext, { - email: newUser.email, - code: confirmationCode, - }); + // await sendAccountCreationConfirmation(applicationContext, { + // email: newUser.email, + // code: confirmationCode, + // }); - console.log('**** signUpUserInteractor, done signing up, done sending email'); + console.log( + '**** signUpUserInteractor, done signing up, done sending email', + confirmationCode, + ); + // TODO 10007: Only return confirmationCode locally as we cannot send an email. If we always return it then we cannot be sure we confirmed their email. + return { + email: user.email, + userId, + confirmationCode, + }; }; const sendAccountCreationConfirmation = async ( diff --git a/web-client/src/presenter/actions/confirmSignUpAction.ts b/web-client/src/presenter/actions/confirmSignUpAction.ts index 3bd1d1ee6ed..033230f4a91 100644 --- a/web-client/src/presenter/actions/confirmSignUpAction.ts +++ b/web-client/src/presenter/actions/confirmSignUpAction.ts @@ -2,15 +2,15 @@ export const confirmSignUpAction = async ({ applicationContext, path, props, -}: ActionProps<{ confirmationCode: string; userEmail: string }>) => { - const { confirmationCode, userEmail } = props; +}: ActionProps<{ confirmationCode: string; userId: string }>) => { + const { confirmationCode, userId } = props; try { await applicationContext .getUseCases() .confirmSignUpInteractor(applicationContext, { confirmationCode, - userEmail, + userId, }); // 10007 TODO: make path.success diff --git a/web-client/src/presenter/actions/createConfirmLinkAction.ts b/web-client/src/presenter/actions/createConfirmLinkAction.ts index 66760a2b812..07057d74728 100644 --- a/web-client/src/presenter/actions/createConfirmLinkAction.ts +++ b/web-client/src/presenter/actions/createConfirmLinkAction.ts @@ -3,13 +3,12 @@ import qs from 'qs'; export const createConfirmLinkAction = ({ props }: ActionProps) => { if (!process.env.IS_LOCAL) return; - const { email } = props; + const { userId, confirmationCode, email } = props; // confirmation code is currently intentionally hard-coded in cognitoLocal // ^^ it is not, have to set process.env.CODE - const confirmationCode = 'COGNITO_LOCAL_CONFIRMATION_CODE'; const queryString = qs.stringify( - { confirmationCode, email }, + { confirmationCode, userId }, { encode: false }, ); diff --git a/web-client/src/presenter/actions/createNewPetitionerUserAction.ts b/web-client/src/presenter/actions/createNewPetitionerUserAction.ts index a00ab01161a..4f4e735255e 100644 --- a/web-client/src/presenter/actions/createNewPetitionerUserAction.ts +++ b/web-client/src/presenter/actions/createNewPetitionerUserAction.ts @@ -6,6 +6,7 @@ export const createNewPetitionerUserAction = async ({ get, path, }: ActionProps) => { + // TODO 10007: Do we need to be parsing results like this? Should we be looking directly at the cognito results? if (!new NewPetitionerUser(get(state.form)).isValid()) { throw new Error('Received invalid petitioner information'); } @@ -23,9 +24,6 @@ export const createNewPetitionerUserAction = async ({ .signUpUserInteractor(applicationContext, { user: petitionerAccountForm, }) - .then(authenticationResults => - responseHandler(authenticationResults, petitionerAccountForm.email), - ) .catch(e => errorHandler(e, cognitoRequestPasswordResetUrl)); if (response.alertError) { @@ -62,21 +60,3 @@ const errorHandler = (e, cognitoRequestPasswordResetUrl) => { }, }; }; - -const responseHandler = ( - authenticationResults, - email, -): { alertError?: object; email?: string } => { - if (Object.keys(authenticationResults).includes('UserConfirmed')) { - return { - email, - }; - } - return { - alertError: { - message: - 'Could not parse authentication results, please contact DAWSON user support', - title: 'Error creating account', - }, - }; -}; diff --git a/web-client/src/presenter/sequences/confirmSignUpSequence.ts b/web-client/src/presenter/sequences/confirmSignUpSequence.ts index 12527293ea1..b1225bab018 100644 --- a/web-client/src/presenter/sequences/confirmSignUpSequence.ts +++ b/web-client/src/presenter/sequences/confirmSignUpSequence.ts @@ -11,4 +11,4 @@ export const confirmSignUpSequence = [ yes: [setAlertSuccessAction], }, navigateToLoginSequence, -]; +] as unknown as (props: {confirmationCode: string; userId: string}) => {}; diff --git a/web-client/src/router.ts b/web-client/src/router.ts index b211b23f890..076efd4fc19 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -836,10 +836,10 @@ const router = { ); registerRoute('/confirm-signup?..', () => { - const { confirmationCode, email } = route.query(); + const { confirmationCode, userId } = route.query(); return app.getSequence('confirmSignUpSequence')({ confirmationCode, - userEmail: email, + userId, }); }); From c866dfae36aad3f30b44290c9f3fbac5dda240c0 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Fri, 5 Jan 2024 11:11:17 -0700 Subject: [PATCH 097/700] 10007: WIP send an email on when creating an account. --- setup-local-env.sh | 1 + web-api/src/applicationContext.ts | 7 +++++++ .../useCases/auth/signUpUserInteractor.ts | 15 +++++++++------ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/setup-local-env.sh b/setup-local-env.sh index 80d5d2ca42d..a2dd6dd1564 100755 --- a/setup-local-env.sh +++ b/setup-local-env.sh @@ -19,3 +19,4 @@ export ELASTICSEARCH_ENDPOINT=http://localhost:9200 export IRS_SUPERUSER_EMAIL=irs-superuser@example.com export USER_POOL_ID='local_2pHzece7' export COGNITO_CLIENT_ID='bvjrggnd3co403c0aahscinne' +export DISABLE_EMAILS=true diff --git a/web-api/src/applicationContext.ts b/web-api/src/applicationContext.ts index 3927118fbe7..27e95097f55 100644 --- a/web-api/src/applicationContext.ts +++ b/web-api/src/applicationContext.ts @@ -225,6 +225,13 @@ export const createApplicationContext = ( }, }; }, + sendEmail: () => { + return { + promise: (): SES.SendEmailResponse => { + return { MessageId: '' }; + }, + }; + }, }; } else { if (!sesCache) { diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 935358e08cc..a7416f23dfa 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -76,10 +76,10 @@ export const signUpUserInteractor = async ( .getPersistenceGateway() .generateAccountConfirmationCode(applicationContext, { userId }); - // await sendAccountCreationConfirmation(applicationContext, { - // email: newUser.email, - // code: confirmationCode, - // }); + await sendAccountCreationConfirmation(applicationContext, { + email: newUser.email, + confirmationCode, + }); console.log( '**** signUpUserInteractor, done signing up, done sending email', @@ -95,11 +95,14 @@ export const signUpUserInteractor = async ( const sendAccountCreationConfirmation = async ( applicationContext: ServerApplicationContext, - { email, code }: { email: string; code: string }, + { email, confirmationCode }: { email: string; confirmationCode: string }, ) => { console.log('**** sendAccountCreationConfirmation'); - const queryString = qs.stringify({ code, email }, { encode: false }); + const queryString = qs.stringify( + { confirmationCode, email }, + { encode: false }, + ); const verificationLink = `https://app.${process.env.EFCMS_DOMAIN}/confirm-signup?${queryString}`; const emailBody = From f6619e19cfa1989ab27ac17c5a624246e73fea91 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Fri, 5 Jan 2024 12:16:11 -0700 Subject: [PATCH 098/700] 10007: Extract AWS Import --- web-api/src/applicationContext.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web-api/src/applicationContext.ts b/web-api/src/applicationContext.ts index 27e95097f55..d66bfe8a375 100644 --- a/web-api/src/applicationContext.ts +++ b/web-api/src/applicationContext.ts @@ -62,14 +62,12 @@ import { sendSetTrialSessionCalendarEvent } from './persistence/messages/sendSet import { sendSlackNotification } from './dispatchers/slack/sendSlackNotification'; import { sendUpdatePetitionerCasesMessage } from './persistence/messages/sendUpdatePetitionerCasesMessage'; import { updatePetitionerCasesInteractor } from '../../shared/src/business/useCases/users/updatePetitionerCasesInteractor'; -import AWS from 'aws-sdk'; +import AWS, { S3, SES, SQS } from 'aws-sdk'; import axios from 'axios'; import pug from 'pug'; import sass from 'sass'; import util from 'util'; -const { S3, SES, SQS } = AWS; - const execPromise = util.promisify(exec); const environment = { From d67ce94cc95b32d1c2a7b1f6a421bc3c01d9018e Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Fri, 5 Jan 2024 12:44:51 -0700 Subject: [PATCH 099/700] 10007: Fix unit tests --- temp_delete_me.md | 5 +- .../getMaintenanceModeAction.test.ts | 31 ++------- web-client/src/router.test.ts | 66 +------------------ 3 files changed, 9 insertions(+), 93 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 69301c156e9..87fe9b47f2c 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -12,17 +12,18 @@ - ensure back works right (public to private and back) - fix tests + email verification flow (just after verifying, are we going to new login with verification success message) -- create account (move to private - client site) - Refactor ifHasAccess Function to be handled by router + initSequence - Refactor maintenance mode to be handled by router + initSequence. No other sequence needs to branch because of it. - invalidate old refreshToken and idToken upon refresh. - Ensure idToken lasts longer than how often we are refreshing the idToken (REFRESH_INTERVAL) - We need to handle temporary password changes on login screen. This happens when cognito forces a password update. +- disable cognito emails. +- resend confirmation code. ::: SOLO TO DO ::: - +- create account (move to private - client site) ::: ON HOLD ::: - In refreshAuthTokenInteractor we are returning the idToken. Should this be an accessToken? Are all of our requests being authed with an idToken? diff --git a/web-client/src/presenter/actions/Maintenance/getMaintenanceModeAction.test.ts b/web-client/src/presenter/actions/Maintenance/getMaintenanceModeAction.test.ts index 1d0802d205a..9c0f6064841 100644 --- a/web-client/src/presenter/actions/Maintenance/getMaintenanceModeAction.test.ts +++ b/web-client/src/presenter/actions/Maintenance/getMaintenanceModeAction.test.ts @@ -4,14 +4,6 @@ import { presenter } from '../../presenter-mock'; import { runAction } from '@web-client/presenter/test.cerebral'; describe('getMaintenanceModeAction', () => { - const pathMaintenanceOnStub = jest.fn(); - const pathMaintenanceOffStub = jest.fn(); - - presenter.providers.path = { - maintenanceOff: pathMaintenanceOffStub, - maintenanceOn: pathMaintenanceOnStub, - }; - beforeAll(() => { presenter.providers.applicationContext = applicationContext; @@ -20,21 +12,8 @@ describe('getMaintenanceModeAction', () => { .getMaintenanceModeInteractor.mockReturnValue(true); }); - it('should set maintenanceMode on state when it is null', async () => { + it('should return true when maintenance mode is turned on', async () => { const result = await runAction(getMaintenanceModeAction, { - modules: { - presenter, - }, - state: { - maintenanceMode: null, - }, - }); - - expect(result.state.maintenanceMode).toEqual(true); - }); - - it('returns path.maintenanceOn if maintenance mode is turned on', async () => { - await runAction(getMaintenanceModeAction, { modules: { presenter, }, @@ -43,15 +22,15 @@ describe('getMaintenanceModeAction', () => { }, }); - expect(pathMaintenanceOnStub).toHaveBeenCalled(); + expect(result.output.maintenanceMode).toEqual(true); }); - it('returns path.maintenanceOff if maintenance mode is turned off', async () => { + it('should return false when maintenance mode is turned off', async () => { applicationContext .getUseCases() .getMaintenanceModeInteractor.mockReturnValue(false); - await runAction(getMaintenanceModeAction, { + const result = await runAction(getMaintenanceModeAction, { modules: { presenter, }, @@ -60,6 +39,6 @@ describe('getMaintenanceModeAction', () => { }, }); - expect(pathMaintenanceOffStub).toHaveBeenCalled(); + expect(result.output.maintenanceMode).toEqual(false); }); }); diff --git a/web-client/src/router.test.ts b/web-client/src/router.test.ts index 7038112c5de..24de635d6b1 100644 --- a/web-client/src/router.test.ts +++ b/web-client/src/router.test.ts @@ -1,5 +1,5 @@ import { ROLE_PERMISSIONS } from '@shared/authorization/authorizationClientService'; -import { ifHasAccess, route, router } from '@web-client/router'; +import { route, router } from '@web-client/router'; describe('router', () => { const getUserMock = jest.fn(); @@ -7,12 +7,6 @@ describe('router', () => { const getPermissionsMock = jest.fn().mockReturnValue({ foo: true }); const sequenceMock = jest.fn().mockReturnValue('Yay'); const getSequenceMock = jest.fn().mockReturnValue(sequenceMock); - const callbackFn = jest.fn(); - const redirect = { - goto404: jest.fn(), - gotoLoginPage: jest.fn(), - gotoMaintenancePage: jest.fn(), - }; const stateMock = jest.fn(); const appMock = { @@ -35,64 +29,6 @@ describe('router', () => { }, }; - describe('ifHasAccess function generator', () => { - it('redirects to login page if user is not defined', () => { - getUserMock.mockReturnValue(undefined); - ifHasAccess({ app: appMock, redirect }, callbackFn)(); - expect(redirect.goto404).not.toHaveBeenCalled(); - expect(redirect.gotoMaintenancePage).not.toHaveBeenCalled(); - expect(callbackFn).not.toHaveBeenCalled(); - expect(redirect.gotoLoginPage).toHaveBeenCalled(); - }); - - it('redirects to maintenance page if maintenanceMode is true', () => { - getUserMock.mockReturnValue({ username: 'Karl Childers' }); - getMaintenanceModeMock.mockReturnValue(true); - - ifHasAccess({ app: appMock, redirect }, callbackFn)(); - expect(redirect.goto404).not.toHaveBeenCalled(); - expect(callbackFn).not.toHaveBeenCalled(); - expect(redirect.gotoMaintenancePage).toHaveBeenCalled(); - }); - - it('redirects to 404 if user does not have the correct permissions', () => { - getUserMock.mockReturnValue({ username: 'Karl Childers' }); - getMaintenanceModeMock.mockReturnValue(false); - stateMock.mockReturnValue({ permissions: undefined }); - ifHasAccess( - { - app: appMock, - permissionToCheck: ROLE_PERMISSIONS.ADVANCED_SEARCH, - redirect, - }, - callbackFn, - )(); - expect(redirect.gotoLoginPage).not.toHaveBeenCalled(); - expect(redirect.gotoMaintenancePage).not.toHaveBeenCalled(); - expect(callbackFn).not.toHaveBeenCalled(); - expect(redirect.goto404).toHaveBeenCalled(); - }); - - it('runs the callback function argument if user has correct permissions', () => { - getPermissionsMock.mockReturnValue({ - [ROLE_PERMISSIONS.ADVANCED_SEARCH]: true, - }); - - ifHasAccess( - { - app: appMock, - permissionToCheck: ROLE_PERMISSIONS.ADVANCED_SEARCH, - redirect, - }, - callbackFn, - )(); - expect(redirect.gotoLoginPage).not.toHaveBeenCalled(); - expect(redirect.gotoMaintenancePage).not.toHaveBeenCalled(); - expect(redirect.goto404).not.toHaveBeenCalled(); - expect(callbackFn).toHaveBeenCalled(); - }); - }); - describe('router function', () => { beforeAll(() => { getUserMock.mockReturnValue({ user: 'Samwise Gamgee' }); From a9cfa777a3a3e3a41bddd4fbd9933052e05d817d Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Fri, 5 Jan 2024 15:52:09 -0700 Subject: [PATCH 100/700] 10007: Update redirect link --- .../environment-specific/main/lambda.tf | 3 +- .../useCases/auth/signUpUserInteractor.ts | 55 +++++++++++-------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/iam/terraform/environment-specific/main/lambda.tf b/iam/terraform/environment-specific/main/lambda.tf index 584977ffda7..47e8e295709 100644 --- a/iam/terraform/environment-specific/main/lambda.tf +++ b/iam/terraform/environment-specific/main/lambda.tf @@ -133,7 +133,8 @@ resource "aws_iam_role_policy" "lambda_policy" { }, { "Action": [ - "ses:SendBulkTemplatedEmail" + "ses:SendBulkTemplatedEmail", + "ses:SendEmail" ], "Resource": [ "arn:aws:ses:us-east-1:${data.aws_caller_identity.current.account_id}:identity/noreply@${var.dns_domain}" diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index a7416f23dfa..bd7bc14f019 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -1,7 +1,7 @@ import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; -import { ServerApplicationContext } from '@web-api/applicationContext'; import { SES } from 'aws-sdk'; +import { ServerApplicationContext } from '@web-api/applicationContext'; import qs from 'qs'; export type SignUpUserResponse = { @@ -77,8 +77,9 @@ export const signUpUserInteractor = async ( .generateAccountConfirmationCode(applicationContext, { userId }); await sendAccountCreationConfirmation(applicationContext, { - email: newUser.email, confirmationCode, + email: newUser.email, + userId, }); console.log( @@ -87,27 +88,31 @@ export const signUpUserInteractor = async ( ); // TODO 10007: Only return confirmationCode locally as we cannot send an email. If we always return it then we cannot be sure we confirmed their email. return { + confirmationCode, email: user.email, userId, - confirmationCode, }; }; const sendAccountCreationConfirmation = async ( applicationContext: ServerApplicationContext, - { email, confirmationCode }: { email: string; confirmationCode: string }, + { + confirmationCode, + email, + userId, + }: { email: string; confirmationCode: string; userId: string }, ) => { console.log('**** sendAccountCreationConfirmation'); const queryString = qs.stringify( - { confirmationCode, email }, + { confirmationCode, userId }, { encode: false }, ); const verificationLink = `https://app.${process.env.EFCMS_DOMAIN}/confirm-signup?${queryString}`; const emailBody = - `Welcome to DAWSON! Your account with DAWSON has been created. Use the` + - ` button below to verify your email address.` + + 'Welcome to DAWSON! Your account with DAWSON has been created. Use the' + + ' button below to verify your email address.' + `` + - `


If you did not create an account with DAWSON, please contact support at ` + - `dawson.support@ustaxcourt.gov.`; + '


If you did not create an account with DAWSON, please contact support at ' + + 'dawson.support@ustaxcourt.gov.'; - const SES: SES = applicationContext.getEmailClient(); + const emailClient: SES = applicationContext.getEmailClient(); console.log( '**** sendAccountCreationConfirmation, about to send email to: ', email, ); - return await SES.sendEmail({ - Destination: { - ToAddresses: [email], - }, - Message: { - Body: { - Html: { - Data: emailBody, - }, + return await emailClient + .sendEmail({ + Destination: { + ToAddresses: [email], }, - Subject: { - Data: 'U.S. Tax Court DAWSON Account Verification', + Message: { + Body: { + Html: { + Data: emailBody, + }, + }, + Subject: { + Data: 'U.S. Tax Court DAWSON Account Verification', + }, }, - }, - Source: process.env.EMAIL_SOURCE!, - }).promise(); + Source: process.env.EMAIL_SOURCE!, + }) + .promise(); }; From 98a9c06d2e299446672f965db99634ee0d36ba46 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 8 Jan 2024 09:02:34 -0800 Subject: [PATCH 101/700] 10007: docs --- .../template/lambdas/createAuthorizer.ts | 164 ++++++++++-------- 1 file changed, 95 insertions(+), 69 deletions(-) diff --git a/web-api/terraform/template/lambdas/createAuthorizer.ts b/web-api/terraform/template/lambdas/createAuthorizer.ts index 3d7c1b4daba..abd760ff493 100644 --- a/web-api/terraform/template/lambdas/createAuthorizer.ts +++ b/web-api/terraform/template/lambdas/createAuthorizer.ts @@ -1,3 +1,7 @@ +import { + APIGatewayAuthorizerResult, + APIGatewayRequestAuthorizerEvent, +} from 'aws-lambda'; import { createLogger } from '../../../src/createLogger'; import { transports } from 'winston'; import axios from 'axios'; @@ -61,71 +65,99 @@ const throw401GatewayError = () => { throw new Error('Unauthorized'); }; -export const createAuthorizer = getToken => async (event, context) => { - const logger = getLogger(context); - - let token; - try { - token = getToken(event); - } catch (error) { - logger.info('An error occured trying to get the token out of the event'); - throw401GatewayError(); - } - - if (!token) { - logger.info('No authorizationToken found in the header'); - throw401GatewayError(); - } - - let iss, kid; - - try { - const decodedToken = decodeToken(token); - ({ iss, kid } = decodedToken); - } catch (error) { - logger.info( - 'The token provided in the header could not be decoded successfully', - ); - throw401GatewayError(); - } - - let keys; - try { - keys = await getKeysForIssuer(iss); - } catch (error) { - logger.warn( - 'Could not fetch keys for token issuer, considering request unauthorized', - error, +export const createAuthorizer = + getToken => async (event: APIGatewayRequestAuthorizerEvent, context) => { + const logger = getLogger(context); + + const unauthorizedPathAllowlist = [ + 'maintenance-mode', + 'auth/login', + 'feature-flag', + 'confirm-signup', + ]; + + if (unauthorizedPathAllowlist.includes(event.path)) { + return createAllowPolicy(event, 'unauthenticated'); + } + + let token; + try { + token = getToken(event); + } catch (error) { + logger.info('An error occured trying to get the token out of the event'); + throw401GatewayError(); + } + + if (!token) { + logger.info('No authorizationToken found in the header'); + throw401GatewayError(); + } + + let iss, kid; + + try { + const decodedToken = decodeToken(token); + ({ iss, kid } = decodedToken); + } catch (error) { + logger.info( + 'The token provided in the header could not be decoded successfully', + ); + throw401GatewayError(); + } + + let keys; + try { + keys = await getKeysForIssuer(iss); + } catch (error) { + logger.warn( + 'Could not fetch keys for token issuer, considering request unauthorized', + error, + ); + throw401GatewayError(); + } + + const key = keys.find(k => k.kid === kid); + + if (!key) { + logger.warn( + 'The key used to sign the authorization token was not found in the user pool’s keys, considering request unauthorized', + { + issuer: iss, + keys, + requestedKeyId: kid, + }, + ); + throw401GatewayError(); + } + + let payload; + try { + payload = await verify(key, token); + } catch (error) { + logger.warn( + 'The token is not valid, considering request unauthorized', + error, + ); + throw401GatewayError(); + } + + const allowPolicy = createAllowPolicy( + event, + payload['custom:userId'] || payload.sub, ); - throw401GatewayError(); - } - const key = keys.find(k => k.kid === kid); - - if (!key) { - logger.warn( - 'The key used to sign the authorization token was not found in the user pool’s keys, considering request unauthorized', - { - issuer: iss, - keys, - requestedKeyId: kid, - }, - ); - throw401GatewayError(); - } + logger.info('Request authorized', { + metadata: { policy: allowPolicy }, + }); - let payload; - try { - payload = await verify(key, token); - } catch (error) { - logger.warn( - 'The token is not valid, considering request unauthorized', - error, - ); - throw401GatewayError(); - } + return allowPolicy; + }; - const policy = { +function createAllowPolicy( + event: APIGatewayRequestAuthorizerEvent, + principalId: string, +): APIGatewayAuthorizerResult { + return { policyDocument: { Statement: [ { @@ -136,12 +168,6 @@ export const createAuthorizer = getToken => async (event, context) => { ], Version: '2012-10-17', }, - principalId: payload['custom:userId'] || payload.sub, + principalId, }; - - logger.info('Request authorized', { - metadata: { policy }, - }); - - return policy; -}; +} From 56c9835295b20fb56c90ed879fbbe5025fd5982a Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 8 Jan 2024 09:39:05 -0800 Subject: [PATCH 102/700] 10007: Exact match paths that can be allowed without token --- web-api/terraform/template/lambdas/createAuthorizer.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web-api/terraform/template/lambdas/createAuthorizer.ts b/web-api/terraform/template/lambdas/createAuthorizer.ts index abd760ff493..86dcc374bcd 100644 --- a/web-api/terraform/template/lambdas/createAuthorizer.ts +++ b/web-api/terraform/template/lambdas/createAuthorizer.ts @@ -70,10 +70,10 @@ export const createAuthorizer = const logger = getLogger(context); const unauthorizedPathAllowlist = [ - 'maintenance-mode', - 'auth/login', - 'feature-flag', - 'confirm-signup', + '/maintenance-mode', + '/auth/login', + '/feature-flag', + '/confirm-signup', ]; if (unauthorizedPathAllowlist.includes(event.path)) { From d002212f939c847c710fd59ff7baa7ef3dfa64f1 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 8 Jan 2024 13:15:53 -0800 Subject: [PATCH 103/700] 10007: Remove attempt to passthrough authorizer for certain routes, deploy infrastructure for maintenance-mode so it does not go through authorizer --- web-api/terraform/api/api.tf | 28 +++++++++++++++++++ .../template/lambdas/createAuthorizer.ts | 11 -------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/web-api/terraform/api/api.tf b/web-api/terraform/api/api.tf index 0f4aa670cdf..b3965604205 100644 --- a/web-api/terraform/api/api.tf +++ b/web-api/terraform/api/api.tf @@ -141,6 +141,34 @@ resource "aws_api_gateway_method" "api_method_head" { authorizer_id = aws_api_gateway_authorizer.custom_authorizer.id } +# +resource "aws_api_gateway_resource" "api_maintenance_mode_resource" { + rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id + parent_id = aws_api_gateway_rest_api.gateway_for_api.root_resource_id + path_part = "maintenance-mode" +} + +resource "aws_api_gateway_method" "api_maintenance_mode_method_any" { + rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id + resource_id = aws_api_gateway_resource.api_auth_resource.id + http_method = "ANY" + authorization = "NONE" +} + +resource "aws_api_gateway_integration" "api_integration_maintenance_mode" { + depends_on = [ + aws_api_gateway_integration.api_integration_options + ] + rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id + resource_id = aws_api_gateway_method.api_maintenance_mode_resource.resource_id + http_method = aws_api_gateway_method.api_maintenance_mode_method_any.http_method + + integration_http_method = "ANY" + type = "AWS_PROXY" + uri = aws_lambda_function.api_lambda.invoke_arn +} +# + resource "aws_api_gateway_authorizer" "custom_authorizer" { name = "custom_authorizer_${var.environment}_${var.current_color}" rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id diff --git a/web-api/terraform/template/lambdas/createAuthorizer.ts b/web-api/terraform/template/lambdas/createAuthorizer.ts index 86dcc374bcd..591ac0d0b34 100644 --- a/web-api/terraform/template/lambdas/createAuthorizer.ts +++ b/web-api/terraform/template/lambdas/createAuthorizer.ts @@ -69,17 +69,6 @@ export const createAuthorizer = getToken => async (event: APIGatewayRequestAuthorizerEvent, context) => { const logger = getLogger(context); - const unauthorizedPathAllowlist = [ - '/maintenance-mode', - '/auth/login', - '/feature-flag', - '/confirm-signup', - ]; - - if (unauthorizedPathAllowlist.includes(event.path)) { - return createAllowPolicy(event, 'unauthenticated'); - } - let token; try { token = getToken(event); From 2b2beed9e99792cc4324e90c99a54ebb75119c1d Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 8 Jan 2024 13:19:16 -0800 Subject: [PATCH 104/700] 10007: set integration http method to POST --- web-api/terraform/api/api.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-api/terraform/api/api.tf b/web-api/terraform/api/api.tf index b3965604205..d4087d90c3d 100644 --- a/web-api/terraform/api/api.tf +++ b/web-api/terraform/api/api.tf @@ -163,7 +163,7 @@ resource "aws_api_gateway_integration" "api_integration_maintenance_mode" { resource_id = aws_api_gateway_method.api_maintenance_mode_resource.resource_id http_method = aws_api_gateway_method.api_maintenance_mode_method_any.http_method - integration_http_method = "ANY" + integration_http_method = "POST" type = "AWS_PROXY" uri = aws_lambda_function.api_lambda.invoke_arn } From 33c606d01d130aaf0b1e04150b7a68b8b89baafb Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 8 Jan 2024 13:26:30 -0800 Subject: [PATCH 105/700] 10007: update resource --- web-api/terraform/api/api.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web-api/terraform/api/api.tf b/web-api/terraform/api/api.tf index d4087d90c3d..065ab8af6d3 100644 --- a/web-api/terraform/api/api.tf +++ b/web-api/terraform/api/api.tf @@ -150,7 +150,7 @@ resource "aws_api_gateway_resource" "api_maintenance_mode_resource" { resource "aws_api_gateway_method" "api_maintenance_mode_method_any" { rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id - resource_id = aws_api_gateway_resource.api_auth_resource.id + resource_id = aws_api_gateway_resource.api_maintenance_mode_resource.id http_method = "ANY" authorization = "NONE" } @@ -160,7 +160,7 @@ resource "aws_api_gateway_integration" "api_integration_maintenance_mode" { aws_api_gateway_integration.api_integration_options ] rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id - resource_id = aws_api_gateway_method.api_maintenance_mode_resource.resource_id + resource_id = aws_api_gateway_resource.api_maintenance_mode_resource.id http_method = aws_api_gateway_method.api_maintenance_mode_method_any.http_method integration_http_method = "POST" From b066d6309f7d5769cf2d239fd6e646aeb8ce7287 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 8 Jan 2024 14:36:56 -0800 Subject: [PATCH 106/700] 10007: WIP add system to root route --- shared/src/proxies/auth/confirmSignUpProxy.ts | 7 ++----- .../featureFlag/getAllFeatureFlagsProxy.ts | 2 +- .../maintenance/getMaintenanceModeProxy.ts | 2 +- web-api/src/app-public.ts | 2 -- web-api/src/app.ts | 15 ++++---------- web-api/terraform/api/api.tf | 20 ++++++++++++------- 6 files changed, 21 insertions(+), 27 deletions(-) diff --git a/shared/src/proxies/auth/confirmSignUpProxy.ts b/shared/src/proxies/auth/confirmSignUpProxy.ts index 62f694dea8e..6c0fe8ee215 100644 --- a/shared/src/proxies/auth/confirmSignUpProxy.ts +++ b/shared/src/proxies/auth/confirmSignUpProxy.ts @@ -3,15 +3,12 @@ import { post } from '../requests'; export const confirmSignUpInteractor = ( applicationContext: ClientApplicationContext, - { - confirmationCode, - userId, - }: { confirmationCode: string; userId: string }, + { confirmationCode, userId }: { confirmationCode: string; userId: string }, ) => { return post({ applicationContext, body: { confirmationCode, userId }, - endpoint: '/confirm-signup', + endpoint: '/auth/confirm-signup', options: { withCredentials: false, }, diff --git a/shared/src/proxies/featureFlag/getAllFeatureFlagsProxy.ts b/shared/src/proxies/featureFlag/getAllFeatureFlagsProxy.ts index 5f8c884bfbc..7e68b9461a8 100644 --- a/shared/src/proxies/featureFlag/getAllFeatureFlagsProxy.ts +++ b/shared/src/proxies/featureFlag/getAllFeatureFlagsProxy.ts @@ -11,7 +11,7 @@ import { get } from '../requests'; export const getAllFeatureFlagsInteractor = applicationContext => { return get({ applicationContext, - endpoint: '/feature-flag/', + endpoint: '/system/feature-flag/', params: {}, }); }; diff --git a/shared/src/proxies/maintenance/getMaintenanceModeProxy.ts b/shared/src/proxies/maintenance/getMaintenanceModeProxy.ts index b1b6a26eeca..babbd439f90 100644 --- a/shared/src/proxies/maintenance/getMaintenanceModeProxy.ts +++ b/shared/src/proxies/maintenance/getMaintenanceModeProxy.ts @@ -10,6 +10,6 @@ import { get } from '../requests'; export const getMaintenanceModeInteractor = applicationContext => { return get({ applicationContext, - endpoint: '/maintenance-mode', + endpoint: '/system/maintenance-mode', }); }; diff --git a/web-api/src/app-public.ts b/web-api/src/app-public.ts index 14d164e31c1..b2cf495e374 100644 --- a/web-api/src/app-public.ts +++ b/web-api/src/app-public.ts @@ -52,7 +52,6 @@ app.use(logger()); import { advancedQueryLimiter } from './middleware/advancedQueryLimiter'; import { casePublicSearchLambda } from './lambdas/public-api/casePublicSearchLambda'; -import { confirmSignUpLambda } from '@web-api/lambdas/auth/confirmSignUpLambda'; import { generatePublicDocketRecordPdfLambda } from './lambdas/public-api/generatePublicDocketRecordPdfLambda'; import { getAllFeatureFlagsLambda } from './lambdas/featureFlag/getAllFeatureFlagsLambda'; import { getCachedHealthCheckLambda } from '@web-api/lambdas/health/getCachedHealthCheckLambda'; @@ -168,5 +167,4 @@ app.get('/public-api/judges', lambdaWrapper(getPublicJudgesLambda)); '/account/resend-verification', lambdaWrapper(resendVerificationLinkLambda), ); - app.post('/confirm-signup', lambdaWrapper(confirmSignUpLambda)); } diff --git a/web-api/src/app.ts b/web-api/src/app.ts index b8e272d4a11..a5f91effea3 100644 --- a/web-api/src/app.ts +++ b/web-api/src/app.ts @@ -1007,17 +1007,11 @@ app.get( } /** - * maintenance-mode + * system */ { - app.get('/maintenance-mode', lambdaWrapper(getMaintenanceModeLambda)); -} - -/** - * feature-flag - */ -{ - app.get('/feature-flag', lambdaWrapper(getAllFeatureFlagsLambda)); + app.get('/system/maintenance-mode', lambdaWrapper(getMaintenanceModeLambda)); + app.get('/system/feature-flag', lambdaWrapper(getAllFeatureFlagsLambda)); } /** @@ -1029,10 +1023,9 @@ app.get( .delete(lambdaWrapper(deleteAuthCookieLambda)) .post(lambdaWrapper(loginLambda)); app.post('/auth/refresh', lambdaWrapper(renewIdTokenLambda)); + app.post('/auth/confirm-signup', lambdaWrapper(confirmSignUpLambda)); } -app.post('/confirm-signup', lambdaWrapper(confirmSignUpLambda)); - // This endpoint is used for testing purpose only which exposes the // CRON lambda which runs nightly to update cases to be ready for trial. if (process.env.IS_LOCAL) { diff --git a/web-api/terraform/api/api.tf b/web-api/terraform/api/api.tf index 065ab8af6d3..31f4af76a9e 100644 --- a/web-api/terraform/api/api.tf +++ b/web-api/terraform/api/api.tf @@ -142,26 +142,32 @@ resource "aws_api_gateway_method" "api_method_head" { } # -resource "aws_api_gateway_resource" "api_maintenance_mode_resource" { +resource "aws_api_gateway_resource" "api_system_resource" { rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id parent_id = aws_api_gateway_rest_api.gateway_for_api.root_resource_id - path_part = "maintenance-mode" + path_part = "system" } -resource "aws_api_gateway_method" "api_maintenance_mode_method_any" { +resource "aws_api_gateway_resource" "api_system_proxy_resource" { + rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id + parent_id = aws_api_gateway_rest_api.api_system_resource.id + path_part = "{proxy+}" +} + +resource "aws_api_gateway_method" "api_system_method_any" { rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id - resource_id = aws_api_gateway_resource.api_maintenance_mode_resource.id + resource_id = aws_api_gateway_resource.api_system_proxy_resource.id http_method = "ANY" authorization = "NONE" } -resource "aws_api_gateway_integration" "api_integration_maintenance_mode" { +resource "aws_api_gateway_integration" "api_integration_system" { depends_on = [ aws_api_gateway_integration.api_integration_options ] rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id - resource_id = aws_api_gateway_resource.api_maintenance_mode_resource.id - http_method = aws_api_gateway_method.api_maintenance_mode_method_any.http_method + resource_id = aws_api_gateway_resource.api_system_proxy_resource.id + http_method = aws_api_gateway_method.api_system_method_any.http_method integration_http_method = "POST" type = "AWS_PROXY" From 07d6063b53e543b53f04478874d0896817081f90 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 8 Jan 2024 14:42:46 -0800 Subject: [PATCH 107/700] 10007: Fix terraform --- web-api/terraform/api/api.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-api/terraform/api/api.tf b/web-api/terraform/api/api.tf index 31f4af76a9e..53ec61b9851 100644 --- a/web-api/terraform/api/api.tf +++ b/web-api/terraform/api/api.tf @@ -150,7 +150,7 @@ resource "aws_api_gateway_resource" "api_system_resource" { resource "aws_api_gateway_resource" "api_system_proxy_resource" { rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id - parent_id = aws_api_gateway_rest_api.api_system_resource.id + parent_id = aws_api_gateway_resource.api_system_resource.id path_part = "{proxy+}" } From ff420e6b6fec57a01865564540f715b3159764a5 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 8 Jan 2024 15:21:41 -0800 Subject: [PATCH 108/700] 10007: Serverless-express bug hack --- web-api/terraform/template/lambdas/api.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web-api/terraform/template/lambdas/api.ts b/web-api/terraform/template/lambdas/api.ts index bee2cb789d4..26eee4f3edc 100644 --- a/web-api/terraform/template/lambdas/api.ts +++ b/web-api/terraform/template/lambdas/api.ts @@ -9,6 +9,10 @@ export const handler = (event, context) => { // awsServerlessExpress will expect this to be set correctly: event.pathParameters.proxy event.pathParameters.proxy = `auth/${event.pathParameters.proxy}`; } + if (event.path && event.path.startsWith('/system')) { + // awsServerlessExpress will expect this to be set correctly: event.pathParameters.proxy + event.pathParameters.proxy = `system/${event.pathParameters.proxy}`; + } // This is a hack needed for when we use async api gateway events. Normal api gateway requests // will send event.body as a string, but for async events with the X-Amz-Invocation-Type header, From adf32fa09b03979f22c2a5ad993db3f7b8cc8bb9 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 8 Jan 2024 15:47:23 -0800 Subject: [PATCH 109/700] 10007: Switch any to GET for proxy+ --- web-api/terraform/api/api.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-api/terraform/api/api.tf b/web-api/terraform/api/api.tf index 53ec61b9851..946f6d51c37 100644 --- a/web-api/terraform/api/api.tf +++ b/web-api/terraform/api/api.tf @@ -157,7 +157,7 @@ resource "aws_api_gateway_resource" "api_system_proxy_resource" { resource "aws_api_gateway_method" "api_system_method_any" { rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id resource_id = aws_api_gateway_resource.api_system_proxy_resource.id - http_method = "ANY" + http_method = "GET" authorization = "NONE" } From 43dc60aaee33b20a661b244286d2e566af5366ba Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 9 Jan 2024 11:08:06 -0700 Subject: [PATCH 110/700] 10007: WIP confirm + verify user account --- temp_delete_me.md | 6 +++++ .../useCases/auth/confirmSignUpInteractor.ts | 22 ++++++++++--------- web-api/src/persistence/cognito/getCognito.ts | 12 ---------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 87fe9b47f2c..1d429e836ca 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -1,3 +1,9 @@ +::: TODAY ::: +1) Confirm works on deployment +2) Finish remaining flows (functionality example: password) +N) All tests pass (x on unit tests) + + ::: STUFF TO DELETE ::: diff --git a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts index 4335859dcda..80796166dba 100644 --- a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts +++ b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts @@ -3,7 +3,7 @@ import { ServerApplicationContext } from '@web-api/applicationContext'; export const confirmSignUpInteractor = async ( applicationContext: ServerApplicationContext, { confirmationCode, userId }: { confirmationCode: string; userId: string }, -) => { +): Promise => { const accountConfirmationRecord = await applicationContext .getPersistenceGateway() .getAccountConfirmationCode(applicationContext, { userId }); @@ -12,18 +12,20 @@ export const confirmSignUpInteractor = async ( } const cognito = applicationContext.getCognito(); - const foundUsers = await cognito.listUsers({ - AttributesToGet: ['sub', 'username'], - Filter: `sub = "${userId}"`, + + await cognito.adminConfirmSignUp({ UserPoolId: process.env.USER_POOL_ID, + Username: userId, }); - const userName = foundUsers?.Users?.[0]?.Username; - if (!userName) { - throw new Error(`No user found in cognito with given ID: ${userId}`); - } - await cognito.adminConfirmSignUp({ - Username: userName, + await cognito.adminUpdateUserAttributes({ + UserAttributes: [ + { + Name: 'email_verified', + Value: 'true', + }, + ], UserPoolId: process.env.USER_POOL_ID, + Username: userId, }); }; diff --git a/web-api/src/persistence/cognito/getCognito.ts b/web-api/src/persistence/cognito/getCognito.ts index 1ee444827b3..ff70ce95fef 100644 --- a/web-api/src/persistence/cognito/getCognito.ts +++ b/web-api/src/persistence/cognito/getCognito.ts @@ -1,6 +1,4 @@ -import { Agent } from 'https'; import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; -import { NodeHttpHandler } from '@smithy/node-http-handler'; let cognitoClientCache: CognitoIdentityProvider; @@ -9,11 +7,6 @@ export function getCognito() { cognitoClientCache = new CognitoIdentityProvider({ maxAttempts: 3, region: 'us-east-1', - requestHandler: new NodeHttpHandler({ - connectionTimeout: 3000, - httpsAgent: new Agent({ keepAlive: true, maxSockets: 75 }), - requestTimeout: 5000, - }), }); } @@ -26,11 +19,6 @@ export function getLocalCognito() { endpoint: 'http://localhost:9229/', maxAttempts: 3, region: 'local', - // requestHandler: new NodeHttpHandler({ - // connectionTimeout: 3000, - // httpsAgent: new Agent({ keepAlive: true, maxSockets: 75 }), - // requestTimeout: 5000, - // }), }); } From 9af31c3f1413978d34796206f648b3d7877d6dda Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 9 Jan 2024 11:31:08 -0700 Subject: [PATCH 111/700] 10007: remap feature fllag route --- temp_delete_me.md | 1 + web-api/src/app-public.ts | 2 +- web-api/terraform/template/cognito.tf | 35 +-------------------------- 3 files changed, 3 insertions(+), 35 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 1d429e836ca..877c7e3cf7d 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -25,6 +25,7 @@ N) All tests pass (x on unit tests) - We need to handle temporary password changes on login screen. This happens when cognito forces a password update. - disable cognito emails. - resend confirmation code. +- cognito srp auth flow diff --git a/web-api/src/app-public.ts b/web-api/src/app-public.ts index b2cf495e374..4a635cc70df 100644 --- a/web-api/src/app-public.ts +++ b/web-api/src/app-public.ts @@ -155,7 +155,7 @@ app.get('/public-api/judges', lambdaWrapper(getPublicJudgesLambda)); * Feature flags */ { - app.get('/feature-flag', lambdaWrapper(getAllFeatureFlagsLambda)); + app.get('/system/feature-flag', lambdaWrapper(getAllFeatureFlagsLambda)); } /** diff --git a/web-api/terraform/template/cognito.tf b/web-api/terraform/template/cognito.tf index 31e5b4ef030..fb06b777166 100644 --- a/web-api/terraform/template/cognito.tf +++ b/web-api/terraform/template/cognito.tf @@ -5,39 +5,6 @@ resource "aws_cognito_user_pool" "pool" { username_attributes = ["email"] - # verification_message_template { - # default_email_option = "CONFIRM_WITH_LINK" - # email_message_by_link = < - #

Welcome to DAWSON!

- - #

Your account with DAWSON has been created. Use the button below to verify your email address.

- - # {####} - # - - #

If you did not create an account with DAWSON, contact dawson.support@ustaxcourt.gov.

- - #
- - #

This is an automated email. We are unable to respond to any messages to this email address.

- # - # EMAILMESSAGE - # email_subject_by_link = "U.S. Tax Court DAWSON Account Verification" - # } - account_recovery_setting { recovery_mechanism { name = "verified_email" @@ -130,7 +97,7 @@ resource "aws_cognito_user_pool" "pool" { resource "aws_cognito_user_pool_client" "client" { name = "client" - explicit_auth_flows = ["ADMIN_NO_SRP_AUTH"] + explicit_auth_flows = ["ADMIN_NO_SRP_AUTH", "USER_PASSWORD_AUTH"] generate_secret = false allowed_oauth_flows_user_pool_client = true From 67ce5448d612a690a123ed595c6856bf49850c72 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 9 Jan 2024 14:32:10 -0800 Subject: [PATCH 112/700] 10007: Only respond back with confirmation code on local --- shared/src/proxies/signUpUserProxy.ts | 3 +- .../useCases/auth/signUpUserInteractor.ts | 33 +++++-------------- .../actions/createConfirmLinkAction.ts | 13 ++++---- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/shared/src/proxies/signUpUserProxy.ts b/shared/src/proxies/signUpUserProxy.ts index cca26e50b6d..aa446b9061c 100644 --- a/shared/src/proxies/signUpUserProxy.ts +++ b/shared/src/proxies/signUpUserProxy.ts @@ -1,6 +1,5 @@ -import { type AdminCreateUserResponse } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import { post } from './requests'; import { SignUpUserResponse } from '@web-api/business/useCases/auth/signUpUserInteractor'; +import { post } from './requests'; export const signUpUserInteractor = ( applicationContext, diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index bd7bc14f019..707d7b97787 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -7,7 +7,7 @@ import qs from 'qs'; export type SignUpUserResponse = { email: string; userId: string; - confirmationCode: string; + confirmationCode?: string; }; export const signUpUserInteractor = async ( @@ -23,8 +23,6 @@ export const signUpUserInteractor = async ( }; }, ): Promise => { - console.log('**** signUpUserInteractor'); - const cognito: CognitoIdentityProvider = applicationContext.getCognito(); const { Users: existingAccounts } = await cognito.listUsers({ @@ -65,13 +63,6 @@ export const signUpUserInteractor = async ( const userId = result.UserSub!; - // generate a confirmation code - // What rules do we want to apply to a code? Right now, cognito generates a 6 digit code. Are we OK with that? - console.log( - '**** signUpUserInteractor, done signing up, about to send email', - userId, - ); - const { confirmationCode } = await applicationContext .getPersistenceGateway() .generateAccountConfirmationCode(applicationContext, { userId }); @@ -82,16 +73,17 @@ export const signUpUserInteractor = async ( userId, }); - console.log( - '**** signUpUserInteractor, done signing up, done sending email', - confirmationCode, - ); - // TODO 10007: Only return confirmationCode locally as we cannot send an email. If we always return it then we cannot be sure we confirmed their email. - return { - confirmationCode, + const signUpUserResponse: SignUpUserResponse = { email: user.email, userId, }; + + // Only return confirmationCode locally as we cannot send an email. Do not expose confirmation code in deployed env. + if (applicationContext.environment.stage === 'local') { + signUpUserResponse.confirmationCode = confirmationCode; + } + + return signUpUserResponse; }; const sendAccountCreationConfirmation = async ( @@ -102,8 +94,6 @@ const sendAccountCreationConfirmation = async ( userId, }: { email: string; confirmationCode: string; userId: string }, ) => { - console.log('**** sendAccountCreationConfirmation'); - const queryString = qs.stringify( { confirmationCode, userId }, { encode: false }, @@ -131,11 +121,6 @@ const sendAccountCreationConfirmation = async ( const emailClient: SES = applicationContext.getEmailClient(); - console.log( - '**** sendAccountCreationConfirmation, about to send email to: ', - email, - ); - return await emailClient .sendEmail({ Destination: { diff --git a/web-client/src/presenter/actions/createConfirmLinkAction.ts b/web-client/src/presenter/actions/createConfirmLinkAction.ts index 07057d74728..66ec59fa18d 100644 --- a/web-client/src/presenter/actions/createConfirmLinkAction.ts +++ b/web-client/src/presenter/actions/createConfirmLinkAction.ts @@ -1,14 +1,13 @@ +import { SignUpUserResponse } from '@web-api/business/useCases/auth/signUpUserInteractor'; import qs from 'qs'; -export const createConfirmLinkAction = ({ props }: ActionProps) => { +export const createConfirmLinkAction = ({ + props, +}: ActionProps) => { if (!process.env.IS_LOCAL) return; - const { userId, confirmationCode, email } = props; - - // confirmation code is currently intentionally hard-coded in cognitoLocal - // ^^ it is not, have to set process.env.CODE const queryString = qs.stringify( - { confirmationCode, userId }, + { confirmationCode: props.confirmationCode, userId: props.userId }, { encode: false }, ); @@ -17,7 +16,7 @@ export const createConfirmLinkAction = ({ props }: ActionProps) => { return { alertSuccess: { alertType: 'success', - message: `New user account created successfully for ${email}! Please click the link below to verify your email address.
Verify Email Address`, + message: `New user account created successfully for ${props.email}! Please click the link below to verify your email address.
Verify Email Address`, title: 'Account Created Locally', }, }; From b10fdb59af35f2828cd5c2857ed7416e24745976 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 9 Jan 2024 14:34:12 -0800 Subject: [PATCH 113/700] 10007: any rename to get --- web-api/terraform/api/api.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web-api/terraform/api/api.tf b/web-api/terraform/api/api.tf index 946f6d51c37..c451c224fd5 100644 --- a/web-api/terraform/api/api.tf +++ b/web-api/terraform/api/api.tf @@ -154,7 +154,7 @@ resource "aws_api_gateway_resource" "api_system_proxy_resource" { path_part = "{proxy+}" } -resource "aws_api_gateway_method" "api_system_method_any" { +resource "aws_api_gateway_method" "api_system_method_get" { rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id resource_id = aws_api_gateway_resource.api_system_proxy_resource.id http_method = "GET" @@ -167,7 +167,7 @@ resource "aws_api_gateway_integration" "api_integration_system" { ] rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id resource_id = aws_api_gateway_resource.api_system_proxy_resource.id - http_method = aws_api_gateway_method.api_system_method_any.http_method + http_method = aws_api_gateway_method.api_system_method_get.http_method integration_http_method = "POST" type = "AWS_PROXY" From 3099ad34a703239a04e1a47727f37b5a5f273c4d Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 9 Jan 2024 15:14:04 -0800 Subject: [PATCH 114/700] 10007: Only redirect to localhost for login when on local --- package.json | 4 ++-- setup-local-env.sh | 1 + web-client/build-dist-public.sh | 2 -- web-client/src/applicationContextPublic.ts | 6 +++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 9b56b77a2ed..8d1f3f3a5c3 100644 --- a/package.json +++ b/package.json @@ -197,14 +197,14 @@ "start:api:docker": "USTC_ENV=dev ./run-api.sh", "start:client:ci": "CI=true SKIP_VIRUS_SCAN=true NODE_ENV=production npm run start:client", "start:client:no-scanner": "NO_SCANNER=true npm run start:client", - "start:client": "npm run start:client-host && WATCH=true IS_LOCAL=true FILE_UPLOAD_MODAL_TIMEOUT=1 USTC_ENV=dev PDF_EXPRESS_LICENSE_KEY=OjkUB41bl1hJg6jvUEfn npm run start:client:esbuild", + "start:client": "npm run start:client-host && WATCH=true IS_LOCAL=true FILE_UPLOAD_MODAL_TIMEOUT=1 USTC_ENV=dev npm run start:client:esbuild", "start:client-host": "servor dist index.html 1234 &", "start:client:esbuild": "node esbuild.config.mjs", "start:madge": "node ./graph-generators/index.js", "start:migration": "node ./web-api/send-migration-segment-messages.js", "start:public:ci": "npm run clean:public && CI=true npm run start:public", "start:public-host": "servor dist-public index.html 5678 &", - "start:public": "npm run start:public-host && CHECK_DEPLOY_DATE_INTERVAL=5000 WATCH=true USTC_ENV=dev IS_LOCAL=true PDF_EXPRESS_LICENSE_KEY=OjkUB41bl1hJg6jvUEfn node esbuild.public.config.mjs", + "start:public": "npm run start:public-host && CHECK_DEPLOY_DATE_INTERVAL=5000 WATCH=true USTC_ENV=dev IS_LOCAL=true ENV=local node esbuild.public.config.mjs", "start:s3rver": "s3rver -d web-api/storage/s3 -a 0.0.0.0 -p 9000 --configure-bucket $DOCUMENTS_BUCKET_NAME web-api/cors-policy.xml --configure-bucket $TEMP_DOCUMENTS_BUCKET_NAME web-api/cors-policy.xml", "switch-colors": "./web-client/switch-colors.sh", "test:_client:parallel": "NO_SCANNER=true SKIP_VIRUS_SCAN=true AWS_ACCESS_KEY_ID=S3RVER AWS_SECRET_ACCESS_KEY=S3RVER FILE_UPLOAD_MODAL_TIMEOUT=1 jest --maxWorkers=50% --config web-client/jest-unit.config.ts", diff --git a/setup-local-env.sh b/setup-local-env.sh index a2dd6dd1564..6e0b891fe71 100755 --- a/setup-local-env.sh +++ b/setup-local-env.sh @@ -20,3 +20,4 @@ export IRS_SUPERUSER_EMAIL=irs-superuser@example.com export USER_POOL_ID='local_2pHzece7' export COGNITO_CLIENT_ID='bvjrggnd3co403c0aahscinne' export DISABLE_EMAILS=true +export ENV=local diff --git a/web-client/build-dist-public.sh b/web-client/build-dist-public.sh index 5b1e08ff6d2..9232cfa17f2 100755 --- a/web-client/build-dist-public.sh +++ b/web-client/build-dist-public.sh @@ -16,8 +16,6 @@ USER_POOL_ID=$(aws cognito-idp list-user-pools --query "UserPools[?Name == 'efcm CLIENT_ID=$(aws cognito-idp list-user-pool-clients --user-pool-id "${USER_POOL_ID}" --query "UserPoolClients[?ClientName == 'client'].ClientId | [0]" --max-results 30 --region "${REGION}" --output text) -COGNITO_LOGIN_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" - COGNITO_PASSWORD_RESET_REQUEST_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/forgotPassword?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" STAGE="${CLIENT_STAGE}" \ diff --git a/web-client/src/applicationContextPublic.ts b/web-client/src/applicationContextPublic.ts index 17b59af5ade..fffd46c8def 100644 --- a/web-client/src/applicationContextPublic.ts +++ b/web-client/src/applicationContextPublic.ts @@ -197,9 +197,9 @@ const applicationContextPublic = { }; }, getPrivateUrl: () => { - return process.env.STAGE - ? `https://app.${process.env.EFCMS_DOMAIN}` - : 'http://localhost:1234'; + return process.env.ENV === 'local' + ? 'http://localhost:1234' + : `https://app.${process.env.EFCMS_DOMAIN}`; }, getPublicSiteUrl, getUseCases: () => allUseCases, From ed97a96a099c1e046f8a7129b60dfdeec002cac0 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 9 Jan 2024 15:38:53 -0800 Subject: [PATCH 115/700] 10007: Add confirmSignUp to permissions --- iam/terraform/environment-specific/main/lambda.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/iam/terraform/environment-specific/main/lambda.tf b/iam/terraform/environment-specific/main/lambda.tf index 47e8e295709..4b27e50a7aa 100644 --- a/iam/terraform/environment-specific/main/lambda.tf +++ b/iam/terraform/environment-specific/main/lambda.tf @@ -67,6 +67,7 @@ resource "aws_iam_role_policy" "lambda_policy" { "cognito-idp:AdminDisableUser", "cognito-idp:AdminGetUser", "cognito-idp:AdminUpdateUserAttributes", + "cognito-idp:AdminConfirmSignUp", "cognito-idp:ListUserPoolClients", "cognito-idp:ListUsers" ], From 4bad0d293cebc039396db78393d428b7b1664d04 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 9 Jan 2024 15:47:13 -0800 Subject: [PATCH 116/700] 10007: docs --- temp_delete_me.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 877c7e3cf7d..2e5efb03c43 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -17,7 +17,11 @@ N) All tests pass (x on unit tests) - finish all todos (review together - KS) - ensure back works right (public to private and back) - fix tests -+ email verification flow (just after verifying, are we going to new login with verification success message) +- email verification flow (just after verifying, are we going to new login with verification success message) +- Handle what happens if a user clicks an expired confirmation email: + - On login to an unconfirmed account immediately send an email to the user + - Expire link after 24hours + - If user clicks on an expired email then redirect them to the login and tell them to sign in so that we can send a new confirmation with a new confirmation code. - Refactor ifHasAccess Function to be handled by router + initSequence - Refactor maintenance mode to be handled by router + initSequence. No other sequence needs to branch because of it. - invalidate old refreshToken and idToken upon refresh. From ea58e9a5b9f337e0bfaf3cc4d62773731c034911 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Wed, 10 Jan 2024 08:32:49 -0800 Subject: [PATCH 117/700] 10007: Delete email configuration for cognito to stop auto sending email when account is created --- web-api/terraform/template/cognito.tf | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/web-api/terraform/template/cognito.tf b/web-api/terraform/template/cognito.tf index fb06b777166..8faea4b6f6d 100644 --- a/web-api/terraform/template/cognito.tf +++ b/web-api/terraform/template/cognito.tf @@ -12,22 +12,6 @@ resource "aws_cognito_user_pool" "pool" { } } - admin_create_user_config { - allow_admin_create_user_only = false - invite_message_template { - sms_message = "Your username is {username} and temporary password is {####}." - email_subject = "An account has been set up for you with the U.S. Tax Court" - email_message = "Welcome to DAWSON, the new U.S. Tax Court case management system. An account has been created for you to access your cases online.

Please verify that your contact information is correct in the system, and make any required changes.




Your username: {username}

Temporary password: {####}

This temporary password is valid for 7 days. Log in to DAWSON to change your password.

NOTE:
1. Make sure your username and password are entered exactly as they appear in the welcome email -- both are case sensitive.
2. Please copy and paste the temporary password versus trying to retype it.
3. Please make sure you do not pick up an extra space at the beginning or end of the password when copying and pasting.
4. If your password ends with a special character or punctuation (.?,), that is part of your temporary password.

" - } - } - - email_configuration { # Use SES to send email - source_arn = aws_ses_email_identity.ses_sender.arn - email_sending_account = "DEVELOPER" - reply_to_email_address = "noreply@${var.dns_domain}" - from_email_address = "U.S. Tax Court " - } - schema { attribute_data_type = "String" name = "email" From 9645710a411165eb92e3e11b84242ab7ced1db44 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Wed, 10 Jan 2024 08:50:08 -0800 Subject: [PATCH 118/700] 10007: WIP resend confirmation code when user has not confirmed new account and attempts to log in --- temp_delete_me.md | 2 +- web-client/src/presenter/actions/Login/submitLoginAction.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 2e5efb03c43..4aa4e0cf16a 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -28,7 +28,7 @@ N) All tests pass (x on unit tests) - Ensure idToken lasts longer than how often we are refreshing the idToken (REFRESH_INTERVAL) - We need to handle temporary password changes on login screen. This happens when cognito forces a password update. - disable cognito emails. -- resend confirmation code. +- On login to unconfirmed account, send another confirmation email to the user. - cognito srp auth flow diff --git a/web-client/src/presenter/actions/Login/submitLoginAction.ts b/web-client/src/presenter/actions/Login/submitLoginAction.ts index f6e744108da..dcd6cb84361 100644 --- a/web-client/src/presenter/actions/Login/submitLoginAction.ts +++ b/web-client/src/presenter/actions/Login/submitLoginAction.ts @@ -18,6 +18,7 @@ export const submitLoginAction = async ({ return path.success({ accessToken, idToken, refreshToken }); } catch (err: any) { + console.log('*** err', err); if (err.responseCode === 401) { return path.error({ alertError: { From 88a07e46e3310cf3be0e8fa8b18f857f069242ba Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Wed, 10 Jan 2024 10:36:56 -0700 Subject: [PATCH 119/700] 10007: WIP Update Terraform to Not Send Messages + Add Resend Confirmation Code --- .../business/useCases/auth/loginInteractor.ts | 44 +++++++++++++++++++ .../useCases/auth/signUpUserInteractor.ts | 2 +- web-api/terraform/template/cognito.tf | 2 +- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 5c121b2c453..4bd6f842183 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -1,5 +1,6 @@ import { ServerApplicationContext } from '@web-api/applicationContext'; import { UnknownUserError } from '@web-api/errors/errors'; +import { sendAccountCreationConfirmation } from '@web-api/business/useCases/auth/signUpUserInteractor'; export const loginInteractor = async ( applicationContext: ServerApplicationContext, @@ -21,6 +22,7 @@ export const loginInteractor = async ( refreshToken: result.AuthenticationResult!.RefreshToken!, }; } catch (err: any) { + console.log('*** api err', err); if ( err.name === 'InvalidPasswordException' || err.name === 'NotAuthorizedException' @@ -28,6 +30,48 @@ export const loginInteractor = async ( throw new UnknownUserError('Invalid Username or Password'); } + if (err.name === 'UserNotConfirmedException') { + const cognito = applicationContext.getCognito(); + const users = await cognito.listUsers({ + AttributesToGet: ['sub'], + Filter: `email = "${email}"`, + UserPoolId: process.env.USER_POOL_ID, + }); + + console.log( + '*** user', + users.Users?.[0], + JSON.stringify(users.Users?.[0].Attributes?.[0].Value), + ); + + const userId = users.Users?.[0].Attributes?.[0].Value!; + + const accountConfirmationRecord = await applicationContext + .getPersistenceGateway() + .getAccountConfirmationCode(applicationContext, { userId }); + + console.log('*** accountConfirmationRecord', accountConfirmationRecord); + + let newConfirmationCode = accountConfirmationRecord.confirmationCode; + + // if doesn't exist regenerate new confirmation code + if (!newConfirmationCode) { + console.log('*** generate new confirmation code'); + const { confirmationCode } = await applicationContext + .getPersistenceGateway() + .generateAccountConfirmationCode(applicationContext, { userId }); + newConfirmationCode = confirmationCode; + } + + // Assume exists and resend confirmation email + console.log('*** sending confirmation cod email'); + await sendAccountCreationConfirmation(applicationContext, { + confirmationCode: newConfirmationCode!, + email, + userId, + }); + } + throw err; } }; diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 707d7b97787..2cf3b871f51 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -86,7 +86,7 @@ export const signUpUserInteractor = async ( return signUpUserResponse; }; -const sendAccountCreationConfirmation = async ( +export const sendAccountCreationConfirmation = async ( applicationContext: ServerApplicationContext, { confirmationCode, diff --git a/web-api/terraform/template/cognito.tf b/web-api/terraform/template/cognito.tf index 8faea4b6f6d..72a686c300a 100644 --- a/web-api/terraform/template/cognito.tf +++ b/web-api/terraform/template/cognito.tf @@ -1,7 +1,7 @@ resource "aws_cognito_user_pool" "pool" { name = "efcms-${var.environment}" - auto_verified_attributes = ["email"] + # auto_verified_attributes = ["email"] username_attributes = ["email"] From 2850ec459ab95ede6fefe53001c336165a81ce34 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Wed, 10 Jan 2024 11:30:56 -0700 Subject: [PATCH 120/700] 10007: Add back emails sent by cognito for create and verify practitioner account --- temp_delete_me.md | 2 +- .../business/useCases/auth/loginInteractor.ts | 2 ++ web-api/terraform/template/cognito.tf | 18 ++++++++++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 4aa4e0cf16a..3015576119b 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -29,7 +29,7 @@ N) All tests pass (x on unit tests) - We need to handle temporary password changes on login screen. This happens when cognito forces a password update. - disable cognito emails. - On login to unconfirmed account, send another confirmation email to the user. -- cognito srp auth flow +- cognito srp auth flow (review together - KS) diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 4bd6f842183..7e1655a261b 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -70,6 +70,8 @@ export const loginInteractor = async ( email, userId, }); + + throw new Error('User is unconfirmed'); } throw err; diff --git a/web-api/terraform/template/cognito.tf b/web-api/terraform/template/cognito.tf index 72a686c300a..1a97b635424 100644 --- a/web-api/terraform/template/cognito.tf +++ b/web-api/terraform/template/cognito.tf @@ -1,8 +1,6 @@ resource "aws_cognito_user_pool" "pool" { name = "efcms-${var.environment}" - # auto_verified_attributes = ["email"] - username_attributes = ["email"] account_recovery_setting { @@ -12,6 +10,22 @@ resource "aws_cognito_user_pool" "pool" { } } + admin_create_user_config { + allow_admin_create_user_only = false + invite_message_template { + sms_message = "Your username is {username} and temporary password is {####}." + email_subject = "An account has been set up for you with the U.S. Tax Court" + email_message = "Welcome to DAWSON, the new U.S. Tax Court case management system. An account has been created for you to access your cases online.

Please verify that your contact information is correct in the system, and make any required changes.




Your username: {username}

Temporary password: {####}

This temporary password is valid for 7 days. Log in to DAWSON to change your password.

NOTE:
1. Make sure your username and password are entered exactly as they appear in the welcome email -- both are case sensitive.
2. Please copy and paste the temporary password versus trying to retype it.
3. Please make sure you do not pick up an extra space at the beginning or end of the password when copying and pasting.
4. If your password ends with a special character or punctuation (.?,), that is part of your temporary password.

" + } + } + + email_configuration { # Use SES to send email + source_arn = aws_ses_email_identity.ses_sender.arn + email_sending_account = "DEVELOPER" + reply_to_email_address = "noreply@${var.dns_domain}" + from_email_address = "U.S. Tax Court " + } + schema { attribute_data_type = "String" name = "email" From 2302cc3b2e31b7ed7c883bf4dac3145dfa37ca91 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Wed, 10 Jan 2024 12:00:20 -0700 Subject: [PATCH 121/700] 10007: Create new utility function for sending an email to a user --- web-api/src/applicationContext.ts | 2 + .../business/useCases/auth/loginInteractor.ts | 116 ++++++++++++------ .../useCases/auth/signUpUserInteractor.ts | 32 ++--- .../persistence/messages/sendEmailToUser.ts | 32 +++++ 4 files changed, 119 insertions(+), 63 deletions(-) create mode 100644 web-api/src/persistence/messages/sendEmailToUser.ts diff --git a/web-api/src/applicationContext.ts b/web-api/src/applicationContext.ts index d66bfe8a375..02c5f363480 100644 --- a/web-api/src/applicationContext.ts +++ b/web-api/src/applicationContext.ts @@ -55,6 +55,7 @@ import { isCurrentColorActive } from './persistence/dynamo/helpers/isCurrentColo import { retrySendNotificationToConnections } from '../../shared/src/notifications/retrySendNotificationToConnections'; import { sendBulkTemplatedEmail } from './dispatchers/ses/sendBulkTemplatedEmail'; import { sendEmailEventToQueue } from './persistence/messages/sendEmailEventToQueue'; +import { sendEmailToUser } from '@web-api/persistence/messages/sendEmailToUser'; import { sendNotificationOfSealing } from './dispatchers/sns/sendNotificationOfSealing'; import { sendNotificationToConnection } from '../../shared/src/notifications/sendNotificationToConnection'; import { sendNotificationToUser } from '../../shared/src/notifications/sendNotificationToUser'; @@ -260,6 +261,7 @@ export const createApplicationContext = ( }); } }, + sendEmailToUser, sendSetTrialSessionCalendarEvent: ({ applicationContext, payload }) => { if (environment.stage === 'local') { return applicationContext diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 7e1655a261b..50542159838 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -1,6 +1,6 @@ import { ServerApplicationContext } from '@web-api/applicationContext'; import { UnknownUserError } from '@web-api/errors/errors'; -import { sendAccountCreationConfirmation } from '@web-api/business/useCases/auth/signUpUserInteractor'; +import qs from 'qs'; export const loginInteractor = async ( applicationContext: ServerApplicationContext, @@ -31,45 +31,7 @@ export const loginInteractor = async ( } if (err.name === 'UserNotConfirmedException') { - const cognito = applicationContext.getCognito(); - const users = await cognito.listUsers({ - AttributesToGet: ['sub'], - Filter: `email = "${email}"`, - UserPoolId: process.env.USER_POOL_ID, - }); - - console.log( - '*** user', - users.Users?.[0], - JSON.stringify(users.Users?.[0].Attributes?.[0].Value), - ); - - const userId = users.Users?.[0].Attributes?.[0].Value!; - - const accountConfirmationRecord = await applicationContext - .getPersistenceGateway() - .getAccountConfirmationCode(applicationContext, { userId }); - - console.log('*** accountConfirmationRecord', accountConfirmationRecord); - - let newConfirmationCode = accountConfirmationRecord.confirmationCode; - - // if doesn't exist regenerate new confirmation code - if (!newConfirmationCode) { - console.log('*** generate new confirmation code'); - const { confirmationCode } = await applicationContext - .getPersistenceGateway() - .generateAccountConfirmationCode(applicationContext, { userId }); - newConfirmationCode = confirmationCode; - } - - // Assume exists and resend confirmation email - console.log('*** sending confirmation cod email'); - await sendAccountCreationConfirmation(applicationContext, { - confirmationCode: newConfirmationCode!, - email, - userId, - }); + await resendAccountConfirmation(applicationContext, email); throw new Error('User is unconfirmed'); } @@ -77,3 +39,77 @@ export const loginInteractor = async ( throw err; } }; + +async function resendAccountConfirmation( + applicationContext: ServerApplicationContext, + email: string, +): Promise { + const cognito = applicationContext.getCognito(); + + const users = await cognito.listUsers({ + AttributesToGet: ['sub'], + Filter: `email = "${email}"`, + UserPoolId: process.env.USER_POOL_ID, + }); + console.log( + '*** user', + users.Users?.[0], + JSON.stringify(users.Users?.[0].Attributes?.[0].Value), + ); + + const userId = users.Users?.[0].Attributes?.[0].Value!; + + const accountConfirmationRecord = await applicationContext + .getPersistenceGateway() + .getAccountConfirmationCode(applicationContext, { userId }); + + console.log('*** accountConfirmationRecord', accountConfirmationRecord); + + let newConfirmationCode = accountConfirmationRecord.confirmationCode; + + // if doesn't exist regenerate new confirmation code + if (!newConfirmationCode) { + console.log('*** generate new confirmation code'); + const { confirmationCode } = await applicationContext + .getPersistenceGateway() + .generateAccountConfirmationCode(applicationContext, { userId }); + newConfirmationCode = confirmationCode; + } + + // Assume exists and resend confirmation email + console.log('*** sending confirmation cod email'); + + const queryString = qs.stringify( + { confirmationCode: newConfirmationCode, userId }, + { encode: false }, + ); + + const verificationLink = `https://app.${process.env.EFCMS_DOMAIN}/confirm-signup?${queryString}`; + + const emailBody = + 'Welcome to DAWSON! Your account with DAWSON has been created. Use the' + + ' button below to verify your email address.' + + `` + + '


If you did not create an account with DAWSON, please contact support at ' + + 'dawson.support@ustaxcourt.gov.'; + + return await applicationContext + .getMessageGateway() + .sendEmailToUser(applicationContext, { + body: emailBody, + subject: 'U.S. Tax Court DAWSON Account Verification', + to: email, + }); +} diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 2cf3b871f51..bb8440b5a28 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -1,6 +1,5 @@ import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; -import { SES } from 'aws-sdk'; import { ServerApplicationContext } from '@web-api/applicationContext'; import qs from 'qs'; @@ -86,14 +85,14 @@ export const signUpUserInteractor = async ( return signUpUserResponse; }; -export const sendAccountCreationConfirmation = async ( +const sendAccountCreationConfirmation = async ( applicationContext: ServerApplicationContext, { confirmationCode, email, userId, }: { email: string; confirmationCode: string; userId: string }, -) => { +): Promise => { const queryString = qs.stringify( { confirmationCode, userId }, { encode: false }, @@ -119,24 +118,11 @@ export const sendAccountCreationConfirmation = async ( '


If you did not create an account with DAWSON, please contact support at ' + 'dawson.support@ustaxcourt.gov.'; - const emailClient: SES = applicationContext.getEmailClient(); - - return await emailClient - .sendEmail({ - Destination: { - ToAddresses: [email], - }, - Message: { - Body: { - Html: { - Data: emailBody, - }, - }, - Subject: { - Data: 'U.S. Tax Court DAWSON Account Verification', - }, - }, - Source: process.env.EMAIL_SOURCE!, - }) - .promise(); + return await applicationContext + .getMessageGateway() + .sendEmailToUser(applicationContext, { + body: emailBody, + subject: 'U.S. Tax Court DAWSON Account Verification', + to: email, + }); }; diff --git a/web-api/src/persistence/messages/sendEmailToUser.ts b/web-api/src/persistence/messages/sendEmailToUser.ts new file mode 100644 index 00000000000..e2675254189 --- /dev/null +++ b/web-api/src/persistence/messages/sendEmailToUser.ts @@ -0,0 +1,32 @@ +export const sendEmailToUser = async ( + applicationContext, + { + body, + subject, + to, + }: { + body: string; + subject: string; + to: string; + }, +): Promise => { + return await applicationContext + .getEmailClient() + .sendEmail({ + Destination: { + ToAddresses: [to], + }, + Message: { + Body: { + Html: { + Data: body, + }, + }, + Subject: { + Data: subject, + }, + }, + Source: process.env.EMAIL_SOURCE!, + }) + .promise(); +}; From 53f7305c4a402fae4f9435aab95c6957bd57181c Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Wed, 10 Jan 2024 12:06:12 -0800 Subject: [PATCH 122/700] 10007: WIP moving frontend createPetitioner to private app --- .../test/createTestApplicationContext.ts | 2 - shared/src/proxies/signUpUserProxy.ts | 2 +- shared/src/sharedAppContext.ts | 4 -- .../users/generateAccountConfirmationCode.ts | 8 ++-- web-client/src/appPublic.tsx | 2 - web-client/src/applicationContextPublic.ts | 2 - .../actions/createNewPetitionerUserAction.ts | 2 +- .../createAccountHelper.test.ts | 2 +- .../createAccountHelper.ts | 2 +- web-client/src/presenter/presenter-public.ts | 4 -- web-client/src/presenter/presenter.ts | 6 +++ .../resendVerificationLinkSequence.ts | 0 web-client/src/presenter/state-public.ts | 5 --- web-client/src/presenter/state.ts | 7 ++++ web-client/src/router.ts | 10 +++++ web-client/src/routerPublic.ts | 11 +---- web-client/src/styles/custom.scss | 23 +++++------ web-client/src/styles/overrides.scss | 4 -- .../createClientTestApplicationContext.ts | 2 - .../MessageAlert/MessageAlert.tsx | 0 web-client/src/views/AppComponent.tsx | 6 +++ web-client/src/views/AppComponentPublic.tsx | 15 ------- .../CreatePetitionerAccount.tsx | 40 +++++++++++++++++++ .../CreatePetitionerAccountForm.tsx | 15 ++++--- .../CreatePetitionerAccountInfo.tsx | 6 +-- .../RequirementsText.tsx | 10 ++++- .../VerificationSent.tsx | 6 +-- web-client/src/views/Login/Login.tsx | 2 +- .../CreatePetitionerAccount.tsx | 38 ------------------ 29 files changed, 110 insertions(+), 126 deletions(-) rename web-client/src/presenter/computeds/{Public => CreatePetitionerAccount}/createAccountHelper.test.ts (98%) rename web-client/src/presenter/computeds/{Public => CreatePetitionerAccount}/createAccountHelper.ts (95%) rename web-client/src/presenter/sequences/{Public => CreatePetitionerAccount}/resendVerificationLinkSequence.ts (100%) rename web-client/src/{views/Public => ustc-ui}/MessageAlert/MessageAlert.tsx (100%) create mode 100644 web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx rename web-client/src/views/{Public => }/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx (95%) rename web-client/src/views/{Public => }/CreatePetitionerAccount/CreatePetitionerAccountInfo.tsx (93%) rename web-client/src/views/{Public => }/CreatePetitionerAccount/RequirementsText.tsx (76%) rename web-client/src/views/{Public => }/CreatePetitionerAccount/VerificationSent.tsx (86%) delete mode 100644 web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccount.tsx diff --git a/shared/src/business/test/createTestApplicationContext.ts b/shared/src/business/test/createTestApplicationContext.ts index 96207b8617e..86128d57aea 100644 --- a/shared/src/business/test/createTestApplicationContext.ts +++ b/shared/src/business/test/createTestApplicationContext.ts @@ -20,7 +20,6 @@ import { import { DocketEntry, getServedPartiesCode } from '../entities/DocketEntry'; import { ERROR_MAP_429, - getCognitoRequestPasswordResetUrl, getPublicSiteUrl, getUniqueId, } from '../../sharedAppContext'; @@ -605,7 +604,6 @@ export const createTestApplicationContext = ({ adminUpdateUserAttributes: jest.fn(), initiateAuth: jest.fn(), }), - getCognitoRequestPasswordResetUrl, getConstants: jest.fn().mockImplementation(() => { return { ...getConstants(), diff --git a/shared/src/proxies/signUpUserProxy.ts b/shared/src/proxies/signUpUserProxy.ts index aa446b9061c..dd93e1d1187 100644 --- a/shared/src/proxies/signUpUserProxy.ts +++ b/shared/src/proxies/signUpUserProxy.ts @@ -8,6 +8,6 @@ export const signUpUserInteractor = ( return post({ applicationContext, body: user, - endpoint: '/public-api/account/create', + endpoint: '/account/create', }); }; diff --git a/shared/src/sharedAppContext.ts b/shared/src/sharedAppContext.ts index c66a7efed52..8e9d2b0f409 100644 --- a/shared/src/sharedAppContext.ts +++ b/shared/src/sharedAppContext.ts @@ -1,9 +1,5 @@ import { v4 as uuidv4 } from 'uuid'; -export const getCognitoRequestPasswordResetUrl = () => { - return process.env.COGNITO_PASSWORD_RESET_REQUEST_URL || '/'; -}; - export const getEnvironment = () => ({ dynamoDbTableName: process.env.DYNAMODB_TABLE_NAME, stage: process.env.STAGE || 'local', diff --git a/web-api/src/persistence/dynamo/users/generateAccountConfirmationCode.ts b/web-api/src/persistence/dynamo/users/generateAccountConfirmationCode.ts index b0d2a6d82d8..1b97bfb406c 100644 --- a/web-api/src/persistence/dynamo/users/generateAccountConfirmationCode.ts +++ b/web-api/src/persistence/dynamo/users/generateAccountConfirmationCode.ts @@ -1,6 +1,6 @@ +import { AccountConfirmationRecord } from '@web-api/persistence/dynamo/dynamoTypes'; import { ServerApplicationContext } from '@web-api/applicationContext'; import { put } from '../../dynamodbClientService'; -import { AccountConfirmationRecord } from '@web-api/persistence/dynamo/dynamoTypes'; export const generateAccountConfirmationCode = async ( applicationContext: ServerApplicationContext, @@ -13,11 +13,11 @@ export const generateAccountConfirmationCode = async ( const confirmationCode = applicationContext.getUniqueId(); const expireInOneDay = Date.now() / 1000 + 24 * 60 * 60; const accountConfirmationRecord: AccountConfirmationRecord = { - pk: `user|${userId}`, - sk: `account-confirmation-code`, confirmationCode, - userId, + pk: `user|${userId}`, + sk: 'account-confirmation-code', ttl: expireInOneDay, + userId, }; await put({ diff --git a/web-client/src/appPublic.tsx b/web-client/src/appPublic.tsx index 1a307216019..147251622db 100644 --- a/web-client/src/appPublic.tsx +++ b/web-client/src/appPublic.tsx @@ -86,8 +86,6 @@ const appPublic = { ); presenter.providers.applicationContext = applicationContext; - presenter.state.cognitoRequestPasswordResetUrl = - applicationContext.getCognitoRequestPasswordResetUrl(); presenter.state.constants = applicationContext.getConstants(); diff --git a/web-client/src/applicationContextPublic.ts b/web-client/src/applicationContextPublic.ts index fffd46c8def..93ae6146817 100644 --- a/web-client/src/applicationContextPublic.ts +++ b/web-client/src/applicationContextPublic.ts @@ -38,7 +38,6 @@ import { } from '../../shared/src/business/entities/cases/Case'; import { ERROR_MAP_429, - getCognitoRequestPasswordResetUrl, getEnvironment, getPublicSiteUrl, } from '../../shared/src/sharedAppContext'; @@ -165,7 +164,6 @@ const applicationContextPublic = { return process.env.API_URL || 'http://localhost:5000'; }, getCaseTitle: Case.getCaseTitle, - getCognitoRequestPasswordResetUrl, getConstants: () => frozenConstants, getCurrentUser: () => ({}), getCurrentUserToken: () => null, diff --git a/web-client/src/presenter/actions/createNewPetitionerUserAction.ts b/web-client/src/presenter/actions/createNewPetitionerUserAction.ts index 4f4e735255e..53df247ed30 100644 --- a/web-client/src/presenter/actions/createNewPetitionerUserAction.ts +++ b/web-client/src/presenter/actions/createNewPetitionerUserAction.ts @@ -1,5 +1,5 @@ import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; -import { state } from '@web-client/presenter/app-public.cerebral'; +import { state } from '@web-client/presenter/app.cerebral'; export const createNewPetitionerUserAction = async ({ applicationContext, diff --git a/web-client/src/presenter/computeds/Public/createAccountHelper.test.ts b/web-client/src/presenter/computeds/CreatePetitionerAccount/createAccountHelper.test.ts similarity index 98% rename from web-client/src/presenter/computeds/Public/createAccountHelper.test.ts rename to web-client/src/presenter/computeds/CreatePetitionerAccount/createAccountHelper.test.ts index 03ffb918c41..ce3e281b1bb 100644 --- a/web-client/src/presenter/computeds/Public/createAccountHelper.test.ts +++ b/web-client/src/presenter/computeds/CreatePetitionerAccount/createAccountHelper.test.ts @@ -1,4 +1,4 @@ -import { createAccountHelper } from '@web-client/presenter/computeds/Public/createAccountHelper'; +import { createAccountHelper } from '@web-client/presenter/computeds/CreatePetitionerAccount/createAccountHelper'; import { runCompute } from '@web-client/presenter/test.cerebral'; describe('createAccountHelper', () => { diff --git a/web-client/src/presenter/computeds/Public/createAccountHelper.ts b/web-client/src/presenter/computeds/CreatePetitionerAccount/createAccountHelper.ts similarity index 95% rename from web-client/src/presenter/computeds/Public/createAccountHelper.ts rename to web-client/src/presenter/computeds/CreatePetitionerAccount/createAccountHelper.ts index c3f81d73ec3..60016e37a5c 100644 --- a/web-client/src/presenter/computeds/Public/createAccountHelper.ts +++ b/web-client/src/presenter/computeds/CreatePetitionerAccount/createAccountHelper.ts @@ -4,7 +4,7 @@ import { NewPetitionerUserPasswordValidations, getDefaultPasswordErrors, } from '@shared/business/entities/NewPetitionerUser'; -import { state } from '@web-client/presenter/app-public.cerebral'; +import { state } from '@web-client/presenter/app.cerebral'; export type CreateAccountHelperResults = { confirmPassword: boolean; diff --git a/web-client/src/presenter/presenter-public.ts b/web-client/src/presenter/presenter-public.ts index 9f940f09954..56b4bf1d078 100644 --- a/web-client/src/presenter/presenter-public.ts +++ b/web-client/src/presenter/presenter-public.ts @@ -33,12 +33,10 @@ import { openAppMaintenanceModalSequence } from './sequences/openAppMaintenanceM import { openCaseDocumentDownloadUrlSequence } from './sequences/openCaseDocumentDownloadUrlSequence'; import { persistFormsOnReloadSequence } from './sequences/persistFormsOnReloadSequence'; import { redirectToLoginSequence } from '@web-client/presenter/sequences/Public/redirectToLoginSequence'; -import { resendVerificationLinkSequence } from '@web-client/presenter/sequences/Public/resendVerificationLinkSequence'; import { setCurrentPageErrorSequence } from './sequences/setCurrentPageErrorSequence'; import { showMaintenancePageDecorator } from './utilities/showMaintenancePageDecorator'; import { showMoreResultsSequence } from './sequences/showMoreResultsSequence'; import { sortTodaysOrdersSequence } from './sequences/Public/sortTodaysOrdersSequence'; -import { submitCreatePetitionerAccountFormSequence } from '@web-client/presenter/sequences/submitCreatePetitionerAccountFormSequence'; import { submitLoginSequence } from '@web-client/presenter/sequences/Login/submitLoginSequence'; import { submitPublicCaseAdvancedSearchSequence } from './sequences/Public/submitPublicCaseAdvancedSearchSequence'; import { submitPublicCaseDocketNumberSearchSequence } from './sequences/Public/submitPublicCaseDocketNumberSearchSequence'; @@ -105,10 +103,8 @@ export const presenterSequences = { openCaseDocumentDownloadUrlSequence, persistFormsOnReloadSequence, redirectToLoginSequence, - resendVerificationLinkSequence, showMoreResultsSequence, sortTodaysOrdersSequence, - submitCreatePetitionerAccountFormSequence, submitLoginSequence, submitPublicCaseAdvancedSearchSequence, submitPublicCaseDocketNumberSearchSequence, diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index a8c4312e40f..6988d854130 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -319,6 +319,7 @@ import { removeSignatureSequence } from './sequences/removeSignatureSequence'; import { removeSupportingDocumentSequence } from './sequences/removeSupportingDocumentSequence'; import { replyToMessageSequence } from './sequences/replyToMessageSequence'; import { rescanBatchSequence } from './sequences/rescanBatchSequence'; +import { resendVerificationLinkSequence } from '@web-client/presenter/sequences/CreatePetitionerAccount/resendVerificationLinkSequence'; import { resetCaseMenuSequence } from './sequences/resetCaseMenuSequence'; import { resetHeaderAccordionsSequence } from './sequences/resetHeaderAccordionsSequence'; import { resetIdleTimerSequence } from './sequences/resetIdleTimerSequence'; @@ -402,6 +403,7 @@ import { submitChangeLoginAndServiceEmailSequence } from './sequences/submitChan import { submitCourtIssuedDocketEntrySequence } from './sequences/submitCourtIssuedDocketEntrySequence'; import { submitCourtIssuedOrderSequence } from './sequences/submitCourtIssuedOrderSequence'; import { submitCreateOrderModalSequence } from './sequences/submitCreateOrderModalSequence'; +import { submitCreatePetitionerAccountFormSequence } from '@web-client/presenter/sequences/submitCreatePetitionerAccountFormSequence'; import { submitEditContactSequence } from './sequences/submitEditContactSequence'; import { submitEditDeficiencyStatisticSequence } from './sequences/submitEditDeficiencyStatisticSequence'; import { submitEditDocketEntryMetaSequence } from './sequences/submitEditDocketEntryMetaSequence'; @@ -1091,6 +1093,8 @@ export const presenterSequences = { removeSupportingDocumentSequence as unknown as Function, replyToMessageSequence: replyToMessageSequence as unknown as Function, rescanBatchSequence: rescanBatchSequence as unknown as Function, + resendVerificationLinkSequence: + resendVerificationLinkSequence as unknown as Function, resetCaseMenuSequence: resetCaseMenuSequence as unknown as Function, resetHeaderAccordionsSequence: resetHeaderAccordionsSequence as unknown as Function, @@ -1229,6 +1233,8 @@ export const presenterSequences = { submitCourtIssuedOrderSequence as unknown as Function, submitCreateOrderModalSequence: submitCreateOrderModalSequence as unknown as Function, + submitCreatePetitionerAccountFormSequence: + submitCreatePetitionerAccountFormSequence as unknown as Function, submitEditContactSequence: submitEditContactSequence as unknown as Function, submitEditDeficiencyStatisticSequence: submitEditDeficiencyStatisticSequence as unknown as Function, diff --git a/web-client/src/presenter/sequences/Public/resendVerificationLinkSequence.ts b/web-client/src/presenter/sequences/CreatePetitionerAccount/resendVerificationLinkSequence.ts similarity index 100% rename from web-client/src/presenter/sequences/Public/resendVerificationLinkSequence.ts rename to web-client/src/presenter/sequences/CreatePetitionerAccount/resendVerificationLinkSequence.ts diff --git a/web-client/src/presenter/state-public.ts b/web-client/src/presenter/state-public.ts index 950f0a38c61..6d86f51f116 100644 --- a/web-client/src/presenter/state-public.ts +++ b/web-client/src/presenter/state-public.ts @@ -2,7 +2,6 @@ import { PUBLIC_DOCKET_RECORD_FILTER_OPTIONS } from '../../../shared/src/busines import { advancedDocumentSearchHelper } from './computeds/AdvancedSearch/advancedDocumentSearchHelper'; import { advancedSearchHelper } from './computeds/AdvancedSearch/advancedSearchHelper'; import { caseSearchByNameHelper } from './computeds/AdvancedSearch/CaseSearchByNameHelper'; -import { createAccountHelper } from './computeds/Public/createAccountHelper'; import { headerPublicHelper } from '@web-client/presenter/computeds/headerPublicHelper'; import { loadingHelper } from './computeds/loadingHelper'; import { menuHelper } from './computeds/menuHelper'; @@ -18,7 +17,6 @@ const computeds = { advancedSearchHelper, alertHelper: publicAlertHelper, caseSearchByNameHelper, - createAccountHelper, headerPublicHelper, loadingHelper, menuHelper, @@ -35,8 +33,6 @@ export const baseState = { alertError: null, alertSuccess: null, caseDetail: {} as RawPublicCase, - cognito: { email: '' }, - cognitoRequestPasswordResetUrl: '', cognitoResendVerificationLinkUrl: '', commonUI: { showBetaBar: true, @@ -62,7 +58,6 @@ export const baseState = { docketRecordFilter: PUBLIC_DOCKET_RECORD_FILTER_OPTIONS.allDocuments, docketRecordSort: {}, }, - showConfirmPassword: false, showPassword: false, todaysOpinions: [], todaysOrders: { diff --git a/web-client/src/presenter/state.ts b/web-client/src/presenter/state.ts index 26e71acd7d8..4fed82f4b71 100644 --- a/web-client/src/presenter/state.ts +++ b/web-client/src/presenter/state.ts @@ -42,6 +42,7 @@ import { completeDocumentTypeSectionHelper } from './computeds/completeDocumentT import { confirmInitiateServiceModalHelper } from './computeds/confirmInitiateServiceModalHelper'; import { contactsHelper } from './computeds/contactsHelper'; import { correspondenceViewerHelper } from './computeds/correspondenceViewerHelper'; +import { createAccountHelper } from '@web-client/presenter/computeds/CreatePetitionerAccount/createAccountHelper'; import { createMessageModalHelper } from './computeds/createMessageModalHelper'; import { createOrderHelper } from './computeds/createOrderHelper'; import { createPractitionerUserHelper } from './computeds/createPractitionerUserHelper'; @@ -255,6 +256,9 @@ export const computeds = { correspondenceViewerHelper as unknown as ReturnType< typeof correspondenceViewerHelper >, + createAccountHelper: createAccountHelper as unknown as ReturnType< + typeof createAccountHelper + >, createMessageModalHelper: createMessageModalHelper as unknown as ReturnType< typeof createMessageModalHelper >, @@ -570,6 +574,8 @@ export const baseState = { clientConnectionId: '', closedCases: [] as TAssociatedCase[], cognito: {} as any, + cognitoRequestPasswordResetUrl: + process.env.COGNITO_PASSWORD_RESET_REQUEST_URL, completeForm: {}, constants: {} as ReturnType, currentJudges: [], @@ -712,6 +718,7 @@ export const baseState = { todaysOrdersSort: [], }, setSelectedConsolidatedCasesToMultiDocketOn: false, + showConfirmPassword: false, showPassword: false, showValidation: false, submittedAndCavCases: { diff --git a/web-client/src/router.ts b/web-client/src/router.ts index 076efd4fc19..6c8dc35e7cb 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -1116,6 +1116,16 @@ const router = { app.getSequence('gotoLoginSequence')(); }); + route('/create-account/petitioner', () => { + setPageTitle('Account Registration'); + app.getSequence('goToCreatePetitionerAccountSequence')(); + }); + + route('/create-account/verification-sent', () => { + setPageTitle('Verification Sent'); + app.getSequence('goToVerificationSentSequence')(); + }); + registerRoute( '/before-filing-a-petition', ifHasAccess({ app }, () => { diff --git a/web-client/src/routerPublic.ts b/web-client/src/routerPublic.ts index e5c5ae012d3..58425203834 100644 --- a/web-client/src/routerPublic.ts +++ b/web-client/src/routerPublic.ts @@ -31,16 +31,6 @@ const router = { app.getSequence('gotoPublicCaseDetailSequence')({ docketNumber }); }); - route('/create-account/petitioner', () => { - setPageTitle('Account Registration'); - app.getSequence('goToCreatePetitionerAccountSequence')(); - }); - - route('/create-account/verification-sent', () => { - setPageTitle('Verification Sent'); - app.getSequence('goToVerificationSentSequence')(); - }); - route('/case-detail/*/printable-docket-record', docketNumber => { setPageTitle(`Docket ${docketNumber}`); app.getSequence('gotoPublicPrintableDocketRecordSequence')({ @@ -78,6 +68,7 @@ const router = { return app.getSequence('gotoContactSequence')(); }); + // TODO 10007 Does this need to be updated to move to private app? route('/email-verification-success', () => { setPageTitle('Email Verification Success'); return app.getSequence('gotoPublicEmailVerificationSuccessSequence')(); diff --git a/web-client/src/styles/custom.scss b/web-client/src/styles/custom.scss index dde825adafe..e897c6b045d 100644 --- a/web-client/src/styles/custom.scss +++ b/web-client/src/styles/custom.scss @@ -990,12 +990,9 @@ header.usa-header { .background-blue { background-color: color($theme-color-primary-darker); - } -.floating-card-pages { - background-color: color($theme-color-primary-darker); - +.create-petitioner-account { .usa-label { margin-top: 15px; margin-bottom: 10px; @@ -1003,16 +1000,16 @@ header.usa-header { } } -.requirement-text{ - line-height: 1.43; +.requirement-text { + line-height: 1.43; - &.valid-requirement{ - color: $color-green - } + &.valid-requirement { + color: $color-green; + } - &.invalid-requirement{ - color: color($theme-color-secondary-vivid) - } + &.invalid-requirement { + color: color($theme-color-secondary-vivid); + } } .create-petitioner-form { @@ -1021,7 +1018,7 @@ header.usa-header { max-width: unset; } - h1, + h1, h2 { font-family: inherit; } diff --git a/web-client/src/styles/overrides.scss b/web-client/src/styles/overrides.scss index 2acf1d27d84..51124075e93 100644 --- a/web-client/src/styles/overrides.scss +++ b/web-client/src/styles/overrides.scss @@ -301,10 +301,6 @@ option:first-child { margin-top: 1rem !important; } -.margin-bottom-10 { - margin-bottom: 5rem !important; -} - .margin-top-10 { margin-top: 7.7rem; } diff --git a/web-client/src/test/createClientTestApplicationContext.ts b/web-client/src/test/createClientTestApplicationContext.ts index ba056109ed6..1f7535341fe 100644 --- a/web-client/src/test/createClientTestApplicationContext.ts +++ b/web-client/src/test/createClientTestApplicationContext.ts @@ -22,7 +22,6 @@ import { } from '@shared/business/entities/DocketEntry'; import { ERROR_MAP_429, - getCognitoRequestPasswordResetUrl, getPublicSiteUrl, getUniqueId, } from '@shared/sharedAppContext'; @@ -570,7 +569,6 @@ const createTestApplicationContext = () => { promise: jest.fn(), }), }), - getCognitoRequestPasswordResetUrl, getConstants: jest.fn().mockImplementation(() => { return { ...getConstants(), diff --git a/web-client/src/views/Public/MessageAlert/MessageAlert.tsx b/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx similarity index 100% rename from web-client/src/views/Public/MessageAlert/MessageAlert.tsx rename to web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx diff --git a/web-client/src/views/AppComponent.tsx b/web-client/src/views/AppComponent.tsx index 3635bca0732..7bfd0b000b9 100644 --- a/web-client/src/views/AppComponent.tsx +++ b/web-client/src/views/AppComponent.tsx @@ -23,6 +23,7 @@ import { Contact } from './Contact'; import { ContactEdit } from './ContactEdit'; import { CourtIssuedDocketEntry } from './CourtIssuedDocketEntry/CourtIssuedDocketEntry'; import { CreateOrder } from './CreateOrder/CreateOrder'; +import { CreatePetitionerAccount } from '@web-client/views/CreatePetitionerAccount/CreatePetitionerAccount'; import { CreatePractitionerUser } from './Practitioners/CreatePractitionerUser'; import { CustomCaseReport } from './CustomCaseReport/CustomCaseReport'; import { DashboardChambers } from './Dashboards/DashboardChambers'; @@ -91,6 +92,7 @@ import { UploadCourtIssuedDocument } from './UploadCourtIssuedDocument/UploadCou import { UsaBanner } from './UsaBanner'; import { UserContactEdit } from './UserContactEdit'; import { UserContactEditProgress } from './UserContactEditProgress'; +import { VerificationSent } from '@web-client/views/CreatePetitionerAccount/VerificationSent'; import { WebSocketErrorModal } from './WebSocketErrorModal'; import { WorkQueue } from './WorkQueue'; import { connect } from '@web-client/presenter/shared.cerebral'; @@ -121,6 +123,7 @@ const pages = { ContactEdit, CourtIssuedDocketEntry, CreateOrder, + CreatePetitionerAccount, CreatePractitionerUser, CustomCaseReport, DashboardChambers, @@ -182,11 +185,14 @@ const pages = { UploadCourtIssuedDocument, UserContactEdit, UserContactEditProgress, + VerificationSent, WorkQueue, }; const pagesWithBlueBackground = { + CreatePetitionerAccount, Login, + VerificationSent, }; let initialPageLoaded = false; diff --git a/web-client/src/views/AppComponentPublic.tsx b/web-client/src/views/AppComponentPublic.tsx index 487de003ae7..027f9f12931 100644 --- a/web-client/src/views/AppComponentPublic.tsx +++ b/web-client/src/views/AppComponentPublic.tsx @@ -1,6 +1,5 @@ import { AppMaintenance } from './AppMaintenance'; import { Contact } from './Contact'; -import { CreatePetitionerAccount } from './Public/CreatePetitionerAccount/CreatePetitionerAccount'; import { EmailVerificationInstructions } from './Public/EmailVerificationInstructions'; import { EmailVerificationSuccess } from './Public/EmailVerificationSuccess'; import { ErrorView } from './Error'; @@ -16,7 +15,6 @@ import { PublicSearch } from './Public/PublicSearch'; import { TodaysOpinions } from './Public/TodaysOpinions'; import { TodaysOrders } from './Public/TodaysOrders'; import { UsaBanner } from './UsaBanner'; -import { VerificationSent } from './Public/CreatePetitionerAccount/VerificationSent'; import { connect } from '@web-client/presenter/shared.cerebral'; import { state } from '@web-client/presenter/app-public.cerebral'; import { useScript } from '../utilities/useScript'; @@ -38,11 +36,6 @@ const pages = { TodaysOrders, }; -const floatingCards = { - CreatePetitionerAccount, - VerificationSent, -}; - let initialPageLoaded = false; export const AppComponentPublic = connect( @@ -73,7 +66,6 @@ export const AppComponentPublic = connect( } const CurrentPage = pages[currentPage]; - const CurrentCardPage = floatingCards[currentPage]; return ( @@ -96,13 +88,6 @@ export const AppComponentPublic = connect( )} - {CurrentCardPage && ( -
-
- -
-
- )} {showHeaderAndFooter &&
} diff --git a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx new file mode 100644 index 00000000000..547963ca1a7 --- /dev/null +++ b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx @@ -0,0 +1,40 @@ +import { CreatePetitionerAccountForm } from '@web-client/views/CreatePetitionerAccount/CreatePetitionerAccountForm'; +import { CreatePetitionerAccountInfo } from '@web-client/views/CreatePetitionerAccount/CreatePetitionerAccountInfo'; +import { MessageAlert } from '@web-client/ustc-ui/MessageAlert/MessageAlert'; +import { connect } from '@web-client/presenter/shared.cerebral'; +import { state } from '@web-client/presenter/app.cerebral'; +import React from 'react'; + +export const CreatePetitionerAccount = connect( + { + alertError: state.alertError, + }, + ({ alertError }) => { + return ( + <> +
+
+ {alertError && ( +
+ +
+ )} +
+ + +
+
+
+ + ); + }, +); + +CreatePetitionerAccount.displayName = 'CreatePetitionerAccount'; diff --git a/web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx similarity index 95% rename from web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx rename to web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx index d9d11d58e3f..0feaf2a6b6e 100644 --- a/web-client/src/views/Public/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx +++ b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx @@ -1,16 +1,15 @@ import { Button } from '@web-client/ustc-ui/Button/Button'; -import { RequirementsText } from '@web-client/views/Public/CreatePetitionerAccount/RequirementsText'; -import { connect } from '@cerebral/react'; -import { sequences, state } from '@web-client/presenter/app-public.cerebral'; +import { RequirementsText } from '@web-client/views/CreatePetitionerAccount/RequirementsText'; +import { connect } from '@web-client/presenter/shared.cerebral'; +import { sequences, state } from '@web-client/presenter/app.cerebral'; import React, { useState } from 'react'; export const CreatePetitionerAccountForm = connect( { confirmPassword: state.form.confirmPassword, createAccountHelper: state.createAccountHelper, - + navigateToLoginSequence: sequences.navigateToLoginSequence, password: state.form.password, - redirectToLoginSequence: sequences.redirectToLoginSequence, showConfirmPassword: state.showConfirmPassword, showPassword: state.showPassword, submitCreatePetitionerAccountFormSequence: @@ -21,8 +20,8 @@ export const CreatePetitionerAccountForm = connect( ({ confirmPassword, createAccountHelper, + navigateToLoginSequence, password, - redirectToLoginSequence, showConfirmPassword, showPassword, submitCreatePetitionerAccountFormSequence, @@ -84,7 +83,7 @@ export const CreatePetitionerAccountForm = connect(
)} -
); diff --git a/web-client/src/views/Login/Login.tsx b/web-client/src/views/Login/Login.tsx index 2bdf5941837..dc3c78f59b0 100644 --- a/web-client/src/views/Login/Login.tsx +++ b/web-client/src/views/Login/Login.tsx @@ -10,6 +10,8 @@ export const Login = connect( alertError: state.alertError, form: state.form, loginHelper: state.loginHelper, + navigateToCreatePetitionerAccountSequence: + sequences.navigateToCreatePetitionerAccountSequence, showPassword: state.showPassword, submitLoginSequence: sequences.submitLoginSequence, toggleShowPasswordSequence: sequences.toggleShowPasswordSequence, @@ -19,6 +21,7 @@ export const Login = connect( alertError, form, loginHelper, + navigateToCreatePetitionerAccountSequence, showPassword, submitLoginSequence, toggleShowPasswordSequence, @@ -121,6 +124,10 @@ export const Login = connect( className="padding-top-0" link={true} type="button" + onClick={e => { + e.preventDefault(); + navigateToCreatePetitionerAccountSequence(); + }} > Create your account now. From c8bbb94be99ef754ff4552d90b86863c8a72dced Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Wed, 10 Jan 2024 14:59:28 -0700 Subject: [PATCH 128/700] 10007: Fix resent email confirmation, remove logs, update task list --- temp_delete_me.md | 4 +--- .../src/business/useCases/auth/loginInteractor.ts | 15 +-------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 2f0c4046f4f..85be1df3556 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -25,9 +25,7 @@ N) All tests pass (x on unit tests) - Ensure idToken lasts longer than how often we are refreshing the idToken (REFRESH_INTERVAL) - We need to handle temporary password changes on login screen. This happens when cognito forces a password update. -Confirm these.. -- disable cognito emails. -- email verification flow (just after verifying, are we going to new login with verification success message) +- API Gateway requires re-deploy so that /system/* routes do not require authorizer. - Handle what happens if a user clicks an expired confirmation email: - On login to an unconfirmed account immediately send an email to the user diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 02c3c9ad1bc..b4bafb337bc 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -22,7 +22,6 @@ export const loginInteractor = async ( refreshToken: result.AuthenticationResult!.RefreshToken!, }; } catch (err: any) { - console.log('*** api err', err); if ( err.name === 'InvalidPasswordException' || err.name === 'NotAuthorizedException' @@ -51,11 +50,6 @@ async function resendAccountConfirmation( Filter: `email = "${email}"`, UserPoolId: process.env.USER_POOL_ID, }); - console.log( - '*** user', - users.Users?.[0], - JSON.stringify(users.Users?.[0].Attributes?.[0].Value), - ); const userId = users.Users?.[0].Attributes?.[0].Value!; @@ -63,24 +57,17 @@ async function resendAccountConfirmation( .getPersistenceGateway() .getAccountConfirmationCode(applicationContext, { userId }); - console.log('*** accountConfirmationRecord', accountConfirmationRecord); - let newConfirmationCode = accountConfirmationRecord.confirmationCode; - // if doesn't exist regenerate new confirmation code if (!newConfirmationCode) { - console.log('*** generate new confirmation code'); const { confirmationCode } = await applicationContext .getPersistenceGateway() .generateAccountConfirmationCode(applicationContext, { userId }); newConfirmationCode = confirmationCode; } - // Assume exists and resend confirmation email - console.log('*** sending confirmation cod email'); - const queryString = qs.stringify( - { confirmationCode: newConfirmationCode, userId }, + { confirmationCode: newConfirmationCode, email, userId }, { encode: false }, ); From ca6884e165e47cc6ef262b40acb52742b6151ead Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Wed, 10 Jan 2024 15:44:00 -0700 Subject: [PATCH 129/700] 10007: When confirmation code has expired, tell the user to log in again --- temp_delete_me.md | 2 +- .../business/useCases/auth/confirmSignUpInteractor.ts | 4 +++- web-api/terraform/api/api.tf | 3 --- .../src/presenter/actions/confirmSignUpAction.ts | 4 +++- web-client/src/presenter/errors/ErrorFactory.ts | 2 +- web-client/src/presenter/errors/InvalidRequestError.ts | 10 ++++++---- 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 85be1df3556..19dc166ca59 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -27,7 +27,7 @@ N) All tests pass (x on unit tests) - API Gateway requires re-deploy so that /system/* routes do not require authorizer. -- Handle what happens if a user clicks an expired confirmation email: +- (KS & RR - need to review with UX) Handle what happens if a user clicks an expired confirmation email: - On login to an unconfirmed account immediately send an email to the user - Expire link after 24hours - If user clicks on an expired email then redirect them to the login and tell them to sign in so that we can send a new confirmation with a new confirmation code. diff --git a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts index 4be63c6cb48..7c7fc72679e 100644 --- a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts +++ b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts @@ -1,3 +1,4 @@ +import { InvalidRequest } from '@web-api/errors/errors'; import { ServerApplicationContext } from '@web-api/applicationContext'; export const confirmSignUpInteractor = async ( @@ -11,8 +12,9 @@ export const confirmSignUpInteractor = async ( const accountConfirmationRecord = await applicationContext .getPersistenceGateway() .getAccountConfirmationCode(applicationContext, { userId }); + if (accountConfirmationRecord.confirmationCode !== confirmationCode) { - throw new Error('confirmation code does not match'); + throw new InvalidRequest('Confirmation code expired'); } const cognito = applicationContext.getCognito(); diff --git a/web-api/terraform/api/api.tf b/web-api/terraform/api/api.tf index c451c224fd5..666694be0fe 100644 --- a/web-api/terraform/api/api.tf +++ b/web-api/terraform/api/api.tf @@ -162,9 +162,6 @@ resource "aws_api_gateway_method" "api_system_method_get" { } resource "aws_api_gateway_integration" "api_integration_system" { - depends_on = [ - aws_api_gateway_integration.api_integration_options - ] rest_api_id = aws_api_gateway_rest_api.gateway_for_api.id resource_id = aws_api_gateway_resource.api_system_proxy_resource.id http_method = aws_api_gateway_method.api_system_method_get.http_method diff --git a/web-client/src/presenter/actions/confirmSignUpAction.ts b/web-client/src/presenter/actions/confirmSignUpAction.ts index 74f22714910..28a74603b52 100644 --- a/web-client/src/presenter/actions/confirmSignUpAction.ts +++ b/web-client/src/presenter/actions/confirmSignUpAction.ts @@ -30,7 +30,9 @@ export const confirmSignUpAction = async ({ // 10007 TODO: make path.error return path.no({ alertError: { - message: 'Error confirming account', + message: + 'Please log in to have a new account verification email sent to you.', + title: 'Confirmation code expired', }, }); } diff --git a/web-client/src/presenter/errors/ErrorFactory.ts b/web-client/src/presenter/errors/ErrorFactory.ts index 3adbc677a95..5a6083317ba 100644 --- a/web-client/src/presenter/errors/ErrorFactory.ts +++ b/web-client/src/presenter/errors/ErrorFactory.ts @@ -21,7 +21,7 @@ export const ErrorFactory = { } else if (504 === responseCode) { newError = new GatewayTimeoutError(); } else if (/^4/.test(responseCode)) { - newError = new InvalidRequestError(); + newError = new InvalidRequestError(e); } else if (/^5/.test(responseCode)) { newError = new ServerInvalidResponseError(); } else if (!e.response) { diff --git a/web-client/src/presenter/errors/InvalidRequestError.ts b/web-client/src/presenter/errors/InvalidRequestError.ts index aa65e097676..6b5b7be1174 100644 --- a/web-client/src/presenter/errors/InvalidRequestError.ts +++ b/web-client/src/presenter/errors/InvalidRequestError.ts @@ -1,10 +1,12 @@ import { ActionError } from './ActionError'; export class InvalidRequestError extends ActionError { // HTTP 4xx unknown error - constructor() { - super(arguments); - this.title = 'An unexpected error has occurred'; - this.message = + constructor(e) { + const message = + (e.response && e.response.data) || 'Ensure that you are using a supported browser: Chrome, Firefox, Safari, MS Edge, or IE11 (or later)'; + super(message); + this.title = 'An unexpected error has occurred'; + this.message = message; } } From 02f49bdcb9d9b5318c3d89f58007b595217c39fc Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 11 Jan 2024 10:48:43 -0800 Subject: [PATCH 130/700] 10007: Update expiration time of refresh token to 1 day. Set custom:role on account creation --- web-api/src/business/useCases/auth/signUpUserInteractor.ts | 5 +++++ web-api/src/lambdas/auth/loginLambda.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 5801b1a2a4f..e9482986de2 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -1,5 +1,6 @@ import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; +import { ROLES } from '@shared/business/entities/EntityConstants'; import { ServerApplicationContext } from '@web-api/applicationContext'; import qs from 'qs'; @@ -56,6 +57,10 @@ export const signUpUserInteractor = async ( Name: 'name', Value: newUser.name, }, + { + Name: 'custom:role', + Value: ROLES.petitioner, + }, ], Username: newUser.email, }); diff --git a/web-api/src/lambdas/auth/loginLambda.ts b/web-api/src/lambdas/auth/loginLambda.ts index d291e60f2b3..8af823a3604 100644 --- a/web-api/src/lambdas/auth/loginLambda.ts +++ b/web-api/src/lambdas/auth/loginLambda.ts @@ -11,7 +11,7 @@ export const loginLambda = event => const expiresAt = applicationContext.getUtilities().calculateISODate({ dateString: applicationContext.getUtilities().createISODateString(), - howMuch: 29, + howMuch: 1, units: 'days', }); From cedc4a1ffdc6bb2760fffa94de7cca42a63a45ce Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 11 Jan 2024 10:49:12 -0800 Subject: [PATCH 131/700] 10007: docs --- temp_delete_me.md | 53 ++++++++--------------------------------------- 1 file changed, 9 insertions(+), 44 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 19dc166ca59..ecbdbb6edc3 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -1,56 +1,21 @@ -::: TODAY ::: -1) Confirm works on deployment -2) Finish remaining flows (functionality example: password) -N) All tests pass (x on unit tests) - - -::: STUFF TO DELETE ::: - - -::: STUFF TO UPDATE ::: -- web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts -- web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts -- web-client/integration-tests/petitionerCreatesAccount.test.ts - - ::: STUFF TO DO ::: -- finish all todos (review together - KS) -- ensure back works right (public to private and back) +- finish all todos +- ensure back button works right on login - fix tests - -- Refactor ifHasAccess Function to be handled by router + initSequence -- Refactor maintenance mode to be handled by router + initSequence. No other sequence needs to branch because of it. - + - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts + - web-client/integration-tests/petitionerCreatesAccount.test.ts - invalidate old refreshToken and idToken upon refresh. -- Ensure idToken lasts longer than how often we are refreshing the idToken (REFRESH_INTERVAL) -- We need to handle temporary password changes on login screen. This happens when cognito forces a password update. - +- We need to handle temporary password changes on login screen(when an admissions clerk creates account for practitioner. Granting e-access to a petitioner. Forgot password). This happens when cognito forces a password update. - API Gateway requires re-deploy so that /system/* routes do not require authorizer. - - (KS & RR - need to review with UX) Handle what happens if a user clicks an expired confirmation email: - On login to an unconfirmed account immediately send an email to the user - Expire link after 24hours - If user clicks on an expired email then redirect them to the login and tell them to sign in so that we can send a new confirmation with a new confirmation code. +- cognito srp auth flow. Research. +- userId, sub, email, username cognito . idk you figure it out. -- cognito srp auth flow (review together - KS) -- Look to see if we need to add custom:role and custom:userId when creating a user - - - -::: SOLO TO DO ::: -- create account (move to private - client site) - -::: ON HOLD ::: -- In refreshAuthTokenInteractor we are returning the idToken. Should this be an accessToken? Are all of our requests being authed with an idToken? - +::: SOLO TO DO::: +- Email Verification email is ugly. ::: QUESTIONS ::: -- Refresh Token TTL? (Shouldn't live for 30 days) - How long does someone need to remain logged in before being logged out? -- Revoke Refresh Token after Use - How are going to make sure our auth is secure? Run scanners or pen testing? - - -::: IDEAS ::: -- when navigating to login sequence try and exchange idToken -- ifHasAccess only does static checks and redirects. Create an initSequence which is responsible for doing all fetching for app. (exchange idToken, get feature flags, get maintenance mode, get user, startRefreshIntervalSequence) From 8d6a2f7638188ab4b4fd29db10ffe3e0b80cd676 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 11 Jan 2024 10:52:25 -0800 Subject: [PATCH 132/700] 10007: docs --- temp_delete_me.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index ecbdbb6edc3..e99ee5f0de2 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -7,7 +7,7 @@ - invalidate old refreshToken and idToken upon refresh. - We need to handle temporary password changes on login screen(when an admissions clerk creates account for practitioner. Granting e-access to a petitioner. Forgot password). This happens when cognito forces a password update. - API Gateway requires re-deploy so that /system/* routes do not require authorizer. -- (KS & RR - need to review with UX) Handle what happens if a user clicks an expired confirmation email: +- Handle what happens if a user clicks an expired confirmation email: - On login to an unconfirmed account immediately send an email to the user - Expire link after 24hours - If user clicks on an expired email then redirect them to the login and tell them to sign in so that we can send a new confirmation with a new confirmation code. From 715e53250e8d6653851e1fa2f42420b99533b5f0 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 11 Jan 2024 12:05:03 -0800 Subject: [PATCH 133/700] 10007: make api deployment depend on new /system route. --- web-api/terraform/api/api.tf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web-api/terraform/api/api.tf b/web-api/terraform/api/api.tf index 666694be0fe..c55b522199a 100644 --- a/web-api/terraform/api/api.tf +++ b/web-api/terraform/api/api.tf @@ -307,6 +307,9 @@ resource "aws_api_gateway_deployment" "api_deployment" { aws_api_gateway_integration.api_auth_integration_delete, // AUTHORIZER aws_api_gateway_authorizer.custom_authorizer, + // SYSTEM + aws_api_gateway_method.api_system_method_get, + aws_api_gateway_integration.api_integration_system ])) } From 5091cc839037df2d7931f9062dffaf1ff41b0d14 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 11 Jan 2024 12:29:12 -0800 Subject: [PATCH 134/700] 10007: Update todos --- temp_delete_me.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index e99ee5f0de2..fbd5d98110e 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -4,9 +4,8 @@ - fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - web-client/integration-tests/petitionerCreatesAccount.test.ts -- invalidate old refreshToken and idToken upon refresh. - We need to handle temporary password changes on login screen(when an admissions clerk creates account for practitioner. Granting e-access to a petitioner. Forgot password). This happens when cognito forces a password update. -- API Gateway requires re-deploy so that /system/* routes do not require authorizer. ++ (RR & ZR) API Gateway requires re-deploy so that /system/* routes do not require authorizer. - Handle what happens if a user clicks an expired confirmation email: - On login to an unconfirmed account immediately send an email to the user - Expire link after 24hours @@ -19,3 +18,9 @@ ::: QUESTIONS ::: - How are going to make sure our auth is secure? Run scanners or pen testing? + + +:::Conversations to Have::: +- When the user hits refresh, we cannot easily revoke old ID tokens when issuing a new ID token. The threat vector is limited to 1 hour though. + - This is not a problem when the user requests a new ID token because the old one has expired after an hour. + - Implementing a system around this is possible, it would require more refactoring to NOT break multi-tab workflows on DAWSON. \ No newline at end of file From b7988200f84e08f9b3fcd7984130c570758e9451 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 11 Jan 2024 12:36:30 -0800 Subject: [PATCH 135/700] 10007: Update user's role on confirmation. --- temp_delete_me.md | 2 +- .../src/business/useCases/auth/confirmSignUpInteractor.ts | 5 +++++ web-api/src/business/useCases/auth/signUpUserInteractor.ts | 5 ----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index fbd5d98110e..f33f531bca7 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -1,6 +1,6 @@ ::: STUFF TO DO ::: - finish all todos -- ensure back button works right on login +- Back button navigation does not work between public and private - fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - web-client/integration-tests/petitionerCreatesAccount.test.ts diff --git a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts index 7c7fc72679e..165252cb2bf 100644 --- a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts +++ b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts @@ -1,4 +1,5 @@ import { InvalidRequest } from '@web-api/errors/errors'; +import { ROLES } from '@shared/business/entities/EntityConstants'; import { ServerApplicationContext } from '@web-api/applicationContext'; export const confirmSignUpInteractor = async ( @@ -34,6 +35,10 @@ export const confirmSignUpInteractor = async ( Name: 'email', Value: email, }, + { + Name: 'custom:role', + Value: ROLES.petitioner, + }, ], UserPoolId: process.env.USER_POOL_ID, Username: email, diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index e9482986de2..5801b1a2a4f 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -1,6 +1,5 @@ import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; -import { ROLES } from '@shared/business/entities/EntityConstants'; import { ServerApplicationContext } from '@web-api/applicationContext'; import qs from 'qs'; @@ -57,10 +56,6 @@ export const signUpUserInteractor = async ( Name: 'name', Value: newUser.name, }, - { - Name: 'custom:role', - Value: ROLES.petitioner, - }, ], Username: newUser.email, }); From 062356e4e73894fae823aa12c59a39616e0254cc Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Thu, 11 Jan 2024 15:46:57 -0600 Subject: [PATCH 136/700] 10007: fix petitionerCreatesAccount test --- temp_delete_me.md | 5 +- .../business/useCases/auth/loginInteractor.ts | 15 ++++- .../useCases/auth/signUpUserInteractor.ts | 2 + .../petitionerCreatesAccount.test.ts | 63 ++++++++++--------- web-client/src/router.ts | 4 +- 5 files changed, 53 insertions(+), 36 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index f33f531bca7..5d7a7c568bb 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -23,4 +23,7 @@ :::Conversations to Have::: - When the user hits refresh, we cannot easily revoke old ID tokens when issuing a new ID token. The threat vector is limited to 1 hour though. - This is not a problem when the user requests a new ID token because the old one has expired after an hour. - - Implementing a system around this is possible, it would require more refactoring to NOT break multi-tab workflows on DAWSON. \ No newline at end of file + - Implementing a system around this is possible, it would require more refactoring to NOT break multi-tab workflows on DAWSON. + +::: WIP ::: +- Create helper function to get userId from Cognito response diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index b4bafb337bc..00633883daf 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -46,12 +46,23 @@ async function resendAccountConfirmation( const cognito = applicationContext.getCognito(); const users = await cognito.listUsers({ - AttributesToGet: ['sub'], + AttributesToGet: ['sub', 'custom:userId'], Filter: `email = "${email}"`, UserPoolId: process.env.USER_POOL_ID, }); - const userId = users.Users?.[0].Attributes?.[0].Value!; + // TODO: extract to utility + const userId: string = + (users.Users?.[0].Attributes?.find(element => { + if (element.Name === 'custom:userId') { + return element.Value; + } + }) as unknown as string) || + (users.Users?.[0].Attributes?.find(element => { + if (element.Name === 'sub') { + return element.Value; + } + })! as unknown as string); const accountConfirmationRecord = await applicationContext .getPersistenceGateway() diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 5801b1a2a4f..1aab9afec15 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -60,8 +60,10 @@ export const signUpUserInteractor = async ( Username: newUser.email, }); + // Todo: use 'new' helper function to signify that this _could_ be custom:userId const userId = result.UserSub!; + //TODO: ensure userId is standardized/consistent const { confirmationCode } = await applicationContext .getPersistenceGateway() .generateAccountConfirmationCode(applicationContext, { userId }); diff --git a/web-client/integration-tests/petitionerCreatesAccount.test.ts b/web-client/integration-tests/petitionerCreatesAccount.test.ts index 211f54cc5b0..4c23e331fd1 100644 --- a/web-client/integration-tests/petitionerCreatesAccount.test.ts +++ b/web-client/integration-tests/petitionerCreatesAccount.test.ts @@ -1,13 +1,10 @@ import { faker } from '@faker-js/faker'; import { setupTest as setupTestPrivate } from './helpers'; -import { setupTest as setupTestPublic } from '../integration-tests-public/helpers'; import { userSuccessfullyUpdatesEmailAddress } from './journey/userSuccessfullyUpdatesEmailAddress'; import { userVerifiesUpdatedEmailAddress } from './journey/userVerifiesUpdatedEmailAddress'; -// TODO: 10007 - we need to implement force password change -describe.skip('Petitioner creates new account', () => { +describe('Petitioner creates new account', () => { const cerebralTestPrivate = setupTestPrivate(); - const cerebralTestPublic = setupTestPublic(); afterAll(() => { cerebralTestPrivate.closeSocket(); @@ -17,42 +14,48 @@ describe.skip('Petitioner creates new account', () => { const updatedEmailAddress = `${faker.internet.userName()}@example.com`; const name = 'Test Petitioner Cognito'; const password = 'aA1!aaaa'; - const standardizedConfirmationCode = '123456'; - const expectedVerificationLink = `/confirm-signup?confirmationCode=${standardizedConfirmationCode}&email=${userName}`; + let testConfirmationCode; + let testUserId; it('petitioner creates a new account', async () => { - await cerebralTestPublic.runSequence('goToCreatePetitionerAccountSequence'); + await cerebralTestPrivate.runSequence( + 'goToCreatePetitionerAccountSequence', + ); - await cerebralTestPublic.runSequence('updateFormValueSequence', { + await cerebralTestPrivate.runSequence('updateFormValueSequence', { key: 'name', value: name, }); - await cerebralTestPublic.runSequence('updateFormValueSequence', { + await cerebralTestPrivate.runSequence('updateFormValueSequence', { key: 'email', value: userName, }); - await cerebralTestPublic.runSequence('updateFormValueSequence', { + await cerebralTestPrivate.runSequence('updateFormValueSequence', { key: 'password', value: password, }); - await cerebralTestPublic.runSequence('updateFormValueSequence', { + await cerebralTestPrivate.runSequence('updateFormValueSequence', { key: 'confirmPassword', value: password, }); - await cerebralTestPublic.runSequence( + const result = await cerebralTestPrivate.runSequence( 'submitCreatePetitionerAccountFormSequence', ); + const { confirmationCode, userId } = result['1'].output; + testConfirmationCode = confirmationCode; + testUserId = userId; + const expectedVerificationLink = `http://localhost:1234/confirm-signup?confirmationCode=${confirmationCode}&email=${userName}&userId=${testUserId}`; - expect(cerebralTestPublic.getState('currentPage')).toEqual( + expect(cerebralTestPrivate.getState('currentPage')).toEqual( 'VerificationSent', ); //THIS IS FOR LOCAL VERIFICATION ONLY - expect(cerebralTestPublic.getState('alertSuccess')).toMatchObject({ + expect(cerebralTestPrivate.getState('alertSuccess')).toMatchObject({ alertType: 'success', message: `New user account created successfully for ${userName}! Please click the link below to verify your email address.
Verify Email Address`, title: 'Account Created Locally', @@ -60,16 +63,16 @@ describe.skip('Petitioner creates new account', () => { }); it('petitioner follows verification link to confirm new account', async () => { - await cerebralTestPublic.runSequence('confirmSignUpSequence', { - confirmationCode: standardizedConfirmationCode, - userEmail: userName, + await cerebralTestPrivate.runSequence('confirmSignUpSequence', { + confirmationCode: testConfirmationCode, + email: userName, + userId: testUserId, }); - expect(cerebralTestPublic.getState('alertSuccess')).toMatchObject( + expect(cerebralTestPrivate.getState('alertSuccess')).toMatchObject( expect.objectContaining({ - alertType: 'success', message: - 'Your registration has been confirmed! You will be redirected shortly!', - title: 'Account Confirmed Locally', + 'Your email address is verified. You can now sign in to DAWSON.', + title: 'Email address verified', }), ); }); @@ -84,11 +87,10 @@ describe.skip('Petitioner creates new account', () => { value: password, }); - // TODO 10007 - // await cerebralTestPrivate.runSequence('loginWithCognitoLocalSequence', { - // code: userName, - // password, - // }); + await cerebralTestPrivate.runSequence('submitLoginSequence', { + email: userName, + password, + }); expect(cerebralTestPrivate.getState('currentPage')).toEqual( 'DashboardPetitioner', @@ -116,11 +118,10 @@ describe.skip('Petitioner creates new account', () => { value: password, }); - // TODO 10007 - // await cerebralTestPrivate.runSequence('loginWithCognitoLocalSequence', { - // code: updatedEmailAddress, - // password, - // }); + await cerebralTestPrivate.runSequence('submitLoginSequence', { + email: updatedEmailAddress, + password, + }); expect(cerebralTestPrivate.getState('currentPage')).toEqual( 'DashboardPetitioner', diff --git a/web-client/src/router.ts b/web-client/src/router.ts index 44079d59b1a..eecc990935f 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -1117,12 +1117,12 @@ const router = { app.getSequence('gotoLoginSequence')(); }); - route('/create-account/petitioner', () => { + registerRoute('/create-account/petitioner', () => { setPageTitle('Account Registration'); app.getSequence('goToCreatePetitionerAccountSequence')(); }); - route('/create-account/verification-sent', () => { + registerRoute('/create-account/verification-sent', () => { setPageTitle('Verification Sent'); app.getSequence('goToVerificationSentSequence')(); }); From d1ff6640b1fcfb11786f13582249ad90761b9e77 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Thu, 11 Jan 2024 14:46:45 -0800 Subject: [PATCH 137/700] 10007: Fix warning notification when user tries to create an account that already exists --- temp_delete_me.md | 8 +-- .../useCases/auth/confirmSignUpInteractor.ts | 1 + .../actions/createNewPetitionerUserAction.ts | 67 ++++++++---------- ...bmitCreatePetitionerAccountFormSequence.ts | 2 + .../src/ustc-ui/MessageAlert/MessageAlert.tsx | 1 + .../AccountAlreadyExistsWarning.tsx | 68 +++++++++++++++++++ .../CreatePetitionerAccount.tsx | 44 +++++------- .../CreatePetitionerAccountForm.tsx | 7 +- 8 files changed, 123 insertions(+), 75 deletions(-) create mode 100644 web-client/src/views/CreatePetitionerAccount/AccountAlreadyExistsWarning.tsx diff --git a/temp_delete_me.md b/temp_delete_me.md index f33f531bca7..dc7b295029d 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -1,7 +1,7 @@ ::: STUFF TO DO ::: -- finish all todos +- Finish all todos - Back button navigation does not work between public and private -- fix tests +- Fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - web-client/integration-tests/petitionerCreatesAccount.test.ts - We need to handle temporary password changes on login screen(when an admissions clerk creates account for practitioner. Granting e-access to a petitioner. Forgot password). This happens when cognito forces a password update. @@ -10,7 +10,7 @@ - On login to an unconfirmed account immediately send an email to the user - Expire link after 24hours - If user clicks on an expired email then redirect them to the login and tell them to sign in so that we can send a new confirmation with a new confirmation code. -- cognito srp auth flow. Research. +- Cognito srp auth flow. Research. - userId, sub, email, username cognito . idk you figure it out. ::: SOLO TO DO::: @@ -20,7 +20,7 @@ - How are going to make sure our auth is secure? Run scanners or pen testing? -:::Conversations to Have::: +::: CONVERSATIONS TO HAVE ::: - When the user hits refresh, we cannot easily revoke old ID tokens when issuing a new ID token. The threat vector is limited to 1 hour though. - This is not a problem when the user requests a new ID token because the old one has expired after an hour. - Implementing a system around this is possible, it would require more refactoring to NOT break multi-tab workflows on DAWSON. \ No newline at end of file diff --git a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts index 165252cb2bf..13048835eab 100644 --- a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts +++ b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts @@ -15,6 +15,7 @@ export const confirmSignUpInteractor = async ( .getAccountConfirmationCode(applicationContext, { userId }); if (accountConfirmationRecord.confirmationCode !== confirmationCode) { + // TODO 10007: log when this happens for UX throw new InvalidRequest('Confirmation code expired'); } diff --git a/web-client/src/presenter/actions/createNewPetitionerUserAction.ts b/web-client/src/presenter/actions/createNewPetitionerUserAction.ts index 53df247ed30..7fb45b8e309 100644 --- a/web-client/src/presenter/actions/createNewPetitionerUserAction.ts +++ b/web-client/src/presenter/actions/createNewPetitionerUserAction.ts @@ -15,48 +15,37 @@ export const createNewPetitionerUserAction = async ({ get(state.form), ).toRawObject(); - const cognitoRequestPasswordResetUrl = get( - state.cognitoRequestPasswordResetUrl, - ); + try { + const response = await applicationContext + .getUseCases() + .signUpUserInteractor(applicationContext, { + user: petitionerAccountForm, + }); - const response = await applicationContext - .getUseCases() - .signUpUserInteractor(applicationContext, { - user: petitionerAccountForm, - }) - .catch(e => errorHandler(e, cognitoRequestPasswordResetUrl)); - - if (response.alertError) { - return path.error(response); - } - return path.success(response); -}; - -const errorHandler = (e, cognitoRequestPasswordResetUrl) => { - const originalErrorMessage = e?.originalError?.response?.data; - if (originalErrorMessage === 'User already exists') { - return { - alertError: { - alertType: 'warning', - message: `This email address is already associated with an account. You can log in here. If you forgot your password, you can request a password reset.`, - title: 'Email address already has an account', - }, - }; - } else if (originalErrorMessage === 'User exists, email unconfirmed') { - return { + return path.success(response); + } catch (err) { + const originalErrorMessage = err?.originalError?.response?.data; + if (originalErrorMessage === 'User already exists') { + return path.warning({ + alertWarning: { + title: 'Email address already has an account', + }, + }); + } else if (originalErrorMessage === 'User exists, email unconfirmed') { + return path.error({ + alertError: { + message: + "The email address is associated with an account but is not verified. We sent an email with a link to verify the email address. If you don't see it, check your spam folder. If you're still having trouble, please contact dawson.support@ustaxcourt.gov.", + title: 'Email address not verified', + }, + }); + } + return path.error({ alertError: { - alertType: 'error', message: - "The email address is associated with an account but is not verified. We sent an email with a link to verify the email address. If you don't see it, check your spam folder. If you're still having trouble, please contact dawson.support@ustaxcourt.gov.", - title: 'Email address not verified', + 'Could not create user account, please contact DAWSON user support', + title: 'Error creating account', }, - }; + }); } - return { - alertError: { - message: - 'Could not create user account, please contact DAWSON user support', - title: 'Error creating account', - }, - }; }; diff --git a/web-client/src/presenter/sequences/submitCreatePetitionerAccountFormSequence.ts b/web-client/src/presenter/sequences/submitCreatePetitionerAccountFormSequence.ts index eda162065ac..44b839bbd79 100644 --- a/web-client/src/presenter/sequences/submitCreatePetitionerAccountFormSequence.ts +++ b/web-client/src/presenter/sequences/submitCreatePetitionerAccountFormSequence.ts @@ -5,6 +5,7 @@ import { createNewPetitionerUserAction } from '@web-client/presenter/actions/cre import { navigateToVerificationSentAction } from '@web-client/presenter/actions/navigateToVerificationSentAction'; import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertErrorAction'; import { setAlertSuccessAction } from '@web-client/presenter/actions/setAlertSuccessAction'; +import { setAlertWarningAction } from '@web-client/presenter/actions/setAlertWarningAction'; import { setNewAccountEmailInStateAction } from '@web-client/presenter/actions/setNewAccountEmailInStateAction'; import { showProgressSequenceDecorator } from '../utilities/showProgressSequenceDecorator'; @@ -20,5 +21,6 @@ export const submitCreatePetitionerAccountFormSequence = [ setNewAccountEmailInStateAction, navigateToVerificationSentAction, ]), + warning: [setAlertWarningAction], }, ]; diff --git a/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx b/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx index 5b2469f4c78..e3b9a5f9d50 100644 --- a/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx +++ b/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useRef } from 'react'; // 10007 TODO: Do we need this? Can we use ErrorNotification? +// Need ability to add bullet point list export const MessageAlert = ({ alertType = 'error', message, title }) => { const alertTypeClassName = { error: 'usa-alert--error', diff --git a/web-client/src/views/CreatePetitionerAccount/AccountAlreadyExistsWarning.tsx b/web-client/src/views/CreatePetitionerAccount/AccountAlreadyExistsWarning.tsx new file mode 100644 index 00000000000..4329dd65a51 --- /dev/null +++ b/web-client/src/views/CreatePetitionerAccount/AccountAlreadyExistsWarning.tsx @@ -0,0 +1,68 @@ +import { connect } from '@web-client/presenter/shared.cerebral'; +import { sequences } from '@web-client/presenter/app.cerebral'; +import { state } from '@web-client/presenter/app.cerebral'; +import React, { useEffect, useRef } from 'react'; +import classNames from 'classnames'; + +export const AccountAlreadyExistsWarning = connect( + { + alertWarning: state.alertWarning, + cognitoRequestPasswordResetUrl: state.cognitoRequestPasswordResetUrl, + dismissAlertSequence: sequences.dismissAlertSequence, + }, + function WarningNotification({ + alertWarning, + cognitoRequestPasswordResetUrl, + }) { + const notificationRef = useRef(null); + + useEffect(() => { + const notification = notificationRef.current; + if (notification) { + window.scrollTo(0, 0); + } + }); + + return ( + <> + {alertWarning && ( +
+
+
+
+
+

+ Email address already has an account +

+

+ This email address is already associated with an account. + You can log in here. If you forgot + your password, you can{' '} + + {' '} + request a password reset + + . +

+
+
+
+
+
+ )} + + ); + }, +); + +AccountAlreadyExistsWarning.displayName = 'AccountAlreadyExistsWarning'; diff --git a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx index 789060c16c3..979d9c93390 100644 --- a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx +++ b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx @@ -1,38 +1,30 @@ +import { AccountAlreadyExistsWarning } from '@web-client/views/CreatePetitionerAccount/AccountAlreadyExistsWarning'; import { CreatePetitionerAccountForm } from '@web-client/views/CreatePetitionerAccount/CreatePetitionerAccountForm'; import { CreatePetitionerAccountInfo } from '@web-client/views/CreatePetitionerAccount/CreatePetitionerAccountInfo'; -import { MessageAlert } from '@web-client/ustc-ui/MessageAlert/MessageAlert'; +import { ErrorNotification } from '@web-client/views/ErrorNotification'; import { connect } from '@web-client/presenter/shared.cerebral'; -import { state } from '@web-client/presenter/app.cerebral'; import React from 'react'; -export const CreatePetitionerAccount = connect( - { - alertError: state.alertError, - }, - ({ alertError }) => { - return ( - <> -
- {alertError && ( -
- +export const CreatePetitionerAccount = connect({}, () => { + return ( + <> +
+
+
+
+ +
- )} -
+
+ +
- - ); - }, -); +
+ + ); +}); CreatePetitionerAccount.displayName = 'CreatePetitionerAccount'; diff --git a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx index 0feaf2a6b6e..2baf5702098 100644 --- a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx +++ b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx @@ -34,12 +34,7 @@ export const CreatePetitionerAccountForm = connect( return ( <>
From 3b5cd844a02ffe524fca95c91b7cc5a80c869fd8 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Thu, 11 Jan 2024 17:14:47 -0600 Subject: [PATCH 138/700] 10007: WIP fix admins clerk creates practitioner account & unify userId --- temp_delete_me.md | 1 - .../business/useCases/auth/loginInteractor.ts | 15 +- .../cognito/getCognitoUserIdByEmail.ts | 1 + .../users/createOrUpdatePractitionerUser.ts | 39 ++++- .../dynamo/users/createOrUpdateUser.ts | 5 +- ...onsClerkCreatesPractitionerAccount.test.ts | 140 +++++++++--------- web-client/src/routerPublic.ts | 2 +- 7 files changed, 116 insertions(+), 87 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index d63a1690329..f2f96d0ac6c 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -3,7 +3,6 @@ - Back button navigation does not work between public and private - Fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - - web-client/integration-tests/petitionerCreatesAccount.test.ts - We need to handle temporary password changes on login screen(when an admissions clerk creates account for practitioner. Granting e-access to a petitioner. Forgot password). This happens when cognito forces a password update. + (RR & ZR) API Gateway requires re-deploy so that /system/* routes do not require authorizer. - Handle what happens if a user clicks an expired confirmation email: diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 00633883daf..898299b758c 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -52,17 +52,18 @@ async function resendAccountConfirmation( }); // TODO: extract to utility - const userId: string = - (users.Users?.[0].Attributes?.find(element => { + const userIdAttribute = + users.Users?.[0].Attributes?.find(element => { if (element.Name === 'custom:userId') { - return element.Value; + return element; } - }) as unknown as string) || - (users.Users?.[0].Attributes?.find(element => { + }) || + users.Users?.[0].Attributes?.find(element => { if (element.Name === 'sub') { - return element.Value; + return element; } - })! as unknown as string); + }); + const userId = userIdAttribute?.Value!; const accountConfirmationRecord = await applicationContext .getPersistenceGateway() diff --git a/web-api/src/persistence/cognito/getCognitoUserIdByEmail.ts b/web-api/src/persistence/cognito/getCognitoUserIdByEmail.ts index 8d1e5ce54fb..f170071b602 100644 --- a/web-api/src/persistence/cognito/getCognitoUserIdByEmail.ts +++ b/web-api/src/persistence/cognito/getCognitoUserIdByEmail.ts @@ -16,6 +16,7 @@ export const getCognitoUserIdByEmail = async ({ attribute => attribute.Name === 'custom:userId', ) || {} ).Value; + // replace with sub here return customUserId || userFromCognito.Username; } catch (e) { return null; diff --git a/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.ts b/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.ts index 436ad23ae87..db186b21db4 100644 --- a/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.ts +++ b/web-api/src/persistence/dynamo/users/createOrUpdatePractitionerUser.ts @@ -94,6 +94,8 @@ export const createOrUpdatePractitionerUser = async ({ if (!userExists) { let params = { + //TODO: make 1000000% sure this works fine on deployed env + DesiredDeliveryMediums: ['EMAIL'], UserAttributes: [ { Name: 'email_verified', @@ -115,13 +117,26 @@ export const createOrUpdatePractitionerUser = async ({ UserPoolId: process.env.USER_POOL_ID, Username: userEmail, }; - + //TODO: deal with type error on params const response = await cognito.adminCreateUser(params); - + console.log('*** response', response.User.Attributes); + //replace sub here if (response && response.User && response.User.Username) { - userId = response.User.Username; + console.log('*** userId1', userId); + const userIdAttribute = // (response.User.Attributes?.find(element => { + // if (element.Name === 'custom:userId') { + // return element.Value; + // } + // }) as unknown as string) || + response.User.Attributes?.find(element => { + if (element.Name === 'sub') { + return element; + } + }); + userId = userIdAttribute?.Value!; } } else { + console.log('*** wrong if statement', userId); const response = await cognito.adminGetUser({ UserPoolId: process.env.USER_POOL_ID, Username: userEmail, @@ -135,12 +150,24 @@ export const createOrUpdatePractitionerUser = async ({ }, ], UserPoolId: process.env.USER_POOL_ID, + // and here Username: response.Username, }); - - userId = response.Username!; + // and here + userId = + (response.UserAttributes?.find(element => { + if (element.Name === 'custom:userId') { + return element.Value; + } + }) as unknown as string) || + (response.UserAttributes?.find(element => { + if (element.Name === 'sub') { + return element.Value; + } + })! as unknown as string); + console.log('*** wrong if statement2', userId); } - + console.log('*** userId3', userId); return await createUserRecords({ applicationContext, user, diff --git a/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts b/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts index 90acc7991a0..1347e3548ba 100644 --- a/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts +++ b/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts @@ -188,7 +188,7 @@ export const createOrUpdateUser = async ({ UserPoolId: userPoolId, Username: user.email, }); - + // replace sub here userId = response.User!.Username; } else { const response = await cognito.adminGetUser({ @@ -203,9 +203,10 @@ export const createOrUpdateUser = async ({ }, ], UserPoolId: userPoolId, + // and here Username: response.Username, }); - + //and here userId = response.Username; } diff --git a/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts b/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts index 428aefb3786..6e6c5a2dad6 100644 --- a/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts +++ b/web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts @@ -29,79 +29,79 @@ describe.skip('Admissions clerk creates practitioner account', () => { value: standardizedTemporaryPassword, }); - // await cerebralTest.runSequence('loginWithCognitoLocalSequence', { - // code: emailAddress, - // password: standardizedTemporaryPassword, - // }); - - await waitForLoadingComponentToHide({ cerebralTest }); - - expect(cerebralTest.getState('currentPage')).toEqual('ChangePasswordLocal'); - }); - - it('practitioner creates new password', async () => { - await cerebralTest.runSequence('updateFormValueSequence', { - key: 'email', - value: emailAddress, + await cerebralTest.runSequence('submitLoginSequence', { + email: emailAddress, + password: standardizedTemporaryPassword, }); - await cerebralTest.runSequence('updateFormValueSequence', { - key: 'newPassword', - value: password, - }); - - // TODO 10070 - await cerebralTest.runSequence('changePasswordLocalSequence'); - - expect(cerebralTest.getState('currentPage')).toEqual('Login'); - - expect(cerebralTest.getState('alertSuccess')).toMatchObject({ - message: 'Password successfully changed.', - }); - }); - - it('practitioner logs attempts to log in with invalid password', async () => { - await cerebralTest.runSequence('updateFormValueSequence', { - key: 'email', - value: emailAddress, - }); - await cerebralTest.runSequence('updateFormValueSequence', { - key: 'password', - value: 'invalidPassword', - }); - - // TODO 10007: put new login sequence - // await cerebralTest.runSequence('loginWithCognitoLocalSequence', { - // code: emailAddress, - // password: 'invalidPassword', - // }); + await waitForLoadingComponentToHide({ cerebralTest }); - expect(cerebralTest.getState('currentPage')).toEqual('Login'); - expect(cerebralTest.getState('alertError')).toEqual({ - message: 'Invalid password', - title: 'Invalid password', - }); + // expect(cerebralTest.getState('currentPage')).toEqual('ChangePasswordLocal'); }); - it('practitioner logs in successfully with new password', async () => { - await cerebralTest.runSequence('updateFormValueSequence', { - key: 'email', - value: emailAddress, - }); - await cerebralTest.runSequence('updateFormValueSequence', { - key: 'password', - value: password, - }); - - await cerebralTest.runSequence('loginWithCognitoLocalSequence', { - code: emailAddress, - password, - }); - - expect(cerebralTest.getState('currentPage')).toEqual( - 'DashboardPractitioner', - ); - expect(cerebralTest.getState('alertError')).toBeUndefined(); - expect(cerebralTest.getState('user.email')).toEqual(emailAddress); - }); + // it('practitioner creates new password', async () => { + // await cerebralTest.runSequence('updateFormValueSequence', { + // key: 'email', + // value: emailAddress, + // }); + + // await cerebralTest.runSequence('updateFormValueSequence', { + // key: 'newPassword', + // value: password, + // }); + + // // TODO 10070 + // await cerebralTest.runSequence('changePasswordLocalSequence'); + + // expect(cerebralTest.getState('currentPage')).toEqual('Login'); + + // expect(cerebralTest.getState('alertSuccess')).toMatchObject({ + // message: 'Password successfully changed.', + // }); + // }); + + // it('practitioner logs attempts to log in with invalid password', async () => { + // await cerebralTest.runSequence('updateFormValueSequence', { + // key: 'email', + // value: emailAddress, + // }); + // await cerebralTest.runSequence('updateFormValueSequence', { + // key: 'password', + // value: 'invalidPassword', + // }); + + // // TODO 10007: put new login sequence + // // await cerebralTest.runSequence('loginWithCognitoLocalSequence', { + // // code: emailAddress, + // // password: 'invalidPassword', + // // }); + + // expect(cerebralTest.getState('currentPage')).toEqual('Login'); + // expect(cerebralTest.getState('alertError')).toEqual({ + // message: 'Invalid password', + // title: 'Invalid password', + // }); + // }); + + // it('practitioner logs in successfully with new password', async () => { + // await cerebralTest.runSequence('updateFormValueSequence', { + // key: 'email', + // value: emailAddress, + // }); + // await cerebralTest.runSequence('updateFormValueSequence', { + // key: 'password', + // value: password, + // }); + + // await cerebralTest.runSequence('loginWithCognitoLocalSequence', { + // code: emailAddress, + // password, + // }); + + // expect(cerebralTest.getState('currentPage')).toEqual( + // 'DashboardPractitioner', + // ); + // expect(cerebralTest.getState('alertError')).toBeUndefined(); + // expect(cerebralTest.getState('user.email')).toEqual(emailAddress); + // }); }); diff --git a/web-client/src/routerPublic.ts b/web-client/src/routerPublic.ts index 58425203834..8504cdc6872 100644 --- a/web-client/src/routerPublic.ts +++ b/web-client/src/routerPublic.ts @@ -68,7 +68,7 @@ const router = { return app.getSequence('gotoContactSequence')(); }); - // TODO 10007 Does this need to be updated to move to private app? + // TODO 10007 Does this need to be updated to move to private app? Or remove? route('/email-verification-success', () => { setPageTitle('Email Verification Success'); return app.getSequence('gotoPublicEmailVerificationSuccessSequence')(); From fe2f36fe8a5d59b1eddb1a87934d8027fd39abfa Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 08:58:34 -0800 Subject: [PATCH 139/700] 10007: docs --- temp_delete_me.md | 1 - 1 file changed, 1 deletion(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index f2f96d0ac6c..aa28005e678 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -4,7 +4,6 @@ - Fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - We need to handle temporary password changes on login screen(when an admissions clerk creates account for practitioner. Granting e-access to a petitioner. Forgot password). This happens when cognito forces a password update. -+ (RR & ZR) API Gateway requires re-deploy so that /system/* routes do not require authorizer. - Handle what happens if a user clicks an expired confirmation email: - On login to an unconfirmed account immediately send an email to the user - Expire link after 24hours From bdec8a894ad1b4fac99a86ca781ed32d0f4323d6 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 09:58:30 -0800 Subject: [PATCH 140/700] 10007: update unit tests --- .../cognito/getCognitoUserIdByEmail.test.ts | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/web-api/src/persistence/cognito/getCognitoUserIdByEmail.test.ts b/web-api/src/persistence/cognito/getCognitoUserIdByEmail.test.ts index c10c46d28fe..14de4118b38 100644 --- a/web-api/src/persistence/cognito/getCognitoUserIdByEmail.test.ts +++ b/web-api/src/persistence/cognito/getCognitoUserIdByEmail.test.ts @@ -11,9 +11,9 @@ describe('getCognitoUserIdByEmail', () => { }; it('returns the cognito user id when there is a corresponding user with the provided email found in cognito', async () => { - applicationContext.getCognito().adminGetUser.mockReturnValue({ - promise: () => Promise.resolve(mockFoundUser), - }); + applicationContext + .getCognito() + .adminGetUser.mockResolvedValue(mockFoundUser); await expect( getCognitoUserIdByEmail({ @@ -26,12 +26,9 @@ describe('getCognitoUserIdByEmail', () => { it('returns the cognito custom user id if one is present when there is a corresponding user with the provided email found in cognito', async () => { const customMockUserId = '84cf1080-559f-4ba4-913b-27398b475bd7'; - applicationContext.getCognito().adminGetUser.mockReturnValue({ - promise: () => - Promise.resolve({ - ...mockFoundUser, - UserAttributes: [{ Name: 'custom:userId', Value: customMockUserId }], - }), + applicationContext.getCognito().adminGetUser.mockResolvedValue({ + ...mockFoundUser, + UserAttributes: [{ Name: 'custom:userId', Value: customMockUserId }], }); await expect( @@ -43,9 +40,9 @@ describe('getCognitoUserIdByEmail', () => { }); it('returns null when there is no corresponding user with the provided email found in cognito', async () => { - applicationContext.getCognito().adminGetUser.mockReturnValue({ - promise: () => Promise.reject(new Error('User does not exist')), - }); + applicationContext + .getCognito() + .adminGetUser.mockRejectedValue('There was an error'); await expect( getCognitoUserIdByEmail({ From 12189f4d7b01f40de04b12b94c0aed4a2c0651f5 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Fri, 12 Jan 2024 12:15:25 -0600 Subject: [PATCH 141/700] 10007: Add additional todo --- temp_delete_me.md | 1 + 1 file changed, 1 insertion(+) diff --git a/temp_delete_me.md b/temp_delete_me.md index aa28005e678..2b2783dd404 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -10,6 +10,7 @@ - If user clicks on an expired email then redirect them to the login and tell them to sign in so that we can send a new confirmation with a new confirmation code. - Cognito srp auth flow. Research. - userId, sub, email, username cognito . idk you figure it out. +- Ensure incorrect login message appears on hosted env, didn't see this on our last test. ::: SOLO TO DO::: - Email Verification email is ugly. From 6d8dabcd7c7b2d76a7a9d0335aaac55eed707f05 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 11:06:59 -0800 Subject: [PATCH 142/700] 10007: fix email styling. Update error notification for expired links. --- .../useCases/auth/signUpUserInteractor.ts | 41 +++++++++++-------- .../presenter/actions/confirmSignUpAction.ts | 4 +- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 1aab9afec15..aabb6b68ac9 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -101,24 +101,29 @@ const sendAccountCreationConfirmation = async ( ); const verificationLink = `https://app.${process.env.EFCMS_DOMAIN}/confirm-signup?${queryString}`; - const emailBody = - 'Welcome to DAWSON! Your account with DAWSON has been created. Use the' + - ' button below to verify your email address.' + - `` + - '


If you did not create an account with DAWSON, please contact support at ' + - 'dawson.support@ustaxcourt.gov.'; + const emailBody = `
+ + Welcome to DAWSON! Your account with DAWSON has been created. Use the button below to verify your email address. After 24 hours, this link will expire. + +
+
+ +
+
+
+ If you did not create an account with DAWSON, please contact support at dawson.support@ustaxcourt.gov. +
+
`; return await applicationContext .getMessageGateway() diff --git a/web-client/src/presenter/actions/confirmSignUpAction.ts b/web-client/src/presenter/actions/confirmSignUpAction.ts index 28a74603b52..66e920d658f 100644 --- a/web-client/src/presenter/actions/confirmSignUpAction.ts +++ b/web-client/src/presenter/actions/confirmSignUpAction.ts @@ -31,8 +31,8 @@ export const confirmSignUpAction = async ({ return path.no({ alertError: { message: - 'Please log in to have a new account verification email sent to you.', - title: 'Confirmation code expired', + 'Enter your email address and password below, then log in to be send a new verification email.', + title: 'Verification email link expired', }, }); } From dc7e60e827004b845345101cf6e5f0beb16aaebe Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 12:31:37 -0800 Subject: [PATCH 143/700] 10007: Add to verify account email warning that email is sent from unmonitored account --- web-api/src/business/useCases/auth/signUpUserInteractor.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index aabb6b68ac9..570da52e35e 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -102,8 +102,9 @@ const sendAccountCreationConfirmation = async ( const verificationLink = `https://app.${process.env.EFCMS_DOMAIN}/confirm-signup?${queryString}`; const emailBody = `
+

Welcome to DAWSON!

- Welcome to DAWSON! Your account with DAWSON has been created. Use the button below to verify your email address. After 24 hours, this link will expire. + Your account with DAWSON has been created. Use the button below to verify your email address. After 24 hours, this link will expire.
@@ -123,6 +124,10 @@ const sendAccountCreationConfirmation = async (
If you did not create an account with DAWSON, please contact support at dawson.support@ustaxcourt.gov.
+
+
+ This is an automated email. We are unable to respond to any messages to this email address. +
`; return await applicationContext From a0d68d8f62ef1b18b63bc7b74ef88dd04f49c927 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Fri, 12 Jan 2024 14:46:44 -0600 Subject: [PATCH 144/700] 10007: WIP test change password flow --- esbuildHelper.mjs | 1 + setup-local-env.sh | 1 + .../business/useCases/auth/loginInteractor.ts | 18 ++++++++++++++++-- .../dynamo/users/createNewPetitionerUser.ts | 1 + .../dynamo/users/createOrUpdateUser.ts | 2 ++ web-client/build-dist-public.sh | 1 + web-client/build-dist.sh | 5 +++++ web-client/src/app.tsx | 4 ++++ web-client/src/applicationContext.ts | 6 ++++++ .../Login/redirectToChangePasswordAction.ts | 8 ++++++++ .../actions/Login/submitLoginAction.ts | 6 ++++++ .../sequences/Login/submitLoginSequence.ts | 2 ++ web-client/src/presenter/state.ts | 4 ++-- 13 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts diff --git a/esbuildHelper.mjs b/esbuildHelper.mjs index 963e72274fb..58ab1a1c704 100644 --- a/esbuildHelper.mjs +++ b/esbuildHelper.mjs @@ -23,6 +23,7 @@ const env = { CIRCLE_SHA1: process.env.CIRCLE_SHA1, COGNITO_CLIENT_ID: process.env.COGNITO_CLIENT_ID, COGNITO_LOGIN_URL: process.env.COGNITO_LOGIN_URL, + COGNITO_PASSWORD_CHANGE_URL: process.env.COGNITO_PASSWORD_CHANGE_URL, COGNITO_PASSWORD_RESET_REQUEST_URL: process.env.COGNITO_PASSWORD_RESET_REQUEST_URL, COGNITO_REDIRECT_URI: process.env.COGNITO_REDIRECT_URI, diff --git a/setup-local-env.sh b/setup-local-env.sh index 6e0b891fe71..9a72554dd27 100755 --- a/setup-local-env.sh +++ b/setup-local-env.sh @@ -20,4 +20,5 @@ export IRS_SUPERUSER_EMAIL=irs-superuser@example.com export USER_POOL_ID='local_2pHzece7' export COGNITO_CLIENT_ID='bvjrggnd3co403c0aahscinne' export DISABLE_EMAILS=true +export COGNITO_PASSWORD_CHANGE_URL='test_url' export ENV=local diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 898299b758c..4e974262406 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -16,23 +16,37 @@ export const loginInteractor = async ( ClientId: applicationContext.environment.cognitoClientId, }); + console.log('*** result', result); + + if ( + result.ChallengeName && + result.ChallengeName === 'NEW_PASSWORD_REQUIRED' + ) { + console.log('NEW_PASSWORD_REQUIRED'); + const PasswordChangeError = new Error('NewPasswordRequired'); + PasswordChangeError.name = 'NewPasswordRequired'; + throw PasswordChangeError; + } + return { accessToken: result.AuthenticationResult!.AccessToken!, idToken: result.AuthenticationResult!.IdToken!, refreshToken: result.AuthenticationResult!.RefreshToken!, }; } catch (err: any) { + console.log('*** err', err); + if ( err.name === 'InvalidPasswordException' || err.name === 'NotAuthorizedException' ) { - throw new UnknownUserError('Invalid Username or Password'); + throw new UnknownUserError('Invalid Username or Password'); //401 } if (err.name === 'UserNotConfirmedException') { await resendAccountConfirmation(applicationContext, email); - throw new UnauthorizedError('User is unconfirmed'); + throw new UnauthorizedError('User is unconfirmed'); //403 } throw err; diff --git a/web-api/src/persistence/dynamo/users/createNewPetitionerUser.ts b/web-api/src/persistence/dynamo/users/createNewPetitionerUser.ts index 07a0e8e3ab6..1ad11e56d79 100644 --- a/web-api/src/persistence/dynamo/users/createNewPetitionerUser.ts +++ b/web-api/src/persistence/dynamo/users/createNewPetitionerUser.ts @@ -41,6 +41,7 @@ export const createNewPetitionerUser = async ({ const { userId } = user; const input: AdminCreateUserCommandInput = { + DesiredDeliveryMediums: ['EMAIL'], UserAttributes: [ { Name: 'email_verified', diff --git a/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts b/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts index 1347e3548ba..511194dbb0c 100644 --- a/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts +++ b/web-api/src/persistence/dynamo/users/createOrUpdateUser.ts @@ -165,6 +165,8 @@ export const createOrUpdateUser = async ({ if (!userExists) { const response = await cognito.adminCreateUser({ + //TODO: make 1000000% sure this works fine on deployed env + DesiredDeliveryMediums: ['EMAIL'], MessageAction: 'SUPPRESS', TemporaryPassword: password, UserAttributes: [ diff --git a/web-client/build-dist-public.sh b/web-client/build-dist-public.sh index 9232cfa17f2..624fcf0ea46 100755 --- a/web-client/build-dist-public.sh +++ b/web-client/build-dist-public.sh @@ -16,6 +16,7 @@ USER_POOL_ID=$(aws cognito-idp list-user-pools --query "UserPools[?Name == 'efcm CLIENT_ID=$(aws cognito-idp list-user-pool-clients --user-pool-id "${USER_POOL_ID}" --query "UserPoolClients[?ClientName == 'client'].ClientId | [0]" --max-results 30 --region "${REGION}" --output text) +# TODO: remove later? COGNITO_PASSWORD_RESET_REQUEST_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/forgotPassword?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" STAGE="${CLIENT_STAGE}" \ diff --git a/web-client/build-dist.sh b/web-client/build-dist.sh index c6daeab0aca..39fce4696a9 100755 --- a/web-client/build-dist.sh +++ b/web-client/build-dist.sh @@ -21,6 +21,9 @@ CLIENT_ID=$(aws cognito-idp list-user-pool-clients --user-pool-id "${USER_POOL_I COGNITO_LOGIN_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" COGNITO_TOKEN_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/oauth2/token" +COGNITO_PASSWORD_RESET_REQUEST_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/forgotPassword?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" +COGNITO_PASSWORD_CHANGE_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com//changePassword?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" + if [[ -z "${DYNAMSOFT_URL_OVERRIDE}" ]]; then SCANNER_RESOURCE_URI="https://dynamsoft-lib.${EFCMS_DOMAIN}/Dynamic%20Web%20TWAIN%20SDK%2017.2.5/Resources" else @@ -29,6 +32,8 @@ fi STAGE="${CLIENT_STAGE}" \ COGNITO_LOGIN_URL="${COGNITO_LOGIN_URL}" \ + COGNITO_PASSWORD_CHANGE_URL="${COGNITO_PASSWORD_CHANGE_URL}" \ + COGNITO_PASSWORD_RESET_REQUEST_URL="${COGNITO_PASSWORD_RESET_REQUEST_URL}" \ CIRCLE_SHA1="${CIRCLE_SHA1}" \ EFCMS_DOMAIN="${EFCMS_DOMAIN}" \ SESSION_TIMEOUT="${SESSION_TIMEOUT}" \ diff --git a/web-client/src/app.tsx b/web-client/src/app.tsx index e937967b094..127269ee7fa 100644 --- a/web-client/src/app.tsx +++ b/web-client/src/app.tsx @@ -142,6 +142,10 @@ const app = { return value; }); presenter.state.constants = applicationContext.getConstants(); + presenter.state.cognitoPasswordChange = + applicationContext.getCognitoPasswordChangeUrl(); + presenter.state.cognitoRequestPasswordResetUrl = + applicationContext.getCognitoResetPasswordUrl(); presenter.state.clientConnectionId = applicationContext.getUniqueId(); diff --git a/web-client/src/applicationContext.ts b/web-client/src/applicationContext.ts index 98f1cf2acb8..b2c328fc1f6 100644 --- a/web-client/src/applicationContext.ts +++ b/web-client/src/applicationContext.ts @@ -645,6 +645,12 @@ const applicationContext = { return broadcastChannel; }, getCaseTitle: Case.getCaseTitle, + getCognitoPasswordChangeUrl: () => { + return process.env.COGNITO_PASSWORD_CHANGE_URL || 'noop'; + }, + getCognitoResetPasswordUrl: () => { + return process.env.COGNITO_PASSWORD_RESET_REQUEST_URL || 'noop'; + }, getConstants: () => appConstants, getCurrentUser, getCurrentUserPermissions: () => { diff --git a/web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts b/web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts new file mode 100644 index 00000000000..fdeff6433b0 --- /dev/null +++ b/web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts @@ -0,0 +1,8 @@ +import { state } from '@web-client/presenter/app.cerebral'; + +export const redirectToChangePasswordAction = ({ get, router }) => { + const a = get(state.cognitoPasswordChange); + console.log(`get(state.cognitoPasswordChange)[${a}]`); + + router.externalRoute(get(state.cognitoPasswordChange)); +}; diff --git a/web-client/src/presenter/actions/Login/submitLoginAction.ts b/web-client/src/presenter/actions/Login/submitLoginAction.ts index 33472c24c89..0ac9d2e1ba5 100644 --- a/web-client/src/presenter/actions/Login/submitLoginAction.ts +++ b/web-client/src/presenter/actions/Login/submitLoginAction.ts @@ -16,8 +16,14 @@ export const submitLoginAction = async ({ .getUseCases() .loginInteractor(applicationContext, { email, password }); + console.log('*** after submit login action'); return path.success({ accessToken, idToken, refreshToken }); } catch (err: any) { + console.log('**** err from submit login', err); + if (err.message === 'NewPasswordRequired') { + return path.changePassword(); + } + if (err.responseCode === 401) { return path.error({ alertError: { diff --git a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts index cbd4b25d65a..64e93250309 100644 --- a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts @@ -2,6 +2,7 @@ import { clearFormAction } from '@web-client/presenter/actions/clearFormAction'; import { decodeTokenAction } from '@web-client/presenter/actions/decodeTokenAction'; import { getUserAction } from '@web-client/presenter/actions/getUserAction'; import { navigateToPathAction } from '@web-client/presenter/actions/navigateToPathAction'; +import { redirectToChangePasswordAction } from '@web-client/presenter/actions/Login/redirectToChangePasswordAction'; import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertErrorAction'; import { setTokenAction } from '@web-client/presenter/actions/Login/setTokenAction'; import { setUserAction } from '@web-client/presenter/actions/setUserAction'; @@ -11,6 +12,7 @@ import { submitLoginAction } from '@web-client/presenter/actions/Login/submitLog export const submitLoginSequence = [ submitLoginAction, { + changePassword: [redirectToChangePasswordAction], error: [setAlertErrorAction], success: [ clearFormAction, diff --git a/web-client/src/presenter/state.ts b/web-client/src/presenter/state.ts index 4fed82f4b71..b21ed11fc92 100644 --- a/web-client/src/presenter/state.ts +++ b/web-client/src/presenter/state.ts @@ -574,8 +574,8 @@ export const baseState = { clientConnectionId: '', closedCases: [] as TAssociatedCase[], cognito: {} as any, - cognitoRequestPasswordResetUrl: - process.env.COGNITO_PASSWORD_RESET_REQUEST_URL, + cognitoPasswordChange: '', + cognitoRequestPasswordResetUrl: '', completeForm: {}, constants: {} as ReturnType, currentJudges: [], From 91011817c8384a986090f3fb26cf13a32aab0e99 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 13:10:20 -0800 Subject: [PATCH 145/700] 10007: Extract generate and send confirmation link to users creating an account to use case helper --- .../auth/createUserConfirmation.ts | 74 +++++++++++++++++++ .../business/useCases/auth/loginInteractor.ts | 52 +------------ .../useCases/auth/signUpUserInteractor.ts | 68 ++--------------- web-api/src/getPersistenceGateway.ts | 6 +- web-api/src/getUseCaseHelpers.ts | 2 + .../users/getAccountConfirmationCode.ts | 4 +- .../refreshConfirmationCodeExpiration.ts | 29 ++++++++ 7 files changed, 121 insertions(+), 114 deletions(-) create mode 100644 web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts create mode 100644 web-api/src/persistence/dynamo/users/refreshConfirmationCodeExpiration.ts diff --git a/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts b/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts new file mode 100644 index 00000000000..10dcdc2376e --- /dev/null +++ b/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts @@ -0,0 +1,74 @@ +import { ServerApplicationContext } from '@web-api/applicationContext'; +import qs from 'qs'; + +export async function createUserConfirmation( + applicationContext: ServerApplicationContext, + { email, userId }: { email: string; userId: string }, +): Promise<{ confirmationCode: string }> { + const { confirmationCode: existingConfirmationCode } = + await applicationContext + .getPersistenceGateway() + .getAccountConfirmationCode(applicationContext, { userId }); + + let code: string; + + if (!existingConfirmationCode) { + const { confirmationCode: newConfirmationCode } = await applicationContext + .getPersistenceGateway() + .generateAccountConfirmationCode(applicationContext, { userId }); + code = newConfirmationCode; + } else { + await applicationContext + .getPersistenceGateway() + .refreshConfirmationCodeExpiration(applicationContext, { + confirmationCode: existingConfirmationCode, + userId, + }); + code = existingConfirmationCode; + } + + const queryString = qs.stringify( + { confirmationCode: code, email, userId }, + { encode: false }, + ); + const verificationLink = `https://app.${process.env.EFCMS_DOMAIN}/confirm-signup?${queryString}`; + + const emailBody = `
+

Welcome to DAWSON!

+ + Your account with DAWSON has been created. Use the button below to verify your email address. After 24 hours, this link will expire. + +
+ + + +
+
+ If you did not create an account with DAWSON, please contact support at dawson.support@ustaxcourt.gov. +
+
+
+ This is an automated email. We are unable to respond to any messages to this email address. +
+
`; + + await applicationContext + .getMessageGateway() + .sendEmailToUser(applicationContext, { + body: emailBody, + subject: 'U.S. Tax Court DAWSON Account Verification', + to: email, + }); + + return { confirmationCode: code }; +} diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 898299b758c..5faea7b4520 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -1,6 +1,5 @@ import { ServerApplicationContext } from '@web-api/applicationContext'; import { UnauthorizedError, UnknownUserError } from '@web-api/errors/errors'; -import qs from 'qs'; export const loginInteractor = async ( applicationContext: ServerApplicationContext, @@ -42,7 +41,7 @@ export const loginInteractor = async ( async function resendAccountConfirmation( applicationContext: ServerApplicationContext, email: string, -): Promise { +): Promise { const cognito = applicationContext.getCognito(); const users = await cognito.listUsers({ @@ -65,50 +64,7 @@ async function resendAccountConfirmation( }); const userId = userIdAttribute?.Value!; - const accountConfirmationRecord = await applicationContext - .getPersistenceGateway() - .getAccountConfirmationCode(applicationContext, { userId }); - - let newConfirmationCode = accountConfirmationRecord.confirmationCode; - - if (!newConfirmationCode) { - const { confirmationCode } = await applicationContext - .getPersistenceGateway() - .generateAccountConfirmationCode(applicationContext, { userId }); - newConfirmationCode = confirmationCode; - } - - const queryString = qs.stringify( - { confirmationCode: newConfirmationCode, email, userId }, - { encode: false }, - ); - - const verificationLink = `https://app.${process.env.EFCMS_DOMAIN}/confirm-signup?${queryString}`; - - const emailBody = - 'Welcome to DAWSON! Your account with DAWSON has been created. Use the' + - ' button below to verify your email address.' + - `` + - '


If you did not create an account with DAWSON, please contact support at ' + - 'dawson.support@ustaxcourt.gov.'; - - return await applicationContext - .getMessageGateway() - .sendEmailToUser(applicationContext, { - body: emailBody, - subject: 'U.S. Tax Court DAWSON Account Verification', - to: email, - }); + await applicationContext + .getUseCaseHelpers() + .createUserConfirmation(applicationContext, { email, userId }); } diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 570da52e35e..5d293850444 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -1,7 +1,6 @@ import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; import { ServerApplicationContext } from '@web-api/applicationContext'; -import qs from 'qs'; export type SignUpUserResponse = { email: string; @@ -63,16 +62,13 @@ export const signUpUserInteractor = async ( // Todo: use 'new' helper function to signify that this _could_ be custom:userId const userId = result.UserSub!; - //TODO: ensure userId is standardized/consistent + //TODO 10007: ensure userId is standardized/consistent const { confirmationCode } = await applicationContext - .getPersistenceGateway() - .generateAccountConfirmationCode(applicationContext, { userId }); - - await sendAccountCreationConfirmation(applicationContext, { - confirmationCode, - email: newUser.email, - userId, - }); + .getUseCaseHelpers() + .createUserConfirmation(applicationContext, { + email: newUser.email, + userId, + }); const signUpUserResponse: SignUpUserResponse = { email: user.email, @@ -86,55 +82,3 @@ export const signUpUserInteractor = async ( return signUpUserResponse; }; - -const sendAccountCreationConfirmation = async ( - applicationContext: ServerApplicationContext, - { - confirmationCode, - email, - userId, - }: { email: string; confirmationCode: string; userId: string }, -): Promise => { - const queryString = qs.stringify( - { confirmationCode, email, userId }, - { encode: false }, - ); - const verificationLink = `https://app.${process.env.EFCMS_DOMAIN}/confirm-signup?${queryString}`; - - const emailBody = `
-

Welcome to DAWSON!

- - Your account with DAWSON has been created. Use the button below to verify your email address. After 24 hours, this link will expire. - -
-
- -
-
-
- If you did not create an account with DAWSON, please contact support at dawson.support@ustaxcourt.gov. -
-
-
- This is an automated email. We are unable to respond to any messages to this email address. -
-
`; - - return await applicationContext - .getMessageGateway() - .sendEmailToUser(applicationContext, { - body: emailBody, - subject: 'U.S. Tax Court DAWSON Account Verification', - to: email, - }); -}; diff --git a/web-api/src/getPersistenceGateway.ts b/web-api/src/getPersistenceGateway.ts index fe27b1d21c5..7f7603ce29c 100644 --- a/web-api/src/getPersistenceGateway.ts +++ b/web-api/src/getPersistenceGateway.ts @@ -139,6 +139,7 @@ import { markMessageThreadRepliedTo } from './persistence/dynamo/messages/markMe import { persistUser } from './persistence/dynamo/users/persistUser'; import { putWorkItemInOutbox } from './persistence/dynamo/workitems/putWorkItemInOutbox'; import { putWorkItemInUsersOutbox } from './persistence/dynamo/workitems/putWorkItemInUsersOutbox'; +import { refreshConfirmationCodeExpiration } from '@web-api/persistence/dynamo/users/refreshConfirmationCodeExpiration'; import { removeCaseFromHearing } from './persistence/dynamo/trialSessions/removeCaseFromHearing'; import { removeIrsPractitionerOnCase, @@ -277,8 +278,6 @@ const gatewayMethods = { }), // methods below are not known to create or update "entity" records advancedDocumentSearch, - generateAccountConfirmationCode, - getAccountConfirmationCode, caseAdvancedSearch, casePublicSearch: casePublicSearchPersistence, createChangeOfAddressJob, @@ -299,6 +298,8 @@ const gatewayMethods = { deleteUserFromCase, deleteWorkItem, fetchEventCodesCountForJudges, + generateAccountConfirmationCode, + getAccountConfirmationCode, getAllPendingMotionDocketEntriesForJudge, getAllUsersByRole, getAllWebSocketConnections, @@ -381,6 +382,7 @@ const gatewayMethods = { getWorkItemsByWorkItemId, isEmailAvailable, isFileExists, + refreshConfirmationCodeExpiration, removeIrsPractitionerOnCase, removeLock, removePrivatePractitionerOnCase, diff --git a/web-api/src/getUseCaseHelpers.ts b/web-api/src/getUseCaseHelpers.ts index a6bc29e002c..25df2d5a881 100644 --- a/web-api/src/getUseCaseHelpers.ts +++ b/web-api/src/getUseCaseHelpers.ts @@ -13,6 +13,7 @@ import { countPagesInDocument } from '../../shared/src/business/useCaseHelper/co import { createAndServeNoticeDocketEntry } from '../../shared/src/business/useCaseHelper/docketEntry/createAndServeNoticeDocketEntry'; import { createCaseAndAssociations } from '../../shared/src/business/useCaseHelper/caseAssociation/createCaseAndAssociations'; import { createTrialSessionAndWorkingCopy } from '../../shared/src/business/useCaseHelper/trialSessions/createTrialSessionAndWorkingCopy'; +import { createUserConfirmation } from '@web-api/business/useCaseHelper/auth/createUserConfirmation'; import { createUserForContact } from '../../shared/src/business/useCaseHelper/caseAssociation/createUserForContact'; import { fileAndServeDocumentOnOneCase } from '../../shared/src/business/useCaseHelper/docketEntry/fileAndServeDocumentOnOneCase'; import { formatConsolidatedCaseCoversheetData } from '../../shared/src/business/useCaseHelper/consolidatedCases/formatConsolidatedCaseCoversheetData'; @@ -60,6 +61,7 @@ const useCaseHelpers = { createAndServeNoticeDocketEntry, createCaseAndAssociations, createTrialSessionAndWorkingCopy, + createUserConfirmation, createUserForContact, fileAndServeDocumentOnOneCase, formatConsolidatedCaseCoversheetData, diff --git a/web-api/src/persistence/dynamo/users/getAccountConfirmationCode.ts b/web-api/src/persistence/dynamo/users/getAccountConfirmationCode.ts index 4df7bf7eb72..9f4459fd861 100644 --- a/web-api/src/persistence/dynamo/users/getAccountConfirmationCode.ts +++ b/web-api/src/persistence/dynamo/users/getAccountConfirmationCode.ts @@ -1,6 +1,6 @@ +import { AccountConfirmationRecord } from '@web-api/persistence/dynamo/dynamoTypes'; import { ServerApplicationContext } from '@web-api/applicationContext'; import { get } from '../../dynamodbClientService'; -import { AccountConfirmationRecord } from '@web-api/persistence/dynamo/dynamoTypes'; export const getAccountConfirmationCode = async ( applicationContext: ServerApplicationContext, @@ -13,7 +13,7 @@ export const getAccountConfirmationCode = async ( const result: AccountConfirmationRecord = await get({ Key: { pk: `user|${userId}`, - sk: `account-confirmation-code`, + sk: 'account-confirmation-code', }, applicationContext, }); diff --git a/web-api/src/persistence/dynamo/users/refreshConfirmationCodeExpiration.ts b/web-api/src/persistence/dynamo/users/refreshConfirmationCodeExpiration.ts new file mode 100644 index 00000000000..51a40da0a17 --- /dev/null +++ b/web-api/src/persistence/dynamo/users/refreshConfirmationCodeExpiration.ts @@ -0,0 +1,29 @@ +import { AccountConfirmationRecord } from '@web-api/persistence/dynamo/dynamoTypes'; +import { ServerApplicationContext } from '@web-api/applicationContext'; +import { put } from '../../dynamodbClientService'; + +export const refreshConfirmationCodeExpiration = async ( + applicationContext: ServerApplicationContext, + { + confirmationCode, + userId, + }: { + userId: string; + confirmationCode: string; + }, +): Promise => { + const expireInOneDay = Date.now() / 1000 + 24 * 60 * 60; + + const accountConfirmationRecord: AccountConfirmationRecord = { + confirmationCode, + pk: `user|${userId}`, + sk: 'account-confirmation-code', + ttl: expireInOneDay, + userId, + }; + + await put({ + Item: accountConfirmationRecord, + applicationContext, + }); +}; From 89e367cb54ebb3a094f362d06b3e5e1b350335ef Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 13:33:59 -0800 Subject: [PATCH 146/700] 10007: add specific log for testing when user is using an expired code. --- temp_delete_me.md | 4 ++-- web-api/src/business/useCases/auth/confirmSignUpInteractor.ts | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 2b2783dd404..a31c9a487a7 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -4,7 +4,7 @@ - Fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - We need to handle temporary password changes on login screen(when an admissions clerk creates account for practitioner. Granting e-access to a petitioner. Forgot password). This happens when cognito forces a password update. -- Handle what happens if a user clicks an expired confirmation email: ++ Handle what happens if a user clicks an expired confirmation email: - On login to an unconfirmed account immediately send an email to the user - Expire link after 24hours - If user clicks on an expired email then redirect them to the login and tell them to sign in so that we can send a new confirmation with a new confirmation code. @@ -13,7 +13,7 @@ - Ensure incorrect login message appears on hosted env, didn't see this on our last test. ::: SOLO TO DO::: -- Email Verification email is ugly. ++ Email Verification email is ugly. ::: QUESTIONS ::: - How are going to make sure our auth is secure? Run scanners or pen testing? diff --git a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts index 13048835eab..379dca26e26 100644 --- a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts +++ b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts @@ -15,7 +15,9 @@ export const confirmSignUpInteractor = async ( .getAccountConfirmationCode(applicationContext, { userId }); if (accountConfirmationRecord.confirmationCode !== confirmationCode) { - // TODO 10007: log when this happens for UX + applicationContext.logger.info( + 'action: user_did_not_confirm_account_within_24hr', + ); throw new InvalidRequest('Confirmation code expired'); } From 7776d397b9dcd8fe67379c17f808d125f903fe18 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 14:05:27 -0800 Subject: [PATCH 147/700] 10007: Remove ability to resend account verification link from public page --- .../resendVerificationLinkInteractor.test.ts | 36 ------ .../resendVerificationLinkInteractor.ts | 13 -- .../public/resendVerificationLinkProxy.ts | 14 --- web-api/src/app.ts | 5 - .../resendVerificationLinkLambda.ts | 14 --- .../resendVerificationLinkAction.test.ts | 114 ------------------ .../Public/resendVerificationLinkAction.ts | 45 ------- web-client/src/presenter/presenter.ts | 3 - .../resendVerificationLinkSequence.ts | 12 -- .../VerificationSent.tsx | 15 +-- 10 files changed, 3 insertions(+), 268 deletions(-) delete mode 100644 shared/src/business/useCases/public/resendVerificationLinkInteractor.test.ts delete mode 100644 shared/src/business/useCases/public/resendVerificationLinkInteractor.ts delete mode 100644 shared/src/proxies/public/resendVerificationLinkProxy.ts delete mode 100644 web-api/src/lambdas/public-api/resendVerificationLinkLambda.ts delete mode 100644 web-client/src/presenter/actions/Public/resendVerificationLinkAction.test.ts delete mode 100644 web-client/src/presenter/actions/Public/resendVerificationLinkAction.ts delete mode 100644 web-client/src/presenter/sequences/CreatePetitionerAccount/resendVerificationLinkSequence.ts diff --git a/shared/src/business/useCases/public/resendVerificationLinkInteractor.test.ts b/shared/src/business/useCases/public/resendVerificationLinkInteractor.test.ts deleted file mode 100644 index 88638604330..00000000000 --- a/shared/src/business/useCases/public/resendVerificationLinkInteractor.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { applicationContext } from '../../test/createTestApplicationContext'; -import { resendVerificationLinkInteractor } from '@shared/business/useCases/public/resendVerificationLinkInteractor'; - -describe('resendVerificationLinkInteractor', () => { - const TEST_EMAIL = 'SOME_TEST_EMAIL@EXAMPLE.COM'; - const TEST_COGNITO_CLIENT_ID = 'TEST_COGNITO_CLIENT_ID'; - - const OLD_ENV = process.env; - - beforeEach(() => { - jest.resetModules(); - process.env = { ...OLD_ENV }; - - applicationContext.getCognito().resendConfirmationCode.mockReturnValue({ - promise: () => {}, - }); - }); - - afterAll(() => { - process.env = OLD_ENV; - }); - - it('should call our "resendConfirmationCode" method with correct data', async () => { - process.env.COGNITO_CLIENT_ID = TEST_COGNITO_CLIENT_ID; - await resendVerificationLinkInteractor(applicationContext, { - email: TEST_EMAIL, - }); - - expect( - applicationContext.getCognito().resendConfirmationCode, - ).toHaveBeenCalledWith({ - ClientId: TEST_COGNITO_CLIENT_ID, - Username: TEST_EMAIL, - }); - }); -}); diff --git a/shared/src/business/useCases/public/resendVerificationLinkInteractor.ts b/shared/src/business/useCases/public/resendVerificationLinkInteractor.ts deleted file mode 100644 index 03e2785e3c3..00000000000 --- a/shared/src/business/useCases/public/resendVerificationLinkInteractor.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; - -export const resendVerificationLinkInteractor = async ( - applicationContext: IApplicationContext, - { email }: { email: string }, -) => { - const cognito: CognitoIdentityProvider = applicationContext.getCognito(); - - return await cognito.resendConfirmationCode({ - ClientId: process.env.COGNITO_CLIENT_ID, - Username: email, - }); -}; diff --git a/shared/src/proxies/public/resendVerificationLinkProxy.ts b/shared/src/proxies/public/resendVerificationLinkProxy.ts deleted file mode 100644 index 7527c60e79f..00000000000 --- a/shared/src/proxies/public/resendVerificationLinkProxy.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { post } from '../requests'; - -export const resendVerificationLinkInteractor = ( - applicationContext, - { email }, -) => { - return post({ - applicationContext, - body: { - email, - }, - endpoint: '/auth/account/resend-verification', - }); -}; diff --git a/web-api/src/app.ts b/web-api/src/app.ts index b0fd2f40faa..8e217e2626f 100644 --- a/web-api/src/app.ts +++ b/web-api/src/app.ts @@ -138,7 +138,6 @@ import { removePetitionerAndUpdateCaptionLambda } from './lambdas/cases/removePe import { removeSignatureFromDocumentLambda } from './lambdas/documents/removeSignatureFromDocumentLambda'; import { renewIdTokenLambda } from './lambdas/auth/renewIdTokenLambda'; import { replyToMessageLambda } from './lambdas/messages/replyToMessageLambda'; -import { resendVerificationLinkLambda } from '@web-api/lambdas/public-api/resendVerificationLinkLambda'; import { runTrialSessionPlanningReportLambda } from './lambdas/trialSessions/runTrialSessionPlanningReportLambda'; import { saveCalendarNoteLambda } from './lambdas/trialSessions/saveCalendarNoteLambda'; import { saveCaseDetailInternalEditLambda } from './lambdas/cases/saveCaseDetailInternalEditLambda'; @@ -1027,10 +1026,6 @@ app.get( app.post('/auth/refresh', lambdaWrapper(renewIdTokenLambda)); app.post('/auth/confirm-signup', lambdaWrapper(confirmSignUpLambda)); app.post('/auth/account/create', lambdaWrapper(signUpUserLambda)); - app.post( - '/auth/account/resend-verification', - lambdaWrapper(resendVerificationLinkLambda), - ); } // This endpoint is used for testing purpose only which exposes the diff --git a/web-api/src/lambdas/public-api/resendVerificationLinkLambda.ts b/web-api/src/lambdas/public-api/resendVerificationLinkLambda.ts deleted file mode 100644 index be9f8d3089d..00000000000 --- a/web-api/src/lambdas/public-api/resendVerificationLinkLambda.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { genericHandler } from '../../genericHandler'; - -export const resendVerificationLinkLambda = event => - genericHandler( - event, - async ({ applicationContext }) => { - return await applicationContext - .getUseCases() - .resendVerificationLinkInteractor(applicationContext, { - ...JSON.parse(event.body), - }); - }, - { user: {} }, - ); diff --git a/web-client/src/presenter/actions/Public/resendVerificationLinkAction.test.ts b/web-client/src/presenter/actions/Public/resendVerificationLinkAction.test.ts deleted file mode 100644 index 38cb4246158..00000000000 --- a/web-client/src/presenter/actions/Public/resendVerificationLinkAction.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; -import { presenter } from '../../presenter-mock'; -import { resendVerificationLinkAction } from './resendVerificationLinkAction'; -import { runAction } from '@web-client/presenter/test.cerebral'; - -describe('resendVerificationLinkAction', () => { - const pathSuccessStub = jest.fn(); - const pathErrorStub = jest.fn(); - - const TEST_EMAIL = 'example@example.com'; - - beforeAll(() => { - presenter.providers.path = { - error: pathErrorStub, - success: pathSuccessStub, - }; - presenter.providers.applicationContext = applicationContext; - - const mockResponse = { CodeDeliveryDetails: {} }; - applicationContext - .getUseCases() - .resendVerificationLinkInteractor.mockResolvedValue(mockResponse); - }); - - it('should call the success path when we successfully call "resendVerificationLinkInteractor" with correct email', async () => { - await runAction(resendVerificationLinkAction, { - modules: { - presenter, - }, - state: { - cognito: { email: TEST_EMAIL }, - }, - }); - - expect(pathSuccessStub).toHaveBeenCalled(); - expect( - applicationContext.getUseCases().resendVerificationLinkInteractor.mock - .calls.length, - ).toEqual(1); - - expect( - applicationContext.getUseCases().resendVerificationLinkInteractor.mock - .calls[0][1], - ).toEqual({ email: TEST_EMAIL }); - }); - - it('should call the error path when we call "resendVerificationLinkInteractor" but no CodeDeliveryDetails are returned', async () => { - const mockResponse = {}; - applicationContext - .getUseCases() - .resendVerificationLinkInteractor.mockResolvedValueOnce(mockResponse); - await runAction(resendVerificationLinkAction, { - modules: { - presenter, - }, - state: { - cognito: { email: TEST_EMAIL }, - }, - }); - - expect(pathErrorStub).toHaveBeenCalledWith({ - alertError: { - alertType: 'error', - message: - 'Unable parse out the code delivery details, please contact DAWSON user support', - title: 'Unable to resend confirmation link', - }, - }); - expect( - applicationContext.getUseCases().resendVerificationLinkInteractor.mock - .calls.length, - ).toEqual(1); - - expect( - applicationContext.getUseCases().resendVerificationLinkInteractor.mock - .calls[0][1], - ).toEqual({ email: TEST_EMAIL }); - }); - - it('should call the error path when "resendVerificationLinkInteractor" throws an error', async () => { - applicationContext - .getUseCases() - .resendVerificationLinkInteractor.mockRejectedValue( - new Error('TEST ERROR'), - ); - await runAction(resendVerificationLinkAction, { - modules: { - presenter, - }, - state: { - cognito: { email: TEST_EMAIL }, - }, - }); - - expect(pathErrorStub).toHaveBeenCalledWith({ - alertError: { - alertType: 'error', - message: - 'Could not resend verification link, please contact DAWSON user support', - title: 'Unable to resend confirmation link', - }, - }); - - expect( - applicationContext.getUseCases().resendVerificationLinkInteractor.mock - .calls.length, - ).toEqual(1); - - expect( - applicationContext.getUseCases().resendVerificationLinkInteractor.mock - .calls[0][1], - ).toEqual({ email: TEST_EMAIL }); - }); -}); diff --git a/web-client/src/presenter/actions/Public/resendVerificationLinkAction.ts b/web-client/src/presenter/actions/Public/resendVerificationLinkAction.ts deleted file mode 100644 index 3246721f033..00000000000 --- a/web-client/src/presenter/actions/Public/resendVerificationLinkAction.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { ClientPublicApplicationContext } from '@web-client/applicationContextPublic'; -import { state } from '@web-client/presenter/app-public.cerebral'; - -export const resendVerificationLinkAction = async ({ - applicationContext, - get, - path, -}: ActionProps<{}, ClientPublicApplicationContext>) => { - const email = get(state.cognito.email); - - try { - const { CodeDeliveryDetails } = await applicationContext - .getUseCases() - .resendVerificationLinkInteractor(applicationContext, { - email, - }); - if (CodeDeliveryDetails) { - return path.success({ - alertSuccess: { - alertType: 'success', - message: `Verification email was sent again to ${email}.`, - title: 'Email re-sent', - }, - }); - } else { - return path.error({ - alertError: { - alertType: 'error', - message: - 'Unable parse out the code delivery details, please contact DAWSON user support', - title: 'Unable to resend confirmation link', - }, - }); - } - } catch (e) { - return path.error({ - alertError: { - alertType: 'error', - message: - 'Could not resend verification link, please contact DAWSON user support', - title: 'Unable to resend confirmation link', - }, - }); - } -}; diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 0f8d550bd2a..9a6229a70df 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -321,7 +321,6 @@ import { removeSignatureSequence } from './sequences/removeSignatureSequence'; import { removeSupportingDocumentSequence } from './sequences/removeSupportingDocumentSequence'; import { replyToMessageSequence } from './sequences/replyToMessageSequence'; import { rescanBatchSequence } from './sequences/rescanBatchSequence'; -import { resendVerificationLinkSequence } from '@web-client/presenter/sequences/CreatePetitionerAccount/resendVerificationLinkSequence'; import { resetCaseMenuSequence } from './sequences/resetCaseMenuSequence'; import { resetHeaderAccordionsSequence } from './sequences/resetHeaderAccordionsSequence'; import { resetIdleTimerSequence } from './sequences/resetIdleTimerSequence'; @@ -1098,8 +1097,6 @@ export const presenterSequences = { removeSupportingDocumentSequence as unknown as Function, replyToMessageSequence: replyToMessageSequence as unknown as Function, rescanBatchSequence: rescanBatchSequence as unknown as Function, - resendVerificationLinkSequence: - resendVerificationLinkSequence as unknown as Function, resetCaseMenuSequence: resetCaseMenuSequence as unknown as Function, resetHeaderAccordionsSequence: resetHeaderAccordionsSequence as unknown as Function, diff --git a/web-client/src/presenter/sequences/CreatePetitionerAccount/resendVerificationLinkSequence.ts b/web-client/src/presenter/sequences/CreatePetitionerAccount/resendVerificationLinkSequence.ts deleted file mode 100644 index 4200962bc48..00000000000 --- a/web-client/src/presenter/sequences/CreatePetitionerAccount/resendVerificationLinkSequence.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { navigateToVerificationSentAction } from '@web-client/presenter/actions/navigateToVerificationSentAction'; -import { resendVerificationLinkAction } from '@web-client/presenter/actions/Public/resendVerificationLinkAction'; -import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertErrorAction'; -import { setAlertSuccessAction } from '@web-client/presenter/actions/setAlertSuccessAction'; - -export const resendVerificationLinkSequence = [ - resendVerificationLinkAction, - { - error: [setAlertErrorAction], - success: [setAlertSuccessAction, navigateToVerificationSentAction], - }, -]; diff --git a/web-client/src/views/CreatePetitionerAccount/VerificationSent.tsx b/web-client/src/views/CreatePetitionerAccount/VerificationSent.tsx index 2c76335436e..6d275468db2 100644 --- a/web-client/src/views/CreatePetitionerAccount/VerificationSent.tsx +++ b/web-client/src/views/CreatePetitionerAccount/VerificationSent.tsx @@ -1,15 +1,14 @@ import { MessageAlert } from '@web-client/ustc-ui/MessageAlert/MessageAlert'; import { connect } from '@web-client/presenter/shared.cerebral'; -import { sequences, state } from '@web-client/presenter/app.cerebral'; +import { state } from '@web-client/presenter/app.cerebral'; import React from 'react'; export const VerificationSent = connect( { alertSuccess: state.alertSuccess, email: state.cognito.email, - resendVerificationLinkSequence: sequences.resendVerificationLinkSequence, }, - ({ alertSuccess, email, resendVerificationLinkSequence }) => { + ({ alertSuccess, email }) => { return (
Email address verification sent

An email to verify your email address was sent to {email}. If you - didn't receive a verification email, check your spam folder - or you can{' '} - - . + didn't receive a verification email, check your spam folder.

From 71eb94bbe1b97a1833758993c63dff424be1ba4b Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 15:19:06 -0800 Subject: [PATCH 148/700] 10007: Fix button styling. --- .../useCaseHelper/auth/createUserConfirmation.ts | 14 +------------- .../src/business/useCases/auth/loginInteractor.ts | 5 +---- .../src/presenter/actions/confirmSignUpAction.ts | 2 +- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts b/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts index 10dcdc2376e..3418b361863 100644 --- a/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts +++ b/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts @@ -39,19 +39,7 @@ export async function createUserConfirmation( Your account with DAWSON has been created. Use the button below to verify your email address. After 24 hours, this link will expire.
-
- -
+ Verify Email
If you did not create an account with DAWSON, please contact support at dawson.support@ustaxcourt.gov. diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 7afe70756c4..effa9c20f1b 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -17,10 +17,7 @@ export const loginInteractor = async ( console.log('*** result', result); - if ( - result.ChallengeName && - result.ChallengeName === 'NEW_PASSWORD_REQUIRED' - ) { + if (result?.ChallengeName === 'NEW_PASSWORD_REQUIRED') { console.log('NEW_PASSWORD_REQUIRED'); const PasswordChangeError = new Error('NewPasswordRequired'); PasswordChangeError.name = 'NewPasswordRequired'; diff --git a/web-client/src/presenter/actions/confirmSignUpAction.ts b/web-client/src/presenter/actions/confirmSignUpAction.ts index 66e920d658f..719b4f541a1 100644 --- a/web-client/src/presenter/actions/confirmSignUpAction.ts +++ b/web-client/src/presenter/actions/confirmSignUpAction.ts @@ -31,7 +31,7 @@ export const confirmSignUpAction = async ({ return path.no({ alertError: { message: - 'Enter your email address and password below, then log in to be send a new verification email.', + 'Enter your email address and password below, then log in to be sent a new verification email.', title: 'Verification email link expired', }, }); From 59faf8b20f9f1c39dc755cad9490b0bdeb667c07 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 15:19:42 -0800 Subject: [PATCH 149/700] 10007: docs --- temp_delete_me.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index a31c9a487a7..ba568e7cccf 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -13,7 +13,7 @@ - Ensure incorrect login message appears on hosted env, didn't see this on our last test. ::: SOLO TO DO::: -+ Email Verification email is ugly. + ::: QUESTIONS ::: - How are going to make sure our auth is secure? Run scanners or pen testing? @@ -23,6 +23,7 @@ - When the user hits refresh, we cannot easily revoke old ID tokens when issuing a new ID token. The threat vector is limited to 1 hour though. - This is not a problem when the user requests a new ID token because the old one has expired after an hour. - Implementing a system around this is possible, it would require more refactoring to NOT break multi-tab workflows on DAWSON. +- DOD: Refactor cognito so every account has and can be looked up by custom:userId. ::: WIP ::: -- Create helper function to get userId from Cognito response +- Create helper function to get userId from Cognito response \ No newline at end of file From 202d0196958f497e13dc6efa2f80da9dea712381 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 16:12:46 -0800 Subject: [PATCH 150/700] 10007: assign customId upon account signUp --- .../business/useCases/auth/loginInteractor.ts | 35 ++++++++++--------- .../useCases/auth/signUpUserInteractor.ts | 4 +++ web-api/src/getUseCases.ts | 2 -- .../template/lambdas/cognito-triggers.ts | 1 + web-client/src/applicationContextPublic.ts | 2 -- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index effa9c20f1b..2f675b9c670 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -1,5 +1,9 @@ +import { + NotFoundError, + UnauthorizedError, + UnknownUserError, +} from '@web-api/errors/errors'; import { ServerApplicationContext } from '@web-api/applicationContext'; -import { UnauthorizedError, UnknownUserError } from '@web-api/errors/errors'; export const loginInteractor = async ( applicationContext: ServerApplicationContext, @@ -56,26 +60,25 @@ async function resendAccountConfirmation( const cognito = applicationContext.getCognito(); const users = await cognito.listUsers({ - AttributesToGet: ['sub', 'custom:userId'], + AttributesToGet: ['custom:userId'], Filter: `email = "${email}"`, UserPoolId: process.env.USER_POOL_ID, }); - // TODO: extract to utility - const userIdAttribute = - users.Users?.[0].Attributes?.find(element => { - if (element.Name === 'custom:userId') { - return element; - } - }) || - users.Users?.[0].Attributes?.find(element => { - if (element.Name === 'sub') { - return element; - } - }); - const userId = userIdAttribute?.Value!; + const userIdAttribute = users.Users?.[0].Attributes?.find( + element => element.Name === 'custom:userId', + ); + + if (!userIdAttribute?.Value) { + throw new NotFoundError( + `Could not find user to re-send confirmation code to. ${email}`, + ); + } await applicationContext .getUseCaseHelpers() - .createUserConfirmation(applicationContext, { email, userId }); + .createUserConfirmation(applicationContext, { + email, + userId: userIdAttribute.Value, + }); } diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 5d293850444..f20f2819c74 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -55,6 +55,10 @@ export const signUpUserInteractor = async ( Name: 'name', Value: newUser.name, }, + { + Name: 'custom:userId', + Value: applicationContext.getUniqueId(), + }, ], Username: newUser.email, }); diff --git a/web-api/src/getUseCases.ts b/web-api/src/getUseCases.ts index a4b0e32d242..afd76577f5b 100644 --- a/web-api/src/getUseCases.ts +++ b/web-api/src/getUseCases.ts @@ -155,7 +155,6 @@ import { removePetitionerAndUpdateCaptionInteractor } from '../../shared/src/bus import { removeSignatureFromDocumentInteractor } from '../../shared/src/business/useCases/removeSignatureFromDocumentInteractor'; import { renewIdTokenInteractor } from './business/useCases/auth/renewIdTokenInteractor'; import { replyToMessageInteractor } from '../../shared/src/business/useCases/messages/replyToMessageInteractor'; -import { resendVerificationLinkInteractor } from '@shared/business/useCases/public/resendVerificationLinkInteractor'; import { runTrialSessionPlanningReportInteractor } from '../../shared/src/business/useCases/trialSessions/runTrialSessionPlanningReportInteractor'; import { saveCalendarNoteInteractor } from '../../shared/src/business/useCases/trialSessions/saveCalendarNoteInteractor'; import { saveCaseDetailInternalEditInteractor } from '../../shared/src/business/useCases/saveCaseDetailInternalEditInteractor'; @@ -368,7 +367,6 @@ const useCases = { removeSignatureFromDocumentInteractor, renewIdTokenInteractor, replyToMessageInteractor, - resendVerificationLinkInteractor, runTrialSessionPlanningReportInteractor, saveCalendarNoteInteractor, saveCaseDetailInternalEditInteractor, diff --git a/web-api/terraform/template/lambdas/cognito-triggers.ts b/web-api/terraform/template/lambdas/cognito-triggers.ts index 71bdf0ea8ab..9e423fb0813 100644 --- a/web-api/terraform/template/lambdas/cognito-triggers.ts +++ b/web-api/terraform/template/lambdas/cognito-triggers.ts @@ -6,6 +6,7 @@ export const handler = async event => { if (event.triggerSource === 'PostConfirmation_ConfirmSignUp') { const { email, name, sub: userId } = event.request.userAttributes; + // TODO 10007: We can replace this create petitioner account trigger and move the functionality over to our confirmSignUpInteractor. const user = await applicationContext .getUseCases() .createPetitionerAccountInteractor(applicationContext, { diff --git a/web-client/src/applicationContextPublic.ts b/web-client/src/applicationContextPublic.ts index 93ae6146817..afb4735ed52 100644 --- a/web-client/src/applicationContextPublic.ts +++ b/web-client/src/applicationContextPublic.ts @@ -78,7 +78,6 @@ import { opinionPublicSearchInteractor } from '../../shared/src/proxies/opinionP import { orderPublicSearchInteractor } from '../../shared/src/proxies/orderPublicSearchProxy'; import { removeItem } from './persistence/localStorage/removeItem'; import { removeItemInteractor } from '../../shared/src/business/useCases/removeItemInteractor'; -import { resendVerificationLinkInteractor } from '../../shared/src/proxies/public/resendVerificationLinkProxy'; import { setItem } from './persistence/localStorage/setItem'; import { setItemInteractor } from '../../shared/src/business/useCases/setItemInteractor'; import { signUpUserInteractor } from '../../shared/src/proxies/signUpUserProxy'; @@ -114,7 +113,6 @@ const allUseCases = { opinionPublicSearchInteractor, orderPublicSearchInteractor, removeItemInteractor, - resendVerificationLinkInteractor, setItemInteractor, signUpUserInteractor, validateCaseAdvancedSearchInteractor, From 9f58b7d9b4fed21a8f08bbfe78f8827c3e0992cc Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Fri, 12 Jan 2024 16:13:03 -0800 Subject: [PATCH 151/700] 10007: docs --- temp_delete_me.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/temp_delete_me.md b/temp_delete_me.md index ba568e7cccf..fc4e90baf28 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -11,12 +11,14 @@ - Cognito srp auth flow. Research. - userId, sub, email, username cognito . idk you figure it out. - Ensure incorrect login message appears on hosted env, didn't see this on our last test. +- Add progress spinner after you hit 'Login' ::: SOLO TO DO::: ::: QUESTIONS ::: - How are going to make sure our auth is secure? Run scanners or pen testing? +- What happens if someone creates an account, we deploy 10007, and THEN they try to verify it? ::: CONVERSATIONS TO HAVE ::: From e59e6ae2fdd2dafdb08528230bee8798ddd2ff17 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Mon, 15 Jan 2024 10:20:40 -0600 Subject: [PATCH 152/700] 10007: fix forgot/change password links --- web-client/build-dist.sh | 2 +- web-client/src/views/Login/Login.tsx | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/web-client/build-dist.sh b/web-client/build-dist.sh index 39fce4696a9..6c59598ebd7 100755 --- a/web-client/build-dist.sh +++ b/web-client/build-dist.sh @@ -22,7 +22,7 @@ COGNITO_LOGIN_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazonco COGNITO_TOKEN_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/oauth2/token" COGNITO_PASSWORD_RESET_REQUEST_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/forgotPassword?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" -COGNITO_PASSWORD_CHANGE_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com//changePassword?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" +COGNITO_PASSWORD_CHANGE_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/changePassword?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" if [[ -z "${DYNAMSOFT_URL_OVERRIDE}" ]]; then SCANNER_RESOURCE_URI="https://dynamsoft-lib.${EFCMS_DOMAIN}/Dynamic%20Web%20TWAIN%20SDK%2017.2.5/Resources" diff --git a/web-client/src/views/Login/Login.tsx b/web-client/src/views/Login/Login.tsx index dc3c78f59b0..9bdb7f754a0 100644 --- a/web-client/src/views/Login/Login.tsx +++ b/web-client/src/views/Login/Login.tsx @@ -8,6 +8,7 @@ import React from 'react'; export const Login = connect( { alertError: state.alertError, + cognitoRequestPasswordResetUrl: state.cognitoRequestPasswordResetUrl, form: state.form, loginHelper: state.loginHelper, navigateToCreatePetitionerAccountSequence: @@ -19,6 +20,7 @@ export const Login = connect( }, ({ alertError, + cognitoRequestPasswordResetUrl, form, loginHelper, navigateToCreatePetitionerAccountSequence, @@ -112,6 +114,7 @@ export const Login = connect(
From 0f171ce6c5256121160e1a761e7439452025ac68 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Mon, 15 Jan 2024 10:46:43 -0700 Subject: [PATCH 156/700] 10007: Allow alerts for warning and errors to set html in message --- ...itLoginAction.ts => submitLoginAction.tsx} | 15 +++- ...n.ts => createNewPetitionerUserAction.tsx} | 32 ++++++++- .../src/ustc-ui/MessageAlert/MessageAlert.tsx | 15 ++-- .../AccountAlreadyExistsWarning.tsx | 68 ------------------- .../CreatePetitionerAccount.tsx | 4 +- web-client/src/views/WarningNotification.tsx | 2 +- 6 files changed, 55 insertions(+), 81 deletions(-) rename web-client/src/presenter/actions/Login/{submitLoginAction.ts => submitLoginAction.tsx} (71%) rename web-client/src/presenter/actions/{createNewPetitionerUserAction.ts => createNewPetitionerUserAction.tsx} (57%) delete mode 100644 web-client/src/views/CreatePetitionerAccount/AccountAlreadyExistsWarning.tsx diff --git a/web-client/src/presenter/actions/Login/submitLoginAction.ts b/web-client/src/presenter/actions/Login/submitLoginAction.tsx similarity index 71% rename from web-client/src/presenter/actions/Login/submitLoginAction.ts rename to web-client/src/presenter/actions/Login/submitLoginAction.tsx index 0ac9d2e1ba5..b8973999099 100644 --- a/web-client/src/presenter/actions/Login/submitLoginAction.ts +++ b/web-client/src/presenter/actions/Login/submitLoginAction.tsx @@ -1,4 +1,5 @@ import { state } from '@web-client/presenter/app.cerebral'; +import React from 'react'; export const submitLoginAction = async ({ applicationContext, @@ -36,8 +37,18 @@ export const submitLoginAction = async ({ if (err.responseCode === 403) { return path.error({ alertError: { - message: - 'The email address is associated with an account but is not verified. We sent an email with a link to verify the email address. If you don’t see it, check your spam folder. If you’re still having trouble, email dawson.support@ustaxcourt.gov.', + message: ( + <> + The email address is associated with an account but is not + verified. We sent an email with a link to verify the email + address. If you don’t see it, check your spam folder. If you’re + still having trouble, email{' '} + + dawson.support@ustaxcourt.gov + + . + + ), title: 'Email address not verified', }, }); diff --git a/web-client/src/presenter/actions/createNewPetitionerUserAction.ts b/web-client/src/presenter/actions/createNewPetitionerUserAction.tsx similarity index 57% rename from web-client/src/presenter/actions/createNewPetitionerUserAction.ts rename to web-client/src/presenter/actions/createNewPetitionerUserAction.tsx index 7fb45b8e309..68352a8042f 100644 --- a/web-client/src/presenter/actions/createNewPetitionerUserAction.ts +++ b/web-client/src/presenter/actions/createNewPetitionerUserAction.tsx @@ -1,5 +1,6 @@ import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; import { state } from '@web-client/presenter/app.cerebral'; +import React from 'react'; export const createNewPetitionerUserAction = async ({ applicationContext, @@ -23,19 +24,44 @@ export const createNewPetitionerUserAction = async ({ }); return path.success(response); - } catch (err) { + } catch (err: any) { const originalErrorMessage = err?.originalError?.response?.data; if (originalErrorMessage === 'User already exists') { + const cognitoRequestPasswordResetUrl = get( + state.cognitoRequestPasswordResetUrl, + ); return path.warning({ alertWarning: { + message: ( + <> + This email address is already associated with an account. You can{' '} + log in here. If you forgot your password, you + can{' '} + + {' '} + request a password reset + + . + + ), title: 'Email address already has an account', }, }); } else if (originalErrorMessage === 'User exists, email unconfirmed') { return path.error({ alertError: { - message: - "The email address is associated with an account but is not verified. We sent an email with a link to verify the email address. If you don't see it, check your spam folder. If you're still having trouble, please contact dawson.support@ustaxcourt.gov.", + message: ( + <> + The email address is associated with an account but is not + verified. We sent an email with a link to verify the email + address. If you don't see it, check your spam folder. If + you're still having trouble, please contact{' '} + + dawson.support@ustaxcourt.gov + + . + + ), title: 'Email address not verified', }, }); diff --git a/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx b/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx index e3b9a5f9d50..91cb42a3bdb 100644 --- a/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx +++ b/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx @@ -2,7 +2,15 @@ import React, { useEffect, useRef } from 'react'; // 10007 TODO: Do we need this? Can we use ErrorNotification? // Need ability to add bullet point list -export const MessageAlert = ({ alertType = 'error', message, title }) => { +export const MessageAlert = ({ + alertType = 'error', + message, + title, +}: { + alertType: string; + message: React.ReactNode | string; + title: string; +}) => { const alertTypeClassName = { error: 'usa-alert--error', info: 'usa-alert--info', @@ -27,10 +35,7 @@ export const MessageAlert = ({ alertType = 'error', message, title }) => { >

{title}

-

+

{message}

); diff --git a/web-client/src/views/CreatePetitionerAccount/AccountAlreadyExistsWarning.tsx b/web-client/src/views/CreatePetitionerAccount/AccountAlreadyExistsWarning.tsx deleted file mode 100644 index 4329dd65a51..00000000000 --- a/web-client/src/views/CreatePetitionerAccount/AccountAlreadyExistsWarning.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { connect } from '@web-client/presenter/shared.cerebral'; -import { sequences } from '@web-client/presenter/app.cerebral'; -import { state } from '@web-client/presenter/app.cerebral'; -import React, { useEffect, useRef } from 'react'; -import classNames from 'classnames'; - -export const AccountAlreadyExistsWarning = connect( - { - alertWarning: state.alertWarning, - cognitoRequestPasswordResetUrl: state.cognitoRequestPasswordResetUrl, - dismissAlertSequence: sequences.dismissAlertSequence, - }, - function WarningNotification({ - alertWarning, - cognitoRequestPasswordResetUrl, - }) { - const notificationRef = useRef(null); - - useEffect(() => { - const notification = notificationRef.current; - if (notification) { - window.scrollTo(0, 0); - } - }); - - return ( - <> - {alertWarning && ( -
-
-
-
-
-

- Email address already has an account -

-

- This email address is already associated with an account. - You can log in here. If you forgot - your password, you can{' '} - - {' '} - request a password reset - - . -

-
-
-
-
-
- )} - - ); - }, -); - -AccountAlreadyExistsWarning.displayName = 'AccountAlreadyExistsWarning'; diff --git a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx index 979d9c93390..850259d1a25 100644 --- a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx +++ b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccount.tsx @@ -1,7 +1,7 @@ -import { AccountAlreadyExistsWarning } from '@web-client/views/CreatePetitionerAccount/AccountAlreadyExistsWarning'; import { CreatePetitionerAccountForm } from '@web-client/views/CreatePetitionerAccount/CreatePetitionerAccountForm'; import { CreatePetitionerAccountInfo } from '@web-client/views/CreatePetitionerAccount/CreatePetitionerAccountInfo'; import { ErrorNotification } from '@web-client/views/ErrorNotification'; +import { WarningNotification } from '@web-client/views/WarningNotification'; import { connect } from '@web-client/presenter/shared.cerebral'; import React from 'react'; @@ -13,7 +13,7 @@ export const CreatePetitionerAccount = connect({}, () => {
- +
diff --git a/web-client/src/views/WarningNotification.tsx b/web-client/src/views/WarningNotification.tsx index bc5ffb39307..75e8f65a183 100644 --- a/web-client/src/views/WarningNotification.tsx +++ b/web-client/src/views/WarningNotification.tsx @@ -18,7 +18,7 @@ export const WarningNotificationComponent = title?: string; linkUrl?: string; linkText?: string; - message: string; + message: string | React.ReactNode; dismissText?: string; dismissIcon?: string; }; From d5c33bf30815a111fbc30276669e5e8f23bb8ca7 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Mon, 15 Jan 2024 11:54:00 -0600 Subject: [PATCH 157/700] 10007: Route to public site when clicking USTC seal on login page --- web-client/src/presenter/computeds/headerHelper.ts | 1 + web-client/src/views/Header/Header.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/web-client/src/presenter/computeds/headerHelper.ts b/web-client/src/presenter/computeds/headerHelper.ts index a437bd3a471..4feed7e6a22 100644 --- a/web-client/src/presenter/computeds/headerHelper.ts +++ b/web-client/src/presenter/computeds/headerHelper.ts @@ -81,5 +81,6 @@ export const headerHelper = ( showVerifyEmailWarningNotification: !!user?.pendingEmail, unreadMessageCount, userName: user && user.name, + ustcSealLink: isLoggedIn ? '/' : applicationContext.getPublicSiteUrl(), }; }; diff --git a/web-client/src/views/Header/Header.tsx b/web-client/src/views/Header/Header.tsx index ad401c6c09b..840ea2ef7bc 100644 --- a/web-client/src/views/Header/Header.tsx +++ b/web-client/src/views/Header/Header.tsx @@ -273,7 +273,7 @@ export const Header = connect(
From 0d8345497c12019372fb7df4b5a0615b052ab64f Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Mon, 15 Jan 2024 10:55:46 -0700 Subject: [PATCH 158/700] 10007: Add todo, and remove console.logs --- temp_delete_me.md | 1 + web-api/src/business/useCases/auth/loginInteractor.ts | 5 ----- web-client/src/presenter/actions/Login/submitLoginAction.tsx | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 25f8727ecbe..c4fa0251c9b 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -10,6 +10,7 @@ - Cognito srp auth flow. Research. - userId, sub, email, username cognito . idk you figure it out. - Ensure incorrect login message appears on hosted env, didn't see this on our last test. +- Unify error handling for loginInteractor, signUpUserInteractor. err.responseCode, err.name, err.message? ::: SOLO TO DO::: diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 2f675b9c670..945f3251c95 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -19,10 +19,7 @@ export const loginInteractor = async ( ClientId: applicationContext.environment.cognitoClientId, }); - console.log('*** result', result); - if (result?.ChallengeName === 'NEW_PASSWORD_REQUIRED') { - console.log('NEW_PASSWORD_REQUIRED'); const PasswordChangeError = new Error('NewPasswordRequired'); PasswordChangeError.name = 'NewPasswordRequired'; throw PasswordChangeError; @@ -34,8 +31,6 @@ export const loginInteractor = async ( refreshToken: result.AuthenticationResult!.RefreshToken!, }; } catch (err: any) { - console.log('*** err', err); - if ( err.name === 'InvalidPasswordException' || err.name === 'NotAuthorizedException' diff --git a/web-client/src/presenter/actions/Login/submitLoginAction.tsx b/web-client/src/presenter/actions/Login/submitLoginAction.tsx index b8973999099..ef2d8742811 100644 --- a/web-client/src/presenter/actions/Login/submitLoginAction.tsx +++ b/web-client/src/presenter/actions/Login/submitLoginAction.tsx @@ -17,10 +17,8 @@ export const submitLoginAction = async ({ .getUseCases() .loginInteractor(applicationContext, { email, password }); - console.log('*** after submit login action'); return path.success({ accessToken, idToken, refreshToken }); } catch (err: any) { - console.log('**** err from submit login', err); if (err.message === 'NewPasswordRequired') { return path.changePassword(); } From 6ae3f5d8dc6dd9b19e292b6243f829eb3f08cedf Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Mon, 15 Jan 2024 11:19:25 -0700 Subject: [PATCH 159/700] 10007: Use custom:userId everywhere we can --- web-api/src/business/useCases/auth/loginInteractor.ts | 8 ++++---- .../src/business/useCases/auth/signUpUserInteractor.ts | 9 +++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 945f3251c95..fd712168ca5 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -60,11 +60,11 @@ async function resendAccountConfirmation( UserPoolId: process.env.USER_POOL_ID, }); - const userIdAttribute = users.Users?.[0].Attributes?.find( + const userId = users.Users?.[0].Attributes?.find( element => element.Name === 'custom:userId', - ); + )?.Value; - if (!userIdAttribute?.Value) { + if (!userId) { throw new NotFoundError( `Could not find user to re-send confirmation code to. ${email}`, ); @@ -74,6 +74,6 @@ async function resendAccountConfirmation( .getUseCaseHelpers() .createUserConfirmation(applicationContext, { email, - userId: userIdAttribute.Value, + userId, }); } diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index f20f2819c74..396d93d014f 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -42,8 +42,8 @@ export const signUpUserInteractor = async ( } const newUser = new NewPetitionerUser(user).validate().toRawObject(); - - const result = await cognito.signUp({ + const userId = applicationContext.getUniqueId(); + await cognito.signUp({ ClientId: process.env.COGNITO_CLIENT_ID, Password: newUser.password, UserAttributes: [ @@ -57,15 +57,12 @@ export const signUpUserInteractor = async ( }, { Name: 'custom:userId', - Value: applicationContext.getUniqueId(), + Value: userId, }, ], Username: newUser.email, }); - // Todo: use 'new' helper function to signify that this _could_ be custom:userId - const userId = result.UserSub!; - //TODO 10007: ensure userId is standardized/consistent const { confirmationCode } = await applicationContext .getUseCaseHelpers() From a675388849db3abdf10b697fddfb856d125106ff Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Mon, 15 Jan 2024 11:02:59 -0800 Subject: [PATCH 160/700] 10007: Use href property on window to change URL so history is preserved --- web-client/src/routerPublic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-client/src/routerPublic.ts b/web-client/src/routerPublic.ts index 8504cdc6872..487b43ab7c6 100644 --- a/web-client/src/routerPublic.ts +++ b/web-client/src/routerPublic.ts @@ -4,7 +4,7 @@ import route from 'riot-route'; route.base('/'); const externalRoute = path => { - window.location.replace(path); + window.location.href = path; }; const back = () => { From b6c44969082589130901340bbc82f5b050e160da Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Mon, 15 Jan 2024 11:03:45 -0800 Subject: [PATCH 161/700] 10007: Remove unused action --- ...mailVerificationInstructionsAction.test.ts | 31 ------------------- ...blicEmailVerificationInstructionsAction.ts | 14 --------- 2 files changed, 45 deletions(-) delete mode 100644 web-client/src/presenter/actions/Public/navigateToPublicEmailVerificationInstructionsAction.test.ts delete mode 100644 web-client/src/presenter/actions/Public/navigateToPublicEmailVerificationInstructionsAction.ts diff --git a/web-client/src/presenter/actions/Public/navigateToPublicEmailVerificationInstructionsAction.test.ts b/web-client/src/presenter/actions/Public/navigateToPublicEmailVerificationInstructionsAction.test.ts deleted file mode 100644 index 200d403e942..00000000000 --- a/web-client/src/presenter/actions/Public/navigateToPublicEmailVerificationInstructionsAction.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { navigateToPublicEmailVerificationInstructionsAction } from './navigateToPublicEmailVerificationInstructionsAction'; -import { presenter } from '../../presenter-public'; -import { runAction } from '@web-client/presenter/test.cerebral'; - -let externalRouteMock; -const publicSiteUrlMock = 'example.com'; - -presenter.providers.applicationContext = { - getPublicSiteUrl: () => publicSiteUrlMock, -}; - -describe('navigateToPublicEmailVerificationInstructionsAction', () => { - beforeAll(() => { - externalRouteMock = jest.fn(); - presenter.providers.router = { - externalRoute: externalRouteMock, - }; - }); - - it('Routes to the public site email-verification-instructions url', async () => { - await runAction(navigateToPublicEmailVerificationInstructionsAction, { - modules: { - presenter, - }, - }); - - expect(externalRouteMock).toHaveBeenCalledWith( - `${publicSiteUrlMock}/email-verification-instructions`, - ); - }); -}); diff --git a/web-client/src/presenter/actions/Public/navigateToPublicEmailVerificationInstructionsAction.ts b/web-client/src/presenter/actions/Public/navigateToPublicEmailVerificationInstructionsAction.ts deleted file mode 100644 index d14b6adc4a2..00000000000 --- a/web-client/src/presenter/actions/Public/navigateToPublicEmailVerificationInstructionsAction.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * calls externalRoute navigation method on the public site verify email instructions url - * - * @param {object} providers the providers object - * @param {object} providers.applicationContext the applicationContext - * @param {object} providers.router the riot.router object that is used for changing the route - */ -export const navigateToPublicEmailVerificationInstructionsAction = ({ - applicationContext, - router, -}: ActionProps) => { - const publicSiteUrl = `${applicationContext.getPublicSiteUrl()}/email-verification-instructions`; - router.externalRoute(publicSiteUrl); -}; From 2ff5786a65fd7e8bc8e013e379ee4ed3dd460b00 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Mon, 15 Jan 2024 11:14:10 -0800 Subject: [PATCH 162/700] 10007: Update task list --- temp_delete_me.md | 1 - 1 file changed, 1 deletion(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index c4fa0251c9b..3583e25dec1 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -1,6 +1,5 @@ ::: STUFF TO DO ::: - Finish all todos -- Back button navigation does not work between public and private - Fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts + Handle what happens if a user clicks an expired confirmation email: From 5ec7e295f9bf0c1ec9e7152a01e09130b0785b3a Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Mon, 15 Jan 2024 12:30:56 -0700 Subject: [PATCH 163/700] 10007: Remove Post Confirmation Lambda --- .cognito/config.json | 11 ++-- .cognito/seedCognitoLocal.ts | 2 - .../main/lambda-logs-to-elasticsearch.tf | 8 --- .../create-missing-log-groups.sh | 2 - .../main/cognito-post-confirmation.tf | 50 ------------------- web-api/src/app-local.ts | 5 +- .../useCases/auth/confirmSignUpInteractor.ts | 31 +++++++++++- web-api/switch-cognito-triggers-color.ts | 1 - web-api/terraform/api/cognito-trigger.tf | 30 ----------- .../template/lambdas/cognito-triggers.ts | 18 +------ ...kAction.ts => createConfirmLinkAction.tsx} | 13 ++++- 11 files changed, 47 insertions(+), 124 deletions(-) delete mode 100644 iam/terraform/environment-specific/main/cognito-post-confirmation.tf rename web-client/src/presenter/actions/{createConfirmLinkAction.ts => createConfirmLinkAction.tsx} (63%) diff --git a/.cognito/config.json b/.cognito/config.json index 35bbd1166f8..7357d773baf 100644 --- a/.cognito/config.json +++ b/.cognito/config.json @@ -11,19 +11,14 @@ "IssuerDomain": "http://localhost:9229" }, "TriggerFunctions": { - "PostConfirmation": "PostConfirmation_ConfirmSignUp", "PostAuthentication": "PostAuthentication_Authentication" }, "LambdaConfig": { "endpoint": "http://localhost:3011" }, "UserPoolDefaults": { - "UsernameAttributes": [ - "email" - ], - "AutoVerifiedAttributes": [ - "email" - ] + "UsernameAttributes": ["email"], + "AutoVerifiedAttributes": ["email"] }, "KMSConfig": { "credentials": { @@ -32,4 +27,4 @@ }, "region": "local" } -} \ No newline at end of file +} diff --git a/.cognito/seedCognitoLocal.ts b/.cognito/seedCognitoLocal.ts index 416df5e7a01..ac68cdfd008 100644 --- a/.cognito/seedCognitoLocal.ts +++ b/.cognito/seedCognitoLocal.ts @@ -33,7 +33,6 @@ type CognitoLocalJSON = { endpoint: string; }; TriggerFunctions: { - PostConfirmation: string; PostAuthentication: string; }; SchemaAttributes: Array<{ @@ -87,7 +86,6 @@ const cognitoLocalJSON: CognitoLocalJSON = { endpoint: 'http://localhost:9991', }, TriggerFunctions: { - PostConfirmation: 'PostConfirmation_ConfirmSignUp', PostAuthentication: 'PostAuthentication_Authentication', }, SchemaAttributes: [ diff --git a/iam/terraform/account-specific/main/lambda-logs-to-elasticsearch.tf b/iam/terraform/account-specific/main/lambda-logs-to-elasticsearch.tf index 12a50037da7..8d97e558170 100644 --- a/iam/terraform/account-specific/main/lambda-logs-to-elasticsearch.tf +++ b/iam/terraform/account-specific/main/lambda-logs-to-elasticsearch.tf @@ -61,14 +61,6 @@ resource "aws_cloudwatch_log_subscription_filter" "cognito_authorizer_filter" { log_group_name = "/aws/lambda/cognito_authorizer_lambda_${element(var.log_group_environments, count.index)}" } -resource "aws_cloudwatch_log_subscription_filter" "cognito_post_confirmation_lambda_filter" { - count = length(var.log_group_environments) - destination_arn = aws_lambda_function.logs_to_es.arn - filter_pattern = "" - name = "cognito_post_confirmation_lambda_${element(var.log_group_environments, count.index)}_filter" - log_group_name = "/aws/lambda/cognito_post_confirmation_lambda_${element(var.log_group_environments, count.index)}" -} - resource "aws_cloudwatch_log_subscription_filter" "cognito_post_authentication_lambda_filter" { count = length(var.log_group_environments) destination_arn = aws_lambda_function.logs_to_es.arn diff --git a/iam/terraform/account-specific/main/regional-log-subscription-filters/create-missing-log-groups.sh b/iam/terraform/account-specific/main/regional-log-subscription-filters/create-missing-log-groups.sh index 99ada23435a..462c5f1fb83 100755 --- a/iam/terraform/account-specific/main/regional-log-subscription-filters/create-missing-log-groups.sh +++ b/iam/terraform/account-specific/main/regional-log-subscription-filters/create-missing-log-groups.sh @@ -58,13 +58,11 @@ for ENV in "${ENVIRONMENTS[@]}"; do process_group "/aws/apigateway/gateway_api_public_${ENV}_${COLOR}" process_group "/aws/lambda/websockets_connect_${ENV}_${COLOR}" process_group "/aws/lambda/websockets_disconnect_${ENV}_${COLOR}" - process_group "/aws/lambda/cognito_post_confirmation_lambda_${ENV}_${COLOR}" process_group "/aws/lambda/cognito_post_authentication_lambda_${ENV}_${COLOR}" process_group "/aws/lambda/send_emails_${ENV}_${COLOR}" process_group "/aws/lambda/set_trial_session_${ENV}_${COLOR}" done - process_group "/aws/lambda/cognito_post_confirmation_lambda_${ENV}" process_group "/aws/ecs/clamav_fargate_${ENV}" process_group "/aws/lambda/legacy_documents_migration_lambda_${ENV}" done diff --git a/iam/terraform/environment-specific/main/cognito-post-confirmation.tf b/iam/terraform/environment-specific/main/cognito-post-confirmation.tf deleted file mode 100644 index dd7fbde28a8..00000000000 --- a/iam/terraform/environment-specific/main/cognito-post-confirmation.tf +++ /dev/null @@ -1,50 +0,0 @@ - -resource "aws_iam_role" "iam_cognito_post_confirmation_lambda_role" { - name = "iam_cognito_post_confirmation_lambda_role_${var.environment}" - - assume_role_policy = < { requestBody += chunk.toString(); }); request.on('end', async () => { - if ( - request.url?.includes('/PostAuthentication_Authentication') || - request.url?.includes('/PostConfirmation_ConfirmSignUp') - ) { + if (request.url?.includes('/PostAuthentication_Authentication')) { try { const data = JSON.parse(requestBody); await handler(data); diff --git a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts index 379dca26e26..3c981d81029 100644 --- a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts +++ b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts @@ -28,7 +28,7 @@ export const confirmSignUpInteractor = async ( Username: email, }); - await cognito.adminUpdateUserAttributes({ + const updatePetitionerAttributes = cognito.adminUpdateUserAttributes({ UserAttributes: [ { Name: 'email_verified', @@ -46,4 +46,33 @@ export const confirmSignUpInteractor = async ( UserPoolId: process.env.USER_POOL_ID, Username: email, }); + + await Promise.all([ + updatePetitionerAttributes, + createPetitionerUser(applicationContext, { email, userId }), + ]); +}; + +const createPetitionerUser = async ( + applicationContext: ServerApplicationContext, + { email, userId }: { email: string; userId: string }, +) => { + const cognito = applicationContext.getCognito(); + const users = await cognito.listUsers({ + AttributesToGet: ['name'], + Filter: `email = "${email}"`, + UserPoolId: process.env.USER_POOL_ID, + }); + + const name = users.Users?.[0].Attributes?.find( + element => element.Name === 'name', + )?.Value!; + + await applicationContext + .getUseCases() + .createPetitionerAccountInteractor(applicationContext, { + email, + name, + userId, + }); }; diff --git a/web-api/switch-cognito-triggers-color.ts b/web-api/switch-cognito-triggers-color.ts index 6eb164a2c54..696354b155e 100644 --- a/web-api/switch-cognito-triggers-color.ts +++ b/web-api/switch-cognito-triggers-color.ts @@ -50,7 +50,6 @@ const run = async () => { EmailConfiguration: poolSettings.UserPool.EmailConfiguration, LambdaConfig: { PostAuthentication: `arn:aws:lambda:us-east-1:${AWS_ACCOUNT_ID}:function:cognito_post_authentication_lambda_${ENV}_${DEPLOYING_COLOR}`, - PostConfirmation: `arn:aws:lambda:us-east-1:${AWS_ACCOUNT_ID}:function:cognito_post_confirmation_lambda_${ENV}_${DEPLOYING_COLOR}`, }, Policies: poolSettings.UserPool.Policies, UserPoolId: userPoolId, diff --git a/web-api/terraform/api/cognito-trigger.tf b/web-api/terraform/api/cognito-trigger.tf index 855428f94c9..e647660e489 100644 --- a/web-api/terraform/api/cognito-trigger.tf +++ b/web-api/terraform/api/cognito-trigger.tf @@ -11,36 +11,6 @@ resource "aws_lambda_permission" "allow_post_auth_trigger" { source_arn = var.pool_arn } -resource "aws_lambda_permission" "allow_trigger" { - statement_id = "AllowPostConfirmationExecutionFromCognito" - action = "lambda:InvokeFunction" - function_name = aws_lambda_function.cognito_post_confirmation_lambda[0].function_name - principal = "cognito-idp.amazonaws.com" - count = var.create_triggers - source_arn = var.pool_arn -} - -resource "aws_lambda_function" "cognito_post_confirmation_lambda" { - function_name = "cognito_post_confirmation_lambda_${var.environment}_${var.current_color}" - role = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/iam_cognito_post_confirmation_lambda_role_${var.environment}" - handler = "cognito-triggers.handler" - timeout = "29" - memory_size = "3008" - runtime = var.node_version - count = var.create_triggers - - depends_on = [var.triggers_object] - s3_bucket = var.lambda_bucket_id - s3_key = "triggers_${var.current_color}.js.zip" - source_code_hash = var.triggers_object_hash - - layers = var.use_layers ? [aws_lambda_layer_version.puppeteer_layer.arn] : null - - environment { - variables = var.lambda_environment - } -} - resource "aws_lambda_function" "cognito_post_authentication_lambda" { function_name = "cognito_post_authentication_lambda_${var.environment}_${var.current_color}" role = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/iam_cognito_post_authentication_lambda_role_${var.environment}" diff --git a/web-api/terraform/template/lambdas/cognito-triggers.ts b/web-api/terraform/template/lambdas/cognito-triggers.ts index 9e423fb0813..b95aa6f319c 100644 --- a/web-api/terraform/template/lambdas/cognito-triggers.ts +++ b/web-api/terraform/template/lambdas/cognito-triggers.ts @@ -3,23 +3,7 @@ import { createApplicationContext } from '../../../src/applicationContext'; export const handler = async event => { const applicationContext = createApplicationContext({}); - if (event.triggerSource === 'PostConfirmation_ConfirmSignUp') { - const { email, name, sub: userId } = event.request.userAttributes; - - // TODO 10007: We can replace this create petitioner account trigger and move the functionality over to our confirmSignUpInteractor. - const user = await applicationContext - .getUseCases() - .createPetitionerAccountInteractor(applicationContext, { - email, - name, - userId, - }); - - applicationContext.logger.info('Petitioner signup processed', { - event, - user, - }); - } else if (event.triggerSource === 'PostAuthentication_Authentication') { + if (event.triggerSource === 'PostAuthentication_Authentication') { const { email, sub } = event.request.userAttributes; const userId = event.request.userAttributes['custom:userId'] || sub; diff --git a/web-client/src/presenter/actions/createConfirmLinkAction.ts b/web-client/src/presenter/actions/createConfirmLinkAction.tsx similarity index 63% rename from web-client/src/presenter/actions/createConfirmLinkAction.ts rename to web-client/src/presenter/actions/createConfirmLinkAction.tsx index 673c0a729c3..df0c6a405a3 100644 --- a/web-client/src/presenter/actions/createConfirmLinkAction.ts +++ b/web-client/src/presenter/actions/createConfirmLinkAction.tsx @@ -1,4 +1,5 @@ import { SignUpUserResponse } from '@web-api/business/useCases/auth/signUpUserInteractor'; +import React from 'react'; import qs from 'qs'; export const createConfirmLinkAction = ({ @@ -20,7 +21,17 @@ export const createConfirmLinkAction = ({ return { alertSuccess: { alertType: 'success', - message: `New user account created successfully for ${props.email}! Please click the link below to verify your email address.
Verify Email Address`, + message: ( + <> + {' '} + New user account created successfully for {props.email}! Please click + the link below to verify your email address. +
+ + Verify Email Address + + + ), title: 'Account Created Locally', }, }; From c5324e309af4bb920659763357973775dbf9ade5 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:37:13 -0600 Subject: [PATCH 164/700] 10007: Unify on string matching error responses from the api. Update task list and add todos --- temp_delete_me.md | 1 + web-api/src/business/useCases/auth/loginInteractor.ts | 8 +++++--- web-api/src/errors/errors.test.ts | 6 +++--- web-api/src/errors/errors.ts | 4 ++-- web-client/build-dist.sh | 1 + web-client/src/app.tsx | 1 + .../src/presenter/actions/Login/submitLoginAction.tsx | 8 +++++--- 7 files changed, 18 insertions(+), 11 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 3583e25dec1..d2695bc1b1c 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -10,6 +10,7 @@ - userId, sub, email, username cognito . idk you figure it out. - Ensure incorrect login message appears on hosted env, didn't see this on our last test. - Unify error handling for loginInteractor, signUpUserInteractor. err.responseCode, err.name, err.message? +- Fix redirect_url in cognito links ::: SOLO TO DO::: diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index fd712168ca5..29ce9257835 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -1,7 +1,7 @@ import { NotFoundError, UnauthorizedError, - UnknownUserError, + UnidentifiedUserError, } from '@web-api/errors/errors'; import { ServerApplicationContext } from '@web-api/applicationContext'; @@ -31,11 +31,13 @@ export const loginInteractor = async ( refreshToken: result.AuthenticationResult!.RefreshToken!, }; } catch (err: any) { + //TODO 10007: Test handle user does not exist on deployed env if ( err.name === 'InvalidPasswordException' || - err.name === 'NotAuthorizedException' + err.name === 'NotAuthorizedException' || + err.name === 'UserNotFoundException' ) { - throw new UnknownUserError('Invalid Username or Password'); //401 + throw new UnidentifiedUserError('Invalid Username or Password'); //401 } if (err.name === 'UserNotConfirmedException') { diff --git a/web-api/src/errors/errors.test.ts b/web-api/src/errors/errors.test.ts index 32fa8c6e80c..cca50585f72 100644 --- a/web-api/src/errors/errors.test.ts +++ b/web-api/src/errors/errors.test.ts @@ -3,7 +3,7 @@ import { NotFoundError, ServiceUnavailableError, UnauthorizedError, - UnknownUserError, + UnidentifiedUserError, UnprocessableEntityError, UnsanitizedEntityError, } from './errors'; @@ -40,11 +40,11 @@ describe('UnauthorizedError', () => { }); }); -describe('UnknownUserError', () => { +describe('UnidentifiedUserError', () => { let error; beforeEach(() => { - error = new UnknownUserError('some error'); + error = new UnidentifiedUserError('some error'); }); it('should set a status code of 401', () => { diff --git a/web-api/src/errors/errors.ts b/web-api/src/errors/errors.ts index 711adcf0de0..642a176378f 100644 --- a/web-api/src/errors/errors.ts +++ b/web-api/src/errors/errors.ts @@ -35,9 +35,9 @@ export const InvalidRequest = class InvalidRequest extends Error { /** * Custom unknown user error handling for middlewares - * @type {module.UnknownUserError} + * @type {module.UnidentifiedUserError} */ -export const UnknownUserError = class UnknownUserError extends Error { +export const UnidentifiedUserError = class UnidentifiedUserError extends Error { public statusCode: number; /** * constructor diff --git a/web-client/build-dist.sh b/web-client/build-dist.sh index 6c59598ebd7..85ea7269950 100755 --- a/web-client/build-dist.sh +++ b/web-client/build-dist.sh @@ -21,6 +21,7 @@ CLIENT_ID=$(aws cognito-idp list-user-pool-clients --user-pool-id "${USER_POOL_I COGNITO_LOGIN_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" COGNITO_TOKEN_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/oauth2/token" +# TODO: remove/update response_type, update redirect_uri COGNITO_PASSWORD_RESET_REQUEST_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/forgotPassword?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" COGNITO_PASSWORD_CHANGE_URL="https://auth-${ENV}-${COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/changePassword?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${COGNITO_REDIRECT_URL}" diff --git a/web-client/src/app.tsx b/web-client/src/app.tsx index 127269ee7fa..a31ad64f916 100644 --- a/web-client/src/app.tsx +++ b/web-client/src/app.tsx @@ -142,6 +142,7 @@ const app = { return value; }); presenter.state.constants = applicationContext.getConstants(); + // TODO: move to state.ts? presenter.state.cognitoPasswordChange = applicationContext.getCognitoPasswordChangeUrl(); presenter.state.cognitoRequestPasswordResetUrl = diff --git a/web-client/src/presenter/actions/Login/submitLoginAction.tsx b/web-client/src/presenter/actions/Login/submitLoginAction.tsx index ef2d8742811..bc82d23407e 100644 --- a/web-client/src/presenter/actions/Login/submitLoginAction.tsx +++ b/web-client/src/presenter/actions/Login/submitLoginAction.tsx @@ -19,11 +19,13 @@ export const submitLoginAction = async ({ return path.success({ accessToken, idToken, refreshToken }); } catch (err: any) { - if (err.message === 'NewPasswordRequired') { + const originalErrorMessage = err?.originalError?.response?.data; + + if (originalErrorMessage === 'NewPasswordRequired') { return path.changePassword(); } - if (err.responseCode === 401) { + if (originalErrorMessage === 'Invalid Username or Password') { return path.error({ alertError: { message: 'The email address or password you entered is invalid.', @@ -32,7 +34,7 @@ export const submitLoginAction = async ({ }); } - if (err.responseCode === 403) { + if (originalErrorMessage === 'User is unconfirmed') { return path.error({ alertError: { message: ( From 813b8458b0dcdeda2343716baa09c86e0de09257 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:41:01 -0600 Subject: [PATCH 165/700] 10007: Update task list --- temp_delete_me.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index d2695bc1b1c..6f38de4ba49 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -7,9 +7,8 @@ - Expire link after 24hours - If user clicks on an expired email then redirect them to the login and tell them to sign in so that we can send a new confirmation with a new confirmation code. - Cognito srp auth flow. Research. -- userId, sub, email, username cognito . idk you figure it out. - Ensure incorrect login message appears on hosted env, didn't see this on our last test. -- Unify error handling for loginInteractor, signUpUserInteractor. err.responseCode, err.name, err.message? +- Extract error message strings into constants OR do something else. - Fix redirect_url in cognito links ::: SOLO TO DO::: From 0f4072926ea21298225d9eedb7330d00f207715c Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Mon, 15 Jan 2024 14:44:57 -0700 Subject: [PATCH 166/700] 10007: Set custom:userId and custom:role to be writeable --- temp_delete_me.md | 4 ++-- .../src/business/useCases/auth/confirmSignUpInteractor.ts | 5 ----- web-api/src/business/useCases/auth/signUpUserInteractor.ts | 6 +++++- web-api/terraform/template/cognito.tf | 2 ++ 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 3583e25dec1..44c729beffb 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -2,12 +2,12 @@ - Finish all todos - Fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts + - Pa11y tests. Determine strategy for how to fix. + Handle what happens if a user clicks an expired confirmation email: - On login to an unconfirmed account immediately send an email to the user - Expire link after 24hours - If user clicks on an expired email then redirect them to the login and tell them to sign in so that we can send a new confirmation with a new confirmation code. - Cognito srp auth flow. Research. -- userId, sub, email, username cognito . idk you figure it out. - Ensure incorrect login message appears on hosted env, didn't see this on our last test. - Unify error handling for loginInteractor, signUpUserInteractor. err.responseCode, err.name, err.message? @@ -24,7 +24,7 @@ - When the user hits refresh, we cannot easily revoke old ID tokens when issuing a new ID token. The threat vector is limited to 1 hour though. - This is not a problem when the user requests a new ID token because the old one has expired after an hour. - Implementing a system around this is possible, it would require more refactoring to NOT break multi-tab workflows on DAWSON. -- DOD: Refactor cognito so every account has and can be looked up by custom:userId. +- DOD: Refactor cognito so every account has and can be looked up by custom:userId. Extract application.getCognito() into application.getUserGateway(); ::: WIP ::: - Create helper function to get userId from Cognito response \ No newline at end of file diff --git a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts index 3c981d81029..a61911199d0 100644 --- a/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts +++ b/web-api/src/business/useCases/auth/confirmSignUpInteractor.ts @@ -1,5 +1,4 @@ import { InvalidRequest } from '@web-api/errors/errors'; -import { ROLES } from '@shared/business/entities/EntityConstants'; import { ServerApplicationContext } from '@web-api/applicationContext'; export const confirmSignUpInteractor = async ( @@ -38,10 +37,6 @@ export const confirmSignUpInteractor = async ( Name: 'email', Value: email, }, - { - Name: 'custom:role', - Value: ROLES.petitioner, - }, ], UserPoolId: process.env.USER_POOL_ID, Username: email, diff --git a/web-api/src/business/useCases/auth/signUpUserInteractor.ts b/web-api/src/business/useCases/auth/signUpUserInteractor.ts index 396d93d014f..c4b30f4e0cc 100644 --- a/web-api/src/business/useCases/auth/signUpUserInteractor.ts +++ b/web-api/src/business/useCases/auth/signUpUserInteractor.ts @@ -1,5 +1,6 @@ import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider'; import { NewPetitionerUser } from '@shared/business/entities/NewPetitionerUser'; +import { ROLES } from '@shared/business/entities/EntityConstants'; import { ServerApplicationContext } from '@web-api/applicationContext'; export type SignUpUserResponse = { @@ -59,11 +60,14 @@ export const signUpUserInteractor = async ( Name: 'custom:userId', Value: userId, }, + { + Name: 'custom:role', + Value: ROLES.petitioner, + }, ], Username: newUser.email, }); - //TODO 10007: ensure userId is standardized/consistent const { confirmationCode } = await applicationContext .getUseCaseHelpers() .createUserConfirmation(applicationContext, { diff --git a/web-api/terraform/template/cognito.tf b/web-api/terraform/template/cognito.tf index 1a97b635424..e5c8cbfefd2 100644 --- a/web-api/terraform/template/cognito.tf +++ b/web-api/terraform/template/cognito.tf @@ -123,6 +123,8 @@ resource "aws_cognito_user_pool_client" "client" { write_attributes = [ "address", "birthdate", + "custom:userId", + "custom:role", "email", "family_name", "gender", From d7fc8d339e5245e1dd5cf4a568bd1d8981624665 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:46:50 -0600 Subject: [PATCH 167/700] 10007: update redirect_uri in cognito links to new login link --- esbuildHelper.mjs | 1 - web-client/build-dist.sh | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/esbuildHelper.mjs b/esbuildHelper.mjs index 58ab1a1c704..46c17120ab1 100644 --- a/esbuildHelper.mjs +++ b/esbuildHelper.mjs @@ -26,7 +26,6 @@ const env = { COGNITO_PASSWORD_CHANGE_URL: process.env.COGNITO_PASSWORD_CHANGE_URL, COGNITO_PASSWORD_RESET_REQUEST_URL: process.env.COGNITO_PASSWORD_RESET_REQUEST_URL, - COGNITO_REDIRECT_URI: process.env.COGNITO_REDIRECT_URI, COGNITO_SUFFIX: process.env.COGNITO_SUFFIX, COGNITO_TOKEN_URL: process.env.COGNITO_TOKEN_URL, DYNAMODB_TABLE_NAME: process.env.DYNAMODB_TABLE_NAME, diff --git a/web-client/build-dist.sh b/web-client/build-dist.sh index 85ea7269950..fc67d927554 100755 --- a/web-client/build-dist.sh +++ b/web-client/build-dist.sh @@ -10,8 +10,8 @@ DEPLOYING_COLOR=$2 REGION="us-east-1" API_URL="https://api-${DEPLOYING_COLOR}.${EFCMS_DOMAIN}" WS_URL="wss://ws-${DEPLOYING_COLOR}.${EFCMS_DOMAIN}" -COGNITO_REDIRECT_URL="https%3A//app.${EFCMS_DOMAIN}/log-in" -COGNITO_REDIRECT_URI="https://app.${EFCMS_DOMAIN}/log-in" +COGNITO_REDIRECT_URL="https%3A//app.${EFCMS_DOMAIN}/login" +# COGNITO_REDIRECT_URI="https://app.${EFCMS_DOMAIN}/login" PUBLIC_SITE_URL="https://${EFCMS_DOMAIN}" USER_POOL_ID=$(aws cognito-idp list-user-pools --query "UserPools[?Name == 'efcms-${ENV}'].Id | [0]" --max-results 30 --region "${REGION}" --output text) @@ -42,7 +42,7 @@ STAGE="${CLIENT_STAGE}" \ COGNITO_CLIENT_ID="${CLIENT_ID}" \ SCANNER_RESOURCE_URI="${SCANNER_RESOURCE_URI}" \ COGNITO_TOKEN_URL="${COGNITO_TOKEN_URL}" \ - COGNITO_REDIRECT_URI="${COGNITO_REDIRECT_URI}" \ + # COGNITO_REDIRECT_URI="${COGNITO_REDIRECT_URI}" \ PDF_EXPRESS_LICENSE_KEY="${PDF_EXPRESS_LICENSE_KEY}" \ WS_URL="${WS_URL}" \ API_URL="${API_URL}" \ From 2de6748176ab0f441c27c0a5e28bf725aadf88d2 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Mon, 15 Jan 2024 14:53:59 -0700 Subject: [PATCH 168/700] 10007: docs --- temp_delete_me.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 08d7033ed07..54e6f5c2472 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -3,10 +3,6 @@ - Fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - Pa11y tests. Determine strategy for how to fix. -+ Handle what happens if a user clicks an expired confirmation email: - - On login to an unconfirmed account immediately send an email to the user - - Expire link after 24hours - - If user clicks on an expired email then redirect them to the login and tell them to sign in so that we can send a new confirmation with a new confirmation code. - Cognito srp auth flow. Research. - Ensure incorrect login message appears on hosted env, didn't see this on our last test. - Extract error message strings into constants OR do something else. From ab5754e7348d5127df82a594766fdb7e1f70fbb3 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Mon, 15 Jan 2024 14:19:30 -0800 Subject: [PATCH 169/700] 10007: Delete comment that is breaking web client deploy --- web-client/build-dist.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/web-client/build-dist.sh b/web-client/build-dist.sh index fc67d927554..59903a6ae59 100755 --- a/web-client/build-dist.sh +++ b/web-client/build-dist.sh @@ -42,7 +42,6 @@ STAGE="${CLIENT_STAGE}" \ COGNITO_CLIENT_ID="${CLIENT_ID}" \ SCANNER_RESOURCE_URI="${SCANNER_RESOURCE_URI}" \ COGNITO_TOKEN_URL="${COGNITO_TOKEN_URL}" \ - # COGNITO_REDIRECT_URI="${COGNITO_REDIRECT_URI}" \ PDF_EXPRESS_LICENSE_KEY="${PDF_EXPRESS_LICENSE_KEY}" \ WS_URL="${WS_URL}" \ API_URL="${API_URL}" \ From c56d090d6f13f14180c5d1dd48049a00e6225c9a Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Mon, 15 Jan 2024 14:45:08 -0800 Subject: [PATCH 170/700] 10007: remove postConfirmation --- scripts/circleci/verify-cognito-lambda-triggers.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/circleci/verify-cognito-lambda-triggers.sh b/scripts/circleci/verify-cognito-lambda-triggers.sh index cb3a30cd7bd..2f35cc9bf39 100755 --- a/scripts/circleci/verify-cognito-lambda-triggers.sh +++ b/scripts/circleci/verify-cognito-lambda-triggers.sh @@ -13,10 +13,10 @@ ENV="${1}" cognito_user_pool_name="efcms-${ENV}" -user_pool_has_both_lambda_triggers=$(aws cognito-idp list-user-pools --max-results=60 --region=us-east-1 | jq '.UserPools[] | select(.Name=="'"${cognito_user_pool_name}"'") | .LambdaConfig | .PostConfirmation and .PostAuthentication') +user_pool_has_lambda_trigger=$(aws cognito-idp list-user-pools --max-results=60 --region=us-east-1 | jq '.UserPools[] | select(.Name=="'"${cognito_user_pool_name}"'") | .LambdaConfig | .PostAuthentication') -if [ "${user_pool_has_both_lambda_triggers}" != 'true' ]; then - echo "ERROR: Cognito user pool ${cognito_user_pool_name} is missing either the PostConfirmation or PostAuthentication Lambda trigger" +if [ "${user_pool_has_lambda_trigger}" == 'null' ]; then + echo "ERROR: Cognito user pool ${cognito_user_pool_name} is missing PostAuthentication Lambda trigger" exit 1 fi From cf38db1d0e95d2ebae0dc8f1c62a862edc7c4b4f Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Mon, 15 Jan 2024 16:57:21 -0600 Subject: [PATCH 171/700] 10007: update allowed callback urls for cognito --- web-api/terraform/template/cognito.tf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web-api/terraform/template/cognito.tf b/web-api/terraform/template/cognito.tf index e5c8cbfefd2..b2935fb560a 100644 --- a/web-api/terraform/template/cognito.tf +++ b/web-api/terraform/template/cognito.tf @@ -10,7 +10,7 @@ resource "aws_cognito_user_pool" "pool" { } } - admin_create_user_config { + admin_create_user_config { allow_admin_create_user_only = false invite_message_template { sms_message = "Your username is {username} and temporary password is {####}." @@ -110,8 +110,8 @@ resource "aws_cognito_user_pool_client" "client" { id_token_validity = 1 callback_urls = [ - "http://localhost:1234/log-in", - "https://app.${var.dns_domain}/log-in", + "http://localhost:1234/login", + "https://app.${var.dns_domain}/login", ] allowed_oauth_flows = ["code", "implicit"] @@ -250,8 +250,8 @@ resource "aws_cognito_user_pool_client" "irs_client" { id_token_validity = 1 callback_urls = [ - "http://localhost:1234/log-in", - "https://app.${var.dns_domain}/log-in", + "http://localhost:1234/login", + "https://app.${var.dns_domain}/login", ] allowed_oauth_flows = ["code", "implicit"] From 83f4357a41b03d36234447f6e1f3d4d271af0e98 Mon Sep 17 00:00:00 2001 From: John Cruz Date: Tue, 16 Jan 2024 09:16:57 -0700 Subject: [PATCH 172/700] 10228: Temp modify circleci config; create new smoke test file; --- .circleci/config.yml | 28 +++++++++---------- .../petitioner-account-creation.cy.ts | 3 ++ 2 files changed, 17 insertions(+), 14 deletions(-) create mode 100644 cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 33a055d828e..313ce42573b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -881,8 +881,8 @@ workflows: build-and-deploy: when: << pipeline.parameters.run_build_and_deploy >> jobs: - - deploy: - <<: *only-deployed-lower-environments + # - deploy: + # <<: *only-deployed-lower-environments # - migrate: # <<: *only-deployed-lower-environments # requires: @@ -917,18 +917,18 @@ workflows: # <<: *only-deployed-lower-environments # requires: # - loadtests - - switch-colors: - <<: *only-deployed-lower-environments - requires: - - deploy - - delete-api-mappings: - <<: *only-deployed-lower-environments - requires: - - switch-colors - - cleanup: - <<: *only-deployed-lower-environments - requires: - - switch-colors + # - switch-colors: + # <<: *only-deployed-lower-environments + # requires: + # - smoketests-readonly + # - delete-api-mappings: + # <<: *only-deployed-lower-environments + # requires: + # - switch-colors + # - cleanup: + # <<: *only-deployed-lower-environments + # requires: + - switch-colors build-and-deploy-with-context: when: << pipeline.parameters.run_build_and_deploy_with_context >> diff --git a/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts b/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts new file mode 100644 index 00000000000..5414be2fd26 --- /dev/null +++ b/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts @@ -0,0 +1,3 @@ +describe('Petitioner Account Creation', () => { + it('should fill out the account creation form', () => {}); +}); From 7dbc70260fd161436452715ffd80c2ef9b662279 Mon Sep 17 00:00:00 2001 From: John Cruz Date: Tue, 16 Jan 2024 09:20:35 -0700 Subject: [PATCH 173/700] 10228: Temp Only run new cypress test on circle; --- cypress-smoketests.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress-smoketests.config.ts b/cypress-smoketests.config.ts index 5f9d86fb763..a74304aad08 100644 --- a/cypress-smoketests.config.ts +++ b/cypress-smoketests.config.ts @@ -29,7 +29,7 @@ export default defineConfig({ }); }, specPattern: - 'cypress/cypress-smoketests/integration/**/*.cy.{js,jsx,ts,tsx}', + 'cypress/cypress-smoketests/integration/petitioner-account-creation.cy.{js,jsx,ts,tsx}', supportFile: 'cypress/cypress-smoketests/support/index.ts', testIsolation: false, }, From 87f7e7f2cb2da298d68c935c8b39982727981664 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 10:22:23 -0600 Subject: [PATCH 174/700] 10007: update task list --- temp_delete_me.md | 1 - 1 file changed, 1 deletion(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 54e6f5c2472..c4126bdecf3 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -4,7 +4,6 @@ - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - Pa11y tests. Determine strategy for how to fix. - Cognito srp auth flow. Research. -- Ensure incorrect login message appears on hosted env, didn't see this on our last test. - Extract error message strings into constants OR do something else. - Fix redirect_url in cognito links From 6961c3e89bd366e774d99d19f683e770ce7df040 Mon Sep 17 00:00:00 2001 From: John Cruz Date: Tue, 16 Jan 2024 09:24:25 -0700 Subject: [PATCH 175/700] 10228: Temp modify circleci config; --- .circleci/config.yml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 313ce42573b..f38cf180834 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -881,8 +881,8 @@ workflows: build-and-deploy: when: << pipeline.parameters.run_build_and_deploy >> jobs: - # - deploy: - # <<: *only-deployed-lower-environments + - deploy: + <<: *only-deployed-lower-environments # - migrate: # <<: *only-deployed-lower-environments # requires: @@ -905,10 +905,10 @@ workflows: # <<: *only-deployed-lower-environments # requires: # - wait-for-reindex - # - smoketests: - # <<: *only-deployed-lower-environments - # requires: - # - disable-reindex-cron + - smoketests: + <<: *only-deployed-lower-environments + requires: + - deploy # - loadtests: # <<: *only-deployed-lower-environments # requires: @@ -917,18 +917,18 @@ workflows: # <<: *only-deployed-lower-environments # requires: # - loadtests - # - switch-colors: - # <<: *only-deployed-lower-environments - # requires: - # - smoketests-readonly - # - delete-api-mappings: - # <<: *only-deployed-lower-environments - # requires: - # - switch-colors - # - cleanup: - # <<: *only-deployed-lower-environments - # requires: - - switch-colors + - switch-colors: + <<: *only-deployed-lower-environments + requires: + - smoketests + - delete-api-mappings: + <<: *only-deployed-lower-environments + requires: + - switch-colors + - cleanup: + <<: *only-deployed-lower-environments + requires: + - switch-colors build-and-deploy-with-context: when: << pipeline.parameters.run_build_and_deploy_with_context >> From 1723831db4986aac105f85999808d56f93bf6bea Mon Sep 17 00:00:00 2001 From: John Cruz Date: Tue, 16 Jan 2024 09:43:13 -0700 Subject: [PATCH 176/700] 10228: Visit account creation page and fill out form; Added data test id on the form for cypress; --- .../petitioner-account-creation.cy.ts | 28 ++++++++++++++++++- .../CreatePetitionerAccountForm.tsx | 4 +++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts b/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts index 5414be2fd26..461174ac7c0 100644 --- a/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts +++ b/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts @@ -1,3 +1,29 @@ describe('Petitioner Account Creation', () => { - it('should fill out the account creation form', () => {}); + const GUID = Date.now(); + const TEST_EMAIL = `cypress+${GUID}@test.com`; + const TEST_NAME = 'Cypress Test'; + const TEST_PASSWORD = 'aA1!aaaa'; + describe('Create Petitioner Account', () => { + beforeEach(() => { + cy.visit('/create-account/petitioner'); + }); + + it('should fill out the account creation form', () => { + 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); + }); + }); }); diff --git a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx index 2baf5702098..8db9c7bccc3 100644 --- a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx +++ b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx @@ -54,6 +54,7 @@ export const CreatePetitionerAccountForm = connect( autoCapitalize="off" autoCorrect="off" className="usa-input" + data-testid="petitioner-account-creation-email" id="email" name="email" type="text" @@ -86,6 +87,7 @@ export const CreatePetitionerAccountForm = connect( autoCapitalize="off" autoCorrect="off" className="usa-input" + data-testid="petitioner-account-creation-name" id="name" name="name" type="text" @@ -116,6 +118,7 @@ export const CreatePetitionerAccountForm = connect( Date: Tue, 16 Jan 2024 09:44:55 -0700 Subject: [PATCH 177/700] 10228: Format; --- .../integration/petitioner-account-creation.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts b/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts index 461174ac7c0..73462ce1e54 100644 --- a/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts +++ b/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts @@ -3,6 +3,7 @@ describe('Petitioner Account Creation', () => { const TEST_EMAIL = `cypress+${GUID}@test.com`; const TEST_NAME = 'Cypress Test'; const TEST_PASSWORD = 'aA1!aaaa'; + describe('Create Petitioner Account', () => { beforeEach(() => { cy.visit('/create-account/petitioner'); From 426e94e7300c2162368c7b759dc628f55d038191 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Tue, 2 Jan 2024 14:35:00 -0800 Subject: [PATCH 178/700] 10007: comments --- shared/src/business/useCases/health/getHealthCheckInteractor.ts | 1 + web-api/src/business/useCases/auth/loginInteractor.ts | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/business/useCases/health/getHealthCheckInteractor.ts b/shared/src/business/useCases/health/getHealthCheckInteractor.ts index f35085a0aa6..8ab3e023163 100644 --- a/shared/src/business/useCases/health/getHealthCheckInteractor.ts +++ b/shared/src/business/useCases/health/getHealthCheckInteractor.ts @@ -206,6 +206,7 @@ const getCognitoStatus = async ({ userPoolId: process.env.USER_POOL_ID, }); + // TODO 10007: code will not work await axios.get( `https://auth-${process.env.STAGE}-${process.env.COGNITO_SUFFIX}.auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=${clientId}&redirect_uri=https%3A//app.${process.env.EFCMS_DOMAIN}/log-in`, { diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index 29ce9257835..ee4b281b76d 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -31,7 +31,6 @@ export const loginInteractor = async ( refreshToken: result.AuthenticationResult!.RefreshToken!, }; } catch (err: any) { - //TODO 10007: Test handle user does not exist on deployed env if ( err.name === 'InvalidPasswordException' || err.name === 'NotAuthorizedException' || From 03ef1610f9f72401444e3230504b55c0b87f6ae3 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 16 Jan 2024 09:55:10 -0800 Subject: [PATCH 179/700] 10007: docs --- temp_delete_me.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 54e6f5c2472..bbd558a0a2e 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -3,7 +3,6 @@ - Fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - Pa11y tests. Determine strategy for how to fix. -- Cognito srp auth flow. Research. - Ensure incorrect login message appears on hosted env, didn't see this on our last test. - Extract error message strings into constants OR do something else. - Fix redirect_url in cognito links @@ -12,6 +11,12 @@ ::: QUESTIONS ::: +- Cognito SRP auth flow + - Leaning towards not implementing + - Current discussion: There is a possibility we could accidentally log out plaintext passwords in CloudWatch. How can we prevent this from ever happeneing? + - Prevent logs from being added to endpoints that accept a password (using lint rules?). + - Deploy a new lambda for endpoints that accept a password and disable logs for that lambda. + - We could encrypt the password on the frontend and decrypt on the backend so that we never see plaintext of their password. - How are going to make sure our auth is secure? Run scanners or pen testing? - What happens if someone creates an account, we deploy 10007, and THEN they try to verify it??? From a21be52dc9a6faaf9f6e468ff49b2ed075c253a9 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 16 Jan 2024 10:19:18 -0800 Subject: [PATCH 180/700] 10007: Remove check of maintenance mode in sequence. Rely on init app --- .../presenter/sequences/Login/gotoLoginSequence.ts | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/web-client/src/presenter/sequences/Login/gotoLoginSequence.ts b/web-client/src/presenter/sequences/Login/gotoLoginSequence.ts index 0d866ada8f3..4fec1674e83 100644 --- a/web-client/src/presenter/sequences/Login/gotoLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/gotoLoginSequence.ts @@ -1,15 +1,5 @@ -import { getMaintenanceModeAction } from '@web-client/presenter/actions/Maintenance/getMaintenanceModeAction'; -import { isMaintenanceModeEngagedAction } from '@web-client/presenter/actions/Maintenance/isMaintenanceModeEngagedAction'; -import { navigateToMaintenanceAction } from '@web-client/presenter/actions/navigateToMaintenanceAction'; -import { setMaintenanceModeAction } from '@web-client/presenter/actions/setMaintenanceModeAction'; import { setupCurrentPageAction } from '../../actions/setupCurrentPageAction'; export const gotoLoginSequence = [ - getMaintenanceModeAction, - setMaintenanceModeAction, - isMaintenanceModeEngagedAction, - { - maintenanceModeOff: [setupCurrentPageAction('Login')], - maintenanceModeOn: [navigateToMaintenanceAction], - }, + setupCurrentPageAction('Login'), ] as unknown as () => void; From f9f86084c485216a009bd08673d8654c62818b7c Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 16 Jan 2024 10:19:38 -0800 Subject: [PATCH 181/700] 10007: docs --- temp_delete_me.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index bbd558a0a2e..679b61b743d 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -5,7 +5,8 @@ - Pa11y tests. Determine strategy for how to fix. - Ensure incorrect login message appears on hosted env, didn't see this on our last test. - Extract error message strings into constants OR do something else. -- Fix redirect_url in cognito links +- Forgot password flow ++ (KS & TE) Change password flow ::: SOLO TO DO::: @@ -27,6 +28,6 @@ - This is not a problem when the user requests a new ID token because the old one has expired after an hour. - Implementing a system around this is possible, it would require more refactoring to NOT break multi-tab workflows on DAWSON. - DOD: Refactor cognito so every account has and can be looked up by custom:userId. Extract application.getCognito() into application.getUserGateway(); - + - Chris is OK with this, wants us to chat with Mike first. ::: WIP ::: - Create helper function to get userId from Cognito response \ No newline at end of file From a62ec4616c7d2e36e3433544383d2dc88bfa3d3b Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 16 Jan 2024 10:25:43 -0800 Subject: [PATCH 182/700] 10007: docs --- temp_delete_me.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 679b61b743d..fa1e1fb2e5e 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -3,10 +3,10 @@ - Fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - Pa11y tests. Determine strategy for how to fix. -- Ensure incorrect login message appears on hosted env, didn't see this on our last test. - Extract error message strings into constants OR do something else. -- Forgot password flow -+ (KS & TE) Change password flow +- Forgot password flow. +- Zach look at errors in submitLoginAction for 1 hr. ++ (KS & TE) Change password flow. ::: SOLO TO DO::: From fd22cca5af25a8a63b193cde583a052742d3cc60 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 12:59:41 -0600 Subject: [PATCH 183/700] 10007: WIP change password skeleton --- .../src/business/entities/ChangePassword.ts | 129 +++++++++++ .../business/entities/NewPetitionerUser.ts | 4 +- .../useCases/auth/changePasswordInteractor.ts | 25 ++ .../Login/redirectToChangePasswordAction.ts | 9 +- .../createAccountHelper.ts | 10 +- .../computeds/Login/changePasswordHelper.ts | 26 +++ web-client/src/presenter/presenter.ts | 2 + .../Login/goToChangePasswordSequence.ts | 5 + web-client/src/presenter/state.ts | 4 + web-client/src/router.ts | 5 + web-client/src/views/AppComponent.tsx | 3 + web-client/src/views/Login/ChangePassword.tsx | 218 ++++++++++++++++++ 12 files changed, 426 insertions(+), 14 deletions(-) create mode 100644 shared/src/business/entities/ChangePassword.ts create mode 100644 web-api/src/business/useCases/auth/changePasswordInteractor.ts create mode 100644 web-client/src/presenter/computeds/Login/changePasswordHelper.ts create mode 100644 web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts create mode 100644 web-client/src/views/Login/ChangePassword.tsx diff --git a/shared/src/business/entities/ChangePassword.ts b/shared/src/business/entities/ChangePassword.ts new file mode 100644 index 00000000000..8c4ec904ee3 --- /dev/null +++ b/shared/src/business/entities/ChangePassword.ts @@ -0,0 +1,129 @@ +import { JoiValidationConstants } from './JoiValidationConstants'; +import { JoiValidationEntity } from './JoiValidationEntity'; +import joi from 'joi'; + +type PasswordValidation = { + message: string; + valid: boolean; +}; + +export type ChangePasswordValidations = { + hasNoLeadingOrTrailingSpace: PasswordValidation; + hasOneLowercase: PasswordValidation; + hasOneNumber: PasswordValidation; + hasOneUppercase: PasswordValidation; + hasSpecialCharacterOrSpace: PasswordValidation; + isProperLength: PasswordValidation; +}; + +const ChangePasswordValidationErrorMessages = { + hasNoLeadingOrTrailingSpace: 'Must not contain leading or trailing space', + hasOneLowercase: 'Must contain lower case letter', + hasOneNumber: 'Must contain number', + hasOneUppercase: 'Must contain upper case letter', + hasSpecialCharacterOrSpace: 'Must contain special character or space', + isProperLength: 'Must be between 8-99 characters long', +}; + +export function getDefaultPasswordErrors(): ChangePasswordValidations { + return { + hasNoLeadingOrTrailingSpace: { + message: + ChangePasswordValidationErrorMessages.hasNoLeadingOrTrailingSpace, + valid: true, + }, + hasOneLowercase: { + message: ChangePasswordValidationErrorMessages.hasOneLowercase, + valid: true, + }, + hasOneNumber: { + message: ChangePasswordValidationErrorMessages.hasOneNumber, + valid: true, + }, + hasOneUppercase: { + message: ChangePasswordValidationErrorMessages.hasOneUppercase, + valid: true, + }, + hasSpecialCharacterOrSpace: { + message: ChangePasswordValidationErrorMessages.hasSpecialCharacterOrSpace, + valid: true, + }, + isProperLength: { + message: ChangePasswordValidationErrorMessages.isProperLength, + valid: true, + }, + }; +} + +export class ChangePasswordForm extends JoiValidationEntity { + public password: string; + public confirmPassword: string; + + constructor(rawProps) { + super('ChangePasswordForm'); + this.password = rawProps.password; + this.confirmPassword = rawProps.confirmPassword; + } + + static VALIDATION_RULES = joi.object().keys({ + confirmPassword: joi + .valid(joi.ref('password')) + .required() + .messages({ '*': 'Passwords must match' }), + entityName: + JoiValidationConstants.STRING.valid('ChangePasswordForm').required(), + password: JoiValidationConstants.STRING.custom((value, helper) => { + const errors = getDefaultPasswordErrors(); + + if (value.length < 8 || value.length > 99) { + errors.isProperLength.valid = false; + } + + if (!/[a-z]/.test(value)) { + errors.hasOneLowercase.valid = false; + } + + if (!/[A-Z]/.test(value)) { + errors.hasOneUppercase.valid = false; + } + + if (!/[\^$*.[\]{}()?\-“!@#%&/,><’:;|_~`]/.test(value)) { + errors.hasSpecialCharacterOrSpace.valid = false; + } + + if (!/[0-9]/.test(value)) { + errors.hasOneNumber.valid = false; + } + + if (/^\s/.test(value) || /\s$/.test(value)) { + errors.hasNoLeadingOrTrailingSpace.valid = false; + } + + const noErrors = Object.values(errors).reduce( + (accumulator, currentValue) => { + return accumulator && currentValue.valid; + }, + true, + ); + + if (noErrors) { + return value; + } else { + return helper.message( + Object.entries(errors) + .filter(([, curValue]) => !curValue.valid) + .map(([key]) => key) + .join('|') as any, + ); + } + }).description( + 'Password for the account. Contains a custom validation because we want to construct a string with all the keys that failed which later we parse out to an object', + ), + }); + + getValidationRules() { + return ChangePasswordForm.VALIDATION_RULES; + } +} + +export type RawChangePasswordForm = ExcludeMethods; diff --git a/shared/src/business/entities/NewPetitionerUser.ts b/shared/src/business/entities/NewPetitionerUser.ts index 8a3da38cb5b..4290bb13614 100644 --- a/shared/src/business/entities/NewPetitionerUser.ts +++ b/shared/src/business/entities/NewPetitionerUser.ts @@ -7,7 +7,7 @@ type PasswordValidation = { valid: boolean; }; -export type NewPetitionerUserPasswordValidations = { +export type PasswordValidations = { hasNoLeadingOrTrailingSpace: PasswordValidation; hasOneLowercase: PasswordValidation; hasOneNumber: PasswordValidation; @@ -24,7 +24,7 @@ const NewPetitionerUserPasswordValidationErrorMessages = { isProperLength: 'Must be between 8-99 characters long', }; -export function getDefaultPasswordErrors(): NewPetitionerUserPasswordValidations { +export function getDefaultPasswordErrors(): PasswordValidations { return { hasNoLeadingOrTrailingSpace: { message: diff --git a/web-api/src/business/useCases/auth/changePasswordInteractor.ts b/web-api/src/business/useCases/auth/changePasswordInteractor.ts new file mode 100644 index 00000000000..9d368652fda --- /dev/null +++ b/web-api/src/business/useCases/auth/changePasswordInteractor.ts @@ -0,0 +1,25 @@ +export const changePasswordInteractor = async ( + applicationContext: IApplicationContext, + { + newPassword, + sessionId, + userEmail, + }: { newPassword: string; sessionId: string; userEmail: string }, +) => { + const params = { + ChallengeName: 'NEW_PASSWORD_REQUIRED', + ChallengeResponses: { + NEW_PASSWORD: newPassword, + USERNAME: userEmail, + }, + ClientId: process.env.COGNITO_CLIENT_ID, + Session: sessionId, + }; + + const result = await applicationContext + .getCognito() + .respondToAuthChallenge(params) + .promise(); + + return result; +}; diff --git a/web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts b/web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts index fdeff6433b0..a3966d6aeb0 100644 --- a/web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts +++ b/web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts @@ -1,8 +1,3 @@ -import { state } from '@web-client/presenter/app.cerebral'; - -export const redirectToChangePasswordAction = ({ get, router }) => { - const a = get(state.cognitoPasswordChange); - console.log(`get(state.cognitoPasswordChange)[${a}]`); - - router.externalRoute(get(state.cognitoPasswordChange)); +export const redirectToChangePasswordAction = async ({ router }) => { + await router.route('/change-password'); }; diff --git a/web-client/src/presenter/computeds/CreatePetitionerAccount/createAccountHelper.ts b/web-client/src/presenter/computeds/CreatePetitionerAccount/createAccountHelper.ts index 60016e37a5c..97aa76be609 100644 --- a/web-client/src/presenter/computeds/CreatePetitionerAccount/createAccountHelper.ts +++ b/web-client/src/presenter/computeds/CreatePetitionerAccount/createAccountHelper.ts @@ -1,7 +1,7 @@ import { Get } from 'cerebral'; import { NewPetitionerUser, - NewPetitionerUserPasswordValidations, + PasswordValidations, getDefaultPasswordErrors, } from '@shared/business/entities/NewPetitionerUser'; import { state } from '@web-client/presenter/app.cerebral'; @@ -11,12 +11,12 @@ export type CreateAccountHelperResults = { email?: string; formIsValid: boolean; name?: string; - passwordErrors?: NewPetitionerUserPasswordValidations; + passwordErrors?: PasswordValidations; }; -const convertErrorMessageToPasswordValidationObject = ( +export const convertErrorMessageToPasswordValidationObject = ( stringToParse: string | undefined, -): NewPetitionerUserPasswordValidations => { +): PasswordValidations => { const errorObjects = getDefaultPasswordErrors(); if (!stringToParse) return errorObjects; @@ -33,7 +33,7 @@ export const createAccountHelper = (get: Get): CreateAccountHelperResults => { const formEntity = new NewPetitionerUser(form); const errors = formEntity.getFormattedValidationErrors(); - const passwordErrors: NewPetitionerUserPasswordValidations = + const passwordErrors: PasswordValidations = convertErrorMessageToPasswordValidationObject(errors?.password); return { diff --git a/web-client/src/presenter/computeds/Login/changePasswordHelper.ts b/web-client/src/presenter/computeds/Login/changePasswordHelper.ts new file mode 100644 index 00000000000..dcb49f2b30e --- /dev/null +++ b/web-client/src/presenter/computeds/Login/changePasswordHelper.ts @@ -0,0 +1,26 @@ +import { ChangePasswordForm } from '@shared/business/entities/ChangePassword'; +import { Get } from 'cerebral'; +import { PasswordValidations } from '@shared/business/entities/NewPetitionerUser'; +import { convertErrorMessageToPasswordValidationObject } from '@web-client/presenter/computeds/CreatePetitionerAccount/createAccountHelper'; +import { state } from '@web-client/presenter/app.cerebral'; + +export type ChangePasswordHelperResults = { + confirmPassword: boolean; + formIsValid: boolean; + passwordErrors?: PasswordValidations; +}; + +export const changePasswordHelper = (get: Get): ChangePasswordHelperResults => { + const form = get(state.form); + const formEntity = new ChangePasswordForm(form); + const errors = formEntity.getFormattedValidationErrors(); + + const passwordErrors: PasswordValidations = + convertErrorMessageToPasswordValidationObject(errors?.password); + + return { + confirmPassword: !errors?.confirmPassword, + formIsValid: formEntity.isValid(), + passwordErrors, + }; +}; diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 9a6229a70df..de3a0b1a102 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -122,6 +122,7 @@ import { getCaseInventoryReportSequence } from './sequences/getCaseInventoryRepo import { getCustomCaseReportSequence } from './sequences/getCustomCaseReportSequence'; import { getUsersInSectionSequence } from './sequences/getUsersInSectionSequence'; import { goToApplyStampSequence } from './sequences/gotoApplyStampSequence'; +import { goToChangePasswordSequence } from '@web-client/presenter/sequences/Login/goToChangePasswordSequence'; import { goToCreatePetitionerAccountSequence } from '@web-client/presenter/sequences/Public/goToCreatePetitionerAccountSequence'; import { goToVerificationSentSequence } from '@web-client/presenter/sequences/goToVerificationSentSequence'; import { gotoAccessibilityStatementSequence } from './sequences/gotoAccessibilityStatementSequence'; @@ -748,6 +749,7 @@ export const presenterSequences = { getCustomCaseReportSequence, getUsersInSectionSequence: getUsersInSectionSequence as unknown as Function, goToApplyStampSequence: goToApplyStampSequence as unknown as Function, + goToChangePasswordSequence, goToCreatePetitionerAccountSequence, goToVerificationSentSequence: goToVerificationSentSequence as unknown as Function, diff --git a/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts b/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts new file mode 100644 index 00000000000..799398ce37a --- /dev/null +++ b/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts @@ -0,0 +1,5 @@ +import { setupCurrentPageAction } from '../../actions/setupCurrentPageAction'; + +export const goToChangePasswordSequence = [ + setupCurrentPageAction('ChangePassword'), +] as unknown as () => void; diff --git a/web-client/src/presenter/state.ts b/web-client/src/presenter/state.ts index b21ed11fc92..5a5819e43fb 100644 --- a/web-client/src/presenter/state.ts +++ b/web-client/src/presenter/state.ts @@ -37,6 +37,7 @@ import { caseSearchNoMatchesHelper } from './computeds/caseSearchNoMatchesHelper import { caseStatusHistoryHelper } from './computeds/caseStatusHistoryHelper'; import { caseTypeDescriptionHelper } from './computeds/caseTypeDescriptionHelper'; import { caseWorksheetsHelper } from '@web-client/presenter/computeds/CaseWorksheets/caseWorksheetsHelper'; +import { changePasswordHelper } from '@web-client/presenter/computeds/Login/changePasswordHelper'; import { cloneDeep } from 'lodash'; import { completeDocumentTypeSectionHelper } from './computeds/completeDocumentTypeSectionHelper'; import { confirmInitiateServiceModalHelper } from './computeds/confirmInitiateServiceModalHelper'; @@ -241,6 +242,9 @@ export const computeds = { caseWorksheetsHelper: caseWorksheetsHelper as unknown as ReturnType< typeof caseWorksheetsHelper >, + changePasswordHelper: changePasswordHelper as unknown as ReturnType< + typeof changePasswordHelper + >, completeDocumentTypeSectionHelper: completeDocumentTypeSectionHelper as unknown as ReturnType< typeof completeDocumentTypeSectionHelper diff --git a/web-client/src/router.ts b/web-client/src/router.ts index eecc990935f..31ef759f7d4 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -1117,6 +1117,11 @@ const router = { app.getSequence('gotoLoginSequence')(); }); + registerRoute('/change-password', () => { + setPageTitle('Change Password'); + app.getSequence('goToChangePasswordSequence')(); + }); + registerRoute('/create-account/petitioner', () => { setPageTitle('Account Registration'); app.getSequence('goToCreatePetitionerAccountSequence')(); diff --git a/web-client/src/views/AppComponent.tsx b/web-client/src/views/AppComponent.tsx index 7bfd0b000b9..f76f503fa19 100644 --- a/web-client/src/views/AppComponent.tsx +++ b/web-client/src/views/AppComponent.tsx @@ -19,6 +19,7 @@ import { CaseInventoryReport } from './CaseInventoryReport/CaseInventoryReport'; import { CaseInventoryReportModal } from './CaseInventoryReport/CaseInventoryReportModal'; import { CaseSearchNoMatches } from './CaseSearchNoMatches'; import { ChangeLoginAndServiceEmail } from './ChangeLoginAndServiceEmail'; +import { ChangePassword } from '@web-client/views/Login/ChangePassword'; import { Contact } from './Contact'; import { ContactEdit } from './ContactEdit'; import { CourtIssuedDocketEntry } from './CourtIssuedDocketEntry/CourtIssuedDocketEntry'; @@ -119,6 +120,7 @@ const pages = { CaseInventoryReport, CaseSearchNoMatches, ChangeLoginAndServiceEmail, + ChangePassword, Contact, ContactEdit, CourtIssuedDocketEntry, @@ -190,6 +192,7 @@ const pages = { }; const pagesWithBlueBackground = { + ChangePassword, CreatePetitionerAccount, Login, VerificationSent, diff --git a/web-client/src/views/Login/ChangePassword.tsx b/web-client/src/views/Login/ChangePassword.tsx new file mode 100644 index 00000000000..b12a5a6df73 --- /dev/null +++ b/web-client/src/views/Login/ChangePassword.tsx @@ -0,0 +1,218 @@ +import { Button } from '@web-client/ustc-ui/Button/Button'; +import { MessageAlert } from '@web-client/ustc-ui/MessageAlert/MessageAlert'; +import { RequirementsText } from '@web-client/views/CreatePetitionerAccount/RequirementsText'; +import { SuccessNotification } from '@web-client/views/SuccessNotification'; +import { connect } from '@web-client/presenter/shared.cerebral'; +import { sequences, state } from '@web-client/presenter/app.cerebral'; +import React from 'react'; + +export const ChangePassword = connect( + { + alertError: state.alertError, + changePasswordHelper: state.changePasswordHelper, + cognitoRequestPasswordResetUrl: state.cognitoRequestPasswordResetUrl, + confirmPassword: state.form.confirmPassword, + password: state.form.password, + showConfirmPassword: state.showConfirmPassword, + showPassword: state.showPassword, + submitLoginSequence: sequences.submitLoginSequence, + toggleShowPasswordSequence: sequences.toggleShowPasswordSequence, + updateFormValueSequence: sequences.updateFormValueSequence, + }, + ({ + alertError, + changePasswordHelper, + confirmPassword, + password, + showConfirmPassword, + showPassword, + submitLoginSequence, + toggleShowPasswordSequence, + updateFormValueSequence, + }) => { + return ( + <> +
+
+
+ + {alertError && ( + + )} +
+
+
+ {/* TODO: Update this with UX? */} +

Reset Password

+
+ + { + updateFormValueSequence({ + key: 'password', + value: e.target.value, + }); + }} + /> + + + + + { + updateFormValueSequence({ + key: 'confirmPassword', + value: e.target.value, + }); + }} + /> + +
+ + +
+
+
+
+
+
+
+
+ + ); + }, +); From 5be727da45437d0f17fc49a053ae8c81203b65f9 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Tue, 16 Jan 2024 13:12:18 -0800 Subject: [PATCH 184/700] 10007: Fix unit tests --- shared/src/test/mockUsers.ts | 19 +- .../dynamo/users/createOrUpdateUser.test.ts | 381 ++++++++---------- 2 files changed, 177 insertions(+), 223 deletions(-) diff --git a/shared/src/test/mockUsers.ts b/shared/src/test/mockUsers.ts index 6a0e9512ba1..960bebf95ae 100644 --- a/shared/src/test/mockUsers.ts +++ b/shared/src/test/mockUsers.ts @@ -13,7 +13,10 @@ import { import { RawIrsPractitioner } from '@shared/business/entities/IrsPractitioner'; import { RawPractitioner } from '@shared/business/entities/Practitioner'; import { RawUser } from '@shared/business/entities/User'; -import { getJudgesChambers } from '../../../web-client/src/business/chambers/getJudgesChambers'; +import { + getJudgesChambers, + getJudgesChambersWithLegacy, +} from '../../../web-client/src/business/chambers/getJudgesChambers'; export const adcUser = { name: 'ADC', @@ -79,6 +82,14 @@ export const judgeUser: RawUser = { userId: '43b00e5f-b78c-476c-820e-5d6ed1d58828', }; +export const legacyJudgeUser: RawUser = { + entityName: 'User', + name: 'Legacy Judge Ginsburg', + role: ROLES.legacyJudge, + section: getJudgesChambersWithLegacy().LEGACY_JUDGES_CHAMBERS_SECTION.section, + userId: 'dc67e189-cf3e-4ca3-a33f-91db111ec270', +}; + export const judgeColvin: RawUser = { email: 'judgeColvin@example.com', entityName: 'User', @@ -115,7 +126,7 @@ export const trialClerkUser: RawUser = { }; export const caseServicesSupervisorUser = { - name: 'CaseServicesSupervisor', + name: 'Test Case Services Supervisor', role: ROLES.caseServicesSupervisor, section: CASE_SERVICES_SUPERVISOR_SECTION, userId: '4562df8a-5c98-49a0-9c53-d8e4ff3b76bb', @@ -137,7 +148,9 @@ export const docketClerk1User: RawUser = { userId: 'b7d90c05-f6cd-442c-a168-202db587f16f', }; -export const petitionsClerkUser = { +export const petitionsClerkUser: RawUser = { + email: 'petitionsclerk1@example.com', + entityName: 'User', name: 'Petitionsclerk1', role: ROLES.petitionsClerk, section: PETITIONS_SECTION, diff --git a/web-api/src/persistence/dynamo/users/createOrUpdateUser.test.ts b/web-api/src/persistence/dynamo/users/createOrUpdateUser.test.ts index 4ee3e2094a6..f713a24ab48 100644 --- a/web-api/src/persistence/dynamo/users/createOrUpdateUser.test.ts +++ b/web-api/src/persistence/dynamo/users/createOrUpdateUser.test.ts @@ -1,216 +1,164 @@ -import { - PETITIONS_SECTION, - ROLES, -} from '../../../../../shared/src/business/entities/EntityConstants'; +import { UserNotFoundException } from '@aws-sdk/client-cognito-identity-provider'; import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; +import { + caseServicesSupervisorUser, + judgeColvin, + legacyJudgeUser, + petitionsClerkUser, + privatePractitionerUser, +} from '@shared/test/mockUsers'; import { createOrUpdateUser, createUserRecords } from './createOrUpdateUser'; -const JUDGES_CHAMBERS_WITH_LEGACY = applicationContext - .getPersistenceGateway() - .getJudgesChambersWithLegacy(); - describe('createOrUpdateUser', () => { - const userId = '9b52c605-edba-41d7-b045-d5f992a499d3'; - const petitionsClerkUser = { - email: 'test@example.com', - name: 'Test Petitionsclerk', - password: 'tempPass', - role: ROLES.petitionsClerk, - section: PETITIONS_SECTION, - }; - const privatePractitionerUser = { - barNumber: 'pt1234', //intentionally lower case - should be converted to upper case when persisted - name: 'Test Private Practitioner', - role: ROLES.privatePractitioner, - section: 'privatePractitioner', - }; - const privatePractitionerUserWithoutBarNumber = { - barNumber: '', - name: 'Test Private Practitioner', - role: ROLES.privatePractitioner, - section: 'privatePractitioner', - }; - const caseServicesSupervisorUser = { - name: 'Test Case Services Supervisor', - role: ROLES.caseServicesSupervisor, - section: 'caseServicesSupervisor', - }; - - beforeAll(() => { - applicationContext.getCognito().adminGetUser.mockReturnValue({ - promise: () => - Promise.resolve({ - Username: '562d6260-aa9b-4010-af99-536d3872c752', - }), - }); - - applicationContext.getCognito().adminCreateUser.mockReturnValue({ - promise: () => - Promise.resolve({ - User: { Username: '562d6260-aa9b-4010-af99-536d3872c752' }, - }), - }); + const mockTemporaryPassword = 'tempPass'; - applicationContext.getCognito().adminUpdateUserAttributes.mockReturnValue({ - promise: () => Promise.resolve(), - }); - - applicationContext.getCognito().adminDisableUser.mockReturnValue({ - promise: () => Promise.resolve(), - }); - - applicationContext.getDocumentClient().put.mockResolvedValue(null); - }); - - it('should create a user only if the user does not already exist', async () => { - applicationContext.getCognito().adminGetUser.mockReturnValue({ - promise: () => { - const error = new Error(); - (error as any).code = 'UserNotFoundException'; - return Promise.reject(error); - }, + it('should ONLY create a user when they do not already exist', async () => { + applicationContext + .getCognito() + .adminGetUser.mockRejectedValue( + new UserNotFoundException({ $metadata: {}, message: '' }), + ); + applicationContext.getCognito().adminCreateUser.mockResolvedValue({ + User: { Username: petitionsClerkUser.userId }, }); await createOrUpdateUser({ applicationContext, disableCognitoUser: false, - password: petitionsClerkUser.password, - user: petitionsClerkUser as any, + password: mockTemporaryPassword, + user: petitionsClerkUser, }); - expect( - applicationContext.getCognito().adminDisableUser, - ).not.toHaveBeenCalled(); - expect( - applicationContext.getCognito().adminUpdateUserAttributes, - ).not.toHaveBeenCalled(); - }); - - it('should create a user and cognito record, but disable the cognito user', async () => { - applicationContext.getCognito().adminGetUser.mockReturnValue({ - promise: () => { - const error = new Error(); - (error as any).code = 'UserNotFoundException'; - return Promise.reject(error); - }, - }); - - await createOrUpdateUser({ - applicationContext, - disableCognitoUser: true, - password: petitionsClerkUser.password, - user: petitionsClerkUser as any, - }); - - expect(applicationContext.getCognito().adminCreateUser).toHaveBeenCalled(); - expect(applicationContext.getCognito().adminDisableUser).toHaveBeenCalled(); - expect(applicationContext.getCognito().adminGetUser).toHaveBeenCalled(); - expect( - applicationContext.getCognito().adminUpdateUserAttributes, - ).not.toHaveBeenCalled(); - }); - - it('should call adminCreateUser with the correct UserAttributes', async () => { - await createOrUpdateUser({ - applicationContext, - disableCognitoUser: false, - password: petitionsClerkUser.password, - user: petitionsClerkUser as any, - }); expect( applicationContext.getCognito().adminCreateUser, ).toHaveBeenCalledWith({ + DesiredDeliveryMediums: ['EMAIL'], MessageAction: 'SUPPRESS', + TemporaryPassword: mockTemporaryPassword, UserAttributes: [ { Name: 'email_verified', Value: 'True', }, + { Name: 'email', - Value: 'test@example.com', + Value: petitionsClerkUser.email, }, { Name: 'custom:role', - Value: 'petitionsclerk', + Value: petitionsClerkUser.role, }, { Name: 'name', - Value: 'Test Petitionsclerk', + Value: petitionsClerkUser.name, }, ], UserPoolId: undefined, - Username: 'test@example.com', + Username: petitionsClerkUser.email, }); + expect( + applicationContext.getCognito().adminDisableUser, + ).not.toHaveBeenCalled(); + expect( + applicationContext.getCognito().adminUpdateUserAttributes, + ).not.toHaveBeenCalled(); }); - it('should attempt to update the user if the user already exists', async () => { - applicationContext.getCognito().adminGetUser.mockReturnValue({ - promise: () => - Promise.resolve({ - Username: '562d6260-aa9b-4010-af99-536d3872c752', - }), + it('should create a user and cognito record, but disable the cognito user', async () => { + applicationContext + .getCognito() + .adminGetUser.mockRejectedValue( + new UserNotFoundException({ $metadata: {}, message: '' }), + ); + applicationContext.getCognito().adminCreateUser.mockResolvedValue({ + User: { Username: petitionsClerkUser.userId }, }); await createOrUpdateUser({ applicationContext, - disableCognitoUser: false, - password: petitionsClerkUser.password, - user: petitionsClerkUser as any, + disableCognitoUser: true, + password: mockTemporaryPassword, + user: petitionsClerkUser, }); - expect( - applicationContext.getCognito().adminCreateUser, - ).not.toHaveBeenCalled(); + expect(applicationContext.getCognito().adminCreateUser).toHaveBeenCalled(); + expect(applicationContext.getCognito().adminDisableUser).toHaveBeenCalled(); expect(applicationContext.getCognito().adminGetUser).toHaveBeenCalled(); expect( applicationContext.getCognito().adminUpdateUserAttributes, - ).toHaveBeenCalled(); + ).not.toHaveBeenCalled(); }); - it('attempts to persist a private practitioner user with name and barNumber mapping records', async () => { - await createUserRecords({ - applicationContext, - user: privatePractitionerUser, - userId, + it('should attempt to update the user when the user already exists', async () => { + applicationContext.getCognito().adminGetUser.mockResolvedValue({ + Username: petitionsClerkUser.userId, }); - expect( - applicationContext.getDocumentClient().put.mock.calls[0][0], - ).toMatchObject({ - Item: { - ...privatePractitionerUser, - pk: `user|${userId}`, - sk: `user|${userId}`, - }, + await createOrUpdateUser({ + applicationContext, + disableCognitoUser: false, + password: mockTemporaryPassword, + user: petitionsClerkUser, }); + + expect(applicationContext.getCognito().adminGetUser).toHaveBeenCalled(); expect( - applicationContext.getDocumentClient().put.mock.calls[1][0], - ).toMatchObject({ - Item: { - pk: 'privatePractitioner|TEST PRIVATE PRACTITIONER', - sk: `user|${userId}`, - }, - }); + applicationContext.getCognito().adminCreateUser, + ).not.toHaveBeenCalled(); expect( - applicationContext.getDocumentClient().put.mock.calls[2][0], - ).toMatchObject({ - Item: { - pk: 'privatePractitioner|PT1234', - sk: `user|${userId}`, - }, - }); + applicationContext.getCognito().adminUpdateUserAttributes, + ).toHaveBeenCalled(); }); describe('createUserRecords', () => { - it('attempts to persist a petitionsclerk user with a section mapping record', async () => { + const mockPrivatePractitionerUser = { + ...privatePractitionerUser, + barNumber: 'pt1234', //intentionally lower case - should be converted to upper case when persisted + }; + + it('should persist a private practitioner user with name and barNumber mapping records', async () => { + await createUserRecords({ + applicationContext, + user: mockPrivatePractitionerUser, + userId: mockPrivatePractitionerUser.userId, + }); + + expect( + applicationContext.getDocumentClient().put.mock.calls[0][0], + ).toMatchObject({ + Item: { + ...mockPrivatePractitionerUser, + pk: `user|${mockPrivatePractitionerUser.userId}`, + sk: `user|${mockPrivatePractitionerUser.userId}`, + }, + }); + expect( + applicationContext.getDocumentClient().put.mock.calls[1][0], + ).toMatchObject({ + Item: { + pk: 'privatePractitioner|PRIVATE PRACTITIONER', + sk: `user|${mockPrivatePractitionerUser.userId}`, + }, + }); + expect( + applicationContext.getDocumentClient().put.mock.calls[2][0], + ).toMatchObject({ + Item: { + pk: 'privatePractitioner|PT1234', + sk: `user|${mockPrivatePractitionerUser.userId}`, + }, + }); + }); + + it('should persist a petitions clerk user with a section mapping record', async () => { await createUserRecords({ applicationContext, user: petitionsClerkUser, - userId, + userId: petitionsClerkUser.userId, }); - expect(applicationContext.getDocumentClient().put.mock.calls.length).toBe( + expect(applicationContext.getDocumentClient().put).toHaveBeenCalledTimes( 2, ); expect( @@ -218,7 +166,7 @@ describe('createOrUpdateUser', () => { ).toMatchObject({ Item: { pk: 'section|petitions', - sk: `user|${userId}`, + sk: `user|${petitionsClerkUser.userId}`, }, }); expect( @@ -226,33 +174,28 @@ describe('createOrUpdateUser', () => { ).toMatchObject({ Item: { ...petitionsClerkUser, - pk: `user|${userId}`, - sk: `user|${userId}`, + pk: `user|${petitionsClerkUser.userId}`, + sk: `user|${petitionsClerkUser.userId}`, }, }); }); - it('attempts to persist a judge user with a section mapping record for the chambers and the judge', async () => { - const judgeUser = { - name: 'Judge Adam', - role: ROLES.judge, - section: 'adamsChambers', - }; - + it('should persist a judge user with a section mapping record for the chambers and the judge', async () => { await createUserRecords({ applicationContext, - user: judgeUser, - userId, + user: judgeColvin, + userId: judgeColvin.userId, }); - expect(applicationContext.getDocumentClient().put.mock.calls.length).toBe( + + expect(applicationContext.getDocumentClient().put).toHaveBeenCalledTimes( 3, ); expect( applicationContext.getDocumentClient().put.mock.calls[0][0], ).toMatchObject({ Item: { - pk: 'section|adamsChambers', - sk: `user|${userId}`, + pk: `section|${judgeColvin.section}`, + sk: `user|${judgeColvin.userId}`, }, }); expect( @@ -260,33 +203,27 @@ describe('createOrUpdateUser', () => { ).toMatchObject({ Item: { pk: 'section|judge', - sk: `user|${userId}`, + sk: `user|${judgeColvin.userId}`, }, }); expect( applicationContext.getDocumentClient().put.mock.calls[2][0], ).toMatchObject({ Item: { - ...judgeUser, - pk: `user|${userId}`, - sk: `user|${userId}`, + ...judgeColvin, + pk: `user|${judgeColvin.userId}`, + sk: `user|${judgeColvin.userId}`, }, }); }); - it('attempts to persist a legacy judge user with a section mapping record for the chambers and the judge', async () => { - const judgeUser = { - name: 'Legacy Judge Ginsburg', - role: ROLES.legacyJudge, - section: - JUDGES_CHAMBERS_WITH_LEGACY.LEGACY_JUDGES_CHAMBERS_SECTION.section, - }; - + it('should persist a legacy judge user with a section mapping record for the chambers and the judge', async () => { await createUserRecords({ applicationContext, - user: judgeUser, - userId, + user: legacyJudgeUser, + userId: legacyJudgeUser.userId, }); + expect(applicationContext.getDocumentClient().put.mock.calls.length).toBe( 3, ); @@ -294,8 +231,8 @@ describe('createOrUpdateUser', () => { applicationContext.getDocumentClient().put.mock.calls[0][0], ).toMatchObject({ Item: { - pk: `section|${JUDGES_CHAMBERS_WITH_LEGACY.LEGACY_JUDGES_CHAMBERS_SECTION.section}`, - sk: `user|${userId}`, + pk: `section|${legacyJudgeUser.section}`, + sk: `user|${legacyJudgeUser.userId}`, }, }); expect( @@ -303,25 +240,30 @@ describe('createOrUpdateUser', () => { ).toMatchObject({ Item: { pk: 'section|judge', - sk: `user|${userId}`, + sk: `user|${legacyJudgeUser.userId}`, }, }); expect( applicationContext.getDocumentClient().put.mock.calls[2][0], ).toMatchObject({ Item: { - ...judgeUser, - pk: `user|${userId}`, - sk: `user|${userId}`, + ...legacyJudgeUser, + pk: `user|${legacyJudgeUser.userId}`, + sk: `user|${legacyJudgeUser.userId}`, }, }); }); - it('does not persist mapping records for practitioner without barNumber', async () => { + it('should NOT persist mapping records for practitioner that does not have a barNumber', async () => { + const privatePractitionerUserWithoutBarNumber = { + ...privatePractitionerUser, + barNumber: undefined, + }; + await createUserRecords({ applicationContext, user: privatePractitionerUserWithoutBarNumber, - userId, + userId: privatePractitionerUserWithoutBarNumber.userId, }); expect(applicationContext.getDocumentClient().put.mock.calls.length).toBe( @@ -332,17 +274,17 @@ describe('createOrUpdateUser', () => { ).toMatchObject({ Item: { ...privatePractitionerUserWithoutBarNumber, - pk: `user|${userId}`, - sk: `user|${userId}`, + pk: `user|${privatePractitionerUserWithoutBarNumber.userId}`, + sk: `user|${privatePractitionerUserWithoutBarNumber.userId}`, }, }); }); - it('attempts to persist a private practitioner user with name and barNumber mapping records', async () => { + it('should persist a private practitioner user with name and barNumber mapping records', async () => { await createUserRecords({ applicationContext, - user: privatePractitionerUser, - userId, + user: mockPrivatePractitionerUser, + userId: mockPrivatePractitionerUser.userId, }); expect(applicationContext.getDocumentClient().put.mock.calls.length).toBe( @@ -352,17 +294,17 @@ describe('createOrUpdateUser', () => { applicationContext.getDocumentClient().put.mock.calls[0][0], ).toMatchObject({ Item: { - ...privatePractitionerUser, - pk: `user|${userId}`, - sk: `user|${userId}`, + ...mockPrivatePractitionerUser, + pk: `user|${mockPrivatePractitionerUser.userId}`, + sk: `user|${mockPrivatePractitionerUser.userId}`, }, }); expect( applicationContext.getDocumentClient().put.mock.calls[1][0], ).toMatchObject({ Item: { - pk: 'privatePractitioner|TEST PRIVATE PRACTITIONER', - sk: `user|${userId}`, + pk: 'privatePractitioner|PRIVATE PRACTITIONER', + sk: `user|${mockPrivatePractitionerUser.userId}`, }, }); expect( @@ -370,7 +312,7 @@ describe('createOrUpdateUser', () => { ).toMatchObject({ Item: { pk: 'privatePractitioner|PT1234', - sk: `user|${userId}`, + sk: `user|${mockPrivatePractitionerUser.userId}`, }, }); }); @@ -379,7 +321,7 @@ describe('createOrUpdateUser', () => { await createUserRecords({ applicationContext, user: caseServicesSupervisorUser, - userId, + userId: caseServicesSupervisorUser.userId, }); expect( @@ -387,7 +329,7 @@ describe('createOrUpdateUser', () => { ).toMatchObject({ Item: { pk: `section|${caseServicesSupervisorUser.section}`, - sk: `user|${userId}`, + sk: `user|${caseServicesSupervisorUser.userId}`, }, }); expect( @@ -395,7 +337,7 @@ describe('createOrUpdateUser', () => { ).toMatchObject({ Item: { pk: 'section|docket', - sk: `user|${userId}`, + sk: `user|${caseServicesSupervisorUser.userId}`, }, }); expect( @@ -403,41 +345,40 @@ describe('createOrUpdateUser', () => { ).toMatchObject({ Item: { pk: 'section|petitions', - sk: `user|${userId}`, + sk: `user|${caseServicesSupervisorUser.userId}`, }, }); expect( applicationContext.getDocumentClient().put.mock.calls[3][0], ).toMatchObject({ Item: { - pk: `user|${userId}`, - sk: `user|${userId}`, + pk: `user|${caseServicesSupervisorUser.userId}`, + sk: `user|${caseServicesSupervisorUser.userId}`, }, }); }); - it('does not persist section mapping record if user does not have a section', async () => { - const privatePractitionerUserWithoutSection = { - name: 'Test Private Practitioner', - role: ROLES.privatePractitioner, - }; - + it('should NOT persist section mapping record when the user does not have a section', async () => { await createUserRecords({ applicationContext, - user: privatePractitionerUserWithoutSection, - userId, + user: { + ...petitionsClerkUser, + section: undefined, + }, + userId: petitionsClerkUser.userId, }); - expect(applicationContext.getDocumentClient().put.mock.calls.length).toBe( + expect(applicationContext.getDocumentClient().put).toHaveBeenCalledTimes( 1, ); expect( applicationContext.getDocumentClient().put.mock.calls[0][0], ).toMatchObject({ Item: { - ...privatePractitionerUserWithoutSection, - pk: `user|${userId}`, - sk: `user|${userId}`, + ...petitionsClerkUser, + pk: `user|${petitionsClerkUser.userId}`, + section: undefined, + sk: `user|${petitionsClerkUser.userId}`, }, }); }); From 4fd557a41b0e45ac991733a142a05100fd26fff4 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:56:35 -0600 Subject: [PATCH 185/700] 10007: updated changePasswordForm entity name --- .../entities/{ChangePassword.ts => ChangePasswordForm.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename shared/src/business/entities/{ChangePassword.ts => ChangePasswordForm.ts} (100%) diff --git a/shared/src/business/entities/ChangePassword.ts b/shared/src/business/entities/ChangePasswordForm.ts similarity index 100% rename from shared/src/business/entities/ChangePassword.ts rename to shared/src/business/entities/ChangePasswordForm.ts From 89a626948d510ffd48b67f66cb0961cb3db1d063 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:06:47 -0600 Subject: [PATCH 186/700] 10007: WIP finish adding change password infrastructure, sequences, form --- .../src/proxies/auth/changePasswordProxy.ts | 26 +++++++++ shared/src/proxies/public/loginProxy.ts | 7 +-- temp_delete_me.md | 1 + web-api/src/app.ts | 2 + .../useCases/auth/changePasswordInteractor.ts | 31 ++++++---- .../business/useCases/auth/loginInteractor.ts | 17 ++++-- web-api/src/getUseCases.ts | 2 + .../src/lambdas/auth/changePasswordLambda.ts | 15 +++++ web-client/src/applicationContext.ts | 2 + .../Login/navigateToChangePasswordAction.ts | 5 ++ .../Login/redirectToChangePasswordAction.ts | 3 - .../Login/submitChangePasswordAction.tsx | 57 +++++++++++++++++++ .../actions/Login/submitLoginAction.tsx | 21 ++++--- .../actions/setupChangePasswordFormAction.ts | 11 ++++ .../computeds/Login/changePasswordHelper.ts | 2 +- web-client/src/presenter/presenter.ts | 2 + .../Login/goToChangePasswordSequence.ts | 2 + .../Login/submitChangePasswordSequence.ts | 28 +++++++++ .../sequences/Login/submitLoginSequence.ts | 4 +- web-client/src/router.ts | 8 ++- web-client/src/views/Login/ChangePassword.tsx | 27 +++++---- 21 files changed, 222 insertions(+), 51 deletions(-) create mode 100644 shared/src/proxies/auth/changePasswordProxy.ts create mode 100644 web-api/src/lambdas/auth/changePasswordLambda.ts create mode 100644 web-client/src/presenter/actions/Login/navigateToChangePasswordAction.ts delete mode 100644 web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts create mode 100644 web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx create mode 100644 web-client/src/presenter/actions/setupChangePasswordFormAction.ts create mode 100644 web-client/src/presenter/sequences/Login/submitChangePasswordSequence.ts diff --git a/shared/src/proxies/auth/changePasswordProxy.ts b/shared/src/proxies/auth/changePasswordProxy.ts new file mode 100644 index 00000000000..ed81a799052 --- /dev/null +++ b/shared/src/proxies/auth/changePasswordProxy.ts @@ -0,0 +1,26 @@ +import { ClientApplicationContext } from '@web-client/applicationContext'; +import { post } from '../requests'; + +export const changePasswordInteractor = ( + applicationContext: ClientApplicationContext, + { + confirmPassword, + password, + session, + userEmail, + }: { + confirmPassword: string; + password: string; + userEmail: string; + session: string; + }, +) => { + return post({ + applicationContext, + body: { confirmPassword, password, session, userEmail }, + endpoint: '/auth/change-password', + options: { + withCredentials: false, + }, + }); +}; diff --git a/shared/src/proxies/public/loginProxy.ts b/shared/src/proxies/public/loginProxy.ts index 62202782c33..06551bfb339 100644 --- a/shared/src/proxies/public/loginProxy.ts +++ b/shared/src/proxies/public/loginProxy.ts @@ -1,13 +1,10 @@ +import { LoginInteractorResponse } from '@web-api/business/useCases/auth/loginInteractor'; import { post } from '@shared/proxies/requests'; export const loginInteractor = ( applicationContext, { email, password }: { email: string; password: string }, -): Promise<{ - accessToken: string; - idToken: string; - refreshToken: string; -}> => { +): Promise => { return post({ applicationContext, body: { email, password }, diff --git a/temp_delete_me.md b/temp_delete_me.md index fa1e1fb2e5e..cb55bf7b867 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -7,6 +7,7 @@ - Forgot password flow. - Zach look at errors in submitLoginAction for 1 hr. + (KS & TE) Change password flow. +- Move loginProxy out of public directory ::: SOLO TO DO::: diff --git a/web-api/src/app.ts b/web-api/src/app.ts index 8e217e2626f..f7461ad7bb0 100644 --- a/web-api/src/app.ts +++ b/web-api/src/app.ts @@ -15,6 +15,7 @@ import { associatePrivatePractitionerWithCaseLambda } from './lambdas/manualAsso import { batchDownloadTrialSessionLambda } from './lambdas/trialSessions/batchDownloadTrialSessionLambda'; import { blockCaseFromTrialLambda } from './lambdas/cases/blockCaseFromTrialLambda'; import { caseAdvancedSearchLambda } from './lambdas/cases/caseAdvancedSearchLambda'; +import { changePasswordLambda } from '@web-api/lambdas/auth/changePasswordLambda'; import { checkEmailAvailabilityLambda } from './lambdas/users/checkEmailAvailabilityLambda'; import { checkForReadyForTrialCasesLambda } from './lambdas/cases/checkForReadyForTrialCasesLambda'; import { closeTrialSessionLambda } from './lambdas/trialSessions/closeTrialSessionLambda'; @@ -1026,6 +1027,7 @@ app.get( app.post('/auth/refresh', lambdaWrapper(renewIdTokenLambda)); app.post('/auth/confirm-signup', lambdaWrapper(confirmSignUpLambda)); app.post('/auth/account/create', lambdaWrapper(signUpUserLambda)); + app.post('/auth/change-password', lambdaWrapper(changePasswordLambda)); } // This endpoint is used for testing purpose only which exposes the diff --git a/web-api/src/business/useCases/auth/changePasswordInteractor.ts b/web-api/src/business/useCases/auth/changePasswordInteractor.ts index 9d368652fda..038dbd37d1a 100644 --- a/web-api/src/business/useCases/auth/changePasswordInteractor.ts +++ b/web-api/src/business/useCases/auth/changePasswordInteractor.ts @@ -1,25 +1,34 @@ +import { RespondToAuthChallengeCommandInput } from '@aws-sdk/client-cognito-identity-provider'; +import { ServerApplicationContext } from '@web-api/applicationContext'; + export const changePasswordInteractor = async ( - applicationContext: IApplicationContext, + applicationContext: ServerApplicationContext, { - newPassword, - sessionId, + confirmPassword, + password, + session, userEmail, - }: { newPassword: string; sessionId: string; userEmail: string }, + }: { + password: string; + session: string; + userEmail: string; + confirmPassword: string; + }, ) => { - const params = { + // confirm password = confirmPassword + console.log('confirmPassword', confirmPassword); + const params: RespondToAuthChallengeCommandInput = { ChallengeName: 'NEW_PASSWORD_REQUIRED', ChallengeResponses: { - NEW_PASSWORD: newPassword, + NEW_PASSWORD: password, USERNAME: userEmail, }, ClientId: process.env.COGNITO_CLIENT_ID, - Session: sessionId, + Session: session, }; - const result = await applicationContext - .getCognito() - .respondToAuthChallenge(params) - .promise(); + const cognito = applicationContext.getCognito(); + const result = await cognito.respondToAuthChallenge(params); return result; }; diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index ee4b281b76d..e1ca93546a8 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -5,10 +5,18 @@ import { } from '@web-api/errors/errors'; import { ServerApplicationContext } from '@web-api/applicationContext'; +export type LoginInteractorResponse = { + idToken?: string; + accessToken?: string; + refreshToken?: string; + challengeName?: string; + session?: string; +}; + export const loginInteractor = async ( applicationContext: ServerApplicationContext, { email, password }: { email: string; password: string }, -): Promise<{ idToken: string; accessToken: string; refreshToken: string }> => { +): Promise => { try { const result = await applicationContext.getCognito().initiateAuth({ AuthFlow: 'USER_PASSWORD_AUTH', @@ -20,9 +28,10 @@ export const loginInteractor = async ( }); if (result?.ChallengeName === 'NEW_PASSWORD_REQUIRED') { - const PasswordChangeError = new Error('NewPasswordRequired'); - PasswordChangeError.name = 'NewPasswordRequired'; - throw PasswordChangeError; + return { + challengeName: 'NEW_PASSWORD_REQUIRED', + session: result.Session!, + }; } return { diff --git a/web-api/src/getUseCases.ts b/web-api/src/getUseCases.ts index afd76577f5b..79f3cb32b6c 100644 --- a/web-api/src/getUseCases.ts +++ b/web-api/src/getUseCases.ts @@ -16,6 +16,7 @@ import { batchDownloadTrialSessionInteractor } from '../../shared/src/business/u import { blockCaseFromTrialInteractor } from '../../shared/src/business/useCases/blockCaseFromTrialInteractor'; import { caseAdvancedSearchInteractor } from '../../shared/src/business/useCases/caseAdvancedSearchInteractor'; import { casePublicSearchInteractor } from '../../shared/src/business/useCases/public/casePublicSearchInteractor'; +import { changePasswordInteractor } from '@web-api/business/useCases/auth/changePasswordInteractor'; import { checkEmailAvailabilityInteractor } from '../../shared/src/business/useCases/users/checkEmailAvailabilityInteractor'; import { checkForReadyForTrialCasesInteractor } from '../../shared/src/business/useCases/checkForReadyForTrialCasesInteractor'; import { closeTrialSessionInteractor } from '../../shared/src/business/useCases/trialSessions/closeTrialSessionInteractor'; @@ -228,6 +229,7 @@ const useCases = { blockCaseFromTrialInteractor, caseAdvancedSearchInteractor, casePublicSearchInteractor, + changePasswordInteractor, checkEmailAvailabilityInteractor, checkForReadyForTrialCasesInteractor, closeTrialSessionInteractor, diff --git a/web-api/src/lambdas/auth/changePasswordLambda.ts b/web-api/src/lambdas/auth/changePasswordLambda.ts new file mode 100644 index 00000000000..6dfca41adc2 --- /dev/null +++ b/web-api/src/lambdas/auth/changePasswordLambda.ts @@ -0,0 +1,15 @@ +import { APIGatewayProxyEvent } from 'aws-lambda'; +import { genericHandler } from '../../genericHandler'; + +export const changePasswordLambda = (event: APIGatewayProxyEvent) => + genericHandler( + event, + async ({ applicationContext }) => { + return await applicationContext + .getUseCases() + .changePasswordInteractor(applicationContext, { + ...JSON.parse(event.body), + }); + }, + { logResults: false }, + ); diff --git a/web-client/src/applicationContext.ts b/web-client/src/applicationContext.ts index b2c328fc1f6..b679fff8bdc 100644 --- a/web-client/src/applicationContext.ts +++ b/web-client/src/applicationContext.ts @@ -72,6 +72,7 @@ import { canConsolidateInteractor } from '../../shared/src/business/useCases/cas import { canSetTrialSessionAsCalendaredInteractor } from '../../shared/src/business/useCases/trialSessions/canSetTrialSessionAsCalendaredInteractor'; import { caseAdvancedSearchInteractor } from '../../shared/src/proxies/caseAdvancedSearchProxy'; import { caseStatusWithTrialInformation } from '@shared/business/utilities/caseStatusWithTrialInformation'; +import { changePasswordInteractor } from '@shared/proxies/auth/changePasswordProxy'; import { checkEmailAvailabilityInteractor } from '../../shared/src/proxies/users/checkEmailAvailabilityProxy'; import { closeTrialSessionInteractor } from '../../shared/src/proxies/trialSessions/closeTrialSessionProxy'; import { @@ -402,6 +403,7 @@ const allUseCases = { canConsolidateInteractor, canSetTrialSessionAsCalendaredInteractor, caseAdvancedSearchInteractor, + changePasswordInteractor, checkEmailAvailabilityInteractor, closeTrialSessionInteractor, completeDocketEntryQCInteractor, diff --git a/web-client/src/presenter/actions/Login/navigateToChangePasswordAction.ts b/web-client/src/presenter/actions/Login/navigateToChangePasswordAction.ts new file mode 100644 index 00000000000..0522d4787fb --- /dev/null +++ b/web-client/src/presenter/actions/Login/navigateToChangePasswordAction.ts @@ -0,0 +1,5 @@ +export const navigateToChangePasswordAction = async ({ props, router }) => { + await router.route( + `/change-password?userEmail=${props.userEmail}?session=${props.session}`, + ); +}; diff --git a/web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts b/web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts deleted file mode 100644 index a3966d6aeb0..00000000000 --- a/web-client/src/presenter/actions/Login/redirectToChangePasswordAction.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const redirectToChangePasswordAction = async ({ router }) => { - await router.route('/change-password'); -}; diff --git a/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx b/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx new file mode 100644 index 00000000000..3d1081344a1 --- /dev/null +++ b/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx @@ -0,0 +1,57 @@ +import { state } from '@web-client/presenter/app.cerebral'; +import React from 'react'; + +export const submitChangePasswordAction = async ({ + applicationContext, + get, + path, +}: ActionProps): Promise<{ + accessToken: string; + idToken: string; + refreshToken: string; +}> => { + // TODO: move userEmail and session off form.state + const { confirmPassword, password, session, userEmail } = get(state.form); + + try { + const { accessToken, idToken, refreshToken } = await applicationContext + .getUseCases() + .changePasswordInteractor(applicationContext, { + confirmPassword, + password, + session, + userEmail, + }).AuthenticationResult; + + return path.success({ accessToken, idToken, refreshToken }); + } catch (err: any) { + const originalErrorMessage = err?.originalError?.response?.data; + + if (originalErrorMessage === 'User is unconfirmed') { + return path.error({ + alertError: { + message: ( + <> + The email address is associated with an account but is not + verified. We sent an email with a link to verify the email + address. If you don’t see it, check your spam folder. If you’re + still having trouble, email{' '} + + dawson.support@ustaxcourt.gov + + . + + ), + title: 'Email address not verified', + }, + }); + } + + return path.error({ + alertError: { + title: + 'There was an unexpected error when logging in. Please try again.', + }, + }); + } +}; diff --git a/web-client/src/presenter/actions/Login/submitLoginAction.tsx b/web-client/src/presenter/actions/Login/submitLoginAction.tsx index bc82d23407e..17b8a5bcd50 100644 --- a/web-client/src/presenter/actions/Login/submitLoginAction.tsx +++ b/web-client/src/presenter/actions/Login/submitLoginAction.tsx @@ -6,25 +6,28 @@ export const submitLoginAction = async ({ get, path, }: ActionProps): Promise<{ - accessToken: string; - idToken: string; - refreshToken: string; + accessToken?: string; + idToken?: string; + refreshToken?: string; + session?: string; + userEmail?: string; }> => { const { email, password } = get(state.form); try { - const { accessToken, idToken, refreshToken } = await applicationContext + const result = await applicationContext .getUseCases() .loginInteractor(applicationContext, { email, password }); - return path.success({ accessToken, idToken, refreshToken }); + if (result.challengeName) { + return path.changePassword({ session: result.session, userEmail: email }); + } else { + const { accessToken, idToken, refreshToken } = result; + return path.success({ accessToken, idToken, refreshToken }); + } } catch (err: any) { const originalErrorMessage = err?.originalError?.response?.data; - if (originalErrorMessage === 'NewPasswordRequired') { - return path.changePassword(); - } - if (originalErrorMessage === 'Invalid Username or Password') { return path.error({ alertError: { diff --git a/web-client/src/presenter/actions/setupChangePasswordFormAction.ts b/web-client/src/presenter/actions/setupChangePasswordFormAction.ts new file mode 100644 index 00000000000..10cb6b1ac01 --- /dev/null +++ b/web-client/src/presenter/actions/setupChangePasswordFormAction.ts @@ -0,0 +1,11 @@ +import { state } from '@web-client/presenter/app.cerebral'; + +export const setupChangePasswordFormAction = ({ + props, + store, +}: ActionProps) => { + const { session, userEmail } = props; + + store.set(state.form.session, session); + store.set(state.form.userEmail, userEmail); +}; diff --git a/web-client/src/presenter/computeds/Login/changePasswordHelper.ts b/web-client/src/presenter/computeds/Login/changePasswordHelper.ts index dcb49f2b30e..fae29abd6bf 100644 --- a/web-client/src/presenter/computeds/Login/changePasswordHelper.ts +++ b/web-client/src/presenter/computeds/Login/changePasswordHelper.ts @@ -1,4 +1,4 @@ -import { ChangePasswordForm } from '@shared/business/entities/ChangePassword'; +import { ChangePasswordForm } from '@shared/business/entities/ChangePasswordForm'; import { Get } from 'cerebral'; import { PasswordValidations } from '@shared/business/entities/NewPetitionerUser'; import { convertErrorMessageToPasswordValidationObject } from '@web-client/presenter/computeds/CreatePetitionerAccount/createAccountHelper'; diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index de3a0b1a102..9212045cac4 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -402,6 +402,7 @@ import { submitCaseInventoryReportModalSequence } from './sequences/submitCaseIn import { submitCaseSearchForConsolidationSequence } from './sequences/submitCaseSearchForConsolidationSequence'; import { submitCaseSearchSequence } from './sequences/submitCaseSearchSequence'; import { submitChangeLoginAndServiceEmailSequence } from './sequences/submitChangeLoginAndServiceEmailSequence'; +import { submitChangePasswordSequence } from '@web-client/presenter/sequences/Login/submitChangePasswordSequence'; import { submitCourtIssuedDocketEntrySequence } from './sequences/submitCourtIssuedDocketEntrySequence'; import { submitCourtIssuedOrderSequence } from './sequences/submitCourtIssuedOrderSequence'; import { submitCreateOrderModalSequence } from './sequences/submitCreateOrderModalSequence'; @@ -1231,6 +1232,7 @@ export const presenterSequences = { submitCaseSearchSequence: submitCaseSearchSequence as unknown as Function, submitChangeLoginAndServiceEmailSequence: submitChangeLoginAndServiceEmailSequence as unknown as Function, + submitChangePasswordSequence, submitCourtIssuedDocketEntrySequence: submitCourtIssuedDocketEntrySequence as unknown as Function, submitCourtIssuedOrderSequence: diff --git a/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts b/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts index 799398ce37a..5e81508f914 100644 --- a/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts +++ b/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts @@ -1,5 +1,7 @@ +import { setupChangePasswordFormAction } from '@web-client/presenter/actions/setupChangePasswordFormAction'; import { setupCurrentPageAction } from '../../actions/setupCurrentPageAction'; export const goToChangePasswordSequence = [ + setupChangePasswordFormAction, setupCurrentPageAction('ChangePassword'), ] as unknown as () => void; diff --git a/web-client/src/presenter/sequences/Login/submitChangePasswordSequence.ts b/web-client/src/presenter/sequences/Login/submitChangePasswordSequence.ts new file mode 100644 index 00000000000..360425edc9a --- /dev/null +++ b/web-client/src/presenter/sequences/Login/submitChangePasswordSequence.ts @@ -0,0 +1,28 @@ +import { clearFormAction } from '@web-client/presenter/actions/clearFormAction'; +import { decodeTokenAction } from '@web-client/presenter/actions/decodeTokenAction'; +import { getUserAction } from '@web-client/presenter/actions/getUserAction'; +import { navigateToPathAction } from '@web-client/presenter/actions/navigateToPathAction'; +import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertErrorAction'; +import { setTokenAction } from '@web-client/presenter/actions/Login/setTokenAction'; +import { setUserAction } from '@web-client/presenter/actions/setUserAction'; +import { setUserPermissionsAction } from '@web-client/presenter/actions/setUserPermissionsAction'; +import { showProgressSequenceDecorator } from '../../utilities/showProgressSequenceDecorator'; +import { submitChangePasswordAction } from '@web-client/presenter/actions/Login/submitChangePasswordAction'; + +export const submitChangePasswordSequence = [ + showProgressSequenceDecorator([ + submitChangePasswordAction, + { + error: [setAlertErrorAction], + success: [ + clearFormAction, + decodeTokenAction, + setTokenAction, + getUserAction, + setUserAction, + setUserPermissionsAction, + navigateToPathAction, + ], + }, + ]), +] as unknown as () => void; diff --git a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts index 392bdb688b4..fcfeb081ca4 100644 --- a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts @@ -1,8 +1,8 @@ import { clearFormAction } from '@web-client/presenter/actions/clearFormAction'; import { decodeTokenAction } from '@web-client/presenter/actions/decodeTokenAction'; import { getUserAction } from '@web-client/presenter/actions/getUserAction'; +import { navigateToChangePasswordAction } from '@web-client/presenter/actions/Login/navigateToChangePasswordAction'; import { navigateToPathAction } from '@web-client/presenter/actions/navigateToPathAction'; -import { redirectToChangePasswordAction } from '@web-client/presenter/actions/Login/redirectToChangePasswordAction'; import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertErrorAction'; import { setTokenAction } from '@web-client/presenter/actions/Login/setTokenAction'; import { setUserAction } from '@web-client/presenter/actions/setUserAction'; @@ -14,7 +14,7 @@ export const submitLoginSequence = [ showProgressSequenceDecorator([ submitLoginAction, { - changePassword: [redirectToChangePasswordAction], + changePassword: [navigateToChangePasswordAction], error: [setAlertErrorAction], success: [ clearFormAction, diff --git a/web-client/src/router.ts b/web-client/src/router.ts index 31ef759f7d4..15bf930d290 100644 --- a/web-client/src/router.ts +++ b/web-client/src/router.ts @@ -1117,9 +1117,13 @@ const router = { app.getSequence('gotoLoginSequence')(); }); - registerRoute('/change-password', () => { + registerRoute('/change-password?..', () => { + const { session, userEmail } = route.query(); setPageTitle('Change Password'); - app.getSequence('goToChangePasswordSequence')(); + app.getSequence('goToChangePasswordSequence')({ + session, + userEmail, + }); }); registerRoute('/create-account/petitioner', () => { diff --git a/web-client/src/views/Login/ChangePassword.tsx b/web-client/src/views/Login/ChangePassword.tsx index b12a5a6df73..88df68812dd 100644 --- a/web-client/src/views/Login/ChangePassword.tsx +++ b/web-client/src/views/Login/ChangePassword.tsx @@ -10,12 +10,11 @@ export const ChangePassword = connect( { alertError: state.alertError, changePasswordHelper: state.changePasswordHelper, - cognitoRequestPasswordResetUrl: state.cognitoRequestPasswordResetUrl, confirmPassword: state.form.confirmPassword, password: state.form.password, showConfirmPassword: state.showConfirmPassword, showPassword: state.showPassword, - submitLoginSequence: sequences.submitLoginSequence, + submitChangePasswordSequence: sequences.submitChangePasswordSequence, toggleShowPasswordSequence: sequences.toggleShowPasswordSequence, updateFormValueSequence: sequences.updateFormValueSequence, }, @@ -26,7 +25,7 @@ export const ChangePassword = connect( password, showConfirmPassword, showPassword, - submitLoginSequence, + submitChangePasswordSequence, toggleShowPasswordSequence, updateFormValueSequence, }) => { @@ -193,18 +192,18 @@ export const ChangePassword = connect( text="Passwords must match" valid={changePasswordHelper.confirmPassword} > -
+
From 6e17e58387b85dbe45b02d63f0298a6015fd1cf4 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 16 Jan 2024 14:23:19 -0800 Subject: [PATCH 187/700] 10007: create helper function to login for pa11y --- temp_delete_me.md | 3 +-- web-client/pa11y/helpers.js | 11 +++++++++++ web-client/pa11y/pa11y-chambers.js | 12 ++++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index fa1e1fb2e5e..ca795dbcffb 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -3,9 +3,8 @@ - Fix tests - web-client/integration-tests/admissionsClerkCreatesPractitionerAccount.test.ts - Pa11y tests. Determine strategy for how to fix. -- Extract error message strings into constants OR do something else. ++ Extract error message strings into constants OR do something else. - Forgot password flow. -- Zach look at errors in submitLoginAction for 1 hr. + (KS & TE) Change password flow. ::: SOLO TO DO::: diff --git a/web-client/pa11y/helpers.js b/web-client/pa11y/helpers.js index 31cd9cae927..52c8d6b8732 100644 --- a/web-client/pa11y/helpers.js +++ b/web-client/pa11y/helpers.js @@ -20,7 +20,18 @@ const setTimeouts = url => { }; }; +const loginAs = ({ username }) => { + return [ + 'wait for [data-testid="email-input"] to be visible', + `set field [data-testid="email-input"] to ${username}`, + 'set field [data-testid="password-input"] to Testing1234$', + 'click element [data-testid="login-button"]', + 'wait for [data-testid="account-menu-button"] to be visible', + ]; +}; + module.exports = { getOnly, + loginAs, setTimeouts, }; diff --git a/web-client/pa11y/pa11y-chambers.js b/web-client/pa11y/pa11y-chambers.js index ca8d64e7f68..32e3b9da21a 100644 --- a/web-client/pa11y/pa11y-chambers.js +++ b/web-client/pa11y/pa11y-chambers.js @@ -1,4 +1,12 @@ +const { loginAs } = require('./helpers'); + module.exports = [ - 'http://localhost:1234/log-in?code=colvinschambers@example.com&path=/', - 'http://localhost:1234/log-in?code=cohenschambers@example.com&path=/case-detail/105-20/documents/3eb53932-1a44-40d1-bfb8-d9e908b0b32e/apply-stamp', + { + actions: [ + ...loginAs({ username: 'colvinschambers@example.com' }), + 'navigate to http://localhost:1234/', + ], + url: 'http://localhost:1234/', + }, + // 'http://localhost:1234/case-detail/105-20/documents/3eb53932-1a44-40d1-bfb8-d9e908b0b32e/apply-stamp', This NEVER actually ran this URL. ]; From f45132c56dd377d93216852d23793290ea4113a2 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 16 Jan 2024 14:26:26 -0800 Subject: [PATCH 188/700] 10007: Use new login helper function for pa11y --- web-client/pa11y/pa11y-floater.js | 10 +++++++++- web-client/pa11y/pa11y-general.js | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/web-client/pa11y/pa11y-floater.js b/web-client/pa11y/pa11y-floater.js index 56173458fa2..6fa3bc164bd 100644 --- a/web-client/pa11y/pa11y-floater.js +++ b/web-client/pa11y/pa11y-floater.js @@ -1,3 +1,11 @@ +const { loginAs } = require('./helpers'); + module.exports = [ - 'http://localhost:1234/log-in?code=floater@example.com&path=/', + { + actions: [ + ...loginAs({ username: 'floater@example.com' }), + 'navigate to http://localhost:1234/', + ], + url: 'http://localhost:1234/', + }, ]; diff --git a/web-client/pa11y/pa11y-general.js b/web-client/pa11y/pa11y-general.js index 8e49f197239..c05561c5efc 100644 --- a/web-client/pa11y/pa11y-general.js +++ b/web-client/pa11y/pa11y-general.js @@ -1,3 +1,11 @@ +const { loginAs } = require('./helpers'); + module.exports = [ - 'http://localhost:1234/log-in?code=general@example.com&path=/', + { + actions: [ + ...loginAs({ username: 'general@example.com' }), + 'navigate to http://localhost:1234/', + ], + url: 'http://localhost:1234/', + }, ]; From 09e047bd692a1696ed18d1cbce0082fff7267c7d Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 17:12:20 -0600 Subject: [PATCH 189/700] 10007: WIP reset password flow --- .../src/proxies/auth/changePasswordProxy.ts | 6 +- shared/src/proxies/public/loginProxy.ts | 7 +- .../useCases/auth/changePasswordInteractor.ts | 78 ++++++++++++++----- .../business/useCases/auth/loginInteractor.ts | 18 ++--- .../Login/navigateToChangePasswordAction.ts | 4 +- .../Login/submitChangePasswordAction.tsx | 8 +- .../actions/Login/submitLoginAction.tsx | 21 +++-- .../actions/setupChangePasswordFormAction.ts | 4 +- .../sequences/Login/submitLoginSequence.ts | 4 +- 9 files changed, 93 insertions(+), 57 deletions(-) diff --git a/shared/src/proxies/auth/changePasswordProxy.ts b/shared/src/proxies/auth/changePasswordProxy.ts index ed81a799052..d687aaa4f50 100644 --- a/shared/src/proxies/auth/changePasswordProxy.ts +++ b/shared/src/proxies/auth/changePasswordProxy.ts @@ -6,18 +6,18 @@ export const changePasswordInteractor = ( { confirmPassword, password, - session, + tempPassword, userEmail, }: { confirmPassword: string; password: string; userEmail: string; - session: string; + tempPassword: string; }, ) => { return post({ applicationContext, - body: { confirmPassword, password, session, userEmail }, + body: { confirmPassword, password, tempPassword, userEmail }, endpoint: '/auth/change-password', options: { withCredentials: false, diff --git a/shared/src/proxies/public/loginProxy.ts b/shared/src/proxies/public/loginProxy.ts index 06551bfb339..62202782c33 100644 --- a/shared/src/proxies/public/loginProxy.ts +++ b/shared/src/proxies/public/loginProxy.ts @@ -1,10 +1,13 @@ -import { LoginInteractorResponse } from '@web-api/business/useCases/auth/loginInteractor'; import { post } from '@shared/proxies/requests'; export const loginInteractor = ( applicationContext, { email, password }: { email: string; password: string }, -): Promise => { +): Promise<{ + accessToken: string; + idToken: string; + refreshToken: string; +}> => { return post({ applicationContext, body: { email, password }, diff --git a/web-api/src/business/useCases/auth/changePasswordInteractor.ts b/web-api/src/business/useCases/auth/changePasswordInteractor.ts index 038dbd37d1a..efbc0aff66d 100644 --- a/web-api/src/business/useCases/auth/changePasswordInteractor.ts +++ b/web-api/src/business/useCases/auth/changePasswordInteractor.ts @@ -1,34 +1,76 @@ import { RespondToAuthChallengeCommandInput } from '@aws-sdk/client-cognito-identity-provider'; import { ServerApplicationContext } from '@web-api/applicationContext'; +import { + UnauthorizedError, + UnidentifiedUserError, +} from '@web-api/errors/errors'; export const changePasswordInteractor = async ( applicationContext: ServerApplicationContext, { confirmPassword, password, - session, + tempPassword, userEmail, }: { password: string; - session: string; + tempPassword: string; userEmail: string; confirmPassword: string; }, ) => { - // confirm password = confirmPassword - console.log('confirmPassword', confirmPassword); - const params: RespondToAuthChallengeCommandInput = { - ChallengeName: 'NEW_PASSWORD_REQUIRED', - ChallengeResponses: { - NEW_PASSWORD: password, - USERNAME: userEmail, - }, - ClientId: process.env.COGNITO_CLIENT_ID, - Session: session, - }; - - const cognito = applicationContext.getCognito(); - const result = await cognito.respondToAuthChallenge(params); - - return result; + try { + // TODO: Validate Password === ConfirmPassword + Rules? + console.log('confirmPassword', confirmPassword); + + const initiateAuthResult = await applicationContext + .getCognito() + .initiateAuth({ + AuthFlow: 'USER_PASSWORD_AUTH', + AuthParameters: { + PASSWORD: tempPassword, + USERNAME: userEmail, + }, + ClientId: applicationContext.environment.cognitoClientId, + }); + + if (initiateAuthResult?.ChallengeName === 'NEW_PASSWORD_REQUIRED') { + const params: RespondToAuthChallengeCommandInput = { + ChallengeName: 'NEW_PASSWORD_REQUIRED', + ChallengeResponses: { + NEW_PASSWORD: password, + USERNAME: userEmail, + }, + ClientId: process.env.COGNITO_CLIENT_ID, + Session: initiateAuthResult.Session, + }; + + const cognito = applicationContext.getCognito(); + const result = await cognito.respondToAuthChallenge(params); + + return { + accessToken: result.AuthenticationResult!.AccessToken!, + idToken: result.AuthenticationResult!.IdToken!, + refreshToken: result.AuthenticationResult!.RefreshToken!, + }; + } + + throw new Error('Something went wrong while changing passwords... :('); + } catch (err: any) { + console.log('changePasswordInteractorError', err); + + if ( + err.name === 'InvalidPasswordException' || + err.name === 'NotAuthorizedException' || + err.name === 'UserNotFoundException' + ) { + throw new UnidentifiedUserError('Invalid Username or Password'); //401 + } + + if (err.name === 'UserNotConfirmedException') { + throw new UnauthorizedError('User is unconfirmed'); //403 + } + + throw err; + } }; diff --git a/web-api/src/business/useCases/auth/loginInteractor.ts b/web-api/src/business/useCases/auth/loginInteractor.ts index e1ca93546a8..9f864010c7c 100644 --- a/web-api/src/business/useCases/auth/loginInteractor.ts +++ b/web-api/src/business/useCases/auth/loginInteractor.ts @@ -5,18 +5,10 @@ import { } from '@web-api/errors/errors'; import { ServerApplicationContext } from '@web-api/applicationContext'; -export type LoginInteractorResponse = { - idToken?: string; - accessToken?: string; - refreshToken?: string; - challengeName?: string; - session?: string; -}; - export const loginInteractor = async ( applicationContext: ServerApplicationContext, { email, password }: { email: string; password: string }, -): Promise => { +): Promise<{ idToken: string; accessToken: string; refreshToken: string }> => { try { const result = await applicationContext.getCognito().initiateAuth({ AuthFlow: 'USER_PASSWORD_AUTH', @@ -28,12 +20,12 @@ export const loginInteractor = async ( }); if (result?.ChallengeName === 'NEW_PASSWORD_REQUIRED') { - return { - challengeName: 'NEW_PASSWORD_REQUIRED', - session: result.Session!, - }; + const PasswordChangeError = new Error('NewPasswordRequired'); + PasswordChangeError.name = 'NewPasswordRequired'; + throw PasswordChangeError; } + // TODO: Always return session?? return { accessToken: result.AuthenticationResult!.AccessToken!, idToken: result.AuthenticationResult!.IdToken!, diff --git a/web-client/src/presenter/actions/Login/navigateToChangePasswordAction.ts b/web-client/src/presenter/actions/Login/navigateToChangePasswordAction.ts index 0522d4787fb..37887b89ed2 100644 --- a/web-client/src/presenter/actions/Login/navigateToChangePasswordAction.ts +++ b/web-client/src/presenter/actions/Login/navigateToChangePasswordAction.ts @@ -1,5 +1,3 @@ export const navigateToChangePasswordAction = async ({ props, router }) => { - await router.route( - `/change-password?userEmail=${props.userEmail}?session=${props.session}`, - ); + await router.route(`/change-password?userEmail=${props.userEmail}`); }; diff --git a/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx b/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx index 3d1081344a1..6c567cf9f61 100644 --- a/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx +++ b/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx @@ -11,7 +11,11 @@ export const submitChangePasswordAction = async ({ refreshToken: string; }> => { // TODO: move userEmail and session off form.state - const { confirmPassword, password, session, userEmail } = get(state.form); + + //TODO: validate entity here + const { confirmPassword, password, tempPassword, userEmail } = get( + state.form, + ); try { const { accessToken, idToken, refreshToken } = await applicationContext @@ -19,7 +23,7 @@ export const submitChangePasswordAction = async ({ .changePasswordInteractor(applicationContext, { confirmPassword, password, - session, + tempPassword, userEmail, }).AuthenticationResult; diff --git a/web-client/src/presenter/actions/Login/submitLoginAction.tsx b/web-client/src/presenter/actions/Login/submitLoginAction.tsx index 17b8a5bcd50..65891b517ee 100644 --- a/web-client/src/presenter/actions/Login/submitLoginAction.tsx +++ b/web-client/src/presenter/actions/Login/submitLoginAction.tsx @@ -6,28 +6,25 @@ export const submitLoginAction = async ({ get, path, }: ActionProps): Promise<{ - accessToken?: string; - idToken?: string; - refreshToken?: string; - session?: string; - userEmail?: string; + accessToken: string; + idToken: string; + refreshToken: string; }> => { const { email, password } = get(state.form); try { - const result = await applicationContext + const { accessToken, idToken, refreshToken } = await applicationContext .getUseCases() .loginInteractor(applicationContext, { email, password }); - if (result.challengeName) { - return path.changePassword({ session: result.session, userEmail: email }); - } else { - const { accessToken, idToken, refreshToken } = result; - return path.success({ accessToken, idToken, refreshToken }); - } + return path.success({ accessToken, idToken, refreshToken }); } catch (err: any) { const originalErrorMessage = err?.originalError?.response?.data; + if (originalErrorMessage === 'NewPasswordRequired') { + return path.changePassword({ tempPassword: password, userEmail: email }); + } + if (originalErrorMessage === 'Invalid Username or Password') { return path.error({ alertError: { diff --git a/web-client/src/presenter/actions/setupChangePasswordFormAction.ts b/web-client/src/presenter/actions/setupChangePasswordFormAction.ts index 10cb6b1ac01..68d5bd23fb7 100644 --- a/web-client/src/presenter/actions/setupChangePasswordFormAction.ts +++ b/web-client/src/presenter/actions/setupChangePasswordFormAction.ts @@ -4,8 +4,8 @@ export const setupChangePasswordFormAction = ({ props, store, }: ActionProps) => { - const { session, userEmail } = props; + const { tempPassword, userEmail } = props; - store.set(state.form.session, session); + store.set(state.form.tempPassword, tempPassword); store.set(state.form.userEmail, userEmail); }; diff --git a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts index fcfeb081ca4..8367dd72d55 100644 --- a/web-client/src/presenter/sequences/Login/submitLoginSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitLoginSequence.ts @@ -1,7 +1,7 @@ import { clearFormAction } from '@web-client/presenter/actions/clearFormAction'; import { decodeTokenAction } from '@web-client/presenter/actions/decodeTokenAction'; import { getUserAction } from '@web-client/presenter/actions/getUserAction'; -import { navigateToChangePasswordAction } from '@web-client/presenter/actions/Login/navigateToChangePasswordAction'; +import { goToChangePasswordSequence } from '@web-client/presenter/sequences/Login/goToChangePasswordSequence'; import { navigateToPathAction } from '@web-client/presenter/actions/navigateToPathAction'; import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertErrorAction'; import { setTokenAction } from '@web-client/presenter/actions/Login/setTokenAction'; @@ -14,7 +14,7 @@ export const submitLoginSequence = [ showProgressSequenceDecorator([ submitLoginAction, { - changePassword: [navigateToChangePasswordAction], + changePassword: [goToChangePasswordSequence], error: [setAlertErrorAction], success: [ clearFormAction, From e906f0e18e996c65752b31a5af181b5a8abd70b0 Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Tue, 16 Jan 2024 15:47:01 -0800 Subject: [PATCH 190/700] fix pa11y tests --- web-client/pa11y/pa11y-adc.js | 18 ++- web-client/pa11y/pa11y-admissionsclerk.js | 39 ++++- web-client/pa11y/pa11y-irs-superuser.js | 14 +- web-client/pa11y/pa11y-petitioner.js | 184 +++++++++++++++++----- 4 files changed, 207 insertions(+), 48 deletions(-) diff --git a/web-client/pa11y/pa11y-adc.js b/web-client/pa11y/pa11y-adc.js index c54dfeaef1c..7dae094b73c 100644 --- a/web-client/pa11y/pa11y-adc.js +++ b/web-client/pa11y/pa11y-adc.js @@ -1,4 +1,18 @@ +const { loginAs } = require('./helpers'); + module.exports = [ - 'http://localhost:1234/log-in?code=adc@example.com&path=/', - 'http://localhost:1234/log-in?code=adc@example.com&path=/case-detail/101-19', + { + actions: [ + ...loginAs({ username: 'adc@example.com' }), + 'navigate to http://localhost:1234/', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'adc@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19', + ], + url: 'http://localhost:1234/', + }, ]; diff --git a/web-client/pa11y/pa11y-admissionsclerk.js b/web-client/pa11y/pa11y-admissionsclerk.js index 9440ef504bf..6ebac5eade3 100644 --- a/web-client/pa11y/pa11y-admissionsclerk.js +++ b/web-client/pa11y/pa11y-admissionsclerk.js @@ -1,19 +1,42 @@ +const { loginAs } = require('./helpers'); + module.exports = [ - 'http://localhost:1234/log-in?code=admissionsclerk@example.com&path=/users/create-practitioner', - 'http://localhost:1234/log-in?code=admissionsclerk@example.com&path=/users/edit-practitioner/PT1234', - 'http://localhost:1234/log-in?code=admissionsclerk@example.com&path=/practitioner-detail/PT1234?tab=practitioner-documentation', { actions: [ + ...loginAs({ username: 'admissionsclerk@example.com' }), + 'navigate to http://localhost:1234/users/create-practitioner', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'admissionsclerk@example.com' }), + 'navigate to http://localhost:1234/users/edit-practitioner/PT1234', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'admissionsclerk@example.com' }), + 'navigate to http://localhost:1234/practitioner-detail/PT1234?tab=practitioner-documentation', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'admissionsclerk@example.com' }), + 'navigate to http://localhost:1234/practitioner-detail/PT1234/add-document', 'wait for #cancel-button to be visible', 'click element #cancel-button', 'wait for dialog to be visible', ], notes: 'checks the add practitioner document page and the cancel modal', - url: 'http://localhost:1234/log-in?code=admissionsclerk@example.com&path=/practitioner-detail/PT1234/add-document', + url: 'http://localhost:1234/', }, - { actions: [ + ...loginAs({ username: 'admissionsclerk@example.com' }), + 'navigate to http://localhost:1234/case-detail/124-20/edit-petitioner-information/d2fadb14-b0bb-4019-b6b1-cb51cb1cb92f', 'wait for #updatedEmail to be visible', 'set field #updatedEmail to petitioner1@example.com', 'set field #confirm-email to petitioner1@example.com', @@ -21,10 +44,12 @@ module.exports = [ 'wait for #matching-email-modal to be visible', ], notes: 'checks a11y of matching email confirm modal', - url: 'http://localhost:1234/log-in?code=admissionsclerk@example.com&path=/case-detail/124-20/edit-petitioner-information/d2fadb14-b0bb-4019-b6b1-cb51cb1cb92f&info=matching-email-modal', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'admissionsclerk@example.com' }), + 'navigate to http://localhost:1234/case-detail/104-20/edit-petitioner-information/f7272c25-99e1-4448-960e-e2a6b86e7d17', 'wait for #updatedEmail to be visible', 'set field #updatedEmail to available@example.com', 'set field #confirm-email to available@example.com', @@ -32,6 +57,6 @@ module.exports = [ 'wait for #no-matching-email-modal to be visible', ], notes: 'checks a11y of no matching email confirm modal', - url: 'http://localhost:1234/log-in?code=admissionsclerk@example.com&path=/case-detail/104-20/edit-petitioner-information/f7272c25-99e1-4448-960e-e2a6b86e7d17&info=no-matching-email-modal', + url: 'http://localhost:1234/', }, ]; diff --git a/web-client/pa11y/pa11y-irs-superuser.js b/web-client/pa11y/pa11y-irs-superuser.js index a9eb2d64d8d..fefaae86239 100644 --- a/web-client/pa11y/pa11y-irs-superuser.js +++ b/web-client/pa11y/pa11y-irs-superuser.js @@ -1,16 +1,22 @@ +const { loginAs } = require('./helpers'); + module.exports = [ { actions: [ + ...loginAs({ username: 'irssuperuser@example.com' }), + 'navigate to http://localhost:1234/', 'wait for #docket-search-field to be visible', 'set field #docket-search-field to 103-19', 'click element .usa-search-submit-text', 'wait for #case-title to be visible', ], notes: 'checks a11y of login and docket search', - url: 'http://localhost:1234/log-in?code=irssuperuser@example.com&path=/&info=docket-search', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'irssuperuser@example.com' }), + 'navigate to http://localhost:1234/', 'wait for a#advanced-search-button to be visible', 'click element #advanced-search-button', 'wait for .advanced-search__form-container to be visible', @@ -19,10 +25,12 @@ module.exports = [ 'wait for table.search-results to be visible', ], notes: 'checks a11y of advanced docket search and table', - url: 'http://localhost:1234/log-in?code=irssuperuser@example.com&path=/&info=advanced-search-by-name', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'irssuperuser@example.com' }), + 'navigate to http://localhost:1234/', 'wait for a#advanced-search-button to be visible', 'click element #advanced-search-button', 'wait for .advanced-search__form-container to be visible', @@ -31,6 +39,6 @@ module.exports = [ 'wait for #case-title to be visible', ], notes: 'checks a11y of case detail page for IRS superuser', - url: 'http://localhost:1234/log-in?code=irssuperuser@example.com&path=/&info=advanced-search', + url: 'http://localhost:1234/', }, ]; diff --git a/web-client/pa11y/pa11y-petitioner.js b/web-client/pa11y/pa11y-petitioner.js index 884221e5774..e796337832d 100644 --- a/web-client/pa11y/pa11y-petitioner.js +++ b/web-client/pa11y/pa11y-petitioner.js @@ -1,38 +1,78 @@ +const { loginAs } = require('./helpers'); + module.exports = [ - 'http://localhost:1234/log-in?code=petitioner@example.com&path=/', - 'http://localhost:1234/log-in?code=petitioner@example.com&path=/before-starting-a-case', - 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-1', - 'http://localhost:1234/log-in?code=petitioner@example.com&path=/my-account', - 'http://localhost:1234/log-in?code=petitioner@example.com&path=/change-login-and-service-email', { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/before-starting-a-case', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-1', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/my-account', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/change-login-and-service-email', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-2', 'wait for element label#hasIrsNotice-0 to be visible', 'click element label#hasIrsNotice-0', 'wait for .case-type-select to be visible', ], notes: 'expose hidden elements on start-a-case for Yes notice', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-2&info=reveal-hidden-elements-yes-notice', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-2', 'wait for element label#hasIrsNotice-1 to be visible', 'click element label#hasIrsNotice-1', 'wait for .case-type-select to be visible', ], notes: 'expose hidden elements on start-a-case for No notice', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-2&info=reveal-hidden-elements-no-notice', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-0 to be visible', 'click element label#filing-type-0', 'wait for element .contact-group to be visible', ], notes: 'expose hidden elements on start-a-case for party type Petitioner', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-petitioner', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-1 to be visible', 'click element label#filing-type-1', 'wait for element label#is-spouse-deceased-0 to be visible', @@ -41,10 +81,12 @@ module.exports = [ ], notes: 'expose hidden elements on start-a-case for party type Petitioner & Deceased Spouse', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-petitioner-and-deceased-spouse', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for label#filing-type-1 to be visible', 'click element label#filing-type-1', 'wait for label#is-spouse-deceased-0 to be visible', @@ -61,10 +103,12 @@ module.exports = [ 'expose hidden elements on start-a-case for party type Petitioner & Deceased Spouse with international addresses', "Use 'set field' and then 'check field' to trigger the onChange event on the select", ], - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-petitioner-and-deceased-spouse-international', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-1 to be visible', 'click element label#filing-type-1', 'wait for element label#is-spouse-deceased-1 to be visible', @@ -73,10 +117,12 @@ module.exports = [ ], notes: 'expose hidden elements on start-a-case for party type Petitioner & Spouse', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-petitioner-and-spouse', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-2 to be visible', 'click element label#filing-type-2', 'wait for element label#is-business-type-0 to be visible', @@ -84,10 +130,12 @@ module.exports = [ 'wait for element .contact-group to be visible', ], notes: 'expose hidden elements on start-a-case for party type Corporation', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-corporation', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-2 to be visible', 'click element label#filing-type-2', 'wait for element label#is-business-type-1 to be visible', @@ -96,10 +144,12 @@ module.exports = [ ], notes: 'expose hidden elements on start-a-case for party type Partnership (Tax Matters)', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-partnership-tax-matters', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-2 to be visible', 'click element label#filing-type-2', 'wait for element label#is-business-type-2 to be visible', @@ -108,10 +158,12 @@ module.exports = [ ], notes: 'expose hidden elements on start-a-case for party type Partnership (Other Than Tax Matters)', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-partnership-other', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-2 to be visible', 'click element label#filing-type-2', 'wait for element label#is-business-type-3 to be visible', @@ -120,10 +172,12 @@ module.exports = [ ], notes: 'expose hidden elements on start-a-case for party type Partnership (BBA)', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-partnership-bba', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-0 to be visible', @@ -134,10 +188,12 @@ module.exports = [ ], notes: 'expose hidden elements on start-a-case for party type Estate With Executor', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-estate-with-executor', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-0 to be visible', @@ -148,10 +204,12 @@ module.exports = [ ], notes: 'expose hidden elements on start-a-case for party type Estate Without Executor', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-estate-without-executor', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-0 to be visible', @@ -161,10 +219,12 @@ module.exports = [ 'wait for element .contact-group to be visible', ], notes: 'expose hidden elements on start-a-case for party type Trust', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-trust', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-1 to be visible', @@ -174,10 +234,12 @@ module.exports = [ 'wait for element .contact-group to be visible', ], notes: 'expose hidden elements on start-a-case for party type Conservator', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-conservator', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-1 to be visible', @@ -187,10 +249,12 @@ module.exports = [ 'wait for element .contact-group to be visible', ], notes: 'expose hidden elements on start-a-case for party type Guardian', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-guardian', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-1 to be visible', @@ -200,10 +264,12 @@ module.exports = [ 'wait for element .contact-group to be visible', ], notes: 'expose hidden elements on start-a-case for party type Custodian', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-custodian', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-1 to be visible', @@ -213,10 +279,12 @@ module.exports = [ 'wait for element .contact-group to be visible', ], notes: 'expose hidden elements on start-a-case for party type Minor', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-minor', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-1 to be visible', @@ -227,10 +295,12 @@ module.exports = [ ], notes: 'expose hidden elements on start-a-case for party type Legally Incompetent Person', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-incompetent-person', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-2 to be visible', @@ -238,10 +308,12 @@ module.exports = [ 'wait for element .contact-group to be visible', ], notes: 'expose hidden elements on start-a-case for party type Donor', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-donor', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-3 to be visible', @@ -249,10 +321,12 @@ module.exports = [ 'wait for element .contact-group to be visible', ], notes: 'expose hidden elements on start-a-case for party type Transferee', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-transferee', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-3', 'wait for element label#filing-type-3 to be visible', 'click element label#filing-type-3', 'wait for element label#is-other-type-4 to be visible', @@ -261,10 +335,12 @@ module.exports = [ ], notes: 'expose hidden elements on start-a-case for party type Surviving Spouse', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-3&info=reveal-hidden-elements-surviving-spouse', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/file-a-petition-pa11y/step-4', 'wait for button.case-difference to be visible', 'wait for #case-difference-container to be hidden', 'click element button.case-difference', @@ -274,13 +350,33 @@ module.exports = [ 'wait for #preferred-trial-city to be visible', ], notes: 'expose all hidden elements on start-a-case', - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/file-a-petition-pa11y/step-4&info=reveal-hidden-elements', + url: 'http://localhost:1234/', }, - 'http://localhost:1234/log-in?code=petitioner@example.com&path=/case-detail/101-19', - 'http://localhost:1234/log-in?code=petitioner@example.com&path=/case-detail/101-19/file-a-document', - 'http://localhost:1234/log-in?code=petitioner@example.com&path=/case-detail/101-19/file-a-document/review', { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19/file-a-document', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19/file-a-document/review', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19/file-a-document', 'wait for element #react-select-2-input to be visible', 'click #react-select-2-input', 'wait for element .select-react-element__menu to be visible', @@ -289,10 +385,12 @@ module.exports = [ notes: [ 'Check accessibility of elements after choosing a Nonstandard H document', ], - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/case-detail/101-19/file-a-document&info=doctype-selection-1', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19/file-a-document', 'wait for element #react-select-2-input to be visible', 'click #react-select-2-input', 'wait for element .select-react-element__menu to be visible', @@ -309,10 +407,11 @@ module.exports = [ 'wait for element #secondary-document to be visible', ], notes: ['File a document, step 2'], - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=/case-detail/101-19/file-a-document&info=doctype-selection-2', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), 'wait for element #case-list to be visible', 'wait for element #pay_filing_fee to be visible', 'click element .payment-options', @@ -321,16 +420,29 @@ module.exports = [ notes: [ 'Check accessibility of view filing fee payment options with filed cases', ], - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'petitioner@example.com' }), 'wait for element #pay_filing_fee to be visible', 'click element #pay_filing_fee', ], notes: ['Check accessibility of Pay filing fee button'], - url: 'http://localhost:1234/log-in?code=petitioner@example.com&path=', + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19/contacts/primary/edit', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'petitioner@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19/contacts/secondary/edit', + ], + url: 'http://localhost:1234/', }, - 'http://localhost:1234/log-in?code=petitioner@example.com&path=/case-detail/101-19/contacts/primary/edit', - 'http://localhost:1234/log-in?code=petitioner@example.com&path=/case-detail/101-19/contacts/secondary/edit', ]; From b10c5c9f046a22601ae8391f189d7d6a6323530a Mon Sep 17 00:00:00 2001 From: Rachel Schneiderman Date: Tue, 16 Jan 2024 16:03:39 -0800 Subject: [PATCH 191/700] 10007: WIP docketclerk pa11y tests --- web-client/pa11y/pa11y-docketclerk.js | 556 ++++++++++++++------------ 1 file changed, 291 insertions(+), 265 deletions(-) diff --git a/web-client/pa11y/pa11y-docketclerk.js b/web-client/pa11y/pa11y-docketclerk.js index bb163fa3fd5..3fed0066915 100644 --- a/web-client/pa11y/pa11y-docketclerk.js +++ b/web-client/pa11y/pa11y-docketclerk.js @@ -1,306 +1,332 @@ +const { loginAs } = require('./helpers'); + module.exports = [ - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/', { actions: [ + ...loginAs({ username: 'docketclerk@example.com' }), + 'navigate to http://localhost:1234/', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'docketclerk@example.com' }), + 'navigate to http://localhost:1234/document-qc/section/inbox', 'wait for td.message-select-control .usa-checkbox>label to be visible', 'click element td.message-select-control .usa-checkbox>label', 'wait for .action-section to be visible', ], notes: 'checks a11y of section queue tab panel', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/document-qc/section/inbox&info=section-queue-tab', + url: 'http://localhost:1234/', }, { - actions: ['wait for .modal-screen to be visible'], + actions: [ + ...loginAs({ username: 'docketclerk@example.com' }), + 'navigate to http://localhost:1234/case-detail/320-21/documents/6b2bcbcc-bc95-4103-b5fd-3e999395c2d3/edit', + 'wait for .modal-screen to be visible', + ], notes: 'verify the work item already completed modal', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/320-21/documents/6b2bcbcc-bc95-4103-b5fd-3e999395c2d3/edit', + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'docketclerk@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19', + ], + url: 'http://localhost:1234/', }, - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/101-19', { actions: [ + ...loginAs({ username: 'docketclerk@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19/edit-details', 'wait for element .usa-radio__label[for=payment-status-paid] to be visible', 'click element .usa-radio__label[for=payment-status-paid]', 'wait for element #petition-payment-method to be visible', ], notes: 'checks a11y of form when petition fee payment status paid is selected', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/101-19/edit-details&info=paid', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'docketclerk@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19/edit-details', 'wait for element .usa-radio__label[for=payment-status-unpaid] to be visible', 'click element .usa-radio__label[for=payment-status-unpaid]', 'wait for element #petition-payment-method to be removed', ], notes: 'checks a11y of form when petition fee payment status unpaid is selected', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/101-19/edit-details&info=unpaid', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'docketclerk@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19/edit-details', 'wait for element .usa-radio__label[for=payment-status-waived] to be visible', 'click element .usa-radio__label[for=payment-status-waived]', 'wait for element #payment-date-waived-picker to be visible', ], notes: 'checks a11y of form when petition fee payment status waived is selected', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/101-19/edit-details&info=waived', - }, - { - actions: [ - 'wait for #has-other-filing-party-label to be visible', - 'click element label#has-other-filing-party-label', - 'wait for input#other-filing-party to be visible', - ], - notes: 'checks a11y of edit docket entry add other filing party', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/103-19/documents/dc2664a1-f552-418f-bcc7-8a67f4246568/edit', - }, - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/reports/pending-report', - { - actions: [ - 'wait for element .case-inventory-report-modal to be visible', - 'wait for #select-case-inventory-status to be visible', - 'set field #select-case-inventory-status to New', - 'check field #select-case-inventory-status', - 'wait for #select-case-inventory-judge to be visible', - 'set field #select-case-inventory-judge to Chief Judge', - 'check field #select-case-inventory-judge', - 'click element .modal-button-confirm', - 'wait for element table.case-inventory to be visible', - ], - notes: 'checks a11y of case inventory report builder', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/reports/case-inventory-report', - }, - { - actions: [ - 'wait for element #certificate-of-service-label to be visible', - 'click element #certificate-of-service-label', - 'wait for element #service-date-picker to be visible', - ], - notes: 'reveal all secondary drop-downs and inputs ', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/103-19/add-paper-filing&info=show-cos-inputs', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'wait for .progress-indicator to be hidden', - 'click element #tab-case-information', - 'wait for #menu-edit-case-context-button to be visible', - 'wait for .progress-indicator to be hidden', - 'click element #menu-edit-case-context-button', - 'wait for .modal-dialog to be visible', - ], - notes: 'checks a11y of case context edit dialog', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/102-19&info=case-context-edit', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'wait for .progress-indicator to be hidden', - 'click element #tab-case-information', - 'wait for #tab-history to be visible', - 'click element #tab-history', - 'wait for .case-status-history to be visible', - ], - notes: 'checks a11y on the case status history table', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/102-22&info=case-status-history-table', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #tab-parties to be visible', - 'click element #tab-parties', - 'wait for #participants-and-counsel to be visible', - 'click element #participants-and-counsel', - 'wait for .edit-participant to be visible', - 'click element .edit-participant', - ], - notes: - 'checks a11y of case information tab, parties secondary tab, participants and counsel tertiary tab', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/999-15&info=case-information-tab-parties-participants-and-counsel', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #tab-parties to be visible', - 'click element #tab-parties', - 'wait for #petitioners-and-counsel to be visible', - 'click element #petitioners-and-counsel', - 'wait for .edit-petitioner-button to be visible', - 'click element .edit-petitioner-button', - ], - notes: - 'checks a11y of case information tab, parties secondary tab, parties and counsel tertiary tab', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/999-15&info=case-information-tab-parties-petitioner-and-counsel', - }, - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/110-19/documents/25100ec6-eeeb-4e88-872f-c99fad1fe6c7/add-court-issued-docket-entry', - { - actions: [ - 'wait for #judge to be visible', - 'set field #judge to Colvin', - 'check field #judge', - 'set field #free-text to Anything', - 'wait for #serve-to-parties-btn to be visible', - 'click element #serve-to-parties-btn', - 'wait for .confirm-initiate-service-modal to be visible', - ], - notes: 'checks a11y of confirm-initiate-service-modal dialog', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/107-19/documents/25100ec6-eeeb-4e88-872f-c99fad1fe6c7/add-court-issued-docket-entry&info=initiate-service-modal', + url: 'http://localhost:1234/', }, - { - actions: [ - 'wait for element #document-type to be visible', - 'set field #free-text to Anything', - 'check field #free-text', - 'set field #date-received-picker to 01/01/2022', - 'check field #date-received-picker', - 'wait for #save-entry-button to be visible', - 'click element #save-entry-button', - 'wait for .confirm-initiate-save-modal to be visible', - ], - notes: 'checks a11y of confirm-initiate-save-modal dialog', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/111-19/documents/25100ec6-eeeb-4e88-872f-c99fad1fe6c7/add-court-issued-docket-entry&info=initiate-save-modal', - }, - { - actions: [ - 'wait for #tab-order to be visible', - 'click element #tab-order', - 'wait for #keyword-search to be visible', - 'set field #keyword-search to dismissal', - 'wait for #date-range to be visible', - 'set field #date-range to customDates', - 'check field #date-range', - 'set field #startDate-date-start to 08/03/2001', - 'check field #startDate-date-start', - 'click element button#advanced-search-button', - 'wait for table.search-results to be visible', - ], - notes: 'checks a11y of advanced order search', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/search&info=order-search-result', - }, - { - actions: [ - 'wait for #tab-opinion to be visible', - 'click element #tab-opinion', - 'wait for #keyword-search to be visible', - 'set field #keyword-search to opinion', - 'wait for #date-range to be visible', - 'set field #date-range to customDates', - 'check field #date-range', - 'set field #startDate-date-start to 08/03/2001', - 'check field #startDate-date-start', - 'click element button#advanced-search-button', - 'wait for table.search-results to be visible', - ], - notes: 'checks a11y of advanced opinion search', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/search&info=opinion-search-result', - }, - { - actions: [ - 'wait for #tab-order to be visible', - 'click element #tab-order', - 'wait for #keyword-search to be visible', - 'set field #keyword-search to meow', - 'wait for #date-range to be visible', - 'set field #date-range to customDates', - 'check field #date-range', - 'set field #startDate-date-start to 08/03/2001', - 'check field #startDate-date-start', - 'click element button#advanced-search-button', - 'wait for svg.iconSealed to be visible', - ], - notes: 'checks a11y of advanced order search of a sealed case', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/search&info=sealed-case-order-search-result', - }, - { - actions: [ - 'wait for #tab-order to be visible', - 'click element #tab-opinion', - 'wait for #keyword-search to be visible', - 'set field #keyword-search to sunglasses', - 'wait for #date-range to be visible', - 'set field #date-range to customDates', - 'check field #date-range', - 'set field #startDate-date-start to 08/03/2001', - 'check field #startDate-date-start', - 'click element button#advanced-search-button', - 'wait for table.search-results to be visible', - ], + // { + // actions: [ + // 'wait for #has-other-filing-party-label to be visible', + // 'click element label#has-other-filing-party-label', + // 'wait for input#other-filing-party to be visible', + // ], + // notes: 'checks a11y of edit docket entry add other filing party', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/103-19/documents/dc2664a1-f552-418f-bcc7-8a67f4246568/edit', + // }, + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/reports/pending-report', + // { + // actions: [ + // 'wait for element .case-inventory-report-modal to be visible', + // 'wait for #select-case-inventory-status to be visible', + // 'set field #select-case-inventory-status to New', + // 'check field #select-case-inventory-status', + // 'wait for #select-case-inventory-judge to be visible', + // 'set field #select-case-inventory-judge to Chief Judge', + // 'check field #select-case-inventory-judge', + // 'click element .modal-button-confirm', + // 'wait for element table.case-inventory to be visible', + // ], + // notes: 'checks a11y of case inventory report builder', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/reports/case-inventory-report', + // }, + // { + // actions: [ + // 'wait for element #certificate-of-service-label to be visible', + // 'click element #certificate-of-service-label', + // 'wait for element #service-date-picker to be visible', + // ], + // notes: 'reveal all secondary drop-downs and inputs ', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/103-19/add-paper-filing&info=show-cos-inputs', + // }, + // { + // actions: [ + // 'wait for #tab-case-information to be visible', + // 'wait for .progress-indicator to be hidden', + // 'click element #tab-case-information', + // 'wait for #menu-edit-case-context-button to be visible', + // 'wait for .progress-indicator to be hidden', + // 'click element #menu-edit-case-context-button', + // 'wait for .modal-dialog to be visible', + // ], + // notes: 'checks a11y of case context edit dialog', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/102-19&info=case-context-edit', + // }, + // { + // actions: [ + // 'wait for #tab-case-information to be visible', + // 'wait for .progress-indicator to be hidden', + // 'click element #tab-case-information', + // 'wait for #tab-history to be visible', + // 'click element #tab-history', + // 'wait for .case-status-history to be visible', + // ], + // notes: 'checks a11y on the case status history table', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/102-22&info=case-status-history-table', + // }, + // { + // actions: [ + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #tab-parties to be visible', + // 'click element #tab-parties', + // 'wait for #participants-and-counsel to be visible', + // 'click element #participants-and-counsel', + // 'wait for .edit-participant to be visible', + // 'click element .edit-participant', + // ], + // notes: + // 'checks a11y of case information tab, parties secondary tab, participants and counsel tertiary tab', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/999-15&info=case-information-tab-parties-participants-and-counsel', + // }, + // { + // actions: [ + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #tab-parties to be visible', + // 'click element #tab-parties', + // 'wait for #petitioners-and-counsel to be visible', + // 'click element #petitioners-and-counsel', + // 'wait for .edit-petitioner-button to be visible', + // 'click element .edit-petitioner-button', + // ], + // notes: + // 'checks a11y of case information tab, parties secondary tab, parties and counsel tertiary tab', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/999-15&info=case-information-tab-parties-petitioner-and-counsel', + // }, + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/110-19/documents/25100ec6-eeeb-4e88-872f-c99fad1fe6c7/add-court-issued-docket-entry', + // { + // actions: [ + // 'wait for #judge to be visible', + // 'set field #judge to Colvin', + // 'check field #judge', + // 'set field #free-text to Anything', + // 'wait for #serve-to-parties-btn to be visible', + // 'click element #serve-to-parties-btn', + // 'wait for .confirm-initiate-service-modal to be visible', + // ], + // notes: 'checks a11y of confirm-initiate-service-modal dialog', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/107-19/documents/25100ec6-eeeb-4e88-872f-c99fad1fe6c7/add-court-issued-docket-entry&info=initiate-service-modal', + // }, + // { + // actions: [ + // 'wait for element #document-type to be visible', + // 'set field #free-text to Anything', + // 'check field #free-text', + // 'set field #date-received-picker to 01/01/2022', + // 'check field #date-received-picker', + // 'wait for #save-entry-button to be visible', + // 'click element #save-entry-button', + // 'wait for .confirm-initiate-save-modal to be visible', + // ], + // notes: 'checks a11y of confirm-initiate-save-modal dialog', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/111-19/documents/25100ec6-eeeb-4e88-872f-c99fad1fe6c7/add-court-issued-docket-entry&info=initiate-save-modal', + // }, + // { + // actions: [ + // 'wait for #tab-order to be visible', + // 'click element #tab-order', + // 'wait for #keyword-search to be visible', + // 'set field #keyword-search to dismissal', + // 'wait for #date-range to be visible', + // 'set field #date-range to customDates', + // 'check field #date-range', + // 'set field #startDate-date-start to 08/03/2001', + // 'check field #startDate-date-start', + // 'click element button#advanced-search-button', + // 'wait for table.search-results to be visible', + // ], + // notes: 'checks a11y of advanced order search', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/search&info=order-search-result', + // }, + // { + // actions: [ + // 'wait for #tab-opinion to be visible', + // 'click element #tab-opinion', + // 'wait for #keyword-search to be visible', + // 'set field #keyword-search to opinion', + // 'wait for #date-range to be visible', + // 'set field #date-range to customDates', + // 'check field #date-range', + // 'set field #startDate-date-start to 08/03/2001', + // 'check field #startDate-date-start', + // 'click element button#advanced-search-button', + // 'wait for table.search-results to be visible', + // ], + // notes: 'checks a11y of advanced opinion search', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/search&info=opinion-search-result', + // }, + // { + // actions: [ + // 'wait for #tab-order to be visible', + // 'click element #tab-order', + // 'wait for #keyword-search to be visible', + // 'set field #keyword-search to meow', + // 'wait for #date-range to be visible', + // 'set field #date-range to customDates', + // 'check field #date-range', + // 'set field #startDate-date-start to 08/03/2001', + // 'check field #startDate-date-start', + // 'click element button#advanced-search-button', + // 'wait for svg.iconSealed to be visible', + // ], + // notes: 'checks a11y of advanced order search of a sealed case', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/search&info=sealed-case-order-search-result', + // }, + // { + // actions: [ + // 'wait for #tab-order to be visible', + // 'click element #tab-opinion', + // 'wait for #keyword-search to be visible', + // 'set field #keyword-search to sunglasses', + // 'wait for #date-range to be visible', + // 'set field #date-range to customDates', + // 'check field #date-range', + // 'set field #startDate-date-start to 08/03/2001', + // 'check field #startDate-date-start', + // 'click element button#advanced-search-button', + // 'wait for table.search-results to be visible', + // ], - notes: 'checks a11y of opinion search', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/search&info=opinion-search-result-sunglasses', - }, - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/print-preview/110-19/', - { - actions: [ - 'wait for #deadlineStart-date-start to be visible', - 'set field #deadlineStart-date-start to 01/01/2019', - 'check field #deadlineStart-date-start', - 'set field #deadlineEnd-date-end to 12/01/2019', - 'check field #deadlineEnd-date-end', - 'click element button#update-date-range-deadlines-button', - 'wait for table.deadlines to be visible', - ], - notes: 'checks a11y of case deadline report', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/reports/case-deadlines', - }, - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/101-20/edit-petitioner-information/7805d1ab-18d0-43ec-bafb-654e83405416', - { - actions: [ - 'wait for #remove-petitioner-btn to be visible', - 'click element #remove-petitioner-btn', - 'wait for #remove-petitioner-modal to be visible', - ], - notes: 'checks a11y of remove petitioner confirm modal', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/101-20/edit-petitioner-information/7805d1ab-18d0-43ec-bafb-654e83405416&info=remove-petitioner-modal', - }, - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/102-19?openModal=PaperServiceConfirmModal', - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/111-19?openModal=UnconsolidateCasesModal', - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/104-20/upload-court-issued', - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/104-20/edit-upload-court-issued/b1aa4aa2-c214-424c-8870-d0049c5744d8', - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/105-20/document-view?docketEntryId=af9e2d43-1255-4e3d-80d0-63f0aedfab5a', - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/103-19/document-view?docketEntryId=f1aa4aa2-c214-424c-8870-d0049c5744d7&info=document-view-serve-button', - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/messages/104-19/message-detail/2d1191d3-4597-454a-a2b2-84e267ccf01e', - { - actions: [ - 'wait for #use-same-address-above-label to be visible', - 'click element #use-same-address-above-label', - ], - notes: 'checks the add petitioner to case page', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/105-20/add-petitioner-to-case', - }, - { - actions: [ - 'wait for #docket-record-table to be visible', - 'click element button[data-testid="seal-docket-entry-button-1"]', - 'wait for .modal-dialog to be visible', - ], - notes: 'checks the seal modal opens on a docket entry', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/105-20', - }, - 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/maintenance', - { - actions: [ - 'wait for #docket-record-table to be visible', - 'wait for button[data-testid="document-viewer-link-A"] to be visible', - 'click element button[data-testid="document-viewer-link-A"]', - 'click element button[data-testid="serve-paper-filed-document"]', - 'wait for .modal-dialog to be visible', - ], - notes: - 'checks a11y of ConfirmInitiatePaperFilingServiceModal on paper filing for a consolidated group', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/111-19', - }, - { - actions: [ - 'wait for table#custom-case-report-table to be visible', - 'set field #caseCreationStartDate-date-start to 04/19/1980', - 'set field #caseCreationEndDate-date-end to 04/19/2023', - 'click element #run-custom-case-report', - 'wait for #custom-case-report-table-body to be visible', - ], - notes: 'checks a11y of Custom Case Inventory Report', - url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/reports/custom-case', - }, + // notes: 'checks a11y of opinion search', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/search&info=opinion-search-result-sunglasses', + // }, + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/print-preview/110-19/', + // { + // actions: [ + // 'wait for #deadlineStart-date-start to be visible', + // 'set field #deadlineStart-date-start to 01/01/2019', + // 'check field #deadlineStart-date-start', + // 'set field #deadlineEnd-date-end to 12/01/2019', + // 'check field #deadlineEnd-date-end', + // 'click element button#update-date-range-deadlines-button', + // 'wait for table.deadlines to be visible', + // ], + // notes: 'checks a11y of case deadline report', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/reports/case-deadlines', + // }, + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/101-20/edit-petitioner-information/7805d1ab-18d0-43ec-bafb-654e83405416', + // { + // actions: [ + // 'wait for #remove-petitioner-btn to be visible', + // 'click element #remove-petitioner-btn', + // 'wait for #remove-petitioner-modal to be visible', + // ], + // notes: 'checks a11y of remove petitioner confirm modal', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/101-20/edit-petitioner-information/7805d1ab-18d0-43ec-bafb-654e83405416&info=remove-petitioner-modal', + // }, + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/102-19?openModal=PaperServiceConfirmModal', + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/111-19?openModal=UnconsolidateCasesModal', + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/104-20/upload-court-issued', + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/104-20/edit-upload-court-issued/b1aa4aa2-c214-424c-8870-d0049c5744d8', + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/105-20/document-view?docketEntryId=af9e2d43-1255-4e3d-80d0-63f0aedfab5a', + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/103-19/document-view?docketEntryId=f1aa4aa2-c214-424c-8870-d0049c5744d7&info=document-view-serve-button', + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/messages/104-19/message-detail/2d1191d3-4597-454a-a2b2-84e267ccf01e', + // { + // actions: [ + // 'wait for #use-same-address-above-label to be visible', + // 'click element #use-same-address-above-label', + // ], + // notes: 'checks the add petitioner to case page', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/105-20/add-petitioner-to-case', + // }, + // { + // actions: [ + // 'wait for #docket-record-table to be visible', + // 'click element button[data-testid="seal-docket-entry-button-1"]', + // 'wait for .modal-dialog to be visible', + // ], + // notes: 'checks the seal modal opens on a docket entry', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/105-20', + // }, + // 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/maintenance', + // { + // actions: [ + // 'wait for #docket-record-table to be visible', + // 'wait for button[data-testid="document-viewer-link-A"] to be visible', + // 'click element button[data-testid="document-viewer-link-A"]', + // 'click element button[data-testid="serve-paper-filed-document"]', + // 'wait for .modal-dialog to be visible', + // ], + // notes: + // 'checks a11y of ConfirmInitiatePaperFilingServiceModal on paper filing for a consolidated group', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/case-detail/111-19', + // }, + // { + // actions: [ + // 'wait for table#custom-case-report-table to be visible', + // 'set field #caseCreationStartDate-date-start to 04/19/1980', + // 'set field #caseCreationEndDate-date-end to 04/19/2023', + // 'click element #run-custom-case-report', + // 'wait for #custom-case-report-table-body to be visible', + // ], + // notes: 'checks a11y of Custom Case Inventory Report', + // url: 'http://localhost:1234/log-in?code=docketclerk@example.com&path=/reports/custom-case', + // }, ]; From 97863e6ce996f5d2f57df88fb66ac7fb42db7549 Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Tue, 16 Jan 2024 16:15:59 -0800 Subject: [PATCH 192/700] 10007: WIP translating petitionsclerk tests to use new login. still have one failing test for http://localhost:1234/case-detail/101-19/edit-order/25100ec6-eeeb-4e88-872f-c99fad1fe6c7/sign --- web-client/pa11y/pa11y-irs-practitioner.js | 34 +- web-client/pa11y/pa11y-petitionsclerk.js | 1257 ++++++++++++-------- 2 files changed, 784 insertions(+), 507 deletions(-) diff --git a/web-client/pa11y/pa11y-irs-practitioner.js b/web-client/pa11y/pa11y-irs-practitioner.js index 03621d6891c..fb0251a6c9f 100644 --- a/web-client/pa11y/pa11y-irs-practitioner.js +++ b/web-client/pa11y/pa11y-irs-practitioner.js @@ -1,22 +1,46 @@ +const { loginAs } = require('./helpers'); + module.exports = [ - 'http://localhost:1234/log-in?code=irspractitioner@example.com&path=/', - 'http://localhost:1234/log-in?code=irspractitioner@example.com&path=/case-detail/101-19', { actions: [ + ...loginAs({ username: 'irspractitioner@example.com' }), + 'navigate to http://localhost:1234/', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'irspractitioner@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19', + ], + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'irspractitioner@example.com' }), + 'navigate to http://localhost:1234/case-detail/104-18&info=can-file-document', 'wait for #button-first-irs-document to be visible', 'click element #button-first-irs-document', 'wait for #file-a-document-header to be visible', ], notes: 'checks a11y of revealed form for filing document', - url: 'http://localhost:1234/log-in?code=irspractitioner@example.com&path=/case-detail/104-18&info=can-file-document', + url: 'http://localhost:1234/', }, { actions: [ + ...loginAs({ username: 'irspractitioner@example.com' }), + 'navigate to http://localhost:1234/case-detail/102-20&info=associated-respondent', 'wait for .sealed-banner to be visible', 'wait for #case-title to be visible', ], notes: 'an associated respondent can see details of sealed case', - url: 'http://localhost:1234/log-in?code=irspractitioner@example.com&path=/case-detail/102-20&info=associated-respondent', + url: 'http://localhost:1234/', + }, + { + actions: [ + ...loginAs({ username: 'irspractitioner@example.com' }), + 'navigate to http://localhost:1234/search/no-matches', + ], + url: 'http://localhost:1234/', }, - 'http://localhost:1234/log-in?code=irspractitioner@example.com&path=/search/no-matches', ]; diff --git a/web-client/pa11y/pa11y-petitionsclerk.js b/web-client/pa11y/pa11y-petitionsclerk.js index 36dcff75812..46d2747e610 100644 --- a/web-client/pa11y/pa11y-petitionsclerk.js +++ b/web-client/pa11y/pa11y-petitionsclerk.js @@ -1,509 +1,762 @@ -module.exports = [ - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/', - /* start case internal */ - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/file-a-petition/step-1', - { - actions: [ - 'wait for #party-type to be visible', - 'set field #party-type to Surviving spouse', - 'check field #party-type', - 'wait for #secondary-name to be visible', - ], - notes: - 'checks a11y of Create Case with inputs revealed - secondary contact', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/file-a-petition/step-1&info=secondary-contact', - }, - { - actions: [ - 'wait for #party-type to be visible', - 'set field #party-type to Corporation', - 'check field #party-type', - 'wait for #order-for-cds-label to be visible', - ], - notes: 'checks a11y of Create Case with inputs revealed - Order for CDS', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/file-a-petition/step-1&info=order-for-cds', - }, - { - actions: [ - 'wait for #tab-case-info to be visible', - 'click element #tab-case-info', - 'wait for #date-received-picker to be visible', - ], - notes: 'checks a11y of Create Case with inputs revealed - Case Info tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/file-a-petition/step-1&info=case-info-tab', - }, - { - actions: [ - 'wait for #tab-irs-notice to be visible', - 'click element #tab-irs-notice', - 'wait for #irs-verified-notice-radios to be visible', - 'click element #has-irs-verified-notice-yes', - 'wait for #date-of-notice-picker to be visible', - ], - notes: 'checks a11y of Create Case with inputs revealed - IRS Notice tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/file-a-petition/step-1&info=irs-notice-tab', - }, +/* eslint-disable max-lines */ +const { loginAs } = require('./helpers'); - /* case detail */ - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/101-19', - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - ], - notes: 'checks a11y of case information tab, overview secondary tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/108-19&info=case-information-tab-overview', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #tab-parties to be visible', - 'click element #tab-parties', - ], - notes: 'checks a11y of case information tab, petitioner secondary tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/102-19&info=case-information-tab-parties', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #tab-parties to be visible', - 'click element #tab-parties', - 'wait for #respondent-counsel to be visible', - 'click element #respondent-counsel', - 'wait for #edit-respondent-counsel to be visible', - 'click element #edit-respondent-counsel', - ], - notes: - 'checks a11y of case information tab, parties secondary tab, respondent counsel tertiary tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/999-15&info=case-information-tab-parties-repondent', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #tab-parties to be visible', - 'click element #tab-parties', - 'wait for #practitioner-search-field to be visible', - 'set field #practitioner-search-field to GL1111', - 'check field #practitioner-search-field', - 'click element button#search-for-practitioner', - 'wait for #counsel-matches-legend to be visible', - ], - notes: 'checks a11y of add practitioner modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/102-19&info=add-practitioner-modal', - }, - { - actions: ['wait for #practitioner-representing to be visible'], - notes: 'checks a11y of edit petitioner counsel page', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/105-19/edit-petitioner-counsel/PT1234', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #tab-parties to be visible', - 'click element #tab-parties', - 'wait for #respondent-counsel to be visible', - 'click element #respondent-counsel', - 'wait for #respondent-search-field to be visible', - 'set field #respondent-search-field to WN7777', - 'check field #respondent-search-field', - 'click element button#search-for-respondent', - 'wait for #counsel-matches-legend to be visible', - ], - notes: 'checks a11y of add respondent modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/102-19&info=add-respondent-modal', - }, - { - actions: ['wait for #submit-edit-respondent-information to be visible'], - notes: 'checks a11y of edit respondentCounsel page', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/103-19/edit-respondent-counsel/RT6789', - }, - { - actions: [ - 'wait for #tab-drafts to be visible', - 'click element #tab-drafts', - 'wait for #edit-order-button to be visible', - 'click element #edit-order-button', - 'wait for .modal-button-confirm to be visible', - ], - notes: 'checks the confirm modal when editing a signed draft document', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/109-19&info=edit-signed-order-confirm-modal/', - }, - { - actions: [ - 'wait for #case-detail-menu-button to be visible', - 'wait for .progress-indicator to be hidden', - 'click element #case-detail-menu-button', - 'wait for #menu-button-add-new-message to be visible', - 'wait for .progress-indicator to be hidden', - 'click element #menu-button-add-new-message', - 'wait for .ustc-create-message-modal to be visible', - ], - notes: 'checks a11y of create message modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/105-19&info=create-message-modal', - }, - { - actions: [ - 'wait for #case-detail-menu-button to be visible', - 'wait for .progress-indicator to be hidden', - 'click element #case-detail-menu-button', - 'wait for #menu-button-create-order to be visible', - 'wait for .progress-indicator to be hidden', - 'click element #menu-button-create-order', - 'wait for #eventCode to be visible', - ], - notes: 'checks a11y of create order select document type modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/105-19&info=create-order-modal', - }, - { - actions: [ - 'wait for #tab-tracked-items to be visible', - 'click element #tab-tracked-items', - ], - notes: 'checks a11y of deadlines tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/107-19&info=tracked-items-tab', - }, - { - actions: [ - 'wait for #case-detail-menu-button to be visible', - 'wait for .progress-indicator to be hidden', - 'click element #case-detail-menu-button', - 'wait for #menu-button-add-deadline to be visible', - 'wait for .progress-indicator to be hidden', - 'click element #menu-button-add-deadline', - 'wait for #deadline-date-picker to be visible', - ], - notes: 'checks a11y of add deadline modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/105-19&info=add-deadline', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #blocked-from-trial-header to be visible', - ], - notes: - 'checks a11y of case information overview tab for a case with a manual and automatic block', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/109-19&info=case-information-tab-blocked', - }, - { - actions: [ - 'wait for #tab-drafts to be visible', - 'click element #tab-drafts', - ], - notes: 'checks a11y of the draft documents tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/109-19&info=drafts-tab', - }, - { - actions: [ - 'wait for #tab-case-messages to be visible', - 'click element #tab-case-messages', - ], - notes: 'checks a11y of case messages tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/109-19&info=case-messages-tab', - }, - { - actions: [ - 'wait for #tab-tracked-items to be visible', - 'click element #tab-tracked-items', - 'wait for #tab-pending-report to be visible', - 'click element #tab-pending-report', - ], - notes: 'checks a11y of tracked-items tab, pending report secondary tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/109-19&info=tracked-items-tab-pending-report', - }, - { - actions: [ - 'wait for #tab-correspondence to be visible', - 'click element #tab-correspondence', - 'wait for .document-viewer--documents to be visible', - ], - notes: 'checks a11y of correspondence tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/103-19&info=correspondence-tab', - }, - { - actions: ['wait for element #upload-correspondence to be visible'], - notes: 'checks a11y of add correspondence page', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/103-19/upload-correspondence&info=add-correspondence', - }, - { - actions: [ - 'wait for #tab-correspondence to be visible', - 'click element #tab-correspondence', - 'wait for .document-viewer--documents to be visible', - 'click element .edit-correspondence-button', - 'wait for element #edit-correspondence-header to be visible', - ], - notes: 'checks a11y of edit correspondence page', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/103-19&info=edit-correspondence', - }, - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/103-20/document-view?docketEntryId=ac62f25a-49f9-46a5-aed7-d6b955a2dc34&info=document-view-review-and-serve-petition-button', - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #edit-case-trial-information-btn to be visible', - 'click element #edit-case-trial-information-btn', - 'wait for #add-edit-calendar-note to be visible', - 'click element #add-edit-calendar-note', - 'wait for .add-edit-calendar-note-modal to be visible', - ], - notes: 'checks the add edit calendar note modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/108-19&info=add-edit-calendar-note-modal', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #edit-case-trial-information-btn to be visible', - 'click element #edit-case-trial-information-btn', - 'wait for #remove-from-trial-session-btn to be visible', - 'click element #remove-from-trial-session-btn', - 'wait for #remove-from-trial-session-modal to be visible', - ], - notes: 'checks the remove from trial session modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/108-19&info=remove-case-from-session-modal', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for .high-priority-btn to be visible', - 'click element .high-priority-btn', - 'wait for #prioritize-case-modal to be visible', - ], - notes: 'opens the prioritize case modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/101-19&info=prioritize-case-modal', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #remove-high-priority-btn to be visible', - 'click element #remove-high-priority-btn', - 'wait for #unprioritize-modal to be visible', - ], - notes: 'opens the unprioritize case modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/110-19&info=unprioritize-case-modal', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #add-to-trial-session-btn to be visible', - 'click element #add-to-trial-session-btn', - 'wait for #add-to-trial-session-modal to be visible', - ], - notes: 'checks the add to trial session modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/104-19&info=add-case-to-session-modal', - }, - { - actions: [ - 'wait for #tab-case-information to be visible', - 'click element #tab-case-information', - 'wait for #tab-statistics to be visible', - 'click element #tab-statistics', - 'wait for #tabContent-statistics to be visible', - ], - notes: 'checks the case detail => case information => statistics tab', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/105-20&info=statistics', - }, - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/101-19/add-other-statistics', - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/105-20/add-deficiency-statistics', - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/101-19/edit-other-statistics', - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/105-20/edit-deficiency-statistic/cb557361-50ee-4440-aaff-0a9f1bfa30ed', - { - actions: [ - 'wait for button.red-warning to be visible', - 'click element button.red-warning', - 'wait for #modal-root to be visible', - ], - notes: 'checks the delete deficiency modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/105-20/edit-deficiency-statistic/cb557361-50ee-4440-aaff-0a9f1bfa30ed&info=delete-deficiency-modal', - }, - { - actions: [ - 'wait for button.red-warning to be visible', - 'click element button.red-warning', - 'wait for #modal-root to be visible', - ], - notes: 'checks the delete modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/101-19/edit-other-statistics&info=delete-other-statistics-modal', - }, - { - actions: [ - 'wait for element #tab-parties to be visible', - 'click element #tab-parties', - 'wait for element .sealed-address to be visible', - ], - notes: - 'checks a11y of sealed address display for primary and secondary contact', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/102-19/case-information&info=sealed-address-display', - }, - - /* petition qc */ - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/104-19/petition-qc?tab=partyInfo', - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/104-19/petition-qc?tab=caseInfo', - { - actions: [ - 'wait for button#tab-irs-notice to be visible', - 'click element button#tab-irs-notice', - 'wait for label#has-irs-verified-notice-yes to be visible', - 'click element label#has-irs-verified-notice-yes', - 'wait for #date-of-notice-picker to be visible', - ], - notes: 'checks a11y of editable fields exposed when Yes notice attached', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/102-19/petition-qc?tab=irsNotice&info=reveal-notice-options', - }, - { - actions: [ - 'wait for #tab-irs-notice to be visible', - 'click element #tab-irs-notice', - 'wait for #irs-verified-notice-radios to be visible', - 'click element #has-irs-verified-notice-yes', - 'wait for #date-of-notice-picker to be visible', - 'set field #case-type to Deficiency', - 'check field #case-type', - 'wait for .statistic-form to be visible', - ], - notes: 'checks the statistics section of the petition QC screen', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/file-a-petition/step-1&info=statistics-petition-qc', - }, - { - actions: [ - 'wait for #tab-irs-notice to be visible', - 'click element #tab-irs-notice', - 'wait for #irs-verified-notice-radios to be visible', - 'click element #has-irs-verified-notice-yes', - 'wait for #date-of-notice-picker to be visible', - 'set field #case-type to Deficiency', - 'check field #case-type', - 'wait for .calculate-penalties to be visible', - 'click element .calculate-penalties', - 'wait for .modal-screen to be visible', - ], - notes: 'checks the Calculate Penalties on IRS Notice modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/file-a-petition/step-1&info=penalties-modal', - }, - { - actions: [ - 'wait for .remove-pdf-button to be visible', - 'click element .remove-pdf-button', - 'wait for .confirm-replace-petition-modal to be visible', - ], - notes: 'checks a11y of ConfirmReplacePetitionModal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/121-20/petition-qc', - }, +module.exports = [ + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/', + // ], + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/file-a-petition/step-1', + // ], + // url: 'http://localhost:1234/', + // }, + // /* start case internal */ + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/file-a-petition/step-1', + // 'wait for #party-type to be visible', + // 'set field #party-type to Surviving spouse', + // 'check field #party-type', + // 'wait for #secondary-name to be visible', + // ], + // notes: + // 'checks a11y of Create Case with inputs revealed - secondary contact', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/file-a-petition/step-1', + // 'wait for #party-type to be visible', + // 'set field #party-type to Corporation', + // 'check field #party-type', + // 'wait for #order-for-cds-label to be visible', + // ], + // notes: 'checks a11y of Create Case with inputs revealed - Order for CDS', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/file-a-petition/step-1', + // 'wait for #tab-case-info to be visible', + // 'click element #tab-case-info', + // 'wait for #date-received-picker to be visible', + // ], + // notes: 'checks a11y of Create Case with inputs revealed - Case Info tab', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/file-a-petition/step-1', + // 'wait for #tab-irs-notice to be visible', + // 'click element #tab-irs-notice', + // 'wait for #irs-verified-notice-radios to be visible', + // 'click element #has-irs-verified-notice-yes', + // 'wait for #date-of-notice-picker to be visible', + // ], + // notes: 'checks a11y of Create Case with inputs revealed - IRS Notice tab', + // url: 'http://localhost:1234/', + // }, - /* review petition */ - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/104-19/documents/c63be3f2-2240-451e-b6bd-8206d52a070b/review', + // /* case detail */ + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/101-19', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/108-19', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // ], + // notes: 'checks a11y of case information tab, overview secondary tab', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/102-19', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #tab-parties to be visible', + // 'click element #tab-parties', + // ], + // notes: 'checks a11y of case information tab, petitioner secondary tab', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/999-15', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #tab-parties to be visible', + // 'click element #tab-parties', + // 'wait for #respondent-counsel to be visible', + // 'click element #respondent-counsel', + // 'wait for #edit-respondent-counsel to be visible', + // 'click element #edit-respondent-counsel', + // ], + // notes: + // 'checks a11y of case information tab, parties secondary tab, respondent counsel tertiary tab', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/102-19', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #tab-parties to be visible', + // 'click element #tab-parties', + // 'wait for #practitioner-search-field to be visible', + // 'set field #practitioner-search-field to GL1111', + // 'check field #practitioner-search-field', + // 'click element button#search-for-practitioner', + // 'wait for #counsel-matches-legend to be visible', + // ], + // notes: 'checks a11y of add practitioner modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/105-19/edit-petitioner-counsel/PT1234', + // 'wait for #practitioner-representing to be visible', + // ], + // notes: 'checks a11y of edit petitioner counsel page', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/102-19', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #tab-parties to be visible', + // 'click element #tab-parties', + // 'wait for #respondent-counsel to be visible', + // 'click element #respondent-counsel', + // 'wait for #respondent-search-field to be visible', + // 'set field #respondent-search-field to WN7777', + // 'check field #respondent-search-field', + // 'click element button#search-for-respondent', + // 'wait for #counsel-matches-legend to be visible', + // ], + // notes: 'checks a11y of add respondent modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/103-19/edit-respondent-counsel/RT6789', + // 'wait for #submit-edit-respondent-information to be visible', + // ], + // notes: 'checks a11y of edit respondentCounsel page', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/109-19', + // 'wait for #tab-drafts to be visible', + // 'click element #tab-drafts', + // 'wait for #edit-order-button to be visible', + // 'click element #edit-order-button', + // 'wait for .modal-button-confirm to be visible', + // ], + // notes: 'checks the confirm modal when editing a signed draft document', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/105-19', + // 'wait for #case-detail-menu-button to be visible', + // 'wait for .progress-indicator to be hidden', + // 'click element #case-detail-menu-button', + // 'wait for #menu-button-add-new-message to be visible', + // 'wait for .progress-indicator to be hidden', + // 'click element #menu-button-add-new-message', + // 'wait for .ustc-create-message-modal to be visible', + // ], + // notes: 'checks a11y of create message modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/105-19', + // 'wait for #case-detail-menu-button to be visible', + // 'wait for .progress-indicator to be hidden', + // 'click element #case-detail-menu-button', + // 'wait for #menu-button-create-order to be visible', + // 'wait for .progress-indicator to be hidden', + // 'click element #menu-button-create-order', + // 'wait for #eventCode to be visible', + // ], + // notes: 'checks a11y of create order select document type modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/107-19', + // 'wait for #tab-tracked-items to be visible', + // 'click element #tab-tracked-items', + // ], + // notes: 'checks a11y of deadlines tab', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/105-19', + // 'wait for #case-detail-menu-button to be visible', + // 'wait for .progress-indicator to be hidden', + // 'click element #case-detail-menu-button', + // 'wait for #menu-button-add-deadline to be visible', + // 'wait for .progress-indicator to be hidden', + // 'click element #menu-button-add-deadline', + // 'wait for #deadline-date-picker to be visible', + // ], + // notes: 'checks a11y of add deadline modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/109-19', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #blocked-from-trial-header to be visible', + // ], + // notes: + // 'checks a11y of case information overview tab for a case with a manual and automatic block', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/109-19', + // 'wait for #tab-drafts to be visible', + // 'click element #tab-drafts', + // ], + // notes: 'checks a11y of the draft documents tab', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/109-19', + // 'wait for #tab-case-messages to be visible', + // 'click element #tab-case-messages', + // ], + // notes: 'checks a11y of case messages tab', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/109-19', + // 'wait for #tab-tracked-items to be visible', + // 'click element #tab-tracked-items', + // 'wait for #tab-pending-report to be visible', + // 'click element #tab-pending-report', + // ], + // notes: 'checks a11y of tracked-items tab, pending report secondary tab', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/103-19', + // 'wait for #tab-correspondence to be visible', + // 'click element #tab-correspondence', + // 'wait for .document-viewer--documents to be visible', + // ], + // notes: 'checks a11y of correspondence tab', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/103-19/upload-correspondence', + // 'wait for element #upload-correspondence to be visible', + // ], + // notes: 'checks a11y of add correspondence page', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/103-19', + // 'wait for #tab-correspondence to be visible', + // 'click element #tab-correspondence', + // 'wait for .document-viewer--documents to be visible', + // 'click element .edit-correspondence-button', + // 'wait for element #edit-correspondence-header to be visible', + // ], + // notes: 'checks a11y of edit correspondence page', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/case-detail/103-20/document-view?docketEntryId=ac62f25a-49f9-46a5-aed7-d6b955a2dc34', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/108-19', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #edit-case-trial-information-btn to be visible', + // 'click element #edit-case-trial-information-btn', + // 'wait for #add-edit-calendar-note to be visible', + // 'click element #add-edit-calendar-note', + // 'wait for .add-edit-calendar-note-modal to be visible', + // ], + // notes: 'checks the add edit calendar note modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/108-19', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #edit-case-trial-information-btn to be visible', + // 'click element #edit-case-trial-information-btn', + // 'wait for #remove-from-trial-session-btn to be visible', + // 'click element #remove-from-trial-session-btn', + // 'wait for #remove-from-trial-session-modal to be visible', + // ], + // notes: 'checks the remove from trial session modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/101-19', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for .high-priority-btn to be visible', + // 'click element .high-priority-btn', + // 'wait for #prioritize-case-modal to be visible', + // ], + // notes: 'opens the prioritize case modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/110-19', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #remove-high-priority-btn to be visible', + // 'click element #remove-high-priority-btn', + // 'wait for #unprioritize-modal to be visible', + // ], + // notes: 'opens the unprioritize case modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/104-19', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #add-to-trial-session-btn to be visible', + // 'click element #add-to-trial-session-btn', + // 'wait for #add-to-trial-session-modal to be visible', + // ], + // notes: 'checks the add to trial session modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/105-20', + // 'wait for #tab-case-information to be visible', + // 'click element #tab-case-information', + // 'wait for #tab-statistics to be visible', + // 'click element #tab-statistics', + // 'wait for #tabContent-statistics to be visible', + // ], + // notes: 'checks the case detail => case information => statistics tab', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/101-19/add-other-statistics', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/105-20/add-deficiency-statistics', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/101-19/edit-other-statistics', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/105-20/edit-deficiency-statistic/cb557361-50ee-4440-aaff-0a9f1bfa30ed', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/105-20/edit-deficiency-statistic/cb557361-50ee-4440-aaff-0a9f1bfa30ed', + // 'wait for button.red-warning to be visible', + // 'click element button.red-warning', + // 'wait for #modal-root to be visible', + // ], + // notes: 'checks the delete deficiency modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/101-19/edit-other-statistics', + // 'wait for button.red-warning to be visible', + // 'click element button.red-warning', + // 'wait for #modal-root to be visible', + // ], + // notes: 'checks the delete modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/102-19/case-information', + // 'wait for element #tab-parties to be visible', + // 'click element #tab-parties', + // 'wait for element .sealed-address to be visible', + // ], + // notes: + // 'checks a11y of sealed address display for primary and secondary contact', + // url: 'http://localhost:1234/', + // }, - /* trial sessions */ - { - actions: ['wait for #trial-sessions-tabs to be visible'], - notes: 'checks a11y of trial sessions table list', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/trial-sessions&info=list-trial-sessions', - }, - { - actions: [ - 'wait for #start-date-picker to be visible', - 'wait for #meeting-id to be visible', - ], - notes: 'checks a11y of remote trial session add form', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/add-a-trial-session&info=add-trial-session', - }, - { - actions: [ - 'wait for #standaloneRemote-session-scope-label to be visible', - 'click element #standaloneRemote-session-scope-label', - ], - notes: 'checks a11y of standalone remote trial session add form', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/add-a-trial-session&info=add-trial-session', - }, - { - actions: [ - 'wait for #start-date-picker to be visible', - 'click element #inPerson-proceeding-label', - 'wait for #address1 to be visible', - ], - notes: 'checks a11y of in-person trial sessions add form', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/add-a-trial-session&info=add-trial-session', - }, - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/trial-session-detail/5b18af9e-4fbd-459b-8db7-7b15108c7fa5&info=non-calendared-case', + // /* petition qc */ + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/104-19/petition-qc?tab=partyInfo', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/104-19/petition-qc?tab=caseInfo', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/102-19/petition-qc?tab=irsNotice', + // 'wait for button#tab-irs-notice to be visible', + // 'click element button#tab-irs-notice', + // 'wait for label#has-irs-verified-notice-yes to be visible', + // 'click element label#has-irs-verified-notice-yes', + // 'wait for #date-of-notice-picker to be visible', + // ], + // notes: 'checks a11y of editable fields exposed when Yes notice attached', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/file-a-petition/step-1', + // 'wait for #tab-irs-notice to be visible', + // 'click element #tab-irs-notice', + // 'wait for #irs-verified-notice-radios to be visible', + // 'click element #has-irs-verified-notice-yes', + // 'wait for #date-of-notice-picker to be visible', + // 'set field #case-type to Deficiency', + // 'check field #case-type', + // 'wait for .statistic-form to be visible', + // ], + // notes: 'checks the statistics section of the petition QC screen', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/file-a-petition/step-1', + // 'wait for #tab-irs-notice to be visible', + // 'click element #tab-irs-notice', + // 'wait for #irs-verified-notice-radios to be visible', + // 'click element #has-irs-verified-notice-yes', + // 'wait for #date-of-notice-picker to be visible', + // 'set field #case-type to Deficiency', + // 'check field #case-type', + // 'wait for .calculate-penalties to be visible', + // 'click element .calculate-penalties', + // 'wait for .modal-screen to be visible', + // ], + // notes: 'checks the Calculate Penalties on IRS Notice modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/121-20/petition-qc', + // 'wait for .remove-pdf-button to be visible', + // 'click element .remove-pdf-button', + // 'wait for .confirm-replace-petition-modal to be visible', + // ], + // notes: 'checks a11y of ConfirmReplacePetitionModal', + // url: 'http://localhost:1234/', + // }, - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/case-detail/101-19/edit-order/25100ec6-eeeb-4e88-872f-c99fad1fe6c7/sign', - { - actions: [ - 'wait for #trial-location to be visible', - 'set field #trial-location to Birmingham, Alabama', - 'check field #trial-location', - ], - notes: 'checks the blocked cases screen', + // /* review petition */ + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/case-detail/104-19/documents/c63be3f2-2240-451e-b6bd-8206d52a070b/review', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/reports/blocked-cases&info=blocked-cases-alabama', - }, + // /* trial sessions */ + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/trial-sessions', + // 'wait for #trial-sessions-tabs to be visible', + // ], + // notes: 'checks a11y of trial sessions table list', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/add-a-trial-session', + // 'wait for #start-date-picker to be visible', + // 'wait for #meeting-id to be visible', + // ], + // notes: 'checks a11y of remote trial session add form', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/add-a-trial-session', + // 'wait for #standaloneRemote-session-scope-label to be visible', + // 'click element #standaloneRemote-session-scope-label', + // ], + // notes: 'checks a11y of standalone remote trial session add form', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/add-a-trial-session', + // 'wait for #start-date-picker to be visible', + // 'click element #inPerson-proceeding-label', + // 'wait for #address1 to be visible', + // ], + // notes: 'checks a11y of in-person trial sessions add form', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/trial-session-detail/5b18af9e-4fbd-459b-8db7-7b15108c7fa5', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + { + actions: [ + ...loginAs({ username: 'petitionsclerk@example.com' }), + 'navigate to http://localhost:1234/case-detail/101-19/edit-order/25100ec6-eeeb-4e88-872f-c99fad1fe6c7/sign', + ], + notes: '', + url: 'http://localhost:1234/', + }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/reports/blocked-cases', + // 'wait for #trial-location to be visible', + // 'set field #trial-location to Birmingham, Alabama', + // 'check field #trial-location', + // ], + // notes: 'checks the blocked cases screen', + // url: 'http://localhost:1234/', + // }, // this url probably needs to be moved to calendaring when those users are created - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/reports/case-deadlines', - { - actions: [ - 'wait for #reports-btn to be visible', - 'click element #reports-btn', - 'wait for #trial-session-planning-btn to be visible', - 'click element #trial-session-planning-btn', - 'wait for .trial-session-planning-modal to be visible', - ], - notes: 'checks the trial session planning modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/search&info=trial-session-planning-modal', - }, - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/edit-trial-session/6b6975cf-2b10-4e84-bcae-91e162d2f9d1', - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/trial-session-detail/5b18af9e-4fbd-459b-8db7-7b15108c7fa5&info=qc-complete-checkboxes', - { - actions: [ - 'wait for #tab-practitioner to be visible', - 'click element #tab-practitioner', - 'wait for #practitioner-name to be visible', - 'set field #practitioner-name to test', - 'click element #practitioner-search-by-name-button', - 'wait for .search-results to be visible', - ], - notes: 'checks the advanced search practitioner tab and results table', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/search&info=practitioner-search-results', - }, - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/practitioner-detail/PT1234', - /* messages */ - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/messages/my/inbox&info=messages-inbox', - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/messages/my/outbox&info=messages-outbox', - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/messages/section/inbox&info=messages-section-inbox', - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/messages/section/outbox&info=messages-section-outbox', - 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/messages/105-20/message-detail/eb0a139a-8951-4de1-8b83-f02a27504105&info=case-message-detail', - { - actions: [ - 'wait for #button-forward to be visible', - 'click element #button-forward', - 'wait for .modal-dialog to be visible', - ], - notes: 'checks the forward modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/messages/105-20/message-detail/eb0a139a-8951-4de1-8b83-f02a27504105&info=message-detail-forward', - }, - { - actions: [ - 'wait for #button-reply to be visible', - 'click element #button-reply', - 'wait for .modal-dialog to be visible', - ], - notes: 'checks the reply modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/messages/105-20/message-detail/eb0a139a-8951-4de1-8b83-f02a27504105&info=message-detail-reply', - }, - { - actions: [ - 'wait for #button-complete to be visible', - 'click element #button-reply', - 'wait for .modal-dialog to be visible', - ], - notes: 'checks the complete modal', - url: 'http://localhost:1234/log-in?code=petitionsclerk@example.com&path=/messages/105-20/message-detail/eb0a139a-8951-4de1-8b83-f02a27504105&info=message-detail-complete', - }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/reports/case-deadlines', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/search', + // 'wait for #reports-btn to be visible', + // 'click element #reports-btn', + // 'wait for #trial-session-planning-btn to be visible', + // 'click element #trial-session-planning-btn', + // 'wait for .trial-session-planning-modal to be visible', + // ], + // notes: 'checks the trial session planning modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/edit-trial-session/6b6975cf-2b10-4e84-bcae-91e162d2f9d1', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/trial-session-detail/5b18af9e-4fbd-459b-8db7-7b15108c7fa5', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/search', + // 'wait for #tab-practitioner to be visible', + // 'click element #tab-practitioner', + // 'wait for #practitioner-name to be visible', + // 'set field #practitioner-name to test', + // 'click element #practitioner-search-by-name-button', + // 'wait for .search-results to be visible', + // ], + // notes: 'checks the advanced search practitioner tab and results table', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/practitioner-detail/PT1234', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // /* messages */ + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/messages/my/inbox', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/messages/my/outbox', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/messages/section/inbox', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/messages/section/outbox', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/messages/105-20/message-detail/eb0a139a-8951-4de1-8b83-f02a27504105', + // ], + // notes: '', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/messages/105-20/message-detail/eb0a139a-8951-4de1-8b83-f02a27504105', + // 'wait for #button-forward to be visible', + // 'click element #button-forward', + // 'wait for .modal-dialog to be visible', + // ], + // notes: 'checks the forward modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/messages/105-20/message-detail/eb0a139a-8951-4de1-8b83-f02a27504105', + // 'wait for #button-reply to be visible', + // 'click element #button-reply', + // 'wait for .modal-dialog to be visible', + // ], + // notes: 'checks the reply modal', + // url: 'http://localhost:1234/', + // }, + // { + // actions: [ + // ...loginAs({ username: 'petitionsclerk@example.com' }), + // 'navigate to http://localhost:1234/messages/105-20/message-detail/eb0a139a-8951-4de1-8b83-f02a27504105', + // 'wait for #button-complete to be visible', + // 'click element #button-reply', + // 'wait for .modal-dialog to be visible', + // ], + // notes: 'checks the complete modal', + // url: 'http://localhost:1234/', + // }, ]; From ea2a56a9cc6c32a1142631230be6961547db2a5c Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 19:55:43 -0600 Subject: [PATCH 193/700] 10007: WIP use adminSetUserPassword instead of responding to NEW_PASSWORD_REQUIRED challenge when setting user password --- .../src/proxies/auth/changePasswordProxy.ts | 2 +- .../useCases/auth/changePasswordInteractor.ts | 89 +++++++++++++------ .../Login/submitChangePasswordAction.tsx | 3 +- 3 files changed, 63 insertions(+), 31 deletions(-) diff --git a/shared/src/proxies/auth/changePasswordProxy.ts b/shared/src/proxies/auth/changePasswordProxy.ts index d687aaa4f50..439ea8e6ec9 100644 --- a/shared/src/proxies/auth/changePasswordProxy.ts +++ b/shared/src/proxies/auth/changePasswordProxy.ts @@ -14,7 +14,7 @@ export const changePasswordInteractor = ( userEmail: string; tempPassword: string; }, -) => { +): Promise<{ accessToken: string; idToken: string; refreshToken: string }> => { return post({ applicationContext, body: { confirmPassword, password, tempPassword, userEmail }, diff --git a/web-api/src/business/useCases/auth/changePasswordInteractor.ts b/web-api/src/business/useCases/auth/changePasswordInteractor.ts index efbc0aff66d..433d87f0ba9 100644 --- a/web-api/src/business/useCases/auth/changePasswordInteractor.ts +++ b/web-api/src/business/useCases/auth/changePasswordInteractor.ts @@ -1,4 +1,4 @@ -import { RespondToAuthChallengeCommandInput } from '@aws-sdk/client-cognito-identity-provider'; +// import { RespondToAuthChallengeCommandInput } from '@aws-sdk/client-cognito-identity-provider'; import { ServerApplicationContext } from '@web-api/applicationContext'; import { UnauthorizedError, @@ -18,50 +18,83 @@ export const changePasswordInteractor = async ( userEmail: string; confirmPassword: string; }, -) => { +): Promise<{ idToken: string; accessToken: string; refreshToken: string }> => { try { // TODO: Validate Password === ConfirmPassword + Rules? + // TODO: If we decide to stick with adminUserSetPassword, remove tempPassword everywhere console.log('confirmPassword', confirmPassword); - - const initiateAuthResult = await applicationContext + console.log('tempPassword', tempPassword); + const setPasswordResult = await applicationContext .getCognito() - .initiateAuth({ - AuthFlow: 'USER_PASSWORD_AUTH', - AuthParameters: { - PASSWORD: tempPassword, - USERNAME: userEmail, - }, - ClientId: applicationContext.environment.cognitoClientId, + .adminSetUserPassword({ + Password: password, + Permanent: true, + UserPoolId: process.env.USER_POOL_ID, + Username: userEmail, }); - if (initiateAuthResult?.ChallengeName === 'NEW_PASSWORD_REQUIRED') { - const params: RespondToAuthChallengeCommandInput = { - ChallengeName: 'NEW_PASSWORD_REQUIRED', - ChallengeResponses: { - NEW_PASSWORD: password, - USERNAME: userEmail, - }, - ClientId: process.env.COGNITO_CLIENT_ID, - Session: initiateAuthResult.Session, - }; + console.log('setPasswordResult****', setPasswordResult); - const cognito = applicationContext.getCognito(); - const result = await cognito.respondToAuthChallenge(params); + if (setPasswordResult.$metadata.httpStatusCode === 200) { + const initiateAuthResult = await applicationContext + .getCognito() + .initiateAuth({ + AuthFlow: 'USER_PASSWORD_AUTH', + AuthParameters: { + PASSWORD: password, + USERNAME: userEmail, + }, + ClientId: applicationContext.environment.cognitoClientId, + }); + console.log('initiateAuthResult****', initiateAuthResult); return { - accessToken: result.AuthenticationResult!.AccessToken!, - idToken: result.AuthenticationResult!.IdToken!, - refreshToken: result.AuthenticationResult!.RefreshToken!, + accessToken: initiateAuthResult.AuthenticationResult!.AccessToken!, + idToken: initiateAuthResult.AuthenticationResult!.IdToken!, + refreshToken: initiateAuthResult.AuthenticationResult!.RefreshToken!, }; } + throw new Error('Could not set user password'); + // const initiateAuthResult = await applicationContext + // .getCognito() + // .initiateAuth({ + // AuthFlow: 'USER_PASSWORD_AUTH', + // AuthParameters: { + // PASSWORD: tempPassword, + // USERNAME: userEmail, + // }, + // ClientId: applicationContext.environment.cognitoClientId, + // }); + + // if (initiateAuthResult?.ChallengeName === 'NEW_PASSWORD_REQUIRED') { + // const params: RespondToAuthChallengeCommandInput = { + // ChallengeName: 'NEW_PASSWORD_REQUIRED', + // ChallengeResponses: { + // NEW_PASSWORD: password, + // USERNAME: userEmail, + // }, + // ClientId: process.env.COGNITO_CLIENT_ID, + // Session: initiateAuthResult.Session, + // }; + + // const cognito = applicationContext.getCognito(); + // const result = await cognito.respondToAuthChallenge(params); + + // return { + // accessToken: result.AuthenticationResult!.AccessToken!, + // idToken: result.AuthenticationResult!.IdToken!, + // refreshToken: result.AuthenticationResult!.RefreshToken!, + // }; + // } - throw new Error('Something went wrong while changing passwords... :('); + // throw new Error('Something went wrong while changing passwords... :('); } catch (err: any) { - console.log('changePasswordInteractorError', err); + console.log('changePasswordInteractorError***', err); if ( err.name === 'InvalidPasswordException' || err.name === 'NotAuthorizedException' || + err.name === 'UserNotFoundException' || err.name === 'UserNotFoundException' ) { throw new UnidentifiedUserError('Invalid Username or Password'); //401 diff --git a/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx b/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx index 6c567cf9f61..fec03377d0b 100644 --- a/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx +++ b/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx @@ -25,8 +25,7 @@ export const submitChangePasswordAction = async ({ password, tempPassword, userEmail, - }).AuthenticationResult; - + }); return path.success({ accessToken, idToken, refreshToken }); } catch (err: any) { const originalErrorMessage = err?.originalError?.response?.data; From f3fee26658d08f577ed105dd355bc940e02a43e9 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:35:22 -0600 Subject: [PATCH 194/700] 10007: update ChangePasswordForm entity with validation rules for whole form, validate form before submitting, replace MessageAlert with ErrorNotification --- .../business/entities/ChangePasswordForm.ts | 8 ++++++ .../Login/submitChangePasswordAction.tsx | 1 + .../Login/validateChangePasswordFormAction.ts | 24 +++++++++++++++++ .../Login/submitChangePasswordSequence.ts | 26 ++++++++++++------- web-client/src/views/Login/ChangePassword.tsx | 12 ++------- 5 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 web-client/src/presenter/actions/Login/validateChangePasswordFormAction.ts diff --git a/shared/src/business/entities/ChangePasswordForm.ts b/shared/src/business/entities/ChangePasswordForm.ts index 8c4ec904ee3..1432127d6a2 100644 --- a/shared/src/business/entities/ChangePasswordForm.ts +++ b/shared/src/business/entities/ChangePasswordForm.ts @@ -56,11 +56,13 @@ export function getDefaultPasswordErrors(): ChangePasswordValidations { } export class ChangePasswordForm extends JoiValidationEntity { + public userEmail: string; public password: string; public confirmPassword: string; constructor(rawProps) { super('ChangePasswordForm'); + this.userEmail = rawProps.userEmail; this.password = rawProps.password; this.confirmPassword = rawProps.confirmPassword; } @@ -119,6 +121,12 @@ export class ChangePasswordForm extends JoiValidationEntity { }).description( 'Password for the account. Contains a custom validation because we want to construct a string with all the keys that failed which later we parse out to an object', ), + userEmail: JoiValidationConstants.EMAIL.required() + .messages({ + '*': 'Enter a valid email address', + 'string.max': 'Email address must contain fewer than 100 characters', + }) + .description('Email of user'), }); getValidationRules() { diff --git a/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx b/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx index fec03377d0b..894a91cb747 100644 --- a/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx +++ b/web-client/src/presenter/actions/Login/submitChangePasswordAction.tsx @@ -26,6 +26,7 @@ export const submitChangePasswordAction = async ({ tempPassword, userEmail, }); + return path.success({ accessToken, idToken, refreshToken }); } catch (err: any) { const originalErrorMessage = err?.originalError?.response?.data; diff --git a/web-client/src/presenter/actions/Login/validateChangePasswordFormAction.ts b/web-client/src/presenter/actions/Login/validateChangePasswordFormAction.ts new file mode 100644 index 00000000000..91f2bdcbbc4 --- /dev/null +++ b/web-client/src/presenter/actions/Login/validateChangePasswordFormAction.ts @@ -0,0 +1,24 @@ +import { ChangePasswordForm } from '@shared/business/entities/ChangePasswordForm'; +import { state } from '@web-client/presenter/app.cerebral'; + +export const validateChangePasswordFormAction = ({ + get, + path, +}: ActionProps) => { + const changePasswordForm = get(state.form); + + const errors = new ChangePasswordForm( + changePasswordForm, + ).getFormattedValidationErrors(); + + if (!errors) { + return path.success(); + } else { + return path.error({ + alertError: { + title: 'Errors were found. Please correct your form and resubmit.', + }, + errors, + }); + } +}; diff --git a/web-client/src/presenter/sequences/Login/submitChangePasswordSequence.ts b/web-client/src/presenter/sequences/Login/submitChangePasswordSequence.ts index 360425edc9a..b977324915d 100644 --- a/web-client/src/presenter/sequences/Login/submitChangePasswordSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitChangePasswordSequence.ts @@ -6,22 +6,30 @@ import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertError import { setTokenAction } from '@web-client/presenter/actions/Login/setTokenAction'; import { setUserAction } from '@web-client/presenter/actions/setUserAction'; import { setUserPermissionsAction } from '@web-client/presenter/actions/setUserPermissionsAction'; +import { setValidationAlertErrorsAction } from '@web-client/presenter/actions/setValidationAlertErrorsAction'; import { showProgressSequenceDecorator } from '../../utilities/showProgressSequenceDecorator'; import { submitChangePasswordAction } from '@web-client/presenter/actions/Login/submitChangePasswordAction'; +import { validateChangePasswordFormAction } from '@web-client/presenter/actions/Login/validateChangePasswordFormAction'; export const submitChangePasswordSequence = [ showProgressSequenceDecorator([ - submitChangePasswordAction, + validateChangePasswordFormAction, { - error: [setAlertErrorAction], + error: [setValidationAlertErrorsAction], success: [ - clearFormAction, - decodeTokenAction, - setTokenAction, - getUserAction, - setUserAction, - setUserPermissionsAction, - navigateToPathAction, + submitChangePasswordAction, + { + error: [setAlertErrorAction], + success: [ + clearFormAction, + decodeTokenAction, + setTokenAction, + getUserAction, + setUserAction, + setUserPermissionsAction, + navigateToPathAction, + ], + }, ], }, ]), diff --git a/web-client/src/views/Login/ChangePassword.tsx b/web-client/src/views/Login/ChangePassword.tsx index 88df68812dd..103e85c2452 100644 --- a/web-client/src/views/Login/ChangePassword.tsx +++ b/web-client/src/views/Login/ChangePassword.tsx @@ -1,5 +1,5 @@ import { Button } from '@web-client/ustc-ui/Button/Button'; -import { MessageAlert } from '@web-client/ustc-ui/MessageAlert/MessageAlert'; +import { ErrorNotification } from '@web-client/views/ErrorNotification'; import { RequirementsText } from '@web-client/views/CreatePetitionerAccount/RequirementsText'; import { SuccessNotification } from '@web-client/views/SuccessNotification'; import { connect } from '@web-client/presenter/shared.cerebral'; @@ -8,7 +8,6 @@ import React from 'react'; export const ChangePassword = connect( { - alertError: state.alertError, changePasswordHelper: state.changePasswordHelper, confirmPassword: state.form.confirmPassword, password: state.form.password, @@ -19,7 +18,6 @@ export const ChangePassword = connect( updateFormValueSequence: sequences.updateFormValueSequence, }, ({ - alertError, changePasswordHelper, confirmPassword, password, @@ -35,13 +33,7 @@ export const ChangePassword = connect(
- {alertError && ( - - )} +
From 682d3017df7d536b0e442500d1875a9e40f59f4e Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:44:05 -0600 Subject: [PATCH 195/700] 10007: share more between NewPetitionerUser and ChangePasswordForm --- .../business/entities/ChangePasswordForm.ts | 54 +------------------ .../business/entities/NewPetitionerUser.ts | 17 +++--- 2 files changed, 9 insertions(+), 62 deletions(-) diff --git a/shared/src/business/entities/ChangePasswordForm.ts b/shared/src/business/entities/ChangePasswordForm.ts index 1432127d6a2..afa9d6be383 100644 --- a/shared/src/business/entities/ChangePasswordForm.ts +++ b/shared/src/business/entities/ChangePasswordForm.ts @@ -1,60 +1,8 @@ import { JoiValidationConstants } from './JoiValidationConstants'; import { JoiValidationEntity } from './JoiValidationEntity'; +import { getDefaultPasswordErrors } from '@shared/business/entities/NewPetitionerUser'; import joi from 'joi'; -type PasswordValidation = { - message: string; - valid: boolean; -}; - -export type ChangePasswordValidations = { - hasNoLeadingOrTrailingSpace: PasswordValidation; - hasOneLowercase: PasswordValidation; - hasOneNumber: PasswordValidation; - hasOneUppercase: PasswordValidation; - hasSpecialCharacterOrSpace: PasswordValidation; - isProperLength: PasswordValidation; -}; - -const ChangePasswordValidationErrorMessages = { - hasNoLeadingOrTrailingSpace: 'Must not contain leading or trailing space', - hasOneLowercase: 'Must contain lower case letter', - hasOneNumber: 'Must contain number', - hasOneUppercase: 'Must contain upper case letter', - hasSpecialCharacterOrSpace: 'Must contain special character or space', - isProperLength: 'Must be between 8-99 characters long', -}; - -export function getDefaultPasswordErrors(): ChangePasswordValidations { - return { - hasNoLeadingOrTrailingSpace: { - message: - ChangePasswordValidationErrorMessages.hasNoLeadingOrTrailingSpace, - valid: true, - }, - hasOneLowercase: { - message: ChangePasswordValidationErrorMessages.hasOneLowercase, - valid: true, - }, - hasOneNumber: { - message: ChangePasswordValidationErrorMessages.hasOneNumber, - valid: true, - }, - hasOneUppercase: { - message: ChangePasswordValidationErrorMessages.hasOneUppercase, - valid: true, - }, - hasSpecialCharacterOrSpace: { - message: ChangePasswordValidationErrorMessages.hasSpecialCharacterOrSpace, - valid: true, - }, - isProperLength: { - message: ChangePasswordValidationErrorMessages.isProperLength, - valid: true, - }, - }; -} - export class ChangePasswordForm extends JoiValidationEntity { public userEmail: string; public password: string; diff --git a/shared/src/business/entities/NewPetitionerUser.ts b/shared/src/business/entities/NewPetitionerUser.ts index 4290bb13614..4b9c0b6142d 100644 --- a/shared/src/business/entities/NewPetitionerUser.ts +++ b/shared/src/business/entities/NewPetitionerUser.ts @@ -15,7 +15,8 @@ export type PasswordValidations = { hasSpecialCharacterOrSpace: PasswordValidation; isProperLength: PasswordValidation; }; -const NewPetitionerUserPasswordValidationErrorMessages = { + +export const PasswordValidationErrorMessages = { hasNoLeadingOrTrailingSpace: 'Must not contain leading or trailing space', hasOneLowercase: 'Must contain lower case letter', hasOneNumber: 'Must contain number', @@ -27,29 +28,27 @@ const NewPetitionerUserPasswordValidationErrorMessages = { export function getDefaultPasswordErrors(): PasswordValidations { return { hasNoLeadingOrTrailingSpace: { - message: - NewPetitionerUserPasswordValidationErrorMessages.hasNoLeadingOrTrailingSpace, + message: PasswordValidationErrorMessages.hasNoLeadingOrTrailingSpace, valid: true, }, hasOneLowercase: { - message: NewPetitionerUserPasswordValidationErrorMessages.hasOneLowercase, + message: PasswordValidationErrorMessages.hasOneLowercase, valid: true, }, hasOneNumber: { - message: NewPetitionerUserPasswordValidationErrorMessages.hasOneNumber, + message: PasswordValidationErrorMessages.hasOneNumber, valid: true, }, hasOneUppercase: { - message: NewPetitionerUserPasswordValidationErrorMessages.hasOneUppercase, + message: PasswordValidationErrorMessages.hasOneUppercase, valid: true, }, hasSpecialCharacterOrSpace: { - message: - NewPetitionerUserPasswordValidationErrorMessages.hasSpecialCharacterOrSpace, + message: PasswordValidationErrorMessages.hasSpecialCharacterOrSpace, valid: true, }, isProperLength: { - message: NewPetitionerUserPasswordValidationErrorMessages.isProperLength, + message: PasswordValidationErrorMessages.isProperLength, valid: true, }, }; From 7cc43409e14deaad368e97151c6813ed226209cc Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 21:09:34 -0600 Subject: [PATCH 196/700] 10007: tentatively add "cognito-idp:AdminSetUserPassword" permissions for lambda --- iam/terraform/environment-specific/main/lambda.tf | 1 + web-api/src/business/useCases/auth/changePasswordInteractor.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iam/terraform/environment-specific/main/lambda.tf b/iam/terraform/environment-specific/main/lambda.tf index 4b27e50a7aa..676a0615a96 100644 --- a/iam/terraform/environment-specific/main/lambda.tf +++ b/iam/terraform/environment-specific/main/lambda.tf @@ -68,6 +68,7 @@ resource "aws_iam_role_policy" "lambda_policy" { "cognito-idp:AdminGetUser", "cognito-idp:AdminUpdateUserAttributes", "cognito-idp:AdminConfirmSignUp", + "cognito-idp:AdminSetUserPassword", "cognito-idp:ListUserPoolClients", "cognito-idp:ListUsers" ], diff --git a/web-api/src/business/useCases/auth/changePasswordInteractor.ts b/web-api/src/business/useCases/auth/changePasswordInteractor.ts index 433d87f0ba9..905e3bda9cd 100644 --- a/web-api/src/business/useCases/auth/changePasswordInteractor.ts +++ b/web-api/src/business/useCases/auth/changePasswordInteractor.ts @@ -21,7 +21,7 @@ export const changePasswordInteractor = async ( ): Promise<{ idToken: string; accessToken: string; refreshToken: string }> => { try { // TODO: Validate Password === ConfirmPassword + Rules? - // TODO: If we decide to stick with adminUserSetPassword, remove tempPassword everywhere + // TODO: If we decide to stick with adminUserSetPassword, remove tempPassword everywhere. Otherwise, remove `"cognito-idp:AdminSetUserPassword"` from lambda.tf console.log('confirmPassword', confirmPassword); console.log('tempPassword', tempPassword); const setPasswordResult = await applicationContext From 8e30116e9a13ca536117e584a0eae038c88db257 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 22:04:30 -0600 Subject: [PATCH 197/700] 10007: fix validation on change password page --- .../src/presenter/sequences/Login/goToChangePasswordSequence.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts b/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts index 5e81508f914..5fe3cd91916 100644 --- a/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts +++ b/web-client/src/presenter/sequences/Login/goToChangePasswordSequence.ts @@ -1,7 +1,9 @@ +import { clearFormAction } from '@web-client/presenter/actions/clearFormAction'; import { setupChangePasswordFormAction } from '@web-client/presenter/actions/setupChangePasswordFormAction'; import { setupCurrentPageAction } from '../../actions/setupCurrentPageAction'; export const goToChangePasswordSequence = [ + clearFormAction, setupChangePasswordFormAction, setupCurrentPageAction('ChangePassword'), ] as unknown as () => void; From d00dfebe9e047d94285b9d213780ac807fbeb695 Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Tue, 16 Jan 2024 22:38:13 -0600 Subject: [PATCH 198/700] 10007: update notes [skip ci] --- temp_delete_me.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index 10eab08e5dc..c23f9995139 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -14,12 +14,13 @@ ::: QUESTIONS ::: - Cognito SRP auth flow - Leaning towards not implementing - - Current discussion: There is a possibility we could accidentally log out plaintext passwords in CloudWatch. How can we prevent this from ever happeneing? + - Current discussion: There is a possibility we could accidentally log out plaintext passwords in CloudWatch. How can we prevent this from ever happening? - Prevent logs from being added to endpoints that accept a password (using lint rules?). - Deploy a new lambda for endpoints that accept a password and disable logs for that lambda. - We could encrypt the password on the frontend and decrypt on the backend so that we never see plaintext of their password. - How are going to make sure our auth is secure? Run scanners or pen testing? - What happens if someone creates an account, we deploy 10007, and THEN they try to verify it??? +- Should we use the initiateAuth + respondToAuthChallenge method or the adminSetUserPassword method for changing passwords? ::: CONVERSATIONS TO HAVE ::: From 5ddbb077826e8f719b4191ce8581cafa28318747 Mon Sep 17 00:00:00 2001 From: John Cruz Date: Wed, 17 Jan 2024 08:12:02 -0700 Subject: [PATCH 199/700] 10228: Get user id using cognito; Add data test ids for cypress test; --- cypress-smoketests.config.ts | 4 ++++ .../petitioner-account-creation.cy.ts | 15 ++++++++++++++- cypress/support/cognito-login.ts | 18 ++++++++++++++++++ web-client/src/presenter/state.ts | 2 +- .../CreatePetitionerAccountForm.tsx | 1 + .../VerificationSent.tsx | 5 ++++- 6 files changed, 42 insertions(+), 3 deletions(-) diff --git a/cypress-smoketests.config.ts b/cypress-smoketests.config.ts index a74304aad08..1b5c5afda58 100644 --- a/cypress-smoketests.config.ts +++ b/cypress-smoketests.config.ts @@ -1,5 +1,6 @@ import { confirmUser, + getNewAccountVerificationCode, getUserTokenWithRetry, } from './cypress/support/cognito-login'; import { defineConfig } from 'cypress'; @@ -18,6 +19,9 @@ export default defineConfig({ confirmUser({ email }) { return confirmUser({ email }); }, + getNewAccountVerificationCode({ email }) { + return getNewAccountVerificationCode({ email }); + }, getUserToken({ email, password }) { return CYPRESS_SMOKETESTS_LOCAL ? getUserTokenLocal(email) diff --git a/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts b/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts index 73462ce1e54..1f5df51b9fc 100644 --- a/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts +++ b/cypress/cypress-smoketests/integration/petitioner-account-creation.cy.ts @@ -9,7 +9,7 @@ describe('Petitioner Account Creation', () => { cy.visit('/create-account/petitioner'); }); - it('should fill out the account creation form', () => { + it('should create an account and verify it using the verification link', () => { cy.get('[data-testid="petitioner-account-creation-email"]').type( TEST_EMAIL, ); @@ -25,6 +25,19 @@ describe('Petitioner Account Creation', () => { cy.get( '[data-testid="petitioner-account-creation-confirm-password"]', ).type(TEST_PASSWORD); + + cy.get( + '[data-testid="petitioner-account-creation-submit-button"]', + ).click(); + + cy.get('data-testid="email-address-verification-sent-message"').should( + 'exist', + ); + + cy.task('getNewAccountVerificationCode', { email: TEST_EMAIL }).should( + 'equal', + 'JOHN TESTING', + ); }); }); }); diff --git a/cypress/support/cognito-login.ts b/cypress/support/cognito-login.ts index 985bd4f959d..fdb27c3dec2 100644 --- a/cypress/support/cognito-login.ts +++ b/cypress/support/cognito-login.ts @@ -98,3 +98,21 @@ async function getUserToken(password: string, username: string) { throw e; }); } + +export const getNewAccountVerificationCode = async ({ + email, +}: { + email: string; +}) => { + const users = await cognito.listUsers({ + AttributesToGet: ['custom:userId'], + Filter: `email = "${email}"`, + UserPoolId: process.env.USER_POOL_ID, + }); + + const userId = users.Users?.[0].Attributes?.find( + element => element.Name === 'custom:userId', + )?.Value; + + return userId; +}; diff --git a/web-client/src/presenter/state.ts b/web-client/src/presenter/state.ts index b21ed11fc92..faa6b127d67 100644 --- a/web-client/src/presenter/state.ts +++ b/web-client/src/presenter/state.ts @@ -553,7 +553,7 @@ export const baseState = { advancedSearchForm: {} as any, // form for advanced search screen, TODO: replace with state.form advancedSearchTab: 'case', alertError: undefined, - alertSuccess: undefined, + alertSuccess: undefined as any, allJudges: [], archiveDraftDocument: { docketEntryId: null, diff --git a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx index 8db9c7bccc3..8672cca0481 100644 --- a/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx +++ b/web-client/src/views/CreatePetitionerAccount/CreatePetitionerAccountForm.tsx @@ -247,6 +247,7 @@ export const CreatePetitionerAccountForm = connect(
- - ); - }, -); - -EmailVerificationSuccess.displayName = 'EmailVerificationSuccess'; From 1f2aba84378e85497c1a43a521a0af3ec1644f9d Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 25 Jan 2024 12:26:26 -0800 Subject: [PATCH 353/700] 10007: Remove MessageAlert in favor of SuccessNotification --- .../petitionerCreatesAccount.test.tsx | 1 - .../actions/createConfirmLinkAction.test.tsx | 3 +- .../actions/createConfirmLinkAction.tsx | 1 - .../src/ustc-ui/MessageAlert/MessageAlert.tsx | 43 ------------------- .../VerificationSent.tsx | 18 ++------ 5 files changed, 4 insertions(+), 62 deletions(-) delete mode 100644 web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx diff --git a/web-client/integration-tests/petitionerCreatesAccount.test.tsx b/web-client/integration-tests/petitionerCreatesAccount.test.tsx index 22fbf4535a7..478534ccb71 100644 --- a/web-client/integration-tests/petitionerCreatesAccount.test.tsx +++ b/web-client/integration-tests/petitionerCreatesAccount.test.tsx @@ -69,7 +69,6 @@ describe('Petitioner creates new account', () => { //THIS IS FOR LOCAL VERIFICATION ONLY expect(cerebralTestPrivate.getState('alertSuccess')).toMatchObject({ - alertType: 'success', message: expectedMessage, title: 'Account Created Locally', }); diff --git a/web-client/src/presenter/actions/createConfirmLinkAction.test.tsx b/web-client/src/presenter/actions/createConfirmLinkAction.test.tsx index 1c50f6c9c3c..30b243f6a97 100644 --- a/web-client/src/presenter/actions/createConfirmLinkAction.test.tsx +++ b/web-client/src/presenter/actions/createConfirmLinkAction.test.tsx @@ -53,9 +53,8 @@ describe('createConfirmLinkAction', () => { }, }); - const { alertType, message, title } = result.output!.alertSuccess; + const { message, title } = result.output!.alertSuccess; - expect(alertType).toEqual('success'); expect(message).toEqual(expectedMessage); expect(title).toEqual('Account Created Locally'); }); diff --git a/web-client/src/presenter/actions/createConfirmLinkAction.tsx b/web-client/src/presenter/actions/createConfirmLinkAction.tsx index df0c6a405a3..a577ceff163 100644 --- a/web-client/src/presenter/actions/createConfirmLinkAction.tsx +++ b/web-client/src/presenter/actions/createConfirmLinkAction.tsx @@ -20,7 +20,6 @@ export const createConfirmLinkAction = ({ return { alertSuccess: { - alertType: 'success', message: ( <> {' '} diff --git a/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx b/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx deleted file mode 100644 index 739244f09b7..00000000000 --- a/web-client/src/ustc-ui/MessageAlert/MessageAlert.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React, { useEffect, useRef } from 'react'; - -// 10007 TODO: Do we need this? Can we use ErrorNotification? -// Need ability to add bullet point list -export const MessageAlert = ({ - alertType = 'error', - message, - title, -}: { - alertType: string; - message: React.ReactNode | string; - title: string; -}) => { - const alertTypeClassName = { - error: 'usa-alert--error', - info: 'usa-alert--info', - success: 'usa-alert--success', - warning: 'usa-alert--warning', - }; - const className = alertTypeClassName[alertType] || alertTypeClassName.error; - const notificationRef = useRef(null); - useEffect(() => { - const notification = notificationRef.current; - if (notification) { - window.scrollTo(0, 0); - } - }); - - return ( -
-
-

{title}

-

{message}

-
-
- ); -}; diff --git a/web-client/src/views/CreatePetitionerAccount/VerificationSent.tsx b/web-client/src/views/CreatePetitionerAccount/VerificationSent.tsx index 13be28d2cd8..827f6401aad 100644 --- a/web-client/src/views/CreatePetitionerAccount/VerificationSent.tsx +++ b/web-client/src/views/CreatePetitionerAccount/VerificationSent.tsx @@ -1,14 +1,13 @@ -import { MessageAlert } from '@web-client/ustc-ui/MessageAlert/MessageAlert'; +import { SuccessNotification } from '@web-client/views/SuccessNotification'; import { connect } from '@web-client/presenter/shared.cerebral'; import { state } from '@web-client/presenter/app.cerebral'; import React from 'react'; export const VerificationSent = connect( { - alertSuccess: state.alertSuccess, email: state.cognito.email, }, - ({ alertSuccess, email }) => { + ({ email }) => { return (
- {alertSuccess && ( -
- -
- )} +

Email address verification sent

From a6ee783cf759389eb960d8fb0b914a664ad4925d Mon Sep 17 00:00:00 2001 From: TomElliottFlexion <66225176+TomElliottFlexion@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:28:10 -0600 Subject: [PATCH 354/700] 10007: provisionally add cognito user migration script --- .cognito/seedCognitoLocal.ts | 2 +- .../storage/scripts/cognitoUserIdMigration.ts | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 web-api/storage/scripts/cognitoUserIdMigration.ts diff --git a/.cognito/seedCognitoLocal.ts b/.cognito/seedCognitoLocal.ts index ac68cdfd008..e6950ab81f0 100644 --- a/.cognito/seedCognitoLocal.ts +++ b/.cognito/seedCognitoLocal.ts @@ -154,7 +154,7 @@ const cognitoLocalJSON: CognitoLocalJSON = { }, }, { - Name: 'userId', + Name: 'custom:userId', AttributeDataType: 'String', DeveloperOnlyAttribute: false, Mutable: true, diff --git a/web-api/storage/scripts/cognitoUserIdMigration.ts b/web-api/storage/scripts/cognitoUserIdMigration.ts new file mode 100644 index 00000000000..522f79f8603 --- /dev/null +++ b/web-api/storage/scripts/cognitoUserIdMigration.ts @@ -0,0 +1,72 @@ +import { + AdminUpdateUserAttributesCommandInput, + CognitoIdentityProvider, + ListUsersCommandInput, +} from '@aws-sdk/client-cognito-identity-provider'; +import { createApplicationContext } from '@web-api/applicationContext'; + +const applicationContext = createApplicationContext({}); +const cognito = applicationContext.getCognito(); +// const cognito = new CognitoIdentityProvider({ +// endpoint: 'http://localhost:9229/', +// maxAttempts: 3, +// region: 'local', +// }); + +async function updateUsersWithMissingAttribute( + userPoolId: string, +): Promise { + try { + let paginationToken; + do { + const params: ListUsersCommandInput = { + Limit: 60, + PaginationToken: paginationToken, + UserPoolId: userPoolId, + }; + const data = await cognito.listUsers(params); + const usersToUpdate = data.Users.filter( + user => !user.Attributes?.find(attr => attr.Name === 'custom:userId'), + ); + + console.log('batch of users to update', usersToUpdate); + + for (const user of usersToUpdate) { + const userEmail = user.Attributes?.find(attr => { + return attr.Name === 'email'; + })?.Value; + const userSub = user.Attributes?.find(attr => { + return attr.Name === 'sub'; + })?.Value; + + const adminUpdateUserParams: AdminUpdateUserAttributesCommandInput = { + UserAttributes: [ + { + Name: 'custom:userId', + Value: userSub, + }, + ], + UserPoolId: userPoolId, + Username: userEmail, + }; + + await cognito.adminUpdateUserAttributes(adminUpdateUserParams); + } + + paginationToken = data.PaginationToken; + } while (paginationToken); + + console.log('Migration completed successfully.'); + } catch (error) { + console.error('Error updating users:', error); + } +} + +async function main() { + await updateUsersWithMissingAttribute( + // 'local_2pHzece7', + applicationContext.environment.userPoolId, + ); +} + +main(); From 60bd8a399e4bebfbc0b4d27086486e3b5cbd177d Mon Sep 17 00:00:00 2001 From: Zachary Rogers Date: Thu, 25 Jan 2024 12:49:13 -0800 Subject: [PATCH 355/700] 10007: Style auth related emails a bit, show spinny wheel when logging in after changing password, small change to login style --- temp_delete_me.md | 1 - .../auth/createUserConfirmation.ts | 4 +++ .../useCases/auth/forgotPasswordInteractor.ts | 4 +-- .../Login/submitForgotPasswordSequence.ts | 29 ++++++++++--------- .../goToCreatePetitionerAccountSequence.ts | 4 +-- web-client/src/views/Login/Login.tsx | 5 +++- 6 files changed, 28 insertions(+), 19 deletions(-) diff --git a/temp_delete_me.md b/temp_delete_me.md index b083e82b0c0..540cb3e8f58 100644 --- a/temp_delete_me.md +++ b/temp_delete_me.md @@ -1,5 +1,4 @@ ::: STUFF TO DO ::: -- Finish all todos - Fix tests - web-api/terraform/template/lambdas/cognito-triggers.ts + Extract error message strings into constants OR do something else. (On hold) diff --git a/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts b/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts index a297929805b..5b6d99ee464 100644 --- a/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts +++ b/web-api/src/business/useCaseHelper/auth/createUserConfirmation.ts @@ -40,6 +40,10 @@ export async function createUserConfirmation(

+
+ Or you can use this URL: + ${verificationLink} +
If you did not create an account with DAWSON, please contact support at dawson.support@ustaxcourt.gov.
diff --git a/web-api/src/business/useCases/auth/forgotPasswordInteractor.ts b/web-api/src/business/useCases/auth/forgotPasswordInteractor.ts index b1bd3dfe5f4..8f0e1b94d67 100644 --- a/web-api/src/business/useCases/auth/forgotPasswordInteractor.ts +++ b/web-api/src/business/useCases/auth/forgotPasswordInteractor.ts @@ -71,11 +71,11 @@ export const forgotPasswordInteractor = async ( ${email} requested a password reset. Use the button below to reset your password. This will expire in 24 hours.
Or you can use this URL: - SOME URL GOES HERE + ${verificationLink}
If you did not request to reset your password, contact dawson.support@ustaxcourt.gov. diff --git a/web-client/src/presenter/sequences/Login/submitForgotPasswordSequence.ts b/web-client/src/presenter/sequences/Login/submitForgotPasswordSequence.ts index 847720a6952..a0afc8c8c3d 100644 --- a/web-client/src/presenter/sequences/Login/submitForgotPasswordSequence.ts +++ b/web-client/src/presenter/sequences/Login/submitForgotPasswordSequence.ts @@ -5,19 +5,22 @@ import { navigateToLoginAction } from '@web-client/presenter/actions/Login/navig import { setAlertSuccessAction } from '@web-client/presenter/actions/setAlertSuccessAction'; import { setAlertWarningAction } from '@web-client/presenter/actions/setAlertWarningAction'; import { setSaveAlertsForNavigationAction } from '@web-client/presenter/actions/setSaveAlertsForNavigationAction'; +import { showProgressSequenceDecorator } from '../../utilities/showProgressSequenceDecorator'; export const submitForgotPasswordSequence = [ - forgotPasswordAction, - { - success: [ - createForgotPasswordLinkAction, - setAlertSuccessAction, - clearAuthStateAction, - ], - unconfirmedAccount: [ - setAlertWarningAction, - setSaveAlertsForNavigationAction, - navigateToLoginAction, - ], - }, + showProgressSequenceDecorator([ + forgotPasswordAction, + { + success: [ + createForgotPasswordLinkAction, + setAlertSuccessAction, + clearAuthStateAction, + ], + unconfirmedAccount: [ + setAlertWarningAction, + setSaveAlertsForNavigationAction, + navigateToLoginAction, + ], + }, + ]), ] as unknown as () => {}; diff --git a/web-client/src/presenter/sequences/Public/goToCreatePetitionerAccountSequence.ts b/web-client/src/presenter/sequences/Public/goToCreatePetitionerAccountSequence.ts index e2ce6c99ca3..49867dd4180 100644 --- a/web-client/src/presenter/sequences/Public/goToCreatePetitionerAccountSequence.ts +++ b/web-client/src/presenter/sequences/Public/goToCreatePetitionerAccountSequence.ts @@ -1,9 +1,9 @@ -import { clearErrorAlertsAction } from '@web-client/presenter/actions/clearErrorAlertsAction'; +import { clearAlertsAction } from '@web-client/presenter/actions/clearAlertsAction'; import { clearFormAction } from '@web-client/presenter/actions/clearFormAction'; import { setupCurrentPageAction } from '../../actions/setupCurrentPageAction'; export const goToCreatePetitionerAccountSequence = [ clearFormAction, - clearErrorAlertsAction, + clearAlertsAction, setupCurrentPageAction('CreatePetitionerAccount'), ] as unknown as () => void; diff --git a/web-client/src/views/Login/Login.tsx b/web-client/src/views/Login/Login.tsx index a7941175c78..d57b1f0b946 100644 --- a/web-client/src/views/Login/Login.tsx +++ b/web-client/src/views/Login/Login.tsx @@ -62,7 +62,10 @@ export const Login = connect( }); }} /> -