зеркало из https://github.com/mozilla/fxa.git
feat(password reset): log user in post-password-reset
Because: - the user could have a verified session after successfully resetting their password for an account This commit: - logs the account in and take the user to /settings if the session is verified and the user did not use a recovery key during the reset
This commit is contained in:
Родитель
5a1ff395a3
Коммит
19fe669101
|
@ -118,8 +118,9 @@ test.describe('severity-2 #smoke', () => {
|
|||
await page.goto(
|
||||
`${target.contentServerUrl}/?forceExperiment=generalizedReactApp&forceExperimentGroup=react&${signinVersion.query}`
|
||||
);
|
||||
await signin.fillOutEmailFirstForm(email);
|
||||
await signin.fillOutPasswordForm(password);
|
||||
// a successful password reset means that the user is signed in
|
||||
await expect(signin.cachedSigninHeading).toBeVisible();
|
||||
await signin.signInButton.click();
|
||||
|
||||
await expect(page).toHaveURL(/settings/);
|
||||
const keys2 = await _getKeys(
|
||||
|
|
|
@ -98,14 +98,6 @@ test.describe('severity-2 #smoke', () => {
|
|||
|
||||
await resetPassword.fillOutNewPasswordForm(password);
|
||||
|
||||
await expect(page).toHaveURL(/reset_password_verified/);
|
||||
|
||||
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,
|
||||
|
|
|
@ -43,12 +43,11 @@ test.describe('severity-1 #smoke', () => {
|
|||
|
||||
await relier.goto();
|
||||
await relier.clickEmailFirst();
|
||||
await signin.fillOutEmailFirstForm(credentials.email);
|
||||
// old password fails
|
||||
await signin.fillOutPasswordForm(credentials.password);
|
||||
await expect(page.getByText('Incorrect password')).toBeVisible();
|
||||
// new passwowrd works
|
||||
await signin.fillOutPasswordForm(newPassword);
|
||||
|
||||
// a successful password reset means that the user is signed in
|
||||
await expect(signin.cachedSigninHeading).toBeVisible();
|
||||
await signin.signInButton.click();
|
||||
|
||||
await expect(page).toHaveURL(target.relierUrl);
|
||||
expect(await relier.isLoggedIn()).toBe(true);
|
||||
|
||||
|
|
|
@ -11,7 +11,13 @@ test.describe('severity-1 #smoke', () => {
|
|||
test.describe('oauth reset password Sync mobile react', () => {
|
||||
test('reset password through Sync mobile', async ({
|
||||
target,
|
||||
syncBrowserPages: { page, connectAnotherDevice, resetPassword, signin },
|
||||
syncBrowserPages: {
|
||||
page,
|
||||
connectAnotherDevice,
|
||||
resetPassword,
|
||||
signin,
|
||||
settings,
|
||||
},
|
||||
testAccountTracker,
|
||||
}) => {
|
||||
const credentials = await testAccountTracker.signUp();
|
||||
|
@ -32,25 +38,10 @@ test.describe('severity-1 #smoke', () => {
|
|||
await resetPassword.fillOutResetPasswordCodeForm(code);
|
||||
await resetPassword.fillOutNewPasswordForm(newPassword);
|
||||
|
||||
await expect(page).toHaveURL(/reset_password_verified/);
|
||||
await expect(
|
||||
resetPassword.passwordResetConfirmationHeading
|
||||
).toBeVisible();
|
||||
|
||||
// TODO in FXA-9561 - Remove this temporary test of sign in with new password
|
||||
await page.goto(
|
||||
`${
|
||||
target.contentServerUrl
|
||||
}/authorization/?${syncMobileOAuthQueryParams.toString()}`
|
||||
await expect(settings.settingsHeading).toBeVisible();
|
||||
await expect(settings.alertBar).toHaveText(
|
||||
'Your password has been reset'
|
||||
);
|
||||
// expect user to be signed in to sync and prompted for cached signin
|
||||
// old password fails
|
||||
await signin.fillOutPasswordForm(credentials.password);
|
||||
await expect(page.getByText('Incorrect password')).toBeVisible();
|
||||
// new passwowrd works
|
||||
await signin.fillOutPasswordForm(newPassword);
|
||||
|
||||
await expect(connectAnotherDevice.fxaConnected).toBeVisible();
|
||||
|
||||
// update password for cleanup function
|
||||
credentials.password = newPassword;
|
||||
|
|
|
@ -27,15 +27,6 @@ test.describe('severity-1 #smoke', () => {
|
|||
// Create and submit new password
|
||||
await resetPassword.fillOutNewPasswordForm(newPassword);
|
||||
|
||||
// Wait for new page to navigate
|
||||
await expect(page).toHaveURL(/reset_password_verified/);
|
||||
|
||||
await page.goto(target.contentServerUrl);
|
||||
|
||||
await signin.fillOutEmailFirstForm(credentials.email);
|
||||
|
||||
await signin.fillOutPasswordForm(newPassword);
|
||||
|
||||
await expect(settings.settingsHeading).toBeVisible();
|
||||
|
||||
// Cleanup requires setting this value to correct password
|
||||
|
|
|
@ -127,11 +127,10 @@ test.describe('severity-1 #smoke', () => {
|
|||
await expect(resetPassword.dataLossWarning).toBeVisible();
|
||||
await resetPassword.fillOutNewPasswordForm(newPassword);
|
||||
|
||||
await expect(
|
||||
resetPassword.passwordResetConfirmationHeading
|
||||
).toBeVisible();
|
||||
|
||||
await signinAccount(credentials.email, newPassword, settings, signin);
|
||||
await expect(settings.settingsHeading).toBeVisible();
|
||||
await expect(settings.alertBar).toHaveText(
|
||||
'Your password has been reset'
|
||||
);
|
||||
|
||||
await expect(settings.recoveryKey.status).toHaveText('Not Set');
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ test.describe('severity-1 #smoke', () => {
|
|||
test.describe('Firefox Desktop Sync v3 reset password react', () => {
|
||||
test('reset pw for sync user', async ({
|
||||
target,
|
||||
syncBrowserPages: { page, resetPassword },
|
||||
syncBrowserPages: { page, resetPassword, settings },
|
||||
testAccountTracker,
|
||||
}) => {
|
||||
const credentials = await testAccountTracker.signUp();
|
||||
|
@ -27,13 +27,10 @@ test.describe('severity-1 #smoke', () => {
|
|||
await expect(resetPassword.dataLossWarning).toBeVisible();
|
||||
await resetPassword.fillOutNewPasswordForm(newPassword);
|
||||
|
||||
await expect(page).toHaveURL(/reset_password_verified/);
|
||||
await expect(
|
||||
resetPassword.passwordResetConfirmationHeading
|
||||
).toBeVisible();
|
||||
|
||||
// TODO in FXA-9561 - Verify that the service name is displayed in the "Continue to ${serviceName}" button
|
||||
// This functionality is not yet implemented in the reset password flow
|
||||
await expect(settings.settingsHeading).toBeVisible();
|
||||
await expect(settings.alertBar).toHaveText(
|
||||
'Your password has been reset'
|
||||
);
|
||||
|
||||
// Update credentials file so that account can be deleted as part of test cleanup
|
||||
credentials.password = newPassword;
|
||||
|
|
|
@ -95,6 +95,7 @@ export const App = ({
|
|||
|
||||
// Determine if user is actually signed in
|
||||
const [isSignedIn, setIsSignedIn] = useState<boolean | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (!integration) {
|
||||
return;
|
||||
|
|
|
@ -773,6 +773,10 @@ export class Account implements AccountData {
|
|||
accountReset.unwrapBKeyVersion2 = credentialsV2?.unwrapBKey;
|
||||
currentAccount(getStoredAccountData(accountReset));
|
||||
sessionToken(accountReset.sessionToken);
|
||||
this.apolloClient.cache.writeQuery({
|
||||
query: GET_LOCAL_SIGNED_IN_STATUS,
|
||||
data: { isSignedIn: true },
|
||||
});
|
||||
return accountReset;
|
||||
} catch (err) {
|
||||
throw getHandledError(err);
|
||||
|
|
|
@ -7,7 +7,9 @@ import { RouteComponentProps, useLocation } from '@reach/router';
|
|||
import { useValidatedQueryParams } from '../../../lib/hooks/useValidate';
|
||||
import {
|
||||
Integration,
|
||||
isWebIntegration,
|
||||
useAccount,
|
||||
useAlertBar,
|
||||
useConfig,
|
||||
useFtlMsgResolver,
|
||||
} from '../../../models';
|
||||
|
@ -23,6 +25,8 @@ import firefox from '../../../lib/channels/firefox';
|
|||
import { useState } from 'react';
|
||||
import { useNavigateWithQuery } from '../../../lib/hooks/useNavigateWithQuery';
|
||||
import { getLocalizedErrorMessage } from '../../../lib/error-utils';
|
||||
import { storeAccountData } from '../../../lib/storage-utils';
|
||||
import { SETTINGS_PATH } from '../../../constants';
|
||||
|
||||
// This component is used for both /complete_reset_password and /account_recovery_reset_password routes
|
||||
// for easier maintenance
|
||||
|
@ -35,6 +39,7 @@ const CompleteResetPasswordContainer = ({
|
|||
const keyStretchExperiment = useValidatedQueryParams(KeyStretchExperiment);
|
||||
|
||||
const account = useAccount();
|
||||
const alertBar = useAlertBar();
|
||||
const config = useConfig();
|
||||
const ftlMsgResolver = useFtlMsgResolver();
|
||||
const navigate = useNavigateWithQuery();
|
||||
|
@ -72,7 +77,22 @@ const CompleteResetPasswordContainer = ({
|
|||
navigate('/reset_password_with_recovery_key_verified');
|
||||
};
|
||||
|
||||
const handleNavigationWithoutRecoveryKey = () => {
|
||||
const handleNavigationWithoutRecoveryKey = async (
|
||||
accountResetData: AccountResetData
|
||||
) => {
|
||||
if (
|
||||
accountResetData.verified &&
|
||||
(isWebIntegration(integration) || integration.isSync())
|
||||
) {
|
||||
alertBar.success(
|
||||
ftlMsgResolver.getMsg(
|
||||
'reset-password-complete-header',
|
||||
'Your password has been reset'
|
||||
)
|
||||
);
|
||||
return navigate(SETTINGS_PATH, { replace: true });
|
||||
}
|
||||
|
||||
navigate('/reset_password_verified', {
|
||||
replace: true,
|
||||
});
|
||||
|
@ -120,7 +140,17 @@ const CompleteResetPasswordContainer = ({
|
|||
return accountResetData;
|
||||
};
|
||||
|
||||
const notifyBrowserOfSignin = async (accountResetData: AccountResetData) => {
|
||||
const notifyClientOfSignin = (accountResetData: AccountResetData) => {
|
||||
if (accountResetData.verified) {
|
||||
storeAccountData({
|
||||
uid: accountResetData.uid,
|
||||
email,
|
||||
lastLogin: Date.now(),
|
||||
sessionToken: accountResetData.sessionToken,
|
||||
verified: accountResetData.verified,
|
||||
});
|
||||
}
|
||||
|
||||
if (integration.isSync()) {
|
||||
firefox.fxaLoginSignedInUser({
|
||||
authAt: accountResetData.authAt,
|
||||
|
@ -156,7 +186,7 @@ const CompleteResetPasswordContainer = ({
|
|||
recoveryKeyId
|
||||
);
|
||||
// TODO add frontend Glean event for successful reset?
|
||||
notifyBrowserOfSignin(accountResetData);
|
||||
notifyClientOfSignin(accountResetData);
|
||||
handleNavigationWithRecoveryKey();
|
||||
} else if (isResetWithoutRecoveryKey) {
|
||||
GleanMetrics.passwordReset.createNewSubmit();
|
||||
|
@ -167,8 +197,14 @@ const CompleteResetPasswordContainer = ({
|
|||
token
|
||||
);
|
||||
// TODO add frontend Glean event for successful reset?
|
||||
notifyBrowserOfSignin(accountResetData);
|
||||
handleNavigationWithoutRecoveryKey();
|
||||
notifyClientOfSignin(accountResetData);
|
||||
|
||||
// DO NOT REMOVE THIS MAKES THE NAVIGATION WORK
|
||||
// Despite all the awaiting in the code path, the signed in state in
|
||||
// the apollo client cache does not seem to update before the re-render
|
||||
// from the navigate call.
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
await handleNavigationWithoutRecoveryKey(accountResetData);
|
||||
}
|
||||
} catch (err) {
|
||||
const localizedBannerMessage = getLocalizedErrorMessage(
|
||||
|
|
Загрузка…
Ссылка в новой задаче