diff --git a/ui/components/app/signature-request-original/signature-request-original.component.js b/ui/components/app/signature-request-original/signature-request-original.component.js index 1260c3d44..570d5821a 100644 --- a/ui/components/app/signature-request-original/signature-request-original.component.js +++ b/ui/components/app/signature-request-original/signature-request-original.component.js @@ -5,7 +5,7 @@ import { ObjectInspector } from 'react-inspector'; import LedgerInstructionField from '../ledger-instruction-field'; import { MESSAGE_TYPE } from '../../../../shared/constants/app'; -import { getURLHostName } from '../../../helpers/utils/util'; +import { getURLHostName, sanitizeString } from '../../../helpers/utils/util'; import { stripHexPrefix } from '../../../../shared/modules/hexstring-utils'; import Button from '../../ui/button'; import SiteOrigin from '../../ui/site-origin'; @@ -177,8 +177,12 @@ export default class SignatureRequestOriginal extends Component { className="request-signature__row" key={`request-signature-row-${index}`} > -
{`${name}:`}
-
{value}
+
+ {sanitizeString(`${name}:`)} +
+
+ {sanitizeString(value)} +
); })} diff --git a/ui/components/app/signature-request-original/signature-request-original.test.js b/ui/components/app/signature-request-original/signature-request-original.test.js index 0b5b75834..5f7e04c93 100644 --- a/ui/components/app/signature-request-original/signature-request-original.test.js +++ b/ui/components/app/signature-request-original/signature-request-original.test.js @@ -52,14 +52,17 @@ const props = { }, }; -const render = () => { +const render = (txData = props.txData) => { const store = configureStore({ metamask: { ...mockState.metamask, }, }); - return renderWithProvider(, store); + return renderWithProvider( + , + store, + ); }; describe('SignatureRequestOriginal', () => { @@ -92,4 +95,24 @@ describe('SignatureRequestOriginal', () => { fireEvent.click(signButton); expect(screen.getByText('Your funds may be at risk')).toBeInTheDocument(); }); + + it('should escape RTL character in label or value', () => { + const txData = { + msgParams: { + from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + data: [ + { + type: 'string', + name: 'Message \u202E test', + value: 'Hi, \u202E Alice!', + }, + ], + origin: 'https://happydapp.website/governance?futarchy=true', + }, + type: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA, + }; + const { getByText } = render(txData); + expect(getByText('Message \\u202E test:')).toBeInTheDocument(); + expect(getByText('Hi, \\u202E Alice!')).toBeInTheDocument(); + }); }); diff --git a/ui/components/app/signature-request/signature-request-data/signature-request-data.js b/ui/components/app/signature-request/signature-request-data/signature-request-data.js index 15b1359d8..a809d4a65 100644 --- a/ui/components/app/signature-request/signature-request-data/signature-request-data.js +++ b/ui/components/app/signature-request/signature-request-data/signature-request-data.js @@ -19,6 +19,7 @@ import { TypographyVariant, TextColor, } from '../../../../helpers/constants/design-system'; +import { sanitizeString } from '../../../../helpers/utils/util'; function SignatureRequestData({ data }) { const identities = useSelector(getMemoizedMetaMaskIdentities); @@ -42,7 +43,7 @@ function SignatureRequestData({ data }) { typeof value === 'object' ? FONT_WEIGHT.BOLD : FONT_WEIGHT.NORMAL } > - {label.charAt(0).toUpperCase() + label.slice(1)}:{' '} + {sanitizeString(label.charAt(0).toUpperCase() + label.slice(1))}:{' '} {typeof value === 'object' && value !== null ? ( @@ -68,7 +69,7 @@ function SignatureRequestData({ data }) { /> ) : ( - `${value}` + sanitizeString(`${value}`) )} )} diff --git a/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js b/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js index 7a2f4a186..9ea93fe05 100644 --- a/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js +++ b/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js @@ -468,5 +468,55 @@ describe('Signature Request Data', () => { expect(getByText('0xB0B...0000')).toBeInTheDocument(); }); + + it('should escape RTL character in label or value', () => { + const messageDataWithRTLCharacters = { + ...messageData, + message: { + ...messageData.message, + contents: 'Hello, \u202E Bob!', + from: { + 'name\u202Ename': 'Cow \u202E Cow', + 'wallets\u202Ewallets': [ + '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + '0x06195827297c7A80a443b6894d3BDB8824b43896', + ], + }, + to: [ + { + 'name\u202Ename': 'Bob \u202E Bob', + 'wallets\u202Ewallets': [ + '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + '0xB0B0b0b0b0b0B000000000000000000000000000', + ], + }, + ], + }, + types: { + ...messageData.message.types, + Person: [ + { name: 'name\u202Ename', type: 'string' }, + { name: 'wallets\u202Ewallets', type: 'address[]' }, + ], + }, + }; + const msgParams = { + data: JSON.parse(JSON.stringify(messageDataWithRTLCharacters)), + version: 'V4', + origin: 'test', + }; + const { getByText, getAllByText } = renderWithProvider( + , + store, + ); + + expect(getByText('Hello, \\u202E Bob!')).toBeInTheDocument(); + expect(getByText('Cow \\u202E Cow')).toBeInTheDocument(); + expect(getByText('Bob \\u202E Bob')).toBeInTheDocument(); + expect(getAllByText('Name\\u202Ename:')).toHaveLength(2); + expect(getAllByText('Wallets\\u202Ewallets:')).toHaveLength(2); + }); }); }); diff --git a/ui/helpers/utils/util.js b/ui/helpers/utils/util.js index 1dc1d9274..05befbe17 100644 --- a/ui/helpers/utils/util.js +++ b/ui/helpers/utils/util.js @@ -5,10 +5,8 @@ import * as ethUtil from 'ethereumjs-util'; import { DateTime } from 'luxon'; import { getFormattedIpfsUrl } from '@metamask/assets-controllers'; import slip44 from '@metamask/slip44'; +import * as lodash from 'lodash'; import bowser from 'bowser'; -///: BEGIN:ONLY_INCLUDE_IN(flask) -import { isEqual } from 'lodash'; -///: END:ONLY_INCLUDE_IN import { CHAIN_IDS } from '../../../shared/constants/network'; import { toChecksumHexAddress, @@ -540,9 +538,27 @@ export function isNullish(value) { export function getSnapDerivationPathName(path, curve) { const pathMetadata = SNAPS_DERIVATION_PATHS.find( (derivationPath) => - derivationPath.curve === curve && isEqual(derivationPath.path, path), + derivationPath.curve === curve && + lodash.isEqual(derivationPath.path, path), ); return pathMetadata?.name ?? null; } ///: END:ONLY_INCLUDE_IN + +/** + * The method escape RTL character in string + * + * @param {any} value + * @returns {(string|*)} escaped string or original param value + */ +export const sanitizeString = (value) => { + if (!value) { + return value; + } + if (!lodash.isString(value)) { + return value; + } + const regex = /\u202E/giu; + return value.replaceAll(regex, '\\u202E'); +}; diff --git a/ui/hooks/useTransactionDisplayData.test.js b/ui/hooks/useTransactionDisplayData.test.js index 970ee1b4e..e61ee354d 100644 --- a/ui/hooks/useTransactionDisplayData.test.js +++ b/ui/hooks/useTransactionDisplayData.test.js @@ -20,6 +20,7 @@ import { TransactionGroupCategory, TransactionStatus, } from '../../shared/constants/transaction'; +import { formatDateWithYearContext } from '../helpers/utils/util'; import * as i18nhooks from './useI18nContext'; import * as useTokenFiatAmountHooks from './useTokenFiatAmount'; import { useTransactionDisplayData } from './useTransactionDisplayData'; @@ -30,7 +31,7 @@ const expectedResults = [ category: TransactionGroupCategory.send, subtitle: 'To: 0xffe...1a97', subtitleContainsOrigin: false, - date: 'May 12, 2020', + date: formatDateWithYearContext(1589314601567), primaryCurrency: '-1 ETH', senderAddress: '0x9eca64466f257793eaa52fcfff5066894b76a149', recipientAddress: '0xffe5bc4e8f1f969934d773fa67da095d2e491a97', @@ -44,7 +45,7 @@ const expectedResults = [ category: TransactionGroupCategory.send, subtitle: 'To: 0x0cc...8848', subtitleContainsOrigin: false, - date: 'May 12, 2020', + date: formatDateWithYearContext(1589314355872), primaryCurrency: '-2 ETH', senderAddress: '0x9eca64466f257793eaa52fcfff5066894b76a149', recipientAddress: '0x0ccc8aeeaf5ce790f3b448325981a143fdef8848', @@ -57,7 +58,7 @@ const expectedResults = [ category: TransactionGroupCategory.send, subtitle: 'To: 0xffe...1a97', subtitleContainsOrigin: false, - date: 'May 12, 2020', + date: formatDateWithYearContext(1589314345433), primaryCurrency: '-2 ETH', senderAddress: '0x9eca64466f257793eaa52fcfff5066894b76a149', recipientAddress: '0xffe5bc4e8f1f969934d773fa67da095d2e491a97', @@ -70,7 +71,7 @@ const expectedResults = [ category: TransactionGroupCategory.receive, subtitle: 'From: 0x31b...4523', subtitleContainsOrigin: false, - date: 'May 12, 2020', + date: formatDateWithYearContext(1589314295000), primaryCurrency: '18.75 ETH', senderAddress: '0x31b98d14007bdee637298086988a0bbd31184523', recipientAddress: '0x9eca64466f257793eaa52fcfff5066894b76a149', @@ -83,7 +84,7 @@ const expectedResults = [ category: TransactionGroupCategory.receive, subtitle: 'From: 0x9ec...a149', subtitleContainsOrigin: false, - date: 'May 8, 2020', + date: formatDateWithYearContext(1588972833000), primaryCurrency: '0 ETH', senderAddress: '0x9eca64466f257793eaa52fcfff5066894b76a149', recipientAddress: '0x9eca64466f257793eaa52fcfff5066894b76a149', @@ -96,7 +97,7 @@ const expectedResults = [ category: TransactionGroupCategory.receive, subtitle: 'From: 0xee0...febb', subtitleContainsOrigin: false, - date: 'May 24, 2020', + date: formatDateWithYearContext(1585087013000), primaryCurrency: '1 ETH', senderAddress: '0xee014609ef9e09776ac5fe00bdbfef57bcdefebb', recipientAddress: '0x9eca64466f257793eaa52fcfff5066894b76a149', @@ -109,7 +110,7 @@ const expectedResults = [ category: TransactionType.swap, subtitle: '', subtitleContainsOrigin: false, - date: 'May 12, 2020', + date: formatDateWithYearContext(1585088013000), primaryCurrency: '+1 ABC', senderAddress: '0xee014609ef9e09776ac5fe00bdbfef57bcdefebb', recipientAddress: '0xabca64466f257793eaa52fcfff5066894b76a149', @@ -122,7 +123,7 @@ const expectedResults = [ category: TransactionGroupCategory.interaction, subtitle: 'metamask.github.io', subtitleContainsOrigin: true, - date: 'May 12, 2020', + date: formatDateWithYearContext(1585088013000), primaryCurrency: '-0 ETH', senderAddress: '0xee014609ef9e09776ac5fe00bdbfef57bcdefebb', recipientAddress: undefined,