Merge pull request #16315 from mozilla/fxa-9065

fix(email): Disable using Relay masks to create an account or secondary
This commit is contained in:
Vijay Budhram 2024-02-05 12:28:02 -05:00 коммит произвёл GitHub
Родитель 54ceed606d 679b80ffa6
Коммит 2b651ce11b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
10 изменённых файлов: 144 добавлений и 3 удалений

Просмотреть файл

@ -624,6 +624,10 @@ var ERRORS = {
errno: 1065,
message: t('The image file size is too large to be uploaded.'),
},
EMAIL_MASK_NEW_ACCOUNT: {
errno: 1066,
message: t('Email masks cant be used to create an account.'),
},
};
export default _.extend({}, Errors, {

Просмотреть файл

@ -18,6 +18,7 @@ Vat.register('channelKey', Vat.string().test(Validate.isBase64Url));
Vat.register('codeChallenge', Vat.string().min(43).max(128));
Vat.register('codeChallengeMethod', Vat.string().valid('S256'));
Vat.register('email', Vat.string().test(Validate.isEmailValid));
Vat.register('emailMask', Vat.string().test(Validate.isEmailMask));
Vat.register('hex', Vat.string().test(Validate.isHexValid));
Vat.register('idToken', Vat.string());
Vat.register('keyFetchToken', Vat.string());

Просмотреть файл

@ -26,6 +26,7 @@ import checkEmailDomain from '../lib/email-domain-validator';
import PocketMigrationMixin from './mixins/pocket-migration-mixin';
import BrandMessagingMixin from './mixins/brand-messaging-mixin';
import MonitorClientMixin from './mixins/monitor-client-mixin';
import { isEmailMask } from 'fxa-shared/email/helpers';
const EMAIL_SELECTOR = 'input[type=email]';
@ -265,6 +266,15 @@ class IndexView extends FormView {
.then(({ exists, hasPassword, hasLinkedAccount }) => {
const nextEndpoint = exists ? 'signin' : 'signup';
// If a Relay email mask is being used for a new account, show an error
if (nextEndpoint === 'signup' && isEmailMask(email)) {
this.showValidationError(
EMAIL_SELECTOR,
AuthErrors.toError('EMAIL_MASK_NEW_ACCOUNT')
);
return;
}
// Temporary hack for React work that allows us to pass the entered `email` as
// a param. When 'signup' and 'signin' flows are both finished and we're ready,
// we can convert the index page over and pass this along with router state

Просмотреть файл

@ -435,6 +435,33 @@ describe('views/index', () => {
assert.equal(account.get('email'), EMAIL);
});
});
it('allows signin with Relay mask email (@mozmail.com)', () => {
const storedAccount = user.initAccount({});
sinon.stub(user, 'checkAccountStatus').callsFake(() =>
Promise.resolve({
exists: true,
hasPassword: true,
hasLinkedAccount: false,
})
);
sinon.stub(user, 'getAccountByEmail').callsFake(() => storedAccount);
return view.checkEmail('aaa@mozmail.com').then(() => {
const brokerAccount = broker.beforeSignIn.args[0][0];
assert.equal(brokerAccount.get('email'), 'aaa@mozmail.com');
assert.isTrue(
view.navigate.calledOnceWith('signin', {
account: storedAccount,
})
);
const { account } = view.navigate.args[0][1];
assert.strictEqual(account, storedAccount);
// Ensure the email is added to the stored account.
assert.equal(account.get('email'), 'aaa@mozmail.com');
});
});
});
describe('email is not registered', () => {
@ -457,6 +484,19 @@ describe('views/index', () => {
assert.isFalse(view.navigate.called);
});
});
it('displays error with Relay mask email (@mozmail.com)', () => {
sinon
.stub(user, 'checkAccountStatus')
.callsFake(() => Promise.resolve({ exists: false }));
sinon.stub(view, '_validateEmailDomain').resolves();
sinon.spy(view, 'showValidationError');
return view.checkEmail('abc@mozmail.com').then(() => {
assert.isTrue(view.showValidationError.called);
const err = view.showValidationError.args[0][1];
assert.isTrue(AuthErrors.is(err, 'EMAIL_MASK_NEW_ACCOUNT'));
});
});
});
describe('MX record validation configurations', () => {

Просмотреть файл

@ -70,6 +70,26 @@ describe('PageSecondaryEmailAdd', () => {
expect(screen.getByTestId('save-button')).toHaveAttribute('disabled');
});
it('should display tooltip error when using email mask', async () => {
renderWithRouter(
<AppContext.Provider value={mockAppContext({ account })}>
<PageSecondaryEmailAdd />
</AppContext.Provider>
);
const input = screen.getByTestId('input-field');
fireEvent.change(input, { target: { value: 'user@mozmail.com' } });
await act(async () => {
fireEvent.click(screen.getByTestId('save-button'));
});
expect(screen.queryByTestId('tooltip')).toBeInTheDocument();
expect(
screen.queryByText('Email masks cant be used as a secondary email')
).toBeInTheDocument();
});
});
describe('createSecondaryEmailCode', () => {

Просмотреть файл

@ -6,7 +6,7 @@ import { HomePath } from '../../../constants';
import InputText from '../../InputText';
import FlowContainer from '../FlowContainer';
import VerifiedSessionGuard from '../VerifiedSessionGuard';
import { isEmailValid } from 'fxa-shared/email/helpers';
import { isEmailMask, isEmailValid } from 'fxa-shared/email/helpers';
import { useAccount, useAlertBar } from 'fxa-settings/src/models';
import {
AuthUiErrorNos,
@ -66,8 +66,18 @@ export const PageSecondaryEmailAdd = (_: RouteComponentProps) => {
setSaveBtnDisabled(!isValid);
setEmail(inputRef.current?.value);
setErrorText('');
if (isEmailMask(email)) {
const errorText = l10n.getString(
'add-secondary-email-mask',
null,
'Email masks cant be used as a secondary email'
);
setErrorText(errorText);
setSaveBtnDisabled(true);
}
},
[setSaveBtnDisabled]
[setSaveBtnDisabled, setErrorText, l10n]
);
return (

Просмотреть файл

@ -622,6 +622,10 @@ const ERRORS = {
errno: 1065,
message: 'The image file size is too large to be uploaded.',
},
EMAIL_MASK_NEW_ACCOUNT: {
errno: 1066,
message: 'Email masks cant be used to create an account.',
},
};
type ErrorKey = keyof typeof ERRORS;

Просмотреть файл

@ -359,6 +359,23 @@ describe('Signup page', () => {
});
});
describe('fails for Relay email masks', () => {
['a@relay.firefox.com', 'b@mozmail.com', 'c@sub.mozmail.com'].forEach(
(mask) => {
it(`fails for mask ${mask}`, async () => {
renderWithLocalizationProvider(
<Subject queryParams={{ email: mask }} />
);
await fillOutForm();
submit();
await screen.findByText(
'Email masks cant be used to create an account.'
);
});
}
);
});
it('passes newsletter subscription options to the next screen', async () => {
const mockBeginSignupHandler = jest
.fn()

Просмотреть файл

@ -47,6 +47,11 @@ import { MozServices } from '../../lib/types';
import LoadingSpinner from 'fxa-react/components/LoadingSpinner';
import firefox from '../../lib/channels/firefox';
import ThirdPartyAuth from '../../components/ThirdPartyAuth';
import {
AuthUiErrors,
composeAuthUiErrorTranslationId,
} from '../../lib/auth-errors/auth-errors';
import { isEmailMask } from 'fxa-shared/email/helpers';
export const viewName = 'signup';
@ -194,6 +199,17 @@ export const Signup = ({
navigate('/cannot_create_account');
return;
}
// Disable creating accounts with email masks
if (isEmailMask(email)) {
const message = 'Email masks cant be used to create an account.';
const ftlId = composeAuthUiErrorTranslationId({
errno: AuthUiErrors.EMAIL_MASK_NEW_ACCOUNT.errno,
});
setBannerErrorText(ftlMsgResolver.getMsg(ftlId, message));
return;
}
setBeginSignupLoading(true);
const atLeast18AtReg = Number(age) >= 18 ? true : null;

Просмотреть файл

@ -1,3 +1,10 @@
/* 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/. */
// Mozmail.com is the Firefox Relay email mask, we prohibit creating accounts with it
const emailMaskRegex = /@([a-zA-Z0-9.-]+\.)?(mozmail|relay\.firefox)\.(com)$/i;
export function normalizeEmail(originalEmail: string): string {
return originalEmail.toLowerCase();
}
@ -32,7 +39,8 @@ export function emailsMatch(firstEmail: string, secondEmail: string): boolean {
// * http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
// '/' in the character class is (redundantly) backslash-escaped to produce
// the same minimized form in node 4.x and node 0.10.
const emailRegex = /^[\w.!#$%&'*+\/=?^`{|}~-]{1,64}@[a-z\d](?:[a-z\d-]{0,253}[a-z\d])?(?:\.[a-z\d](?:[a-z\d-]{0,253}[a-z\d])?)+$/i;
const emailRegex =
/^[\w.!#$%&'*+\/=?^`{|}~-]{1,64}@[a-z\d](?:[a-z\d-]{0,253}[a-z\d])?(?:\.[a-z\d](?:[a-z\d-]{0,253}[a-z\d])?)+$/i;
/**
* Check if an email address is valid
@ -55,3 +63,14 @@ export function isEmailValid(email: string): boolean {
return emailRegex.test(email);
}
/**
* Check if an email address is an email mask. Currently, the only email mask
* we check is mozmail.com, relay.firefox.com and *.mozmail.com from Firefox Relay.
*
* @param {String} email
* @return {Boolean} true if email is mask, false otw.
*/
export function isEmailMask(email: string): boolean {
return emailMaskRegex.test(email);
}