mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge pull request #2630 from MetaMask/i2624-VersionedNotices
Versioned notices
This commit is contained in:
commit
c30b543a80
@ -2,8 +2,11 @@
|
||||
|
||||
## Current Master
|
||||
|
||||
## 3.12.1 2017-11-29
|
||||
|
||||
- Fix bug where a user could be shown two different seed phrases.
|
||||
- Detect when multiple web3 extensions are active, and provide useful error.
|
||||
- Adds notice about seed phrase backup.
|
||||
|
||||
## 3.12.0 2017-10-25
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "MetaMask",
|
||||
"short_name": "Metamask",
|
||||
"version": "3.12.0",
|
||||
"version": "3.12.1",
|
||||
"manifest_version": 2,
|
||||
"author": "https://metamask.io",
|
||||
"description": "Ethereum Browser Extension",
|
||||
|
@ -45,6 +45,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
|
||||
this.opts = opts
|
||||
const initState = opts.initState || {}
|
||||
this.recordFirstTimeInfo(initState)
|
||||
|
||||
// platform-specific api
|
||||
this.platform = opts.platform
|
||||
@ -150,6 +151,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
// notices
|
||||
this.noticeController = new NoticeController({
|
||||
initState: initState.NoticeController,
|
||||
version,
|
||||
firstVersion: initState.firstTimeInfo.version,
|
||||
})
|
||||
this.noticeController.updateNoticesList()
|
||||
// to be uncommented when retrieving notices from a remote server.
|
||||
@ -484,7 +487,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
vault = await this.keyringController.fullUpdate()
|
||||
|
||||
} else {
|
||||
let vault = await this.keyringController.createNewVaultAndKeychain(password)
|
||||
vault = await this.keyringController.createNewVaultAndKeychain(password)
|
||||
this.selectFirstIdentity(vault)
|
||||
}
|
||||
release()
|
||||
@ -798,4 +801,13 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
return rpcTarget
|
||||
}
|
||||
|
||||
recordFirstTimeInfo (initState) {
|
||||
if (!('firstTimeInfo' in initState)) {
|
||||
initState.firstTimeInfo = {
|
||||
version,
|
||||
date: Date.now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
41
app/scripts/migrations/020.js
Normal file
41
app/scripts/migrations/020.js
Normal file
@ -0,0 +1,41 @@
|
||||
const version = 20
|
||||
|
||||
/*
|
||||
|
||||
This migration ensures previous installations
|
||||
get a `firstTimeInfo` key on the metamask state,
|
||||
so that we can version notices in the future.
|
||||
|
||||
*/
|
||||
|
||||
const clone = require('clone')
|
||||
|
||||
module.exports = {
|
||||
version,
|
||||
|
||||
migrate: 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)
|
||||
},
|
||||
}
|
||||
|
||||
function transformState (state) {
|
||||
const newState = state
|
||||
if ('metamask' in newState &&
|
||||
!('firstTimeInfo' in newState.metamask)) {
|
||||
newState.metamask.firstTimeInfo = {
|
||||
version: '3.12.0',
|
||||
date: Date.now(),
|
||||
}
|
||||
}
|
||||
return newState
|
||||
}
|
||||
|
@ -30,4 +30,5 @@ module.exports = [
|
||||
require('./017'),
|
||||
require('./018'),
|
||||
require('./019'),
|
||||
require('./020'),
|
||||
]
|
||||
|
@ -1,13 +1,17 @@
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const semver = require('semver')
|
||||
const extend = require('xtend')
|
||||
const ObservableStore = require('obs-store')
|
||||
const hardCodedNotices = require('../../notices/notices.json')
|
||||
const uniqBy = require('lodash.uniqby')
|
||||
|
||||
module.exports = class NoticeController extends EventEmitter {
|
||||
|
||||
constructor (opts) {
|
||||
super()
|
||||
this.noticePoller = null
|
||||
this.firstVersion = opts.firstVersion
|
||||
this.version = opts.version
|
||||
const initState = extend({
|
||||
noticesList: [],
|
||||
}, opts.initState)
|
||||
@ -30,9 +34,9 @@ module.exports = class NoticeController extends EventEmitter {
|
||||
return unreadNotices[unreadNotices.length - 1]
|
||||
}
|
||||
|
||||
setNoticesList (noticesList) {
|
||||
async setNoticesList (noticesList) {
|
||||
this.store.updateState({ noticesList })
|
||||
return Promise.resolve(true)
|
||||
return true
|
||||
}
|
||||
|
||||
markNoticeRead (noticeToMark, cb) {
|
||||
@ -50,12 +54,14 @@ module.exports = class NoticeController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
updateNoticesList () {
|
||||
return this._retrieveNoticeData().then((newNotices) => {
|
||||
var oldNotices = this.getNoticesList()
|
||||
var combinedNotices = this._mergeNotices(oldNotices, newNotices)
|
||||
return Promise.resolve(this.setNoticesList(combinedNotices))
|
||||
})
|
||||
async updateNoticesList () {
|
||||
const newNotices = await this._retrieveNoticeData()
|
||||
const oldNotices = this.getNoticesList()
|
||||
const combinedNotices = this._mergeNotices(oldNotices, newNotices)
|
||||
const filteredNotices = this._filterNotices(combinedNotices)
|
||||
const result = this.setNoticesList(filteredNotices)
|
||||
this._updateMemstore()
|
||||
return result
|
||||
}
|
||||
|
||||
startPolling () {
|
||||
@ -68,22 +74,30 @@ module.exports = class NoticeController extends EventEmitter {
|
||||
}
|
||||
|
||||
_mergeNotices (oldNotices, newNotices) {
|
||||
var noticeMap = this._mapNoticeIds(oldNotices)
|
||||
newNotices.forEach((notice) => {
|
||||
if (noticeMap.indexOf(notice.id) === -1) {
|
||||
oldNotices.push(notice)
|
||||
return uniqBy(oldNotices.concat(newNotices), 'id')
|
||||
}
|
||||
|
||||
_filterNotices(notices) {
|
||||
return notices.filter((newNotice) => {
|
||||
if ('version' in newNotice) {
|
||||
const satisfied = semver.satisfies(this.version, newNotice.version)
|
||||
return satisfied
|
||||
}
|
||||
if ('firstVersion' in newNotice) {
|
||||
const satisfied = semver.satisfies(this.firstVersion, newNotice.firstVersion)
|
||||
return satisfied
|
||||
}
|
||||
return true
|
||||
})
|
||||
return oldNotices
|
||||
}
|
||||
|
||||
_mapNoticeIds (notices) {
|
||||
return notices.map((notice) => notice.id)
|
||||
}
|
||||
|
||||
_retrieveNoticeData () {
|
||||
async _retrieveNoticeData () {
|
||||
// Placeholder for the API.
|
||||
return Promise.resolve(hardCodedNotices)
|
||||
return hardCodedNotices
|
||||
}
|
||||
|
||||
_updateMemstore () {
|
||||
|
@ -64,7 +64,7 @@ class NoticeScreen extends Component {
|
||||
<Identicon address={address} diameter={70} />
|
||||
<div className="tou__title">{title}</div>
|
||||
<Markdown
|
||||
className="tou__body"
|
||||
className="tou__body markdown"
|
||||
source={body}
|
||||
skipHtml
|
||||
/>
|
||||
|
11
notices/archive/notice_3.md
Normal file
11
notices/archive/notice_3.md
Normal file
@ -0,0 +1,11 @@
|
||||
Please take a moment to [back up your seed phrase again](https://support.metamask.io/kb/article/28-abbu-always-be-backed-up-how-to-make-sure-your-12-word-metamask-seed-phrase-is-backed-up).
|
||||
|
||||
MetaMask has become aware of a previous issue where a very small number of users were shown the wrong seed phrase to back up. The only way to protect yourself from this issue, is to back up your seed phrase again now.
|
||||
|
||||
You can follow the guide at this link:
|
||||
|
||||
[https://support.metamask.io/kb/article/28-abbu-always-be-backed-up-how-to-make-sure-your-12-word-metamask-seed-phrase-is-backed-up](https://support.metamask.io/kb/article/28-abbu-always-be-backed-up-how-to-make-sure-your-12-word-metamask-seed-phrase-is-backed-up)
|
||||
|
||||
We have fixed the known issue, but will be issuing ongoing bug bounties to help prevent this kind of problem in the future.
|
||||
|
||||
For more information on this issue, [see this blog post](https://medium.com/metamask/seed-phrase-issue-bounty-awarded-e1986e811021)
|
@ -1 +1 @@
|
||||
3
|
||||
4
|
File diff suppressed because one or more lines are too long
@ -107,6 +107,7 @@
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.memoize": "^4.1.2",
|
||||
"lodash.shuffle": "^4.2.0",
|
||||
"lodash.uniqby": "^4.7.0",
|
||||
"loglevel": "^1.4.1",
|
||||
"metamascara": "^1.3.1",
|
||||
"metamask-logo": "^2.1.2",
|
||||
@ -144,6 +145,7 @@
|
||||
"request-promise": "^4.2.1",
|
||||
"sandwich-expando": "^1.1.3",
|
||||
"semaphore": "^1.0.5",
|
||||
"semver": "^5.4.1",
|
||||
"sw-stream": "^2.0.0",
|
||||
"textarea-caret": "^3.0.1",
|
||||
"through2": "^2.0.3",
|
||||
|
@ -6,23 +6,7 @@ async function runFirstTimeUsageTest (assert, done) {
|
||||
|
||||
const app = $('#app-content')
|
||||
|
||||
// recurse notices
|
||||
while (true) {
|
||||
const button = app.find('button')
|
||||
if (button.html() === 'Accept') {
|
||||
// still notices to accept
|
||||
const termsPage = app.find('.markdown')[0]
|
||||
termsPage.scrollTop = termsPage.scrollHeight
|
||||
await timeout()
|
||||
console.log('Clearing notice')
|
||||
button.click()
|
||||
await timeout()
|
||||
} else {
|
||||
// exit loop
|
||||
console.log('No more notices...')
|
||||
break
|
||||
}
|
||||
}
|
||||
await skipNotices(app)
|
||||
|
||||
await timeout()
|
||||
|
||||
@ -51,28 +35,13 @@ async function runFirstTimeUsageTest (assert, done) {
|
||||
assert.equal(created.textContent, 'Your unique account image', 'unique image screen')
|
||||
|
||||
// Agree button
|
||||
const button = app.find('button')[0]
|
||||
let button = app.find('button')[0]
|
||||
assert.ok(button, 'button present')
|
||||
button.click()
|
||||
|
||||
await timeout(1000)
|
||||
|
||||
// Privacy Screen
|
||||
const detail = app.find('.tou__title')[0]
|
||||
assert.equal(detail.textContent, 'Privacy Notice', 'privacy notice screen')
|
||||
app.find('button').click()
|
||||
|
||||
await timeout(1000)
|
||||
|
||||
|
||||
// terms of service screen
|
||||
const tou = app.find('.tou__title')[0]
|
||||
assert.equal(tou.textContent, 'Terms of Use', 'terms of use screen')
|
||||
app.find('.tou__body').scrollTop(100000)
|
||||
await timeout(1000)
|
||||
|
||||
app.find('.first-time-flow__button').click()
|
||||
await timeout(1000)
|
||||
await skipNotices(app)
|
||||
|
||||
// secret backup phrase
|
||||
const seedTitle = app.find('.backup-phrase__title')[0]
|
||||
@ -165,3 +134,23 @@ function timeout (time) {
|
||||
setTimeout(resolve, time || 1500)
|
||||
})
|
||||
}
|
||||
|
||||
async function skipNotices (app) {
|
||||
while (true) {
|
||||
const button = app.find('button')
|
||||
if (button && button.html() === 'Accept') {
|
||||
// still notices to accept
|
||||
const termsPage = app.find('.markdown')[0]
|
||||
if (!termsPage) {
|
||||
break
|
||||
}
|
||||
termsPage.scrollTop = termsPage.scrollHeight
|
||||
await timeout()
|
||||
button.click()
|
||||
await timeout()
|
||||
} else {
|
||||
console.log('No more notices...')
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user