diff --git a/packages/account/src/Components/reset-trading-password-modal/reset-trading-password-modal.tsx b/packages/account/src/Components/reset-trading-password-modal/reset-trading-password-modal.tsx
index eafe2db12a4a..949437f899d0 100644
--- a/packages/account/src/Components/reset-trading-password-modal/reset-trading-password-modal.tsx
+++ b/packages/account/src/Components/reset-trading-password-modal/reset-trading-password-modal.tsx
@@ -64,12 +64,10 @@ const ResetTradingPassword = ({
min_number: 8,
max_number: max_length,
});
+ } else if (platform === CFD_PLATFORMS.MT5 && !validMT5Password(values.password)) {
+ errors.password = getErrorMessages().special_characters();
} else if (!validPassword(values.password)) {
errors.password = getErrorMessages().password();
- } else if (platform === CFD_PLATFORMS.MT5 && !validMT5Password(values.password)) {
- errors.password = localize(
- 'Please include at least 1 special character such as ( _ @ ? ! / # ) in your password.'
- );
}
return errors;
diff --git a/packages/appstore/src/components/cfds-listing/cfds-listing.scss b/packages/appstore/src/components/cfds-listing/cfds-listing.scss
index b495d57780c5..24cd9d5a53af 100644
--- a/packages/appstore/src/components/cfds-listing/cfds-listing.scss
+++ b/packages/appstore/src/components/cfds-listing/cfds-listing.scss
@@ -2215,17 +2215,17 @@
justify-content: center;
@include typeface(--paragraph-left-normal-black);
color: var(--text-prominent);
+ padding: 2.4rem;
&__container {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
- width: 100%;
+ width: 34rem;
justify-items: center;
flex-grow: 1;
gap: 4rem;
- padding: 2.4rem 0;
@include mobile-or-tablet-screen {
min-height: 24rem;
@@ -2250,7 +2250,7 @@
}
&__password-area {
@include desktop-screen {
- width: calc(min(34rem, 100vw));
+ width: 100%;
}
@include mobile-or-tablet-screen {
width: 100%;
diff --git a/packages/cfd/src/Containers/cfd-password-change.tsx b/packages/cfd/src/Containers/cfd-password-change.tsx
index 0dd66adc8e7c..8f4405671cab 100644
--- a/packages/cfd/src/Containers/cfd-password-change.tsx
+++ b/packages/cfd/src/Containers/cfd-password-change.tsx
@@ -94,13 +94,7 @@ const CFDPasswordChange = observer(
if (response.error.code === 'PasswordError')
actions.setFieldError('old_password', response.error.message);
if (response.error.code === 'InputValidationFailed')
- actions.setFieldError(
- 'new_password',
- // Localize is employed to convert the customized error message since the backend error lacks clarity.
- localize(
- 'Please include at least 1 special character such as ( _ @ ? ! / # ) in your password.'
- )
- );
+ actions.setFieldError('new_password', getErrorMessages().special_characters());
}
if (!response.error) {
diff --git a/packages/cfd/src/Containers/cfd-password-manager-modal.tsx b/packages/cfd/src/Containers/cfd-password-manager-modal.tsx
index 41276c3d41d4..009e58e2024f 100644
--- a/packages/cfd/src/Containers/cfd-password-manager-modal.tsx
+++ b/packages/cfd/src/Containers/cfd-password-manager-modal.tsx
@@ -13,7 +13,7 @@ import {
} from '@deriv/components';
import { useDevice } from '@deriv-com/ui';
import { localize, Localize } from '@deriv/translations';
-import { getCFDPlatformLabel } from '@deriv/shared';
+import { getCFDPlatformLabel, getErrorMessages, validMT5Password } from '@deriv/shared';
import { FormikErrors } from 'formik';
import CFDStore from '../Stores/Modules/CFD/cfd-store';
import TradingPasswordManager from './trading-password-manager';
@@ -169,7 +169,9 @@ const CFDPasswordManagerTabContent = ({
errors.new_password = localize('This field is required');
}
- if (validatePassword(values.new_password)) errors.new_password = validatePassword(values.new_password);
+ if (platform === CFD_PLATFORMS.MT5 && !validMT5Password(values.new_password)) {
+ errors.new_password = getErrorMessages().special_characters();
+ } else if (validatePassword(values.new_password)) errors.new_password = validatePassword(values.new_password);
return errors;
};
diff --git a/packages/cfd/src/Containers/cfd-password-modal.tsx b/packages/cfd/src/Containers/cfd-password-modal.tsx
index 3bd3a1f3f0d5..30262ef1b9ab 100644
--- a/packages/cfd/src/Containers/cfd-password-modal.tsx
+++ b/packages/cfd/src/Containers/cfd-password-modal.tsx
@@ -738,16 +738,14 @@ const CFDPasswordModal = observer(({ form_error, platform }: TCFDPasswordModalPr
min_number: 8,
max_number: max_length,
});
- } else if (!validPassword(values.password)) {
- errors.password = getErrorMessages().password();
} else if (
platform === CFD_PLATFORMS.MT5 &&
should_set_trading_password &&
!validMT5Password(values.password)
) {
- errors.password = localize(
- 'Please include at least 1 special character such as ( _ @ ? ! / # ) in your password.'
- );
+ errors.password = getErrorMessages().special_characters();
+ } else if (!validPassword(values.password)) {
+ getErrorMessages().password();
}
if (values.password?.toLowerCase() === email.toLowerCase()) {
errors.password = localize('Your password cannot be the same as your email address.');
diff --git a/packages/cfd/src/Containers/cfd-reset-password-modal.tsx b/packages/cfd/src/Containers/cfd-reset-password-modal.tsx
index 8515beaee4fb..31b153103eac 100644
--- a/packages/cfd/src/Containers/cfd-reset-password-modal.tsx
+++ b/packages/cfd/src/Containers/cfd-reset-password-modal.tsx
@@ -101,12 +101,10 @@ const CFDResetPasswordModal = observer(({ platform }: TCFDResetPasswordModal) =>
min_number: 8,
max_number: max_length,
});
- } else if (!validPassword(values.new_password)) {
- errors.new_password = getErrorMessages().password();
} else if (platform !== CFD_PLATFORMS.DXTRADE && !validMT5Password(values.new_password)) {
- errors.new_password = localize(
- 'Please include at least 1 special character such as ( _ @ ? ! / # ) in your password.'
- );
+ errors.new_password = getErrorMessages().special_characters();
+ } else if (!validPassword(values.new_password)) {
+ errors.new_password = getErrorMessages().special_characters();
}
if (values.new_password.toLowerCase() === email.toLowerCase()) {
errors.new_password = localize('Your password cannot be the same as your email address.');
@@ -212,7 +210,7 @@ const CFDResetPasswordModal = observer(({ platform }: TCFDResetPasswordModal) =>
align='center'
className='cfd-reset-password__description2'
>
-
+
)}
diff --git a/packages/cfd/src/Containers/mt5-migration-modal/__test__/mt5-migration-back-side-content.spec.tsx b/packages/cfd/src/Containers/mt5-migration-modal/__test__/mt5-migration-back-side-content.spec.tsx
index 3e80704ed184..13d64c56094d 100644
--- a/packages/cfd/src/Containers/mt5-migration-modal/__test__/mt5-migration-back-side-content.spec.tsx
+++ b/packages/cfd/src/Containers/mt5-migration-modal/__test__/mt5-migration-back-side-content.spec.tsx
@@ -23,6 +23,7 @@ jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
getErrorMessages: jest.fn().mockReturnValue({
password: jest.fn(),
+ special_chracters: jest.fn(),
password_warnings: '',
}),
WS: {
@@ -119,7 +120,7 @@ describe('MT5MigrationBackSideContent', () => {
renderComponent();
const input_field = screen.getByLabelText('Deriv MT5 password');
- userEvent.type(input_field, 'Abcd1234');
+ userEvent.type(input_field, 'Abcd1234!');
const upgrade_button = screen.getByRole('button', { name: 'Upgrade' });
userEvent.click(upgrade_button);
await waitFor(() => {
diff --git a/packages/cfd/src/Containers/mt5-migration-modal/mt5-migration-back-side-content.tsx b/packages/cfd/src/Containers/mt5-migration-modal/mt5-migration-back-side-content.tsx
index 0cf68b938f9b..da1fa9b8b826 100644
--- a/packages/cfd/src/Containers/mt5-migration-modal/mt5-migration-back-side-content.tsx
+++ b/packages/cfd/src/Containers/mt5-migration-modal/mt5-migration-back-side-content.tsx
@@ -1,6 +1,6 @@
import { InlineMessage, Modal, Text, PasswordInput, FormSubmitButton } from '@deriv/components';
import { useMT5SVGEligibleToMigrate } from '@deriv/hooks';
-import { CFD_PLATFORMS, WS, validLength, validPassword, getErrorMessages } from '@deriv/shared';
+import { CFD_PLATFORMS, WS, validLength, validMT5Password, getErrorMessages } from '@deriv/shared';
import { observer, useStore } from '@deriv/stores';
import { Localize, localize } from '@deriv/translations';
import React from 'react';
@@ -58,7 +58,7 @@ const MT5MigrationBackSideContent = observer(() => {
min_number: 8,
max_number: 25,
});
- } else if (!validPassword(values.password)) {
+ } else if (!validMT5Password(values.password)) {
errors.password = getErrorMessages().password();
}
if (values.password?.toLowerCase() === email.toLowerCase()) {
diff --git a/packages/cfd/src/Helpers/constants.ts b/packages/cfd/src/Helpers/constants.ts
index 9dc6e632da17..a8f542158583 100644
--- a/packages/cfd/src/Helpers/constants.ts
+++ b/packages/cfd/src/Helpers/constants.ts
@@ -6,6 +6,7 @@ import {
validPassword,
validMT5Password,
mobileOSDetectAsync,
+ hasBritishPound,
} from '@deriv/shared';
import { localize } from '@deriv/translations';
import { TCFDsPlatformType, TDetailsOfEachMT5Loginid, TMobilePlatforms } from 'Components/props.types';
@@ -139,10 +140,10 @@ const validatePassword = (password: string): string | undefined => {
min_number: 8,
max_number: 16,
});
- } else if (!validPassword(password)) {
- return getErrorMessages().password();
} else if (!validMT5Password(password)) {
- return localize('Please include at least 1 special character such as ( _ @ ? ! / # ) in your password.');
+ return getErrorMessages().special_characters();
+ } else if (!validPassword(password)) {
+ return hasBritishPound(password) ? getErrorMessages().special_characters() : getErrorMessages().password();
}
};
diff --git a/packages/cfd/src/sass/cfd.scss b/packages/cfd/src/sass/cfd.scss
index 0965b987a81b..7c573168c0a3 100644
--- a/packages/cfd/src/sass/cfd.scss
+++ b/packages/cfd/src/sass/cfd.scss
@@ -310,17 +310,17 @@
justify-content: center;
@include typeface(--paragraph-left-normal-black);
color: var(--text-prominent);
+ padding: 2.4rem;
&__container {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
- width: 100%;
+ width: 34rem;
justify-items: center;
flex-grow: 1;
gap: 4rem;
- padding: 2.4rem 0;
@include mobile-or-tablet-screen {
min-height: 24rem;
@@ -345,7 +345,7 @@
}
&__password-area {
@include desktop-screen {
- width: calc(min(34rem, 100vw));
+ width: 100%;
}
@include mobile-or-tablet-screen {
width: 100%;
diff --git a/packages/core/src/App/Containers/ResetPasswordModal/reset-password-modal.tsx b/packages/core/src/App/Containers/ResetPasswordModal/reset-password-modal.tsx
index 13d52bbfbe3f..63821223102a 100644
--- a/packages/core/src/App/Containers/ResetPasswordModal/reset-password-modal.tsx
+++ b/packages/core/src/App/Containers/ResetPasswordModal/reset-password-modal.tsx
@@ -2,7 +2,15 @@ import React from 'react';
import classNames from 'classnames';
import { Formik, Form, FormikHelpers, FormikErrors } from 'formik';
import { Button, Dialog, PasswordInput, PasswordMeter, Text } from '@deriv/components';
-import { redirectToLogin, validPassword, validLength, getErrorMessages, WS, removeActionParam } from '@deriv/shared';
+import {
+ redirectToLogin,
+ validPassword,
+ validLength,
+ getErrorMessages,
+ WS,
+ removeActionParam,
+ validMT5Password,
+} from '@deriv/shared';
import { getLanguage, localize, Localize } from '@deriv/translations';
import { observer, useStore } from '@deriv/stores';
import { TSocketError, TSocketRequest, TSocketResponse } from '@deriv/api/types';
@@ -84,6 +92,8 @@ const ResetPasswordModal = observer(() => {
min_number: 8,
max_number: 25,
});
+ } else if (!validMT5Password(values.password)) {
+ errors.password = getErrorMessages().special_characters();
} else if (!validPassword(values.password)) {
errors.password = getErrorMessages().password();
}
diff --git a/packages/core/src/Constants/form-error-messages.js b/packages/core/src/Constants/form-error-messages.js
index 491d4095bca5..c34269512ecd 100644
--- a/packages/core/src/Constants/form-error-messages.js
+++ b/packages/core/src/Constants/form-error-messages.js
@@ -16,6 +16,8 @@ export const FORM_ERROR_MESSAGES = {
general: () => localize('Only letters, numbers, space, hyphen, period, and apostrophe are allowed.'),
name: () => localize('Letters, spaces, periods, hyphens, apostrophes only.'),
password: () => localize('Password should have lower and uppercase English letters with numbers.'),
+ special_characters: () =>
+ localize('Password must have at least one of these special characters: !&‘’*-“%+.#&(),:;?=@<>\\[]^_{}|~'),
po_box: () => localize('P.O. Box is not accepted in address'),
phone: () => localize('Please enter a valid phone number (e.g. +15417541234).'),
postcode: () => localize('Only letters, numbers, space and hyphen are allowed.'),
diff --git a/packages/shared/src/utils/validation/declarative-validation-rules.ts b/packages/shared/src/utils/validation/declarative-validation-rules.ts
index 0fc8148ea6d9..c1edda3387d1 100644
--- a/packages/shared/src/utils/validation/declarative-validation-rules.ts
+++ b/packages/shared/src/utils/validation/declarative-validation-rules.ts
@@ -62,6 +62,7 @@ export const validName = (value: string) => /^(?!.*\s{2,})(?!\s)[\p{L}\s'.-]{1,5
export const validLength = (value = '', options: TOptions) =>
(options.min ? value.length >= Number(options.min) : true) &&
(options.max ? value.length <= Number(options.max) : true);
+export const hasBritishPound = (value: string) => /£/.test(value);
export const validPassword = (value: string) => /^(?=.*[a-z])(?=.*\d)(?=.*[A-Z])[!-~]{8,25}$/.test(value);
export const validEmail = (value: string) => /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$/.test(value);
const validBarrier = (value: string) => /^[+-]?\d+\.?\d*$/.test(value);
@@ -74,7 +75,8 @@ export const hasInvalidCharacters = (target_string: string) => /[^\dX\s]/.test(t
export const isFormattedCardNumber = (target_string: string) =>
/(^\d{4})\s(\d{2}X{2})\s(X{4})\s(\d{4}$)/.test(target_string);
export const validFile = (file: File) => file?.type && /(image|application)\/(jpe?g|pdf|png)$/.test(file?.type);
-export const validMT5Password = (value: string) => /^(?=.*[!@#$%^&*()+\-=[\]{};':"|,.<>/?_~])[ -~]{8,16}$/.test(value);
+export const validMT5Password = (value: string) =>
+ /^(?=.*[!@#$%^&*()+\-=[\]{};':"|,.<>/?_~])[ -~]{8,16}$/.test(value) && !hasBritishPound(value);
let pre_build_dvrs: TInitPreBuildDVRs, form_error_messages: TFormErrorMessagesTypes;
diff --git a/packages/shared/src/utils/validation/form-error-messages-types.ts b/packages/shared/src/utils/validation/form-error-messages-types.ts
index b04937dbb60d..0dd38062eb67 100644
--- a/packages/shared/src/utils/validation/form-error-messages-types.ts
+++ b/packages/shared/src/utils/validation/form-error-messages-types.ts
@@ -9,6 +9,7 @@ export type TFormErrorMessagesTypes = Record<
| 'general'
| 'name'
| 'password'
+ | 'special_characters'
| 'po_box'
| 'phone'
| 'postcode'
diff --git a/packages/wallets/src/constants/password.ts b/packages/wallets/src/constants/password.ts
index fe969b4058b7..71a54f34e5be 100644
--- a/packages/wallets/src/constants/password.ts
+++ b/packages/wallets/src/constants/password.ts
@@ -42,7 +42,7 @@ export const getPasswordErrorMessage = () => ({
}),
missingCharacter: localize('Password should have lower and uppercase English letters with numbers.'),
missingCharacterMT5: localize(
- 'Please include at least 1 special character such as ( _ @ ? ! / # ) in your password.'
+ 'Password must have at least one of these special characters: !&‘’*-“%+.#&(),:;?=@<>\\[]^_{}|~'
),
PasswordError: localize('That password is incorrect. Please try again.'),
});