EIP-1102: add user privacy option

feature/default_network_editable
bitpshr 6 years ago committed by Dan Finlay
parent bfcb73ad53
commit 226601a956
  1. 6
      app/_locales/cs/messages.json
  2. 6
      app/_locales/de/messages.json
  3. 12
      app/_locales/en/messages.json
  4. 6
      app/_locales/es/messages.json
  5. 12
      app/_locales/fr/messages.json
  6. 6
      app/_locales/hn/messages.json
  7. 39
      app/_locales/ht/messages.json
  8. 6
      app/_locales/it/messages.json
  9. 6
      app/_locales/ja/messages.json
  10. 6
      app/_locales/ko/messages.json
  11. 6
      app/_locales/nl/messages.json
  12. 6
      app/_locales/ph/messages.json
  13. 6
      app/_locales/pt/messages.json
  14. 6
      app/_locales/ru/messages.json
  15. 6
      app/_locales/th/messages.json
  16. 6
      app/_locales/tml/messages.json
  17. 6
      app/_locales/tr/messages.json
  18. 6
      app/_locales/vi/messages.json
  19. 6
      app/_locales/zh_CN/messages.json
  20. 6
      app/_locales/zh_TW/messages.json
  21. 27
      app/scripts/contentscript.js
  22. 41
      app/scripts/controllers/provider-approval.js
  23. 4
      app/scripts/inpage.js
  24. 4
      app/scripts/metamask-controller.js
  25. 16
      old-ui/app/config.js
  26. 16
      test/e2e/beta/metamask-beta-ui.spec.js
  27. 31
      test/e2e/metamask.spec.js
  28. 7
      ui/app/actions.js
  29. 39
      ui/app/components/modals/force-injection/force-injection.component.js
  30. 16
      ui/app/components/modals/force-injection/force-injection.container.js
  31. 1
      ui/app/components/modals/force-injection/index.js
  32. 14
      ui/app/components/modals/modal.js
  33. 65
      ui/app/components/pages/settings/settings-tab/settings-tab.component.js
  34. 8
      ui/app/components/pages/settings/settings-tab/settings-tab.container.js

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Režim súkromia"
},
"privacyModeDescription": {
"message": "Webové stránky musia požiadať o prístup k zobrazeniu informácií o vašom účte."
},
"exposeAccounts": {
"message": "Vystavte účty"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Datenschutzmodus"
},
"privacyModeDescription": {
"message": "Websites müssen Zugriff anfordern, um Ihre Kontoinformationen anzuzeigen."
},
"exposeAccounts": {
"message": "Expose Konten"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Privacy Mode"
},
"privacyModeDescription": {
"message": "Websites must request access to view your account information."
},
"exposeAccounts": {
"message": "Expose Accounts"
},
@ -15,13 +21,13 @@
"message": "Approved website data cleared successfully."
},
"approvalData": {
"message": "Approval Data"
"message": "Privacy Data"
},
"approvalDataDescription": {
"message": "Clear approved website data so all sites must request approval again."
"message": "Clear privacy data so all websites must request access to view account information again."
},
"clearApprovalData": {
"message": "Clear Approval Data"
"message": "Clear Privacy Data"
},
"reject": {
"message": "Reject"

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Modo privado"
},
"privacyModeDescription": {
"message": "Los sitios web deben solicitar acceso para ver la información de su cuenta."
},
"exposeAccounts": {
"message": "Exponer cuentas"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Les sites Web doivent demander un accès pour afficher les informations de votre compte."
},
"privacyModeDescription": {
"message": "Les sites Web doivent demander un accès pour afficher les informations de votre compte."
},
"exposeAccounts": {
"message": "Exposer les comptes"
},
@ -23,12 +29,6 @@
"clearApprovalData": {
"message": "Effacer les données d'approbation"
},
"approve": {
"message": "Approuver"
},
"reject": {
"message": "Rejeter"
},
"providerAPIRequest": {
"message": "Demande d'API Web3"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "गपनयतड"
},
"privacyModeDescription": {
"message": "वबसइट आपकनकखनिए पहच क अनध करन।"
},
"exposeAccounts": {
"message": "ख परश कर"
},

