1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 01:47:00 +01:00

Security and Privacy Settings Re-org (#16756)

This commit is contained in:
Olusegun Akintayo 2022-12-19 18:46:36 +01:00 committed by GitHub
parent 22fc60a341
commit 13de51e748
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1143 additions and 731 deletions

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "Ungültige Eingabe! Die geheime Wiederherstellungsphrase berücksichtigt Groß- und Kleinschreibung."
},
"ipfsGateway": {
"message": "IPFS-Gateway"
},
"ipfsGatewayDescription": {
"message": "Geben Sie die URL des IPFS CID Gateways ein, das für die Auflösung der ENS Inhalte verwendet werden soll."
},
"jazzAndBlockies": {
"message": "Jazzicons und Blockies sind zwei verschiedene Arten von einzigartigen Symbolen, mit denen Sie ein Konto auf einen Blick erkennen können."
},
@ -3021,7 +3015,8 @@
"message": "Eingehende Transaktionen anzeigen"
},
"showIncomingTransactionsDescription": {
"message": "Aktivieren Sie dies, um Etherscan zu aktivieren und eingehende Transaktionen in der Transaktionsliste anzuzeigen"
"message": "Aktivieren Sie dies, um Etherscan zu aktivieren und eingehende Transaktionen in der Transaktionsliste anzuzeigen",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Berechtigungen anzeigen"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "Μη έγκυρη εισαγωγή! Η Μυστική σας Φράση Ανάκτησης κάνει διάκριση πεζών-κεφαλαίων."
},
"ipfsGateway": {
"message": "Πύλη IPFS"
},
"ipfsGatewayDescription": {
"message": "Εισάγετε τη διεύθυνση URL της πύλης IPFS CID που θα χρησιμοποιηθεί για την ανάλυση περιεχομένου ENS."
},
"jazzAndBlockies": {
"message": "Τα Jazzicons και τα Blockies είναι δύο διαφορετικά στυλ μοναδικών εικονιδίων που σας βοηθούν να αναγνωρίζετε έναν λογαριασμό με μια ματιά."
},
@ -3021,7 +3015,8 @@
"message": "Εμφάνιση Εισερχομένων Συναλλαγών"
},
"showIncomingTransactionsDescription": {
"message": "Επιλέξτε αυτό για να χρησιμοποιήσετε Etherscan για να εμφανίσετε τις εισερχόμενες συναλλαγές στη λίστα συναλλαγών"
"message": "Επιλέξτε αυτό για να χρησιμοποιήσετε Etherscan για να εμφανίσετε τις εισερχόμενες συναλλαγές στη λίστα συναλλαγών",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Εμφάνιση δικαιωμάτων"

View File

@ -183,6 +183,15 @@
"addContact": {
"message": "Add contact"
},
"addCustomIPFSGateway": {
"message": "Add custom IPFS gateway"
},
"addCustomIPFSGatewayDescription": {
"message": "The IPFS gateway makes it possible to access and view data hosted by third parties. You can add a custom IPFS gateway or continue using the default."
},
"addCustomNetwork": {
"message": "Add custom network"
},
"addCustomToken": {
"message": "Add custom token"
},
@ -415,6 +424,13 @@
"authorizedPermissions": {
"message": "You have authorized the following permissions"
},
"autoDetectTokens": {
"message": "Autodetect tokens"
},
"autoDetectTokensDescription": {
"message": "We use third-party APIs to detect and display new tokens sent to your wallet. Turn off if you dont want the app to pull data from those services. $1",
"description": "$1 is a link to a support article"
},
"autoLockTimeLimit": {
"message": "Auto-lock timer (minutes)"
},
@ -639,6 +655,13 @@
"message": "The network with chain ID $1 may use a different currency symbol ($2) than the one you have entered. Please verify before continuing.",
"description": "$1 is the chain id currently entered in the network form and $2 is the return value of nativeCurrency.symbol from chainlist.network"
},
"chooseYourNetwork": {
"message": "Choose your network"
},
"chooseYourNetworkDescription": {
"message": "We use Infura as our remote procedure call (RPC) provider to offer the most reliable and private access to Ethereum data we can. You can choose your own RPC, but remember that any RPC will receive your IP address and Ethereum wallet to make transactions. Read our $1 to learn more about how Infura handles data.",
"description": "$1 is a link to the privacy policy"
},
"chromeRequiredForHardwareWallets": {
"message": "You need to use MetaMask on Google Chrome in order to connect to your Hardware Wallet."
},
@ -1797,12 +1820,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "Invalid input! Secret Recovery Phrase is case sensitive."
},
"ipfsGateway": {
"message": "IPFS Gateway"
},
"ipfsGatewayDescription": {
"message": "Enter the URL of the IPFS CID gateway to use for ENS content resolution."
},
"jazzAndBlockies": {
"message": "Jazzicons and Blockies are two different styles of unique icons that help you identify an account at a glance."
},
@ -2159,6 +2176,9 @@
"networkNameTestnet": {
"message": "Testnet"
},
"networkProvider": {
"message": "Network provider"
},
"networkSettingsChainIdDescription": {
"message": "The chain ID is used for signing transactions. It must match the chain ID returned by the network. You can enter a decimal or '0x'-prefixed hexadecimal number, but we will display the number in decimal."
},
@ -2857,6 +2877,9 @@
"priorityFeeProperCase": {
"message": "Priority Fee"
},
"privacy": {
"message": "Privacy"
},
"privacyMsg": {
"message": "Privacy policy"
},
@ -3123,6 +3146,9 @@
"secureWallet": {
"message": "Secure wallet"
},
"security": {
"message": "Security"
},
"securityAndPrivacy": {
"message": "Security & privacy"
},
@ -3295,7 +3321,8 @@
"message": "Show incoming transactions"
},
"showIncomingTransactionsDescription": {
"message": "Select this to use Etherscan to show incoming transactions in the transactions list"
"message": "This relies on $1 which will have access to your Ethereum address and your IP address. $2",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Show permissions"
@ -4104,6 +4131,9 @@
"tokenList": {
"message": "Token lists:"
},
"tokenNftAutoDetection": {
"message": "Token and NFT autodetection"
},
"tokenScamSecurityRisk": {
"message": "token scams and security risks"
},
@ -4231,6 +4261,9 @@
"transactionUpdated": {
"message": "Transaction updated at $2."
},
"transactions": {
"message": "Transactions"
},
"transfer": {
"message": "Transfer"
},
@ -4346,7 +4379,16 @@
"message": "Autodetect NFTs"
},
"useCollectibleDetectionDescription": {
"message": "Displaying NFTs media & data may expose your IP address to centralized servers. Third-party APIs (like OpenSea) are used to detect NFTs in your wallet. This exposes your account address with those services. Leave this disabled if you dont want the app to pull data from those those services."
"message": "We use third-party APIs to detect NFTs in your wallet, which means your IP address may be exposed to their servers. Leave this feature off if you don't want the app to pull data from those services."
},
"useCollectibleDetectionDescriptionLine2": {
"message": "Additionally, be aware that:"
},
"useCollectibleDetectionDescriptionLine3": {
"message": "NFT metadata may contain links to scams or phishing sites."
},
"useCollectibleDetectionDescriptionLine4": {
"message": "Anyone can airdrop NFTs to your account. This can include offensive content that might be automatically displayed in your wallet."
},
"useDefault": {
"message": "Use default"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "¡Entrada inválida! La frase secreta de recuperación distingue entre mayúsculas y minúsculas."
},
"ipfsGateway": {
"message": "Puerta de enlace de IPFS"
},
"ipfsGatewayDescription": {
"message": "Escriba la dirección URL de la puerta de enlace de IPFS CID para usar la resolución de contenido de ENS."
},
"jazzAndBlockies": {
"message": "Jazzicons y Blockies son dos estilos distintos de íconos únicos que pueden ayudarlo a identificar rápidamente una cuenta."
},
@ -3021,7 +3015,8 @@
"message": "Mostrar transacciones entrantes"
},
"showIncomingTransactionsDescription": {
"message": "Seleccione esta opción para usar Etherscan para mostrar las transacciones entrantes en la lista de transacciones"
"message": "Seleccione esta opción para usar Etherscan para mostrar las transacciones entrantes en la lista de transacciones",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Mostrar permisos"

View File

@ -1312,12 +1312,6 @@
"invalidSeedPhrase": {
"message": "Frase secreta de recuperación no válida"
},
"ipfsGateway": {
"message": "Puerta de enlace de IPFS"
},
"ipfsGatewayDescription": {
"message": "Escriba la dirección URL de la puerta de enlace de IPFS CID para usar la resolución de contenido de ENS."
},
"jsDeliver": {
"message": "jsDeliver"
},
@ -2310,7 +2304,8 @@
"message": "Mostrar transacciones entrantes"
},
"showIncomingTransactionsDescription": {
"message": "Seleccione esta opción para usar Etherscan para mostrar las transacciones entrantes en la lista de transacciones"
"message": "Seleccione esta opción para usar Etherscan para mostrar las transacciones entrantes en la lista de transacciones",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Mostrar permisos"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "Entrée invalide ! La phrase secrète de récupération est sensible à la casse."
},
"ipfsGateway": {
"message": "Passerelle IPFS"
},
"ipfsGatewayDescription": {
"message": "Entrez lURL de la passerelle CID IPFS à utiliser pour résoudre les contenus ENS."
},
"jazzAndBlockies": {
"message": "Les Jazzicons et les Blockies sont deux styles différents dicônes uniques qui vous aident à identifier un compte en un coup dœil."
},
@ -3021,7 +3015,8 @@
"message": "Afficher les transactions entrantes"
},
"showIncomingTransactionsDescription": {
"message": "Sélectionnez ceci pour utiliser Etherscan afin dafficher les transactions entrantes dans la liste des transactions"
"message": "Sélectionnez ceci pour utiliser Etherscan afin dafficher les transactions entrantes dans la liste des transactions",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Afficher les autorisations"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "अमान्य निवेश! गुप्त पुनर्प्राप्ति वाक्यांश केस संवेदी है।"
},
"ipfsGateway": {
"message": "IPFS गेटवे"
},
"ipfsGatewayDescription": {
"message": "ENS सामग्री रिजॉल्यूशन का उपयोग करने के लिए IPFS CID गेटवे का URL दर्ज करें।"
},
"jazzAndBlockies": {
"message": "जाज़िकॉन्स और ब्लॉकीज़ विशिष्ट आइकनों की दो अलग-अलग शैलियां हैं जो आपको एक नज़र में किसी अकाउंट की पहचान करने में मदद करती हैं।"
},
@ -3021,7 +3015,8 @@
"message": "आने वाले लेन-देन दिखाएं"
},
"showIncomingTransactionsDescription": {
"message": "लेनदेन सूची में आने वाले लेनदेन को दिखाने के लिए Etherscan का उपयोग करने के लिए इसका चयन करें"
"message": "लेनदेन सूची में आने वाले लेनदेन को दिखाने के लिए Etherscan का उपयोग करने के लिए इसका चयन करें",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "अनुमतियां दिखाएं"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "Masukan tidak valid! Frasa Pemulihan Rahasia peka terhadap huruf besar/kecil."
},
"ipfsGateway": {
"message": "Gateway IPFS"
},
"ipfsGatewayDescription": {
"message": "Masukkan URL gateway CID IPFS dan gunakan untuk resolusi konten ENS."
},
"jazzAndBlockies": {
"message": "Jazzicons dan Blockies merupakan dua gaya ikon unik yang berbeda untuk membantu Anda mengidentifikasi akun dengan cepat."
},
@ -3021,7 +3015,8 @@
"message": "Tampilkan transaksi masuk"
},
"showIncomingTransactionsDescription": {
"message": "Pilih ini untuk menggunakan Etherscan untuk menampilkan transaksi yang masuk di daftar transaksi"
"message": "Pilih ini untuk menggunakan Etherscan untuk menampilkan transaksi yang masuk di daftar transaksi",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Tampilkan Izin"

View File

@ -1269,12 +1269,6 @@
"invalidSeedPhrase": {
"message": "Frase seed non valida"
},
"ipfsGateway": {
"message": "Portale IPFS"
},
"ipfsGatewayDescription": {
"message": "Inserisci l'URL del portale IPFS CID da usare per la risoluzione del contenuto ENS."
},
"jsonFile": {
"message": "File JSON",
"description": "format for importing an account"
@ -1733,7 +1727,8 @@
"message": "Mostra Transazioni in Ingresso"
},
"showIncomingTransactionsDescription": {
"message": "Usa Etherscan per visualizzare le transazioni in ingresso nella lista delle transazioni"
"message": "Usa Etherscan per visualizzare le transazioni in ingresso nella lista delle transazioni",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Mostra permessi"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "入力値が無効です!秘密のリカバリーフレーズは大文字・小文字が区別されます。"
},
"ipfsGateway": {
"message": "IPFSゲートウェイ"
},
"ipfsGatewayDescription": {
"message": "ENSコンテンツの解決に使用するIPFS CIDゲートウェイのURLを入力します。"
},
"jazzAndBlockies": {
"message": "Jazzicon と Blockie は、アカウントを一目で見分けるためのユニークなアイコンであり、2 つの異なるスタイルが特徴です。"
},
@ -3021,7 +3015,8 @@
"message": "受信トランザクションを表示"
},
"showIncomingTransactionsDescription": {
"message": "これを選択すると、Etherscanを使用して受信トランザクションがトランザクションリストに表示されます"
"message": "これを選択すると、Etherscanを使用して受信トランザクションがトランザクションリストに表示されます",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "表示許可"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "입력 오류: 비밀 복구 구문은 대소문자를 구분해야 합니다."
},
"ipfsGateway": {
"message": "IPFS 게이트웨이"
},
"ipfsGatewayDescription": {
"message": "ENS 콘텐츠 해결에 사용할 IPFS CID 게이트웨이의 URL을 입력하세요."
},
"jazzAndBlockies": {
"message": "Jazzicons와 Blockies는 계정을 한눈에 식별할 수 있게 도와주는 두 가지 고유한 아이콘 스타일입니다."
},
@ -3021,7 +3015,8 @@
"message": "수신 거래 표시"
},
"showIncomingTransactionsDescription": {
"message": "이 항목을 선택하면 Etherscan을 사용해 거래 목록에 수신 거래를 표시할 수 있습니다."
"message": "이 항목을 선택하면 Etherscan을 사용해 거래 목록에 수신 거래를 표시할 수 있습니다.",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "권한 표시"

View File

@ -878,12 +878,6 @@
"invalidSeedPhrase": {
"message": "Invalid na Secret Recovery Phrase"
},
"ipfsGateway": {
"message": "IPFS Gateway"
},
"ipfsGatewayDescription": {
"message": "Ilagay ang URL ng IPFS CID gateway para magamit para sa resolusyon ng content ng ENS."
},
"jsonFile": {
"message": "JSON File",
"description": "format for importing an account"
@ -1532,7 +1526,8 @@
"message": "Ipakita ang Mga Papasok na Transaksyon"
},
"showIncomingTransactionsDescription": {
"message": "Piliin ito para gamitin ang Etherscan sa pagpapakita ng mga papasok na transaksyon sa listahan ng mga transaksyon"
"message": "Piliin ito para gamitin ang Etherscan sa pagpapakita ng mga papasok na transaksyon sa listahan ng mga transaksyon",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Ipakita ang mga pahintulot"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "Entrada inválida! A frase secreta de recuperação diferencia maiúsculas e minúsculas."
},
"ipfsGateway": {
"message": "Gateway IPFS"
},
"ipfsGatewayDescription": {
"message": "Informe o URL do gateway de CID do IPFS para usar com resolução de conteúdo de ENS."
},
"jazzAndBlockies": {
"message": "Jazzicons e Blockies são dois estilos diferentes de ícones únicos que ajudam você a identificar uma conta num relance."
},
@ -3021,7 +3015,8 @@
"message": "Mostrar transações recebidas"
},
"showIncomingTransactionsDescription": {
"message": "Selecione essa opção para usar o Etherscan e mostrar as transações recebidas na lista de transações"
"message": "Selecione essa opção para usar o Etherscan e mostrar as transações recebidas na lista de transações",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Mostrar permissões"

View File

@ -1312,12 +1312,6 @@
"invalidSeedPhrase": {
"message": "Frase de Recuperação Secreta inválida"
},
"ipfsGateway": {
"message": "Gateway IPFS"
},
"ipfsGatewayDescription": {
"message": "Informe o URL do gateway de CID do IPFS para usar com resolução de conteúdo de ENS."
},
"jsDeliver": {
"message": "jsDeliver"
},
@ -2310,7 +2304,8 @@
"message": "Mostrar transações recebidas"
},
"showIncomingTransactionsDescription": {
"message": "Selecione essa opção para usar o Etherscan e mostrar as transações recebidas na lista de transações"
"message": "Selecione essa opção para usar o Etherscan e mostrar as transações recebidas na lista de transações",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Mostrar permissões"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "Неправильный ввод! Секретная фраза для восстановления чувствительна к регистру."
},
"ipfsGateway": {
"message": "Шлюз IPFS"
},
"ipfsGatewayDescription": {
"message": "Введите URL-адрес шлюза IPFS CID, который будет использоваться для разрешения содержимого ENS."
},
"jazzAndBlockies": {
"message": "«Джазиконы» и «Блокиз» — это два разных стиля уникальных значков, которые помогут вам с первого взгляда идентифицировать свой счет."
},
@ -3021,7 +3015,8 @@
"message": "Показать входящие транзакции"
},
"showIncomingTransactionsDescription": {
"message": "Выберите это, чтобы использовать Etherscan для отображения входящих транзакций в списке транзакций"
"message": "Выберите это, чтобы использовать Etherscan для отображения входящих транзакций в списке транзакций",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Показать разрешения"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "Di-wastong input! Ang Secret Recovery Phrase ay case sensitive."
},
"ipfsGateway": {
"message": "Gateway na IPFS"
},
"ipfsGatewayDescription": {
"message": "Ilagay ang URL ng IPFS CID gateway para magamit para sa resolusyon ng content ng ENS."
},
"jazzAndBlockies": {
"message": "Ang Jazzicons at Blockies ay dalawang magkaibang istilo ng mga natatanging icon na makakatulong sa iyong matukoy ang account sa isang sulyap."
},
@ -3021,7 +3015,8 @@
"message": "Ipakita ang Mga Papasok na Transaksyon"
},
"showIncomingTransactionsDescription": {
"message": "Piliin ito para gamitin ang Etherscan sa pagpapakita ng mga papasok na transaksyon sa listahan ng mga transaksyon"
"message": "Piliin ito para gamitin ang Etherscan sa pagpapakita ng mga papasok na transaksyon sa listahan ng mga transaksyon",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Ipakita ang mga pahintulot"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "Giriş geçersiz! Gizli Kurtarma İfadesi büyük/küçük harf duyarlıdır."
},
"ipfsGateway": {
"message": "IPFS Ağ Geçidi"
},
"ipfsGatewayDescription": {
"message": "ENS içerik çözünürlüğünde kullanmak için IPFS CID ağ geçidi URL adresini girin."
},
"jazzAndBlockies": {
"message": "Jazzicons ve Blockies, bir bakışta bir hesabı tanımlamana yardımcı olan iki farklı benzersiz simge stilidir."
},
@ -3021,7 +3015,8 @@
"message": "Gelen İşlemleri Göster"
},
"showIncomingTransactionsDescription": {
"message": "Etherscan'in işlemler listesinde gelecek işlemleri göstermesi için bunu seçin"
"message": "Etherscan'in işlemler listesinde gelecek işlemleri göstermesi için bunu seçin",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "İzinleri göster"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "Nội dung nhập không hợp lệ! Cụm từ khôi phục bí mật phân biệt chữ hoa và chữ thường."
},
"ipfsGateway": {
"message": "Cổng kết nối IPFS"
},
"ipfsGatewayDescription": {
"message": "Nhập URL của cổng kết nối IPFS CID để dùng cho quá trình phân giải nội dung ENS."
},
"jazzAndBlockies": {
"message": "Jazzicons và Blockies là hai kiểu biểu tượng độc nhất khác nhau giúp bạn nhận ra tài khoản trong nháy mắt."
},
@ -3021,7 +3015,8 @@
"message": "Hiển thị các giao dịch đến"
},
"showIncomingTransactionsDescription": {
"message": "Chọn tùy chọn này nếu bạn muốn dùng Etherscan để hiển thị các giao dịch đến trong danh sách giao dịch"
"message": "Chọn tùy chọn này nếu bạn muốn dùng Etherscan để hiển thị các giao dịch đến trong danh sách giao dịch",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "Hiển thị quyền"

View File

@ -1676,12 +1676,6 @@
"invalidSeedPhraseCaseSensitive": {
"message": "输入无效!助记词须区分大小写。"
},
"ipfsGateway": {
"message": "IPFS 网关"
},
"ipfsGatewayDescription": {
"message": "输入用于 ENS 内容解析的 IPFS CID 网关的 URL。"
},
"jazzAndBlockies": {
"message": "哈希头像是帮助您一眼识别账户的独特图标,有 Jazzicons 和 Blockies 两种不同风格。"
},
@ -3021,7 +3015,8 @@
"message": "显示传入的交易"
},
"showIncomingTransactionsDescription": {
"message": "选择此项以使用 Etherscan 在交易列表中显示传入的交易"
"message": "选择此项以使用 Etherscan 在交易列表中显示传入的交易",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "显示权限"

View File

@ -883,9 +883,6 @@
"invalidSeedPhrase": {
"message": "無效的助憶詞"
},
"ipfsGatewayDescription": {
"message": "輸入用於解析 ENS 內容的 IPFS CID gateway URL。"
},
"jsonFile": {
"message": "JSON 格式檔案",
"description": "format for importing an account"
@ -1421,7 +1418,8 @@
"message": "顯示傳入的交易"
},
"showIncomingTransactionsDescription": {
"message": "選擇此項來利用 Etherscan 在交易列表裡顯示傳入的交易"
"message": "選擇此項來利用 Etherscan 在交易列表裡顯示傳入的交易",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showPermissions": {
"message": "顯示權限"

View File

@ -130,8 +130,7 @@ export default class PreferencesController {
/**
* Setter for the `useMultiAccountBalanceChecker` property
*
* @param {boolean} val - Whether or not the user wants to fetch balances for
* all accounts that he has added to the MetaMask wallet state.
* @param {boolean} val - Whether or not the user prefers to turn off/on all security settings
*/
setUseMultiAccountBalanceChecker(val) {
this.store.updateState({ useMultiAccountBalanceChecker: val });

View File

@ -246,3 +246,10 @@ export function previousValueComparator(comparator, initialValue) {
}
};
}
export function addUrlProtocolPrefix(urlString) {
if (!urlString.match(/(^http:\/\/)|(^https:\/\/)/u)) {
return `https://${urlString}`;
}
return urlString;
}

View File

@ -300,6 +300,14 @@ export const EVENT_NAMES = {
KEY_EXPORT_CANCELED: 'Key Export Canceled',
KEY_EXPORT_REVEALED: 'Key Material Revealed',
KEY_EXPORT_COPIED: 'Key Material Copied',
KEY_TOKEN_DETECTION_SELECTED: 'Key Token Detection Selected',
KEY_GLOBAL_SECURITY_TOGGLE_SELECTED: 'Key Global Security/Privacy Settings',
KEY_BALANCE_TOKEN_PRICE_CHECKER:
'Key Show Balance and Token Price Checker Settings',
KEY_GAS_FEE_ESTIMATION_BUY_SWAP_TOKENS:
'Key Show Gas Fee Estimation, Buy Crypto and Swap Tokens',
KEY_AUTO_DETECT_TOKENS: 'Key Autodetect tokens',
KEY_BATCH_ACCOUNT_BALANCE_REQUESTS: 'Key Batch account balance requests',
METRICS_OPT_IN: 'Metrics Opt In',
METRICS_OPT_OUT: 'Metrics Opt Out',
NAV_ACCOUNT_MENU_OPENED: 'Account Menu Opened',

View File

@ -5,3 +5,8 @@ _supportLink = 'https://metamask-flask.zendesk.com/hc';
///: END:ONLY_INCLUDE_IN
export const SUPPORT_LINK = _supportLink;
// TODO make sure these links are correct
export const ETHERSCAN_PRIVACY_LINK = 'https://etherscan.io/privacyPolicy';
export const CONSENSYS_PRIVACY_LINK = 'https://consensys.net/privacy-policy/';
export const AUTO_DETECT_TOKEN_LEARN_MORE_LINK =
'https://consensys.net/privacy-policy/';

View File

@ -238,6 +238,7 @@ function defaultFixture() {
useNonceField: false,
usePhishDetect: true,
useTokenDetection: false,
useMultiAccountBalanceChecker: true,
},
SmartTransactionsController: {
smartTransactionsState: {
@ -350,6 +351,7 @@ function onboardingFixture() {
useNonceField: false,
usePhishDetect: true,
useTokenDetection: false,
useMultiAccountBalanceChecker: true,
},
SmartTransactionsController: {
smartTransactionsState: {

View File

@ -45,6 +45,7 @@
"useNftDetection": false,
"useNonceField": false,
"usePhishDetect": true,
"useTokenDetection": false
"useTokenDetection": false,
"useMultiAccountBalanceChecker": true
}
}

View File

@ -49,7 +49,7 @@ function getActionFunctionById(id, history) {
},
10: () => {
updateViewedNotifications({ 10: true });
history.push(`${ADVANCED_ROUTE}#token-description`);
history.push(`${SECURITY_ROUTE}#token-description`);
},
12: () => {
updateViewedNotifications({ 12: true });

View File

@ -118,13 +118,6 @@ export const SETTINGS_CONSTANTS = [
route: `${ADVANCED_ROUTE}#autolock-timer`,
icon: 'fas fa-sliders-h',
},
{
tabMessage: (t) => t('advanced'),
sectionMessage: (t) => t('ipfsGateway'),
descriptionMessage: (t) => t('ipfsGatewayDescription'),
route: `${ADVANCED_ROUTE}#ipfs-gateway`,
icon: 'fas fa-sliders-h',
},
{
tabMessage: (t) => t('advanced'),
sectionMessage: (t) => t('preferredLedgerConnectionType'),
@ -183,13 +176,49 @@ export const SETTINGS_CONSTANTS = [
route: `${SECURITY_ROUTE}#metrametrics`,
icon: 'fa fa-lock',
},
{
tabMessage: (t) => t('securityAndPrivacy'),
sectionMessage: (t) => t('enhancedTokenDetection'),
descriptionMessage: (t) => t('enhancedTokenDetectionDescription'),
route: `${SECURITY_ROUTE}#token-description`,
icon: 'fas fa-sliders-h',
},
{
tabMessage: (t) => t('securityAndPrivacy'),
sectionMessage: (t) => t('chooseYourNetwork'),
descriptionMessage: (t) => t('chooseYourNetworkDescription'),
route: `${SECURITY_ROUTE}#-chose-your-network`,
icon: 'fa fa-lock',
},
{
tabMessage: (t) => t('securityAndPrivacy'),
sectionMessage: (t) => t('addCustomIPFSGateway'),
descriptionMessage: (t) => t('addCustomIPFSGatewayDescription'),
route: `${SECURITY_ROUTE}#-add-custom-ipfs-gateway`,
icon: 'fa fa-lock',
},
{
tabMessage: (t) => t('securityAndPrivacy'),
sectionMessage: (t) => t('autoDetectTokens'),
descriptionMessage: (t) => t('autoDetectTokensDescription'),
route: `${SECURITY_ROUTE}#-auto-detect-tokens`,
icon: 'fa fa-lock',
},
{
tabMessage: (t) => t('securityAndPrivacy'),
sectionMessage: (t) => t('useMultiAccountBalanceChecker'),
descriptionMessage: (t) => t('useMultiAccountBalanceCheckerDescription'),
route: `${SECURITY_ROUTE}#multi-account-balance-checker`,
route: `${SECURITY_ROUTE}#-use-milti-account-balance-checker`,
icon: 'fa fa-lock',
},
{
tabMessage: (t) => t('securityAndPrivacy'),
sectionMessage: (t) => t('useCollectibleDetection'),
descriptionMessage: (t) => t('useCollectibleDetectionDescription'),
route: `${SECURITY_ROUTE}#autodetect-nfts`,
icon: 'fa fa-flask',
featureFlag: 'COLLECTIBLES_V1',
},
{
tabMessage: (t) => t('alerts'),
sectionMessage: (t) => t('alertSettingsUnconnectedAccount'),
@ -314,14 +343,6 @@ export const SETTINGS_CONSTANTS = [
icon: 'fa fa-flask',
featureFlag: 'NFTS_V1',
},
{
tabMessage: (t) => t('experimental'),
sectionMessage: (t) => t('useCollectibleDetection'),
descriptionMessage: (t) => t('useCollectibleDetectionDescription'),
route: `${EXPERIMENTAL_ROUTE}#autodetect-nfts`,
icon: 'fa fa-flask',
featureFlag: 'NFTS_V1',
},
{
tabMessage: (t) => t('advanced'),
sectionMessage: (t) => t('backupUserData'),

View File

@ -155,7 +155,7 @@ describe('Settings Search Utils', () => {
});
it('should get good advanced section number', () => {
expect(getNumberOfSettingsInSection(t, t('advanced'))).toStrictEqual(15);
expect(getNumberOfSettingsInSection(t, t('advanced'))).toStrictEqual(14);
});
it('should get good contact section number', () => {
@ -165,7 +165,7 @@ describe('Settings Search Utils', () => {
it('should get good security & privacy section number', () => {
expect(
getNumberOfSettingsInSection(t, t('securityAndPrivacy')),
).toStrictEqual(5);
).toStrictEqual(9);
});
it('should get good alerts section number', () => {

View File

@ -10,7 +10,7 @@ import { tokenInfoGetter } from '../../helpers/utils/token-util';
import {
ADD_COLLECTIBLE_ROUTE,
CONFIRM_IMPORT_TOKEN_ROUTE,
ADVANCED_ROUTE,
SECURITY_ROUTE,
} from '../../helpers/constants/routes';
import TextField from '../../components/ui/text-field';
import PageContainer from '../../components/ui/page-container';
@ -445,7 +445,7 @@ class ImportToken extends Component {
key="import-token-token-detection-announcement"
className="import-token__link"
onClick={() =>
history.push(`${ADVANCED_ROUTE}#token-description`)
history.push(`${SECURITY_ROUTE}#token-description`)
}
>
{t('inYourSettings')}
@ -588,7 +588,7 @@ class ImportToken extends Component {
key="token-detection-announcement"
className="import-token__link"
onClick={() =>
history.push(`${ADVANCED_ROUTE}#token-description`)
history.push(`${SECURITY_ROUTE}#token-description`)
}
>
{t('enableFromSettings')}

View File

@ -14,7 +14,6 @@ import {
getNumberOfSettingsInSection,
handleSettingsRefs,
} from '../../../helpers/utils/settings-search';
import { addUrlProtocolPrefix } from '../../../helpers/utils/ipfs';
import {
LEDGER_TRANSPORT_TYPES,
@ -50,15 +49,11 @@ export default class AdvancedTab extends PureComponent {
setAutoLockTimeLimit: PropTypes.func.isRequired,
setShowFiatConversionOnTestnetsPreference: PropTypes.func.isRequired,
setShowTestNetworks: PropTypes.func.isRequired,
setIpfsGateway: PropTypes.func.isRequired,
ipfsGateway: PropTypes.string.isRequired,
ledgerTransportType: PropTypes.oneOf(Object.values(LEDGER_TRANSPORT_TYPES)),
setLedgerTransportPreference: PropTypes.func.isRequired,
setDismissSeedBackUpReminder: PropTypes.func.isRequired,
dismissSeedBackUpReminder: PropTypes.bool.isRequired,
userHasALedgerAccount: PropTypes.bool.isRequired,
useTokenDetection: PropTypes.bool.isRequired,
setUseTokenDetection: PropTypes.func.isRequired,
backupUserData: PropTypes.func.isRequired,
restoreUserData: PropTypes.func.isRequired,
};
@ -66,8 +61,6 @@ export default class AdvancedTab extends PureComponent {
state = {
autoLockTimeLimit: this.props.autoLockTimeLimit,
lockTimeError: '',
ipfsGateway: this.props.ipfsGateway,
ipfsGatewayError: '',
showLedgerTransportWarning: false,
showResultMessage: false,
restoreSuccessful: true,
@ -92,37 +85,6 @@ export default class AdvancedTab extends PureComponent {
handleSettingsRefs(t, t('advanced'), this.settingsRefs);
}
renderMobileSync() {
const { t } = this.context;
const { history } = this.props;
return (
<div
ref={this.settingsRefs[1]}
className="settings-page__content-row"
data-testid="advanced-setting-mobile-sync"
>
<div className="settings-page__content-item">
<span>{t('syncWithMobile')}</span>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<Button
type="secondary"
large
onClick={(event) => {
event.preventDefault();
history.push(MOBILE_SYNC_ROUTE);
}}
>
{t('syncWithMobile')}
</Button>
</div>
</div>
</div>
);
}
async getTextFromFile(file) {
return new Promise((resolve, reject) => {
const reader = new window.FileReader();
@ -172,68 +134,6 @@ export default class AdvancedTab extends PureComponent {
}
}
renderRestoreUserData() {
const { t } = this.context;
const { showResultMessage, restoreSuccessful, restoreMessage } = this.state;
const defaultRestoreMessage = restoreSuccessful
? t('restoreSuccessful')
: t('restoreFailed');
const restoreMessageToRender =
restoreMessage === CORRUPT_JSON_FILE
? t('dataBackupSeemsCorrupt')
: defaultRestoreMessage;
return (
<div
ref={this.settingsRefs[14]}
className="settings-page__content-row"
data-testid="advanced-setting-data-restore"
>
<div className="settings-page__content-item">
<span>{t('restoreUserData')}</span>
<span className="settings-page__content-description">
{t('restoreUserDataDescription')}
</span>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<label
htmlFor="restore-file"
className="button btn btn--rounded btn-secondary btn--large settings-page__button"
>
{t('restore')}
</label>
<input
id="restore-file"
data-testid="restore-file"
style={{ visibility: 'hidden' }}
type="file"
accept=".json"
onChange={(e) => this.handleFileUpload(e)}
/>
</div>
{showResultMessage && (
<ActionableMessage
type={restoreSuccessful ? 'success' : 'danger'}
message={restoreMessageToRender}
primaryActionV2={{
label: t('dismiss'),
onClick: () => {
this.setState({
showResultMessage: false,
restoreSuccessful: true,
restoreMessage: null,
});
},
}}
/>
)}
</div>
</div>
);
}
backupUserData = async () => {
const { fileName, data } = await this.props.backupUserData();
exportAsFile(fileName, data);
@ -245,36 +145,6 @@ export default class AdvancedTab extends PureComponent {
});
};
renderUserDataBackup() {
const { t } = this.context;
return (
<div
ref={this.settingsRefs[13]}
className="settings-page__content-row"
data-testid="advanced-setting-data-backup"
>
<div className="settings-page__content-item">
<span>{t('backupUserData')}</span>
<span className="settings-page__content-description">
{t('backupUserDataDescription')}
</span>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<Button
data-testid="backup-button"
type="secondary"
large
onClick={() => this.backupUserData()}
>
{t('backup')}
</Button>
</div>
</div>
</div>
);
}
renderStateLogs() {
const { t } = this.context;
const { displayWarning } = this.props;
@ -314,6 +184,37 @@ export default class AdvancedTab extends PureComponent {
);
}
renderMobileSync() {
const { t } = this.context;
const { history } = this.props;
return (
<div
ref={this.settingsRefs[1]}
className="settings-page__content-row"
data-testid="advanced-setting-mobile-sync"
>
<div className="settings-page__content-item">
<span>{t('syncWithMobile')}</span>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<Button
type="secondary"
large
onClick={(event) => {
event.preventDefault();
history.push(MOBILE_SYNC_ROUTE);
}}
>
{t('syncWithMobile')}
</Button>
</div>
</div>
</div>
);
}
renderResetAccount() {
const { t } = this.context;
const { showResetAccountConfirmationModal } = this.props;
@ -354,36 +255,6 @@ export default class AdvancedTab extends PureComponent {
);
}
renderHexDataOptIn() {
const { t } = this.context;
const { sendHexData, setHexDataFeatureFlag } = this.props;
return (
<div
ref={this.settingsRefs[4]}
className="settings-page__content-row"
data-testid="advanced-setting-hex-data"
>
<div className="settings-page__content-item">
<span>{t('showHexData')}</span>
<div className="settings-page__content-description">
{t('showHexDataDescription')}
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={sendHexData}
onToggle={(value) => setHexDataFeatureFlag(!value)}
offLabel={t('off')}
onLabel={t('on')}
/>
</div>
</div>
</div>
);
}
renderAdvancedGasInputInline() {
const { t } = this.context;
const { advancedInlineGas, setAdvancedInlineGasFeatureFlag } = this.props;
@ -414,27 +285,27 @@ export default class AdvancedTab extends PureComponent {
);
}
renderToggleTestNetworks() {
renderHexDataOptIn() {
const { t } = this.context;
const { showTestNetworks, setShowTestNetworks } = this.props;
const { sendHexData, setHexDataFeatureFlag } = this.props;
return (
<div
ref={this.settingsRefs[6]}
ref={this.settingsRefs[4]}
className="settings-page__content-row"
data-testid="advanced-setting-show-testnet-conversion"
data-testid="advanced-setting-hex-data"
>
<div className="settings-page__content-item">
<span>{t('showTestnetNetworks')}</span>
<span>{t('showHexData')}</span>
<div className="settings-page__content-description">
{t('showTestnetNetworksDescription')}
{t('showHexDataDescription')}
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={showTestNetworks}
onToggle={(value) => setShowTestNetworks(!value)}
value={sendHexData}
onToggle={(value) => setHexDataFeatureFlag(!value)}
offLabel={t('off')}
onLabel={t('on')}
/>
@ -477,6 +348,36 @@ export default class AdvancedTab extends PureComponent {
);
}
renderToggleTestNetworks() {
const { t } = this.context;
const { showTestNetworks, setShowTestNetworks } = this.props;
return (
<div
ref={this.settingsRefs[6]}
className="settings-page__content-row"
data-testid="advanced-setting-show-testnet-conversion"
>
<div className="settings-page__content-item">
<span>{t('showTestnetNetworks')}</span>
<div className="settings-page__content-description">
{t('showTestnetNetworksDescription')}
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={showTestNetworks}
onToggle={(value) => setShowTestNetworks(!value)}
offLabel={t('off')}
onLabel={t('on')}
/>
</div>
</div>
</div>
);
}
renderUseNonceOptIn() {
const { t } = this.context;
const { useNonceField, setUseNonceField } = this.props;
@ -507,24 +408,6 @@ export default class AdvancedTab extends PureComponent {
);
}
handleLockChange(time) {
const { t } = this.context;
const autoLockTimeLimit = Math.max(Number(time), 0);
this.setState(() => {
let lockTimeError = '';
if (autoLockTimeLimit > 10080) {
lockTimeError = t('lockTimeTooGreat');
}
return {
autoLockTimeLimit,
lockTimeError,
};
});
}
renderAutoLockTimeLimit() {
const { t } = this.context;
const { lockTimeError } = this.state;
@ -610,7 +493,7 @@ export default class AdvancedTab extends PureComponent {
: LEDGER_TRANSPORT_NAMES.U2F;
return (
<div ref={this.settingsRefs[10]} className="settings-page__content-row">
<div ref={this.settingsRefs[9]} className="settings-page__content-row">
<div className="settings-page__content-item">
<span>{t('preferredLedgerConnectionType')}</span>
<div className="settings-page__content-description">
@ -666,85 +549,6 @@ export default class AdvancedTab extends PureComponent {
);
}
handleIpfsGatewayChange(url) {
const { t } = this.context;
this.setState(() => {
let ipfsGatewayError = '';
try {
const urlObj = new URL(addUrlProtocolPrefix(url));
if (!urlObj.host) {
throw new Error();
}
// don't allow the use of this gateway
if (urlObj.host === 'gateway.ipfs.io') {
throw new Error('Forbidden gateway');
}
} catch (error) {
ipfsGatewayError =
error.message === 'Forbidden gateway'
? t('forbiddenIpfsGateway')
: t('invalidIpfsGateway');
}
return {
ipfsGateway: url,
ipfsGatewayError,
};
});
}
handleIpfsGatewaySave() {
const url = new URL(addUrlProtocolPrefix(this.state.ipfsGateway));
const { host } = url;
this.props.setIpfsGateway(host);
}
renderIpfsGatewayControl() {
const { t } = this.context;
const { ipfsGatewayError } = this.state;
return (
<div
ref={this.settingsRefs[9]}
className="settings-page__content-row"
data-testid="advanced-setting-ipfs-gateway"
>
<div className="settings-page__content-item">
<span>{t('ipfsGateway')}</span>
<div className="settings-page__content-description">
{t('ipfsGatewayDescription')}
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<TextField
type="text"
value={this.state.ipfsGateway}
onChange={(e) => this.handleIpfsGatewayChange(e.target.value)}
error={ipfsGatewayError}
fullWidth
margin="dense"
/>
<Button
type="primary"
className="settings-tab__rpc-save-button"
disabled={Boolean(ipfsGatewayError)}
onClick={() => {
this.handleIpfsGatewaySave();
}}
>
{t('save')}
</Button>
</div>
</div>
</div>
);
}
renderDismissSeedBackupReminderControl() {
const { t } = this.context;
const { dismissSeedBackUpReminder, setDismissSeedBackUpReminder } =
@ -752,7 +556,7 @@ export default class AdvancedTab extends PureComponent {
return (
<div
ref={this.settingsRefs[11]}
ref={this.settingsRefs[10]}
className="settings-page__content-row"
data-testid="advanced-setting-dismiss-reminder"
>
@ -776,41 +580,111 @@ export default class AdvancedTab extends PureComponent {
);
}
renderTokenDetectionToggle() {
handleLockChange(time) {
const { t } = this.context;
const { useTokenDetection, setUseTokenDetection } = this.props;
const autoLockTimeLimit = Math.max(Number(time), 0);
this.setState(() => {
let lockTimeError = '';
if (autoLockTimeLimit > 10080) {
lockTimeError = t('lockTimeTooGreat');
}
return {
autoLockTimeLimit,
lockTimeError,
};
});
}
renderUserDataBackup() {
const { t } = this.context;
return (
<div
ref={this.settingsRefs[11]}
className="settings-page__content-row"
data-testid="advanced-setting-data-backup"
>
<div className="settings-page__content-item">
<span>{t('backupUserData')}</span>
<span className="settings-page__content-description">
{t('backupUserDataDescription')}
</span>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<Button
data-testid="backup-button"
type="secondary"
large
onClick={() => this.backupUserData()}
>
{t('backup')}
</Button>
</div>
</div>
</div>
);
}
renderRestoreUserData() {
const { t } = this.context;
const { showResultMessage, restoreSuccessful, restoreMessage } = this.state;
const defaultRestoreMessage = restoreSuccessful
? t('restoreSuccessful')
: t('restoreFailed');
const restoreMessageToRender =
restoreMessage === CORRUPT_JSON_FILE
? t('dataBackupSeemsCorrupt')
: defaultRestoreMessage;
return (
<div
ref={this.settingsRefs[12]}
className="settings-page__content-row"
data-testid="advanced-setting-token-detection"
data-testid="advanced-setting-data-restore"
>
<div className="settings-page__content-item">
<span>{t('enhancedTokenDetection')}</span>
<div className="settings-page__content-description">
{t('enhancedTokenDetectionDescription')}
</div>
<span>{t('restoreUserData')}</span>
<span className="settings-page__content-description">
{t('restoreUserDataDescription')}
</span>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={useTokenDetection}
onToggle={(value) => {
this.context.trackEvent({
category: EVENT.CATEGORIES.SETTINGS,
event: 'Token Detection',
properties: {
action: 'Token Detection',
legacy_event: true,
},
});
setUseTokenDetection(!value);
}}
offLabel={t('off')}
onLabel={t('on')}
<label
htmlFor="restore-file"
className="button btn btn--rounded btn-secondary btn--large settings-page__button"
>
{t('restore')}
</label>
<input
id="restore-file"
data-testid="restore-file"
style={{ visibility: 'hidden' }}
type="file"
accept=".json"
onChange={(e) => this.handleFileUpload(e)}
/>
</div>
{showResultMessage && (
<ActionableMessage
type={restoreSuccessful ? 'success' : 'danger'}
message={restoreMessageToRender}
primaryActionV2={{
label: t('dismiss'),
onClick: () => {
this.setState({
showResultMessage: false,
restoreSuccessful: true,
restoreMessage: null,
});
},
}}
/>
)}
</div>
</div>
);
@ -828,7 +702,6 @@ export default class AdvancedTab extends PureComponent {
{this.renderMobileSync()}
{this.renderResetAccount()}
{this.renderAdvancedGasInputInline()}
{this.renderTokenDetectionToggle()}
{this.renderHexDataOptIn()}
{this.renderShowConversionInTestnets()}
{this.renderToggleTestNetworks()}
@ -836,7 +709,6 @@ export default class AdvancedTab extends PureComponent {
{this.renderAutoLockTimeLimit()}
{this.renderUserDataBackup()}
{this.renderRestoreUserData()}
{this.renderIpfsGatewayControl()}
{notUsingFirefox ? this.renderLedgerLiveControl() : null}
{this.renderDismissSeedBackupReminderControl()}
</div>

View File

@ -8,13 +8,11 @@ import AdvancedTab from '.';
const mockSetAutoLockTimeLimit = jest.fn();
const mockSetShowTestNetworks = jest.fn();
const mockSetUseTokenDetection = jest.fn();
jest.mock('../../../store/actions.js', () => {
return {
setAutoLockTimeLimit: () => mockSetAutoLockTimeLimit,
setShowTestNetworks: () => mockSetShowTestNetworks,
setUseTokenDetection: () => mockSetUseTokenDetection,
};
});
@ -50,20 +48,10 @@ describe('AdvancedTab Component', () => {
it('should toggle show test networks', () => {
const { queryAllByRole } = renderWithProvider(<AdvancedTab />, mockStore);
const testNetworkToggle = queryAllByRole('checkbox')[4];
const testNetworkToggle = queryAllByRole('checkbox')[3];
fireEvent.click(testNetworkToggle);
expect(mockSetShowTestNetworks).toHaveBeenCalled();
});
it('should toggle token detection', () => {
const { queryAllByRole } = renderWithProvider(<AdvancedTab />, mockStore);
const tokenDetectionToggle = queryAllByRole('checkbox')[1];
fireEvent.click(tokenDetectionToggle);
expect(mockSetUseTokenDetection).toHaveBeenCalled();
});
});

View File

@ -9,10 +9,8 @@ import {
setShowTestNetworks,
setAutoLockTimeLimit,
setUseNonceField,
setIpfsGateway,
setLedgerTransportPreference,
setDismissSeedBackUpReminder,
setUseTokenDetection,
backupUserData,
restoreUserData,
} from '../../../store/actions';
@ -28,10 +26,8 @@ export const mapStateToProps = (state) => {
const {
featureFlags: { sendHexData, advancedInlineGas } = {},
useNonceField,
ipfsGateway,
ledgerTransportType,
dismissSeedBackUpReminder,
useTokenDetection,
} = metamask;
const {
showFiatInTestnets,
@ -49,11 +45,9 @@ export const mapStateToProps = (state) => {
showTestNetworks,
autoLockTimeLimit,
useNonceField,
ipfsGateway,
ledgerTransportType,
dismissSeedBackUpReminder,
userHasALedgerAccount,
useTokenDetection,
};
};
@ -78,18 +72,12 @@ export const mapDispatchToProps = (dispatch) => {
setAutoLockTimeLimit: (value) => {
return dispatch(setAutoLockTimeLimit(value));
},
setIpfsGateway: (value) => {
return dispatch(setIpfsGateway(value));
},
setLedgerTransportPreference: (value) => {
return dispatch(setLedgerTransportPreference(value));
},
setDismissSeedBackUpReminder: (value) => {
return dispatch(setDismissSeedBackUpReminder(value));
},
setUseTokenDetection: (value) => {
return dispatch(setUseTokenDetection(value));
},
};
};

View File

@ -45,57 +45,6 @@ export default class ExperimentalTab extends PureComponent {
handleSettingsRefs(t, t('experimental'), this.settingsRefs);
}
renderCollectibleDetectionToggle() {
if (!process.env.NFTS_V1) {
return null;
}
const { t } = this.context;
const {
useNftDetection,
setUseNftDetection,
openSeaEnabled,
setOpenSeaEnabled,
} = this.props;
return (
<div
ref={this.settingsRefs[2]}
className="settings-page__content-row--dependent"
>
<div className="settings-page__content-item">
<span>{t('useCollectibleDetection')}</span>
<div className="settings-page__content-description">
{t('useCollectibleDetectionDescription')}
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={useNftDetection}
onToggle={(value) => {
this.context.trackEvent({
category: EVENT.CATEGORIES.SETTINGS,
event: 'Collectible Detection',
properties: {
action: 'Collectible Detection',
legacy_event: true,
},
});
if (!value && !openSeaEnabled) {
setOpenSeaEnabled(!value);
}
setUseNftDetection(!value);
}}
offLabel={t('off')}
onLabel={t('on')}
/>
</div>
</div>
</div>
);
}
renderOpenSeaEnabledToggle() {
if (!process.env.NFTS_V1) {
return null;
@ -231,7 +180,6 @@ export default class ExperimentalTab extends PureComponent {
this.renderTransactionSecurityCheckToggle()}
{this.renderImprovedTokenAllowanceToggle()}
{this.renderOpenSeaEnabledToggle()}
{this.renderCollectibleDetectionToggle()}
</div>
);
}

View File

@ -12,6 +12,10 @@
display: flex;
flex-flow: column nowrap;
&__content-padded {
padding: 16px;
}
&__error-text {
@include H7;
@ -194,6 +198,18 @@
}
}
&__security-tab-sub-header {
font-weight: 500;
font-size: 16px;
color: var(--color-icon-alternative);
&__bold {
font-weight: 700;
font-size: 18px;
color: var(--color-text-default);
}
}
&__back-button {
display: none;
@ -275,6 +291,8 @@
display: flex;
flex-direction: column;
margin-bottom: 20px;
font-size: 16px;
font-weight: 500;
@include screen-sm-max {
height: initial;
@ -327,6 +345,8 @@
margin-top: 8px;
margin-bottom: 12px;
color: var(--color-text-default);
font-size: 14px;
font-weight: 400;
}
}
@ -334,10 +354,16 @@
text-transform: capitalize;
}
&__content-unordered-list {
padding-left: 2.5rem;
margin-top: 2.5rem;
list-style: disc;
}
&__content-description {
@include H6;
color: var(--color-text-default);
color: var(--color-text-alternative);
padding-top: 5px;
a {

View File

@ -5,168 +5,476 @@ exports[`Security Tab should match snapshot 1`] = `
<div
class="settings-page__body"
>
<span
class="settings-page__security-tab-sub-header__bold"
>
Security
</span>
<div
class="settings-page__content-row"
class="settings-page__content-padded"
>
<div
class="settings-page__content-item"
>
<span>
Reveal Secret Recovery Phrase
</span>
</div>
<div
class="settings-page__content-item"
class="settings-page__content-row"
>
<div
class="settings-page__content-item-col"
class="settings-page__content-item"
>
<button
class="button btn--rounded btn-danger btn--large"
data-testid="reveal-seed-words"
role="button"
tabindex="0"
>
<span>
Reveal Secret Recovery Phrase
</button>
</span>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
>
<button
class="button btn--rounded btn-danger btn--large"
data-testid="reveal-seed-words"
role="button"
tabindex="0"
>
Reveal Secret Recovery Phrase
</button>
</div>
</div>
</div>
</div>
<span
class="settings-page__security-tab-sub-header__bold"
>
Privacy
</span>
<div>
<span
class="settings-page__security-tab-sub-header"
>
Alerts
</span>
</div>
<div
class="settings-page__content-row"
class="settings-page__content-padded"
>
<div
class="settings-page__content-item"
>
<span>
Show incoming transactions
</span>
<div
class="settings-page__content-description"
>
Select this to use Etherscan to show incoming transactions in the transactions list
</div>
</div>
<div
class="settings-page__content-item"
class="settings-page__content-row"
>
<div
class="settings-page__content-item-col"
class="settings-page__content-item"
>
<label
class="toggle-button toggle-button--on"
tabindex="0"
<span>
Use phishing detection
</span>
<div
class="settings-page__content-description"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
Display a warning for phishing domains targeting Ethereum users
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
>
<label
class="toggle-button toggle-button--on"
tabindex="0"
>
<div
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 1; width: 26px; height: 20px; left: 4px;"
/>
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 1; width: 26px; height: 20px; left: 4px;"
/>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 0;"
/>
</div>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 0;"
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(3, 125, 214); left: 18px;"
/>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="true"
/>
</div>
<div
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
class="toggle-button__status"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(3, 125, 214); left: 18px;"
/>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="true"
/>
</div>
<div
class="toggle-button__status"
>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
</label>
</div>
</div>
</div>
</div>
<span
class="settings-page__security-tab-sub-header"
>
Transactions
</span>
<div
class="settings-page__content-row"
class="settings-page__content-padded"
>
<div
class="settings-page__content-item"
class="settings-page__content-row"
>
<span>
Use phishing detection
</span>
<div
class="settings-page__content-description"
class="settings-page__content-item"
>
Display a warning for phishing domains targeting Ethereum users
<span>
Show incoming transactions
</span>
<div
class="settings-page__content-description"
>
<span>
This relies on
<a
href="https://etherscan.io/privacyPolicy"
rel="noopener noreferrer"
target="_blank"
>
Etherscan
</a>
which will have access to your Ethereum address and your IP address.
<a
href="https://consensys.net/privacy-policy/"
rel="noopener noreferrer"
target="_blank"
>
Privacy policy
</a>
</span>
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
>
<label
class="toggle-button toggle-button--on"
tabindex="0"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
>
<div
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 1; width: 26px; height: 20px; left: 4px;"
/>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 0;"
/>
</div>
<div
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(3, 125, 214); left: 18px;"
/>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="true"
/>
</div>
<div
class="toggle-button__status"
>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
</div>
</div>
</div>
</div>
<span
class="settings-page__security-tab-sub-header"
>
Network provider
</span>
<div
class="settings-page__content-padded"
>
<div
class="settings-page__content-row"
data-testid="advanced-setting-choose-your-network"
>
<div
class="settings-page__content-item"
>
<span>
Choose your network
</span>
<div
class="settings-page__content-description"
>
<span>
We use Infura as our remote procedure call (RPC) provider to offer the most reliable and private access to Ethereum data we can. You can choose your own RPC, but remember that any RPC will receive your IP address and Ethereum wallet to make transactions. Read our
<a
href="https://consensys.net/privacy-policy/"
rel="noopener noreferrer"
target="_blank"
>
Privacy policy
</a>
to learn more about how Infura handles data.
</span>
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
>
<button
class="button btn--rounded btn-secondary settings-page__button"
role="button"
tabindex="0"
>
Add custom network
</button>
</div>
</div>
</div>
<div
class="settings-page__content-item"
class="settings-page__content-row"
data-testid="setting-ipfs-gateway"
>
<div
class="settings-page__content-item-col"
class="settings-page__content-item"
>
<label
class="toggle-button toggle-button--on"
tabindex="0"
<span>
Add custom IPFS gateway
</span>
<div
class="settings-page__content-description"
>
The IPFS gateway makes it possible to access and view data hosted by third parties. You can add a custom IPFS gateway or continue using the default.
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginDense MuiFormControl-fullWidth"
>
<div
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
class="MuiInputBase-root MuiInput-root TextField-inputRoot-12 MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl MuiInputBase-marginDense MuiInput-marginDense"
>
<input
aria-invalid="false"
class="MuiInputBase-input MuiInput-input MuiInputBase-inputMarginDense MuiInput-inputMarginDense"
dir="auto"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
</div>
</div>
<span
class="settings-page__security-tab-sub-header"
>
Token and NFT autodetection
</span>
<div
class="settings-page__content-padded"
>
<div
class="settings-page__content-row"
data-testid="advanced-setting-gas-fee-estimation"
>
<div
class="settings-page__content-item"
>
<span>
Autodetect tokens
</span>
<div
class="settings-page__content-description"
>
<span>
We use third-party APIs to detect and display new tokens sent to your wallet. Turn off if you dont want the app to pull data from those services.
<a
href="https://consensys.net/privacy-policy/"
rel="noopener noreferrer"
target="_blank"
>
Learn More
</a>
</span>
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
>
<label
class="toggle-button toggle-button--on"
tabindex="0"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 1; width: 26px; height: 20px; left: 4px;"
/>
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 1; width: 26px; height: 20px; left: 4px;"
/>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 0;"
/>
</div>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 0;"
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(3, 125, 214); left: 18px;"
/>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="true"
/>
</div>
<div
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
class="toggle-button__status"
>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
</div>
</div>
</div>
<div
class="settings-page__content-row"
>
<div
class="settings-page__content-item"
>
<span>
Batch account balance requests
</span>
<div
class="settings-page__content-description"
>
We batch accounts and query Infura to responsively show your balances. If you turn this off, only active accounts will be queried. Some dapps won't work unless you connect your wallet.
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
>
<label
class="toggle-button toggle-button--off"
tabindex="0"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(3, 125, 214); left: 18px;"
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 0; width: 26px; height: 20px; left: 4px;"
/>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 1;"
/>
</div>
<div
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(106, 115, 125); left: 3px;"
/>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="false"
/>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="true"
/>
</div>
<div
class="toggle-button__status"
>
<span
class="toggle-button__label-off"
<div
class="toggle-button__status"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
</div>
</div>
</div>
</div>
@ -241,77 +549,6 @@ exports[`Security Tab should match snapshot 1`] = `
</div>
</div>
</div>
<div
class="settings-page__content-row"
>
<div
class="settings-page__content-item"
>
<span>
Batch account balance requests
</span>
<div
class="settings-page__content-description"
>
<span>
We batch accounts and query Infura to responsively show your balances. If you turn this off, only active accounts will be queried. Some dapps won't work unless you connect your wallet.
</span>
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
>
<label
class="toggle-button toggle-button--off"
tabindex="0"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
>
<div
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 0; width: 26px; height: 20px; left: 4px;"
/>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 1;"
/>
</div>
<div
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(106, 115, 125); left: 3px;"
/>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="false"
/>
</div>
<div
class="toggle-button__status"
>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -1,13 +1,28 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { startCase } from 'lodash';
import ToggleButton from '../../../components/ui/toggle-button';
import { REVEAL_SEED_ROUTE } from '../../../helpers/constants/routes';
import TextField from '../../../components/ui/text-field';
import {
ADD_POPULAR_CUSTOM_NETWORK,
REVEAL_SEED_ROUTE,
} from '../../../helpers/constants/routes';
import Button from '../../../components/ui/button';
import {
getNumberOfSettingsInSection,
handleSettingsRefs,
} from '../../../helpers/utils/settings-search';
import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics';
import {
AUTO_DETECT_TOKEN_LEARN_MORE_LINK,
CONSENSYS_PRIVACY_LINK,
ETHERSCAN_PRIVACY_LINK,
} from '../../../../shared/lib/ui-utils';
import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app';
import {
addUrlProtocolPrefix,
getEnvironmentType,
} from '../../../../app/scripts/lib/util';
export default class SecurityTab extends PureComponent {
static contextTypes = {
@ -24,10 +39,25 @@ export default class SecurityTab extends PureComponent {
setShowIncomingTransactionsFeatureFlag: PropTypes.func.isRequired,
setUsePhishDetect: PropTypes.func.isRequired,
usePhishDetect: PropTypes.bool.isRequired,
useTokenDetection: PropTypes.bool.isRequired,
setUseTokenDetection: PropTypes.func.isRequired,
setIpfsGateway: PropTypes.func.isRequired,
ipfsGateway: PropTypes.string.isRequired,
useMultiAccountBalanceChecker: PropTypes.bool.isRequired,
setUseMultiAccountBalanceChecker: PropTypes.func.isRequired,
useNftDetection: PropTypes.bool,
setUseNftDetection: PropTypes.func,
setOpenSeaEnabled: PropTypes.func,
openSeaEnabled: PropTypes.bool,
};
state = {
ipfsGateway: this.props.ipfsGateway,
ipfsGatewayError: '',
};
settingsRefCounter = 0;
settingsRefs = Array(
getNumberOfSettingsInSection(
this.context.t,
@ -49,6 +79,18 @@ export default class SecurityTab extends PureComponent {
handleSettingsRefs(t, t('securityAndPrivacy'), this.settingsRefs);
}
toggleSetting(value, eventName, eventAction, toggleMethod) {
this.context.trackEvent({
category: EVENT.CATEGORIES.SETTINGS,
event: eventName,
properties: {
action: eventAction,
legacy_event: true,
},
});
toggleMethod(!value);
}
renderSeedWords() {
const { t } = this.context;
const { history } = this.props;
@ -95,7 +137,26 @@ export default class SecurityTab extends PureComponent {
<div className="settings-page__content-item">
<span>{t('showIncomingTransactions')}</span>
<div className="settings-page__content-description">
{t('showIncomingTransactionsDescription')}
{t('showIncomingTransactionsDescription', [
// TODO: Update to use real link
<a
href={ETHERSCAN_PRIVACY_LINK}
target="_blank"
rel="noopener noreferrer"
key="etherscan-privacy-link"
>
{t('etherscan')}
</a>,
// TODO: Update to use real link
<a
href={CONSENSYS_PRIVACY_LINK}
target="_blank"
rel="noopener noreferrer"
key="ic-consensys-privacy-link"
>
{t('privacyMsg')}
</a>,
])}
</div>
</div>
<div className="settings-page__content-item">
@ -167,7 +228,168 @@ export default class SecurityTab extends PureComponent {
);
}
renderMultiAccountBalanceCheckerOptIn() {
renderChooseYourNetworkButton() {
const { t } = this.context;
return (
<div
ref={this.settingsRefs[5]}
className="settings-page__content-row"
data-testid="advanced-setting-choose-your-network"
>
<div className="settings-page__content-item">
<span>{t('chooseYourNetwork')}</span>
<div className="settings-page__content-description">
{t('chooseYourNetworkDescription', [
// TODO: Update to use real link
<a
href={CONSENSYS_PRIVACY_LINK}
target="_blank"
rel="noopener noreferrer"
key="cyn-consensys-privacy-link"
>
{t('privacyMsg')}
</a>,
])}
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<Button
type="secondary"
className="settings-page__button"
onClick={() => {
getEnvironmentType() === ENVIRONMENT_TYPE_POPUP
? global.platform.openExtensionInBrowser(
ADD_POPULAR_CUSTOM_NETWORK,
)
: this.props.history.push(ADD_POPULAR_CUSTOM_NETWORK);
}}
>
{t('addCustomNetwork')}
</Button>
</div>
</div>
</div>
);
}
renderIpfsGatewayControl() {
const { t } = this.context;
const { ipfsGatewayError } = this.state;
const handleIpfsGatewaySave = (gateway) => {
const url = new URL(addUrlProtocolPrefix(gateway));
const { host } = url;
this.props.setIpfsGateway(host);
};
const handleIpfsGatewayChange = (url) => {
this.setState(() => {
let ipfsError = '';
try {
const urlObj = new URL(addUrlProtocolPrefix(url));
if (!urlObj.host) {
throw new Error();
}
// don't allow the use of this gateway
if (urlObj.host === 'gateway.ipfs.io') {
throw new Error('Forbidden gateway');
}
} catch (error) {
ipfsError =
error.message === 'Forbidden gateway'
? t('forbiddenIpfsGateway')
: t('invalidIpfsGateway');
}
handleIpfsGatewaySave(url);
return {
ipfsGateway: url,
ipfsGatewayError: ipfsError,
};
});
};
return (
<div
ref={this.settingsRefs[6]}
className="settings-page__content-row"
data-testid="setting-ipfs-gateway"
>
<div className="settings-page__content-item">
<span>{t('addCustomIPFSGateway')}</span>
<div className="settings-page__content-description">
{t('addCustomIPFSGatewayDescription')}
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<TextField
type="text"
value={this.state.ipfsGateway}
onChange={(e) => handleIpfsGatewayChange(e.target.value)}
error={ipfsGatewayError}
fullWidth
margin="dense"
/>
</div>
</div>
</div>
);
}
renderAutoDectectTokensToggle() {
const { t } = this.context;
const { useTokenDetection, setUseTokenDetection } = this.props;
return (
<div
ref={this.settingsRefs[7]}
className="settings-page__content-row"
data-testid="advanced-setting-gas-fee-estimation"
>
<div className="settings-page__content-item">
<span>{t('autoDetectTokens')}</span>
<div className="settings-page__content-description">
{t('autoDetectTokensDescription', [
// TODO: Update to use real link
<a
href={AUTO_DETECT_TOKEN_LEARN_MORE_LINK}
target="_blank"
rel="noopener noreferrer"
key="cyn-consensys-privacy-link"
>
{startCase(t('learnMore'))}
</a>,
])}
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={useTokenDetection}
onToggle={(value) => {
this.toggleSetting(
value,
EVENT_NAMES.KEY_AUTO_DETECT_TOKENS,
EVENT_NAMES.KEY_AUTO_DETECT_TOKENS,
setUseTokenDetection,
);
}}
offLabel={t('off')}
onLabel={t('on')}
/>
</div>
</div>
</div>
);
}
renderBatchAccountBalanceRequestsToggle() {
const { t } = this.context;
const { useMultiAccountBalanceChecker, setUseMultiAccountBalanceChecker } =
this.props;
@ -177,14 +399,75 @@ export default class SecurityTab extends PureComponent {
<div className="settings-page__content-item">
<span>{t('useMultiAccountBalanceChecker')}</span>
<div className="settings-page__content-description">
<span>{t('useMultiAccountBalanceCheckerDescription')}</span>
{t('useMultiAccountBalanceCheckerDescription')}
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={useMultiAccountBalanceChecker}
onToggle={(value) => setUseMultiAccountBalanceChecker(!value)}
onToggle={(value) => {
this.toggleSetting(
value,
EVENT_NAMES.KEY_BATCH_ACCOUNT_BALANCE_REQUESTS,
EVENT_NAMES.KEY_BATCH_ACCOUNT_BALANCE_REQUESTS,
setUseMultiAccountBalanceChecker,
);
}}
offLabel={t('off')}
onLabel={t('on')}
/>
</div>
</div>
</div>
);
}
renderCollectibleDetectionToggle() {
if (!process.env.COLLECTIBLES_V1) {
return null;
}
const { t } = this.context;
const {
useNftDetection,
setUseNftDetection,
openSeaEnabled,
setOpenSeaEnabled,
} = this.props;
return (
<div ref={this.settingsRefs[9]} className="settings-page__content-row">
<div className="settings-page__content-item">
<span>{t('useCollectibleDetection')}</span>
<div className="settings-page__content-description">
{t('useCollectibleDetectionDescription')}
<br />
{t('useCollectibleDetectionDescriptionLine2')}
<ul className="settings-page__content-unordered-list">
<li>{t('useCollectibleDetectionDescriptionLine3')}</li>
<li>{t('useCollectibleDetectionDescriptionLine4')}</li>
</ul>
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={useNftDetection}
onToggle={(value) => {
this.context.trackEvent({
category: EVENT.CATEGORIES.SETTINGS,
event: 'Collectible Detection',
properties: {
action: 'Collectible Detection',
legacy_event: true,
},
});
if (!value && !openSeaEnabled) {
setOpenSeaEnabled(!value);
}
setUseNftDetection(!value);
}}
offLabel={t('off')}
onLabel={t('on')}
/>
@ -200,11 +483,44 @@ export default class SecurityTab extends PureComponent {
return (
<div className="settings-page__body">
{warning ? <div className="settings-tab__error">{warning}</div> : null}
{this.renderSeedWords()}
{this.renderIncomingTransactionsOptIn()}
{this.renderPhishingDetectionToggle()}
<span className="settings-page__security-tab-sub-header__bold">
{this.context.t('security')}
</span>
<div className="settings-page__content-padded">
{this.renderSeedWords()}
</div>
<span className="settings-page__security-tab-sub-header__bold">
{this.context.t('privacy')}
</span>
<div>
<span className="settings-page__security-tab-sub-header">Alerts</span>
</div>
<div className="settings-page__content-padded">
{this.renderPhishingDetectionToggle()}
</div>
<span className="settings-page__security-tab-sub-header">
{this.context.t('transactions')}
</span>
<div className="settings-page__content-padded">
{this.renderIncomingTransactionsOptIn()}
</div>
<span className="settings-page__security-tab-sub-header">
{this.context.t('networkProvider')}
</span>
<div className="settings-page__content-padded">
{this.renderChooseYourNetworkButton()}
{this.renderIpfsGatewayControl()}
</div>
<span className="settings-page__security-tab-sub-header">
{this.context.t('tokenNftAutoDetection')}
</span>
<div className="settings-page__content-padded">
{this.renderAutoDectectTokensToggle()}
{this.renderBatchAccountBalanceRequestsToggle()}
{this.renderCollectibleDetectionToggle()}
</div>
{this.renderMetaMetricsOptIn()}
{this.renderMultiAccountBalanceCheckerOptIn()}
</div>
);
}

View File

@ -5,8 +5,13 @@ import {
setFeatureFlag,
setParticipateInMetaMetrics,
setUsePhishDetect,
setUseTokenDetection,
setIpfsGateway,
setUseMultiAccountBalanceChecker,
setUseNftDetection,
setOpenSeaEnabled,
} from '../../../store/actions';
import { getOpenSeaEnabled, getUseNftDetection } from '../../../selectors';
import SecurityTab from './security-tab.component';
const mapStateToProps = (state) => {
@ -18,6 +23,8 @@ const mapStateToProps = (state) => {
featureFlags: { showIncomingTransactions } = {},
participateInMetaMetrics,
usePhishDetect,
useTokenDetection,
ipfsGateway,
useMultiAccountBalanceChecker,
} = metamask;
@ -26,7 +33,11 @@ const mapStateToProps = (state) => {
showIncomingTransactions,
participateInMetaMetrics,
usePhishDetect,
useTokenDetection,
ipfsGateway,
useMultiAccountBalanceChecker,
useNftDetection: getUseNftDetection(state),
openSeaEnabled: getOpenSeaEnabled(state),
};
};
@ -37,8 +48,17 @@ const mapDispatchToProps = (dispatch) => {
setShowIncomingTransactionsFeatureFlag: (shouldShow) =>
dispatch(setFeatureFlag('showIncomingTransactions', shouldShow)),
setUsePhishDetect: (val) => dispatch(setUsePhishDetect(val)),
setUseMultiAccountBalanceChecker: (val) =>
dispatch(setUseMultiAccountBalanceChecker(val)),
setUseTokenDetection: (value) => {
return dispatch(setUseTokenDetection(value));
},
setIpfsGateway: (value) => {
return dispatch(setIpfsGateway(value));
},
setUseMultiAccountBalanceChecker: (value) => {
return dispatch(setUseMultiAccountBalanceChecker(value));
},
setUseNftDetection: (val) => dispatch(setUseNftDetection(val)),
setOpenSeaEnabled: (val) => dispatch(setOpenSeaEnabled(val)),
};
};

View File

@ -43,7 +43,7 @@ describe('Security Tab', () => {
const { queryAllByRole } = renderWithProvider(<SecurityTab />, mockStore);
const checkboxes = queryAllByRole('checkbox');
const showIncomingCheckbox = checkboxes[0];
const showIncomingCheckbox = checkboxes[1];
expect(showIncomingCheckbox).toHaveAttribute('value', 'true');
@ -58,37 +58,42 @@ describe('Security Tab', () => {
const { queryAllByRole } = renderWithProvider(<SecurityTab />, mockStore);
const checkboxes = queryAllByRole('checkbox');
const showIncomingCheckbox = checkboxes[1];
const togglePhishingCheckbox = checkboxes[0];
expect(showIncomingCheckbox).toHaveAttribute('value', 'true');
expect(togglePhishingCheckbox).toHaveAttribute('value', 'true');
fireEvent.change(showIncomingCheckbox, {
fireEvent.change(togglePhishingCheckbox, {
target: { value: false },
});
expect(showIncomingCheckbox).toHaveAttribute('value', 'false');
expect(togglePhishingCheckbox).toHaveAttribute('value', 'false');
});
it('toggles metaMetrics', () => {
const { queryAllByRole } = renderWithProvider(<SecurityTab />, mockStore);
const checkboxes = queryAllByRole('checkbox');
const showIncomingCheckbox = checkboxes[2];
expect(showIncomingCheckbox).toHaveAttribute('value', 'false');
let index = 4;
if (process.env.COLLECTIBLES_V1) {
index = 5;
}
const toggleMetaMetricsCheckbox = checkboxes[index];
fireEvent.change(showIncomingCheckbox, {
expect(toggleMetaMetricsCheckbox).toHaveAttribute('value', 'false');
fireEvent.change(toggleMetaMetricsCheckbox, {
target: { value: true },
});
expect(showIncomingCheckbox).toHaveAttribute('value', 'true');
expect(toggleMetaMetricsCheckbox).toHaveAttribute('value', 'true');
});
it('toggles batch balance checks', () => {
const { queryAllByRole } = renderWithProvider(<SecurityTab />, mockStore);
const checkboxes = queryAllByRole('checkbox');
const batchBalanceChecksCheckbox = checkboxes[3];
const batchBalanceChecksCheckbox = checkboxes[4];
expect(batchBalanceChecksCheckbox).toHaveAttribute('value', 'false');
@ -98,4 +103,25 @@ describe('Security Tab', () => {
expect(batchBalanceChecksCheckbox).toHaveAttribute('value', 'true');
});
it('should toggle token detection', () => {
const { queryAllByRole } = renderWithProvider(<SecurityTab />, mockStore);
const checkboxes = queryAllByRole('checkbox');
const tokenDetectionToggle = checkboxes[2];
expect(tokenDetectionToggle).toHaveAttribute('value', 'true');
fireEvent.change(tokenDetectionToggle, {
target: { value: false },
});
expect(tokenDetectionToggle).toHaveAttribute('value', 'false');
fireEvent.change(tokenDetectionToggle, {
target: { value: true },
});
expect(tokenDetectionToggle).toHaveAttribute('value', 'true');
});
});

View File

@ -2798,10 +2798,8 @@ export function setTheme(val) {
export function setIpfsGateway(val) {
return (dispatch) => {
dispatch(showLoadingIndication());
log.debug(`background.setIpfsGateway`);
callBackgroundMethod('setIpfsGateway', [val], (err) => {
dispatch(hideLoadingIndication());
if (err) {
dispatch(displayWarning(err.message));
} else {