|
|
@ -118,6 +118,8 @@ function API(opts) { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
API.prototype._tryToCompleteFromServer = function(wcd, cb) { |
|
|
|
|
|
|
|
if (!wcd.walletPrivKey) |
|
|
@ -176,15 +178,65 @@ API.prototype._tryToComplete = function(opts, wcd, cb) { |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// access: 'full' > 'readwrite' > readonly'
|
|
|
|
API.prototype._processWcdAfterRead = function(rawData, requiredAccess, cb) { |
|
|
|
var WU = WalletUtils; |
|
|
|
requiredAccess = requiredAccess || 'full'; |
|
|
|
|
|
|
|
if (!rawData) |
|
|
|
return cb(null, rawData); |
|
|
|
|
|
|
|
var requiredAccessLevel = WU.accessNameToLevel(requiredAccess); |
|
|
|
|
|
|
|
var access = WU.accessFromData(rawData); |
|
|
|
var accessLevel = WU.accessNameToLevel(access); |
|
|
|
|
|
|
|
// Is the data available?
|
|
|
|
if (requiredAccessLevel <= accessLevel) |
|
|
|
return cb(null, rawData); |
|
|
|
|
|
|
|
// Has any encrypted info?
|
|
|
|
if (!rawData.enc) |
|
|
|
return cb('NOTAUTH'); |
|
|
|
|
|
|
|
// Decrypt it and try again
|
|
|
|
this.emit('needPassword', function(password) { |
|
|
|
if (!password) return cb('No password'); |
|
|
|
rawData = WE.decryptWallet(rawData, password); |
|
|
|
var access = WU.accessFromData(rawData); |
|
|
|
|
|
|
|
// Is the data available?
|
|
|
|
if (requiredAccessLevel <= accessLevel) |
|
|
|
return cb(null, rawData); |
|
|
|
|
|
|
|
return cb('NOTAUTH'); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
API.prototype._processWcdBeforeWrite = function(wcd, accessWithoutEncrytion, cb) { |
|
|
|
// Is any encrypted?
|
|
|
|
if (encryptedAccess) { |
|
|
|
this.emit('needPassword', function(password) { |
|
|
|
if (!password) return cb('No password'); |
|
|
|
rawdata = WE.encryptWallet(wcd, accessWithoutEncrytion, password); |
|
|
|
return cb(null, rawdata); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
return rawdata; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
API.prototype._load = function(cb) { |
|
|
|
API.prototype._load = function(opts, cb) { |
|
|
|
var self = this; |
|
|
|
$.shouldBeFunction(cb); |
|
|
|
|
|
|
|
this.storage.load(function(err, wcd) { |
|
|
|
if (err || !wcd) { |
|
|
|
this.storage.load(function(err, rawdata) { |
|
|
|
if (err || !rawdata) { |
|
|
|
return cb(err || 'wcd file not found.'); |
|
|
|
} |
|
|
|
return cb(null, wcd); |
|
|
|
self._processWcdAfterRead(rawdata, opts.requiredAccess, cb); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
@ -197,7 +249,7 @@ API.prototype._load = function(cb) { |
|
|
|
API.prototype._loadAndCheck = function(opts, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._load(function(err, wcd) { |
|
|
|
this._load(opts, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
if (!wcd.n || (wcd.n > 1 && wcd.publicKeyRing.length != wcd.n)) { |
|
|
@ -337,7 +389,9 @@ API.prototype.createWallet = function(walletName, copayerName, m, n, network, cb |
|
|
|
|
|
|
|
API.prototype.reCreateWallet = function(walletName, cb) { |
|
|
|
var self = this; |
|
|
|
this._loadAndCheck({}, function(err, wcd) { |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readonly', |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var walletPrivKey = new Bitcore.PrivateKey(); |
|
|
@ -393,7 +447,9 @@ API.prototype.joinWallet = function(secret, copayerName, cb) { |
|
|
|
API.prototype.getStatus = function(cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._load(function(err, wcd) { |
|
|
|
this._load({ |
|
|
|
requiredAccess: 'readonly' |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var url = '/v1/wallets/'; |
|
|
@ -418,7 +474,9 @@ API.prototype.sendTxProposal = function(opts, cb) { |
|
|
|
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({}, function(err, wcd) { |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readonly', |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
if (!wcd.rwPrivKey) |
|
|
@ -441,7 +499,9 @@ API.prototype.sendTxProposal = function(opts, cb) { |
|
|
|
API.prototype.createAddress = function(cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({}, function(err, wcd) { |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readwrite', |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var url = '/v1/addresses/'; |
|
|
@ -463,7 +523,9 @@ API.prototype.createAddress = function(cb) { |
|
|
|
API.prototype.getMainAddresses = function(opts, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({}, function(err, wcd) { |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readonly', |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var url = '/v1/addresses/'; |
|
|
@ -489,7 +551,9 @@ API.prototype.history = function(limit, cb) { |
|
|
|
API.prototype.getBalance = function(cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({}, function(err, wcd) { |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readonly', |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
var url = '/v1/balance/'; |
|
|
|
self._doGetRequest(url, wcd, cb); |
|
|
@ -508,7 +572,9 @@ API.prototype.export = function(opts, cb) { |
|
|
|
opts = opts || {}; |
|
|
|
var access = opts.access || 'full'; |
|
|
|
|
|
|
|
this._load(function(err, wcd) { |
|
|
|
this._load({ |
|
|
|
requiredAccess: access, |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
var v = []; |
|
|
|
|
|
|
@ -587,6 +653,7 @@ API.prototype.parseTxProposals = function(txData, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readonly', |
|
|
|
toComplete: txData.toComplete |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
@ -617,7 +684,9 @@ API.prototype.parseTxProposals = function(txData, cb) { |
|
|
|
API.prototype.getTxProposals = function(opts, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({}, function(err, wcd) { |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readonly' |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
var url = '/v1/txproposals/'; |
|
|
|
self._doGetRequest(url, wcd, function(err, txps) { |
|
|
@ -681,7 +750,9 @@ API.prototype.getSignatures = function(txp, cb) { |
|
|
|
$.checkArgument(txp.creatorId); |
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({}, function(err, wcd) { |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'full' |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
if (!Verifier.checkTxProposal(wcd, txp)) { |
|
|
@ -695,7 +766,9 @@ API.prototype.getSignatures = function(txp, cb) { |
|
|
|
API.prototype.getEncryptedWalletData = function(cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({}, function(err, wcd) { |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readonly' |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
var toComplete = JSON.stringify(_.pick(wcd, WALLET_AIRGAPPED_TOCOMPLETE)); |
|
|
|
return cb(null, _encryptMessage(toComplete, WalletUtils.privateKeyToAESKey(wcd.roPrivKey))); |
|
|
@ -709,7 +782,9 @@ API.prototype.signTxProposal = function(txp, cb) { |
|
|
|
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({}, function(err, wcd) { |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: txp.signatures ? 'readwrite' : 'full' |
|
|
|
}, function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
if (!Verifier.checkTxProposal(wcd, txp)) { |
|
|
@ -732,7 +807,9 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) { |
|
|
|
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({}, |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readwrite' |
|
|
|
}, |
|
|
|
function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
@ -747,7 +824,9 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) { |
|
|
|
API.prototype.broadcastTxProposal = function(txp, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
this._loadAndCheck({}, |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readwrite' |
|
|
|
}, |
|
|
|
function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
@ -760,7 +839,9 @@ API.prototype.broadcastTxProposal = function(txp, cb) { |
|
|
|
|
|
|
|
API.prototype.removeTxProposal = function(txp, cb) { |
|
|
|
var self = this; |
|
|
|
this._loadAndCheck({}, |
|
|
|
this._loadAndCheck({ |
|
|
|
requiredAccess: 'readwrite' |
|
|
|
}, |
|
|
|
function(err, wcd) { |
|
|
|
if (err) return cb(err); |
|
|
|
var url = '/v1/txproposals/' + txp.id; |
|
|
|