add public key ring to txprposals
This commit is contained in:
parent
0b6706b118
commit
879a352b3e
|
@ -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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue