add public key ring to txprposals

This commit is contained in:
Matias Alejo Garcia 2015-02-23 00:43:39 -03:00
parent 0b6706b118
commit 879a352b3e
4 changed files with 150 additions and 71 deletions

View File

@ -23,8 +23,15 @@ function end(err, txps, rawtxps) {
}
utils.renderTxProposals(txps);
if (program.output) {
fs.writeFileSync(program.output, JSON.stringify(rawtxps));
console.log(' * Proposals Saved to: %s\n', program.output);
client.getEncryptedPublicKeyRing(function (err, pkr) {
var txData = {
pkr: pkr,
txps: txps,
};
fs.writeFileSync(program.output, JSON.stringify(txData));
console.log(' * Proposals Saved to: %s\n', program.output);
});
}
};

View File

@ -83,8 +83,7 @@ function API(opts) {
}
};
API.prototype._tryToComplete = function(data, cb) {
API.prototype._tryToCompleteFromServer = function(data, cb) {
var self = this;
var url = '/v1/wallets/';
@ -112,6 +111,24 @@ API.prototype._tryToComplete = function(data, cb) {
API.prototype._tryToComplete = function(opts, data, cb) {
if (opts.pkr) {
var pkr = _decryptMessage(opts.pkr, data.sharedEncryptingKey);
if (!pkr)
return cb('Could not complete wallet');
data.publicKeyRing = JSON.parse(pkr);
this.storage.save(data, function(err) {
return cb(err, data);
});
} else {
this._tryToCompleteFromServer(data,cb);
}
};
API.prototype._load = function(cb) {
var self = this;
@ -124,7 +141,12 @@ API.prototype._load = function(cb) {
};
API.prototype._loadAndCheck = function(cb) {
/**
* _loadAndCheck
*
* @param opts.pkr
*/
API.prototype._loadAndCheck = function(opts, cb) {
var self = this;
this._load(function(err, data) {
@ -133,7 +155,7 @@ API.prototype._loadAndCheck = function(cb) {
var pkrComplete = data.publicKeyRing && data.m && data.publicKeyRing.length === data.n;
if (!pkrComplete) {
return self._tryToComplete(data, cb);
return self._tryToComplete(opts, data, cb);
}
}
return cb(null, data);
@ -270,7 +292,7 @@ API.prototype.createWallet = function(walletName, copayerName, m, n, network, cb
API.prototype.reCreateWallet = function(walletName, cb) {
var self = this;
this._loadAndCheck(function(err, data) {
this._loadAndCheck({}, function(err, data) {
if (err) return cb(err);
var walletPrivKey = new Bitcore.PrivateKey();
@ -351,7 +373,7 @@ API.prototype.sendTxProposal = function(opts, cb) {
var self = this;
this._loadAndCheck(function(err, data) {
this._loadAndCheck({}, function(err, data) {
if (err) return cb(err);
if (!data.rwPrivKey)
@ -374,7 +396,7 @@ API.prototype.sendTxProposal = function(opts, cb) {
API.prototype.createAddress = function(cb) {
var self = this;
this._loadAndCheck(function(err, data) {
this._loadAndCheck({}, function(err, data) {
if (err) return cb(err);
var url = '/v1/addresses/';
@ -396,7 +418,7 @@ API.prototype.createAddress = function(cb) {
API.prototype.getMainAddresses = function(opts, cb) {
var self = this;
this._loadAndCheck(function(err, data) {
this._loadAndCheck({}, function(err, data) {
if (err) return cb(err);
var url = '/v1/addresses/';
@ -422,7 +444,7 @@ API.prototype.history = function(limit, cb) {
API.prototype.getBalance = function(cb) {
var self = this;
this._loadAndCheck(function(err, data) {
this._loadAndCheck({}, function(err, data) {
if (err) return cb(err);
var url = '/v1/balance/';
self._doGetRequest(url, data, cb);
@ -440,7 +462,7 @@ API.prototype.export = function(opts, cb) {
opts = opts || {};
var access = opts.access || 'full';
this._loadAndCheck(function(err, data) {
this._loadAndCheck({}, function(err, data) {
if (err) return cb(err);
var v = [];
@ -517,19 +539,12 @@ API.prototype.import = function(str, cb) {
*
*/
API.prototype.parseTxProposals = function(txps, cb) {
API.prototype.parseTxProposals = function(txData, cb) {
var self = this;
this._load(function(err, data) {
if (err) return cb(err);
if (data.n > 1) {
var pkrComplete = data.publicKeyRing && data.m && data.publicKeyRing.length === data.n;
if (!pkrComplete) {
return cb('Wallet Incomplete');
}
}
this._loadAndCheck({pkr: txData.pkr},function(err, data) {
var txps = txData.txps;
_processTxps(txps, data.sharedEncryptingKey);
var fake = _.any(txps, function(txp) {
@ -555,7 +570,7 @@ API.prototype.parseTxProposals = function(txps, cb) {
API.prototype.getTxProposals = function(opts, cb) {
var self = this;
this._loadAndCheck(function(err, data) {
this._loadAndCheck({}, function(err, data) {
if (err) return cb(err);
var url = '/v1/txproposals/';
self._doGetRequest(url, data, function(err, txps) {
@ -619,7 +634,7 @@ API.prototype.getSignatures = function(txp, cb) {
$.checkArgument(txp.creatorId);
var self = this;
this._loadAndCheck(function(err, data) {
this._loadAndCheck({}, function(err, data) {
if (err) return cb(err);
if (!Verifier.checkTxProposal(data, txp)) {
@ -630,12 +645,25 @@ API.prototype.getSignatures = function(txp, cb) {
});
};
API.prototype.getEncryptedPublicKeyRing = function(cb) {
var self = this;
this._loadAndCheck({}, function(err, data) {
if (err) return cb(err);
var pkr = JSON.stringify(data.publicKeyRing);
return cb(null, _encryptMessage(pkr, data.sharedEncryptingKey));
});
};
API.prototype.signTxProposal = function(txp, cb) {
$.checkArgument(txp.creatorId);
var self = this;
this._loadAndCheck(function(err, data) {
this._loadAndCheck({}, function(err, data) {
if (err) return cb(err);
if (!Verifier.checkTxProposal(data, txp)) {
@ -658,7 +686,7 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) {
var self = this;
this._loadAndCheck(
this._loadAndCheck({},
function(err, data) {
if (err) return cb(err);
@ -673,7 +701,7 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) {
API.prototype.broadcastTxProposal = function(txp, cb) {
var self = this;
this._loadAndCheck(
this._loadAndCheck({},
function(err, data) {
if (err) return cb(err);
@ -686,7 +714,7 @@ API.prototype.broadcastTxProposal = function(txp, cb) {
API.prototype.removeTxProposal = function(txp, cb) {
var self = this;
this._loadAndCheck(
this._loadAndCheck({},
function(err, data) {
if (err) return cb(err);
var url = '/v1/txproposals/' + txp.id;

View File

@ -59,7 +59,9 @@ Verifier.checkTxProposal = function(data, txp) {
var creatorXPubKey = _.find(data.publicKeyRing, function(xPubKey) {
if (WalletUtils.xPubToCopayerId(xPubKey) === txp.creatorId) return true;
});
if (!creatorXPubKey) return false;
var creatorSigningPubKey = (new Bitcore.HDPublicKey(creatorXPubKey)).derive('m/1/1').publicKey.toString();
var hash = WalletUtils.getProposalHash(txp.toAddress, txp.amount, txp.encryptedMessage || txp.message);

View File

@ -458,7 +458,9 @@ describe('client API ', function() {
}, function(err, txs, rawTxps) {
should.not.exist(err);
clients[0].parseTxProposals(rawTxps, function(err, txs2) {
clients[0].parseTxProposals({
txps: rawTxps
}, function(err, txs2) {
should.not.exist(err);
txs[0].should.deep.equal(txs2[0]);
done();
@ -490,7 +492,9 @@ describe('client API ', function() {
//Tamper
rawTxps[0].amount++;
clients[0].parseTxProposals(rawTxps, function(err, txs2) {
clients[0].parseTxProposals({
txps: rawTxps
}, function(err, txs2) {
err.code.should.equal('SERVERCOMPROMISED');
done();
});
@ -500,43 +504,81 @@ 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) {
it('should complete public key ring from file', function(done) {
helpers.createAndJoinWallet(clients, 1, 2, function(err, w) {
should.not.exist(err);
clients[0].createAddress(function(err, x0) {
clients[1].createAddress(function(err, x0) {
should.not.exist(err);
blockExplorerMock.setUtxo(x0, 1, 1);
blockExplorerMock.setUtxo(x0, 1, 2);
var opts = {
amount: 150000000,
amount: 10000000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hello 1-1',
};
clients[0].sendTxProposal(opts, function(err, txp) {
clients[1].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
clients[0].getSignatures(txp, function(err, signatures) {
clients[1].getTxProposals({
getRawTxps: true
}, function(err, txs, rawTxps) {
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) {
clients[1].getEncryptedPublicKeyRing(function(err, pkr) {
should.not.exist(err);
txp.status.should.equal('broadcasted');
done();
// Will trigger _tryToComplete and use pkr
// then, needs pkr to verify the txps
clients[0].parseTxProposals({
txps: rawTxps,
pkr: pkr,
}, function(err, txs2) {
should.not.exist(err);
done();
});
});
});
});
});
});
});
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() {
@ -977,29 +1019,29 @@ describe('client API ', function() {
};
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
clients[0].getStatus( function(err, st) {
should.not.exist(err);
var x = st.pendingTxps[0];
x.status.should.equal('pending');
x.requiredRejections.should.equal(2);
x.requiredSignatures.should.equal(2);
var w = st.wallet;
w.copayers.length.should.equal(3);
w.status.should.equal('complete');
var b = st.balance;
b.totalAmount.should.equal(1000000000);
b.lockedAmount.should.equal(1000000000);
clients[0].getStatus(function(err, st) {
should.not.exist(err);
var x = st.pendingTxps[0];
x.status.should.equal('pending');
x.requiredRejections.should.equal(2);
x.requiredSignatures.should.equal(2);
var w = st.wallet;
w.copayers.length.should.equal(3);
w.status.should.equal('complete');
var b = st.balance;
b.totalAmount.should.equal(1000000000);
b.lockedAmount.should.equal(1000000000);
clients[0].signTxProposal(x, function(err, tx) {
should.not.exist(err, err);
tx.status.should.equal('pending');
clients[1].signTxProposal(x, function(err, tx) {
should.not.exist(err);
tx.status.should.equal('broadcasted');
tx.txid.should.equal((new Bitcore.Transaction(blockExplorerMock.lastBroadcasted)).id);
done();
});
clients[0].signTxProposal(x, function(err, tx) {
should.not.exist(err, err);
tx.status.should.equal('pending');
clients[1].signTxProposal(x, function(err, tx) {
should.not.exist(err);
tx.status.should.equal('broadcasted');
tx.txid.should.equal((new Bitcore.Transaction(blockExplorerMock.lastBroadcasted)).id);
done();
});
});
});
});