Skip to content

Commit

Permalink
fixup! feat(clerk-js,localizations,shared,types): Prompt user to rese…
Browse files Browse the repository at this point in the history
…t pwned password at sign-in
  • Loading branch information
Mark Pitsilos committed Mar 27, 2024
1 parent 8f2162a commit e98fd3d
Show file tree
Hide file tree
Showing 33 changed files with 986 additions and 55 deletions.
15 changes: 12 additions & 3 deletions packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ const AlternativeMethodsList = (props: AlternativeMethodListProps) => {
localizationKey={getButtonLabel(resetPasswordFactor)}
elementDescriptor={descriptors.alternativeMethodsBlockButton}
isDisabled={card.isLoading}
onClick={() => onFactorSelected(resetPasswordFactor)}
onClick={() => {
card.setError(undefined);
onFactorSelected(resetPasswordFactor);
}}
/>
)}
{asForgotPassword && hasAnyStrategy && (
Expand Down Expand Up @@ -99,7 +102,10 @@ const AlternativeMethodsList = (props: AlternativeMethodListProps) => {
key={i}
textVariant='buttonLarge'
isDisabled={card.isLoading}
onClick={() => onFactorSelected(factor)}
onClick={() => {
card.setError(undefined);
onFactorSelected(factor);
}}
/>
))}
</Flex>
Expand All @@ -108,7 +114,10 @@ const AlternativeMethodsList = (props: AlternativeMethodListProps) => {
<BackLink
boxElementDescriptor={descriptors.backRow}
linkElementDescriptor={descriptors.backLink}
onClick={onBackLinkClick}
onClick={e => {
card.setError(undefined);
onBackLinkClick(e);
}}
/>
)}
</Col>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps)
const clerk = useClerk();

const goBack = () => {
card.setError(undefined);
return navigate('../');
};

Expand All @@ -84,12 +83,10 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps)
return clerk.__internal_navigateWithError('..', err.errors[0]);
}

if (isPasswordPwnedError(err)) {
if (onPasswordPwned) {
card.setError({ ...err.errors[0], code: err.errors[0].code + '__sign_in' });
onPasswordPwned();
return;
}
if (isPasswordPwnedError(err) && onPasswordPwned) {
card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' });
onPasswordPwned();
return;
}

handleError(err, [passwordControl], card.setError);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,98 @@ describe('SignInFactorOne', () => {
});
});
});

it('Prompts the user to reset their password via email if it has been pwned', async () => {
const { wrapper, fixtures } = await createFixtures(f => {
f.withEmailAddress();
f.withPassword();
f.withPreferredSignInStrategy({ strategy: 'password' });
f.startSignInWithEmailAddress({
supportPassword: true,
supportEmailCode: true,
supportResetPassword: true,
});
});
fixtures.signIn.prepareFirstFactor.mockReturnValueOnce(Promise.resolve({} as SignInResource));

const errJSON = {
code: 'form_password_pwned',
long_message:
'Password has been found in an online data breach. For account safety, please reset your password.',
message: 'Password has been found in an online data breach. For account safety, please reset your password.',
meta: { param_name: 'password' },
};

fixtures.signIn.attemptFirstFactor.mockRejectedValueOnce(
new ClerkAPIResponseError('Error', {
data: [errJSON],
status: 422,
}),
);

await runFakeTimers(async () => {
const { userEvent } = render(<SignInFactorOne />, { wrapper });
await userEvent.type(screen.getByLabelText('Password'), '123456');
await userEvent.click(screen.getByText('Continue'));

await waitFor(() => {
screen.getByText('Password compromised');
screen.getByText(
'This password has been found as part of a breach and can not be used, please reset your password.',
);
screen.getByText('Or, sign in with another method');
});

await userEvent.click(screen.getByText('Reset your password'));
screen.getByText('First, enter the code sent to your email ID');
});
});

it('Prompts the user to reset their password via phone if it has been pwned', async () => {
const { wrapper, fixtures } = await createFixtures(f => {
f.withEmailAddress();
f.withPassword();
f.withPreferredSignInStrategy({ strategy: 'password' });
f.startSignInWithPhoneNumber({
supportPassword: true,
supportPhoneCode: true,
supportResetPassword: true,
});
});
fixtures.signIn.prepareFirstFactor.mockReturnValueOnce(Promise.resolve({} as SignInResource));

const errJSON = {
code: 'form_password_pwned',
long_message:
'Password has been found in an online data breach. For account safety, please reset your password.',
message: 'Password has been found in an online data breach. For account safety, please reset your password.',
meta: { param_name: 'password' },
};

fixtures.signIn.attemptFirstFactor.mockRejectedValueOnce(
new ClerkAPIResponseError('Error', {
data: [errJSON],
status: 422,
}),
);

await runFakeTimers(async () => {
const { userEvent } = render(<SignInFactorOne />, { wrapper });
await userEvent.type(screen.getByLabelText('Password'), '123456');
await userEvent.click(screen.getByText('Continue'));

await waitFor(() => {
screen.getByText('Password compromised');
screen.getByText(
'This password has been found as part of a breach and can not be used, please reset your password.',
);
screen.getByText('Or, sign in with another method');
});

await userEvent.click(screen.getByText('Reset your password'));
screen.getByText('First, enter the code sent to your phone');
});
});
});

