Browse Source

improvements

activeAddress
Ivan Socolsky 10 years ago
parent
commit
6ca443bf58
  1. 18
      app.js
  2. 14
      cli.js
  3. 142
      lib/clilib.js
  4. 7
      lib/server.js
  5. 19
      test/integration.js

18
app.js

@ -88,19 +88,21 @@ function getServerWithAuth(req, res, cb) {
router.post('/v1/wallets/', function(req, res) { router.post('/v1/wallets/', function(req, res) {
var server = CopayServer.getInstance(); var server = CopayServer.getInstance();
server.createWallet(req.body, function(err, walletId) { server.createWallet(req.body, function(err, walletId) {
if (err) returnError(err, res); if (err) return returnError(err, res);
res.json(walletId); res.json({
walletId: walletId,
});
}); });
}); });
router.post('/v1/wallets/:id/copayers/', function(req, res) { router.post('/v1/wallets/:id/copayers/', function(req, res) {
req.body.walletId = req.params['id']; req.body.walletId = req.params['id'];
var server = CopayServer.getInstance(); var server = CopayServer.getInstance();
server.joinWallet(req.body, function(err, copayerId) { server.joinWallet(req.body, function(err, result) {
if (err) returnError(err, res); if (err) return returnError(err, res);
res.json(copayerId); res.json(result);
}); });
}); });
@ -117,7 +119,7 @@ router.get('/v1/wallets/', function(req, res) {
router.post('/v1/addresses/', function(req, res) { router.post('/v1/addresses/', function(req, res) {
getServerWithAuth(req, res, function(server) { getServerWithAuth(req, res, function(server) {
server.createAddress(req.body, function(err, address) { server.createAddress(req.body, function(err, address) {
if (err) returnError(err, res); if (err) return returnError(err, res);
res.json(address); res.json(address);
}); });
}); });
@ -126,7 +128,7 @@ router.post('/v1/addresses/', function(req, res) {
router.get('/v1/addresses/', function(req, res) { router.get('/v1/addresses/', function(req, res) {
getServerWithAuth(req, res, function(server) { getServerWithAuth(req, res, function(server) {
server.getAddresses({}, function(err, addresses) { server.getAddresses({}, function(err, addresses) {
if (err) returnError(err, res); if (err) return returnError(err, res);
res.json(addresses); res.json(addresses);
}); });
}); });
@ -135,7 +137,7 @@ router.get('/v1/addresses/', function(req, res) {
router.get('/v1/balance/', function(req, res) { router.get('/v1/balance/', function(req, res) {
getServerWithAuth(req, res, function(server) { getServerWithAuth(req, res, function(server) {
server.getBalance({}, function(err, balance) { server.getBalance({}, function(err, balance) {
if (err) returnError(err, res); if (err) return returnError(err, res);
res.json(balance); res.json(balance);
}); });
}); });

14
cli.js

@ -3,17 +3,23 @@ var async = require('async');
var log = require('npmlog'); var log = require('npmlog');
var fs = require('fs'); var fs = require('fs');
var clilib = require('./lib/clilib'); var CliLib = require('./lib/clilib');
fs.unlinkSync('.bit'); try {
fs.unlinkSync('copay.dat');
} catch (e) {}
clilib.createWallet('my wallet', 'me', 1, 1, function(err, secret) { var cli = new CliLib({
filename: 'copay.dat'
});
cli.createWallet('my wallet', 'me', 1, 1, 'testnet', function(err, secret) {
if (err) { if (err) {
console.log(err); console.log(err);
process.exit(); process.exit();
} }
clilib.status(function(err, status) { cli.status(function(err, status) {
if (err) { if (err) {
console.log(err); console.log(err);
process.exit(); process.exit();

142
lib/clilib.js

@ -13,35 +13,64 @@ var SignUtils = require('./signutils');
var BASE_URL = 'http://localhost:3001/copay/api/'; var BASE_URL = 'http://localhost:3001/copay/api/';
var clilib = {};
function _getUrl(path) { function _getUrl(path) {
return BASE_URL + path; return BASE_URL + path;
}; };
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 _signRequest(url, args) { function _signRequest(url, args, privKey) {
var message = url + (args ? '|' + JSON.stringify(args) : '');
return SignUtils.sign(message, privKey);
};
function _createXPrivKey() {
return new Bitcore.HDPrivateKey().toString();
}; };
function _save(data) { function CliLib(opts) {
fs.writeFileSync('.bit', JSON.stringify(data)); this.filename = opts.filename;
}; };
function _load() { CliLib.prototype._save = function(data) {
fs.writeFileSync(this.filename, JSON.stringify(data));
};
CliLib.prototype._load = function() {
try { try {
return JSON.parse(fs.readFileSync('.bit')); return JSON.parse(fs.readFileSync(this.filename));
} catch (ex) {} } catch (ex) {}
}; };
function _createXPrivKey() { CliLib.prototype._loadAndCheck = function() {
return new Bitcore.HDPrivateKey().toString(); var data = this._load();
if (!data) {
log.error('Wallet file not found.');
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.createWallet = function(walletName, copayerName, m, n, cb) { CliLib.prototype.createWallet = function(walletName, copayerName, m, n, network, cb) {
var data = _load(); var self = this;
if (data) return cb('Only one wallet can exist');
var data = this._load();
if (data) return cb('Only one wallet is supported in this version');
data = { data = {
xPrivKey: _createXPrivKey(), xPrivKey: _createXPrivKey(),
@ -56,6 +85,7 @@ clilib.createWallet = function(walletName, copayerName, m, n, cb) {
m: m, m: m,
n: n, n: n,
pubKey: pubKey.toString(), pubKey: pubKey.toString(),
network: network || 'livenet',
}; };
request({ request({
@ -65,12 +95,18 @@ clilib.createWallet = function(walletName, copayerName, m, n, cb) {
json: true, json: true,
}, function(err, res, body) { }, function(err, res, body) {
if (err) return cb(err); if (err) return cb(err);
var walletId = body; if (res.statusCode != 200) {
data.secret = walletId + '|' + privKey.toString(); _parseError(body);
return cb('Request error');
}
_save(data); var walletId = body.walletId;
var secret = walletId + '|' + privKey.toString();
data.secret = secret;
clilib.joinWallet(data.secret, copayerName, function(err) { self._save(data);
self._joinWallet(data, secret, copayerName, function(err) {
if (err) return cb(err); if (err) return cb(err);
return cb(null, data.secret); return cb(null, data.secret);
@ -78,27 +114,22 @@ clilib.createWallet = function(walletName, copayerName, m, n, cb) {
}); });
}; };
clilib.joinWallet = function(secret, copayerName, cb) { CliLib.prototype._joinWallet = function(data, secret, copayerName, cb) {
var data = _load(); var self = this;
if (data && data.copayerId) return cb('Only one wallet can exist');
if (!data) {
data = {
xPrivKey: _createXPrivKey(),
};
}
var secretSplit = secret.split('|'); var secretSplit = secret.split('|');
var walletId = secretSplit[0]; var walletId = secretSplit[0];
var privKey = Bitcore.PrivateKey.fromString(secretSplit[1]); var privKey = Bitcore.PrivateKey.fromString(secretSplit[1]);
var pubKey = privKey.toPublicKey(); var pubKey = privKey.toPublicKey();
var xPubKey = new Bitcore.HDPublicKey(data.xPrivKey).toString(); var xPubKey = new Bitcore.HDPublicKey(data.xPrivKey);
var xPubKeySignature = SignUtils.sign(xPubKey, privKey); var xPubKeySignature = SignUtils.sign(xPubKey.toString(), privKey);
var signingPrivKey = xPubKey.derive('m/1/0');
var args = { var args = {
walletId: walletId, walletId: walletId,
name: copayerName, name: copayerName,
xPubKey: xPubKey, xPubKey: xPubKey.toString(),
xPubKeySignature: xPubKeySignature, xPubKeySignature: xPubKeySignature,
}; };
@ -109,23 +140,43 @@ clilib.joinWallet = function(secret, copayerName, cb) {
json: true, json: true,
}, function(err, res, body) { }, function(err, res, body) {
if (err) return cb(err); if (err) return cb(err);
var copayerId = body; if (res.statusCode != 200) {
data.copayerId = copayerId; _parseError(body);
return cb('Request error');
_save(data); }
// TODO: call status to retrieve wallet.m 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);
return clilib.status(cb); return cb();
}); });
}; };
clilib.status = function(cb) { CliLib.prototype.joinWallet = function(secret, copayerName, cb) {
var data = _load(); var self = this;
if (!data || !data.copayerId) return cb('Not a part of an active wallet');
var url = 'v1/dump/'; var data = this._load();
var signature = _signRequest(url); if (data) return cb('Only one wallet is supported in this version');
data = {
xPrivKey: _createXPrivKey(),
};
self._joinWallet(data, secret, copayerName, cb);
};
CliLib.prototype.status = function(cb) {
var self = this;
var data = this._loadAndCheck();
var url = 'v1/wallets/';
var signature = _signRequest(url, null, data.signingPrivKey);
request({ request({
headers: { headers: {
@ -134,31 +185,36 @@ clilib.status = function(cb) {
}, },
method: 'get', method: 'get',
url: _getUrl(url), url: _getUrl(url),
json: true,
}, function(err, res, body) { }, function(err, res, body) {
if (err) return cb(err); if (err) return cb(err);
if (res.statusCode != 200) {
_parseError(body);
return cb('Request error');
}
return cb(null, body); return cb(null, body);
}); });
}; };
clilib.send = function(addressTo, amount, message, cb) { 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;

7
lib/server.js

@ -221,11 +221,16 @@ CopayServer.prototype.joinWallet = function(opts, cb) {
wallet.addCopayer(copayer); wallet.addCopayer(copayer);
self.storage.storeWalletAndUpdateCopayersLookup(wallet, function(err) { self.storage.storeWalletAndUpdateCopayersLookup(wallet, function(err) {
if (err) return cb(err);
self._notify('NewCopayer', { self._notify('NewCopayer', {
walletId: opts.walletId, walletId: opts.walletId,
copayerId: copayer.id, copayerId: copayer.id,
}); });
return cb(err, copayer.id); return cb(null, {
copayerId: copayer.id,
wallet: wallet
});
}); });
}); });
}); });

19
test/integration.js

@ -57,8 +57,8 @@ helpers.createAndJoinWallet = function(m, n, cb) {
xPubKeySignature: TestData.copayers[i].xPubKeySignature, xPubKeySignature: TestData.copayers[i].xPubKeySignature,
}; };
server.joinWallet(copayerOpts, function(err, copayerId) { server.joinWallet(copayerOpts, function(err, result) {
copayerIds.push(copayerId); copayerIds.push(result.copayerId);
return cb(err); return cb(err);
}); });
}, function(err) { }, function(err) {
@ -345,8 +345,9 @@ describe('Copay server', function() {
xPubKey: TestData.copayers[0].xPubKey, xPubKey: TestData.copayers[0].xPubKey,
xPubKeySignature: TestData.copayers[0].xPubKeySignature, xPubKeySignature: TestData.copayers[0].xPubKeySignature,
}; };
server.joinWallet(copayerOpts, function(err, copayerId) { server.joinWallet(copayerOpts, function(err, result) {
should.not.exist(err); should.not.exist(err);
var copayerId = result.copayerId;
helpers.getAuthServer(copayerId, function(server) { helpers.getAuthServer(copayerId, function(server) {
server.getWallet({}, function(err, wallet) { server.getWallet({}, function(err, wallet) {
wallet.id.should.equal(walletId); wallet.id.should.equal(walletId);
@ -367,8 +368,8 @@ describe('Copay server', function() {
xPubKey: TestData.copayers[0].xPubKey, xPubKey: TestData.copayers[0].xPubKey,
xPubKeySignature: TestData.copayers[0].xPubKeySignature, xPubKeySignature: TestData.copayers[0].xPubKeySignature,
}; };
server.joinWallet(copayerOpts, function(err, copayerId) { server.joinWallet(copayerOpts, function(err, result) {
should.not.exist(copayerId); should.not.exist(result);
err.should.exist; err.should.exist;
err.message.should.contain('name'); err.message.should.contain('name');
done(); done();
@ -548,9 +549,9 @@ describe('Copay server', function() {
xPubKey: TestData.copayers[0].xPubKey, xPubKey: TestData.copayers[0].xPubKey,
xPubKeySignature: TestData.copayers[0].xPubKeySignature, xPubKeySignature: TestData.copayers[0].xPubKeySignature,
}; };
server.joinWallet(copayerOpts, function(err, copayerId) { server.joinWallet(copayerOpts, function(err, result) {
should.not.exist(err); should.not.exist(err);
helpers.getAuthServer(copayerId, function(server) { helpers.getAuthServer(result.copayerId, function(server) {
server.createAddress({}, function(err, address) { server.createAddress({}, function(err, address) {
should.not.exist(address); should.not.exist(address);
err.should.exist; err.should.exist;
@ -652,9 +653,9 @@ describe('Copay server', function() {
xPubKey: TestData.copayers[0].xPubKey, xPubKey: TestData.copayers[0].xPubKey,
xPubKeySignature: TestData.copayers[0].xPubKeySignature, xPubKeySignature: TestData.copayers[0].xPubKeySignature,
}; };
server.joinWallet(copayerOpts, function(err, copayerId) { server.joinWallet(copayerOpts, function(err, result) {
should.not.exist(err); should.not.exist(err);
helpers.getAuthServer(copayerId, function(server, wallet) { helpers.getAuthServer(result.copayerId, function(server, wallet) {
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, null, copayerPriv[0].privKey); var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, null, copayerPriv[0].privKey);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.not.exist(tx); should.not.exist(tx);

Loading…
Cancel
Save