diff --git a/lib/expressapp.js b/lib/expressapp.js index 8240e8b..ae23f83 100644 --- a/lib/expressapp.js +++ b/lib/expressapp.js @@ -173,6 +173,12 @@ ExpressApp.prototype.start = function(opts, cb) { WalletService.getInstanceWithAuth(auth, function(err, server) { if (err) return returnError(err, res, req); + if (opts.onlySupportStaff && !server.copayerIsSupportStaff) { + return returnError(new WalletService.ClientError({ + code: 'NOT_AUTHORIZED' + }), res, req); + } + // For logging req.walletId = server.walletId; req.copayerId = server.copayerId; @@ -301,6 +307,29 @@ ExpressApp.prototype.start = function(opts, cb) { }); }); + router.get('/v1/wallets/:identifier/', function(req, res) { + getServerWithAuth(req, res, { + onlySupportStaff: true + }, function(server) { + var opts = { + identifier: req.query.identifier, + }; + server.getWalletFromIdentifier(opts, function(err, wallet) { + if (err) return returnError(err, res, req); + if (!wallet) return res.end(); + + server.walletId = wallet.id; + var opts = {}; + if (req.query.includeExtendedInfo == '1') opts.includeExtendedInfo = true; + if (req.query.twoStep == '1') opts.twoStep = true; + server.getStatus(opts, function(err, status) { + if (err) return returnError(err, res, req); + res.json(status); + }); + }); + }); + }); + router.get('/v1/preferences/', function(req, res) { getServerWithAuth(req, res, function(server) { server.getPreferences({}, function(err, preferences) { diff --git a/lib/server.js b/lib/server.js index 470d4b0..9b8923e 100644 --- a/lib/server.js +++ b/lib/server.js @@ -224,6 +224,7 @@ WalletService.getInstanceWithAuth = function(opts, cb) { server.walletId = copayer.walletId; } else { server.walletId = opts.walletId || copayer.walletId; + server.copayerIsSupportStaff = true; } server.copayerId = opts.copayerId; @@ -395,6 +396,81 @@ WalletService.prototype.getWallet = function(opts, cb) { }); }; +/** + * Retrieves a wallet from storage. + * @param {Object} opts + * @param {string} opts.identifier - The identifier associated with the wallet (one of: walletId, address, txid). + * @returns {Object} wallet + */ +WalletService.prototype.getWalletFromIdentifier = function(opts, cb) { + var self = this; + + var walletId; + async.parallel([ + + function(next) { + self.storage.fetchWallet(identifier, function(err, wallet) { + if (wallet) walletId = wallet.id; + return next(err); + }); + }, + function(next) { + self.storage.fetchAddress(identifier, function(err, address) { + if (address) walletId = address.walletId; + return next(err); + }); + }, + function(next) { + self.storage.fetchTxByHash(identifier, function(err, tx) { + if (tx) walletId = tx.walletId; + return next(err); + }); + }, + ], function(err) { + if (err) return cb(err); + if (walletId) { + return self.storage.fetchWallet(walletId, cb); + } + + // Is identifier a txid form an incomming tx? + async.eachSeries(['livenet', 'testnet'], function(network, nextNetwork) { + var bc = self._getBlockchainExplorer('livenet'); + bc.getTransaction(identifier, function(err, tx) { + if (err || !tx) return cb(err); + + var outputs = _.first(self._normalizeTxHistory(tx)).outputs; + var toAddresses = _.pluck(outputs, 'address'); + async.detect(toAddresses, function(addressStr, nextAddress) { + self.storage.fetchAddress(addressStr, function(err, address) { + if (err || !address) return nextAddress(false); + walletId = address.walletId; + return nextAddress(true); + }); + }, function() { + if (walletId) { + return self.storage.fetchWallet(walletId, cb); + } + return cb(); + }); + }); + return nextNetwork(); + }, function(err) { + if (err) return cb(err); + if (walletId) { + return self.storage.fetchWallet(walletId, cb); + } + return cb(); + }); + }); + + + self.storage.fetchWallet(self.walletId, function(err, wallet) { + if (err) return cb(err); + if (!wallet) return cb(Errors.WALLET_NOT_FOUND); + return cb(null, wallet); + }); +}; + /** * Retrieves wallet status. * @param {Object} opts @@ -2571,7 +2647,7 @@ WalletService.prototype.getNotifications = function(opts, cb) { WalletService.prototype._normalizeTxHistory = function(txs) { var now = Math.floor(Date.now() / 1000); - return _.map(txs, function(tx) { + return _.map([].concat(txs), function(tx) { var inputs = _.map(tx.vin, function(item) { return { address: item.addr,