From f3dd501a06f72d5635ce5382bf5c513102c8f2d9 Mon Sep 17 00:00:00 2001 From: Valerie Pomerleau Date: Mon, 23 Sep 2024 13:09:05 -0700 Subject: [PATCH] cleanup(many): Remove feature flags for reset password with code Because: * Reset password with code is now fully rolled out This commit: * Remove functional tests for reset password with link * Remove config check for resetPasswordWithCode flag in functional-tests * Remove content-server resetPasswordWithCode feature flag/env * Remove auth-server passwordForgotOtp.enabled config Closes #FXA-9728, FXA-10387 --- .../key-stretching-v2/recoveryKey.spec.ts | 6 - .../recoveryKeyWithLink.spec.ts | 147 ---------- .../key-stretching-v2/resetPassword.spec.ts | 14 +- .../resetPasswordWithLink.spec.ts | 136 --------- .../oauthResetPassword.spec.ts | 14 +- .../oauthResetPasswordRecoveryKey.spec.ts | 14 +- .../oauthResetPasswordScopeKeys.spec.ts | 14 +- .../oauthResetPasswordSyncMobile.spec.ts | 16 +- .../resetPassword.spec.ts | 10 +- .../resetPasswordRecoveryKey.spec.ts | 17 +- .../oauthResetPassword.spec.ts | 276 ------------------ .../oauthResetPasswordRecoveryKey.spec.ts | 99 ------- .../oauthResetPasswordScopeKeys.spec.ts | 88 ------ .../oauthResetPasswordSyncMobile.spec.ts | 89 ------ .../resetPassword.spec.ts | 216 -------------- .../resetPasswordRecoveryKey.spec.ts | 147 ---------- .../syncV3ResetPassword.spec.ts | 47 --- .../syncV3ResetPassword.spec.ts | 10 +- packages/fxa-auth-server/config/dev.json | 3 - packages/fxa-auth-server/config/index.ts | 6 - .../fxa-auth-server/lib/routes/password.ts | 15 +- .../test/local/routes/password.js | 71 +---- .../server/config/local.json-dist | 1 - .../server/lib/beta-settings.js | 1 - .../server/lib/configuration.js | 6 - .../server/lib/routes/get-index.js | 4 - 26 files changed, 26 insertions(+), 1441 deletions(-) delete mode 100644 packages/functional-tests/tests/key-stretching-v2/recoveryKeyWithLink.spec.ts delete mode 100644 packages/functional-tests/tests/key-stretching-v2/resetPasswordWithLink.spec.ts rename packages/functional-tests/tests/resetPassword/{resetPasswordWithCode => }/oauthResetPassword.spec.ts (93%) rename packages/functional-tests/tests/resetPassword/{resetPasswordWithCode => }/oauthResetPasswordRecoveryKey.spec.ts (83%) rename packages/functional-tests/tests/resetPassword/{resetPasswordWithCode => }/oauthResetPasswordScopeKeys.spec.ts (79%) rename packages/functional-tests/tests/resetPassword/{resetPasswordWithCode => }/oauthResetPasswordSyncMobile.spec.ts (80%) rename packages/functional-tests/tests/resetPassword/{resetPasswordWithCode => }/resetPassword.spec.ts (93%) rename packages/functional-tests/tests/resetPassword/{resetPasswordWithCode => }/resetPasswordRecoveryKey.spec.ts (89%) delete mode 100644 packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPassword.spec.ts delete mode 100644 packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordRecoveryKey.spec.ts delete mode 100644 packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordScopeKeys.spec.ts delete mode 100644 packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordSyncMobile.spec.ts delete mode 100644 packages/functional-tests/tests/resetPassword/resetPasswordWithLink/resetPassword.spec.ts delete mode 100644 packages/functional-tests/tests/resetPassword/resetPasswordWithLink/resetPasswordRecoveryKey.spec.ts delete mode 100644 packages/functional-tests/tests/resetPassword/resetPasswordWithLink/syncV3ResetPassword.spec.ts rename packages/functional-tests/tests/resetPassword/{resetPasswordWithCode => }/syncV3ResetPassword.spec.ts (81%) diff --git a/packages/functional-tests/tests/key-stretching-v2/recoveryKey.spec.ts b/packages/functional-tests/tests/key-stretching-v2/recoveryKey.spec.ts index c9e1df4e696..8f6e3006152 100644 --- a/packages/functional-tests/tests/key-stretching-v2/recoveryKey.spec.ts +++ b/packages/functional-tests/tests/key-stretching-v2/recoveryKey.spec.ts @@ -59,7 +59,6 @@ test.describe('severity-2 #smoke', () => { page, target, pages: { - configPage, signin, signup, settings, @@ -69,11 +68,6 @@ test.describe('severity-2 #smoke', () => { }, testAccountTracker, }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode !== true, - 'TODO in FXA-9728, remove this config check' - ); const { email, password } = testAccountTracker.generateAccountDetails(); await page.goto( `${target.contentServerUrl}/?forceExperiment=generalizedReactApp&forceExperimentGroup=react&${signupVersion.query}` diff --git a/packages/functional-tests/tests/key-stretching-v2/recoveryKeyWithLink.spec.ts b/packages/functional-tests/tests/key-stretching-v2/recoveryKeyWithLink.spec.ts deleted file mode 100644 index 06617de757b..00000000000 --- a/packages/functional-tests/tests/key-stretching-v2/recoveryKeyWithLink.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { expect, test } from '../../lib/fixtures/standard'; -import { BaseTarget } from '../../lib/targets/base'; - -const AGE_21 = '21'; -const HINT = 'secret key location'; - -// This test file is copied from recoveryKey.spec.ts -// this copy includes the previous version of the reset password flow (reset with link) -// Git history is preserved in the original that we will keep moving forward -// TODO in FXA-9728: remove this file when the reset password with code flow is fully rolled out in production - -/** - * These tests represent various permutations between interacting with V1 and V2 - * key stretched passwords. We need to ensure that operations are interchangeable! - */ -test.describe('severity-2 #smoke', () => { - // Helpers - async function _getKeys( - version: 1 | 2, - target: BaseTarget, - email: string, - password: string - ) { - const client = target.createAuthClient(version); - const response = await client.signIn(email, password, { keys: true }); - - expect(response.keyFetchToken).toBeDefined(); - expect(response.keyFetchToken).toBeDefined(); - - const keys = client.accountKeys( - response.keyFetchToken as string, - response.unwrapBKey as string - ); - return keys; - } - - type Version = { version: 1 | 2; query: string }; - type TestCase = { - signupVersion: Version; - resetVersion: Version; - signinVersion: Version; - }; - const v1: Version = { version: 1, query: '' }; - const v2: Version = { version: 2, query: 'stretch=2' }; - const TestCases: TestCase[] = [ - { signupVersion: v1, resetVersion: v1, signinVersion: v1 }, - { signupVersion: v1, resetVersion: v1, signinVersion: v2 }, - { signupVersion: v1, resetVersion: v2, signinVersion: v1 }, - { signupVersion: v1, resetVersion: v2, signinVersion: v2 }, - { signupVersion: v2, resetVersion: v1, signinVersion: v1 }, - { signupVersion: v2, resetVersion: v1, signinVersion: v2 }, - { signupVersion: v2, resetVersion: v2, signinVersion: v1 }, - { signupVersion: v2, resetVersion: v2, signinVersion: v2 }, - ]; - - for (const { signupVersion, resetVersion, signinVersion } of TestCases) { - test(`signs up as v${signupVersion.version} resets password with recovery key as v${resetVersion.version} and signs in as v${signinVersion.version}`, async ({ - page, - target, - pages: { - configPage, - signin, - signup, - settings, - recoveryKey, - resetPassword, - confirmSignupCode, - }, - testAccountTracker, - }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode === true, - 'TODO in FXA-9728, remove this file' - ); - const { email, password } = testAccountTracker.generateAccountDetails(); - await page.goto( - `${target.contentServerUrl}/?forceExperiment=generalizedReactApp&forceExperimentGroup=react&${signupVersion.query}` - ); - await signup.fillOutEmailForm(email); - await signup.fillOutSignupForm(password, AGE_21); - await expect(page).toHaveURL(/confirm_signup_code/); - const code = await target.emailClient.getVerifyShortCode(email); - await confirmSignupCode.fillOutCodeForm(code); - - await expect(page).toHaveURL(/settings/); - - await settings.signOut(); - const keys = await _getKeys( - signupVersion.version, - target, - email, - password - ); - await page.goto( - `${target.contentServerUrl}/?forceExperiment=generalizedReactApp&forceExperimentGroup=react&${resetVersion.query}` - ); - await signin.fillOutEmailFirstForm(email); - await signin.fillOutPasswordForm(password); - - await expect(page).toHaveURL(/settings/); - - await settings.goto(`${resetVersion.version}`); - await settings.recoveryKey.createButton.click(); - const key = await recoveryKey.createRecoveryKey(password, HINT); - await settings.signOut(); - await page.goto( - `${target.contentServerUrl}/reset_password?${resetVersion.query}` - ); - await resetPassword.fillOutEmailForm(email); - const link = - (await target.emailClient.getRecoveryLink(email)) + - `&${resetVersion.query}`; - await page.goto(link); - await resetPassword.fillOutRecoveryKeyForm(key); - - await expect(page).toHaveURL( - new RegExp(`account_recovery_reset_password.*${resetVersion.query}`) - ); - - await resetPassword.fillOutNewPasswordForm(password); - - await expect(page).toHaveURL(/reset_password_with_recovery_key_verified/); - - await settings.goto(); - await settings.signOut(); - await page.goto( - `${target.contentServerUrl}/?forceExperiment=generalizedReactApp&forceExperimentGroup=react&${signinVersion.query}` - ); - await signin.fillOutEmailFirstForm(email); - await signin.fillOutPasswordForm(password); - - await expect(page).toHaveURL(/settings/); - const keys2 = await _getKeys( - signinVersion.version, - target, - email, - password - ); - expect(keys2.kB).toEqual(keys.kB); - }); - } -}); diff --git a/packages/functional-tests/tests/key-stretching-v2/resetPassword.spec.ts b/packages/functional-tests/tests/key-stretching-v2/resetPassword.spec.ts index fc3e6349dd2..4bd69ffe31f 100644 --- a/packages/functional-tests/tests/key-stretching-v2/resetPassword.spec.ts +++ b/packages/functional-tests/tests/key-stretching-v2/resetPassword.spec.ts @@ -57,21 +57,9 @@ test.describe('severity-2 #smoke', () => { test(`signs up as v${signupVersion.version} resets password as v${resetVersion.version} and signs in as v${signinVersion.version}`, async ({ page, target, - pages: { - configPage, - signin, - signup, - settings, - resetPassword, - confirmSignupCode, - }, + pages: { signin, signup, settings, resetPassword, confirmSignupCode }, testAccountTracker, }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode !== true, - 'TODO in FXA-9728, remove this config check' - ); const { email, password } = testAccountTracker.generateAccountDetails(); await page.goto( `${target.contentServerUrl}/?forceExperiment=generalizedReactApp&forceExperimentGroup=react&${signupVersion.query}` diff --git a/packages/functional-tests/tests/key-stretching-v2/resetPasswordWithLink.spec.ts b/packages/functional-tests/tests/key-stretching-v2/resetPasswordWithLink.spec.ts deleted file mode 100644 index bec3b3aa736..00000000000 --- a/packages/functional-tests/tests/key-stretching-v2/resetPasswordWithLink.spec.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { expect, test } from '../../lib/fixtures/standard'; -import { BaseTarget } from '../../lib/targets/base'; - -const AGE_21 = '21'; - -// This test file is copied from resetPassword.spec.ts -// this copy includes the previous version of the reset password flow (reset with link) -// Git history is preserved in the original that we will keep moving forward -// TODO in FXA-9728: remove this file when the reset password with code flow is fully rolled out in production - -/** - * These tests represent various permutations between interacting with V1 and V2 - * key stretched passwords. We need to ensure that operations are interchangeable! - */ -test.describe('severity-2 #smoke', () => { - // Helpers - async function _getKeys( - version: 1 | 2, - target: BaseTarget, - email: string, - password: string - ) { - const client = target.createAuthClient(version); - const response = await client.signIn(email, password, { keys: true }); - - expect(response.keyFetchToken).toBeDefined(); - expect(response.unwrapBKey).toBeDefined(); - - const keys = client.accountKeys( - response.keyFetchToken as string, - response.unwrapBKey as string - ); - return keys; - } - - type Version = { version: 1 | 2; query: string }; - type TestCase = { - signupVersion: Version; - resetVersion: Version; - signinVersion: Version; - }; - const v1: Version = { version: 1, query: '' }; - const v2: Version = { version: 2, query: 'stretch=2' }; - const TestCases: TestCase[] = [ - { signupVersion: v1, resetVersion: v1, signinVersion: v1 }, - { signupVersion: v1, resetVersion: v1, signinVersion: v2 }, - { signupVersion: v1, resetVersion: v2, signinVersion: v1 }, - { signupVersion: v1, resetVersion: v2, signinVersion: v2 }, - { signupVersion: v2, resetVersion: v1, signinVersion: v1 }, - { signupVersion: v2, resetVersion: v1, signinVersion: v2 }, - { signupVersion: v2, resetVersion: v2, signinVersion: v1 }, - { signupVersion: v2, resetVersion: v2, signinVersion: v2 }, - ]; - - for (const { signupVersion, resetVersion, signinVersion } of TestCases) { - test(`signs up as v${signupVersion.version} resets password as v${resetVersion.version} and signs in as v${signinVersion.version}`, async ({ - page, - target, - pages: { - configPage, - signin, - signup, - settings, - resetPassword, - confirmSignupCode, - }, - testAccountTracker, - }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode === true, - 'TODO in FXA-9728 - remove this file' - ); - const { email, password } = testAccountTracker.generateAccountDetails(); - await page.goto( - `${target.contentServerUrl}/?forceExperiment=generalizedReactApp&forceExperimentGroup=react&${signupVersion.query}` - ); - await signup.fillOutEmailForm(email); - await signup.fillOutSignupForm(password, AGE_21); - await expect(page).toHaveURL(/confirm_signup_code/); - const code = await target.emailClient.getVerifyShortCode(email); - await confirmSignupCode.fillOutCodeForm(code); - - await expect(page).toHaveURL(/settings/); - - await settings.signOut(); - const keys = await _getKeys( - signupVersion.version, - target, - email, - password - ); - await page.goto( - `${target.contentServerUrl}/?forceExperiment=generalizedReactApp&forceExperimentGroup=react&${resetVersion.query}` - ); - await signin.fillOutEmailFirstForm(email); - await signin.fillOutPasswordForm(password); - - await expect(page).toHaveURL(/settings/); - - await settings.signOut(); - await page.goto( - `${target.contentServerUrl}/reset_password?${resetVersion.query}` - ); - await resetPassword.fillOutEmailForm(email); - const link = - (await target.emailClient.getRecoveryLink(email)) + - `&${resetVersion.version}`; - await page.goto(link); - await resetPassword.fillOutNewPasswordForm(password); - - await expect(page).toHaveURL(/reset_password_verified/); - - await settings.goto(); - await settings.signOut(); - await page.goto( - `${target.contentServerUrl}/?forceExperiment=generalizedReactApp&forceExperimentGroup=react&${signinVersion.query}` - ); - await signin.fillOutEmailFirstForm(email); - await signin.fillOutPasswordForm(password); - - await expect(page).toHaveURL(/settings/); - const keys2 = await _getKeys( - signinVersion.version, - target, - email, - password - ); - expect(keys2.kB).not.toEqual(keys.kB); - }); - } -}); diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPassword.spec.ts b/packages/functional-tests/tests/resetPassword/oauthResetPassword.spec.ts similarity index 93% rename from packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPassword.spec.ts rename to packages/functional-tests/tests/resetPassword/oauthResetPassword.spec.ts index 74682ca5fcd..70c87bdff66 100644 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPassword.spec.ts +++ b/packages/functional-tests/tests/resetPassword/oauthResetPassword.spec.ts @@ -3,20 +3,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { getCode } from 'fxa-settings/src/lib/totp'; -import { expect, test } from '../../../lib/fixtures/standard'; -import { ResetPasswordPage } from '../../../pages/resetPassword'; -import { SigninPage } from '../../../pages/signin'; +import { expect, test } from '../../lib/fixtures/standard'; +import { ResetPasswordPage } from '../../pages/resetPassword'; +import { SigninPage } from '../../pages/signin'; test.describe('severity-1 #smoke', () => { test.describe('oauth reset password', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode !== true, - 'see FXA-9728, remove conditional skip when feature flag removed' - ); - }); - test('reset password', async ({ target, page, diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPasswordRecoveryKey.spec.ts b/packages/functional-tests/tests/resetPassword/oauthResetPasswordRecoveryKey.spec.ts similarity index 83% rename from packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPasswordRecoveryKey.spec.ts rename to packages/functional-tests/tests/resetPassword/oauthResetPasswordRecoveryKey.spec.ts index 50449bf550c..7b4cfaec3e2 100644 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPasswordRecoveryKey.spec.ts +++ b/packages/functional-tests/tests/resetPassword/oauthResetPasswordRecoveryKey.spec.ts @@ -2,20 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { expect, test } from '../../../lib/fixtures/standard'; -import { ResetPasswordPage } from '../../../pages/resetPassword'; -import { SigninPage } from '../../../pages/signin'; +import { expect, test } from '../../lib/fixtures/standard'; +import { ResetPasswordPage } from '../../pages/resetPassword'; +import { SigninPage } from '../../pages/signin'; test.describe('severity-1 #smoke', () => { test.describe('oauth reset password with recovery key', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode !== true, - 'see FXA-9728, remove conditional skip when feature flag removed' - ); - }); - test('reset password with account recovery key', async ({ target, pages: { page, recoveryKey, relier, resetPassword, settings, signin }, diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPasswordScopeKeys.spec.ts b/packages/functional-tests/tests/resetPassword/oauthResetPasswordScopeKeys.spec.ts similarity index 79% rename from packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPasswordScopeKeys.spec.ts rename to packages/functional-tests/tests/resetPassword/oauthResetPasswordScopeKeys.spec.ts index c8f2d42da1a..c6377077044 100644 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPasswordScopeKeys.spec.ts +++ b/packages/functional-tests/tests/resetPassword/oauthResetPasswordScopeKeys.spec.ts @@ -2,20 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { expect, test } from '../../../lib/fixtures/standard'; -import { ResetPasswordPage } from '../../../pages/resetPassword'; -import { SigninPage } from '../../../pages/signin'; +import { expect, test } from '../../lib/fixtures/standard'; +import { ResetPasswordPage } from '../../pages/resetPassword'; +import { SigninPage } from '../../pages/signin'; test.describe('severity-1 #smoke', () => { test.describe('oauth reset password scoped keys react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode !== true, - 'see FXA-9728, remove conditional skip when feature flag removed' - ); - }); - test('reset password scoped keys', async ({ target, page, diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPasswordSyncMobile.spec.ts b/packages/functional-tests/tests/resetPassword/oauthResetPasswordSyncMobile.spec.ts similarity index 80% rename from packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPasswordSyncMobile.spec.ts rename to packages/functional-tests/tests/resetPassword/oauthResetPasswordSyncMobile.spec.ts index b361365b151..43a8d45aa86 100644 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/oauthResetPasswordSyncMobile.spec.ts +++ b/packages/functional-tests/tests/resetPassword/oauthResetPasswordSyncMobile.spec.ts @@ -2,21 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { expect, test } from '../../../lib/fixtures/standard'; -import { syncMobileOAuthQueryParams } from '../../../lib/query-params'; -import { ResetPasswordPage } from '../../../pages/resetPassword'; -import { SigninPage } from '../../../pages/signin'; +import { expect, test } from '../../lib/fixtures/standard'; +import { syncMobileOAuthQueryParams } from '../../lib/query-params'; +import { ResetPasswordPage } from '../../pages/resetPassword'; +import { SigninPage } from '../../pages/signin'; test.describe('severity-1 #smoke', () => { test.describe('oauth reset password Sync mobile react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode !== true, - 'see FXA-9728, remove conditional skip when feature flag removed' - ); - }); - test('reset password through Sync mobile', async ({ target, syncBrowserPages: { page, connectAnotherDevice, resetPassword, signin }, diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/resetPassword.spec.ts b/packages/functional-tests/tests/resetPassword/resetPassword.spec.ts similarity index 93% rename from packages/functional-tests/tests/resetPassword/resetPasswordWithCode/resetPassword.spec.ts rename to packages/functional-tests/tests/resetPassword/resetPassword.spec.ts index bfe39fecbbf..86ee44a7f44 100644 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/resetPassword.spec.ts +++ b/packages/functional-tests/tests/resetPassword/resetPassword.spec.ts @@ -2,17 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { expect, test } from '../../../lib/fixtures/standard'; +import { expect, test } from '../../lib/fixtures/standard'; test.describe('severity-1 #smoke', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode !== true, - 'see FXA-9728, remove conditional skip when feature flag removed' - ); - }); - test('can reset password', async ({ page, target, diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/resetPasswordRecoveryKey.spec.ts b/packages/functional-tests/tests/resetPassword/resetPasswordRecoveryKey.spec.ts similarity index 89% rename from packages/functional-tests/tests/resetPassword/resetPasswordWithCode/resetPasswordRecoveryKey.spec.ts rename to packages/functional-tests/tests/resetPassword/resetPasswordRecoveryKey.spec.ts index b0a7a6b08fd..fa8392d57fd 100644 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/resetPasswordRecoveryKey.spec.ts +++ b/packages/functional-tests/tests/resetPassword/resetPasswordRecoveryKey.spec.ts @@ -2,22 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { expect, test } from '../../../lib/fixtures/standard'; -import { SettingsPage } from '../../../pages/settings'; -import { RecoveryKeyPage } from '../../../pages/settings/recoveryKey'; -import { SigninPage } from '../../../pages/signin'; +import { expect, test } from '../../lib/fixtures/standard'; +import { SettingsPage } from '../../pages/settings'; +import { RecoveryKeyPage } from '../../pages/settings/recoveryKey'; +import { SigninPage } from '../../pages/signin'; test.describe('severity-1 #smoke', () => { test.describe('recovery key react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - // Ensure that the react reset password route feature flag is enabled - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode !== true, - 'see FXA-9728, remove conditional skip when feature flag removed' - ); - }); - test('can reset password with recovery key', async ({ target, page, diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPassword.spec.ts b/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPassword.spec.ts deleted file mode 100644 index 19cc2800f04..00000000000 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPassword.spec.ts +++ /dev/null @@ -1,276 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { Page, expect, test } from '../../../lib/fixtures/standard'; -import { syncMobileOAuthQueryParams } from '../../../lib/query-params'; -import { ResetPasswordPage } from '../../../pages/resetPassword'; -import { SigninPage } from '../../../pages/signin'; - -const SERVICE_NAME_123 = '123'; -const SERVICE_NAME_FIREFOX = 'Firefox'; - -test.describe('severity-1 #smoke', () => { - test.describe('oauth reset password react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode === true, - 'see FXA-9728, remove these tests' - ); - }); - - test('reset password', async ({ - target, - page, - pages: { signin, relier, resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - // Make sure user is not signed in, and goes to the relier (ie 123done) - await relier.goto(); - - await relier.clickEmailFirst(); - - await beginPasswordReset( - page, - signin, - resetPassword, - credentials.email, - SERVICE_NAME_123 - ); - - await resetPassword.fillOutEmailForm(credentials.email); - const link = await target.emailClient.getRecoveryLink(credentials.email); - await page.goto(link); - await resetPassword.fillOutNewPasswordForm(newPassword); - credentials.password = newPassword; - - // Note: We used to redirect the user back to the relier in some cases - // but we've decided to just show the success message for now - // and let the user re-authenticate with the relier. - await expect(page).toHaveURL(/reset_password_verified/); - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - - await page.reload(); - await expect( - page.getByText(new RegExp(`.*${SERVICE_NAME_123}.*`, 'i')) - ).toBeVisible(); - }); - - test('reset password through Sync mobile', async ({ - target, - syncBrowserPages: { page, signin, resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - await page.goto( - `${ - target.contentServerUrl - }/authorization/?${syncMobileOAuthQueryParams.toString()}` - ); - - await beginPasswordReset( - page, - signin, - resetPassword, - credentials.email, - SERVICE_NAME_FIREFOX - ); - - await resetPassword.fillOutEmailForm(credentials.email); - const link = await target.emailClient.getRecoveryLink(credentials.email); - await page.goto(link); - await resetPassword.fillOutNewPasswordForm(newPassword); - credentials.password = newPassword; - - // Note: We used to redirect the user back to the relier in some cases - // but we've decided to just show the success message for now - // and let the user re-authenticate with the relier. - await expect(page).toHaveURL(/reset_password_verified/); - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - - await expect( - page.getByText(new RegExp(`.*${SERVICE_NAME_FIREFOX}.*`, 'i')) - ).toBeVisible(); - }); - - test('reset password different tab', async ({ - target, - page, - pages: { signin, relier, resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - // Make sure user is not signed in, and goes to the relier (ie 123done) - await relier.goto(); - - await relier.clickEmailFirst(); - - await beginPasswordReset( - page, - signin, - resetPassword, - credentials.email, - SERVICE_NAME_123 - ); - - await resetPassword.fillOutEmailForm(credentials.email); - const link = await target.emailClient.getRecoveryLink(credentials.email); - // Clearing session state simulates a 'new' tab, and changes the navigation at the end of the flow. - await page.evaluate(() => window.sessionStorage.clear()); - - await page.goto(link); - await resetPassword.fillOutNewPasswordForm(newPassword); - credentials.password = newPassword; - - // Note: We used to redirect the user back to the relier in some cases - // but we've decided to just show the success message for now - // and let the user re-authenticate with the relier. - await expect(page).toHaveURL(/reset_password_verified/); - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - - await page.reload(); - await expect( - page.getByText(new RegExp(`.*${SERVICE_NAME_123}.*`, 'i')) - ).toBeVisible(); - }); - - test('reset password with PKCE different tab', async ({ - target, - page, - pages: { signin, resetPassword }, - testAccountTracker, - }) => { - test.fixme(true, 'Fix required as of 2023/07/18 (see FXA-8006).'); - // the PKCE button is broken at the moment, so for now navigate directly to the link. - // PKCE button doesn't appear to work at the moment locally. Some sort of cors error - // keeps getting in the way. Just go to link directly for now. - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - await page.goto( - `http://localhost:3030/authorization?` + - `&access_type=offline` + - `&client_id=${target.relierClientID}` + - `&pkce_client_id=38a6b9b3a65a1871` + - `&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fapi%2Foauth` + - `&scope=profile%20openid` + - `&action=signin` + - `&state=12eeaba43cc7548bf1f6b478b9de95328855b46df1e754fe94b21036c41c9cba` - ); - - await beginPasswordReset( - page, - signin, - resetPassword, - credentials.email, - SERVICE_NAME_123 - ); - - await resetPassword.fillOutEmailForm(credentials.email); - const link = await target.emailClient.getRecoveryLink(credentials.email); - // Clearing session state simulates a 'new' tab, and changes the navigation at the end of the flow. - await page.evaluate(() => window.sessionStorage.clear()); - - await page.goto(link, { waitUntil: 'load' }); - await resetPassword.fillOutNewPasswordForm(newPassword); - credentials.password = newPassword; - - // Note: We used to redirect the user back to the relier in some cases - // but we've decided to just show the success message for now - // and let the user re-authenticate with the relier. - await expect(page).toHaveURL(/reset_password_verified/); - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - await expect( - page.getByText(new RegExp(`.*${SERVICE_NAME_123}.*`, 'i')) - ).toBeVisible(); - }); - - test('reset password with valid totp', async ({ - target, - pages: { page, signin, resetPassword, relier, totp, settings }, - testAccountTracker, - }) => { - test.fixme(true, 'Fix required as of 2024/04/25 FXA-9513'); - - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - await signin.goto(); - await signin.fillOutEmailFirstForm(credentials.email); - await signin.fillOutPasswordForm(credentials.password); - // Goes to settings and enables totp on user's account. - await settings.totp.addButton.click(); - await totp.fillOutTotpForms(); - await expect(settings.totp.status).toHaveText('Enabled'); - await settings.signOut(); - - // Makes sure user is not signed in, and goes to the relier (ie 123done) - await relier.goto(); - await relier.clickEmailFirst(); - - await beginPasswordReset( - page, - signin, - resetPassword, - credentials.email, - SERVICE_NAME_123 - ); - - await resetPassword.fillOutEmailForm(credentials.email); - const link = await target.emailClient.getRecoveryLink(credentials.email); - await page.goto(link, { waitUntil: 'load' }); - await resetPassword.fillOutNewPasswordForm(newPassword); - credentials.password = newPassword; - - // Note: We used to redirect the user back to the relier in some cases - // but we've decided to just show the success message for now - // and let the user re-authenticate with the relier. - await expect(page).toHaveURL(/reset_password_verified/); - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - await expect( - page.getByText(new RegExp(`.*${SERVICE_NAME_123}.*`, 'i')) - ).toBeVisible(); - }); - }); - - async function beginPasswordReset( - page: Page, - signin: SigninPage, - resetPassword: ResetPasswordPage, - email: string, - serviceName: string - ): Promise { - await signin.fillOutEmailFirstForm(email); - await signin.forgotPasswordLink.click(); - - // Verify reset password header - // The service name can change based on environments and all of our test RPs from 123done have - // service names that begin with '123'. This test just ensures that the OAuth service name is rendered, - // it's OK that it does not exactly match. - // If the 'relier' page isn't passed, it's a Sync test, and 'serviceName' will display as "Firefox Sync" - // due to a `scope` param check (see `getServiceName` method on the OAuth integration). When resetting - // through a link, we do not pass the `scope` param, and the service name is not altered. This means for - // the iOS client_id, the name displays as "Firefox for iOS" on the "verified" page and also means - // for now we can check for if the string contains "Firefox", but when we switch to codes, we can determine - // if we want to and always display "Firefox Sync" on both pages. - await expect(resetPassword.resetPasswordHeading).toContainText(serviceName); - } -}); diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordRecoveryKey.spec.ts b/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordRecoveryKey.spec.ts deleted file mode 100644 index f7cb72f20f6..00000000000 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordRecoveryKey.spec.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { Page, expect, test } from '../../../lib/fixtures/standard'; -import { ResetPasswordPage } from '../../../pages/resetPassword'; -import { SigninPage } from '../../../pages/signin'; - -const SERVICE_NAME_123 = '123'; - -test.describe('severity-1 #smoke', () => { - test.describe('oauth reset password with recovery key react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode === true, - 'see FXA-9728, remove these tests' - ); - }); - - test('reset password with account recovery key', async ({ - target, - pages: { page, signin, resetPassword, relier, settings, recoveryKey }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - await signin.goto(); - await signin.fillOutEmailFirstForm(credentials.email); - await signin.fillOutPasswordForm(credentials.password); - - // Goes to settings and enables the account recovery key on user's account. - await settings.recoveryKey.createButton.click(); - const accountRecoveryKey = await recoveryKey.createRecoveryKey( - credentials.password, - 'hint' - ); - await settings.signOut(); - - // Make sure user is not signed in, and goes to the relier (ie 123done) - await relier.goto(); - - await relier.clickEmailFirst(); - - await beginPasswordReset( - page, - signin, - resetPassword, - credentials.email, - SERVICE_NAME_123 - ); - - await resetPassword.fillOutEmailForm(credentials.email); - const link = await target.emailClient.getRecoveryLink(credentials.email); - await page.goto(link, { waitUntil: 'load' }); - await resetPassword.fillOutRecoveryKeyForm(accountRecoveryKey); - await resetPassword.fillOutNewPasswordForm(newPassword); - credentials.password = newPassword; - - // Note: We used to redirect the user back to the relier in some cases - // but we've decided to just show the success message for now - // and let the user re-authenticate with the relier. - - await expect(page).toHaveURL(/reset_password_with_recovery_key_verified/); - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - await expect( - page.getByText(new RegExp(`.*${SERVICE_NAME_123}.*`, 'i')) - ).toBeVisible(); - }); - }); - - async function beginPasswordReset( - page: Page, - signin: SigninPage, - resetPassword: ResetPasswordPage, - email: string, - serviceName: string - ): Promise { - // TODO: FXA-9015 Update once we port signin / signup. - // param is set, this view is still using backbone. - await signin.fillOutEmailFirstForm(email); - await signin.forgotPasswordLink.click(); - - // Verify reset password header - // The service name can change based on environments and all of our test RPs from 123done have - // service names that begin with '123'. This test just ensures that the OAuth service name is rendered, - // it's OK that it does not exactly match. - // If the 'relier' page isn't passed, it's a Sync test, and 'serviceName' will display as "Firefox Sync" - // due to a `scope` param check (see `getServiceName` method on the OAuth integration). When resetting - // through a link, we do not pass the `scope` param, and the service name is not altered. This means for - // the iOS client_id, the name displays as "Firefox for iOS" on the "verified" page and also means - // for now we can check for if the string contains "Firefox", but when we switch to codes, we can determine - // if we want to and always display "Firefox Sync" on both pages. - await expect(resetPassword.resetPasswordHeading).toContainText(serviceName); - } -}); diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordScopeKeys.spec.ts b/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordScopeKeys.spec.ts deleted file mode 100644 index 18d6e0e3dc7..00000000000 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordScopeKeys.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { Page, expect, test } from '../../../lib/fixtures/standard'; -import { ResetPasswordPage } from '../../../pages/resetPassword'; -import { SigninPage } from '../../../pages/signin'; - -const SERVICE_NAME_123 = '123'; - -test.describe('severity-1 #smoke', () => { - test.describe('oauth reset password scoped keys react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode === true, - 'see FXA-9728, remove these tests' - ); - }); - - test('reset password scoped keys', async ({ - target, - page, - pages: { signin, relier, resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - // Make sure user is not signed in, and goes to the relier (ie 123done) - await relier.goto(); - - await relier.clickSignInScopedKeys(); - - await beginPasswordReset( - page, - signin, - resetPassword, - credentials.email, - SERVICE_NAME_123 - ); - - await resetPassword.fillOutEmailForm(credentials.email); - const link = await target.emailClient.getRecoveryLink(credentials.email); - await page.goto(link); - await resetPassword.fillOutNewPasswordForm(newPassword); - credentials.password = newPassword; - - // Note: We used to redirect the user back to the relier in some cases - // but we've decided to just show the success message for now - // and let the user re-authenticate with the relier. - await expect(page).toHaveURL(/reset_password_verified/); - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - - await page.reload(); - await expect( - page.getByText(new RegExp(`.*${SERVICE_NAME_123}.*`, 'i')) - ).toBeVisible(); - }); - }); - - async function beginPasswordReset( - page: Page, - signin: SigninPage, - resetPassword: ResetPasswordPage, - email: string, - serviceName: string - ): Promise { - // TODO: FXA-9015 Update once we port signin / signup. - // param is set, this view is still using backbone. - await signin.fillOutEmailFirstForm(email); - await signin.forgotPasswordLink.click(); - - // Verify reset password header - // The service name can change based on environments and all of our test RPs from 123done have - // service names that begin with '123'. This test just ensures that the OAuth service name is rendered, - // it's OK that it does not exactly match. - // If the 'relier' page isn't passed, it's a Sync test, and 'serviceName' will display as "Firefox Sync" - // due to a `scope` param check (see `getServiceName` method on the OAuth integration). When resetting - // through a link, we do not pass the `scope` param, and the service name is not altered. This means for - // the iOS client_id, the name displays as "Firefox for iOS" on the "verified" page and also means - // for now we can check for if the string contains "Firefox", but when we switch to codes, we can determine - // if we want to and always display "Firefox Sync" on both pages. - await expect(resetPassword.resetPasswordHeading).toContainText(serviceName); - } -}); diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordSyncMobile.spec.ts b/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordSyncMobile.spec.ts deleted file mode 100644 index 92b85495222..00000000000 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/oauthResetPasswordSyncMobile.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { Page, expect, test } from '../../../lib/fixtures/standard'; -import { syncMobileOAuthQueryParams } from '../../../lib/query-params'; -import { ResetPasswordPage } from '../../../pages/resetPassword'; -import { SigninPage } from '../../../pages/signin'; - -const SERVICE_NAME_FIREFOX = 'Firefox'; - -test.describe('severity-1 #smoke', () => { - test.describe('oauth reset password Sync mobile react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode === true, - 'see FXA-9728, remove these tests' - ); - }); - - test('reset password through Sync mobile', async ({ - target, - syncBrowserPages: { page, signin, resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - await page.goto( - `${ - target.contentServerUrl - }/authorization/?${syncMobileOAuthQueryParams.toString()}` - ); - - await beginPasswordReset( - page, - signin, - resetPassword, - credentials.email, - SERVICE_NAME_FIREFOX - ); - - await resetPassword.fillOutEmailForm(credentials.email); - const link = await target.emailClient.getRecoveryLink(credentials.email); - await page.goto(link); - await resetPassword.fillOutNewPasswordForm(newPassword); - credentials.password = newPassword; - - // Note: We used to redirect the user back to the relier in some cases - // but we've decided to just show the success message for now - // and let the user re-authenticate with the relier. - await expect(page).toHaveURL(/reset_password_verified/); - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - - await page.reload(); - await expect( - page.getByText(new RegExp(`.*${SERVICE_NAME_FIREFOX}.*`, 'i')) - ).toBeVisible(); - }); - }); - - async function beginPasswordReset( - page: Page, - signin: SigninPage, - resetPassword: ResetPasswordPage, - email: string, - serviceName: string - ): Promise { - // TODO: FXA-9015 Update once we port signin / signup. - // param is set, this view is still using backbone. - await signin.fillOutEmailFirstForm(email); - await signin.forgotPasswordLink.click(); - - // Verify reset password header - // The service name can change based on environments and all of our test RPs from 123done have - // service names that begin with '123'. This test just ensures that the OAuth service name is rendered, - // it's OK that it does not exactly match. - // If the 'relier' page isn't passed, it's a Sync test, and 'serviceName' will display as "Firefox Sync" - // due to a `scope` param check (see `getServiceName` method on the OAuth integration). When resetting - // through a link, we do not pass the `scope` param, and the service name is not altered. This means for - // the iOS client_id, the name displays as "Firefox for iOS" on the "verified" page and also means - // for now we can check for if the string contains "Firefox", but when we switch to codes, we can determine - // if we want to and always display "Firefox Sync" on both pages. - await expect(resetPassword.resetPasswordHeading).toContainText(serviceName); - } -}); diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/resetPassword.spec.ts b/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/resetPassword.spec.ts deleted file mode 100644 index 508f5ccb3c5..00000000000 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/resetPassword.spec.ts +++ /dev/null @@ -1,216 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { expect, test } from '../../../lib/fixtures/standard'; -import { ResetPasswordPage } from '../../../pages/resetPassword'; - -test.describe('severity-1 #smoke', () => { - test.describe('reset password react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode === true, - 'see FXA-9728, remove these tests' - ); - }); - - test('can reset password', async ({ - page, - target, - context, - pages: { signin, resetPassword, settings }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - await resetPassword.goto(); - - await resetPassword.fillOutEmailForm(credentials.email); - - // Verify confirm password reset page rendered - await expect(resetPassword.confirmResetPasswordHeading).toBeVisible(); - - const link = await target.emailClient.getRecoveryLink(credentials.email); - // Open link in a new window - const diffPage = await context.newPage(); - const diffResetPasswordReact = new ResetPasswordPage(diffPage, target); - await diffPage.goto(link); - - await expect( - diffResetPasswordReact.createNewPasswordHeading - ).toBeVisible(); - - // Create and submit new password - await diffResetPasswordReact.fillOutNewPasswordForm(newPassword); - - // Wait for new page to navigate - await diffPage.waitForURL(/reset_password_verified/); - // Verify password reset confirmation page is rendered - await expect( - diffResetPasswordReact.passwordResetConfirmationHeading - ).toBeVisible(); - await diffPage.close(); - - await page.goto(target.contentServerUrl); - - // Verify initial page redirected to sign in and sign in page rendered - await expect(signin.emailFirstHeading).toBeVisible(); - - await signin.fillOutEmailFirstForm(credentials.email); - - await expect(signin.passwordFormHeading).toBeVisible(); - - await signin.fillOutPasswordForm(newPassword); - // Cleanup requires setting this value to correct password - credentials.password = newPassword; - - await expect(settings.settingsHeading).toBeVisible(); - // Check that connected service name is not empty! - await expect(settings.connectedServiceName).toContainText('Firefox'); - }); - - test('forgot password', async ({ - target, - page, - pages: { resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - await resetPassword.goto(); - - await resetPassword.fillOutEmailForm(credentials.email); - const link = await target.emailClient.getRecoveryLink(credentials.email); - await page.goto(link); - await resetPassword.fillOutNewPasswordForm(credentials.password); - - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - }); - - const testCases = [ - { - name: 'short password', - error: 'At least 8 characters', - password: '2short', - }, - { - name: 'common password', - error: 'Not a commonly used password', - password: 'password', - }, - { name: 'email as password', error: 'Not your email' }, - ]; - for (const { name, error, password } of testCases) { - test(`cannot set an invalid password - ${name}`, async ({ - target, - context, - pages: { resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - // eslint-disable-next-line playwright/no-conditional-in-test - const passwordValue = password ?? credentials.email; - - await resetPassword.goto(); - - await resetPassword.fillOutEmailForm(credentials.email); - - // Verify confirm password reset page rendered - await expect(resetPassword.confirmResetPasswordHeading).toBeVisible(); - - const link = await target.emailClient.getRecoveryLink( - credentials.email - ); - // Open link in a new window - const diffPage = await context.newPage(); - const diffResetPasswordReact = new ResetPasswordPage(diffPage, target); - await diffPage.goto(link); - - await expect( - diffResetPasswordReact.createNewPasswordHeading - ).toBeVisible(); - - await diffResetPasswordReact.fillOutNewPasswordForm(passwordValue); - - await expect(diffPage.getByText(error)).toBeVisible(); - await expect(diffResetPasswordReact.resetPasswordButton).toBeDisabled(); - await expect(diffResetPasswordReact.newPasswordTextbox).toHaveClass( - 'error' - ); - }); - } - - test('visit confirmation screen without initiating reset_password, user is redirected to /reset_password', async ({ - page, - pages: { resetPassword }, - }) => { - await resetPassword.goto('/confirm_reset_password'); - - // Verify its redirected to react reset password page - await expect(page.locator('#root')).toBeEnabled(); - await expect(resetPassword.resetPasswordHeading).toBeVisible(); - }); - - test('open /reset_password page from /signin', async ({ - pages: { page, signin, resetPassword }, - target, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - await page.goto(target.contentServerUrl); - - await expect(signin.emailFirstHeading).toBeVisible(); - - await signin.fillOutEmailFirstForm(credentials.email); - - await signin.forgotPasswordLink.click(); - - await expect(resetPassword.resetPasswordHeading).toBeVisible(); - }); - - test('open confirm_reset_password page, click resend', async ({ - pages: { resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - await resetPassword.goto(); - - await resetPassword.fillOutEmailForm(credentials.email); - - await expect(resetPassword.confirmResetPasswordHeading).toBeVisible(); - - resetPassword.resendButton.click(); - - await expect(resetPassword.statusBar).toHaveText(/Email re-?sent/); - }); - - test('open /reset_password page, enter unknown email, wait for error', async ({ - pages: { resetPassword }, - }) => { - await resetPassword.goto(); - - await resetPassword.fillOutEmailForm('email@restmail.net'); - - await expect(resetPassword.statusBar).toHaveText('Unknown account'); - }); - - test('browse directly to page with email on query params', async ({ - pages: { resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - await resetPassword.goto(undefined, `email=${credentials.email}`); - - //The email shouldn't be pre-filled - const emailInput = await resetPassword.emailTextbox.inputValue(); - expect(emailInput).toEqual(''); - - await resetPassword.fillOutEmailForm(credentials.email); - - await expect(resetPassword.confirmResetPasswordHeading).toBeVisible(); - }); - }); -}); diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/resetPasswordRecoveryKey.spec.ts b/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/resetPasswordRecoveryKey.spec.ts deleted file mode 100644 index 82ac7fce7f9..00000000000 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/resetPasswordRecoveryKey.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { expect, test } from '../../../lib/fixtures/standard'; - -const HINT = 'secret key location'; - -test.describe('severity-1 #smoke', () => { - test.describe('recovery key react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - // Ensure that the react reset password route feature flag is enabled - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode === true, - 'see FXA-9728, remove these tests' - ); - }); - - test('can reset password with recovery key', async ({ - target, - page, - pages: { settings, recoveryKey, signin, resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - await signin.goto(); - await signin.fillOutEmailFirstForm(credentials.email); - await signin.fillOutPasswordForm(credentials.password); - - await expect(settings.settingsHeading).toBeVisible(); - await expect(settings.recoveryKey.status).toHaveText('Not Set'); - - await settings.recoveryKey.createButton.click(); - - const key = await recoveryKey.createRecoveryKey( - credentials.password, - HINT - ); - - // Verify status as 'enabled' - await expect(settings.settingsHeading).toBeVisible(); - await expect(settings.recoveryKey.status).toHaveText('Enabled'); - - // Ensure password reset occurs with no session token available - await signin.clearCache(); - - // Stash original encryption keys to be verified later - const accountData = await target.authClient.sessionReauth( - credentials.sessionToken, - credentials.email, - credentials.password, - { - keys: true, - reason: 'recovery_key', - } - ); - - expect(accountData.keyFetchToken).toBeDefined(); - expect(accountData.unwrapBKey).toBeDefined(); - - const originalEncryptionKeys = await target.authClient.accountKeys( - accountData.keyFetchToken as string, - accountData.unwrapBKey as string - ); - - await resetPassword.goto(); - - await resetPassword.fillOutEmailForm(credentials.email); - await expect(resetPassword.confirmResetPasswordHeading).toBeVisible(); - - const link = await target.emailClient.getRecoveryLink(credentials.email); - await page.goto(link); - await resetPassword.fillOutRecoveryKeyForm(key); - await resetPassword.fillOutNewPasswordForm(newPassword); - credentials.password = newPassword; - // After using a recovery key to reset password, expect to be prompted to create a new one - await resetPassword.generateRecoveryKeyButton.click(); - await page.waitForURL(/settings\/account_recovery/); - - // Attempt to login with new password - const { sessionToken } = await target.authClient.signIn( - credentials.email, - newPassword - ); - - const newAccountData = await target.authClient.sessionReauth( - sessionToken, - credentials.email, - newPassword, - { - keys: true, - reason: 'recovery_key', - } - ); - expect(newAccountData.keyFetchToken).toBeDefined(); - expect(newAccountData.unwrapBKey).toBeDefined(); - - const newEncryptionKeys = await target.authClient.accountKeys( - newAccountData.keyFetchToken as string, - newAccountData.unwrapBKey as string - ); - expect(originalEncryptionKeys).toEqual(newEncryptionKeys); - }); - - test('forgot password has account recovery key but skip using it', async ({ - target, - page, - pages: { settings, recoveryKey, resetPassword, signin }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - - await signin.goto(); - await signin.fillOutEmailFirstForm(credentials.email); - await signin.fillOutPasswordForm(credentials.password); - - await expect(settings.settingsHeading).toBeVisible(); - await expect(settings.recoveryKey.status).toHaveText('Not Set'); - - await settings.recoveryKey.createButton.click(); - await recoveryKey.createRecoveryKey(credentials.password, 'hint'); - - await expect(settings.settingsHeading).toBeVisible(); - await expect(settings.recoveryKey.status).toHaveText('Enabled'); - - await resetPassword.goto(); - - await resetPassword.fillOutEmailForm(credentials.email); - const link = await target.emailClient.getRecoveryLink(credentials.email); - await page.goto(link); - await resetPassword.forgotKeyLink.click(); - await resetPassword.fillOutNewPasswordForm(credentials.password); - - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - - await settings.goto(); - - await expect(settings.settingsHeading).toBeVisible(); - await expect(settings.recoveryKey.status).toHaveText('Not Set'); - }); - }); -}); diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/syncV3ResetPassword.spec.ts b/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/syncV3ResetPassword.spec.ts deleted file mode 100644 index 9723c54e94b..00000000000 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithLink/syncV3ResetPassword.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { expect, test } from '../../../lib/fixtures/standard'; - -test.describe('severity-1 #smoke', () => { - test.describe('Firefox Desktop Sync v3 reset password react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode === true, - 'see FXA-9728, remove these tests' - ); - }); - - test('reset pw for sync user', async ({ - target, - syncBrowserPages: { page, resetPassword }, - testAccountTracker, - }) => { - const credentials = await testAccountTracker.signUp(); - const newPassword = testAccountTracker.generatePassword(); - - await resetPassword.goto(undefined, 'context=fx_desktop_v3&service=sync'); - - // Check that the sync relier is in the heading - await expect(resetPassword.resetPasswordHeading).toHaveText( - /Firefox Sync/ - ); - - await resetPassword.fillOutEmailForm(credentials.email); - - const link = await target.emailClient.getRecoveryLink(credentials.email); - await page.goto(link); - - await resetPassword.fillOutNewPasswordForm(newPassword); - // Update credentials file so that account can be deleted as part of test cleanup - credentials.password = newPassword; - - await expect(page).toHaveURL(/reset_password_verified/); - await expect( - resetPassword.passwordResetConfirmationHeading - ).toBeVisible(); - }); - }); -}); diff --git a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/syncV3ResetPassword.spec.ts b/packages/functional-tests/tests/resetPassword/syncV3ResetPassword.spec.ts similarity index 81% rename from packages/functional-tests/tests/resetPassword/resetPasswordWithCode/syncV3ResetPassword.spec.ts rename to packages/functional-tests/tests/resetPassword/syncV3ResetPassword.spec.ts index f6c37ec99e7..68b2f391d41 100644 --- a/packages/functional-tests/tests/resetPassword/resetPasswordWithCode/syncV3ResetPassword.spec.ts +++ b/packages/functional-tests/tests/resetPassword/syncV3ResetPassword.spec.ts @@ -2,18 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { expect, test } from '../../../lib/fixtures/standard'; +import { expect, test } from '../../lib/fixtures/standard'; test.describe('severity-1 #smoke', () => { test.describe('Firefox Desktop Sync v3 reset password react', () => { - test.beforeEach(async ({ pages: { configPage } }) => { - const config = await configPage.getConfig(); - test.skip( - config.featureFlags.resetPasswordWithCode !== true, - 'see FXA-9728, remove conditional skip when feature flag removed' - ); - }); - test('reset pw for sync user', async ({ target, syncBrowserPages: { page, resetPassword }, diff --git a/packages/fxa-auth-server/config/dev.json b/packages/fxa-auth-server/config/dev.json index 103fb7b302c..3b62239ca40 100644 --- a/packages/fxa-auth-server/config/dev.json +++ b/packages/fxa-auth-server/config/dev.json @@ -467,8 +467,5 @@ "subscriptionAccountReminders": { "firstInterval": "5s", "secondInterval": "10s" - }, - "passwordForgotOtp": { - "enabled": true } } diff --git a/packages/fxa-auth-server/config/index.ts b/packages/fxa-auth-server/config/index.ts index 8e1eceeca02..efbb38bfbb1 100644 --- a/packages/fxa-auth-server/config/index.ts +++ b/packages/fxa-auth-server/config/index.ts @@ -1921,12 +1921,6 @@ const convictConf = convict({ }, }, passwordForgotOtp: { - enabled: { - doc: 'Feature flag for init password reset with emailed OTP', - format: Boolean, - default: false, - env: 'OTP_PASSWORD_FORGOT_ENABLED', - }, digits: { doc: 'Number of digits in token', default: 8, diff --git a/packages/fxa-auth-server/lib/routes/password.ts b/packages/fxa-auth-server/lib/routes/password.ts index 5e68fadfbed..a0904e599e4 100644 --- a/packages/fxa-auth-server/lib/routes/password.ts +++ b/packages/fxa-auth-server/lib/routes/password.ts @@ -59,9 +59,10 @@ module.exports = function ( statsd: StatsD ) { const otpUtils = require('../../lib/routes/utils/otp')(log, config, db); - const otpRedisAdapter = config.passwordForgotOtp.enabled - ? new OtpRedisAdapter(authServerCacheRedis, config.passwordForgotOtp.ttl) - : { set: async () => null, get: async () => null, del: async () => null }; + const otpRedisAdapter = new OtpRedisAdapter( + authServerCacheRedis, + config.passwordForgotOtp.ttl + ); const otpManager = new OtpManager( { kind: 'passwordForgot', digits: config.passwordForgotOtp.digits }, otpRedisAdapter @@ -575,10 +576,6 @@ module.exports = function ( }, }, handler: async function (request: AuthRequest) { - if (!config.passwordForgotOtp.enabled) { - throw error.featureNotEnabled(); - } - log.begin('Password.forgotOtp', request); await request.emitMetricsEvent('password.forgot.send_otp.start'); const payload = request.payload as { @@ -672,10 +669,6 @@ module.exports = function ( }, }, handler: async function (request: any) { - if (!config.passwordForgotOtp.enabled) { - throw error.featureNotEnabled(); - } - log.begin('Password.forgotOtpVerify', request); await request.emitMetricsEvent('password.forgot.verify_otp.start'); statsd.increment('otp.passwordForgot.attempt'); diff --git a/packages/fxa-auth-server/test/local/routes/password.js b/packages/fxa-auth-server/test/local/routes/password.js index 6824e1898e8..8cb7f94783b 100644 --- a/packages/fxa-auth-server/test/local/routes/password.js +++ b/packages/fxa-auth-server/test/local/routes/password.js @@ -24,7 +24,6 @@ function makeRoutes(options = {}) { verifierVersion: 0, smtp: {}, passwordForgotOtp: { - enabled: false, digits: 8, }, }; @@ -80,7 +79,6 @@ describe('/password', () => { describe('/forgot/send_otp', () => { const mockConfig = { passwordForgotOtp: { - enabled: true, digits: 8, ttl: 300, }, @@ -207,51 +205,11 @@ describe('/password', () => { ); }); }); - - it('returns an error when not enabled', () => { - const configDisabled = { - ...mockConfig, - passwordForgotOtp: { enabled: false, digits: 8 }, - }; - const passwordRoutes = makeRoutes({ - config: configDisabled, - customs: mockCustoms, - db: mockDB, - mailer: mockMailer, - metricsContext: mockMetricsContext, - log: mockLog, - authServerCacheRedis: mockRedis, - statsd: mockStatsd, - }); - - const mockRequest = mocks.mockRequest({ - log: mockLog, - payload: { - email: TEST_EMAIL, - metricsContext: { - deviceId: 'wibble', - flowId: - 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103', - flowBeginTime: Date.now() - 1, - }, - }, - query: {}, - metricsContext: mockMetricsContext, - }); - return runRoute( - passwordRoutes, - '/password/forgot/send_otp', - mockRequest - ).catch((response) => { - assert.equal(response.errno, error.featureNotEnabled().errno); - }); - }); }); describe('/forgot/verify_otp', () => { const mockConfig = { passwordForgotOtp: { - enabled: true, digits: 8, ttl: 300, }, @@ -405,31 +363,6 @@ describe('/password', () => { ); }); }); - - it('returns an error when not enabled', () => { - const configDisabled = { - ...mockConfig, - passwordForgotOtp: { enabled: false, digits: 8 }, - }; - const passwordRoutes = makeRoutes({ - config: configDisabled, - customs: mockCustoms, - db: mockDB, - mailer: mockMailer, - metricsContext: mockMetricsContext, - log: mockLog, - authServerCacheRedis: mockRedis, - statsd: mockStatsd, - }); - - return runRoute( - passwordRoutes, - '/password/forgot/verify_otp', - mockRequest - ).catch((response) => { - assert.equal(response.errno, error.featureNotEnabled().errno); - }); - }); }); it('/forgot/send_code', () => { @@ -988,7 +921,7 @@ describe('/password', () => { config: { domain: 'wibble', smtp: {}, - passwordForgotOtp: { enabled: false, digits: 8 }, + passwordForgotOtp: { digits: 8 }, }, db: mockDB, push: mockPush, @@ -1098,7 +1031,7 @@ describe('/password', () => { config: { domain: 'wibble', smtp: {}, - passwordForgotOtp: { enabled: false, digits: 8 }, + passwordForgotOtp: { digits: 8 }, }, db: mockDB, push: mockPush, diff --git a/packages/fxa-content-server/server/config/local.json-dist b/packages/fxa-content-server/server/config/local.json-dist index 6cfd779b241..c9afb5dabd6 100644 --- a/packages/fxa-content-server/server/config/local.json-dist +++ b/packages/fxa-content-server/server/config/local.json-dist @@ -65,7 +65,6 @@ }, "featureFlags": { "sendFxAStatusOnSettings": true, - "resetPasswordWithCode": true, "recoveryCodeSetupOnSyncSignIn": true } } diff --git a/packages/fxa-content-server/server/lib/beta-settings.js b/packages/fxa-content-server/server/lib/beta-settings.js index 549a4e1db2e..84ec930d602 100644 --- a/packages/fxa-content-server/server/lib/beta-settings.js +++ b/packages/fxa-content-server/server/lib/beta-settings.js @@ -102,7 +102,6 @@ const settingsConfig = { }, featureFlags: { keyStretchV2: config.get('featureFlags.keyStretchV2'), - resetPasswordWithCode: config.get('featureFlags.resetPasswordWithCode'), recoveryCodeSetupOnSyncSignIn: config.get( 'featureFlags.recoveryCodeSetupOnSyncSignIn' ), diff --git a/packages/fxa-content-server/server/lib/configuration.js b/packages/fxa-content-server/server/lib/configuration.js index 1fe235622d1..4ee0f4640db 100644 --- a/packages/fxa-content-server/server/lib/configuration.js +++ b/packages/fxa-content-server/server/lib/configuration.js @@ -226,12 +226,6 @@ const conf = (module.exports = convict({ format: Boolean, env: 'FEATURE_FLAGS_KEY_STRETCH_V2', }, - resetPasswordWithCode: { - default: false, - doc: 'Enables using confirmation codes instead of links for password reset', - format: Boolean, - env: 'FEATURE_FLAGS_RESET_PWD_WITH_CODE', - }, recoveryCodeSetupOnSyncSignIn: { default: false, doc: 'Enables setting up a recovery code after a Sync sign in', diff --git a/packages/fxa-content-server/server/lib/routes/get-index.js b/packages/fxa-content-server/server/lib/routes/get-index.js index ebc8bb4dc8e..a4dee243945 100644 --- a/packages/fxa-content-server/server/lib/routes/get-index.js +++ b/packages/fxa-content-server/server/lib/routes/get-index.js @@ -52,9 +52,6 @@ module.exports = function (config) { const FEATURE_FLAGS_FXA_STATUS_ON_SETTINGS = config.get( 'featureFlags.sendFxAStatusOnSettings' ); - const FEATURE_FLAGS_RESET_PWD_WITH_CODE = config.get( - 'featureFlags.resetPasswordWithCode' - ); const FEATURE_FLAGS_RECOVERY_CODE_SETUP_ON_SYNC_SIGN_IN = config.get( 'featureFlags.recoveryCodeSetupOnSyncSignIn' ); @@ -116,7 +113,6 @@ module.exports = function (config) { brandMessagingMode: BRAND_MESSAGING_MODE, featureFlags: { sendFxAStatusOnSettings: FEATURE_FLAGS_FXA_STATUS_ON_SETTINGS, - resetPasswordWithCode: FEATURE_FLAGS_RESET_PWD_WITH_CODE, recoveryCodeSetupOnSyncSignIn: FEATURE_FLAGS_RECOVERY_CODE_SETUP_ON_SYNC_SIGN_IN, },