@ -1,4 +1,43 @@
{
"privacyMode": {
"message": "Mòd Privacy"
},
"privacyModeDescription": {
"message": "Sou sit entènèt yo dwe mande aksè pou wè enfòmasyon kont ou."
},
"exposeAccounts": {
"message": "Ekspoze Kont"
},
"exposeDescription": {
"message": "Ekspoze kont sou sitwèb aktyèl la. Itil pou dapps eritaj."
},
"confirmExpose": {
"message": "Èske ou sèten ou vle ekspoze kont ou sou sit entènèt aktyèl la?"
},
"confirmClear": {
"message": "Èske ou sèten ou vle klè sitwèb apwouve?"
},
"clearApprovalDataSuccess": {
"message": "Done sou sit wèb apwouve yo te klarifye avèk siksè."
},
"approvalData": {
"message": "Done sou vi prive"
},
"approvalDataDescription": {
"message": "Done sou vi prive klè pou tout sit entènèt yo dwe mande aksè pou wè enfòmasyon kont ankò."
},
"clearApprovalData": {
"message": "Klè Done sou vi prive"
},
"providerAPIRequest": {
"message": "Ethereum API Mande"
},
"reviewProviderRequest": {
"message": "Tanpri revize sa API demann Ethereum."
},
"providerRequestInfo": {
"message": "Domèn ki nan lis anba a ap mande pou jwenn aksè a blòkchou Ethereum ak pou wè kont ou ye kounye a. Toujou double tcheke ke ou sou sit ki kòrèk la anvan apwouve aksè."
},
"accept": {
"message": "Aksepte"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Modalità di privacy"
},
"privacyModeDescription": {
"message": "I siti Web devono richiedere l'accesso per visualizzare le informazioni del tuo account."
},
"exposeAccounts": {
"message": "Expose Accounts"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "プライバシーモード"
},
"privacyModeDescription": {
"message": "ウェブサイトはあなたのアカウント情報を閲覧するためのアクセスを要求する必要があります。"
},
"exposeAccounts": {
"message": "アカウントを公開する"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "개인 정보 보호 모드"
},
"privacyModeDescription": {
"message": "웹 사이트는 계정 정보를 볼 수있는 액세스 권한을 요청해야합니다."
},
"exposeAccounts": {
"message": "계정 노출"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Privacy-modus"
},
"privacyModeDescription": {
"message": "Websites moeten toegang vragen om uw accountgegevens te bekijken."
},
"exposeAccounts": {
"message": "Expose Accounts"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Mode ng Privacy"
},
"privacyModeDescription": {
"message": "Dapat humiling ng access ang mga website upang tingnan ang impormasyon ng iyong account."
},
"exposeAccounts": {
"message": "Ilantad ang Mga Account"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Modo de privacidade"
},
"privacyModeDescription": {
"message": "Os sites devem solicitar acesso para visualizar as informações da sua conta."
},
"exposeAccounts": {
"message": "Expor contas"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Режим конфиденциальности"
},
"privacyModeDescription": {
"message": "Веб-сайты должны запрашивать доступ для просмотра информации об учетной записи."
},
"exposeAccounts": {
"message": "Открыть счета"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "โหมดความเปนสวนตว"
},
"privacyModeDescription": {
"message": "เวบไซตองขอเขาถงเพอดอมลบญชของคณ"
},
"exposeAccounts": {
"message": "เปดเผยบญช"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "தனிி"
},
"privacyModeDescription": {
"message": "உஙகள கணக தகவலிட வலதளஙகள அணகலர வ."
},
"exposeAccounts": {
"message": "கணககள அமபலபபடகள"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Gizlilik modu"
},
"privacyModeDescription": {
"message": "Web siteleri, hesap bilgilerinizi görmek için erişim istemek zorundadır."
},
"exposeAccounts": {
"message": "Hesapları Açığa Çıkar"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "Chế độ riêng tư"
},
"privacyModeDescription": {
"message": "Trang web phải yêu cầu quyền truy cập để xem thông tin tài khoản của bạn."
},
"exposeAccounts": {
"message": "Hiển thị tài khoản"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "隐私模式"
},
"privacyModeDescription": {
"message": "网站必须请求访问权限才能查看您的帐户信息。"
},
"exposeAccounts": {
"message": "公开账户"
},

@ -1,4 +1,10 @@
{
"privacyMode": {
"message": "隱私模式"
},
"privacyModeDescription": {
"message": "網站必須請求訪問權限才能查看您的帳戶信息。"
},
"exposeAccounts": {
"message": "公開賬戶"
},

@ -24,7 +24,7 @@ if (shouldInjectWeb3()) {
injectScript(inpageBundle)
setupStreams()
listenForProviderRequest()
checkForcedInjection()
checkPrivacyMode()
}
/**
@ -125,9 +125,9 @@ function listenForProviderRequest () {
origin: source.location.hostname,
})
break
case 'ETHEREUM_PROVIDER_STATUS':
case 'ETHEREUM_QUERY_STATUS':
extension.runtime.sendMessage({
action: 'provider-status-request',
action: 'init-status-request',
origin: source.location.hostname,
})
break
@ -144,14 +144,7 @@ function listenForProviderRequest () {
case 'reject-provider-request':
injectScript(`window.dispatchEvent(new CustomEvent('ethereumprovider', { detail: { error: 'User rejected provider access' }}))`)
break
case 'force-injection':
extension.storage.local.get(['forcedOrigins'], ({ forcedOrigins = [] }) => {
extension.storage.local.set({ forcedOrigins: [ ...forcedOrigins, window.location.hostname ] }, () => {
injectScript(`window.location.reload()`)
})
})
break
case 'provider-status':
case 'answer-status-request':
injectScript(`window.dispatchEvent(new CustomEvent('ethereumproviderstatus', { detail: { isEnabled: ${isEnabled}}}))`)
break
}
@ -159,15 +152,11 @@ function listenForProviderRequest () {
}
/**
* Checks the current origin to see if it exists in the extension's locally-stored list
* off user-whitelisted dapp origins. If it is, this origin will be marked as approved,
* meaning the publicConfig stream will be enabled. This is only meant to ease the transition
* to 1102 and will be removed in the future.
* Checks if MetaMask is currently operating in "privacy mode", meaning
* dapps must call ethereum.enable in order to access user accounts
*/
function checkForcedInjection () {
extension.storage.local.get(['forcedOrigins'], ({ forcedOrigins = [] }) => {
originApproved = forcedOrigins.indexOf(window.location.hostname) > -1
})
function checkPrivacyMode () {
extension.runtime.sendMessage({ action: 'init-privacy-request' })
}
/**

@ -1,5 +1,4 @@
const ObservableStore = require('obs-store')
const extension = require('extensionizer')
/**
* A controller that services user-approved requests for a full Ethereum provider API
@ -10,22 +9,25 @@ class ProviderApprovalController {
*
* @param {Object} [config] - Options to configure controller
*/
constructor ({ closePopup, openPopup, platform, publicConfigStore } = {}) {
constructor ({ closePopup, openPopup, platform, preferencesController, publicConfigStore } = {}) {
this.store = new ObservableStore()
this.closePopup = closePopup
this.openPopup = openPopup
this.platform = platform
this.publicConfigStore = publicConfigStore
this.approvedOrigins = {}
this.preferencesController = preferencesController
platform && platform.addMessageListener && platform.addMessageListener(({ action, origin }) => {
if (!action) { return }
switch (action) {
case 'init-provider-request':
this.handleProviderRequest(origin)
break
case 'provider-status-request':
case 'init-status-request':
this.handleProviderStatusRequest(origin)
break
case 'init-privacy-request':
this.handlePrivacyStatusRequest()
}
})
}
@ -35,9 +37,9 @@ class ProviderApprovalController {
*
* @param {string} origin - Origin of the window requesting full provider access
*/
async handleProviderRequest (origin) {
handleProviderRequest (origin) {
this.store.updateState({ providerRequests: [{ origin }] })
if (await this.isApproved(origin)) {
if (this.isApproved(origin)) {
this.approveProviderRequest(origin)
return
}
@ -45,13 +47,21 @@ class ProviderApprovalController {
}
/**
* Called by a tab to detemrine if a full Ethereum provider API is exposed
* Called by a tab to determine if a full Ethereum provider API is exposed
*
* @param {string} origin - Origin of the window requesting provider status
*/
async handleProviderStatusRequest (origin) {
const isEnabled = await this.isApproved(origin)
this.platform && this.platform.sendMessage({ action: 'provider-status', isEnabled }, { active: true })
const isEnabled = this.isApproved(origin)
this.platform && this.platform.sendMessage({ action: 'answer-status-request', isEnabled }, { active: true })
}
handlePrivacyStatusRequest () {
const privacyMode = this.preferencesController.getFeatureFlags().privacyMode
if (!privacyMode) {
this.platform && this.platform.sendMessage({ action: 'approve-provider-request' }, { active: true })
this.publicConfigStore.emit('update', this.publicConfigStore.getState())
}
}
/**
@ -87,7 +97,6 @@ class ProviderApprovalController {
*/
clearApprovedOrigins () {
this.approvedOrigins = {}
extension.storage.local.set({ forcedOrigins: [] })
}
/**
@ -97,18 +106,8 @@ class ProviderApprovalController {
* @returns {boolean} - True if the origin has been approved
*/
isApproved (origin) {
return new Promise(resolve => {
extension.storage.local.get(['forcedOrigins'], ({ forcedOrigins = [] }) => {
resolve(this.approvedOrigins[origin] || forcedOrigins.indexOf(origin) > -1)
})
})
}
/**
* Called when a user forces the exposure of a full Ethereum provider API
*/
forceInjection () {
this.platform.sendMessage({ action: 'force-injection' }, { active: true })
const privacyMode = this.preferencesController.getFeatureFlags().privacyMode
return !privacyMode || this.approvedOrigins[origin]
}
}

@ -56,10 +56,10 @@ inpageProvider.isEnabled = function () {
if (typeof detail.error !== 'undefined') {
reject(detail.error)
} else {
resolve(detail.isEnabled)
resolve(!!detail.isEnabled)
}
})
window.postMessage({ type: 'ETHEREUM_PROVIDER_STATUS' }, '*')
window.postMessage({ type: 'ETHEREUM_QUERY_STATUS' }, '*')
})
}

@ -224,6 +224,7 @@ module.exports = class MetamaskController extends EventEmitter {
closePopup: opts.closePopup,
openPopup: opts.openPopup,
platform: opts.platform,
preferencesController: this.preferencesController,
publicConfigStore: this.publicConfigStore,
})
@ -275,7 +276,7 @@ module.exports = class MetamaskController extends EventEmitter {
getAccounts: async ({ origin }) => {
// Expose no accounts if this origin has not been approved, preventing
// account-requring RPC methods from completing successfully
const isApproved = await this.providerApprovalController.isApproved(origin)
const isApproved = this.providerApprovalController.isApproved(origin)
if (origin !== 'MetaMask' && !isApproved) { return [] }
const isUnlocked = this.keyringController.memStore.getState().isUnlocked
const selectedAddress = this.preferencesController.getSelectedAddress()
@ -455,7 +456,6 @@ module.exports = class MetamaskController extends EventEmitter {
approveProviderRequest: providerApprovalController.approveProviderRequest.bind(providerApprovalController),
clearApprovedOrigins: providerApprovalController.clearApprovedOrigins.bind(providerApprovalController),
rejectProviderRequest: providerApprovalController.rejectProviderRequest.bind(providerApprovalController),
forceInjection: providerApprovalController.forceInjection.bind(providerApprovalController),
}
}

@ -210,7 +210,7 @@ ConfigScreen.prototype.render = function () {
fontFamily: 'Montserrat Light',
fontSize: '13px',
},
}, 'Clear approved website data so all sites must request approval again.'),
}, 'Clear privacy data so all websites must request access to view account information again.'),
h('br'),
h('button', {
style: {
@ -220,7 +220,7 @@ ConfigScreen.prototype.render = function () {
event.preventDefault()
state.dispatch(actions.clearApprovedOrigins())
},
}, 'Clear approval data'),
}, 'Clear privacy data'),
]),
h('hr.horizontal-line'),
@ -235,7 +235,10 @@ ConfigScreen.prototype.render = function () {
fontFamily: 'Montserrat Light',
fontSize: '13px',
},
}, 'Expose accounts to the current website. This is useful for legacy dapps.'),
}, metamaskState.featureFlags.privacyMode ?
'Websites will be able to view your account information.' :
'Websites must request access to view your account information.'
),
h('br'),
h('button', {
style: {
@ -243,9 +246,12 @@ ConfigScreen.prototype.render = function () {
},
onClick (event) {
event.preventDefault()
state.dispatch(actions.forceInjection())
state.dispatch(actions.setFeatureFlag('privacyMode', !metamaskState.featureFlags.privacyMode))
},
}, 'Expose accounts'),
}, metamaskState.featureFlags.privacyMode ?
'Disable privacy mode' :
'Enable privacy mode'
),
]),
h('hr.horizontal-line'),

