checking arguments
This commit is contained in:
parent
0885b26983
commit
07012633a9
|
@ -10,17 +10,17 @@ var MESSAGE_SIGNING_PATH = "m/1/0";
|
||||||
function Copayer(opts) {
|
function Copayer(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
|
this.version = VERSION;
|
||||||
this.createdOn = Math.floor(Date.now() / 1000);
|
this.createdOn = Math.floor(Date.now() / 1000);
|
||||||
this.id = opts.id;
|
this.id = opts.id;
|
||||||
this.name = opts.name;
|
this.name = opts.name;
|
||||||
this.xPubKey = opts.xPubKey;
|
this.xPubKey = opts.xPubKey;
|
||||||
this.xPubKeySignature = opts.xPubKeySignature; // So third parties can check independently
|
this.xPubKeySignature = opts.xPubKeySignature; // So third parties can check independently
|
||||||
this.version = VERSION;
|
if (opts.xPubKey) {
|
||||||
this.signingPubKey = opts.signingPubKey || this.getSigningPubKey();
|
this.signingPubKey = this.getSigningPubKey();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Copayer.prototype.getSigningPubKey = function () {
|
Copayer.prototype.getSigningPubKey = function () {
|
||||||
if (!this.xPubKey) return null;
|
if (!this.xPubKey) return null;
|
||||||
return HDPublicKey.fromString(this.xPubKey).derive(MESSAGE_SIGNING_PATH).publicKey.toString();
|
return HDPublicKey.fromString(this.xPubKey).derive(MESSAGE_SIGNING_PATH).publicKey.toString();
|
||||||
|
@ -29,13 +29,13 @@ Copayer.prototype.getSigningPubKey = function () {
|
||||||
Copayer.fromObj = function (obj) {
|
Copayer.fromObj = function (obj) {
|
||||||
var x = new Copayer();
|
var x = new Copayer();
|
||||||
|
|
||||||
|
x.version = obj.version;
|
||||||
x.createdOn = obj.createdOn;
|
x.createdOn = obj.createdOn;
|
||||||
x.id = obj.id;
|
x.id = obj.id;
|
||||||
x.name = obj.name;
|
x.name = obj.name;
|
||||||
x.xPubKey = obj.xPubKey;
|
x.xPubKey = obj.xPubKey;
|
||||||
x.xPubKeySignature = obj.xPubKeySignature;
|
x.xPubKeySignature = obj.xPubKeySignature;
|
||||||
x.signingPubKey = obj.signingPubKey || this.getSigningPubKey();
|
x.signingPubKey = obj.signingPubKey;
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,9 +4,12 @@ var _ = require('lodash');
|
||||||
|
|
||||||
var TxProposalAction = require('./txproposalaction');
|
var TxProposalAction = require('./txproposalaction');
|
||||||
|
|
||||||
|
var VERSION = '1.0.0';
|
||||||
|
|
||||||
function TxProposal(opts) {
|
function TxProposal(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
|
this.version = VERSION;
|
||||||
this.createdOn = Math.floor(Date.now() / 1000);
|
this.createdOn = Math.floor(Date.now() / 1000);
|
||||||
this.id = opts.id;
|
this.id = opts.id;
|
||||||
this.creatorId = opts.creatorId;
|
this.creatorId = opts.creatorId;
|
||||||
|
@ -24,6 +27,7 @@ function TxProposal(opts) {
|
||||||
TxProposal.fromObj = function (obj) {
|
TxProposal.fromObj = function (obj) {
|
||||||
var x = new TxProposal();
|
var x = new TxProposal();
|
||||||
|
|
||||||
|
x.version = obj.version;
|
||||||
x.createdOn = obj.createdOn;
|
x.createdOn = obj.createdOn;
|
||||||
x.id = obj.id;
|
x.id = obj.id;
|
||||||
x.creatorId = obj.creatorId;
|
x.creatorId = obj.creatorId;
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
|
|
||||||
var Copayer = require('./copayer');
|
var Copayer = require('./copayer');
|
||||||
var WALLET_VERSION = '1.0.0';
|
var VERSION = '1.0.0';
|
||||||
|
|
||||||
function Wallet(opts) {
|
function Wallet(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
|
this.version = VERSION;
|
||||||
this.createdOn = Math.floor(Date.now() / 1000);
|
this.createdOn = Math.floor(Date.now() / 1000);
|
||||||
this.id = opts.id;
|
this.id = opts.id;
|
||||||
this.name = opts.name;
|
this.name = opts.name;
|
||||||
|
@ -17,23 +18,43 @@ function Wallet(opts) {
|
||||||
this.publicKeyRing = [];
|
this.publicKeyRing = [];
|
||||||
this.addressIndex = 0;
|
this.addressIndex = 0;
|
||||||
this.copayers = [];
|
this.copayers = [];
|
||||||
this.version = WALLET_VERSION;
|
|
||||||
this.pubKey = opts.pubKey;
|
this.pubKey = opts.pubKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* For compressed keys, m*73 + n*34 <= 496 */
|
||||||
|
Wallet.COPAYER_PAIR_LIMITS = {
|
||||||
|
1: 1,
|
||||||
|
2: 2,
|
||||||
|
3: 3,
|
||||||
|
4: 4,
|
||||||
|
5: 4,
|
||||||
|
6: 4,
|
||||||
|
7: 3,
|
||||||
|
8: 3,
|
||||||
|
9: 2,
|
||||||
|
10: 2,
|
||||||
|
11: 1,
|
||||||
|
12: 1,
|
||||||
|
};
|
||||||
|
|
||||||
Wallet.fromUntrustedObj = function (obj) {
|
/**
|
||||||
|
* Get the maximum allowed number of required copayers.
|
||||||
|
* This is a limit imposed by the maximum allowed size of the scriptSig.
|
||||||
|
* @param {number} totalCopayers - the total number of copayers
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
Wallet.getMaxRequiredCopayers = function(totalCopayers) {
|
||||||
|
return Wallet.COPAYER_PAIR_LIMITS[totalCopayers];
|
||||||
|
};
|
||||||
|
|
||||||
// TODO add sanity checks OR migration steps?
|
Wallet.verifyCopayerLimits = function (m, n) {
|
||||||
if (!obj.pubKey || !obj.m || !obj.n)
|
return (n >= 1 && n <= 12) && (m >= 1 && m <= Wallet.COPAYER_PAIR_LIMITS[n]);
|
||||||
return cb('Wallet corrupted');
|
|
||||||
|
|
||||||
return Wallet.fromObj(obj);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.fromObj = function (obj) {
|
Wallet.fromObj = function (obj) {
|
||||||
var x = new Wallet();
|
var x = new Wallet();
|
||||||
|
|
||||||
|
x.version = obj.version;
|
||||||
x.createdOn = obj.createdOn;
|
x.createdOn = obj.createdOn;
|
||||||
x.id = obj.id;
|
x.id = obj.id;
|
||||||
x.name = obj.name;
|
x.name = obj.name;
|
||||||
|
|
|
@ -5,11 +5,13 @@ var $ = require('preconditions').singleton();
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var log = require('npmlog');
|
var log = require('npmlog');
|
||||||
log.debug = log.verbose;
|
log.debug = log.verbose;
|
||||||
|
|
||||||
var Bitcore = require('bitcore');
|
var Bitcore = require('bitcore');
|
||||||
var PublicKey = Bitcore.PublicKey;
|
var PublicKey = Bitcore.PublicKey;
|
||||||
var HDPublicKey = Bitcore.HDPublicKey;
|
var HDPublicKey = Bitcore.HDPublicKey;
|
||||||
var Explorers = require('bitcore-explorers');
|
var Explorers = require('bitcore-explorers');
|
||||||
|
|
||||||
|
var utils = require('./utils');
|
||||||
var Lock = require('./lock');
|
var Lock = require('./lock');
|
||||||
var Storage = require('./storage');
|
var Storage = require('./storage');
|
||||||
var SignUtils = require('./signutils');
|
var SignUtils = require('./signutils');
|
||||||
|
@ -45,6 +47,11 @@ function CopayServer(opts) {
|
||||||
CopayServer.prototype.createWallet = function (opts, cb) {
|
CopayServer.prototype.createWallet = function (opts, cb) {
|
||||||
var self = this, pubKey;
|
var self = this, pubKey;
|
||||||
|
|
||||||
|
utils.checkRequired(opts, ['id', 'name', 'm', 'n', 'pubKey']);
|
||||||
|
if (!Wallet.verifyCopayerLimits(opts.m, opts.n)) return cb('Incorrect m or n value');
|
||||||
|
var network = opts.network || 'livenet';
|
||||||
|
if (network != 'livenet' && network != 'testnet') return cb('Invalid network');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pubKey = new PublicKey.fromString(opts.pubKey);
|
pubKey = new PublicKey.fromString(opts.pubKey);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -60,7 +67,7 @@ CopayServer.prototype.createWallet = function (opts, cb) {
|
||||||
name: opts.name,
|
name: opts.name,
|
||||||
m: opts.m,
|
m: opts.m,
|
||||||
n: opts.n,
|
n: opts.n,
|
||||||
network: opts.network || 'livenet',
|
network: network,
|
||||||
pubKey: pubKey,
|
pubKey: pubKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -119,6 +126,8 @@ CopayServer.prototype._verifySignature = function (text, signature, pubKey) {
|
||||||
CopayServer.prototype.joinWallet = function (opts, cb) {
|
CopayServer.prototype.joinWallet = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
utils.checkRequired(opts, ['walletId', 'id', 'name', 'xPubKey', 'xPubKeySignature']);
|
||||||
|
|
||||||
self._runLocked(opts.walletId, cb, function (cb) {
|
self._runLocked(opts.walletId, cb, function (cb) {
|
||||||
self.getWallet({ id: opts.walletId }, function (err, wallet) {
|
self.getWallet({ id: opts.walletId }, function (err, wallet) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
@ -164,6 +173,8 @@ CopayServer.prototype._doCreateAddress = function (pkr, index, isChange) {
|
||||||
CopayServer.prototype.createAddress = function (opts, cb) {
|
CopayServer.prototype.createAddress = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
utils.checkRequired(opts, ['walletId', 'isChange']);
|
||||||
|
|
||||||
self._runLocked(opts.walletId, cb, function (cb) {
|
self._runLocked(opts.walletId, cb, function (cb) {
|
||||||
self.getWallet({ id: opts.walletId }, function (err, wallet) {
|
self.getWallet({ id: opts.walletId }, function (err, wallet) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
@ -195,6 +206,8 @@ CopayServer.prototype._doCreateAddress = function (pkr, index, isChange) {
|
||||||
CopayServer.prototype.verifyMessageSignature = function (opts, cb) {
|
CopayServer.prototype.verifyMessageSignature = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
utils.checkRequired(opts, ['walletId', 'copayerId', 'message', 'signature']);
|
||||||
|
|
||||||
self.getWallet({ id: opts.walletId }, function (err, wallet) {
|
self.getWallet({ id: opts.walletId }, function (err, wallet) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
@ -275,6 +288,8 @@ CopayServer.prototype._getUtxos = function (opts, cb) {
|
||||||
CopayServer.prototype.getBalance = function (opts, cb) {
|
CopayServer.prototype.getBalance = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
utils.checkRequired(opts, 'walletId');
|
||||||
|
|
||||||
self._getUtxos({ walletId: opts.walletId }, function (err, utxos) {
|
self._getUtxos({ walletId: opts.walletId }, function (err, utxos) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
@ -326,6 +341,8 @@ CopayServer.prototype._selectUtxos = function (txp, utxos) {
|
||||||
CopayServer.prototype.createTx = function (opts, cb) {
|
CopayServer.prototype.createTx = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
utils.checkRequired(opts, ['walletId', 'copayerId', 'toAddress', 'amount', 'message']);
|
||||||
|
|
||||||
self.getWallet({ id: opts.walletId }, function (err, wallet) {
|
self.getWallet({ id: opts.walletId }, function (err, wallet) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
@ -373,6 +390,8 @@ CopayServer.prototype._broadcastTx = function (rawTx, cb) {
|
||||||
CopayServer.prototype.signTx = function (opts, cb) {
|
CopayServer.prototype.signTx = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
utils.checkRequired(opts, ['walletId', 'copayerId', 'txProposalId', 'signature']);
|
||||||
|
|
||||||
self.fetchTx(opts.walletId, opts.txProposalId, function (err, txp) {
|
self.fetchTx(opts.walletId, opts.txProposalId, function (err, txp) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (!txp) return cb('Transaction proposal not found');
|
if (!txp) return cb('Transaction proposal not found');
|
||||||
|
@ -406,10 +425,13 @@ CopayServer.prototype.signTx = function (opts, cb) {
|
||||||
* @param {string} opts.walletId - The wallet id.
|
* @param {string} opts.walletId - The wallet id.
|
||||||
* @param {string} opts.copayerId - The wallet id.
|
* @param {string} opts.copayerId - The wallet id.
|
||||||
* @param {string} opts.txProposalId - The identifier of the transaction.
|
* @param {string} opts.txProposalId - The identifier of the transaction.
|
||||||
|
* @param {string} [opts.reason] - A message to other copayers explaining the rejection.
|
||||||
*/
|
*/
|
||||||
CopayServer.prototype.rejectTx = function (opts, cb) {
|
CopayServer.prototype.rejectTx = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
utils.checkRequired(opts, ['walletId', 'copayerId', 'txProposalId']);
|
||||||
|
|
||||||
self.fetchTx(opts.walletId, opts.txProposalId, function (err, txp) {
|
self.fetchTx(opts.walletId, opts.txProposalId, function (err, txp) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (!txp) return cb('Transaction proposal not found');
|
if (!txp) return cb('Transaction proposal not found');
|
||||||
|
@ -436,6 +458,8 @@ CopayServer.prototype.rejectTx = function (opts, cb) {
|
||||||
CopayServer.prototype.getPendingTxs = function (opts, cb) {
|
CopayServer.prototype.getPendingTxs = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
utils.checkRequired(opts, 'walletId');
|
||||||
|
|
||||||
self.storage.fetchTxs(opts.walletId, function (err, txps) {
|
self.storage.fetchTxs(opts.walletId, function (err, txps) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
var $ = require('preconditions').singleton();
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
var utils = {};
|
||||||
|
|
||||||
|
utils.checkRequired = function (obj, args) {
|
||||||
|
args = [].concat(args);
|
||||||
|
if (!_.isObject(obj)) throw 'Required arguments missing';
|
||||||
|
_.each(args, function (arg) {
|
||||||
|
if (!obj.hasOwnProperty(arg)) throw "Missing required argument '" + arg + "'";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = utils;
|
|
@ -428,10 +428,12 @@ describe('Copay server', function() {
|
||||||
name: 'me',
|
name: 'me',
|
||||||
xPubKey: someXPubKeys[0],
|
xPubKey: someXPubKeys[0],
|
||||||
};
|
};
|
||||||
server.joinWallet(copayerOpts, function(err) {
|
try {
|
||||||
err.should.contain('Bad request');
|
server.joinWallet(copayerOpts, function(err) {});
|
||||||
|
} catch (e) {
|
||||||
|
e.should.contain('xPubKeySignature');
|
||||||
done();
|
done();
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -526,11 +528,12 @@ describe('Copay server', function() {
|
||||||
it('should create address', function(done) {
|
it('should create address', function(done) {
|
||||||
server._doCreateAddress = sinon.stub().returns(new Address({
|
server._doCreateAddress = sinon.stub().returns(new Address({
|
||||||
address: 'addr1',
|
address: 'addr1',
|
||||||
path: 'path1'
|
path: 'path1',
|
||||||
}));
|
}));
|
||||||
helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) {
|
helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) {
|
||||||
server.createAddress({
|
server.createAddress({
|
||||||
walletId: '123'
|
walletId: '123',
|
||||||
|
isChange: false,
|
||||||
}, function(err, address) {
|
}, function(err, address) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
address.should.exist;
|
address.should.exist;
|
||||||
|
|
Loading…
Reference in New Issue