commit
83de3b5248
|
@ -6,8 +6,8 @@ var common = require('./common');
|
||||||
|
|
||||||
program
|
program
|
||||||
.version('0.0.1')
|
.version('0.0.1')
|
||||||
.option('-c,--config [file]', 'Wallet config filename')
|
.option('-c, --config [file]', 'Wallet config filename')
|
||||||
.option('-v,--verbose', 'be verbose')
|
.option('-v, --verbose', 'be verbose')
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
var args = program.args;
|
var args = program.args;
|
||||||
|
|
|
@ -7,8 +7,8 @@ var common = require('./common');
|
||||||
|
|
||||||
program
|
program
|
||||||
.version('0.0.1')
|
.version('0.0.1')
|
||||||
.option('-c,--config [file]', 'Wallet config filename')
|
.option('-c, --config [file]', 'Wallet config filename')
|
||||||
.option('-v,--verbose', 'be verbose')
|
.option('-v, --verbose', 'be verbose')
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
var args = program.args;
|
var args = program.args;
|
||||||
|
|
|
@ -6,8 +6,8 @@ var common = require('./common');
|
||||||
|
|
||||||
program
|
program
|
||||||
.version('0.0.1')
|
.version('0.0.1')
|
||||||
.option('-c,--config [file]', 'Wallet config filename')
|
.option('-c, --config [file]', 'Wallet config filename')
|
||||||
.option('-v,--verbose', 'be verbose')
|
.option('-v, --verbose', 'be verbose')
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
var args = program.args;
|
var args = program.args;
|
||||||
|
|
|
@ -6,8 +6,8 @@ var common = require('./common');
|
||||||
|
|
||||||
program
|
program
|
||||||
.version('0.0.1')
|
.version('0.0.1')
|
||||||
.option('-c,--config [file]', 'Wallet config filename')
|
.option('-c, --config [file]', 'Wallet config filename')
|
||||||
.option('-n,--network [networkname]', 'livenet|testnet', String, 'livenet')
|
.option('-n, --network [networkname]', 'livenet|testnet', String, 'livenet')
|
||||||
.usage('[options] <walletName> <m-n> [copayerName]')
|
.usage('[options] <walletName> <m-n> [copayerName]')
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
var program = require('commander');
|
|
||||||
var cli = require('../lib/clilib.js');
|
|
||||||
|
|
||||||
program
|
|
||||||
.version('0.0.1')
|
|
||||||
.parse(process.argv);
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ var common = require('./common');
|
||||||
|
|
||||||
program
|
program
|
||||||
.version('0.0.1')
|
.version('0.0.1')
|
||||||
.option('-c,--config [file]', 'Wallet config filename')
|
.option('-c, --config [file]', 'Wallet config filename')
|
||||||
.usage('[options] <secret> [copayerName]')
|
.usage('[options] <secret> [copayerName]')
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ var common = require('./common');
|
||||||
|
|
||||||
program
|
program
|
||||||
.version('0.0.1')
|
.version('0.0.1')
|
||||||
.option('-c,--config [file]', 'Wallet config filename')
|
.option('-c, --config [file]', 'Wallet config filename')
|
||||||
.option('-v,--verbose', 'be verbose')
|
.option('-v, --verbose', 'be verbose')
|
||||||
.usage('[options] <address> <amount> <message>')
|
.usage('[options] <address> <amount> <message>')
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ var common = require('./common');
|
||||||
|
|
||||||
program
|
program
|
||||||
.version('0.0.1')
|
.version('0.0.1')
|
||||||
.option('-c,--config [file]', 'Wallet config filename')
|
.option('-c, --config [file]', 'Wallet config filename')
|
||||||
.option('-v,--verbose', 'be verbose')
|
.option('-v, --verbose', 'be verbose')
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
var args = program.args;
|
var args = program.args;
|
||||||
|
|
|
@ -72,8 +72,6 @@ CliLib.prototype._loadAndCheck = function() {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
delete data['verified'];
|
|
||||||
if (data.verified == 'corrupt') {
|
if (data.verified == 'corrupt') {
|
||||||
log.error('The wallet is tagged as corrupt. Some of the copayers cannot be verified to have known the wallet secret.');
|
log.error('The wallet is tagged as corrupt. Some of the copayers cannot be verified to have known the wallet secret.');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
@ -143,10 +141,10 @@ CliLib.prototype._joinWallet = function(data, secret, copayerName, cb) {
|
||||||
|
|
||||||
var secretSplit = secret.split(':');
|
var secretSplit = secret.split(':');
|
||||||
var walletId = secretSplit[0];
|
var walletId = secretSplit[0];
|
||||||
var privKey = Bitcore.PrivateKey.fromString(secretSplit[1]);
|
var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]);
|
||||||
|
|
||||||
var xPubKey = new Bitcore.HDPublicKey(data.xPrivKey);
|
var xPubKey = new Bitcore.HDPublicKey(data.xPrivKey);
|
||||||
var xPubKeySignature = SignUtils.sign(xPubKey.toString(), privKey);
|
var xPubKeySignature = SignUtils.sign(xPubKey.toString(), walletPrivKey);
|
||||||
|
|
||||||
var signingPrivKey = (new Bitcore.HDPrivateKey(data.xPrivKey)).derive('m/1/0').privateKey;
|
var signingPrivKey = (new Bitcore.HDPrivateKey(data.xPrivKey)).derive('m/1/0').privateKey;
|
||||||
|
|
||||||
|
@ -171,6 +169,7 @@ CliLib.prototype._joinWallet = function(data, secret, copayerName, cb) {
|
||||||
|
|
||||||
var wallet = body.wallet;
|
var wallet = body.wallet;
|
||||||
data.copayerId = body.copayerId;
|
data.copayerId = body.copayerId;
|
||||||
|
data.walletPrivKey = walletPrivKey;
|
||||||
data.signingPrivKey = signingPrivKey.toString();
|
data.signingPrivKey = signingPrivKey.toString();
|
||||||
data.m = wallet.m;
|
data.m = wallet.m;
|
||||||
data.n = wallet.n;
|
data.n = wallet.n;
|
||||||
|
|
|
@ -332,7 +332,6 @@ CopayServer.prototype._getUtxos = function(cb) {
|
||||||
|
|
||||||
// Get addresses for this wallet
|
// Get addresses for this wallet
|
||||||
self.storage.fetchAddresses(self.walletId, function(err, addresses) {
|
self.storage.fetchAddresses(self.walletId, function(err, addresses) {
|
||||||
console.log('[server.js.334:addresses:]',addresses); //TODO
|
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (addresses.length == 0)
|
if (addresses.length == 0)
|
||||||
return cb(null, []);
|
return cb(null, []);
|
||||||
|
@ -389,7 +388,6 @@ CopayServer.prototype.getBalance = function(opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self._getUtxos(function(err, utxos) {
|
self._getUtxos(function(err, utxos) {
|
||||||
console.log('[server.js.390:utxos:]',utxos); //TODO
|
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
var balance = {};
|
var balance = {};
|
||||||
|
@ -445,15 +443,13 @@ CopayServer.prototype._selectUtxos = function(txp, utxos) {
|
||||||
CopayServer.prototype.createTx = function(opts, cb) {
|
CopayServer.prototype.createTx = function(opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (!Utils.checkRequired(opts, ['toAddress', 'amount']))
|
if (!Utils.checkRequired(opts, ['toAddress', 'amount', 'proposalSignature']))
|
||||||
return cb(new ClientError('Required argument missing'));
|
return cb(new ClientError('Required argument missing'));
|
||||||
|
|
||||||
Utils.runLocked(self.walletId, cb, function(cb) {
|
Utils.runLocked(self.walletId, cb, function(cb) {
|
||||||
self.getWallet({}, function(err, wallet) {
|
self.getWallet({}, function(err, wallet) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (!wallet.isComplete()) return cb(new ClientError('Wallet is not complete'));
|
if (!wallet.isComplete()) return cb(new ClientError('Wallet is not complete'));
|
||||||
if (wallet.isShared() && !Utils.checkRequired(opts, 'proposalSignature'))
|
|
||||||
return cb(new ClientError('Proposal signature is required for shared wallets'));
|
|
||||||
|
|
||||||
var copayer = wallet.getCopayer(self.copayerId);
|
var copayer = wallet.getCopayer(self.copayerId);
|
||||||
var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message;
|
var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
var Bitcore = require('bitcore');
|
var Bitcore = require('bitcore');
|
||||||
var PrivateKey = Bitcore.PrivateKey;
|
var PrivateKey = Bitcore.PrivateKey;
|
||||||
|
@ -10,12 +9,11 @@ var BufferReader = Bitcore.encoding.BufferReader;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var SignUtils = function () {
|
var SignUtils = function() {};
|
||||||
};
|
|
||||||
|
|
||||||
/* TODO: It would be nice to be compatible with bitcoind signmessage. How
|
/* TODO: It would be nice to be compatible with bitcoind signmessage. How
|
||||||
* the hash is calculated there? */
|
* the hash is calculated there? */
|
||||||
SignUtils.hash = function (text) {
|
SignUtils.hash = function(text) {
|
||||||
var buf = new Buffer(text);
|
var buf = new Buffer(text);
|
||||||
var ret = Hash.sha256sha256(buf);
|
var ret = Hash.sha256sha256(buf);
|
||||||
ret = new BufferReader(ret).readReverse();
|
ret = new BufferReader(ret).readReverse();
|
||||||
|
@ -23,14 +21,14 @@ SignUtils.hash = function (text) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
SignUtils.sign = function (text, privKey) {
|
SignUtils.sign = function(text, privKey) {
|
||||||
var priv = new PrivateKey(privKey);
|
var priv = new PrivateKey(privKey);
|
||||||
var hash = SignUtils.hash(text);
|
var hash = SignUtils.hash(text);
|
||||||
return ECDSA.sign(hash, priv, 'little').toString();
|
return ECDSA.sign(hash, priv, 'little').toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
SignUtils.verify = function (text, signature, pubKey) {
|
SignUtils.verify = function(text, signature, pubKey) {
|
||||||
var pub = new PublicKey(pubKey);
|
var pub = new PublicKey(pubKey);
|
||||||
var hash = SignUtils.hash(text);
|
var hash = SignUtils.hash(text);
|
||||||
|
|
||||||
|
|
|
@ -167,9 +167,13 @@ helpers.createProposalOpts = function(toAddress, amount, message, signingKey) {
|
||||||
toAddress: toAddress,
|
toAddress: toAddress,
|
||||||
amount: helpers.toSatoshi(amount),
|
amount: helpers.toSatoshi(amount),
|
||||||
message: message,
|
message: message,
|
||||||
|
proposalSignature: null,
|
||||||
};
|
};
|
||||||
var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message;
|
var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message;
|
||||||
opts.proposalSignature = SignUtils.sign(msg, signingKey);
|
try {
|
||||||
|
opts.proposalSignature = SignUtils.sign(msg, signingKey);
|
||||||
|
} catch (ex) {}
|
||||||
|
|
||||||
return opts;
|
return opts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -667,6 +671,34 @@ describe('Copay server', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fail to create tx with invalid proposal signature', function(done) {
|
||||||
|
helpers.createUtxos(server, wallet, [100, 200], function(utxos) {
|
||||||
|
helpers.stubBlockExplorer(server, utxos);
|
||||||
|
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, null, 'dummy');
|
||||||
|
|
||||||
|
server.createTx(txOpts, function(err, tx) {
|
||||||
|
should.not.exist(tx);
|
||||||
|
err.should.exist;
|
||||||
|
err.message.should.equal('Invalid proposal signature');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail to create tx with proposal signed by another copayer', function(done) {
|
||||||
|
helpers.createUtxos(server, wallet, [100, 200], function(utxos) {
|
||||||
|
helpers.stubBlockExplorer(server, utxos);
|
||||||
|
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, null, TestData.copayers[1].privKey);
|
||||||
|
|
||||||
|
server.createTx(txOpts, function(err, tx) {
|
||||||
|
should.not.exist(tx);
|
||||||
|
err.should.exist;
|
||||||
|
err.message.should.equal('Invalid proposal signature');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should fail to create tx for address invalid address', function(done) {
|
it('should fail to create tx for address invalid address', function(done) {
|
||||||
helpers.createUtxos(server, wallet, [100, 200], function(utxos) {
|
helpers.createUtxos(server, wallet, [100, 200], function(utxos) {
|
||||||
helpers.stubBlockExplorer(server, utxos);
|
helpers.stubBlockExplorer(server, utxos);
|
||||||
|
|
Loading…
Reference in New Issue