mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
migrations - report migrations errors to sentry with vault structure
This commit is contained in:
parent
bcb5f14b06
commit
2b880dd4e0
@ -20,6 +20,7 @@ const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry')
|
||||
const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics')
|
||||
const EdgeEncryptor = require('./edge-encryptor')
|
||||
const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code')
|
||||
const getObjStructure = require('./lib/getObjStructure')
|
||||
|
||||
const STORAGE_KEY = 'metamask-config'
|
||||
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
|
||||
@ -77,6 +78,16 @@ async function loadStateFromPersistence () {
|
||||
diskStore.getState() ||
|
||||
migrator.generateInitialState(firstTimeState)
|
||||
|
||||
// report migration errors to sentry
|
||||
migrator.on('error', (err) => {
|
||||
// get vault structure without secrets
|
||||
const vaultStructure = getObjStructure(versionedData)
|
||||
raven.captureException(err, {
|
||||
// "extra" key is required by Sentry
|
||||
extra: { vaultStructure },
|
||||
})
|
||||
})
|
||||
|
||||
// migrate data
|
||||
versionedData = await migrator.migrateData(versionedData)
|
||||
if (!versionedData) {
|
||||
@ -84,7 +95,14 @@ async function loadStateFromPersistence () {
|
||||
}
|
||||
|
||||
// write to disk
|
||||
if (localStore.isSupported) localStore.set(versionedData)
|
||||
if (localStore.isSupported) {
|
||||
localStore.set(versionedData)
|
||||
} else {
|
||||
// throw in setTimeout so as to not block boot
|
||||
setTimeout(() => {
|
||||
throw new Error('MetaMask - Localstore not supported')
|
||||
})
|
||||
}
|
||||
|
||||
// return just the data
|
||||
return versionedData.data
|
||||
|
33
app/scripts/lib/getObjStructure.js
Normal file
33
app/scripts/lib/getObjStructure.js
Normal file
@ -0,0 +1,33 @@
|
||||
const clone = require('clone')
|
||||
|
||||
module.exports = getObjStructure
|
||||
|
||||
// This will create an object that represents the structure of the given object
|
||||
// it replaces all values with the result of their type
|
||||
|
||||
// {
|
||||
// "data": {
|
||||
// "CurrencyController": {
|
||||
// "conversionDate": "number",
|
||||
// "conversionRate": "number",
|
||||
// "currentCurrency": "string"
|
||||
// }
|
||||
// }
|
||||
|
||||
function getObjStructure(obj) {
|
||||
const structure = clone(obj)
|
||||
return deepMap(structure, (value) => {
|
||||
return value === null ? 'null' : typeof value
|
||||
})
|
||||
}
|
||||
|
||||
function deepMap(target = {}, visit) {
|
||||
Object.entries(target).forEach(([key, value]) => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
target[key] = deepMap(value, visit)
|
||||
} else {
|
||||
target[key] = visit(value)
|
||||
}
|
||||
})
|
||||
return target
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
class Migrator {
|
||||
const EventEmitter = require('events')
|
||||
|
||||
class Migrator extends EventEmitter {
|
||||
|
||||
constructor (opts = {}) {
|
||||
super()
|
||||
const migrations = opts.migrations || []
|
||||
// sort migrations by version
|
||||
this.migrations = migrations.sort((a, b) => a.version - b.version)
|
||||
@ -12,13 +15,26 @@ class Migrator {
|
||||
|
||||
// run all pending migrations on meta in place
|
||||
async migrateData (versionedData = this.generateInitialState()) {
|
||||
// get all migrations that have not yet been run
|
||||
const pendingMigrations = this.migrations.filter(migrationIsPending)
|
||||
|
||||
// perform each migration
|
||||
for (const index in pendingMigrations) {
|
||||
const migration = pendingMigrations[index]
|
||||
versionedData = await migration.migrate(versionedData)
|
||||
if (!versionedData.data) throw new Error('Migrator - migration returned empty data')
|
||||
if (versionedData.version !== undefined && versionedData.meta.version !== migration.version) throw new Error('Migrator - Migration did not update version number correctly')
|
||||
try {
|
||||
// attempt migration and validate
|
||||
const migratedData = await migration.migrate(versionedData)
|
||||
if (!migratedData.data) throw new Error('Migrator - migration returned empty data')
|
||||
if (migratedData.version !== undefined && migratedData.meta.version !== migration.version) throw new Error('Migrator - Migration did not update version number correctly')
|
||||
// accept the migration as good
|
||||
versionedData = migratedData
|
||||
} catch (err) {
|
||||
// emit error instead of throw so as to not break the run (gracefully fail)
|
||||
const error = new Error(`MetaMask Migration Error #${version}:\n${err.stack}`)
|
||||
this.emit('error', error)
|
||||
// stop migrating and use state as is
|
||||
return versionedData
|
||||
}
|
||||
}
|
||||
|
||||
return versionedData
|
||||
|
@ -13,17 +13,13 @@ const clone = require('clone')
|
||||
module.exports = {
|
||||
version,
|
||||
|
||||
migrate: function (originalVersionedData) {
|
||||
migrate: async function (originalVersionedData) {
|
||||
const versionedData = clone(originalVersionedData)
|
||||
versionedData.meta.version = version
|
||||
try {
|
||||
const state = versionedData.data
|
||||
const newState = transformState(state)
|
||||
versionedData.data = newState
|
||||
} catch (err) {
|
||||
console.warn(`MetaMask Migration #${version}` + err.stack)
|
||||
}
|
||||
return Promise.resolve(versionedData)
|
||||
const state = versionedData.data
|
||||
const newState = transformState(state)
|
||||
versionedData.data = newState
|
||||
return versionedData
|
||||
},
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user