openethereum/js/src/api/local/ethkey/worker.js

136 lines
3.2 KiB
JavaScript
Raw Normal View History

2017-03-29 17:07:58 +02:00
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import secp256k1 from 'secp256k1/js';
2017-04-03 18:50:11 +02:00
import { keccak_256 as keccak256 } from 'js-sha3';
2017-04-04 11:49:36 +02:00
import { bytesToHex } from '~/api/util/format';
2017-04-03 18:50:11 +02:00
const isWorker = typeof self !== 'undefined';
2017-03-29 17:07:58 +02:00
// Stay compatible between environments
2017-04-03 18:50:11 +02:00
if (!isWorker) {
2017-03-29 17:07:58 +02:00
const scope = typeof global === 'undefined' ? window : global;
scope.self = scope;
}
2017-04-03 18:50:11 +02:00
// keythereum should never be used outside of the browser
let keythereum = null;
2017-03-29 17:07:58 +02:00
2017-04-03 18:50:11 +02:00
if (isWorker) {
require('keythereum/dist/keythereum');
2017-03-29 17:07:58 +02:00
2017-04-03 18:50:11 +02:00
keythereum = self.keythereum;
}
function route ({ action, payload }) {
if (action in actions) {
return actions[action](payload);
2017-03-29 17:07:58 +02:00
}
2017-04-03 18:50:11 +02:00
return null;
}
const actions = {
phraseToWallet (phrase) {
let secret = keccak256.array(phrase);
for (let i = 0; i < 16384; i++) {
secret = keccak256.array(secret);
}
while (true) {
secret = keccak256.array(secret);
2017-03-29 17:07:58 +02:00
2017-04-03 18:50:11 +02:00
const secretBuf = Buffer.from(secret);
2017-03-29 17:07:58 +02:00
2017-04-03 18:50:11 +02:00
if (secp256k1.privateKeyVerify(secretBuf)) {
// No compression, slice out last 64 bytes
const publicBuf = secp256k1.publicKeyCreate(secretBuf, false).slice(-64);
const address = keccak256.array(publicBuf).slice(12);
2017-03-29 17:07:58 +02:00
2017-04-03 18:50:11 +02:00
if (address[0] !== 0) {
continue;
}
const wallet = {
secret: bytesToHex(secretBuf),
public: bytesToHex(publicBuf),
address: bytesToHex(address)
};
return wallet;
2017-03-29 17:07:58 +02:00
}
2017-04-03 18:50:11 +02:00
}
},
verifySecret (secret) {
const key = Buffer.from(secret.slice(2), 'hex');
return secp256k1.privateKeyVerify(key);
},
createKeyObject ({ key, password }) {
key = Buffer.from(key);
password = Buffer.from(password);
const iv = keythereum.crypto.randomBytes(16);
const salt = keythereum.crypto.randomBytes(32);
const keyObject = keythereum.dump(password, key, salt, iv);
2017-03-29 17:07:58 +02:00
2017-04-03 18:50:11 +02:00
return JSON.stringify(keyObject);
},
2017-03-29 17:07:58 +02:00
2017-04-03 18:50:11 +02:00
decryptPrivateKey ({ keyObject, password }) {
password = Buffer.from(password);
try {
const key = keythereum.recover(password, keyObject);
// Convert to array to safely send from the worker
return Array.from(key);
} catch (e) {
return null;
2017-03-29 17:07:58 +02:00
}
}
2017-04-03 18:50:11 +02:00
};
2017-03-29 17:07:58 +02:00
self.onmessage = function ({ data }) {
2017-04-03 18:50:11 +02:00
const result = route(data);
2017-03-29 17:07:58 +02:00
2017-04-03 18:50:11 +02:00
postMessage(result);
2017-03-29 17:07:58 +02:00
};
// Emulate a web worker in Node.js
class KeyWorker {
postMessage (data) {
// Force async
setTimeout(() => {
2017-04-03 18:50:11 +02:00
const result = route(data);
2017-03-29 17:07:58 +02:00
2017-04-03 18:50:11 +02:00
this.onmessage({ data: result });
2017-03-29 17:07:58 +02:00
}, 0);
}
onmessage (event) {
// no-op to be overriden
}
}
if (exports != null) {
exports.KeyWorker = KeyWorker;
}