Merge branch 'master' of github.com:bitpay/copay into feature/better-buy-and-sell
This commit is contained in:
commit
aaf9008394
41 changed files with 931 additions and 1016 deletions
|
|
@ -1,24 +1,36 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services').factory('amazonService', function($http, $log, lodash, moment, storageService, configService, platformInfo) {
|
||||
angular.module('copayApp.services').factory('amazonService', function($http, $log, lodash, moment, storageService, configService, platformInfo, nextStepsService, homeIntegrationsService) {
|
||||
var root = {};
|
||||
var credentials = {};
|
||||
|
||||
var _setCredentials = function() {
|
||||
/*
|
||||
* Development: 'testnet'
|
||||
* Production: 'livenet'
|
||||
*/
|
||||
credentials.NETWORK = 'livenet';
|
||||
/*
|
||||
* Development: 'testnet'
|
||||
* Production: 'livenet'
|
||||
*/
|
||||
credentials.NETWORK = 'livenet';
|
||||
//credentials.NETWORK = 'testnet';
|
||||
|
||||
if (credentials.NETWORK == 'testnet') {
|
||||
credentials.BITPAY_API_URL = "https://test.bitpay.com";
|
||||
} else {
|
||||
credentials.BITPAY_API_URL = "https://bitpay.com";
|
||||
};
|
||||
if (credentials.NETWORK == 'testnet') {
|
||||
credentials.BITPAY_API_URL = "https://test.bitpay.com";
|
||||
} else {
|
||||
credentials.BITPAY_API_URL = "https://bitpay.com";
|
||||
};
|
||||
|
||||
var homeItem = {
|
||||
name: 'amazon',
|
||||
title: 'Amazon Gift Cards',
|
||||
icon: 'icon-amazon',
|
||||
sref: 'tabs.giftcards.amazon',
|
||||
};
|
||||
|
||||
var nextStepItem = {
|
||||
name: 'amazon',
|
||||
title: 'Buy a gift card',
|
||||
icon: 'icon-amazon',
|
||||
sref: 'tabs.giftcards.amazon',
|
||||
};
|
||||
|
||||
var _getBitPay = function(endpoint) {
|
||||
_setCredentials();
|
||||
return {
|
||||
method: 'GET',
|
||||
url: credentials.BITPAY_API_URL + endpoint,
|
||||
|
|
@ -29,7 +41,6 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
|
|||
};
|
||||
|
||||
var _postBitPay = function(endpoint, data) {
|
||||
_setCredentials();
|
||||
return {
|
||||
method: 'POST',
|
||||
url: credentials.BITPAY_API_URL + endpoint,
|
||||
|
|
@ -41,7 +52,6 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
|
|||
};
|
||||
|
||||
root.getNetwork = function() {
|
||||
_setCredentials();
|
||||
return credentials.NETWORK;
|
||||
};
|
||||
|
||||
|
|
@ -65,12 +75,12 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
|
|||
inv = JSON.stringify(inv);
|
||||
|
||||
storageService.setAmazonGiftCards(network, inv, function(err) {
|
||||
|
||||
homeIntegrationsService.register(homeItem);
|
||||
nextStepsService.unregister(nextStepItem.name);
|
||||
return cb(err);
|
||||
});
|
||||
});
|
||||
|
||||
// Show pending task from the UI
|
||||
storageService.setNextStep('AmazonGiftCards', 'true', function(err) {});
|
||||
};
|
||||
|
||||
root.getPendingGiftCards = function(cb) {
|
||||
|
|
@ -144,6 +154,16 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
|
|||
});
|
||||
};
|
||||
|
||||
return root;
|
||||
var register = function() {
|
||||
storageService.getAmazonGiftCards(root.getNetwork(), function(err, giftCards) {
|
||||
if (giftCards) {
|
||||
homeIntegrationsService.register(homeItem);
|
||||
} else {
|
||||
nextStepsService.register(nextStepItem);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
register();
|
||||
return root;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('bitpayCardService', function($log, $rootScope, lodash, storageService, bitauthService, platformInfo, moment, appIdentityService, bitpayService) {
|
||||
angular.module('copayApp.services').factory('bitpayCardService', function($log, $rootScope, lodash, storageService, bitauthService, platformInfo, moment, appIdentityService, bitpayService, nextStepsService) {
|
||||
var root = {};
|
||||
|
||||
var _setError = function(msg, e) {
|
||||
|
|
@ -10,7 +10,7 @@ angular.module('copayApp.services').factory('bitpayCardService', function($log,
|
|||
};
|
||||
|
||||
var _processTransactions = function(invoices, history) {
|
||||
invoices = invoices || [];
|
||||
invoices = invoices || [];
|
||||
for (var i = 0; i < invoices.length; i++) {
|
||||
var matched = false;
|
||||
for (var j = 0; j < history.length; j++) {
|
||||
|
|
@ -22,8 +22,8 @@ angular.module('copayApp.services').factory('bitpayCardService', function($log,
|
|||
if (!matched && isInvoiceLessThanOneDayOld) {
|
||||
var isInvoiceUnderpaid = invoices[i].exceptionStatus === 'paidPartial';
|
||||
|
||||
if(['paid', 'confirmed', 'complete'].indexOf(invoices[i].status) >= 0
|
||||
|| (invoices[i].status === 'invalid' || isInvoiceUnderpaid)) {
|
||||
if (['paid', 'confirmed', 'complete'].indexOf(invoices[i].status) >= 0 ||
|
||||
(invoices[i].status === 'invalid' || isInvoiceUnderpaid)) {
|
||||
|
||||
history.unshift({
|
||||
timestamp: new Date(invoices[i].invoiceTime),
|
||||
|
|
@ -39,7 +39,7 @@ angular.module('copayApp.services').factory('bitpayCardService', function($log,
|
|||
return history;
|
||||
};
|
||||
|
||||
root.fetchBitpayDebitCards = function(apiContext, cb) {
|
||||
root.sync = function(apiContext, cb) {
|
||||
var json = {
|
||||
method: 'getDebitCards'
|
||||
};
|
||||
|
|
@ -47,65 +47,109 @@ angular.module('copayApp.services').factory('bitpayCardService', function($log,
|
|||
bitpayService.post('/api/v2/' + apiContext.token, json, function(data) {
|
||||
if (data && data.data.error) return cb(data.data.error);
|
||||
$log.info('BitPay Get Debit Cards: SUCCESS');
|
||||
return cb(data.data.error, {token: apiContext.token, cards: data.data.data, email: apiContext.pairData.email});
|
||||
|
||||
var cards = [];
|
||||
|
||||
lodash.each(data.data.data, function(x) {
|
||||
var n = {};
|
||||
|
||||
if (!x.eid || !x.id || !x.lastFourDigits || !x.token) {
|
||||
$log.warn('BAD data from Bitpay card' + JSON.stringify(x));
|
||||
return;
|
||||
}
|
||||
|
||||
n.eid = x.eid;
|
||||
n.id = x.id;
|
||||
n.lastFourDigits = x.lastFourDigits;
|
||||
n.token = x.token;
|
||||
cards.push(n);
|
||||
});
|
||||
|
||||
storageService.setBitpayDebitCards(bitpayService.getEnvironment().network, apiContext.pairData.email, cards, function(err) {
|
||||
register();
|
||||
|
||||
return cb(err, cards);
|
||||
});
|
||||
}, function(data) {
|
||||
return cb(_setError('BitPay Card Error: Get Debit Cards', data));
|
||||
});
|
||||
};
|
||||
|
||||
root.getHistory = function(cardId, params, cb) {
|
||||
// opts: range
|
||||
root.getHistory = function(cardId, opts, cb) {
|
||||
var invoices, transactions;
|
||||
params = params || {};
|
||||
opts = opts || {};
|
||||
|
||||
var json = {
|
||||
method: 'getInvoiceHistory',
|
||||
params: JSON.stringify(params)
|
||||
params: JSON.stringify(opts)
|
||||
};
|
||||
|
||||
appIdentityService.getIdentity(bitpayService.getEnvironment().network, function(err, appIdentity) {
|
||||
if (err) return cb(err);
|
||||
root.getBitpayDebitCards(function(err, data) {
|
||||
|
||||
root.getCards(function(err, data) {
|
||||
if (err) return cb(err);
|
||||
var card = lodash.find(data, {id : cardId});
|
||||
if (!card) return cb(_setError('Card not found'));
|
||||
var card = lodash.find(data, {
|
||||
id: cardId
|
||||
});
|
||||
|
||||
if (!card)
|
||||
return cb(_setError('Card not found'));
|
||||
|
||||
// Get invoices
|
||||
bitpayService.post('/api/v2/' + card.token, json, function(data) {
|
||||
$log.info('BitPay Get Invoices: SUCCESS');
|
||||
invoices = data.data.data || [];
|
||||
if (lodash.isEmpty(invoices)) $log.info('No invoices');
|
||||
|
||||
if (lodash.isEmpty(invoices))
|
||||
$log.info('No invoices');
|
||||
|
||||
json = {
|
||||
method: 'getTransactionHistory',
|
||||
params: JSON.stringify(params)
|
||||
params: JSON.stringify(opts)
|
||||
};
|
||||
// Get transactions list
|
||||
bitpayService.post('/api/v2/' + card.token, json, function(data) {
|
||||
$log.info('BitPay Get Transactions: SUCCESS');
|
||||
transactions = data.data.data || {};
|
||||
transactions['txs'] = _processTransactions(invoices, transactions.transactionList);
|
||||
|
||||
root.setLastKnownBalance(cardId, transactions.currentCardBalance, function() {});
|
||||
|
||||
return cb(data.data.error, transactions);
|
||||
}, function(data) {
|
||||
return cb(_setError('BitPay Card Error: Get Transactions', data));
|
||||
});
|
||||
}, function(data) {
|
||||
return cb(_setError('BitPay Card Error: Get Invoices', data));
|
||||
return cb(_setError('BitPay Card Error: Get Invoices', data));
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
root.topUp = function(cardId, params, cb) {
|
||||
params = params || {};
|
||||
root.topUp = function(cardId, opts, cb) {
|
||||
opts = opts || {};
|
||||
var json = {
|
||||
method: 'generateTopUpInvoice',
|
||||
params: JSON.stringify(params)
|
||||
params: JSON.stringify(opts)
|
||||
};
|
||||
appIdentityService.getIdentity(bitpayService.getEnvironment().network, function(err, appIdentity) {
|
||||
if (err) return cb(err);
|
||||
root.getBitpayDebitCards(function(err, data) {
|
||||
|
||||
root.getCards(function(err, data) {
|
||||
if (err) return cb(err);
|
||||
var card = lodash.find(data, {id : cardId});
|
||||
if (!card) return cb(_setError('Card not found'));
|
||||
|
||||
var card = lodash.find(data, {
|
||||
id: cardId
|
||||
});
|
||||
|
||||
if (!card)
|
||||
return cb(_setError('Card not found'));
|
||||
|
||||
bitpayService.post('/api/v2/' + card.token, json, function(data) {
|
||||
$log.info('BitPay TopUp: SUCCESS');
|
||||
if(data.data.error) {
|
||||
if (data.data.error) {
|
||||
return cb(data.data.error);
|
||||
} else {
|
||||
return cb(null, data.data.data.invoice);
|
||||
|
|
@ -126,75 +170,50 @@ angular.module('copayApp.services').factory('bitpayCardService', function($log,
|
|||
});
|
||||
};
|
||||
|
||||
root.getBitpayDebitCards = function(cb) {
|
||||
storageService.getBitpayDebitCards(bitpayService.getEnvironment().network, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
return cb(null, data);
|
||||
});
|
||||
// get all cards, for all accounts.
|
||||
root.getCards = function(cb) {
|
||||
storageService.getBitpayDebitCards(bitpayService.getEnvironment().network, cb);
|
||||
};
|
||||
|
||||
root.setBitpayDebitCards = function(data, cb) {
|
||||
data = JSON.stringify(data);
|
||||
storageService.setBitpayDebitCards(bitpayService.getEnvironment().network, data, function(err) {
|
||||
if (err) return cb(err);
|
||||
root.getLastKnownBalance = function(cardId, cb) {
|
||||
storageService.getBalanceCache(cardId, cb);
|
||||
};
|
||||
|
||||
root.addLastKnownBalance = function(card, cb) {
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
var showRange = 600; // 10min;
|
||||
|
||||
root.getLastKnownBalance(card.eid, function(err, data) {
|
||||
if (data) {
|
||||
data = JSON.parse(data);
|
||||
card.balance = data.balance;
|
||||
card.updatedOn = (data.updatedOn < now - showRange) ? data.updatedOn : null;
|
||||
}
|
||||
return cb();
|
||||
});
|
||||
};
|
||||
|
||||
root.getBitpayDebitCardsHistory = function(cardId, cb) {
|
||||
storageService.getBitpayDebitCardsHistory(bitpayService.getEnvironment().network, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
if (cardId) data = data[cardId];
|
||||
return cb(null, data);
|
||||
});
|
||||
root.setLastKnownBalance = function(cardId, balance, cb) {
|
||||
|
||||
storageService.setBalanceCache(cardId, {
|
||||
balance: balance,
|
||||
updatedOn: Math.floor(Date.now() / 1000),
|
||||
}, cb);
|
||||
};
|
||||
|
||||
root.setBitpayDebitCardsHistory = function(cardId, data, opts, cb) {
|
||||
storageService.getBitpayDebitCardsHistory(bitpayService.getEnvironment().network, function(err, oldData) {
|
||||
if (lodash.isString(oldData)) {
|
||||
oldData = JSON.parse(oldData);
|
||||
}
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
var inv = oldData || {};
|
||||
inv[cardId] = data;
|
||||
if (opts && opts.remove) {
|
||||
delete(inv[cardId]);
|
||||
}
|
||||
inv = JSON.stringify(inv);
|
||||
|
||||
storageService.setBitpayDebitCardsHistory(bitpayService.getEnvironment().network, inv, function(err) {
|
||||
return cb(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
root.remove = function(card, cb) {
|
||||
storageService.removeBitpayDebitCard(bitpayService.getEnvironment().network, card, function(err) {
|
||||
root.remove = function(cardId, cb) {
|
||||
storageService.removeBitpayDebitCard(bitpayService.getEnvironment().network, cardId, function(err) {
|
||||
if (err) {
|
||||
$log.error('Error removing BitPay debit card: ' + err);
|
||||
// Continue, try to remove/cleanup card history
|
||||
return cb(err);
|
||||
}
|
||||
storageService.removeBitpayDebitCardHistory(bitpayService.getEnvironment().network, card, function(err) {
|
||||
if (err) {
|
||||
$log.error('Error removing BitPay debit card transaction history: ' + err);
|
||||
return cb(err);
|
||||
}
|
||||
$log.info('Successfully removed BitPay debit card');
|
||||
return cb();
|
||||
});
|
||||
register();
|
||||
storageService.removeBalanceCache(cardId, cb);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
root.getRates = function(currency, cb) {
|
||||
bitpayService.get('/rates/' + currency, function(data) {
|
||||
$log.info('BitPay Get Rates: SUCCESS');
|
||||
|
|
@ -204,6 +223,39 @@ angular.module('copayApp.services').factory('bitpayCardService', function($log,
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
root.get = function(opts, cb) {
|
||||
root.getCards(function(err, cards) {
|
||||
if (err) return;
|
||||
|
||||
if (lodash.isEmpty(cards)) {
|
||||
return cb();
|
||||
}
|
||||
|
||||
if (opts.cardId) {
|
||||
cards = lodash.filter(cards, function(x) {
|
||||
return opts.cardId == x.eid;
|
||||
});
|
||||
}
|
||||
|
||||
// Async, no problem
|
||||
lodash.each(cards, function(x) {
|
||||
|
||||
root.addLastKnownBalance(x, function() {});
|
||||
|
||||
// async refresh
|
||||
if (!opts.noRefresh) {
|
||||
root.getHistory(x.id, {}, function(err, data) {
|
||||
if (err) return;
|
||||
root.addLastKnownBalance(x, function() {});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return cb(null, cards);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* CONSTANTS
|
||||
*/
|
||||
|
|
@ -1241,6 +1293,25 @@ angular.module('copayApp.services').factory('bitpayCardService', function($log,
|
|||
'bp002': 'default'
|
||||
};
|
||||
|
||||
var nextStepItem = {
|
||||
name: 'bitpaycard',
|
||||
title: 'Add Bitpay VISA Card',
|
||||
icon: 'icon-bitpay-card',
|
||||
sref: 'tabs.bitpayCardIntro',
|
||||
};
|
||||
|
||||
|
||||
var register = function() {
|
||||
root.getCards(function(err, cards) {
|
||||
if (lodash.isEmpty(cards)) {
|
||||
nextStepsService.register(nextStepItem);
|
||||
} else {
|
||||
nextStepsService.unregister(nextStepItem.name);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
register();
|
||||
return root;
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -136,13 +136,10 @@ angular.module('copayApp.services').factory('bitpayService', function($log, $htt
|
|||
};
|
||||
|
||||
var setBitpayAccount = function(accountData, cb) {
|
||||
var data = JSON.stringify(accountData);
|
||||
storageService.setBitpayAccount(root.getEnvironment().network, data, function(err) {
|
||||
if (err) return cb(err);
|
||||
return cb();
|
||||
});
|
||||
storageService.setBitpayAccount(root.getEnvironment().network, accountData, cb);
|
||||
};
|
||||
|
||||
|
||||
var _get = function(endpoint) {
|
||||
return {
|
||||
method: 'GET',
|
||||
|
|
|
|||
73
src/js/services/buyAndSellService.js
Normal file
73
src/js/services/buyAndSellService.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('buyAndSellService', function($log, nextStepsService, lodash, $ionicScrollDelegate, $timeout) {
|
||||
var root = {};
|
||||
var services = [];
|
||||
var linkedServices = [];
|
||||
|
||||
root.update = function() {
|
||||
|
||||
var newLinked = lodash.filter(services, function(x) {
|
||||
return x.linked;
|
||||
});
|
||||
|
||||
// This is to preserve linkedServices pointer
|
||||
while (linkedServices.length)
|
||||
linkedServices.pop();
|
||||
|
||||
while (newLinked.length)
|
||||
linkedServices.push(newLinked.pop());
|
||||
//
|
||||
|
||||
$log.debug('buyAndSell Service, updating nextSteps. linked/total: ' + linkedServices.length + '/' + services.length);
|
||||
|
||||
if (linkedServices.length == 0) {
|
||||
nextStepsService.register({
|
||||
title: 'Buy and Sell',
|
||||
name: 'buyandsell',
|
||||
icon: 'icon-buy-bitcoin',
|
||||
sref: 'tabs.buyandsell',
|
||||
});
|
||||
} else {
|
||||
nextStepsService.unregister({
|
||||
name: 'buyandsell',
|
||||
});
|
||||
};
|
||||
|
||||
$timeout(function() {
|
||||
$ionicScrollDelegate.resize();
|
||||
}, 10);
|
||||
};
|
||||
|
||||
var updateNextStepsDebunced = lodash.debounce(root.update, 1000);
|
||||
|
||||
root.register = function(serviceInfo) {
|
||||
services.push(serviceInfo);
|
||||
$log.info('Adding Buy and Sell service:' + serviceInfo.name + ' linked:' + serviceInfo.linked);
|
||||
updateNextStepsDebunced();
|
||||
};
|
||||
|
||||
|
||||
root.updateLink = function(name, linked) {
|
||||
var service = lodash.find(services, function(x) {
|
||||
return x.name == name;
|
||||
});
|
||||
$log.info('Updating Buy and Sell service:' + name + ' linked:' + linked);
|
||||
service.linked = linked
|
||||
|
||||
root.update();
|
||||
};
|
||||
|
||||
|
||||
root.get = function() {
|
||||
return services;
|
||||
};
|
||||
|
||||
|
||||
root.getLinked = function() {
|
||||
return linkedServices;
|
||||
};
|
||||
|
||||
|
||||
return root;
|
||||
});
|
||||
|
|
@ -44,7 +44,7 @@ angular.module('copayApp.services')
|
|||
body = gettextCatalog.getString('Insufficient funds');
|
||||
break;
|
||||
case 'CONNECTION_ERROR':
|
||||
body = gettextCatalog.getString('Network connection error');
|
||||
body = gettextCatalog.getString('Network error');
|
||||
break;
|
||||
case 'NOT_FOUND':
|
||||
body = gettextCatalog.getString('Wallet service not found');
|
||||
|
|
|
|||
|
|
@ -1,37 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('coinbaseService', function($http, $log, $window, $filter, platformInfo, lodash, storageService, configService, appConfigService, txFormatService) {
|
||||
angular.module('copayApp.services').factory('coinbaseService', function($http, $log, $window, $filter, platformInfo, lodash, storageService, configService, appConfigService, txFormatService, buyAndSellService, $rootScope) {
|
||||
var root = {};
|
||||
var credentials = {};
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isNW = platformInfo.isNW;
|
||||
var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova;
|
||||
|
||||
root.priceSensitivity = [
|
||||
{
|
||||
value: 0.5,
|
||||
name: '0.5%'
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
name: '1%'
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
name: '2%'
|
||||
},
|
||||
{
|
||||
value: 5,
|
||||
name: '5%'
|
||||
},
|
||||
{
|
||||
value: 10,
|
||||
name: '10%'
|
||||
}
|
||||
];
|
||||
root.priceSensitivity = [{
|
||||
value: 0.5,
|
||||
name: '0.5%'
|
||||
}, {
|
||||
value: 1,
|
||||
name: '1%'
|
||||
}, {
|
||||
value: 2,
|
||||
name: '2%'
|
||||
}, {
|
||||
value: 5,
|
||||
name: '5%'
|
||||
}, {
|
||||
value: 10,
|
||||
name: '10%'
|
||||
}];
|
||||
|
||||
root.selectedPriceSensitivity = root.priceSensitivity[1];
|
||||
|
||||
root.setCredentials = function() {
|
||||
var setCredentials = function() {
|
||||
|
||||
if (!$window.externalServices || !$window.externalServices.coinbase) {
|
||||
return;
|
||||
|
|
@ -46,19 +41,19 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
credentials.NETWORK = 'livenet';
|
||||
|
||||
// Coinbase permissions
|
||||
credentials.SCOPE = ''
|
||||
+ 'wallet:accounts:read,'
|
||||
+ 'wallet:addresses:read,'
|
||||
+ 'wallet:addresses:create,'
|
||||
+ 'wallet:user:read,'
|
||||
+ 'wallet:user:email,'
|
||||
+ 'wallet:buys:read,'
|
||||
+ 'wallet:buys:create,'
|
||||
+ 'wallet:sells:read,'
|
||||
+ 'wallet:sells:create,'
|
||||
+ 'wallet:transactions:read,'
|
||||
+ 'wallet:transactions:send,'
|
||||
+ 'wallet:payment-methods:read';
|
||||
credentials.SCOPE = '' +
|
||||
'wallet:accounts:read,' +
|
||||
'wallet:addresses:read,' +
|
||||
'wallet:addresses:create,' +
|
||||
'wallet:user:read,' +
|
||||
'wallet:user:email,' +
|
||||
'wallet:buys:read,' +
|
||||
'wallet:buys:create,' +
|
||||
'wallet:sells:read,' +
|
||||
'wallet:sells:create,' +
|
||||
'wallet:transactions:read,' +
|
||||
'wallet:transactions:send,' +
|
||||
'wallet:payment-methods:read';
|
||||
|
||||
// NW has a bug with Window Object
|
||||
if (isCordova) {
|
||||
|
|
@ -72,8 +67,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
credentials.API = coinbase.sandbox.api;
|
||||
credentials.CLIENT_ID = coinbase.sandbox.client_id;
|
||||
credentials.CLIENT_SECRET = coinbase.sandbox.client_secret;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
credentials.HOST = coinbase.production.host;
|
||||
credentials.API = coinbase.production.api;
|
||||
credentials.CLIENT_ID = coinbase.production.client_id;
|
||||
|
|
@ -85,6 +79,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
if (data && data.access_token && data.refresh_token) {
|
||||
storageService.setCoinbaseToken(credentials.NETWORK, data.access_token, function() {
|
||||
storageService.setCoinbaseRefreshToken(credentials.NETWORK, data.refresh_token, function() {
|
||||
buyAndSellService.updateLink('coinbase', true);
|
||||
return cb(null, data.access_token);
|
||||
});
|
||||
});
|
||||
|
|
@ -107,8 +102,8 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
root.getAvailableCurrency = function() {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
// ONLY "USD"
|
||||
switch(config.alternativeIsoCode) {
|
||||
default : return 'USD'
|
||||
switch (config.alternativeIsoCode) {
|
||||
default: return 'USD'
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -141,14 +136,14 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
}
|
||||
|
||||
root.getOauthCodeUrl = function() {
|
||||
return credentials.HOST
|
||||
+ '/oauth/authorize?response_type=code&client_id='
|
||||
+ credentials.CLIENT_ID
|
||||
+ '&redirect_uri='
|
||||
+ credentials.REDIRECT_URI
|
||||
+ '&state=SECURE_RANDOM&scope='
|
||||
+ credentials.SCOPE
|
||||
+ '&meta[send_limit_amount]=1000&meta[send_limit_currency]=USD&meta[send_limit_period]=day';
|
||||
return credentials.HOST +
|
||||
'/oauth/authorize?response_type=code&client_id=' +
|
||||
credentials.CLIENT_ID +
|
||||
'&redirect_uri=' +
|
||||
credentials.REDIRECT_URI +
|
||||
'&state=SECURE_RANDOM&scope=' +
|
||||
credentials.SCOPE +
|
||||
'&meta[send_limit_amount]=1000&meta[send_limit_currency]=USD&meta[send_limit_period]=day';
|
||||
};
|
||||
|
||||
root.getToken = function(code, cb) {
|
||||
|
|
@ -160,9 +155,9 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
'Accept': 'application/json'
|
||||
},
|
||||
data: {
|
||||
grant_type : 'authorization_code',
|
||||
grant_type: 'authorization_code',
|
||||
code: code,
|
||||
client_id : credentials.CLIENT_ID,
|
||||
client_id: credentials.CLIENT_ID,
|
||||
client_secret: credentials.CLIENT_SECRET,
|
||||
redirect_uri: credentials.REDIRECT_URI
|
||||
}
|
||||
|
|
@ -171,7 +166,6 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
$http(req).then(function(data) {
|
||||
$log.info('Coinbase Authorization Access Token: SUCCESS');
|
||||
// Show pending task from the UI
|
||||
storageService.setNextStep('BuyAndSell', 'true', function(err) {});
|
||||
_afterTokenReceived(data.data, cb);
|
||||
}, function(data) {
|
||||
$log.error('Coinbase Authorization Access Token: ERROR ' + data.statusText);
|
||||
|
|
@ -188,8 +182,8 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
'Accept': 'application/json'
|
||||
},
|
||||
data: {
|
||||
grant_type : 'refresh_token',
|
||||
client_id : credentials.CLIENT_ID,
|
||||
grant_type: 'refresh_token',
|
||||
client_id: credentials.CLIENT_ID,
|
||||
client_secret: credentials.CLIENT_SECRET,
|
||||
redirect_uri: credentials.REDIRECT_URI,
|
||||
refresh_token: refreshToken
|
||||
|
|
@ -219,6 +213,19 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
});
|
||||
};
|
||||
|
||||
root.isActive = function(cb) {
|
||||
|
||||
if (isWindowsPhoneApp)
|
||||
return cb();
|
||||
|
||||
if (lodash.isEmpty(credentials.CLIENT_ID))
|
||||
return cb();
|
||||
|
||||
storageService.getCoinbaseToken(credentials.NETWORK, function(err, accessToken) {
|
||||
return cb(err, !!accessToken);
|
||||
});
|
||||
}
|
||||
|
||||
root.init = lodash.throttle(function(cb) {
|
||||
if (lodash.isEmpty(credentials.CLIENT_ID)) {
|
||||
return cb('Coinbase is Disabled');
|
||||
|
|
@ -238,7 +245,10 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
if (err) return cb(err);
|
||||
_getMainAccountId(newToken, function(err, accountId) {
|
||||
if (err) return cb(err);
|
||||
return cb(null, {accessToken: newToken, accountId: accountId});
|
||||
return cb(null, {
|
||||
accessToken: newToken,
|
||||
accountId: accountId
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -246,7 +256,10 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
return cb(err);
|
||||
}
|
||||
} else {
|
||||
return cb(null, {accessToken: accessToken, accountId: accountId});
|
||||
return cb(null, {
|
||||
accessToken: accessToken,
|
||||
accountId: accountId
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -410,7 +423,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
var data = {
|
||||
amount: data.amount,
|
||||
currency: data.currency,
|
||||
payment_method: data.payment_method || null,
|
||||
payment_method: data.payment_method || null,
|
||||
commit: data.commit || false,
|
||||
quote: data.quote || false
|
||||
};
|
||||
|
|
@ -598,9 +611,10 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
};
|
||||
|
||||
root.updatePendingTransactions = lodash.throttle(function() {
|
||||
$log.debug('Updating pending transactions...');
|
||||
root.setCredentials();
|
||||
var pendingTransactions = { data: {} };
|
||||
$log.debug('Updating coinbase pending transactions...');
|
||||
var pendingTransactions = {
|
||||
data: {}
|
||||
};
|
||||
root.getPendingTransactions(pendingTransactions);
|
||||
}, 20000);
|
||||
|
||||
|
|
@ -707,6 +721,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
|
||||
root.logout = function(cb) {
|
||||
storageService.removeCoinbaseToken(credentials.NETWORK, function() {
|
||||
buyAndSellService.updateLink('coinbase', false);
|
||||
storageService.removeCoinbaseRefreshToken(credentials.NETWORK, function() {
|
||||
storageService.removeCoinbaseTxs(credentials.NETWORK, function() {
|
||||
return cb();
|
||||
|
|
@ -715,6 +730,33 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
});
|
||||
};
|
||||
|
||||
return root;
|
||||
var register = function() {
|
||||
|
||||
root.isActive(function(err, isActive){
|
||||
if (err) return;
|
||||
|
||||
buyAndSellService.register({
|
||||
name: 'coinbase',
|
||||
logo: 'img/coinbase-logo.png',
|
||||
location: '33 Countries',
|
||||
sref: 'tabs.buyandsell.coinbase',
|
||||
configSref: 'tabs.preferences.coinbase',
|
||||
linked: isActive,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
setCredentials();
|
||||
register();
|
||||
|
||||
$rootScope.$on('bwsEvent', function(e, walletId, type, n) {
|
||||
if (type == 'NewBlock' && n && n.data && n.data.network == 'livenet') {
|
||||
root.isActive(function(err,isActive){
|
||||
// Update Coinbase
|
||||
if (isActive)
|
||||
root.updatePendingTransactions();
|
||||
});
|
||||
}
|
||||
});
|
||||
return root;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -43,26 +43,14 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
},
|
||||
|
||||
// External services
|
||||
glidera: {
|
||||
enabled: true,
|
||||
testnet: false
|
||||
},
|
||||
|
||||
coinbaseV2: true,
|
||||
|
||||
bitpayCard: {
|
||||
enabled: true
|
||||
},
|
||||
|
||||
amazon: {
|
||||
enabled: true
|
||||
},
|
||||
|
||||
|
||||
recentTransactions: {
|
||||
enabled: true,
|
||||
},
|
||||
|
||||
hideNextSteps: {
|
||||
enabled: false,
|
||||
},
|
||||
|
||||
rates: {
|
||||
url: 'https://insight.bitpay.com:443/api/rates',
|
||||
},
|
||||
|
|
@ -191,18 +179,11 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
if (!configCache.wallet.settings.unitCode) {
|
||||
configCache.wallet.settings.unitCode = defaultConfig.wallet.settings.unitCode;
|
||||
}
|
||||
if (!configCache.glidera) {
|
||||
configCache.glidera = defaultConfig.glidera;
|
||||
}
|
||||
if (!configCache.coinbaseV2) {
|
||||
configCache.coinbaseV2 = defaultConfig.coinbaseV2;
|
||||
}
|
||||
if (!configCache.amazon) {
|
||||
configCache.amazon = defaultConfig.amazon;
|
||||
}
|
||||
if (!configCache.bitpayCard) {
|
||||
configCache.bitpayCard = defaultConfig.bitpayCard;
|
||||
|
||||
if (!configCache.hideNextSteps) {
|
||||
configCache.hideNextSteps = defaultConfig.hideNextSteps;
|
||||
}
|
||||
|
||||
if (!configCache.recentTransactions) {
|
||||
configCache.recentTransactions = defaultConfig.recentTransactions;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ angular.module('copayApp.services')
|
|||
if (lodash.isObject(v))
|
||||
v = JSON.stringify(v);
|
||||
|
||||
if (!lodash.isString(v)) {
|
||||
if (v && !lodash.isString(v)) {
|
||||
v = v.toString();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('glideraService', function($http, $log, $window, platformInfo, storageService) {
|
||||
angular.module('copayApp.services').factory('glideraService', function($http, $log, $window, platformInfo, storageService, buyAndSellService) {
|
||||
var root = {};
|
||||
var credentials = {};
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova;
|
||||
|
||||
var _setCredentials = function() {
|
||||
var setCredentials = function() {
|
||||
if (!$window.externalServices || !$window.externalServices.glidera) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -17,6 +18,7 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l
|
|||
* Production: 'livenet'
|
||||
*/
|
||||
credentials.NETWORK = 'livenet';
|
||||
//credentials.NETWORK = 'testnet';
|
||||
|
||||
if (credentials.NETWORK == 'testnet') {
|
||||
credentials.HOST = glidera.sandbox.host;
|
||||
|
|
@ -44,7 +46,6 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l
|
|||
};
|
||||
|
||||
root.getEnvironment = function() {
|
||||
_setCredentials();
|
||||
return credentials.NETWORK;
|
||||
};
|
||||
|
||||
|
|
@ -57,19 +58,17 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l
|
|||
}
|
||||
|
||||
root.getOauthCodeUrl = function() {
|
||||
_setCredentials();
|
||||
return credentials.HOST + '/oauth2/auth?response_type=code&client_id=' + credentials.CLIENT_ID + '&redirect_uri=' + credentials.REDIRECT_URI;
|
||||
};
|
||||
|
||||
root.removeToken = function(cb) {
|
||||
_setCredentials();
|
||||
storageService.removeGlideraToken(credentials.NETWORK, function() {
|
||||
buyAndSellService.updateLink('glidera', false);
|
||||
return cb();
|
||||
});
|
||||
};
|
||||
|
||||
root.getToken = function(code, cb) {
|
||||
_setCredentials();
|
||||
var req = {
|
||||
method: 'POST',
|
||||
url: credentials.HOST + '/api/v1/oauth/token',
|
||||
|
|
@ -98,7 +97,6 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l
|
|||
};
|
||||
|
||||
var _get = function(endpoint, token) {
|
||||
_setCredentials();
|
||||
return {
|
||||
method: 'GET',
|
||||
url: credentials.HOST + '/api/v1' + endpoint,
|
||||
|
|
@ -216,7 +214,6 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l
|
|||
};
|
||||
|
||||
var _post = function(endpoint, token, twoFaCode, data) {
|
||||
_setCredentials();
|
||||
return {
|
||||
method: 'POST',
|
||||
url: credentials.HOST + '/api/v1' + endpoint,
|
||||
|
|
@ -293,7 +290,6 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l
|
|||
};
|
||||
|
||||
root.init = function(accessToken, cb) {
|
||||
_setCredentials();
|
||||
$log.debug('Init Glidera...');
|
||||
|
||||
var glidera = {
|
||||
|
|
@ -312,6 +308,8 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l
|
|||
getToken(function(err, accessToken) {
|
||||
if (err || !accessToken) return cb();
|
||||
else {
|
||||
buyAndSellService.updateLink('glidera', true);
|
||||
|
||||
root.getAccessTokenPermissions(accessToken, function(err, p) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
|
|
@ -325,6 +323,25 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l
|
|||
});
|
||||
};
|
||||
|
||||
return root;
|
||||
|
||||
var register = function() {
|
||||
if (isWindowsPhoneApp) return;
|
||||
|
||||
storageService.getGlideraToken(credentials.NETWORK, function(err, token) {
|
||||
if (err) return cb(err);
|
||||
|
||||
buyAndSellService.register({
|
||||
name: 'glidera',
|
||||
logo: 'img/glidera-logo.png',
|
||||
location: 'US Only',
|
||||
sref: 'tabs.buyandsell.glidera',
|
||||
configSref: 'tabs.preferences.glidera',
|
||||
linked: !!token,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
setCredentials();
|
||||
register();
|
||||
return root;
|
||||
});
|
||||
|
|
|
|||
23
src/js/services/homeIntegrations.js
Normal file
23
src/js/services/homeIntegrations.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services').factory('', function(configService, $log) {
|
||||
var root = {};
|
||||
var services = [];
|
||||
|
||||
root.register = function(serviceInfo) {
|
||||
$log.info('Adding homeIntegration entry:' + serviceInfo.name);
|
||||
services.push(serviceInfo);
|
||||
};
|
||||
|
||||
root.unregister = function(serviceName) {
|
||||
services = lodash.filter(services, function(x) {
|
||||
return x.name != serviceName
|
||||
});
|
||||
};
|
||||
|
||||
root.get = function() {
|
||||
return services;
|
||||
};
|
||||
|
||||
return root;
|
||||
|
||||
});
|
||||
23
src/js/services/homeIntegrationsService.js
Normal file
23
src/js/services/homeIntegrationsService.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services').factory('homeIntegrationsService', function(configService, $log) {
|
||||
var root = {};
|
||||
var services = [];
|
||||
|
||||
root.register = function(serviceInfo) {
|
||||
$log.info('Adding home Integrations entry:' + serviceInfo.name);
|
||||
services.push(serviceInfo);
|
||||
};
|
||||
|
||||
root.unregister = function(serviceName) {
|
||||
services = lodash.filter(services, function(x) {
|
||||
return x.name != serviceName
|
||||
});
|
||||
};
|
||||
|
||||
root.get = function() {
|
||||
return services;
|
||||
};
|
||||
|
||||
return root;
|
||||
|
||||
});
|
||||
|
|
@ -43,16 +43,17 @@ angular.module('copayApp.services')
|
|||
};
|
||||
|
||||
root.set = function(k, v, cb) {
|
||||
|
||||
if (lodash.isObject(v)) {
|
||||
v = JSON.stringify(v);
|
||||
}
|
||||
if (v && !lodash.isString(v)) {
|
||||
v = v.toString();
|
||||
}
|
||||
|
||||
if (isChromeApp || isNW) {
|
||||
var obj = {};
|
||||
|
||||
if (lodash.isObject(v)) {
|
||||
v = JSON.stringify(v);
|
||||
}
|
||||
if (!lodash.isString(v)) {
|
||||
v = v.toString();
|
||||
}
|
||||
|
||||
obj[k] = v;
|
||||
|
||||
chrome.storage.local.set(obj, cb);
|
||||
|
|
@ -60,7 +61,6 @@ angular.module('copayApp.services')
|
|||
ls.setItem(k, v);
|
||||
return cb();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
root.remove = function(k, cb) {
|
||||
|
|
|
|||
40
src/js/services/nextStepsService.js
Normal file
40
src/js/services/nextStepsService.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services').factory('nextStepsService', function(configService, $log, lodash) {
|
||||
var root = {};
|
||||
var services = [];
|
||||
|
||||
root.register = function(serviceInfo) {
|
||||
$log.info('Adding NextSteps entry:' + serviceInfo.name);
|
||||
|
||||
if (!lodash.find(services, function(x) {
|
||||
return x.name == serviceInfo.name;
|
||||
})) {
|
||||
services.push(serviceInfo);
|
||||
}
|
||||
};
|
||||
|
||||
root.unregister = function(serviceName) {
|
||||
|
||||
var newS = lodash.filter(services, function(x) {
|
||||
return x.name != serviceName;
|
||||
});
|
||||
|
||||
// Found?
|
||||
if (newS.length == services.length) return;
|
||||
|
||||
$log.info('Removing NextSteps entry:' + serviceName);
|
||||
// This is to preserve services pointer
|
||||
while (services.length)
|
||||
services.pop();
|
||||
|
||||
while (newS.length)
|
||||
services.push(newS.pop());
|
||||
};
|
||||
|
||||
root.get = function() {
|
||||
return services;
|
||||
};
|
||||
|
||||
return root;
|
||||
|
||||
});
|
||||
|
|
@ -84,6 +84,7 @@ angular.module('copayApp.services').factory('openURLService', function($rootScop
|
|||
$log.debug('Registering Browser handlers base:' + base);
|
||||
navigator.registerProtocolHandler('bitcoin', url, 'Copay Bitcoin Handler');
|
||||
navigator.registerProtocolHandler('web+copay', url, 'Copay Wallet Handler');
|
||||
navigator.registerProtocolHandler('web+bitpay', url, 'Bitpay Wallet Handler');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -747,6 +747,31 @@ angular.module('copayApp.services')
|
|||
storageService.storeProfile(root.profile, cb);
|
||||
};
|
||||
|
||||
root.getLastKnownBalance = function(wid, cb) {
|
||||
storageService.getBalanceCache(wid, cb);
|
||||
};
|
||||
|
||||
root.addLastKnownBalance = function(wallet, cb) {
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
var showRange = 600; // 10min;
|
||||
|
||||
root.getLastKnownBalance(wallet.id, function(err, data) {
|
||||
if (data) {
|
||||
data = JSON.parse(data);
|
||||
wallet.cachedBalance = data.balance;
|
||||
wallet.cachedBalanceUpdatedOn = (data.updatedOn < now - showRange) ? data.updatedOn : null;
|
||||
}
|
||||
return cb();
|
||||
});
|
||||
};
|
||||
|
||||
root.setLastKnownBalance = function(wid, balance, cb) {
|
||||
storageService.setBalanceCache(wid, {
|
||||
balance: balance,
|
||||
updatedOn: Math.floor(Date.now() / 1000),
|
||||
}, cb);
|
||||
};
|
||||
|
||||
root.getWallets = function(opts) {
|
||||
|
||||
if (opts && !lodash.isObject(opts))
|
||||
|
|
@ -780,6 +805,12 @@ angular.module('copayApp.services')
|
|||
});
|
||||
} else {}
|
||||
|
||||
// Add cached balance async
|
||||
lodash.each(ret, function(x) {
|
||||
root.addLastKnownBalance(x, function() {});
|
||||
});
|
||||
|
||||
|
||||
return lodash.sortBy(ret, [
|
||||
|
||||
function(x) {
|
||||
|
|
@ -796,7 +827,7 @@ angular.module('copayApp.services')
|
|||
root.getNotifications = function(opts, cb) {
|
||||
opts = opts || {};
|
||||
|
||||
var TIME_STAMP = 60 * 60 * 6;
|
||||
var TIME_STAMP = 60 * 60 * 6;
|
||||
var MAX = 30;
|
||||
|
||||
var typeFilter = {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ angular.module('copayApp.services')
|
|||
}, cb);
|
||||
};
|
||||
|
||||
// This is only used in Copay, we used to encrypt profile
|
||||
// using device's UUID.
|
||||
|
||||
var decryptOnMobile = function(text, cb) {
|
||||
var json;
|
||||
try {
|
||||
|
|
@ -74,312 +77,8 @@ angular.module('copayApp.services')
|
|||
});
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// UPGRADING STORAGE
|
||||
//
|
||||
// Upgraders are executed in numerical order per the '##_' object key prefix. Each upgrader will run.
|
||||
// Each upgrader should detect storage configuraton and fail-safe; no upgrader should damage the ability
|
||||
// of another to function properly (in order). Each upgrader should upgrade storage incrementally; storage
|
||||
// upgrade is not complete until all upgraders have run.
|
||||
//
|
||||
// 1. Write a function to upgrade the desired storage key(s). The function should have the protocol:
|
||||
//
|
||||
// _upgrade_x(key, network, cb), where:
|
||||
//
|
||||
// `x` is the name of the storage key
|
||||
// `key` is the name of the storage key being upgraded
|
||||
// `network` is one of 'livenet', 'testnet'
|
||||
//
|
||||
// 2. Add the storage key to `_upgraders` object using the name of the key as the `_upgrader` object key
|
||||
// with the value being the name of the upgrade function (e.g., _upgrade_x). In order to avoid conflicts
|
||||
// when a storage key is involved in multiple upgraders as well as predicte the order in which upgrades
|
||||
// occur the `_upgrader` object key should be prefixed with '##_' (e.g., '01_') to create a unique and
|
||||
// sortable name. This format is interpreted by the _upgrade() function.
|
||||
//
|
||||
// 3. Any dependency functions called by upgraders should be copied/factored out and remain unchanged as
|
||||
// long as the upgrader remains in effect. By convention the dependency function is prefixed by '##_' to
|
||||
// match the upgrader key.
|
||||
//
|
||||
var _upgraders = {
|
||||
'00_bitpayDebitCards' : _upgrade_bitpayDebitCards, // 2016-11: Upgrade bitpayDebitCards-x to bitpayAccounts-x
|
||||
'01_bitpayCardCredentials' : _upgrade_bitpayCardCredentials, // 2016-11: Upgrade bitpayCardCredentials-x to appIdentity-x
|
||||
'02_bitpayAccounts' : _upgrade_bitpayAccounts, // 2016-12: Upgrade bitpayAccounts-x to bitpayAccounts-v2-x
|
||||
'03_bitpayAccounts-v2' : _validate_bitpayAccounts_v2 // 2017-01: Validate keys on bitpayAccounts-v2-x, remove if not valid
|
||||
};
|
||||
|
||||
function _upgrade_bitpayDebitCards(key, network, cb) {
|
||||
key += '-' + network;
|
||||
storage.get(key, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
if (data != null) {
|
||||
// Needs upgrade
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
_00_setBitpayDebitCards(network, data, function(err) {
|
||||
if (err) return cb(err);
|
||||
storage.remove(key, function() {
|
||||
cb(null, 'replaced with \'bitpayAccounts\'');
|
||||
});
|
||||
});
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function _upgrade_bitpayCardCredentials(key, network, cb) {
|
||||
key += '-' + network;
|
||||
storage.get(key, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
if (data != null) {
|
||||
// Needs upgrade
|
||||
_01_setAppIdentity(network, data, function(err) {
|
||||
if (err) return cb(err);
|
||||
storage.remove(key, function() {
|
||||
cb(null, 'replaced with \'appIdentity\'');
|
||||
});
|
||||
});
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function _upgrade_bitpayAccounts(key, network, cb) {
|
||||
key += '-' + network;
|
||||
storage.get(key, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
var upgraded = '';
|
||||
_asyncEach(Object.keys(data), function(key, callback) {
|
||||
// Keys are account emails
|
||||
if (!data[key]['bitpayApi-' + network]) {
|
||||
// Needs upgrade
|
||||
upgraded += ' ' + key;
|
||||
var acctData = {
|
||||
acct: data[key],
|
||||
token: data[key]['bitpayDebitCards-' + network].token,
|
||||
email: key
|
||||
};
|
||||
_02_setBitpayAccount(network, acctData, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
_02_setBitpayDebitCards(network, data[key]['bitpayDebitCards-' + network], function(err) {
|
||||
if (err) return cb(err);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
callback();
|
||||
}, function() {
|
||||
// done
|
||||
// Remove obsolete key.
|
||||
storage.remove('bitpayAccounts-' + network, function() {
|
||||
if (upgraded.length > 0) {
|
||||
cb(null, 'upgraded to \'bitpayAccounts-v2-' + network + '\':' + upgraded);
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function _validate_bitpayAccounts_v2(key, network, cb) {
|
||||
key += '-' + network;
|
||||
storage.get(key, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
var verified = '';
|
||||
var toRemove = [];
|
||||
_asyncEach(Object.keys(data), function(key, callback) {
|
||||
// Verify account API data
|
||||
if (!data[key]['bitpayApi-' + network] ||
|
||||
!data[key]['bitpayApi-' + network].token) {
|
||||
// Invalid entry - one or more keys are missing
|
||||
toRemove.push(key);
|
||||
return callback();
|
||||
}
|
||||
// Verify debit cards
|
||||
if (Array.isArray(data[key]['bitpayDebitCards-' + network])) {
|
||||
for (var i = 0; i < data[key]['bitpayDebitCards-' + network].length; i++) {
|
||||
if (!data[key]['bitpayDebitCards-' + network][i].token ||
|
||||
!data[key]['bitpayDebitCards-' + network][i].eid ||
|
||||
!data[key]['bitpayDebitCards-' + network][i].id ||
|
||||
!data[key]['bitpayDebitCards-' + network][i].lastFourDigits) {
|
||||
// Invalid entry - one or more keys are missing
|
||||
toRemove.push(key);
|
||||
return callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
verified += ' ' + key;
|
||||
return callback();
|
||||
}, function() {
|
||||
// done, remove invalid account entrys
|
||||
if (toRemove.length > 0) {
|
||||
var removed = '';
|
||||
for (var i = 0; i < toRemove.length; i++) {
|
||||
removed += ' ' + toRemove[i];
|
||||
delete data[toRemove[i]];
|
||||
}
|
||||
storage.set('bitpayAccounts-v2-' + network, JSON.stringify(data), function(err) {
|
||||
if (err) return cb(err);
|
||||
// Ensure next step for cards is visible
|
||||
storage.get('bitpayAccounts-v2-' + network, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isEmpty(data)) {
|
||||
root.removeNextStep('BitpayCard', function(err) {});
|
||||
}
|
||||
});
|
||||
cb(null, 'removed invalid account records, please re-pair cards for these accounts:' + removed + '; ' +
|
||||
'the following accounts validated OK: ' + (verified.length > 0 ? verified : 'none'));
|
||||
});
|
||||
} else {
|
||||
cb(null, (verified.length > 0 ? 'accounts OK: ' + verified : 'no accounts found'));
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// UPGRADER DEPENDENCIES
|
||||
// These functions remain as long as the upgrader remains in effect.
|
||||
//
|
||||
var _00_setBitpayDebitCards = function(network, data, cb) {
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
if (lodash.isEmpty(data) || !data.email) return cb('No card(s) to set');
|
||||
storage.get('bitpayAccounts-' + network, function(err, bitpayAccounts) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(bitpayAccounts)) {
|
||||
bitpayAccounts = JSON.parse(bitpayAccounts);
|
||||
}
|
||||
bitpayAccounts = bitpayAccounts || {};
|
||||
bitpayAccounts[data.email] = bitpayAccounts[data.email] || {};
|
||||
bitpayAccounts[data.email]['bitpayDebitCards-' + network] = data;
|
||||
storage.set('bitpayAccounts-' + network, JSON.stringify(bitpayAccounts), cb);
|
||||
});
|
||||
};
|
||||
|
||||
var _01_setAppIdentity = function(network, data, cb) {
|
||||
storage.set('appIdentity-' + network, data, cb);
|
||||
};
|
||||
|
||||
var _02_setBitpayAccount = function(network, data, cb) {
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
if (lodash.isEmpty(data) || !data.email || !data.acct) return cb('No account to set');
|
||||
storage.get('bitpayAccounts-v2-' + network, function(err, bitpayAccounts) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(bitpayAccounts)) {
|
||||
bitpayAccounts = JSON.parse(bitpayAccounts);
|
||||
}
|
||||
bitpayAccounts = bitpayAccounts || {};
|
||||
bitpayAccounts[data.email] = data.acct;
|
||||
bitpayAccounts[data.email]['bitpayApi-' + network] = {};
|
||||
bitpayAccounts[data.email]['bitpayApi-' + network].token = data.token;
|
||||
storage.set('bitpayAccounts-v2-' + network, JSON.stringify(bitpayAccounts), cb);
|
||||
});
|
||||
};
|
||||
|
||||
var _02_setBitpayDebitCards = function(network, data, cb) {
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
if (lodash.isEmpty(data) || !data.email) return cb('Cannot set cards: no account to set');
|
||||
storage.get('bitpayAccounts-v2-' + network, function(err, bitpayAccounts) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(bitpayAccounts)) {
|
||||
bitpayAccounts = JSON.parse(bitpayAccounts);
|
||||
}
|
||||
bitpayAccounts = bitpayAccounts || {};
|
||||
bitpayAccounts[data.email] = bitpayAccounts[data.email] || {};
|
||||
bitpayAccounts[data.email]['bitpayDebitCards-' + network] = data.cards;
|
||||
storage.set('bitpayAccounts-v2-' + network, JSON.stringify(bitpayAccounts), cb);
|
||||
});
|
||||
};
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// IMPORTANT: This function is designed to block execution until it completes.
|
||||
// Ideally storage should not be used until it has been verified.
|
||||
root.verify = function(cb) {
|
||||
_upgrade(function(err) {
|
||||
cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
function _handleUpgradeError(key, err) {
|
||||
$log.error('Failed to upgrade storage for \'' + key + '\': ' + err);
|
||||
};
|
||||
|
||||
function _handleUpgradeSuccess(key, msg) {
|
||||
$log.info('Storage upgraded for \'' + key + '\': ' + msg);
|
||||
};
|
||||
|
||||
// IMPORTANT: This function is designed to block execution until it completes.
|
||||
// Ideally storage should not be used until it has been verified.
|
||||
function _upgrade(cb) {
|
||||
var errorCount = 0;
|
||||
var errorMessage = undefined;
|
||||
var keys = Object.keys(_upgraders).sort();
|
||||
var networks = ['livenet', 'testnet'];
|
||||
_asyncEach(keys, function(key, callback_keys) {
|
||||
_asyncEach(networks, function(network, callback_networks) {
|
||||
var storagekey = key.split('_')[1];
|
||||
_upgraders[key](storagekey, network, function(err, msg) {
|
||||
if (err) {
|
||||
_handleUpgradeError(storagekey + '-' + network, err);
|
||||
errorCount++;
|
||||
errorMessage = errorCount + ' storage upgrade failures';
|
||||
}
|
||||
if (msg) _handleUpgradeSuccess(storagekey + '-' + network, msg);
|
||||
callback_networks();
|
||||
});
|
||||
}, function() {
|
||||
// done - networks
|
||||
callback_keys();
|
||||
});
|
||||
}, function() {
|
||||
//done - keys
|
||||
cb(errorMessage);
|
||||
});
|
||||
};
|
||||
|
||||
function _asyncEach(iterableList, callback, done) {
|
||||
var i = -1;
|
||||
var length = iterableList.length;
|
||||
|
||||
function loop() {
|
||||
i++;
|
||||
if (i === length) {
|
||||
done();
|
||||
return;
|
||||
} else if (i < length) {
|
||||
callback(iterableList[i], loop);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
loop();
|
||||
};
|
||||
|
||||
// This is only use in Copay, for very old instalations
|
||||
// in which we use to use localStorage instead of fileStorage
|
||||
root.tryToMigrate = function(cb) {
|
||||
if (!shouldUseFileStorage) return cb();
|
||||
|
||||
|
|
@ -645,51 +344,35 @@ angular.module('copayApp.services')
|
|||
storage.remove('coinbaseTxs-' + network, cb);
|
||||
};
|
||||
|
||||
root.setBitpayDebitCardsHistory = function(network, data, cb) {
|
||||
storage.set('bitpayDebitCardsHistory-' + network, data, cb);
|
||||
root.setBalanceCache = function(cardId, data, cb) {
|
||||
storage.set('balanceCache-' + cardId, data, cb);
|
||||
};
|
||||
|
||||
root.getBitpayDebitCardsHistory = function(network, cb) {
|
||||
storage.get('bitpayDebitCardsHistory-' + network, cb);
|
||||
root.getBalanceCache = function(cardId, cb) {
|
||||
storage.get('balanceCache-' + cardId, cb);
|
||||
};
|
||||
|
||||
root.removeBitpayDebitCardHistory = function(network, card, cb) {
|
||||
root.getBitpayDebitCardsHistory(network, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
delete data[card.eid];
|
||||
root.setBitpayDebitCardsHistory(network, JSON.stringify(data), cb);
|
||||
});
|
||||
root.removeBalanceCache = function(cardId, cb) {
|
||||
storage.remove('balanceCache-' + cardId, cb);
|
||||
};
|
||||
|
||||
// data: {
|
||||
// cards: [
|
||||
// eid: card id
|
||||
// id: card id
|
||||
// lastFourDigits: card number
|
||||
// token: card token
|
||||
// ]
|
||||
// email: account email
|
||||
// token: account token
|
||||
// }
|
||||
root.setBitpayDebitCards = function(network, data, cb) {
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
if (lodash.isEmpty(data) || !data.email) return cb('Cannot set cards: no account to set');
|
||||
storage.get('bitpayAccounts-v2-' + network, function(err, bitpayAccounts) {
|
||||
root.setBitpayDebitCards = function(network, email, cards, cb) {
|
||||
|
||||
root.getBitpayAccounts(network, function(err, allAccounts) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(bitpayAccounts)) {
|
||||
bitpayAccounts = JSON.parse(bitpayAccounts);
|
||||
|
||||
if (!allAccounts[email]) {
|
||||
return cb('Cannot set cards for unknown account ' + email);
|
||||
}
|
||||
bitpayAccounts = bitpayAccounts || {};
|
||||
bitpayAccounts[data.email] = bitpayAccounts[data.email] || {};
|
||||
bitpayAccounts[data.email]['bitpayDebitCards-' + network] = data.cards;
|
||||
storage.set('bitpayAccounts-v2-' + network, JSON.stringify(bitpayAccounts), cb);
|
||||
|
||||
allAccounts[email].cards = cards;
|
||||
storage.set('bitpayAccounts-v2-' + network, allAccounts, cb);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -702,24 +385,24 @@ angular.module('copayApp.services')
|
|||
// email: account email
|
||||
// ]
|
||||
root.getBitpayDebitCards = function(network, cb) {
|
||||
storage.get('bitpayAccounts-v2-' + network, function(err, bitpayAccounts) {
|
||||
if (lodash.isString(bitpayAccounts)) {
|
||||
bitpayAccounts = JSON.parse(bitpayAccounts);
|
||||
}
|
||||
bitpayAccounts = bitpayAccounts || {};
|
||||
var cards = [];
|
||||
_asyncEach(Object.keys(bitpayAccounts), function(email, callback) {
|
||||
// For the UI, add the account email to the card object.
|
||||
var acctCards = bitpayAccounts[email]['bitpayDebitCards-' + network] || [];
|
||||
for (var i = 0; i < acctCards.length; i++) {
|
||||
acctCards[i].email = email;
|
||||
}
|
||||
cards = cards.concat(acctCards);
|
||||
callback();
|
||||
}, function() {
|
||||
// done
|
||||
cb(err, cards);
|
||||
|
||||
root.getBitpayAccounts(network, function(err, allAccounts) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var allCards = [];
|
||||
|
||||
lodash.each(allAccounts, function(account, email) {
|
||||
|
||||
// Add account's email to card list, for convenience
|
||||
var cards = lodash.clone(account.cards);
|
||||
lodash.each(cards, function(x) {
|
||||
x.email = email;
|
||||
});
|
||||
|
||||
allCards = allCards.concat(cards);
|
||||
});
|
||||
|
||||
return cb(null, allCards);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -729,95 +412,101 @@ angular.module('copayApp.services')
|
|||
// lastFourDigits: card number
|
||||
// token: card token
|
||||
// }
|
||||
root.removeBitpayDebitCard = function(network, card, cb) {
|
||||
if (lodash.isString(card)) {
|
||||
card = JSON.parse(card);
|
||||
}
|
||||
card = card || {};
|
||||
if (lodash.isEmpty(card) || !card.eid) return cb('No card to remove');
|
||||
storage.get('bitpayAccounts-v2-' + network, function(err, bitpayAccounts) {
|
||||
if (err) cb(err);
|
||||
if (lodash.isString(bitpayAccounts)) {
|
||||
bitpayAccounts = JSON.parse(bitpayAccounts);
|
||||
}
|
||||
bitpayAccounts = bitpayAccounts || {};
|
||||
_asyncEach(Object.keys(bitpayAccounts), function(email, callback) {
|
||||
var data = bitpayAccounts[email]['bitpayDebitCards-' + network];
|
||||
var newCards = lodash.reject(data, {
|
||||
'eid': card.eid
|
||||
});
|
||||
data = {};
|
||||
data.cards = newCards;
|
||||
data.email = email;
|
||||
root.setBitpayDebitCards(network, data, function(err) {
|
||||
if (err) cb(err);
|
||||
// If there are no more cards in storage then re-enable the next step entry.
|
||||
root.getBitpayDebitCards(network, function(err, cards) {
|
||||
if (err) cb(err);
|
||||
if (cards.length == 0) {
|
||||
root.removeNextStep('BitpayCard', callback());
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
});
|
||||
});
|
||||
}, function() {
|
||||
// done
|
||||
cb();
|
||||
});
|
||||
});
|
||||
};
|
||||
root.removeBitpayDebitCard = function(network, cardEid, cb) {
|
||||
|
||||
// data: {
|
||||
// email: account email
|
||||
// token: account token
|
||||
// }
|
||||
root.setBitpayAccount = function(network, data, cb) {
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
data = data || {};
|
||||
if (lodash.isEmpty(data) || !data.email) return cb('No account to set');
|
||||
storage.get('bitpayAccounts-v2-' + network, function(err, bitpayAccounts) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(bitpayAccounts)) {
|
||||
bitpayAccounts = JSON.parse(bitpayAccounts);
|
||||
}
|
||||
bitpayAccounts = bitpayAccounts || {};
|
||||
bitpayAccounts[data.email] = bitpayAccounts[data.email] || {};
|
||||
bitpayAccounts[data.email]['bitpayApi-' + network] = bitpayAccounts[data.email]['bitpayApi-' + network] || {};
|
||||
bitpayAccounts[data.email]['bitpayApi-' + network].token = data.token;
|
||||
storage.set('bitpayAccounts-v2-' + network, JSON.stringify(bitpayAccounts), cb);
|
||||
root.getBitpayAccounts(network, function(err, allAccounts){
|
||||
|
||||
lodash.each(allAccounts, function(account){
|
||||
account.cards = lodash.reject(account.cards, {
|
||||
'eid': cardEid
|
||||
});
|
||||
});
|
||||
|
||||
storage.set('bitpayAccounts-v2-' + network, allAccounts, cb);
|
||||
});
|
||||
};
|
||||
|
||||
// cb(err, accounts)
|
||||
// accounts: {
|
||||
// email_1: {
|
||||
// bitpayApi-<network>: {
|
||||
// token: account token
|
||||
// }
|
||||
// bitpayDebitCards-<network>: {
|
||||
// token: account token
|
||||
// cards: {
|
||||
// <card-data>
|
||||
// }
|
||||
// }
|
||||
// ...
|
||||
// email_n: {
|
||||
// bitpayApi-<network>: {
|
||||
// token: account token
|
||||
// }
|
||||
// bitpayDebitCards-<network>: {
|
||||
// token: account token
|
||||
// cards: {
|
||||
// <card-data>
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
root.getBitpayAccounts = function(network, cb) {
|
||||
storage.get('bitpayAccounts-v2-' + network, function(err, bitpayAccounts) {
|
||||
storage.get('bitpayAccounts-v2-' + network, function(err, allAccountsStr) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(bitpayAccounts)) {
|
||||
bitpayAccounts = JSON.parse(bitpayAccounts);
|
||||
}
|
||||
cb(err, bitpayAccounts);
|
||||
|
||||
var allAccounts = {};
|
||||
try {
|
||||
allAccounts = JSON.parse(allAccountsStr);
|
||||
} catch (e) {};
|
||||
|
||||
var anyMigration;
|
||||
|
||||
lodash.each(allAccounts, function(account, email) {
|
||||
|
||||
// Migrate old `'bitpayApi-' + network` key, if exists
|
||||
if (!account.token && account['bitpayApi-' + network].token) {
|
||||
|
||||
$log.info('Migrating all bitpayApi-network branch');
|
||||
account.token = account['bitpayApi-' + network].token;
|
||||
account.cards = lodash.clone(account['bitpayApi-' + network].cards);
|
||||
if (!account.cards) {
|
||||
account.cards = lodash.clone(account['bitpayDebitCards-' + network]);
|
||||
}
|
||||
|
||||
delete account['bitpayDebitCards-' + network];
|
||||
delete account['bitpayApi-' + network];
|
||||
anyMigration = true;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
if (anyMigration) {
|
||||
storage.set('bitpayAccounts-v2-' + network, allAccounts, function(){
|
||||
return cb(err, allAccounts);
|
||||
});
|
||||
} else
|
||||
return cb(err, allAccounts);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// data: {
|
||||
// email: account email
|
||||
// token: account token
|
||||
// }
|
||||
root.setBitpayAccount = function(network, data, cb) {
|
||||
|
||||
if (!lodash.isObject(data) || !data.email || !data.token)
|
||||
return cb('No account to set');
|
||||
|
||||
var email = data.email;
|
||||
var token = data.token;
|
||||
|
||||
|
||||
root.getBitpayAccounts(network, function(err, allAccounts) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var account = allAccounts[email] || {};
|
||||
account.token = token;
|
||||
|
||||
allAccounts[email] = account;
|
||||
|
||||
$log.info('Storing BitPay accounts with new account:' + email);
|
||||
storage.set('bitpayAccounts-v2-' + network, allAccounts, cb);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -828,10 +517,7 @@ angular.module('copayApp.services')
|
|||
root.getAppIdentity = function(network, cb) {
|
||||
storage.get('appIdentity-' + network, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
if (lodash.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
cb(err, data);
|
||||
cb(err, JSON.parse(data || '{}'));
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue