Skip to content

Commit

Permalink
Merge pull request #15397 from mozilla/FXA-7149-reset-pwd-link-not-ex…
Browse files Browse the repository at this point in the history
…pired

fix(fxa-settings): Expired reset password link should always redirect
  • Loading branch information
vpomerleau authored Jun 2, 2023
2 parents e52ab76 + f543288 commit 0612880
Show file tree
Hide file tree
Showing 17 changed files with 452 additions and 417 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const NEW_PASSWORD = 'notYourAveragePassW0Rd';
function getReactFeatureFlagUrl(
target: BaseTarget,
path: string,
showReactApp: boolean = true
showReactApp = true
) {
return `${target.contentServerUrl}${path}?showReactApp=${showReactApp}`;
}
Expand Down
21 changes: 19 additions & 2 deletions packages/fxa-settings/src/components/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export const App = ({
<LinkValidator
path="/complete_reset_password/*"
linkType={LinkType['reset-password']}
viewName={'complete-reset-password'}
viewName="complete-reset-password"
getParamsFromModel={() => {
return CreateCompleteResetPasswordLink();
}}
Expand All @@ -158,7 +158,24 @@ export const App = ({
)}
</LinkValidator>

<AccountRecoveryConfirmKey path="/account_recovery_confirm_key/*" />
<LinkValidator
path="/account_recovery_confirm_key/*"
linkType={LinkType['reset-password']}
viewName="account-recovery-confirm-key"
getParamsFromModel={() => {
return CreateCompleteResetPasswordLink();
}}
>
{({ setLinkStatus, params }) => (
<AccountRecoveryConfirmKey
{...{
setLinkStatus,
params,
}}
/>
)}
</LinkValidator>

<AccountRecoveryResetPassword path="/account_recovery_reset_password/*" />

<SigninReported path="/signin_reported/*" />
Expand Down
1 change: 1 addition & 0 deletions packages/fxa-settings/src/components/LinkDamaged/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const LinkDamaged = ({ headingText, headingTextFtlId }: LinkDamagedProps) => {
};

export const ResetPasswordLinkDamaged = () => {
// TODO in FXA-7630 add metrics event and associated tests for users hitting the LinkDamaged page
return (
<LinkDamaged
headingText="Reset password link damaged"
Expand Down
5 changes: 2 additions & 3 deletions packages/fxa-settings/src/components/LinkExpired/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,10 @@ export const LinkExpired = ({
{resendStatus === ResendStatus['error'] && <ResendLinkErrorBanner />}

<FtlMsg id={messageFtlId}>
<p className="mt-4 text-sm">{messageText}</p>
<p className="text-sm my-4">{messageText}</p>
</FtlMsg>
{/* TODO Extract for reuse into ButtonResendResetPasswordLink */}
<FtlMsg id="reset-pwd-resend-link">
<button onClick={resendLinkHandler} className="link-blue mt-4">
<button onClick={resendLinkHandler} className="link-blue text-sm">
Receive new link
</button>
</FtlMsg>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const LinkExpiredResetPassword = ({
email,
viewName,
}: LinkExpiredResetPasswordProps) => {
// TODO in FXA-7630 add metrics event and associated tests for users hitting the LinkExpired page
const account = useAccount();

const [resendStatus, setResendStatus] = useState<ResendStatus>(
Expand Down
80 changes: 0 additions & 80 deletions packages/fxa-settings/src/lib/hooks/useLinkStatus/index.tsx

This file was deleted.

25 changes: 0 additions & 25 deletions packages/fxa-settings/src/lib/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,3 @@ export const typeByLabelText = (labelText: string) => async (x: string) => {
target: { value: x },
});
};

type LinkParamValue = string | null;

export const getSearchWithParams = ({
mockToken,
mockCode,
mockEmail,
mockPasswordHash,
mockUid,
}: {
mockToken: LinkParamValue;
mockCode: LinkParamValue;
mockEmail: LinkParamValue;
mockPasswordHash?: LinkParamValue;
mockUid?: LinkParamValue;
}) => {
const tokenParam = mockToken !== null ? `token=${mockToken}&` : '';
const codeParam = mockCode !== null ? `code=${mockCode}&` : '';
const emailParam = mockEmail !== null ? `email=${mockEmail}&` : '';
const passwordHashParam = mockPasswordHash
? `emailToHashWith=${mockPasswordHash}`
: '';
const uidParam = mockUid ? `uid=${mockUid}` : '';
return `?${tokenParam}${codeParam}${emailParam}${passwordHashParam}${uidParam}`;
};
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ export class CompleteResetPasswordLink extends ModelDataProvider {

@bind([V.isHex, V.isRequired])
token: string = '';

@bind([V.isHex, V.isRequired])
uid: string = '';
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,66 @@
* 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 { createHistory, createMemorySource, History } from '@reach/router';
import React from 'react';
import { Account } from '../../../models';
import AccountRecoveryConfirmKey from '.';
import { Meta } from '@storybook/react';
import { AuthUiErrors } from '../../../lib/auth-errors/auth-errors';
import { Subject } from './mocks';
import {
mockCompleteResetPasswordParams,
paramsWithMissingEmail,
Subject,
} from './mocks';

export default {
title: 'Pages/ResetPassword/AccountRecoveryConfirmKey',
component: AccountRecoveryConfirmKey,
} as Meta;

const source = createMemorySource('/fake-memories');

const storyWithAccountAndHistory = (
const storyWithSubject = (
account: Account,
history: History,
params: Record<string, string>,
storyName?: string
) => {
const story = () => <Subject {...{ account, history }} />;
const story = () => <Subject {...{ account, params }} />;
story.storyName = storyName;
return story;
};

const historyWithParams = createHistory(source);
historyWithParams.location.href =
'http://localhost.com/?&token=token&code=code&email=email@email&uid=uid';

const historyWithoutParams = createHistory(source);
historyWithoutParams.location.href = 'http://localhost.com/?';

const accountValid = {
resetPasswordStatus: () => Promise.resolve(true),
getRecoveryKeyBundle: () => Promise.resolve(true),
verifyPasswordForgotToken: () => Promise.resolve(false),
} as unknown as Account;

const accountWithTokenError = {
verifyPasswordForgotToken: () => {
throw AuthUiErrors.INVALID_TOKEN;
},
const accountWithExpiredLink = {
resetPasswordStatus: () => Promise.resolve(false),
} as unknown as Account;

const accountWithInvalidRecoveryKey = {
resetPasswordStatus: () => Promise.resolve(true),
getRecoveryKeyBundle: () => {
throw Error('boop');
},
verifyPasswordForgotToken: () => Promise.resolve(true),
} as unknown as Account;

export const OnConfirmValidKey = storyWithAccountAndHistory(
export const OnConfirmValidKey = storyWithSubject(
accountValid,
historyWithParams,
mockCompleteResetPasswordParams,
'Valid recovery key. Users will be redirected to AccountRecoveryResetPassword on confirm'
);

export const OnConfirmInvalidKey = storyWithAccountAndHistory(
export const OnConfirmInvalidKey = storyWithSubject(
accountWithInvalidRecoveryKey,
historyWithParams
mockCompleteResetPasswordParams
);

export const OnConfirmLinkExpired = storyWithAccountAndHistory(
accountWithTokenError,
historyWithParams
export const OnConfirmLinkExpired = storyWithSubject(
accountWithExpiredLink,
mockCompleteResetPasswordParams
);

export const WithDamagedLink = storyWithAccountAndHistory(
export const WithDamagedLink = storyWithSubject(
accountValid,
historyWithoutParams
paramsWithMissingEmail
);
Loading

0 comments on commit 0612880

Please sign in to comment.