Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add migration on 3box imports and remove feature flag #7209

Merged
merged 10 commits into from
Sep 26, 2019
1 change: 0 additions & 1 deletion app/scripts/controllers/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ class PreferencesController {
// perform sensitive operations.
featureFlags: {
showIncomingTransactions: true,
threeBox: false,
},
knownMethodData: {},
participateInMetaMetrics: null,
Expand Down
91 changes: 61 additions & 30 deletions app/scripts/controllers/threebox.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ const ObservableStore = require('obs-store')
const Box = process.env.IN_TEST
? require('../../../development/mock-3box')
: require('3box')
// const Box = require(process.env.IN_TEST ? '../lib/mock-3box' : '3box/dist/3box.min')
const log = require('loglevel')

const migrations = require('../migrations/')
const Migrator = require('../lib/migrator')
const JsonRpcEngine = require('json-rpc-engine')
const providerFromEngine = require('eth-json-rpc-middleware/providerFromEngine')
const createMetamaskMiddleware = require('./network/createMetamaskMiddleware')
Expand Down Expand Up @@ -48,19 +48,19 @@ class ThreeBoxController {
})

const initState = {
threeBoxSyncingAllowed: true,
restoredFromThreeBox: null,
threeBoxSyncingAllowed: false,
showRestorePrompt: true,
threeBoxLastUpdated: 0,
...opts.initState,
threeBoxAddress: null,
threeBoxSynced: false,
threeBoxDisabled: false,
}
this.store = new ObservableStore(initState)
this.registeringUpdates = false
this.lastMigration = migrations.sort((a, b) => a.version - b.version).slice(-1)[0]

const threeBoxFeatureFlagTurnedOn = this.preferencesController.getFeatureFlags().threeBox

if (threeBoxFeatureFlagTurnedOn) {
if (initState.threeBoxSyncingAllowed) {
this.init()
}
}
Expand All @@ -73,12 +73,19 @@ class ThreeBoxController {
}
}

