commit
7177baf043
24
app.js
24
app.js
|
@ -44,6 +44,8 @@ var router = express.Router();
|
|||
|
||||
function returnError(err, res) {
|
||||
if (err instanceof CopayServer.ClientError) {
|
||||
|
||||
console.log('[app.js.47]'); //TODO
|
||||
var status = (err.code == 'NOTAUTHORIZED') ? 401 : 400;
|
||||
res.status(status).json({
|
||||
code: err.code,
|
||||
|
@ -78,7 +80,6 @@ function getServerWithAuth(req, res, cb) {
|
|||
message: req.url + '|' + JSON.stringify(req.body),
|
||||
signature: credentials.signature,
|
||||
};
|
||||
|
||||
CopayServer.getInstanceWithAuth(auth, function(err, server) {
|
||||
if (err) return returnError(err, res);
|
||||
return cb(server);
|
||||
|
@ -87,26 +88,27 @@ function getServerWithAuth(req, res, cb) {
|
|||
|
||||
router.post('/v1/wallets/', function(req, res) {
|
||||
var server = CopayServer.getInstance();
|
||||
server.createWallet(req.body, function(err, wallet) {
|
||||
if (err) returnError(err, res);
|
||||
server.createWallet(req.body, function(err, walletId) {
|
||||
if (err) return returnError(err, res);
|
||||
|
||||
res.json(wallet);
|
||||
res.json({
|
||||
walletId: walletId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/v1/wallets/:id/copayers/', function(req, res) {
|
||||
req.body.walletId = req.params['id'];
|
||||
var server = CopayServer.getInstance();
|
||||
server.joinWallet(req.body, function(err) {
|
||||
if (err) returnError(err, res);
|
||||
server.joinWallet(req.body, function(err, result) {
|
||||
if (err) return returnError(err, res);
|
||||
|
||||
res.end();
|
||||
res.json(result);
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/v1/wallets/', function(req, res) {
|
||||
getServerWithAuth(req, res, function(server) {
|
||||
if (err) return returnError(err, res);
|
||||
server.getWallet({}, function(err, wallet) {
|
||||
if (err) returnError(err, res);
|
||||
res.json(wallet);
|
||||
|
@ -117,7 +119,7 @@ router.get('/v1/wallets/', function(req, res) {
|
|||
router.post('/v1/addresses/', function(req, res) {
|
||||
getServerWithAuth(req, res, function(server) {
|
||||
server.createAddress(req.body, function(err, address) {
|
||||
if (err) returnError(err, res);
|
||||
if (err) return returnError(err, res);
|
||||
res.json(address);
|
||||
});
|
||||
});
|
||||
|
@ -126,7 +128,7 @@ router.post('/v1/addresses/', function(req, res) {
|
|||
router.get('/v1/addresses/', function(req, res) {
|
||||
getServerWithAuth(req, res, function(server) {
|
||||
server.getAddresses({}, function(err, addresses) {
|
||||
if (err) returnError(err, res);
|
||||
if (err) return returnError(err, res);
|
||||
res.json(addresses);
|
||||
});
|
||||
});
|
||||
|
@ -135,7 +137,7 @@ router.get('/v1/addresses/', function(req, res) {
|
|||
router.get('/v1/balance/', function(req, res) {
|
||||
getServerWithAuth(req, res, function(server) {
|
||||
server.getBalance({}, function(err, balance) {
|
||||
if (err) returnError(err, res);
|
||||
if (err) return returnError(err, res);
|
||||
res.json(balance);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var program = require('commander');
|
||||
var cli = require('../lib/clilib.js');
|
||||
|
||||
program
|
||||
.version('0.0.1')
|
||||
.command('create <walletName> <m-n> [username]', 'creates a wallet')
|
||||
.command('join <secret> [username]', 'join a wallet')
|
||||
.command('status', 'get wallet status')
|
||||
.parse(process.argv);
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var program = require('commander');
|
||||
var CliLib = require('../lib/clilib.js');
|
||||
var common = require('./common');
|
||||
|
||||
program
|
||||
.version('0.0.1')
|
||||
.option('-c,--config [file]', 'Wallet config filename')
|
||||
.option('-n,--network [networkname]', 'livenet|testnet', String, 'livenet')
|
||||
.usage('[options] <walletName> <m-n> [copayerName]')
|
||||
.parse(process.argv);
|
||||
|
||||
var args = program.args;
|
||||
if (!args[0])
|
||||
program.help();
|
||||
|
||||
var walletName = args[0];
|
||||
var copayerName = args[2] || process.env.USER;
|
||||
var network = program.network;
|
||||
|
||||
var mn = common.parseMN(args[1]);
|
||||
|
||||
var cli = new CliLib({
|
||||
filename: program.config
|
||||
});
|
||||
cli.createWallet(walletName, copayerName, mn[0], mn[1], network, function(err, secret) {
|
||||
common.die(err);
|
||||
console.log(' * Wallet Created.');
|
||||
console.log(' - Secret to share:\n\t' + secret);
|
||||
});
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var program = require('commander');
|
||||
var cli = require('../lib/clilib.js');
|
||||
|
||||
program
|
||||
.version('0.0.1')
|
||||
.parse(process.argv);
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var program = require('commander');
|
||||
var CliLib = require('../lib/clilib.js');
|
||||
var common = require('./common');
|
||||
|
||||
program
|
||||
.version('0.0.1')
|
||||
.option('-c,--config [file]', 'Wallet config filename')
|
||||
.usage('[options] <secret> [copayerName]')
|
||||
.parse(process.argv);
|
||||
|
||||
var args = program.args;
|
||||
if (!args[0])
|
||||
program.help();
|
||||
|
||||
var secret = args[0];
|
||||
var copayerName = args[1] || process.env.USER;
|
||||
|
||||
var cli = new CliLib({
|
||||
filename: program.config
|
||||
});
|
||||
|
||||
cli.joinWallet(secret, copayerName, function(err, xx) {
|
||||
common.die(err);
|
||||
console.log(' * Wallet Joined.', xx || '');
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var program = require('commander');
|
||||
var CliLib = require('../lib/clilib.js');
|
||||
var common = require('./common');
|
||||
|
||||
program
|
||||
.version('0.0.1')
|
||||
.option('-c,--config [file]', 'Wallet config filename')
|
||||
.parse(process.argv);
|
||||
|
||||
var args = program.args;
|
||||
var cli = new CliLib({
|
||||
filename: program.config
|
||||
});
|
||||
|
||||
cli.status(function(err, xx) {
|
||||
common.die(err);
|
||||
console.log(' * Status:', xx);
|
||||
});
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
var common = function() {};
|
||||
|
||||
|
||||
var die = common.die = function(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
common.parseMN = function(MN) {
|
||||
if (!MN)
|
||||
die('No m-n parameter');
|
||||
var mn = MN.split('-');
|
||||
|
||||
var m = parseInt(mn[0]);
|
||||
var n = parseInt(mn[1]);
|
||||
|
||||
if (!m || ! n) {
|
||||
die('Bad m-n parameter');
|
||||
}
|
||||
|
||||
return [m, n];
|
||||
};
|
||||
|
||||
|
||||
module.exports = common;
|
|
@ -0,0 +1,30 @@
|
|||
var _ = require('lodash');
|
||||
var async = require('async');
|
||||
var log = require('npmlog');
|
||||
var fs = require('fs');
|
||||
|
||||
var CliLib = require('./lib/clilib');
|
||||
|
||||
try {
|
||||
fs.unlinkSync('copay.dat');
|
||||
} catch (e) {}
|
||||
|
||||
var cli = new CliLib({
|
||||
filename: 'copay.dat'
|
||||
});
|
||||
|
||||
cli.createWallet('my wallet', 'me', 1, 1, 'testnet', function(err, secret) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
cli.status(function(err, status) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
console.log(status);
|
||||
})
|
||||
});
|
213
lib/clilib.js
213
lib/clilib.js
|
@ -4,7 +4,6 @@ var _ = require('lodash');
|
|||
var async = require('async');
|
||||
var log = require('npmlog');
|
||||
var request = require('request')
|
||||
var commander = require('commander')
|
||||
log.debug = log.verbose;
|
||||
log.level = 'debug';
|
||||
var fs = require('fs')
|
||||
|
@ -14,132 +13,238 @@ var SignUtils = require('./signutils');
|
|||
|
||||
var BASE_URL = 'http://localhost:3001/copay/api/';
|
||||
|
||||
var cli = {};
|
||||
|
||||
|
||||
function _getUrl(path) {
|
||||
return BASE_URL + path;
|
||||
};
|
||||
|
||||
|
||||
function signRequest(url, args) {
|
||||
|
||||
function _parseError(body) {
|
||||
if (_.isString(body)) {
|
||||
body = JSON.parse(body);
|
||||
}
|
||||
var code = body.code || 'ERROR';
|
||||
var message = body.error || 'There was an unknown error processing the request';
|
||||
log.error(code, message);
|
||||
};
|
||||
|
||||
function save(data) {
|
||||
fs.writeFileSync('./.bit', JSON.stringify(data));
|
||||
function _signRequest(url, args, privKey) {
|
||||
var message = url + '|' + JSON.stringify(args);
|
||||
return SignUtils.sign(message, privKey);
|
||||
};
|
||||
|
||||
function load() {
|
||||
function _createXPrivKey() {
|
||||
return new Bitcore.HDPrivateKey().toString();
|
||||
};
|
||||
|
||||
function CliLib(opts) {
|
||||
if (!opts.filename) {
|
||||
throw new Error('Please set the config filename');
|
||||
}
|
||||
this.filename = opts.filename;
|
||||
};
|
||||
|
||||
|
||||
CliLib.prototype._save = function(data) {
|
||||
fs.writeFileSync(this.filename, JSON.stringify(data));
|
||||
};
|
||||
|
||||
CliLib.prototype._load = function() {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync('./.bit'));
|
||||
return JSON.parse(fs.readFileSync(this.filename));
|
||||
} catch (ex) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
clilib.createWallet = function(walletName, copayerName, m, n, cb) {
|
||||
var data = load();
|
||||
CliLib.prototype._loadAndCheck = function() {
|
||||
var data = this._load();
|
||||
if (!data) {
|
||||
data = {};
|
||||
data.xPrivKey = new Bitcore.HDPrivateKey().toString();
|
||||
data.m = m;
|
||||
log.error('Wallet file not found.');
|
||||
process.exit(1);
|
||||
}
|
||||
if (data.verified == 'corrupt') {
|
||||
log.error('The wallet is tagged as corrupt. Some of the copayers cannot be verified to have known the wallet secret.');
|
||||
process.exit(1);
|
||||
}
|
||||
if (data.n > 1) {
|
||||
var pkrComplete = data.publicKeyRing && data.m && data.publicKeyRing.length === data.n;
|
||||
if (!pkrComplete) {
|
||||
log.warn('The file ' + this.filename + ' is incomplete. It will allow you to operate with the wallet but it should not be trusted as a backup. Please wait for all copayers to join the wallet and run the tool with -export flag.')
|
||||
}
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
CliLib.prototype.createWallet = function(walletName, copayerName, m, n, network, cb) {
|
||||
var self = this;
|
||||
|
||||
var data = this._load();
|
||||
if (data) return cb('File ' + this.filename + ' already contains a wallet');
|
||||
|
||||
// Generate wallet key pair to verify copayers
|
||||
var privKey = new Bitcore.PrivateKey();
|
||||
var pubKey = privKey.toPublicKey();
|
||||
|
||||
data = {
|
||||
xPrivKey: _createXPrivKey(),
|
||||
m: m,
|
||||
n: n,
|
||||
walletPrivKey: privKey.toString(),
|
||||
};
|
||||
|
||||
var args = {
|
||||
name: walletName,
|
||||
m: m,
|
||||
n: n,
|
||||
pubKey: pubKey.toString(),
|
||||
network: network || 'livenet',
|
||||
};
|
||||
|
||||
request({
|
||||
method: 'post',
|
||||
url: _getUrl('v1/wallets'),
|
||||
url: _getUrl('/v1/wallets/'),
|
||||
body: args,
|
||||
json: true,
|
||||
}, function(err, res, body) {
|
||||
if (err) return cb(err);
|
||||
var walletId = body;
|
||||
var secret = walletId + '|' + privKey.toString();
|
||||
if (res.statusCode != 200) {
|
||||
_parseError(body);
|
||||
return cb('Request error');
|
||||
}
|
||||
|
||||
joinWallet(secret, copayerName, function(err) {
|
||||
var walletId = body.walletId;
|
||||
var secret = walletId + ':' + privKey.toString();
|
||||
data.secret = secret;
|
||||
|
||||
self._save(data);
|
||||
|
||||
self._joinWallet(data, secret, copayerName, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
save(data);
|
||||
return cb(null, secret);
|
||||
return cb(null, data.secret);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
clilib.joinWallet = function(secret, copayerName, cb) {
|
||||
var data = load();
|
||||
if (!data) {
|
||||
data = {};
|
||||
data.xPrivKey = new Bitcore.HDPrivateKey().toString();
|
||||
}
|
||||
var secretSplit = secret.split('|');
|
||||
CliLib.prototype._joinWallet = function(data, secret, copayerName, cb) {
|
||||
var self = this;
|
||||
|
||||
var secretSplit = secret.split(':');
|
||||
var walletId = secretSplit[0];
|
||||
var privKey = Bitcore.PrivateKey.fromString(secretSplit[1]);
|
||||
var pubKey = privKey.toPublicKey();
|
||||
|
||||
var xPubKey = new Bitcore.HDPublicKey(data.xPrivKey).toString();
|
||||
var xPubKeySignature = SignUtils.sign(xPubKey, privKey);
|
||||
var xPubKey = new Bitcore.HDPublicKey(data.xPrivKey);
|
||||
var xPubKeySignature = SignUtils.sign(xPubKey.toString(), privKey);
|
||||
|
||||
var signingPrivKey = (new Bitcore.HDPrivateKey(data.xPrivKey)).derive('m/1/0').privateKey;
|
||||
|
||||
var args = {
|
||||
walletId: walletId,
|
||||
name: copayerName,
|
||||
xPubKey: xPubKey,
|
||||
xPubKey: xPubKey.toString(),
|
||||
xPubKeySignature: xPubKeySignature,
|
||||
};
|
||||
|
||||
request({
|
||||
method: 'post',
|
||||
url: _getUrl('v1/wallets/' + walletId + '/copayers'),
|
||||
url: _getUrl('/v1/wallets/' + walletId + '/copayers'),
|
||||
body: args,
|
||||
json: true,
|
||||
}, function(err, res, body) {
|
||||
if (err) return cb(err);
|
||||
if (res.statusCode != 200) {
|
||||
_parseError(body);
|
||||
return cb('Request error');
|
||||
}
|
||||
|
||||
var copayerId = body;
|
||||
data.copayerId = copayerId;
|
||||
save(data);
|
||||
return status(cb);
|
||||
});
|
||||
};
|
||||
var wallet = body.wallet;
|
||||
data.copayerId = body.copayerId;
|
||||
data.signingPrivKey = signingPrivKey.toString();
|
||||
data.m = wallet.m;
|
||||
data.n = wallet.n;
|
||||
data.publicKeyRing = wallet.publicKeyRing;
|
||||
self._save(data);
|
||||
|
||||
clilib.status = function(cb) {
|
||||
request({
|
||||
method: 'get',
|
||||
url: _getUrl('v1/dump/'),
|
||||
}, function(err, res, body) {
|
||||
if (err) return cb(err);
|
||||
|
||||
console.log(body);
|
||||
return cb();
|
||||
});
|
||||
};
|
||||
|
||||
clilib.send = function(addressTo, amount, message, cb) {
|
||||
CliLib.prototype.joinWallet = function(secret, copayerName, cb) {
|
||||
var self = this;
|
||||
|
||||
var data = this._load();
|
||||
if (data) return cb('File ' + this.filename + ' already contains a wallet');
|
||||
|
||||
data = {
|
||||
xPrivKey: _createXPrivKey(),
|
||||
};
|
||||
|
||||
self._joinWallet(data, secret, copayerName, cb);
|
||||
};
|
||||
|
||||
CliLib.prototype.status = function(cb) {
|
||||
var self = this;
|
||||
|
||||
var data = this._loadAndCheck();
|
||||
console.log('[clilib.js.180:data:]', data); //TODO
|
||||
|
||||
var url = '/v1/wallets/';
|
||||
var signature = _signRequest(url, {}, data.signingPrivKey);
|
||||
|
||||
request({
|
||||
headers: {
|
||||
'x-identity': data.copayerId,
|
||||
'x-signature': signature,
|
||||
},
|
||||
method: 'get',
|
||||
url: _getUrl(url),
|
||||
json: true,
|
||||
}, function(err, res, body) {
|
||||
if (err) return cb(err);
|
||||
if (res.statusCode != 200) {
|
||||
_parseError(body);
|
||||
return cb('Request error');
|
||||
}
|
||||
var wallet = body;
|
||||
|
||||
if (wallet.n > 0 && wallet.status === 'complete' && !data.verified) {
|
||||
var pubKey = Bitcore.PrivateKey.fromString(data.walletPrivKey).toPublicKey().toString();
|
||||
var fake = [];
|
||||
_.each(wallet.copayers, function(copayer) {
|
||||
if (!SignUtils.verify(copayer.xPubKey, copayer.xPubKeySignature, pubKey)) {
|
||||
fake.push(copayer);
|
||||
}
|
||||
});
|
||||
if (fake.length > 0) {
|
||||
log.error('Some copayers in the wallet could not be verified to have known the wallet secret');
|
||||
data.verified = 'corrupt';
|
||||
} else {
|
||||
data.verified = 'ok';
|
||||
}
|
||||
self._save(data);
|
||||
}
|
||||
|
||||
return cb(null, wallet);
|
||||
});
|
||||
};
|
||||
|
||||
CliLib.prototype.send = function(addressTo, amount, message, cb) {
|
||||
|
||||
};
|
||||
|
||||
clilib.sign = function(proposalId, cb) {
|
||||
CliLib.prototype.sign = function(proposalId, cb) {
|
||||
|
||||
};
|
||||
|
||||
clilib.reject = function(proposalId, cb) {
|
||||
CliLib.prototype.reject = function(proposalId, cb) {
|
||||
|
||||
};
|
||||
|
||||
clilib.address = function(cb) {
|
||||
CliLib.prototype.address = function(cb) {
|
||||
|
||||
};
|
||||
|
||||
clilib.history = function(limit, cb) {
|
||||
CliLib.prototype.history = function(limit, cb) {
|
||||
|
||||
};
|
||||
|
||||
module.exports = clilib;
|
||||
module.exports = CliLib;
|
||||
|
|
|
@ -221,11 +221,17 @@ CopayServer.prototype.joinWallet = function(opts, cb) {
|
|||
|
||||
wallet.addCopayer(copayer);
|
||||
self.storage.storeWalletAndUpdateCopayersLookup(wallet, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
self._notify('NewCopayer', {
|
||||
walletId: opts.walletId,
|
||||
copayerId: copayer.id,
|
||||
copayerName: copayer.name,
|
||||
});
|
||||
return cb(null, {
|
||||
copayerId: copayer.id,
|
||||
wallet: wallet
|
||||
});
|
||||
return cb(err, copayer.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@ var levelup = require('levelup');
|
|||
var async = require('async');
|
||||
var $ = require('preconditions').singleton();
|
||||
var log = require('npmlog');
|
||||
var util = require('util');
|
||||
log.debug = log.verbose;
|
||||
|
||||
var Wallet = require('./model/wallet');
|
||||
|
@ -195,8 +196,8 @@ Storage.prototype.fetchNotifications = function(walletId, opts, cb) {
|
|||
var txs = [];
|
||||
opts = opts || {};
|
||||
opts.limit = _.isNumber(opts.limit) ? parseInt(opts.limit) : -1;
|
||||
opts.minTs = _.isNumber(opts.minTs) ? zeroPad(opts.minTs,11) : 0;
|
||||
opts.maxTs = _.isNumber(opts.maxTs) ? zeroPad(opts.maxTs,11) : MAX_TS;
|
||||
opts.minTs = _.isNumber(opts.minTs) ? zeroPad(opts.minTs, 11) : 0;
|
||||
opts.maxTs = _.isNumber(opts.maxTs) ? zeroPad(opts.maxTs, 11) : MAX_TS;
|
||||
|
||||
var key = KEY.NOTIFICATION(walletId, opts.minTs);
|
||||
var endkey = KEY.NOTIFICATION(walletId, opts.maxTs);
|
||||
|
@ -380,7 +381,11 @@ Storage.prototype._dump = function(cb, fn) {
|
|||
fn = fn || console.log;
|
||||
|
||||
this.db.readStream()
|
||||
.on('data', fn)
|
||||
.on('data', function(data) {
|
||||
fn(util.inspect(data, {
|
||||
depth: 10
|
||||
}));
|
||||
})
|
||||
.on('end', function() {
|
||||
if (cb) return cb();
|
||||
});
|
||||
|
|
|
@ -57,8 +57,8 @@ helpers.createAndJoinWallet = function(m, n, cb) {
|
|||
xPubKeySignature: TestData.copayers[i].xPubKeySignature,
|
||||
};
|
||||
|
||||
server.joinWallet(copayerOpts, function(err, copayerId) {
|
||||
copayerIds.push(copayerId);
|
||||
server.joinWallet(copayerOpts, function(err, result) {
|
||||
copayerIds.push(result.copayerId);
|
||||
return cb(err);
|
||||
});
|
||||
}, function(err) {
|
||||
|
@ -66,7 +66,7 @@ helpers.createAndJoinWallet = function(m, n, cb) {
|
|||
|
||||
helpers.getAuthServer(copayerIds[0], function(s) {
|
||||
s.getWallet({}, function(err, w) {
|
||||
cb(s, w, _.take(TestData.copayers, w.n), copayerIds);
|
||||
cb(s, w);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -193,8 +193,8 @@ describe('Copay server', function() {
|
|||
beforeEach(function() {});
|
||||
|
||||
it('should get server instance for existing copayer', function(done) {
|
||||
helpers.createAndJoinWallet(1, 2, function(s, wallet, copayers, copayerIds) {
|
||||
var xpriv = copayers[0].xPrivKey;
|
||||
helpers.createAndJoinWallet(1, 2, function(s, wallet) {
|
||||
var xpriv = TestData.copayers[0].xPrivKey;
|
||||
var priv = Bitcore.HDPrivateKey
|
||||
.fromString(xpriv)
|
||||
.derive('m/1/0')
|
||||
|
@ -205,7 +205,7 @@ describe('Copay server', function() {
|
|||
var sig = SignUtils.sign(message, priv);
|
||||
|
||||
CopayServer.getInstanceWithAuth({
|
||||
copayerId: copayerIds[0],
|
||||
copayerId: wallet.copayers[0].id,
|
||||
message: message,
|
||||
signature: sig,
|
||||
}, function(err, server) {
|
||||
|
@ -218,22 +218,24 @@ describe('Copay server', function() {
|
|||
it('should fail when requesting for non-existent copayer', function(done) {
|
||||
CopayServer.getInstanceWithAuth({
|
||||
copayerId: 'ads',
|
||||
message: 'dummy',
|
||||
signature: 'dummy',
|
||||
message: TestData.message.text,
|
||||
signature: TestData.message.signature,
|
||||
}, function(err, server) {
|
||||
err.should.contain('Copayer not found');
|
||||
err.code.should.equal('NOTAUTHORIZED');
|
||||
err.message.should.contain('Copayer not found');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail when message signature cannot be verified', function(done) {
|
||||
helpers.createAndJoinWallet(1, 2, function(s, wallet, copayers, copayerIds) {
|
||||
helpers.createAndJoinWallet(1, 2, function(s, wallet) {
|
||||
CopayServer.getInstanceWithAuth({
|
||||
copayerId: copayerIds[0],
|
||||
copayerId: wallet.copayers[0].id,
|
||||
message: 'dummy',
|
||||
signature: 'dummy',
|
||||
}, function(err, server) {
|
||||
err.should.contain('Invalid signature');
|
||||
err.code.should.equal('NOTAUTHORIZED');
|
||||
err.message.should.contain('Invalid signature');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -343,8 +345,9 @@ describe('Copay server', function() {
|
|||
xPubKey: TestData.copayers[0].xPubKey,
|
||||
xPubKeySignature: TestData.copayers[0].xPubKeySignature,
|
||||
};
|
||||
server.joinWallet(copayerOpts, function(err, copayerId) {
|
||||
server.joinWallet(copayerOpts, function(err, result) {
|
||||
should.not.exist(err);
|
||||
var copayerId = result.copayerId;
|
||||
helpers.getAuthServer(copayerId, function(server) {
|
||||
server.getWallet({}, function(err, wallet) {
|
||||
wallet.id.should.equal(walletId);
|
||||
|
@ -365,8 +368,8 @@ describe('Copay server', function() {
|
|||
xPubKey: TestData.copayers[0].xPubKey,
|
||||
xPubKeySignature: TestData.copayers[0].xPubKeySignature,
|
||||
};
|
||||
server.joinWallet(copayerOpts, function(err, copayerId) {
|
||||
should.not.exist(copayerId);
|
||||
server.joinWallet(copayerOpts, function(err, result) {
|
||||
should.not.exist(result);
|
||||
err.should.exist;
|
||||
err.message.should.contain('name');
|
||||
done();
|
||||
|
@ -546,9 +549,9 @@ describe('Copay server', function() {
|
|||
xPubKey: TestData.copayers[0].xPubKey,
|
||||
xPubKeySignature: TestData.copayers[0].xPubKeySignature,
|
||||
};
|
||||
server.joinWallet(copayerOpts, function(err, copayerId) {
|
||||
server.joinWallet(copayerOpts, function(err, result) {
|
||||
should.not.exist(err);
|
||||
helpers.getAuthServer(copayerId, function(server) {
|
||||
helpers.getAuthServer(result.copayerId, function(server) {
|
||||
server.createAddress({}, function(err, address) {
|
||||
should.not.exist(address);
|
||||
err.should.exist;
|
||||
|
@ -598,12 +601,11 @@ describe('Copay server', function() {
|
|||
});
|
||||
|
||||
describe('#createTx', function() {
|
||||
var server, wallet, copayerPriv;
|
||||
var server, wallet;
|
||||
beforeEach(function(done) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w, c) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w) {
|
||||
server = s;
|
||||
wallet = w;
|
||||
copayerPriv = c;
|
||||
server.createAddress({}, function(err, address) {
|
||||
done();
|
||||
});
|
||||
|
@ -613,7 +615,7 @@ describe('Copay server', function() {
|
|||
it('should create a tx', function(done) {
|
||||
helpers.createUtxos(server, wallet, [100, 200], function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.should.exist;
|
||||
|
@ -650,10 +652,10 @@ describe('Copay server', function() {
|
|||
xPubKey: TestData.copayers[0].xPubKey,
|
||||
xPubKeySignature: TestData.copayers[0].xPubKeySignature,
|
||||
};
|
||||
server.joinWallet(copayerOpts, function(err, copayerId) {
|
||||
server.joinWallet(copayerOpts, function(err, result) {
|
||||
should.not.exist(err);
|
||||
helpers.getAuthServer(copayerId, function(server, wallet) {
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, null, copayerPriv[0].privKey);
|
||||
helpers.getAuthServer(result.copayerId, function(server, wallet) {
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, null, TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(tx);
|
||||
err.should.exist;
|
||||
|
@ -668,7 +670,7 @@ describe('Copay server', function() {
|
|||
it('should fail to create tx for address invalid address', function(done) {
|
||||
helpers.createUtxos(server, wallet, [100, 200], function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('invalid address', 80, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('invalid address', 80, null, TestData.copayers[0].privKey);
|
||||
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(tx);
|
||||
|
@ -683,7 +685,7 @@ describe('Copay server', function() {
|
|||
it('should fail to create tx for address of different network', function(done) {
|
||||
helpers.createUtxos(server, wallet, [100, 200], function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('myE38JHdxmQcTJGP1ZiX4BiGhDxMJDvLJD', 80, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('myE38JHdxmQcTJGP1ZiX4BiGhDxMJDvLJD', 80, null, TestData.copayers[0].privKey);
|
||||
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(tx);
|
||||
|
@ -698,7 +700,7 @@ describe('Copay server', function() {
|
|||
it('should fail to create tx when insufficient funds', function(done) {
|
||||
helpers.createUtxos(server, wallet, [100], function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 120, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 120, null, TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
err.code.should.equal('INSUFFICIENTFUNDS');
|
||||
err.message.should.equal('Insufficient funds');
|
||||
|
@ -723,11 +725,11 @@ describe('Copay server', function() {
|
|||
it('should create tx when there is a pending tx and enough UTXOs', function(done) {
|
||||
helpers.createUtxos(server, wallet, [10.1, 10.2, 10.3], function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 12, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 12, null, TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.should.exist;
|
||||
var txOpts2 = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 8, null, copayerPriv[0].privKey);
|
||||
var txOpts2 = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 8, null, TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts2, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.should.exist;
|
||||
|
@ -749,11 +751,11 @@ describe('Copay server', function() {
|
|||
it('should fail to create tx when there is a pending tx and not enough UTXOs', function(done) {
|
||||
helpers.createUtxos(server, wallet, [10.1, 10.2, 10.3], function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 12, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 12, null, TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.should.exist;
|
||||
var txOpts2 = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 24, null, copayerPriv[0].privKey);
|
||||
var txOpts2 = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 24, null, TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts2, function(err, tx) {
|
||||
err.code.should.equal('INSUFFICIENTFUNDS');
|
||||
err.message.should.equal('Insufficient funds');
|
||||
|
@ -783,7 +785,7 @@ describe('Copay server', function() {
|
|||
should.not.exist(err);
|
||||
balance.totalAmount.should.equal(helpers.toSatoshi(N * 100));
|
||||
balance.lockedAmount.should.equal(helpers.toSatoshi(0));
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, null, TestData.copayers[0].privKey);
|
||||
async.map(_.range(N), function(i, cb) {
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
cb(err, tx);
|
||||
|
@ -808,18 +810,16 @@ describe('Copay server', function() {
|
|||
|
||||
|
||||
describe('#rejectTx', function() {
|
||||
var server, wallet, copayerPriv, txid, copayerIds;
|
||||
var server, wallet, txid;
|
||||
|
||||
beforeEach(function(done) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w, c, ids) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w) {
|
||||
server = s;
|
||||
wallet = w;
|
||||
copayerPriv = c;
|
||||
copayerIds = ids;
|
||||
server.createAddress({}, function(err, address) {
|
||||
helpers.createUtxos(server, wallet, _.range(1, 9), function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.should.exist;
|
||||
|
@ -847,8 +847,8 @@ describe('Copay server', function() {
|
|||
|
||||
var actors = tx.getActors();
|
||||
actors.length.should.equal(1);
|
||||
actors[0].should.equal(copayerIds[0]);
|
||||
tx.getActionBy(copayerIds[0]).type.should.equal('reject');
|
||||
actors[0].should.equal(wallet.copayers[0].id);
|
||||
tx.getActionBy(wallet.copayers[0].id).type.should.equal('reject');
|
||||
|
||||
done();
|
||||
});
|
||||
|
@ -858,18 +858,16 @@ describe('Copay server', function() {
|
|||
});
|
||||
|
||||
describe('#signTx', function() {
|
||||
var server, wallet, copayerPriv, txid, copayerIds;
|
||||
var server, wallet, txid;
|
||||
|
||||
beforeEach(function(done) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w, c, ids) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w) {
|
||||
server = s;
|
||||
wallet = w;
|
||||
copayerPriv = c;
|
||||
copayerIds = ids;
|
||||
server.createAddress({}, function(err, address) {
|
||||
helpers.createUtxos(server, wallet, _.range(1, 9), function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.should.exist;
|
||||
|
@ -899,8 +897,8 @@ describe('Copay server', function() {
|
|||
|
||||
var actors = tx.getActors();
|
||||
actors.length.should.equal(1);
|
||||
actors[0].should.equal(copayerIds[0]);
|
||||
tx.getActionBy(copayerIds[0]).type.should.equal('accept');
|
||||
actors[0].should.equal(wallet.copayers[0].id);
|
||||
tx.getActionBy(wallet.copayers[0].id).type.should.equal('accept');
|
||||
|
||||
done();
|
||||
});
|
||||
|
@ -1002,12 +1000,11 @@ describe('Copay server', function() {
|
|||
|
||||
|
||||
describe('#signTx and broadcast', function() {
|
||||
var server, wallet, copayerPriv, utxos;
|
||||
var server, wallet, utxos;
|
||||
beforeEach(function(done) {
|
||||
helpers.createAndJoinWallet(1, 1, function(s, w, c) {
|
||||
helpers.createAndJoinWallet(1, 1, function(s, w) {
|
||||
server = s;
|
||||
wallet = w;
|
||||
copayerPriv = c;
|
||||
server.createAddress({}, function(err, address) {
|
||||
helpers.createUtxos(server, wallet, _.range(1, 9), function(inutxos) {
|
||||
utxos = inutxos;
|
||||
|
@ -1019,7 +1016,7 @@ describe('Copay server', function() {
|
|||
|
||||
it('should sign and broadcast a tx', function(done) {
|
||||
helpers.stubBlockExplorer(server, utxos, '1122334455');
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, txp) {
|
||||
should.not.exist(err);
|
||||
txp.should.exist;
|
||||
|
@ -1045,7 +1042,7 @@ describe('Copay server', function() {
|
|||
|
||||
it('should keep tx as *accepted* if unable to broadcast it', function(done) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, txp) {
|
||||
should.not.exist(err);
|
||||
txp.should.exist;
|
||||
|
@ -1076,12 +1073,11 @@ describe('Copay server', function() {
|
|||
});
|
||||
|
||||
describe('Tx proposal workflow', function() {
|
||||
var server, wallet, copayerPriv, utxos;
|
||||
var server, wallet, utxos;
|
||||
beforeEach(function(done) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w, c) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w) {
|
||||
server = s;
|
||||
wallet = w;
|
||||
copayerPriv = c;
|
||||
server.createAddress({}, function(err, address) {
|
||||
helpers.createUtxos(server, wallet, _.range(1, 9), function(inutxos) {
|
||||
utxos = inutxos;
|
||||
|
@ -1093,7 +1089,7 @@ describe('Copay server', function() {
|
|||
|
||||
it('other copayers should see pending proposal created by one copayer', function(done) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, 'some message', copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, 'some message', TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, txp) {
|
||||
should.not.exist(err);
|
||||
should.exist.txp;
|
||||
|
@ -1119,21 +1115,20 @@ describe('Copay server', function() {
|
|||
});
|
||||
|
||||
describe('#getTxs', function() {
|
||||
var server, wallet, copayerPriv, clock;
|
||||
var server, wallet, clock;
|
||||
|
||||
beforeEach(function(done) {
|
||||
if (server) return done();
|
||||
this.timeout(5000);
|
||||
console.log('\tCreating TXS...');
|
||||
clock = sinon.useFakeTimers();
|
||||
helpers.createAndJoinWallet(1, 1, function(s, w, c) {
|
||||
helpers.createAndJoinWallet(1, 1, function(s, w) {
|
||||
server = s;
|
||||
wallet = w;
|
||||
copayerPriv = c;
|
||||
server.createAddress({}, function(err, address) {
|
||||
helpers.createUtxos(server, wallet, _.range(10), function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.1, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.1, null, TestData.copayers[0].privKey);
|
||||
async.eachSeries(_.range(10), function(i, next) {
|
||||
clock.tick(10000);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
|
@ -1211,19 +1206,18 @@ describe('Copay server', function() {
|
|||
|
||||
|
||||
describe('Notifications', function() {
|
||||
var server, wallet, copayerPriv;
|
||||
var server, wallet;
|
||||
|
||||
beforeEach(function(done) {
|
||||
if (server) return done();
|
||||
console.log('\tCreating TXS...');
|
||||
helpers.createAndJoinWallet(1, 1, function(s, w, c) {
|
||||
helpers.createAndJoinWallet(1, 1, function(s, w) {
|
||||
server = s;
|
||||
wallet = w;
|
||||
copayerPriv = c;
|
||||
server.createAddress({}, function(err, address) {
|
||||
helpers.createUtxos(server, wallet, helpers.toSatoshi(_.range(4)), function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.01, null, copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.01, null, TestData.copayers[0].privKey);
|
||||
async.eachSeries(_.range(3), function(i, next) {
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
|
@ -1253,8 +1247,8 @@ describe('Copay server', function() {
|
|||
server.getNotifications({
|
||||
limit: 5,
|
||||
reverse: true,
|
||||
maxTs: Date.now()/1000,
|
||||
minTs: Date.now()/1000-1000,
|
||||
maxTs: Date.now() / 1000,
|
||||
minTs: Date.now() / 1000 - 1000,
|
||||
}, function(err, notifications) {
|
||||
should.not.exist(err);
|
||||
var types = _.pluck(notifications, 'type');
|
||||
|
@ -1436,16 +1430,15 @@ describe('Copay server', function() {
|
|||
|
||||
|
||||
describe('#removePendingTx', function() {
|
||||
var server, wallet, copayerPriv, txp;
|
||||
var server, wallet, txp;
|
||||
beforeEach(function(done) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w, c) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w) {
|
||||
server = s;
|
||||
wallet = w;
|
||||
copayerPriv = c;
|
||||
server.createAddress({}, function(err, address) {
|
||||
helpers.createUtxos(server, wallet, [100, 200], function(utxos) {
|
||||
helpers.stubBlockExplorer(server, utxos);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', copayerPriv[0].privKey);
|
||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
server.getPendingTxs({}, function(err, txs) {
|
||||
txp = txs[0];
|
||||
|
|
Loading…
Reference in New Issue