@ -284,6 +284,22 @@ describe('MetaMask', function () {
})
})
describe('Enable privacy mode', () => {
it('enables privacy mode', async () => {
const networkDropdown = await findElement(driver, By.css('.network-name'))
await networkDropdown.click()
await delay(regularDelayMs)
const customRpcButton = await findElement(driver, By.xpath(`//span[contains(text(), 'Custom RPC')]`))
await customRpcButton.click()
await delay(regularDelayMs)
const privacyToggle = await findElement(driver, By.css('.settings-page__content-row:nth-of-type(9) .settings-page__content-item-col > div'))
await privacyToggle.click()
await delay(largeDelayMs * 2)
})
})
describe('Log out an log back in', () => {
it('logs out of the account', async () => {
await driver.findElement(By.css('.account-menu__icon')).click()

@ -2,11 +2,6 @@ const path = require('path')
const assert = require('assert')
const { By, Key, until } = require('selenium-webdriver')
const { delay, createModifiedTestBuild, setupBrowserAndExtension, verboseReportOnFailure } = require('./func')
const {
closeAllWindowHandlesExcept,
switchToWindowWithTitle,
switchToWindowWithUrlThatMatches,
} = require('./beta/helpers')
describe('Metamask popup page', function () {
const browser = process.env.SELENIUM_BROWSER
@ -188,7 +183,6 @@ describe('Metamask popup page', function () {
})
it('restores from seed phrase', async function () {
await delay(1000)
const restoreSeedLink = await driver.findElement(By.css('#app-content > div > div.app-primary.from-left > div > div.flex-row.flex-center.flex-grow > p'))
assert.equal(await restoreSeedLink.getText(), 'Restore from seed phrase')
await restoreSeedLink.click()
@ -207,10 +201,10 @@ describe('Metamask popup page', function () {
})
it('balance renders', async function () {
await delay(1000)
await delay(500)
const balance = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > div.ether-balance.ether-balance-amount > div > div > div:nth-child(1) > div:nth-child(1)'))
assert.equal(await balance.getText(), '100.000')
await delay(1000)
await delay(200)
})
it('sends transaction', async function () {
@ -248,31 +242,12 @@ describe('Metamask popup page', function () {
})
describe('Token Factory', function () {
let windowHandles
let extension
let dapp
it('navigates to token factory', async function () {
await driver.get('http://token-factory-1102.now.sh')
await delay(7000)
windowHandles = await driver.getAllWindowHandles()
dapp = await switchToWindowWithTitle(driver, 'Token Factory', windowHandles)
await delay(400)
extension = await switchToWindowWithUrlThatMatches(driver, /notification.html/, windowHandles)
await delay(400)
await closeAllWindowHandlesExcept(driver, [extension, dapp])
await switchToWindowWithUrlThatMatches(driver, /notification.html/, [extension, dapp])
const approveButton = await driver.wait(until.elementLocated(By.xpath(`//button[contains(text(), 'APPROVE')]`)), 10000)
await approveButton.click()
await driver.get('http://tokenfactory.surge.sh/')
})
it('navigates to create token contract link', async function () {
await delay(400)
await switchToWindowWithTitle(driver, 'Token Factory', windowHandles)
await delay(400)
const createToken = await driver.findElement(By.css('#bs-example-navbar-collapse-1 > ul > li:nth-child(3) > a'))
await createToken.click()
})

@ -328,7 +328,6 @@ var actions = {
approveProviderRequest,
rejectProviderRequest,
clearApprovedOrigins,
forceInjection,
}
module.exports = actions
@ -2506,9 +2505,3 @@ function clearApprovedOrigins () {
background.clearApprovedOrigins()
}
}
function forceInjection () {
return (dispatch) => {
background.forceInjection()
}
}

@ -1,39 +0,0 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import Modal, { ModalContent } from '../../modal'
export default class ForceInjection extends PureComponent {
static propTypes = {
hideModal: PropTypes.func.isRequired,
forceInjection: PropTypes.func.isRequired,
}
static contextTypes = {
t: PropTypes.func,
}
handleForce = () => {
const { forceInjection, hideModal } = this.props
forceInjection()
hideModal()
}
render () {
const { t } = this.context
return (
<Modal
onSubmit={this.handleForce}
onCancel={() => this.props.hideModal()}
submitText={t('ok')}
cancelText={t('nevermind')}
submitType="secondary"
>
<ModalContent
title={t('exposeAccounts')}
description={t('confirmExpose')}
/>
</Modal>
)
}
}

@ -1,16 +0,0 @@
import { connect } from 'react-redux'
import { compose } from 'recompose'
import withModalProps from '../../../higher-order-components/with-modal-props'
import ForceInjectionComponent from './force-injection.component'
import { forceInjection } from '../../../actions'
const mapDispatchToProps = dispatch => {
return {
forceInjection: () => dispatch(forceInjection()),
}
}
export default compose(
withModalProps,
connect(null, mapDispatchToProps)
)(ForceInjectionComponent)

@ -1 +0,0 @@
export { default } from './force-injection.container'

@ -29,7 +29,6 @@ import CancelTransaction from './cancel-transaction'
import WelcomeBeta from './welcome-beta'
import RejectTransactions from './reject-transactions'
import ClearApprovedOrigins from './clear-approved-origins'
import ForceInjection from './force-injection'
const modalContainerBaseStyle = {
transform: 'translate3d(-50%, 0, 0px)',
@ -227,19 +226,6 @@ const MODALS = {
},
},
FORCE_INJECTION: {
contents: h(ForceInjection),
mobileModalStyle: {
...modalContainerMobileStyle,
},
laptopModalStyle: {
...modalContainerLaptopStyle,
},
contentStyle: {
borderRadius: '8px',
},
},
OLD_UI_NOTIFICATION_MODAL: {
contents: [
h(NotifcationModal, {

@ -39,6 +39,8 @@ export default class SettingsTab extends PureComponent {
metamask: PropTypes.object,
setUseBlockie: PropTypes.func,
setHexDataFeatureFlag: PropTypes.func,
setPrivacyMode: PropTypes.func,
privacyMode: PropTypes.bool,
setCurrentCurrency: PropTypes.func,
setRpcTarget: PropTypes.func,
delRpcTarget: PropTypes.func,
@ -46,7 +48,6 @@ export default class SettingsTab extends PureComponent {
revealSeedConfirmation: PropTypes.func,
setFeatureFlagToBeta: PropTypes.func,
showClearApprovalModal: PropTypes.func,
showForceInjectionModal: PropTypes.func,
showResetAccountConfirmationModal: PropTypes.func,
warning: PropTypes.string,
history: PropTypes.object,
@ -308,36 +309,6 @@ export default class SettingsTab extends PureComponent {
)
}
renderForceInjection () {
const { t } = this.context
const { showForceInjectionModal } = this.props
return (
<div className="settings-page__content-row">
<div className="settings-page__content-item">
<span>{ t('exposeAccounts') }</span>
<span className="settings-page__content-description">
{ t('exposeDescription') }
</span>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<Button
type="secondary"
large
className="settings-tab__button--orange"
onClick={event => {
event.preventDefault()
showForceInjectionModal()
}}
>
{ t('exposeAccounts') }
</Button>
</div>
</div>
</div>
)
}
renderSeedWords () {
const { t } = this.context
const { history } = this.props
@ -523,6 +494,32 @@ export default class SettingsTab extends PureComponent {
)
}
renderPrivacyOptIn () {
const { t } = this.context
const { privacyMode, setPrivacyMode } = this.props
return (
<div className="settings-page__content-row">
<div className="settings-page__content-item">
<span>{ t('privacyMode') }</span>
<div className="settings-page__content-description">
{ t('privacyModeDescription') }
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={privacyMode}
onToggle={value => setPrivacyMode(!value)}
activeLabel=""
inactiveLabel=""
/>
</div>
</div>
</div>
)
}
render () {
const { warning, isMascara } = this.props
@ -535,12 +532,12 @@ export default class SettingsTab extends PureComponent {
{ this.renderNewRpcUrl() }
{ this.renderStateLogs() }
{ this.renderSeedWords() }
{ this.renderClearApproval() }
{ this.renderForceInjection() }
{ !isMascara && this.renderOldUI() }
{ this.renderResetAccount() }
{ this.renderBlockieOptIn() }
{ this.renderClearApproval() }
{ this.renderPrivacyOptIn() }
{ this.renderHexDataOptIn() }
{ this.renderBlockieOptIn() }
</div>
)
}

@ -22,7 +22,10 @@ const mapStateToProps = state => {
conversionDate,
nativeCurrency,
useBlockie,
featureFlags: { sendHexData } = {},
featureFlags: {
sendHexData,
privacyMode,
} = {},
provider = {},
isMascara,
currentLocale,
@ -38,6 +41,7 @@ const mapStateToProps = state => {
nativeCurrency,
useBlockie,
sendHexData,
privacyMode,
provider,
useNativeCurrencyAsPrimaryCurrency,
}
@ -55,12 +59,12 @@ const mapDispatchToProps = dispatch => {
return dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
},
setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)),
setPrivacyMode: enabled => dispatch(setFeatureFlag('privacyMode', enabled)),
showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })),
setUseNativeCurrencyAsPrimaryCurrencyPreference: value => {
return dispatch(setUseNativeCurrencyAsPrimaryCurrencyPreference(value))
},
showClearApprovalModal: () => dispatch(showModal({ name: 'CLEAR_APPROVED_ORIGINS' })),
showForceInjectionModal: () => dispatch(showModal({ name: 'FORCE_INJECTION' })),
}
}

Loading…
Cancel
Save