async _update3Box ({ type }, newState) {
async _update3Box () {
try {
const { threeBoxSyncingAllowed, threeBoxSynced } = this.store.getState()
if (threeBoxSyncingAllowed && threeBoxSynced) {
await this.space.private.set('lastUpdated', Date.now())
await this.space.private.set(type, JSON.stringify(newState))
const newState = {
preferences: this.preferencesController.store.getState(),
addressBook: this.addressBookController.state,
lastUpdated: Date.now(),
lastMigration: this.lastMigration,
}

await this.space.private.set('metamaskBackup', JSON.stringify(newState))
await this.setShowRestorePromptToFalse()
}
} catch (error) {
console.error(error)
Expand All @@ -105,11 +112,17 @@ class ThreeBoxController {

async new3Box () {
const accounts = await this.keyringController.getAccounts()
const address = accounts[0]

if (this.getThreeBoxSyncingState()) {
this.address = await this.keyringController.getAppKeyAddress(accounts[0], 'wallet://3box.metamask.io')
let backupExists
try {
const threeBoxConfig = await Box.getConfig(this.address)
backupExists = threeBoxConfig.spaces && threeBoxConfig.spaces.metamask
} catch (e) {
log.error(e)
Gudahtt marked this conversation as resolved.
Show resolved Hide resolved
backupExists = false
}
if (this.getThreeBoxSyncingState() || backupExists) {
Gudahtt marked this conversation as resolved.
Show resolved Hide resolved
this.store.updateState({ threeBoxSynced: false })
this.address = await this.keyringController.getAppKeyAddress(address, 'wallet://3box.metamask.io')

let timedOut = false
const syncTimeout = setTimeout(() => {
Expand All @@ -121,13 +134,13 @@ class ThreeBoxController {
})
}, SYNC_TIMEOUT)
try {
this.box = await Box.openBox(address, this.provider)
this.box = await Box.openBox(this.address, this.provider)
await this._waitForOnSyncDone()
this.space = await this.box.openSpace('metamask', {
onSyncDone: async () => {
const stateUpdate = {
threeBoxSynced: true,
threeBoxAddress: address,
threeBoxAddress: this.address,
}
if (timedOut) {
log.info(`3Box sync completed after timeout; no longer disabled`)
Expand All @@ -136,6 +149,7 @@ class ThreeBoxController {

clearTimeout(syncTimeout)
this.store.updateState(stateUpdate)

log.debug('3Box space sync done')
},
})
Expand All @@ -147,15 +161,36 @@ class ThreeBoxController {
}

async getLastUpdated () {
return await this.space.private.get('lastUpdated')
const res = await this.space.private.get('metamaskBackup')
const parsedRes = JSON.parse(res || '{}')
return parsedRes.lastUpdated
}

async migrateBackedUpState (backedUpState) {
const migrator = new Migrator({ migrations })

const formattedStateBackup = {
PreferencesController: backedUpState.preferences,
AddressBookController: backedUpState.addressBook,
}
const initialMigrationState = migrator.generateInitialState(formattedStateBackup)
const migratedState = await migrator.migrateData(initialMigrationState)
return {
preferences: migratedState.PreferencesController,
addressBook: migratedState.AddressBookController,
}
}

async restoreFromThreeBox () {
this.setRestoredFromThreeBoxToTrue()
const backedUpPreferences = await this.space.private.get('preferences')
backedUpPreferences && this.preferencesController.store.updateState(JSON.parse(backedUpPreferences))
const backedUpAddressBook = await this.space.private.get('addressBook')
backedUpAddressBook && this.addressBookController.update(JSON.parse(backedUpAddressBook), true)
const backedUpState = await this.space.private.get('metamaskBackup')
const {
preferences,
addressBook,
} = await this.migrateBackedUpState(backedUpState)
this.store.updateState({ threeBoxLastUpdated: backedUpState.lastUpdated })
preferences && this.preferencesController.store.updateState(JSON.parse(preferences))
addressBook && this.addressBookController.update(JSON.parse(addressBook), true)
this.setShowRestorePromptToFalse()
}

turnThreeBoxSyncingOn () {
Expand All @@ -166,12 +201,8 @@ class ThreeBoxController {
this.box.logout()
}

setRestoredFromThreeBoxToTrue () {
this.store.updateState({ restoredFromThreeBox: true })
}

setRestoredFromThreeBoxToFalse () {
this.store.updateState({ restoredFromThreeBox: false })
setShowRestorePromptToFalse () {
this.store.updateState({ showRestorePrompt: false })
}

setThreeBoxSyncingPermission (newThreeboxSyncingState) {
Expand Down Expand Up @@ -201,9 +232,9 @@ class ThreeBoxController {

_registerUpdates () {
if (!this.registeringUpdates) {
const updatePreferences = this._update3Box.bind(this, { type: 'preferences' })
const updatePreferences = this._update3Box.bind(this)
this.preferencesController.store.subscribe(updatePreferences)
const updateAddressBook = this._update3Box.bind(this, { type: 'addressBook' })
const updateAddressBook = this._update3Box.bind(this)
this.addressBookController.subscribe(updateAddressBook)
this.registeringUpdates = true
}
Expand Down
20 changes: 8 additions & 12 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ module.exports = class MetamaskController extends EventEmitter {
// 3Box
setThreeBoxSyncingPermission: nodeify(threeBoxController.setThreeBoxSyncingPermission, threeBoxController),
restoreFromThreeBox: nodeify(threeBoxController.restoreFromThreeBox, threeBoxController),
setRestoredFromThreeBoxToFalse: nodeify(threeBoxController.setRestoredFromThreeBoxToFalse, threeBoxController),
setShowRestorePromptToFalse: nodeify(threeBoxController.setShowRestorePromptToFalse, threeBoxController),
getThreeBoxLastUpdated: nodeify(threeBoxController.getLastUpdated, threeBoxController),
turnThreeBoxSyncingOn: nodeify(threeBoxController.turnThreeBoxSyncingOn, threeBoxController),
initializeThreeBox: nodeify(this.initializeThreeBox, this),
Expand Down Expand Up @@ -741,16 +741,12 @@ module.exports = class MetamaskController extends EventEmitter {
await this.preferencesController.syncAddresses(accounts)
await this.txController.pendingTxTracker.updatePendingTxs()

const threeBoxFeatureFlagTurnedOn = this.preferencesController.getFeatureFlags().threeBox

if (threeBoxFeatureFlagTurnedOn) {
const threeBoxSyncingAllowed = this.threeBoxController.getThreeBoxSyncingState()
if (threeBoxSyncingAllowed && !this.threeBoxController.box) {
await this.threeBoxController.new3Box()
this.threeBoxController.turnThreeBoxSyncingOn()
} else if (threeBoxSyncingAllowed && this.threeBoxController.box) {
this.threeBoxController.turnThreeBoxSyncingOn()
}
const threeBoxSyncingAllowed = this.threeBoxController.getThreeBoxSyncingState()
if (threeBoxSyncingAllowed && !this.threeBoxController.box) {
await this.threeBoxController.new3Box()
this.threeBoxController.turnThreeBoxSyncingOn()
} else if (threeBoxSyncingAllowed && this.threeBoxController.box) {
this.threeBoxController.turnThreeBoxSyncingOn()
}

return this.keyringController.fullUpdate()
Expand Down Expand Up @@ -1703,7 +1699,7 @@ module.exports = class MetamaskController extends EventEmitter {
}

async initializeThreeBox () {
await this.threeBoxController.new3Box()
await this.threeBoxController.init()
}

/**
Expand Down
7 changes: 7 additions & 0 deletions development/mock-3box.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ class Mock3Box {
logout: () => {},
})
}

static async getConfig (address) {
const backup = await loadFromMock3Box(`${address}-metamask-metamaskBackup`)
return backup
? { spaces: { metamask: {} } }
: {}
}
}

module.exports = Mock3Box
31 changes: 18 additions & 13 deletions test/e2e/threebox.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,6 @@ describe('MetaMask', function () {
describe('set up data to be restored by 3box', () => {

describe('First time flow starting from an existing seed phrase', () => {
it('turns on the threebox feature flag', async () => {
await delay(largeDelayMs)
await driver.executeScript('window.metamask.setFeatureFlag("threeBox", true)')
await delay(largeDelayMs)
})

it('clicks the continue button on the welcome screen', async () => {
await findElement(driver, By.css('.welcome-page__header'))
const welcomeScreenBtn = await findElement(driver, By.css('.first-time-flow__button'))
Expand Down Expand Up @@ -108,7 +102,7 @@ describe('MetaMask', function () {
})
})

describe('updates settings and address book', () => {
describe('turns on threebox syncing', () => {
it('goes to the settings screen', async () => {
await driver.findElement(By.css('.account-menu__icon')).click()
await delay(regularDelayMs)
Expand All @@ -117,6 +111,23 @@ describe('MetaMask', function () {
settingsButton.click()
})

it('turns on threebox syncing', async () => {
const advancedButton = await findElement(driver, By.xpath(`//div[contains(text(), 'Advanced')]`))
await advancedButton.click()

const threeBoxToggle = await findElements(driver, By.css('.toggle-button'))
const threeBoxToggleButton = await threeBoxToggle[3].findElement(By.css('div'))
await threeBoxToggleButton.click()
})

})

describe('updates settings and address book', () => {
it('adds an address to the contact list', async () => {
const generalButton = await findElement(driver, By.xpath(`//div[contains(text(), 'General')]`))
await generalButton.click()
})

it('turns on use of blockies', async () => {
const toggleButton = await findElement(driver, By.css('.toggle-button > div'))
await toggleButton.click()
Expand Down Expand Up @@ -163,12 +174,6 @@ describe('MetaMask', function () {
})

describe('First time flow starting from an existing seed phrase', () => {
it('turns on the threebox feature flag', async () => {
await delay(largeDelayMs)
await driver2.executeScript('window.metamask.setFeatureFlag("threeBox", true)')
await delay(largeDelayMs)
})

it('clicks the continue button on the welcome screen', async () => {
await findElement(driver2, By.css('.welcome-page__header'))
const welcomeScreenBtn = await findElement(driver2, By.css('.first-time-flow__button'))
Expand Down
9 changes: 1 addition & 8 deletions test/unit/app/controllers/metamask-controller-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,7 @@ describe('MetaMaskController', function () {
})
})

it('gets does not instantiate 3box if the feature flag is false', async () => {
await metamaskController.submitPassword(password)
assert(threeBoxSpies.new3Box.notCalled)
assert(threeBoxSpies.turnThreeBoxSyncingOn.notCalled)
})

it('gets the address from threebox and creates a new 3box instance if the feature flag is true', async () => {
metamaskController.preferencesController.setFeatureFlag('threeBox', true)
it('gets the address from threebox and creates a new 3box instance', async () => {
await metamaskController.submitPassword(password)
assert(threeBoxSpies.new3Box.calledOnce)
assert(threeBoxSpies.turnThreeBoxSyncingOn.calledOnce)
Expand Down
18 changes: 8 additions & 10 deletions ui/app/pages/home/home.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,11 @@ export default class Home extends PureComponent {
threeBoxSynced: PropTypes.bool,
setupThreeBox: PropTypes.func,
turnThreeBoxSyncingOn: PropTypes.func,
restoredFromThreeBox: PropTypes.bool,
showRestorePrompt: PropTypes.bool,
selectedAddress: PropTypes.string,
restoreFromThreeBox: PropTypes.func,
setRestoredFromThreeBoxToFalse: PropTypes.func,
setShowRestorePromptToFalse: PropTypes.func,
threeBoxLastUpdated: PropTypes.string,
threeBoxFeatureFlagIsTrue: PropTypes.bool,
}

componentWillMount () {
Expand Down Expand Up @@ -73,10 +72,10 @@ export default class Home extends PureComponent {
const {
threeBoxSynced,
setupThreeBox,
restoredFromThreeBox,
showRestorePrompt,
threeBoxLastUpdated,
} = this.props
if (threeBoxSynced && restoredFromThreeBox === null && threeBoxLastUpdated === null) {
if (threeBoxSynced && showRestorePrompt && threeBoxLastUpdated === null) {
setupThreeBox()
}
}
Expand All @@ -94,10 +93,9 @@ export default class Home extends PureComponent {
selectedAddress,
restoreFromThreeBox,
turnThreeBoxSyncingOn,
setRestoredFromThreeBoxToFalse,
restoredFromThreeBox,
setShowRestorePromptToFalse,
showRestorePrompt,
threeBoxLastUpdated,
threeBoxFeatureFlagIsTrue,
} = this.props

if (forgottenPassword) {
Expand Down Expand Up @@ -155,7 +153,7 @@ export default class Home extends PureComponent {
/>,
},
{
shouldBeRendered: threeBoxFeatureFlagIsTrue && threeBoxLastUpdated && restoredFromThreeBox === null,
shouldBeRendered: threeBoxLastUpdated && showRestorePrompt,
component: <HomeNotification
descriptionText={t('restoreWalletPreferences', [ formatDate(parseInt(threeBoxLastUpdated), 'M/d/y') ])}
acceptText={t('restore')}
Expand All @@ -168,7 +166,7 @@ export default class Home extends PureComponent {
})
}}
onIgnore={() => {
setRestoredFromThreeBoxToFalse()
setShowRestorePromptToFalse()
}}
key="home-privacyModeDefault"
/>,
Expand Down
Loading