|
|
@ -15,6 +15,8 @@ var ServerCompromisedError = require('./servercompromisederror') |
|
|
|
|
|
|
|
var BASE_URL = 'http://localhost:3001/copay/api'; |
|
|
|
|
|
|
|
var WALLET_CRITICAL_DATA = ['copayerId', 'xPrivKey', 'm', 'walletPrivKey', 'publicKeyRing']; |
|
|
|
|
|
|
|
function _createProposalOpts(opts, signingKey) { |
|
|
|
var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message; |
|
|
|
opts.proposalSignature = WalletUtils.signMessage(msg, signingKey); |
|
|
@ -104,7 +106,12 @@ API.prototype._loadAndCheck = function(cb) { |
|
|
|
}; |
|
|
|
|
|
|
|
API.prototype._doRequest = function(method, url, args, data, cb) { |
|
|
|
var reqSignature = _signRequest(method, url, args, data.signingPrivKey); |
|
|
|
var reqSignature; |
|
|
|
data = data || {}; |
|
|
|
|
|
|
|
if (data.signingPrivKey) |
|
|
|
reqSignature = _signRequest(method, url, args, data.signingPrivKey); |
|
|
|
|
|
|
|
var absUrl = _getUrl(url); |
|
|
|
var args = { |
|
|
|
headers: { |
|
|
@ -142,8 +149,6 @@ API.prototype._doGetRequest = function(url, data, cb) { |
|
|
|
return this._doRequest('get', url, {}, data, cb); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
API.prototype.createWallet = function(walletName, copayerName, m, n, network, cb) { |
|
|
|
var self = this; |
|
|
|
network = network || 'livenet'; |
|
|
@ -154,62 +159,46 @@ API.prototype.createWallet = function(walletName, copayerName, m, n, network, cb |
|
|
|
if (data) |
|
|
|
return cb('Storage already contains a wallet'); |
|
|
|
|
|
|
|
// Generate wallet key pair to verify copayers
|
|
|
|
var privKey = new Bitcore.PrivateKey(null, network); |
|
|
|
var pubKey = privKey.toPublicKey(); |
|
|
|
|
|
|
|
data = { |
|
|
|
m: m, |
|
|
|
n: n, |
|
|
|
walletPrivKey: privKey.toWIF(), |
|
|
|
network: network, |
|
|
|
}; |
|
|
|
|
|
|
|
var walletPrivKey = new Bitcore.PrivateKey(); |
|
|
|
var args = { |
|
|
|
name: walletName, |
|
|
|
m: m, |
|
|
|
n: n, |
|
|
|
pubKey: pubKey.toString(), |
|
|
|
pubKey: walletPrivKey.toPublicKey().toString(), |
|
|
|
network: network, |
|
|
|
}; |
|
|
|
var url = '/v1/wallets/'; |
|
|
|
|
|
|
|
self._doPostRequest(url, args, data, function(err, body) { |
|
|
|
self._doPostRequest(url, args, {}, function(err, body) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var walletId = body.walletId; |
|
|
|
var secret = walletId + ':' + privKey.toString() + ':' + (network == 'testnet' ? 'T' : 'L'); |
|
|
|
var secret = walletId + ':' + walletPrivKey.toWIF() + ':' + (network == 'testnet' ? 'T' : 'L'); |
|
|
|
var ret; |
|
|
|
|
|
|
|
if (n > 1) |
|
|
|
ret = data.secret = secret; |
|
|
|
|
|
|
|
self.storage.save(data, function(err) { |
|
|
|
if (err) return cb(err); |
|
|
|
self._joinWallet(data, secret, copayerName, function(err) { |
|
|
|
return cb(err, ret); |
|
|
|
}); |
|
|
|
ret = secret; |
|
|
|
|
|
|
|
self._joinWallet(secret, copayerName, function(err) { |
|
|
|
return cb(err, ret); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
API.prototype._joinWallet = function(data, secret, copayerName, cb) { |
|
|
|
API.prototype._joinWallet = function(secret, copayerName, cb) { |
|
|
|
var self = this; |
|
|
|
data = data || {}; |
|
|
|
|
|
|
|
var secretSplit = secret.split(':'); |
|
|
|
var walletId = secretSplit[0]; |
|
|
|
|
|
|
|
var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]); |
|
|
|
var network = secretSplit[2] == 'T' ? 'testnet' : 'livenet'; |
|
|
|
data.xPrivKey = _createXPrivKey(network); |
|
|
|
var xPrivKey = _createXPrivKey(network); |
|
|
|
|
|
|
|
var xPubKey = new Bitcore.HDPublicKey(data.xPrivKey); |
|
|
|
var xPubKey = new Bitcore.HDPublicKey(xPrivKey); |
|
|
|
var xPubKeySignature = WalletUtils.signMessage(xPubKey.toString(), walletPrivKey); |
|
|
|
|
|
|
|
var signingPrivKey = (new Bitcore.HDPrivateKey(data.xPrivKey)).derive('m/1/0').privateKey; |
|
|
|
var signingPrivKey = (new Bitcore.HDPrivateKey(xPrivKey)).derive('m/1/0').privateKey; |
|
|
|
var args = { |
|
|
|
walletId: walletId, |
|
|
|
name: copayerName, |
|
|
@ -218,15 +207,17 @@ API.prototype._joinWallet = function(data, secret, copayerName, cb) { |
|
|
|
}; |
|
|
|
var url = '/v1/wallets/' + walletId + '/copayers'; |
|
|
|
|
|
|
|
this._doPostRequest(url, args, data, function(err, body) { |
|
|
|
this._doPostRequest(url, args, {}, function(err, body) { |
|
|
|
var wallet = body.wallet; |
|
|
|
data.copayerId = body.copayerId; |
|
|
|
data.walletPrivKey = walletPrivKey.toWIF(); |
|
|
|
data.signingPrivKey = signingPrivKey.toWIF(); |
|
|
|
data.m = wallet.m; |
|
|
|
data.n = wallet.n; |
|
|
|
data.publicKeyRing = wallet.publicKeyRing; |
|
|
|
data.network = wallet.network, |
|
|
|
var data = { |
|
|
|
copayerId: body.copayerId, |
|
|
|
walletPrivKey: walletPrivKey.toWIF(), |
|
|
|
signingPrivKey: signingPrivKey.toWIF(), |
|
|
|
m: wallet.m, |
|
|
|
n: wallet.n, |
|
|
|
publicKeyRing: wallet.publicKeyRing, |
|
|
|
network: wallet.network, |
|
|
|
}; |
|
|
|
self.storage.save(data, cb); |
|
|
|
}); |
|
|
|
}; |
|
|
@ -238,7 +229,7 @@ API.prototype.joinWallet = function(secret, copayerName, cb) { |
|
|
|
if (data) |
|
|
|
return cb('Storage already contains a wallet'); |
|
|
|
|
|
|
|
self._joinWallet(data, secret, copayerName, cb); |
|
|
|
self._joinWallet(secret, copayerName, cb); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
@ -313,11 +304,27 @@ API.prototype.export = function(cb) { |
|
|
|
|
|
|
|
this._loadAndCheck(function(err, data) { |
|
|
|
if (err) return cb(err); |
|
|
|
var x = _.pick(data, ['publicKeyRing', 'xPrivKey', 'copayerId', 'm']) |
|
|
|
return cb(null, JSON.stringify(x)); |
|
|
|
var x = _.pick(data, WALLET_CRITICAL_DATA) |
|
|
|
return cb(null, JSON.stringify(_.values(x))); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
API.prototype.import = function(str, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
var inData = JSON.parse(str); |
|
|
|
var data = {}, |
|
|
|
i = 0; |
|
|
|
|
|
|
|
_.each(WALLET_CRITICAL_DATA, function(k) { |
|
|
|
data[k] = inData[i++]; |
|
|
|
}); |
|
|
|
|
|
|
|
if (err) return cb(err); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
API.prototype.getTxProposals = function(opts, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|