checking arguments

This commit is contained in:
Ivan Socolsky 2015-02-02 15:29:14 -03:00
parent 0885b26983
commit 07012633a9
6 changed files with 87 additions and 21 deletions

View File

@ -10,17 +10,17 @@ var MESSAGE_SIGNING_PATH = "m/1/0";
function Copayer(opts) {
opts = opts || {};
this.version = VERSION;
this.createdOn = Math.floor(Date.now() / 1000);
this.id = opts.id;
this.name = opts.name;
this.xPubKey = opts.xPubKey;
this.xPubKeySignature = opts.xPubKeySignature; // So third parties can check independently
this.version = VERSION;
this.signingPubKey = opts.signingPubKey || this.getSigningPubKey();
this.xPubKeySignature = opts.xPubKeySignature; // So third parties can check independently
if (opts.xPubKey) {
this.signingPubKey = this.getSigningPubKey();
}
};
Copayer.prototype.getSigningPubKey = function () {
if (!this.xPubKey) return null;
return HDPublicKey.fromString(this.xPubKey).derive(MESSAGE_SIGNING_PATH).publicKey.toString();
@ -29,13 +29,13 @@ Copayer.prototype.getSigningPubKey = function () {
Copayer.fromObj = function (obj) {
var x = new Copayer();
x.version = obj.version;
x.createdOn = obj.createdOn;
x.id = obj.id;
x.name = obj.name;
x.xPubKey = obj.xPubKey;
x.xPubKeySignature = obj.xPubKeySignature;
x.signingPubKey = obj.signingPubKey || this.getSigningPubKey();
x.signingPubKey = obj.signingPubKey;
return x;
};

View File

@ -4,9 +4,12 @@ var _ = require('lodash');
var TxProposalAction = require('./txproposalaction');
var VERSION = '1.0.0';
function TxProposal(opts) {
opts = opts || {};
this.version = VERSION;
this.createdOn = Math.floor(Date.now() / 1000);
this.id = opts.id;
this.creatorId = opts.creatorId;
@ -24,6 +27,7 @@ function TxProposal(opts) {
TxProposal.fromObj = function (obj) {
var x = new TxProposal();
x.version = obj.version;
x.createdOn = obj.createdOn;
x.id = obj.id;
x.creatorId = obj.creatorId;

View File

@ -3,11 +3,12 @@
var _ = require('lodash');
var Copayer = require('./copayer');
var WALLET_VERSION = '1.0.0';
var VERSION = '1.0.0';
function Wallet(opts) {
opts = opts || {};
this.version = VERSION;
this.createdOn = Math.floor(Date.now() / 1000);
this.id = opts.id;
this.name = opts.name;
@ -17,23 +18,43 @@ function Wallet(opts) {
this.publicKeyRing = [];
this.addressIndex = 0;
this.copayers = [];
this.version = WALLET_VERSION;
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?
if (!obj.pubKey || !obj.m || !obj.n)
return cb('Wallet corrupted');
return Wallet.fromObj(obj);
Wallet.verifyCopayerLimits = function (m, n) {
return (n >= 1 && n <= 12) && (m >= 1 && m <= Wallet.COPAYER_PAIR_LIMITS[n]);
};
Wallet.fromObj = function (obj) {
var x = new Wallet();
x.version = obj.version;
x.createdOn = obj.createdOn;
x.id = obj.id;
x.name = obj.name;

View File

@ -5,11 +5,13 @@ var $ = require('preconditions').singleton();
var async = require('async');
var log = require('npmlog');
log.debug = log.verbose;
var Bitcore = require('bitcore');
var PublicKey = Bitcore.PublicKey;
var HDPublicKey = Bitcore.HDPublicKey;
var Explorers = require('bitcore-explorers');
var utils = require('./utils');
var Lock = require('./lock');
var Storage = require('./storage');
var SignUtils = require('./signutils');
@ -45,6 +47,11 @@ function CopayServer(opts) {
CopayServer.prototype.createWallet = function (opts, cb) {
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 {
pubKey = new PublicKey.fromString(opts.pubKey);
} catch (e) {
@ -60,7 +67,7 @@ CopayServer.prototype.createWallet = function (opts, cb) {
name: opts.name,
m: opts.m,
n: opts.n,
network: opts.network || 'livenet',
network: network,
pubKey: pubKey,
});
@ -119,6 +126,8 @@ CopayServer.prototype._verifySignature = function (text, signature, pubKey) {
CopayServer.prototype.joinWallet = function (opts, cb) {
var self = this;
utils.checkRequired(opts, ['walletId', 'id', 'name', 'xPubKey', 'xPubKeySignature']);
self._runLocked(opts.walletId, cb, function (cb) {
self.getWallet({ id: opts.walletId }, function (err, wallet) {
if (err) return cb(err);
@ -164,6 +173,8 @@ CopayServer.prototype._doCreateAddress = function (pkr, index, isChange) {
CopayServer.prototype.createAddress = function (opts, cb) {
var self = this;
utils.checkRequired(opts, ['walletId', 'isChange']);
self._runLocked(opts.walletId, cb, function (cb) {
self.getWallet({ id: opts.walletId }, function (err, wallet) {
if (err) return cb(err);
@ -195,6 +206,8 @@ CopayServer.prototype._doCreateAddress = function (pkr, index, isChange) {
CopayServer.prototype.verifyMessageSignature = function (opts, cb) {
var self = this;
utils.checkRequired(opts, ['walletId', 'copayerId', 'message', 'signature']);
self.getWallet({ id: opts.walletId }, function (err, wallet) {
if (err) return cb(err);
@ -275,6 +288,8 @@ CopayServer.prototype._getUtxos = function (opts, cb) {
CopayServer.prototype.getBalance = function (opts, cb) {
var self = this;
utils.checkRequired(opts, 'walletId');
self._getUtxos({ walletId: opts.walletId }, function (err, utxos) {
if (err) return cb(err);
@ -326,6 +341,8 @@ CopayServer.prototype._selectUtxos = function (txp, utxos) {
CopayServer.prototype.createTx = function (opts, cb) {
var self = this;
utils.checkRequired(opts, ['walletId', 'copayerId', 'toAddress', 'amount', 'message']);
self.getWallet({ id: opts.walletId }, function (err, wallet) {
if (err) return cb(err);
@ -373,6 +390,8 @@ CopayServer.prototype._broadcastTx = function (rawTx, cb) {
CopayServer.prototype.signTx = function (opts, cb) {
var self = this;
utils.checkRequired(opts, ['walletId', 'copayerId', 'txProposalId', 'signature']);
self.fetchTx(opts.walletId, opts.txProposalId, function (err, txp) {
if (err) return cb(err);
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.copayerId - The wallet id.
* @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) {
var self = this;
utils.checkRequired(opts, ['walletId', 'copayerId', 'txProposalId']);
self.fetchTx(opts.walletId, opts.txProposalId, function (err, txp) {
if (err) return cb(err);
if (!txp) return cb('Transaction proposal not found');
@ -436,6 +458,8 @@ CopayServer.prototype.rejectTx = function (opts, cb) {
CopayServer.prototype.getPendingTxs = function (opts, cb) {
var self = this;
utils.checkRequired(opts, 'walletId');
self.storage.fetchTxs(opts.walletId, function (err, txps) {
if (err) return cb(err);

14
lib/utils.js Normal file
View File

@ -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;

View File

@ -428,10 +428,12 @@ describe('Copay server', function() {
name: 'me',
xPubKey: someXPubKeys[0],
};
server.joinWallet(copayerOpts, function(err) {
err.should.contain('Bad request');
try {
server.joinWallet(copayerOpts, function(err) {});
} catch (e) {
e.should.contain('xPubKeySignature');
done();
});
}
});
});
@ -526,11 +528,12 @@ describe('Copay server', function() {
it('should create address', function(done) {
server._doCreateAddress = sinon.stub().returns(new Address({
address: 'addr1',
path: 'path1'
path: 'path1',
}));
helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) {
server.createAddress({
walletId: '123'
walletId: '123',
isChange: false,
}, function(err, address) {
should.not.exist(err);
address.should.exist;