describe('Forgot Password', () => {
Expand Down
29 changes: 29 additions & 0 deletions packages/localizations/src/ar-SA.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { LocalizationResource } from '@clerk/types';

export const arSA: LocalizationResource = {
locale: 'ar-SA',
__experimental_formFieldLabel__passkeyName: undefined,
backButton: 'الرجوع',
badge__default: 'الأفتراضي',
badge__otherImpersonatorDevice: 'جهاز منتحل آخر',
Expand Down Expand Up @@ -279,6 +280,7 @@ export const arSA: LocalizationResource = {
blockButton__backupCode: 'استخدم رمز النسخ الاحتياطي',
blockButton__emailCode: 'رمز البريد الإلكتروني ل {{identifier}}',
blockButton__emailLink: 'رابط البريد الإلكتروني ل {{identifier}}',
blockButton__passkey: undefined,
blockButton__password: 'تسجيل الدخول بكلمة السر الخاصة بك',
blockButton__phoneCode: 'أرسال رسالة نصية ل{{identifier}}',
blockButton__totp: 'استخدم تطبيق المصادقة الخاص بك',
Expand Down Expand Up @@ -350,11 +352,18 @@ export const arSA: LocalizationResource = {
subtitle: 'حدث خطأ',
title: 'لا يمكن تسجيل الدخول',
},
passkey: {
subtitle: undefined,
title: undefined,
},
password: {
actionLink: 'أستعمل طريقة أخرى',
subtitle: 'للمتابعة إلى {{applicationName}}',
title: 'ادخل كلمة المرور',
},
passwordPwned: {
title: undefined,
},
phoneCode: {
formTitle: 'رمز التحقق',
resendButton: 'لم يصلك الرمز؟ حاول مرة أخرى',
Expand All @@ -381,6 +390,7 @@ export const arSA: LocalizationResource = {
actionLink: 'إنشاء حساب جديد',
actionLink__use_email: 'استخدم البريد الإلكتروني',
actionLink__use_email_username: 'استخدم البريد الإلكتروني أو اسم المستخدم',
actionLink__use_passkey: undefined,
actionLink__use_phone: 'استخدم رقم الجوال',
actionLink__use_username: 'استخدم اسم المستخدم',
actionText: 'ليس لديك حساب؟',
Expand Down Expand Up @@ -460,13 +470,19 @@ export const arSA: LocalizationResource = {
form_password_length_too_short: '',
form_password_not_strong_enough: 'كلمة المرور ليست قوية',
form_password_pwned: 'لا يمكن أستعمال كلمة السر هذه لانها غير أمنة, الرجاء اختيار كلمة مرور أخرى',
form_password_pwned__sign_in: undefined,
form_password_size_in_bytes_exceeded:
'تجاوزت كلمة المرور الحد الأقصى للحروف المدخلة, الرجاء أدخال كلمة مرور أقصر أو حذف بعض الأحرف الخاصة',
form_password_validation_failed: 'كلمة مرور خاطئة',
form_username_invalid_character: '',
form_username_invalid_length: '',
identification_deletion_failed: 'لا يمكن حذف هويتك الآخيرة ',
not_allowed_access: '',
passkey_already_exists: undefined,
passkey_not_supported: undefined,
passkey_registration_cancelled: undefined,
passkey_retrieval_cancelled: undefined,
passkeys_pa_not_supported: undefined,
passwordComplexity: {
maximumLength: 'أقل من {{length}} حروف',
minimumLength: '{{length}} حروف أو أكثر',
Expand Down Expand Up @@ -524,6 +540,14 @@ export const arSA: LocalizationResource = {
action__signOutAll: 'تسجيل الخروج من جميع الحسابات',
},
userProfile: {
__experimental_passkeyScreen: {
removeResource: {
messageLine1: undefined,
title: undefined,
},
subtitle__rename: undefined,
title__rename: undefined,
},
backupCodePage: {
actionLabel__copied: 'تم النسخ',
actionLabel__copy: 'نسخ الكل',
Expand Down Expand Up @@ -675,6 +699,11 @@ export const arSA: LocalizationResource = {
title: 'تحديث الملف الشخصي',
},
start: {
__experimental_passkeysSection: {
menuAction__destructive: undefined,
menuAction__rename: undefined,
title: undefined,
},
activeDevicesSection: {
destructiveAction: 'قم بتسجيل الخروج من الجهاز',
title: 'الأجهزة النشطة',
Expand Down
29 changes: 29 additions & 0 deletions packages/localizations/src/bg-BG.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { LocalizationResource } from '@clerk/types';

export const bgBG: LocalizationResource = {
locale: 'bg-BG',
__experimental_formFieldLabel__passkeyName: undefined,
backButton: 'Назад',
badge__default: 'По подразбиране',
badge__otherImpersonatorDevice: 'Друго устройство за имитация',
Expand Down Expand Up @@ -282,6 +283,7 @@ export const bgBG: LocalizationResource = {
blockButton__backupCode: 'Използвай резервен код',
blockButton__emailCode: 'Изпрати код по имейл до {{identifier}}',
blockButton__emailLink: 'Изпрати линк по имейл до {{identifier}}',
blockButton__passkey: undefined,
blockButton__password: 'Влез с парола',
blockButton__phoneCode: 'Изпрати SMS код до {{identifier}}',
blockButton__totp: 'Използвай приложение за удостоверяване',
Expand Down Expand Up @@ -353,11 +355,18 @@ export const bgBG: LocalizationResource = {
subtitle: 'Възникна грешка',
title: 'Неуспешно влизане',
},
passkey: {
subtitle: undefined,
title: undefined,
},
password: {
actionLink: 'Използвайте друг метод',
subtitle: 'Въведете паролата, свързана с вашия акаунт',
title: 'Въведете вашата парола',
},
passwordPwned: {
title: undefined,
},
phoneCode: {
formTitle: 'Код за потвърждение',
resendButton: 'Не сте получили код? Изпрати отново',
Expand All @@ -383,6 +392,7 @@ export const bgBG: LocalizationResource = {
actionLink: 'Регистрирайте се',
actionLink__use_email: 'Използвайте имейл',
actionLink__use_email_username: 'Използвайте имейл или потребителско име',
actionLink__use_passkey: undefined,
actionLink__use_phone: 'Използвайте телефон',
actionLink__use_username: 'Използвайте потребителско име',
actionText: 'Нямате акаунт?',
Expand Down Expand Up @@ -463,13 +473,19 @@ export const bgBG: LocalizationResource = {
form_password_length_too_short: '',
form_password_not_strong_enough: 'Вашата парола не е достатъчно сигурна.',
form_password_pwned: 'Тази парола е част от изтекли данни и не може да се използва. Моля, опитайте с друга парола.',
form_password_pwned__sign_in: undefined,
form_password_size_in_bytes_exceeded:
'Паролата ви надвиши максималния брой байтове, позволен, моля, я скратете или премахнете някои специални знаци.',
form_password_validation_failed: 'Неправилна парола',
form_username_invalid_character: '',
form_username_invalid_length: '',
identification_deletion_failed: 'Не можете да изтриете последната си идентификация.',
not_allowed_access: '',
passkey_already_exists: undefined,
passkey_not_supported: undefined,
passkey_registration_cancelled: undefined,
passkey_retrieval_cancelled: undefined,
passkeys_pa_not_supported: undefined,
passwordComplexity: {
maximumLength: 'по-малко от {{length}} символа',
minimumLength: '{{length}} или повече символа',
Expand Down Expand Up @@ -527,6 +543,14 @@ export const bgBG: LocalizationResource = {
action__signOutAll: 'Изход от всички акаунти',
},
userProfile: {
__experimental_passkeyScreen: {
removeResource: {
messageLine1: undefined,
title: undefined,
},
subtitle__rename: undefined,
title__rename: undefined,
},
backupCodePage: {
actionLabel__copied: 'Копирано!',
actionLabel__copy: 'Копиране на всички',
Expand Down Expand Up @@ -684,6 +708,11 @@ export const bgBG: LocalizationResource = {
title: 'Актуализиране на профила',
},
start: {
__experimental_passkeysSection: {
menuAction__destructive: undefined,
menuAction__rename: undefined,
title: undefined,
},
activeDevicesSection: {
destructiveAction: 'Излез от устройството',
title: 'Активни устройства',
Expand Down
Loading

0 comments on commit e98fd3d

Please sign in to comment.