From 4805c18664ba219ddcc2afa28a840b5a9c38446a Mon Sep 17 00:00:00 2001 From: Csillag Kristof Date: Tue, 4 Jul 2023 16:51:16 +0200 Subject: [PATCH] Add check against sending menmonics to search --- .changelog/656.feature.md | 1 + src/app/components/Search/index.tsx | 6 ++++++ .../components/Search/privacy-protection.ts | 18 ++++++++++++++++++ src/app/components/Search/search-utils.ts | 8 +++++--- src/locales/en/translation.json | 3 ++- 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 .changelog/656.feature.md create mode 100644 src/app/components/Search/privacy-protection.ts diff --git a/.changelog/656.feature.md b/.changelog/656.feature.md new file mode 100644 index 0000000000..c616d0d818 --- /dev/null +++ b/.changelog/656.feature.md @@ -0,0 +1 @@ +Add check against sending menmonics to search diff --git a/src/app/components/Search/index.tsx b/src/app/components/Search/index.tsx index d1beaa3169..9be88c8e43 100644 --- a/src/app/components/Search/index.tsx +++ b/src/app/components/Search/index.tsx @@ -20,6 +20,7 @@ import { exhaustedTypeWarning } from '../../../types/errors' import { TFunction } from 'i18next' import { NotificationBox } from '../../pages/SearchResultsPage/notifications' import { testnetTheme } from '../../../styles/theme' +import { wordsOfPower } from './privacy-protection' export type SearchVariant = 'button' | 'icon' | 'expandable' @@ -106,6 +107,11 @@ const decodeSearchErrorCode = (code: SearchErrorCode, t: TFunction): string => { switch (code) { case 'TOO_SHORT': return t('search.error.tooShort') + case 'PRIVACY': + return t('search.error.privacy', { + appName: t('pageTitle'), + wordsOfPower, + }) default: exhaustedTypeWarning('Unexpected search error code', code) return code diff --git a/src/app/components/Search/privacy-protection.ts b/src/app/components/Search/privacy-protection.ts new file mode 100644 index 0000000000..b95f6f80c8 --- /dev/null +++ b/src/app/components/Search/privacy-protection.ts @@ -0,0 +1,18 @@ +import { SearchError } from './search-utils' +import { isValidMnemonic } from '../../utils/helpers' + +/** + * Try to determine whether a search term is safe to send over to the server + */ +export const isSafeToSend = (searchTerm: string): boolean => !isValidMnemonic(searchTerm) + +export const wordsOfPower = 'I COMMAND THEE TO SEARCH FOR' + +export const checkForSearchPrivacyProtection = (searchTerm: string): string | undefined => { + if (!!wordsOfPower && searchTerm.toLowerCase().startsWith(wordsOfPower.toLowerCase())) { + return searchTerm.substring(wordsOfPower.length).trim().toLowerCase() + } else if (isSafeToSend(searchTerm)) { + return searchTerm.toLowerCase() + } + throw new SearchError('PRIVACY') +} diff --git a/src/app/components/Search/search-utils.ts b/src/app/components/Search/search-utils.ts index cdcce6006f..5f04a321bc 100644 --- a/src/app/components/Search/search-utils.ts +++ b/src/app/components/Search/search-utils.ts @@ -11,6 +11,7 @@ import { Network } from '../../../types/network' import { RouteUtils, SpecifiedPerEnabledLayer } from '../../utils/route-utils' import { AppError, AppErrors } from '../../../types/errors' import { Layer } from '../../../oasis-nexus/api' +import { checkForSearchPrivacyProtection } from './privacy-protection' type LayerSuggestions = { suggestedBlock: string @@ -19,7 +20,7 @@ type LayerSuggestions = { suggestedTokenFragment: string } -export type SearchErrorCode = 'TOO_SHORT' +export type SearchErrorCode = 'TOO_SHORT' | 'PRIVACY' export class SearchError extends Error { // eslint-disable-next-line @typescript-eslint/no-useless-constructor @@ -99,10 +100,11 @@ export const validateAndNormalize = { } }, evmTokenNameFragment: (searchTerm: string) => { - if (searchTerm.length < 3) { + const term = checkForSearchPrivacyProtection(searchTerm) + if (!!term && term.length < 3) { throw new SearchError('TOO_SHORT') } - return searchTerm + return term }, } satisfies Record string | undefined> diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 1b2e20e686..6987822300 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -365,7 +365,8 @@ "search": { "placeholder": "Address, Block, Contract, Txn Hash, Transaction ID, Token name, etc", "error": { - "tooShort": "Please enter at least 3 characters for a full-text search!" + "tooShort": "Please enter at least 3 characters for a full-text search!", + "privacy": "This thing that you are trying to search for looks an awful lot like a mnemonic for an Oasis wallet. Please note that this is super-secret data that should never ever be shared with anyone; not even with such excellent services as our {{ appName }}. That being said, we are not here to tell you what you can or can not do with your own data, so if you insist, we WILL search for it. So, if you really think that there is a token with a name that contains this, then in order to signify that you understand and accept the terrible risk of sending this data to our servers, please insert this to the beginning of your search: '{{ wordsOfPower }}'! (Without quotation marks, of course.) If you do so, we will comply with your command." }, "mobilePlaceholder": "Search Address, Block, Txn, Token, etc", "noResults": {