mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge branch 'i328-MultiVault' of github.com:MetaMask/metamask-plugin into i328-MultiVault
This commit is contained in:
commit
9b4f3825e7
@ -11,8 +11,10 @@ const createId = require('web3-provider-engine/util/random-id')
|
|||||||
|
|
||||||
// Keyrings:
|
// Keyrings:
|
||||||
const SimpleKeyring = require('./keyrings/simple')
|
const SimpleKeyring = require('./keyrings/simple')
|
||||||
|
const HdKeyring = require('./keyrings/hd')
|
||||||
const keyringTypes = [
|
const keyringTypes = [
|
||||||
SimpleKeyring,
|
SimpleKeyring,
|
||||||
|
HdKeyring,
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports = class KeyringController extends EventEmitter {
|
module.exports = class KeyringController extends EventEmitter {
|
||||||
@ -67,7 +69,12 @@ module.exports = class KeyringController extends EventEmitter {
|
|||||||
})
|
})
|
||||||
.then((encryptedString) => {
|
.then((encryptedString) => {
|
||||||
this.configManager.setVault(encryptedString)
|
this.configManager.setVault(encryptedString)
|
||||||
cb(null, this.getState())
|
|
||||||
|
// TEMPORARY SINGLE-KEYRING CONFIG:
|
||||||
|
this.addNewKeyring('HD Key Tree', null, cb)
|
||||||
|
|
||||||
|
// NORMAL BEHAVIOR:
|
||||||
|
// cb(null, this.getState())
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
cb(err)
|
cb(err)
|
||||||
@ -97,25 +104,35 @@ module.exports = class KeyringController extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addNewKeyring(type, opts, cb) {
|
addNewKeyring(type, opts, cb) {
|
||||||
const i = this.getAccounts().length
|
|
||||||
const Keyring = this.getKeyringClassForType(type)
|
const Keyring = this.getKeyringClassForType(type)
|
||||||
const keyring = new Keyring(opts)
|
const keyring = new Keyring(opts)
|
||||||
const accounts = keyring.addAccounts(1)
|
const accounts = keyring.addAccounts(1)
|
||||||
|
|
||||||
accounts.forEach((account) => {
|
this.setupAccounts(accounts)
|
||||||
this.loadBalanceAndNickname(account, i)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.keyrings.push(keyring)
|
this.keyrings.push(keyring)
|
||||||
this.persistAllKeyrings()
|
this.persistAllKeyrings()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
cb(this.getState())
|
cb(null, this.getState())
|
||||||
})
|
})
|
||||||
.catch((reason) => {
|
.catch((reason) => {
|
||||||
cb(reason)
|
cb(reason)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addNewAccount(keyRingNum = 0, cb) {
|
||||||
|
const ring = this.keyrings[keyRingNum]
|
||||||
|
const accounts = ring.addAccounts(1)
|
||||||
|
this.setupAccounts(accounts)
|
||||||
|
cb(null, this.getState())
|
||||||
|
}
|
||||||
|
|
||||||
|
setupAccounts(accounts) {
|
||||||
|
const i = this.getAccounts().length
|
||||||
|
accounts.forEach((account) => {
|
||||||
|
this.loadBalanceAndNickname(account, i)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Takes an account address and an iterator representing
|
// Takes an account address and an iterator representing
|
||||||
// the current number of named accounts.
|
// the current number of named accounts.
|
||||||
loadBalanceAndNickname(account, i) {
|
loadBalanceAndNickname(account, i) {
|
||||||
|
86
app/scripts/keyrings/hd.js
Normal file
86
app/scripts/keyrings/hd.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
const EventEmitter = require('events').EventEmitter
|
||||||
|
const hdkey = require('ethereumjs-wallet/hdkey')
|
||||||
|
const bip39 = require('bip39')
|
||||||
|
const ethUtil = require('ethereumjs-util')
|
||||||
|
const type = 'HD Key Tree'
|
||||||
|
const sigUtil = require('../lib/sig-util')
|
||||||
|
|
||||||
|
const hdPathString = `m/44'/60'/0'/0`
|
||||||
|
|
||||||
|
module.exports = class HdKeyring extends EventEmitter {
|
||||||
|
|
||||||
|
static type() {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(opts) {
|
||||||
|
super()
|
||||||
|
this.type = type
|
||||||
|
this.opts = opts || {}
|
||||||
|
this.wallets = []
|
||||||
|
this.mnemonic = null
|
||||||
|
}
|
||||||
|
|
||||||
|
deserialize({ mnemonic, n }) {
|
||||||
|
this.initFromMnemonic(mnemonic || bip39.generateMnemonic())
|
||||||
|
this.addAccounts(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
initFromMnemonic(mnemonic) {
|
||||||
|
const seed = bip39.mnemonicToSeed(mnemonic)
|
||||||
|
this.mnemonic = mnemonic
|
||||||
|
this.hdWallet = hdkey.fromMasterSeed(seed)
|
||||||
|
this.root = this.hdWallet.derivePath(hdPathString)
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize() {
|
||||||
|
return {
|
||||||
|
mnemonic: this.mnemonic,
|
||||||
|
n: this.wallets.length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addAccounts(n = 1) {
|
||||||
|
if (!this.root) {
|
||||||
|
this.initFromMnemonic(bip39.generateMnemonic())
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldLen = this.wallets.length
|
||||||
|
const newWallets = []
|
||||||
|
for (let i = oldLen; i < n + oldLen; i++) {
|
||||||
|
const child = this.root.deriveChild(i)
|
||||||
|
const wallet = child.getWallet()
|
||||||
|
newWallets.push(wallet)
|
||||||
|
this.wallets.push(wallet)
|
||||||
|
}
|
||||||
|
return newWallets.map(w => w.getAddress().toString('hex'))
|
||||||
|
}
|
||||||
|
|
||||||
|
getAccounts() {
|
||||||
|
return this.wallets.map(w => w.getAddress().toString('hex'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// tx is an instance of the ethereumjs-transaction class.
|
||||||
|
signTransaction(address, tx) {
|
||||||
|
const wallet = this.getWalletForAccount(address)
|
||||||
|
var privKey = wallet.getPrivateKey()
|
||||||
|
tx.sign(privKey)
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
|
// For eth_sign, we need to sign transactions:
|
||||||
|
signMessage(withAccount, data) {
|
||||||
|
const wallet = this.getWalletForAccount(withAccount)
|
||||||
|
const message = ethUtil.removeHexPrefix(data)
|
||||||
|
var privKey = wallet.getPrivateKey()
|
||||||
|
var msgSig = ethUtil.ecsign(new Buffer(message, 'hex'), privKey)
|
||||||
|
var rawMsgSig = ethUtil.bufferToHex(sigUtil.concatSig(msgSig.v, msgSig.r, msgSig.s))
|
||||||
|
return rawMsgSig
|
||||||
|
}
|
||||||
|
|
||||||
|
getWalletForAccount(account) {
|
||||||
|
return this.wallets.find(w => w.getAddress().toString('hex') === account)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -61,6 +61,7 @@ module.exports = class MetamaskController {
|
|||||||
// forward directly to keyringController
|
// forward directly to keyringController
|
||||||
createNewVault: keyringController.createNewVault.bind(keyringController),
|
createNewVault: keyringController.createNewVault.bind(keyringController),
|
||||||
addNewKeyring: keyringController.addNewKeyring.bind(keyringController),
|
addNewKeyring: keyringController.addNewKeyring.bind(keyringController),
|
||||||
|
addNewAccount: keyringController.addNewAccount.bind(keyringController),
|
||||||
submitPassword: keyringController.submitPassword.bind(keyringController),
|
submitPassword: keyringController.submitPassword.bind(keyringController),
|
||||||
setSelectedAddress: keyringController.setSelectedAddress.bind(keyringController),
|
setSelectedAddress: keyringController.setSelectedAddress.bind(keyringController),
|
||||||
approveTransaction: keyringController.approveTransaction.bind(keyringController),
|
approveTransaction: keyringController.approveTransaction.bind(keyringController),
|
||||||
|
File diff suppressed because one or more lines are too long
39
development/states/first-time.json
Normal file
39
development/states/first-time.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"metamask": {
|
||||||
|
"isInitialized": false,
|
||||||
|
"isUnlocked": false,
|
||||||
|
"rpcTarget": "https://rawtestrpc.metamask.io/",
|
||||||
|
"identities": {},
|
||||||
|
"unconfTxs": {},
|
||||||
|
"currentFiat": "USD",
|
||||||
|
"conversionRate": 11.47635827,
|
||||||
|
"conversionDate": 1477606503,
|
||||||
|
"network": null,
|
||||||
|
"accounts": {},
|
||||||
|
"transactions": [],
|
||||||
|
"isConfirmed": true,
|
||||||
|
"unconfMsgs": {},
|
||||||
|
"messages": [],
|
||||||
|
"shapeShiftTxList": [],
|
||||||
|
"keyringTypes": [
|
||||||
|
"Simple Key Pair"
|
||||||
|
],
|
||||||
|
"provider": {
|
||||||
|
"type": "testnet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"appState": {
|
||||||
|
"menuOpen": false,
|
||||||
|
"currentView": {
|
||||||
|
"name": "accounts",
|
||||||
|
"detailView": null
|
||||||
|
},
|
||||||
|
"accountDetail": {
|
||||||
|
"subview": "transactions"
|
||||||
|
},
|
||||||
|
"transForward": true,
|
||||||
|
"isLoading": false,
|
||||||
|
"warning": null
|
||||||
|
},
|
||||||
|
"identities": {}
|
||||||
|
}
|
@ -34,6 +34,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^1.5.2",
|
"async": "^1.5.2",
|
||||||
|
"bip39": "^2.2.0",
|
||||||
"browserify-derequire": "^0.9.4",
|
"browserify-derequire": "^0.9.4",
|
||||||
"clone": "^1.0.2",
|
"clone": "^1.0.2",
|
||||||
"copy-to-clipboard": "^2.0.0",
|
"copy-to-clipboard": "^2.0.0",
|
||||||
@ -55,7 +56,7 @@
|
|||||||
"iframe": "^1.0.0",
|
"iframe": "^1.0.0",
|
||||||
"iframe-stream": "^1.0.2",
|
"iframe-stream": "^1.0.2",
|
||||||
"inject-css": "^0.1.1",
|
"inject-css": "^0.1.1",
|
||||||
"jazzicon": "^1.1.3",
|
"jazzicon": "^1.2.0",
|
||||||
"menu-droppo": "^1.1.0",
|
"menu-droppo": "^1.1.0",
|
||||||
"metamask-logo": "^2.1.2",
|
"metamask-logo": "^2.1.2",
|
||||||
"mississippi": "^1.2.0",
|
"mississippi": "^1.2.0",
|
||||||
|
91
test/unit/idStore-migration-test.js
Normal file
91
test/unit/idStore-migration-test.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
const async = require('async')
|
||||||
|
const assert = require('assert')
|
||||||
|
const ethUtil = require('ethereumjs-util')
|
||||||
|
const BN = ethUtil.BN
|
||||||
|
const configManagerGen = require('../lib/mock-config-manager')
|
||||||
|
const delegateCallCode = require('../lib/example-code.json').delegateCallCode
|
||||||
|
|
||||||
|
// The old way:
|
||||||
|
const IdentityStore = require('../../app/scripts/lib/idStore')
|
||||||
|
|
||||||
|
// The new ways:
|
||||||
|
var KeyringController = require('../../app/scripts/keyring-controller')
|
||||||
|
const mockEncryptor = require('../lib/mock-encryptor')
|
||||||
|
const MockSimpleKeychain = require('../lib/mock-simple-keychain')
|
||||||
|
const sinon = require('sinon')
|
||||||
|
|
||||||
|
const mockVault = {
|
||||||
|
seed: 'picnic injury awful upper eagle junk alert toss flower renew silly vague',
|
||||||
|
account: '0x5d8de92c205279c10e5669f797b853ccef4f739a',
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('IdentityStore to KeyringController migration', function() {
|
||||||
|
|
||||||
|
// The stars of the show:
|
||||||
|
let idStore, keyringController, seedWords
|
||||||
|
|
||||||
|
let password = 'password123'
|
||||||
|
let entropy = 'entripppppyy duuude'
|
||||||
|
let accounts = []
|
||||||
|
let newAccounts = []
|
||||||
|
let originalKeystore
|
||||||
|
|
||||||
|
// This is a lot of setup, I know!
|
||||||
|
// We have to create an old style vault, populate it,
|
||||||
|
// and THEN create a new one, before we can run tests on it.
|
||||||
|
beforeEach(function(done) {
|
||||||
|
this.sinon = sinon.sandbox.create()
|
||||||
|
window.localStorage = {} // Hacking localStorage support into JSDom
|
||||||
|
var configManager = configManagerGen()
|
||||||
|
|
||||||
|
window.localStorage = {} // Hacking localStorage support into JSDom
|
||||||
|
|
||||||
|
idStore = new IdentityStore({
|
||||||
|
configManager: configManagerGen(),
|
||||||
|
ethStore: {
|
||||||
|
addAccount(acct) { accounts.push(ethUtil.addHexPrefix(acct)) },
|
||||||
|
del(acct) { delete accounts[acct] },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
idStore._createVault(password, mockVault.seed, null, function (err, seeds) {
|
||||||
|
assert.ifError(err, 'createNewVault threw error')
|
||||||
|
originalKeystore = idStore._idmgmt.keyStore
|
||||||
|
|
||||||
|
idStore.setLocked(function(err) {
|
||||||
|
assert.ifError(err, 'createNewVault threw error')
|
||||||
|
keyringController = new KeyringController({
|
||||||
|
configManager,
|
||||||
|
ethStore: {
|
||||||
|
addAccount(acct) { newAccounts.push(ethUtil.addHexPrefix(acct)) },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Stub out the browser crypto for a mock encryptor.
|
||||||
|
// Browser crypto is tested in the integration test suite.
|
||||||
|
keyringController.encryptor = mockEncryptor
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('creating new vault type', function() {
|
||||||
|
it('should use the password to migrate the old vault', function(done) {
|
||||||
|
keyringController.createNewVault(password, null, function (err, state) {
|
||||||
|
assert.ifError(err, 'createNewVault threw error')
|
||||||
|
|
||||||
|
let newAccounts = keyringController.getAccounts()
|
||||||
|
let newAccount = ethUtil.addHexPrefix(newAccounts[0])
|
||||||
|
assert.equal(newAccount, accounts[0], 'restored the account')
|
||||||
|
assert.equal(newAccount, mockVault.account, 'restored the correct account')
|
||||||
|
|
||||||
|
const newSeed = keyringController.keyrings[0].mnemonic
|
||||||
|
assert.equal(newSeed, mockVault.seed, 'seed phrase transferred.')
|
||||||
|
|
||||||
|
assert(configManager.getVault(), 'new type of vault is persisted')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
97
test/unit/keyrings/hd-test.js
Normal file
97
test/unit/keyrings/hd-test.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
const assert = require('assert')
|
||||||
|
const extend = require('xtend')
|
||||||
|
const HdKeyring = require('../../../app/scripts/keyrings/hd')
|
||||||
|
|
||||||
|
// Sample account:
|
||||||
|
const privKeyHex = 'b8a9c05beeedb25df85f8d641538cbffedf67216048de9c678ee26260eb91952'
|
||||||
|
|
||||||
|
const sampleMnemonic = 'finish oppose decorate face calm tragic certain desk hour urge dinosaur mango'
|
||||||
|
const firstAcct = '1c96099350f13d558464ec79b9be4445aa0ef579'
|
||||||
|
const secondAcct = '1b00aed43a693f3a957f9feb5cc08afa031e37a0'
|
||||||
|
|
||||||
|
describe('simple-keyring', function() {
|
||||||
|
|
||||||
|
let keyring
|
||||||
|
beforeEach(function() {
|
||||||
|
keyring = new HdKeyring()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Keyring.type()', function() {
|
||||||
|
it('is a class method that returns the type string.', function() {
|
||||||
|
const type = HdKeyring.type()
|
||||||
|
assert.equal(typeof type, 'string')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#type', function() {
|
||||||
|
it('returns the correct value', function() {
|
||||||
|
const type = keyring.type
|
||||||
|
const correct = HdKeyring.type()
|
||||||
|
assert.equal(type, correct)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#serialize empty wallets.', function() {
|
||||||
|
it('serializes a new mnemonic', function() {
|
||||||
|
const output = keyring.serialize()
|
||||||
|
assert.equal(output.n, 0)
|
||||||
|
assert.equal(output.mnemonic, null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#deserialize a private key', function() {
|
||||||
|
it('serializes what it deserializes', function() {
|
||||||
|
keyring.deserialize({
|
||||||
|
mnemonic: sampleMnemonic,
|
||||||
|
n: 1
|
||||||
|
})
|
||||||
|
assert.equal(keyring.wallets.length, 1, 'restores two accounts')
|
||||||
|
keyring.addAccounts(1)
|
||||||
|
|
||||||
|
const accounts = keyring.getAccounts()
|
||||||
|
assert.equal(accounts[0], firstAcct)
|
||||||
|
assert.equal(accounts[1], secondAcct)
|
||||||
|
assert.equal(accounts.length, 2)
|
||||||
|
|
||||||
|
const serialized = keyring.serialize()
|
||||||
|
assert.equal(serialized.mnemonic, sampleMnemonic)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#addAccounts', function() {
|
||||||
|
describe('with no arguments', function() {
|
||||||
|
it('creates a single wallet', function() {
|
||||||
|
keyring.addAccounts()
|
||||||
|
assert.equal(keyring.wallets.length, 1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with a numeric argument', function() {
|
||||||
|
it('creates that number of wallets', function() {
|
||||||
|
keyring.addAccounts(3)
|
||||||
|
assert.equal(keyring.wallets.length, 3)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#getAccounts', function() {
|
||||||
|
it('calls getAddress on each wallet', function() {
|
||||||
|
|
||||||
|
// Push a mock wallet
|
||||||
|
const desiredOutput = 'foo'
|
||||||
|
keyring.wallets.push({
|
||||||
|
getAddress() {
|
||||||
|
return {
|
||||||
|
toString() {
|
||||||
|
return desiredOutput
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const output = keyring.getAccounts()
|
||||||
|
assert.equal(output[0], desiredOutput)
|
||||||
|
assert.equal(output.length, 1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -87,7 +87,7 @@ AccountsScreen.prototype.render = function () {
|
|||||||
h('div.footer.hover-white.pointer', {
|
h('div.footer.hover-white.pointer', {
|
||||||
key: 'reveal-account-bar',
|
key: 'reveal-account-bar',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
this.addNewKeyring()
|
this.addNewAccount()
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -146,8 +146,8 @@ AccountsScreen.prototype.onShowDetail = function (address, event) {
|
|||||||
this.props.dispatch(actions.showAccountDetail(address))
|
this.props.dispatch(actions.showAccountDetail(address))
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountsScreen.prototype.addNewKeyring = function () {
|
AccountsScreen.prototype.addNewAccount = function () {
|
||||||
this.props.dispatch(actions.addNewKeyring('Simple Key Pair'))
|
this.props.dispatch(actions.addNewAccount(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountsScreen.prototype.goHome = function () {
|
AccountsScreen.prototype.goHome = function () {
|
||||||
|
@ -25,7 +25,8 @@ var actions = {
|
|||||||
showInitializeMenu: showInitializeMenu,
|
showInitializeMenu: showInitializeMenu,
|
||||||
createNewVault: createNewVault,
|
createNewVault: createNewVault,
|
||||||
createNewVaultInProgress: createNewVaultInProgress,
|
createNewVaultInProgress: createNewVaultInProgress,
|
||||||
addNewKeyring: addNewKeyring,
|
addNewKeyring,
|
||||||
|
addNewAccount,
|
||||||
showNewVaultSeed: showNewVaultSeed,
|
showNewVaultSeed: showNewVaultSeed,
|
||||||
showInfoPage: showInfoPage,
|
showInfoPage: showInfoPage,
|
||||||
// unlock screen
|
// unlock screen
|
||||||
@ -178,6 +179,7 @@ function createNewVault (password, entropy) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return dispatch(actions.showWarning(err.message))
|
return dispatch(actions.showWarning(err.message))
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(this.updateMetamaskState(newState))
|
dispatch(this.updateMetamaskState(newState))
|
||||||
dispatch(this.showAccountsPage())
|
dispatch(this.showAccountsPage())
|
||||||
dispatch(this.hideLoadingIndication())
|
dispatch(this.hideLoadingIndication())
|
||||||
@ -199,6 +201,19 @@ function addNewKeyring (type, opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addNewAccount (ringNumber = 0) {
|
||||||
|
return (dispatch) => {
|
||||||
|
dispatch(actions.showLoadingIndication())
|
||||||
|
background.addNewAccount(ringNumber, (err, newState) => {
|
||||||
|
dispatch(this.hideLoadingIndication())
|
||||||
|
if (err) {
|
||||||
|
return dispatch(actions.showWarning(err))
|
||||||
|
}
|
||||||
|
dispatch(this.updateMetamaskState(newState))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function showInfoPage () {
|
function showInfoPage () {
|
||||||
return {
|
return {
|
||||||
type: actions.SHOW_INFO_PAGE,
|
type: actions.SHOW_INFO_PAGE,
|
||||||
|
@ -16,8 +16,8 @@ function IdenticonComponent () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IdenticonComponent.prototype.render = function () {
|
IdenticonComponent.prototype.render = function () {
|
||||||
var state = this.props
|
var props = this.props
|
||||||
var diameter = state.diameter || this.defaultDiameter
|
var diameter = props.diameter || this.defaultDiameter
|
||||||
return (
|
return (
|
||||||
h('div', {
|
h('div', {
|
||||||
key: 'identicon-' + this.props.address,
|
key: 'identicon-' + this.props.address,
|
||||||
@ -33,15 +33,14 @@ IdenticonComponent.prototype.render = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IdenticonComponent.prototype.componentDidMount = function () {
|
IdenticonComponent.prototype.componentDidMount = function () {
|
||||||
var state = this.props
|
var props = this.props
|
||||||
var address = state.address
|
var address = props.address
|
||||||
|
|
||||||
if (!address) return
|
if (!address) return
|
||||||
|
|
||||||
var container = findDOMNode(this)
|
var container = findDOMNode(this)
|
||||||
var diameter = state.diameter || this.defaultDiameter
|
var diameter = props.diameter || this.defaultDiameter
|
||||||
var imageify = state.imageify === undefined ? true : state.imageify
|
var img = iconFactory.iconForAddress(address, diameter, false)
|
||||||
var img = iconFactory.iconForAddress(address, diameter, imageify)
|
|
||||||
container.appendChild(img)
|
container.appendChild(img)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ const connect = require('react-redux').connect
|
|||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const Mascot = require('../components/mascot')
|
const Mascot = require('../components/mascot')
|
||||||
const actions = require('../actions')
|
const actions = require('../actions')
|
||||||
|
const Tooltip = require('../components/tooltip')
|
||||||
|
const getCaretCoordinates = require('textarea-caret')
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(InitializeMenuScreen)
|
module.exports = connect(mapStateToProps)(InitializeMenuScreen)
|
||||||
|
|
||||||
@ -54,18 +56,73 @@ InitializeMenuScreen.prototype.renderMenu = function () {
|
|||||||
},
|
},
|
||||||
}, 'MetaMask'),
|
}, 'MetaMask'),
|
||||||
|
|
||||||
|
|
||||||
|
h('div', [
|
||||||
|
h('h3', {
|
||||||
|
style: {
|
||||||
|
fontSize: '0.8em',
|
||||||
|
color: '#7F8082',
|
||||||
|
display: 'inline',
|
||||||
|
},
|
||||||
|
}, 'Encrypt your new DEN'),
|
||||||
|
|
||||||
|
h(Tooltip, {
|
||||||
|
title: 'Your DEN is your password-encrypted storage within MetaMask.',
|
||||||
|
}, [
|
||||||
|
h('i.fa.fa-question-circle.pointer', {
|
||||||
|
style: {
|
||||||
|
fontSize: '18px',
|
||||||
|
position: 'relative',
|
||||||
|
color: 'rgb(247, 134, 28)',
|
||||||
|
top: '2px',
|
||||||
|
marginLeft: '4px',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
|
||||||
|
// password
|
||||||
|
h('input.large-input.letter-spacey', {
|
||||||
|
type: 'password',
|
||||||
|
id: 'password-box',
|
||||||
|
placeholder: 'New Password (min 8 chars)',
|
||||||
|
onInput: this.inputChanged.bind(this),
|
||||||
|
style: {
|
||||||
|
width: 260,
|
||||||
|
marginTop: 12,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
// confirm password
|
||||||
|
h('input.large-input.letter-spacey', {
|
||||||
|
type: 'password',
|
||||||
|
id: 'password-box-confirm',
|
||||||
|
placeholder: 'Confirm Password',
|
||||||
|
onKeyPress: this.createVaultOnEnter.bind(this),
|
||||||
|
onInput: this.inputChanged.bind(this),
|
||||||
|
style: {
|
||||||
|
width: 260,
|
||||||
|
marginTop: 16,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
|
||||||
h('button.primary', {
|
h('button.primary', {
|
||||||
onClick: this.showCreateVault.bind(this),
|
onClick: this.createNewVault.bind(this),
|
||||||
style: {
|
style: {
|
||||||
margin: 12,
|
margin: 12,
|
||||||
},
|
},
|
||||||
}, 'Create New Vault'),
|
}, 'Create'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
h('.flex-row.flex-center.flex-grow', [
|
h('.flex-row.flex-center.flex-grow', [
|
||||||
h('hr'),
|
h('p.pointer', {
|
||||||
h('div', 'Advanced (Eventually?)'),
|
style: {
|
||||||
h('hr'),
|
fontSize: '0.8em',
|
||||||
|
color: 'rgb(247, 134, 28)',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
},
|
||||||
|
}, 'I already have a DEN that I would like to import'),
|
||||||
]),
|
]),
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -73,7 +130,42 @@ InitializeMenuScreen.prototype.renderMenu = function () {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.showCreateVault = function () {
|
InitializeMenuScreen.prototype.createVaultOnEnter = function (event) {
|
||||||
this.props.dispatch(actions.showCreateVault())
|
if (event.key === 'Enter') {
|
||||||
|
event.preventDefault()
|
||||||
|
this.createNewVault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeMenuScreen.prototype.createNewVault = function () {
|
||||||
|
var passwordBox = document.getElementById('password-box')
|
||||||
|
var password = passwordBox.value
|
||||||
|
var passwordConfirmBox = document.getElementById('password-box-confirm')
|
||||||
|
var passwordConfirm = passwordConfirmBox.value
|
||||||
|
// var entropy = document.getElementById('entropy-text-entry').value
|
||||||
|
|
||||||
|
if (password.length < 8) {
|
||||||
|
this.warning = 'password not long enough'
|
||||||
|
this.props.dispatch(actions.displayWarning(this.warning))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (password !== passwordConfirm) {
|
||||||
|
this.warning = 'passwords don\'t match'
|
||||||
|
this.props.dispatch(actions.displayWarning(this.warning))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.dispatch(actions.createNewVault(password, ''/* entropy*/))
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeMenuScreen.prototype.inputChanged = function (event) {
|
||||||
|
// tell mascot to look at page action
|
||||||
|
var element = event.target
|
||||||
|
var boundingRect = element.getBoundingClientRect()
|
||||||
|
var coordinates = getCaretCoordinates(element, element.selectionEnd)
|
||||||
|
this.animationEventEmitter.emit('point', {
|
||||||
|
x: boundingRect.left + coordinates.left - element.scrollLeft,
|
||||||
|
y: boundingRect.top + coordinates.top - element.scrollTop,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +104,3 @@ UnlockScreen.prototype.inputChanged = function (event) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
UnlockScreen.prototype.emitAnim = function (name, a, b, c) {
|
|
||||||
this.animationEventEmitter.emit(name, a, b, c)
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user