Browse Source

sigs -i -o

activeAddress
Matias Alejo Garcia 10 years ago
parent
commit
f5cb3f02f3
  1. 41
      bit-wallet/bit-sign
  2. 78
      lib/client/api.js
  3. 43
      test/integration/clientApi.js

41
bit-wallet/bit-sign

@ -1,12 +1,15 @@
#!/usr/bin/env node
var _ = require('lodash');
var fs = require('fs');
var program = require('commander');
var utils = require('./cli-utils');
var utils = require('./cli-utils');
program = utils.configureCommander(program);
program
.usage('[options] <txpid>')
.option('-i, --input [filename]', 'use signatures from file')
.option('-o, --output [filename]', 'write signatures to file')
.parse(process.argv);
var args = program.args;
@ -17,11 +20,33 @@ client.getTxProposals({}, function(err, txps) {
utils.die(err);
var txp = utils.findOneTxProposal(txps, txpid);
client.signTxProposal(txp, function(err, tx) {
utils.die(err);
if (tx.status == 'broadcasted')
console.log('Transaction Broadcasted: TXID: ' + tx.txid);
else
console.log('Transaction signed by you.');
});
if (program.output) {
client.getSignatures(txp, function(err, signatures) {
utils.die(err);
var out = {
id: txp.id,
signatures: signatures,
};
fs.writeFileSync(program.output, JSON.stringify(out));
console.log('Signatures written to file.');
});
} else {
if (program.input) {
var infile = JSON.parse(fs.readFileSync(program.input));
if (infile.id != txp.id)
utils.die('Signatures does not match Transaction')
txp.signatures = infile.signatures;
}
client.signTxProposal(txp, function(err, tx) {
utils.die(err);
if (tx.status == 'broadcasted')
console.log('Transaction Broadcasted: TXID: ' + tx.txid);
else
console.log('Transaction signed by you.');
});
}
});

78
lib/client/api.js

@ -579,48 +579,70 @@ API.prototype.getTxProposals = function(opts, cb) {
});
};
API.prototype.signTxProposal = function(txp, cb) {
$.checkArgument(txp.creatorId);
API.prototype._getSignaturesFor = function(txp, data) {
//Derive proper key to sign, for each input
var privs = [],
derived = {};
var network = new Bitcore.Address(txp.toAddress).network.name;
var xpriv = new Bitcore.HDPrivateKey(data.xPrivKey, network);
_.each(txp.inputs, function(i) {
if (!derived[i.path]) {
derived[i.path] = xpriv.derive(i.path).privateKey;
privs.push(derived[i.path]);
}
});
var t = new Bitcore.Transaction();
_.each(txp.inputs, function(i) {
t.from(i, i.publicKeys, txp.requiredSignatures);
});
t.to(txp.toAddress, txp.amount)
.change(txp.changeAddress.address);
var signatures = _.map(privs, function(priv, i) {
return t.getSignatures(priv);
});
signatures = _.map(_.sortBy(_.flatten(signatures), 'inputIndex'), function(s) {
return s.signature.toDER().toString('hex');
});
return signatures;
};
API.prototype.getSignatures = function(txp, cb) {
$.checkArgument(txp.creatorId);
var self = this;
this._loadAndCheck(function(err, data) {
if (err) return cb(err);
if (!Verifier.checkTxProposal(data, txp)) {
return cb(new ServerCompromisedError('Server sent fake transaction proposal'));
return cb(new ServerCompromisedError('Transaction proposal is invalid'));
}
//Derive proper key to sign, for each input
var privs = [],
derived = {};
var network = new Bitcore.Address(txp.toAddress).network.name;
var xpriv = new Bitcore.HDPrivateKey(data.xPrivKey, network);
_.each(txp.inputs, function(i) {
if (!derived[i.path]) {
derived[i.path] = xpriv.derive(i.path).privateKey;
privs.push(derived[i.path]);
}
});
return cb(null, self._getSignaturesFor(txp, data));
});
};
var t = new Bitcore.Transaction();
API.prototype.signTxProposal = function(txp, cb) {
$.checkArgument(txp.creatorId);
_.each(txp.inputs, function(i) {
t.from(i, i.publicKeys, txp.requiredSignatures);
});
var self = this;
t.to(txp.toAddress, txp.amount)
.change(txp.changeAddress.address);
this._loadAndCheck(function(err, data) {
if (err) return cb(err);
var signatures = _.map(privs, function(priv, i) {
return t.getSignatures(priv);
});
if (!Verifier.checkTxProposal(data, txp)) {
return cb(new ServerCompromisedError('Server sent fake transaction proposal'));
}
signatures = _.map(_.sortBy(_.flatten(signatures), 'inputIndex'), function(s) {
return s.signature.toDER().toString('hex');
});
var signatures = txp.signatures || self._getSignaturesFor(txp, data);
var url = '/v1/txproposals/' + txp.id + '/signatures/';
var args = {

43
test/integration/clientApi.js

@ -353,7 +353,7 @@ describe('client API ', function() {
});
});
describe('Access control & export', function() {
describe('Access control', function() {
it('should not be able to create address if not rwPubKey', function(done) {
helpers.createAndJoinWallet(clients, 1, 1, function(err) {
should.not.exist(err);
@ -438,7 +438,8 @@ describe('client API ', function() {
});
});
});
});
describe('Air gapped flows', function() {
it('should be able get Tx proposals from a file', function(done) {
helpers.createAndJoinWallet(clients, 1, 2, function(err, w) {
should.not.exist(err);
@ -499,9 +500,43 @@ describe('client API ', function() {
});
});
});
it('should be able export signatures and sign later from a ro client',
function(done) {
helpers.createAndJoinWallet(clients, 1, 1, function(err, w) {
should.not.exist(err);
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
blockExplorerMock.setUtxo(x0, 1, 1);
blockExplorerMock.setUtxo(x0, 1, 2);
var opts = {
amount: 150000000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hello 1-1',
};
clients[0].sendTxProposal(opts, function(err, txp) {
should.not.exist(err);
clients[0].getSignatures(txp, function(err, signatures) {
should.not.exist(err);
signatures.length.should.equal(txp.inputs.length);
signatures[0].length.should.above(62 * 2);
txp.signatures = signatures;
// Make client RO
var data = JSON.parse(fsmock._get('client0'));
delete data.xPrivKey;
fsmock._set('client0', JSON.stringify(data));
clients[0].signTxProposal(txp, function(err, txp) {
should.not.exist(err);
txp.status.should.equal('broadcasted');
done();
});
});
});
});
});
});
});
describe('Address Creation', function() {
@ -887,7 +922,9 @@ describe('client API ', function() {
should.not.exist(err);
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
clients[0].getMainAddresses({doNotVerify: true}, function(err, addr) {
clients[0].getMainAddresses({
doNotVerify: true
}, function(err, addr) {
should.not.exist(err);
addr.length.should.equal(2);
done();

Loading…
Cancel
Save