diff --git a/src/js/routes.js b/src/js/routes.js index cc8037381..315a26415 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -1153,50 +1153,40 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr }); } - $log.info('Verifying storage...'); - storageService.verify(function(err) { + $log.info('Init profile...'); + // Try to open local profile + profileService.loadAndBindProfile(function(err) { + $ionicHistory.nextViewOptions({ + disableAnimate: true + }); if (err) { - $log.error('Storage failed to verify: ' + err); - // TODO - what next? - } else { - $log.info('Storage OK'); - } - - $log.info('Init profile...'); - // Try to open local profile - profileService.loadAndBindProfile(function(err) { - $ionicHistory.nextViewOptions({ - disableAnimate: true - }); - if (err) { - if (err.message && err.message.match('NOPROFILE')) { - $log.debug('No profile... redirecting'); + if (err.message && err.message.match('NOPROFILE')) { + $log.debug('No profile... redirecting'); + $state.go('onboarding.welcome'); + } else if (err.message && err.message.match('NONAGREEDDISCLAIMER')) { + if (lodash.isEmpty(profileService.getWallets())) { + $log.debug('No wallets and no disclaimer... redirecting'); $state.go('onboarding.welcome'); - } else if (err.message && err.message.match('NONAGREEDDISCLAIMER')) { - if (lodash.isEmpty(profileService.getWallets())) { - $log.debug('No wallets and no disclaimer... redirecting'); - $state.go('onboarding.welcome'); - } else { - $log.debug('Display disclaimer... redirecting'); - $state.go('onboarding.disclaimer', { - resume: true - }); - } } else { - throw new Error(err); // TODO + $log.debug('Display disclaimer... redirecting'); + $state.go('onboarding.disclaimer', { + resume: true + }); } } else { - profileService.storeProfileIfDirty(); - $log.debug('Profile loaded ... Starting UX.'); - scannerService.gentleInitialize(); - $state.go('tabs.home'); + throw new Error(err); // TODO } + } else { + profileService.storeProfileIfDirty(); + $log.debug('Profile loaded ... Starting UX.'); + scannerService.gentleInitialize(); + $state.go('tabs.home'); + } - // After everything have been loaded, initialize handler URL - $timeout(function() { - openURLService.init(); - }, 1000); - }); + // After everything have been loaded, initialize handler URL + $timeout(function() { + openURLService.init(); + }, 1000); }); }); diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 526c65a87..e999b058d 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -74,312 +74,9 @@ 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();