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

Validate empty key #4513

Merged
merged 9 commits into from
Jun 14, 2018
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Current Master

- Attempting to import an empty private key will now show a clear error.
- Fix bug where metamask data would stop being written to disk after prolonged use
- Fix bug where account reset did not work with custom RPC providers.
- Fix bug where nonce mutex was never released
Expand Down
13 changes: 12 additions & 1 deletion app/scripts/account-import-strategies/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,18 @@ const accountImporter = {

strategies: {
'Private Key': (privateKey) => {
const stripped = ethUtil.stripHexPrefix(privateKey)
if (!privateKey) {
throw new Error('Cannot import an empty key.')
}

const prefixed = ethUtil.addHexPrefix(privateKey)
const buffer = ethUtil.toBuffer(prefixed)

if (!ethUtil.isValidPrivate(buffer)) {
throw new Error('Cannot import invalid private key.')
}

const stripped = ethUtil.stripHexPrefix(prefixed)
return stripped
},
'JSON File': (input, password) => {
Expand Down
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 45 additions & 17 deletions test/unit/app/account-import-strategies.spec.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,59 @@
const assert = require('assert')
const path = require('path')
const accountImporter = require('../../../app/scripts/account-import-strategies/index')
const ethUtil = require('ethereumjs-util')
const accountImporter = require('../../../app/scripts/account-import-strategies/index')
const { assertRejects } = require('../test-utils')

describe('Account Import Strategies', function () {
const privkey = '0x4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553'
const json = '{"version":3,"id":"dbb54385-0a99-437f-83c0-647de9f244c3","address":"a7f92ce3fba24196cf6f4bd2e1eb3db282ba998c","Crypto":{"ciphertext":"bde13d9ade5c82df80281ca363320ce254a8a3a06535bbf6ffdeaf0726b1312c","cipherparams":{"iv":"fbf93718a57f26051b292f072f2e5b41"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"7ffe00488319dec48e4c49a120ca49c6afbde9272854c64d9541c83fc6acdffe","n":8192,"r":8,"p":1},"mac":"2adfd9c4bc1cdac4c85bddfb31d9e21a684e0e050247a70c5698facf6b7d4681"}}'

it('imports a private key and strips 0x prefix', async function () {
const importPrivKey = await accountImporter.importAccount('Private Key', [ privkey ])
assert.equal(importPrivKey, ethUtil.stripHexPrefix(privkey))
})
describe('private key import', function () {
it('imports a private key and strips 0x prefix', async function () {
const importPrivKey = await accountImporter.importAccount('Private Key', [ privkey ])
assert.equal(importPrivKey, ethUtil.stripHexPrefix(privkey))
})

it('fails when password is incorrect for keystore', async function () {
const wrongPassword = 'password2'
it('throws an error for empty string private key', async () => {
assertRejects(async function() {
await accountImporter.importAccount('Private Key', [ '' ])
}, Error, 'no empty strings')
})

try {
await accountImporter.importAccount('JSON File', [ json, wrongPassword])
} catch (error) {
assert.equal(error.message, 'Key derivation failed - possibly wrong passphrase')
}
})
it('throws an error for undefined string private key', async () => {
assertRejects(async function () {
await accountImporter.importAccount('Private Key', [ undefined ])
})
})

it('imports json string and password to return a private key', async function () {
const fileContentsPassword = 'password1'
const importJson = await accountImporter.importAccount('JSON File', [ json, fileContentsPassword])
assert.equal(importJson, '0x5733876abe94146069ce8bcbabbde2677f2e35fa33e875e92041ed2ac87e5bc7')
it('throws an error for undefined string private key', async () => {
assertRejects(async function () {
await accountImporter.importAccount('Private Key', [])
})
})

it('throws an error for invalid private key', async () => {
assertRejects(async function () {
await accountImporter.importAccount('Private Key', [ 'popcorn' ])
})
})
})

describe('JSON keystore import', function () {
it('fails when password is incorrect for keystore', async function () {
const wrongPassword = 'password2'

try {
await accountImporter.importAccount('JSON File', [ json, wrongPassword])
} catch (error) {
assert.equal(error.message, 'Key derivation failed - possibly wrong passphrase')
}
})

it('imports json string and password to return a private key', async function () {
const fileContentsPassword = 'password1'
const importJson = await accountImporter.importAccount('JSON File', [ json, fileContentsPassword])
assert.equal(importJson, '0x5733876abe94146069ce8bcbabbde2677f2e35fa33e875e92041ed2ac87e5bc7')
})
})
})
17 changes: 17 additions & 0 deletions test/unit/test-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const assert = require('assert')

module.exports = {
assertRejects,
}

// assert.rejects added in node v10
async function assertRejects (asyncFn, regExp) {
let f = () => {}
try {
await asyncFn()
} catch (error) {
f = () => { throw error }
} finally {
assert.throws(f, regExp)
}
}