Skip to content

Commit 0832b7d

Browse files
vpomerleaunshirley
authored andcommitted
feat(auth, settings): Move 2fa setup initial code validation server-side
Because: * Delaying the 2fa code verification after recovery method confirmation could cause issues with expired codes * We want to immediately verify the code server-side on code submission This commit: * Remove 2fa setup handling from session/verify/totp and only keep session verification handling * Create new API endpoints to verify 2fa setup code and complete 2fa setup * totp/setup/verify stores the verification status in Redis * Update totp/create to use existing Redis secret on restart/refresh if not expired * Add new handlers in fxa-client for new endpoints * Update frontend to use new endpoints and remove client-side code verification * Remove client-side otplib import * Update tests Closes #FXA-12128
1 parent 6b1764e commit 0832b7d

48 files changed

Lines changed: 877 additions & 817 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import { authenticator as otplibAuthenticator } from 'otplib';
6+
7+
// Generate a TOTP code matching server settings (hex-encoded secret)
8+
export async function getCode(secretHex: string): Promise<string> {
9+
const auth = new otplibAuthenticator.Authenticator();
10+
auth.options = Object.assign({}, otplibAuthenticator.options, {
11+
encoding: 'hex',
12+
});
13+
return auth.generate(secretHex);
14+
}

packages/functional-tests/pages/relier.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export class RelierPage extends BaseLayout {
2323
}
2424

2525
async isLoggedIn() {
26+
// Ensure we've navigated back to the relier before checking login status
27+
await this.page.waitForURL(`${this.target.relierUrl}/**`);
2628
const loggedInStatus = this.page.locator('#loggedin');
2729
await loggedInStatus.waitFor();
2830
return loggedInStatus.isVisible();

packages/functional-tests/pages/settings/totp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import jsQR from 'jsqr';
66
import UPNG from 'upng-js';
77
import { expect } from '../../lib/fixtures/standard';
88
import { SettingsLayout } from './layout';
9-
import { getCode } from 'fxa-settings/src/lib/totp';
9+
import { getCode } from '../../lib/totp';
1010
import { DataTrioComponent } from './components/dataTrio';
1111

1212
export type TotpCredentials = {

packages/functional-tests/tests/cms/cms-2fa.spec.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import { expect, test } from '../../lib/fixtures/standard';
66
import { syncDesktopOAuthQueryParams } from '../../lib/query-params';
7-
import { getCode } from 'fxa-settings/src/lib/totp';
7+
import { getCode } from '../../lib/totp';
88
import {
99
TargetName,
1010
getFromEnvWithFallback,
@@ -158,7 +158,8 @@ test.describe('severity-1 #smoke', () => {
158158
await settings.totp.addButton.click();
159159

160160
// Set up 2FA with QR code and backup codes
161-
const { secret } = await totp.setUpTwoStepAuthWithQrAndBackupCodesChoice();
161+
const { secret } =
162+
await totp.setUpTwoStepAuthWithQrAndBackupCodesChoice();
162163

163164
await expect(settings.settingsHeading).toBeVisible();
164165
await expect(settings.alertBar).toHaveText(
@@ -592,7 +593,8 @@ test.describe('severity-1 #smoke', () => {
592593
await settings.totp.addButton.click();
593594

594595
// Set up 2FA with QR code and backup codes
595-
const { secret } = await totp.setUpTwoStepAuthWithQrAndBackupCodesChoice();
596+
const { secret } =
597+
await totp.setUpTwoStepAuthWithQrAndBackupCodesChoice();
596598

597599
await expect(settings.settingsHeading).toBeVisible();
598600
await expect(settings.alertBar).toHaveText(

packages/functional-tests/tests/key-stretching-v2/totp.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
import { getCode } from 'fxa-settings/src/lib/totp';
5+
import { getCode } from '../../lib/totp';
66
import { expect, test } from '../../lib/fixtures/standard';
77

88
/**

packages/functional-tests/tests/misc/recoveryKeyPromoInline.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

55
import { expect, test } from '../../lib/fixtures/standard';
6-
import { getCode } from 'packages/fxa-settings/src/lib/totp';
6+
import { getCode } from '../../lib/totp';
77

88
test.describe('recovery key promo', () => {
99
test.describe('inline', () => {

packages/functional-tests/tests/misc/relayIntegration.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import { FirefoxCommand } from '../../lib/channels';
66
import { expect, test } from '../../lib/fixtures/standard';
77
import { relayDesktopOAuthQueryParams } from '../../lib/query-params';
8-
import { getCode } from 'packages/fxa-settings/src/lib/totp';
8+
import { getCode } from '../../lib/totp';
99

1010
test.describe('relay integration', () => {
1111
test('signup with Relay desktop', async ({

packages/functional-tests/tests/oauth/totp.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
import { getCode } from 'fxa-settings/src/lib/totp';
5+
import { getCode } from '../../lib/totp';
66
import { Page, expect, test } from '../../lib/fixtures/standard';
77
import { BaseTarget, Credentials } from '../../lib/targets/base';
88
import { SettingsPage } from '../../pages/settings';
@@ -392,7 +392,7 @@ test.describe('severity-1 #smoke', () => {
392392
await totp.chooseBackupCodesOption();
393393
const recoveryCodes = await totp.backupCodesDownloadStep();
394394
await totp.confirmBackupCodeStep(recoveryCodes[0]);
395-
await page.getByRole('button', { name: 'Continue' }).click();
395+
await page.getByRole('button', { name: /Continue/ }).click();
396396

397397
expect(await relier.isLoggedIn()).toBe(true);
398398

packages/functional-tests/tests/react-conversion/signinTotp.spec.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,13 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
import { getCode } from 'fxa-settings/src/lib/totp';
5+
import { getCode } from '../../lib/totp';
66
import { expect, test } from '../../lib/fixtures/standard';
77

88
test.describe('severity-1 #smoke', () => {
99
test.describe('two step auth', () => {
1010
test('add totp', async ({
11-
pages: {
12-
settings,
13-
totp,
14-
page,
15-
signin,
16-
signup,
17-
signinTotpCode,
18-
},
11+
pages: { settings, totp, page, signin, signup, signinTotpCode },
1912
testAccountTracker,
2013
}) => {
2114
const credentials = await testAccountTracker.signUp();
@@ -106,14 +99,7 @@ test.describe('severity-1 #smoke', () => {
10699
});
107100

108101
test('error message when totp code is invalid', async ({
109-
pages: {
110-
page,
111-
settings,
112-
totp,
113-
signin,
114-
signup,
115-
signinTotpCode,
116-
},
102+
pages: { page, settings, totp, signin, signup, signinTotpCode },
117103
testAccountTracker,
118104
}) => {
119105
const credentials = await testAccountTracker.signUp();

packages/functional-tests/tests/resetPassword/oauthResetPassword.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
import { getCode } from 'fxa-settings/src/lib/totp';
5+
import { getCode } from '../../lib/totp';
66
import { expect, test } from '../../lib/fixtures/standard';
77
import { ResetPasswordPage } from '../../pages/resetPassword';
88
import { SigninPage } from '../../pages/signin';

0 commit comments

Comments
 (0)