From cc2f5f6a145531a0df08eaf2bacc3eb02d191d16 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Wed, 30 May 2018 16:28:32 +1200 Subject: [PATCH 01/34] Rudimentarily working with getting and setting the profile in the Keychain on iOS. --- app-template/config-template.xml | 1 + src/js/services/storageService.js | 55 ++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/app-template/config-template.xml b/app-template/config-template.xml index 8031c8110..32440782c 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -72,6 +72,7 @@ + diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 3d1ecfeef..ea0a975c0 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -116,19 +116,60 @@ angular.module('copayApp.services') }; root.storeNewProfile = function(profile, cb) { - storage.create('profile', profile.toObj(), cb); + console.log('storeNewProfile() 6'); + + SecureStorage.set('profile', profile.toObj(), function success(){ cb(); }, function error(err){ cb(err); }); + + //storage.create('profile', profile.toObj(), cb); }; root.storeProfile = function(profile, cb) { - storage.set('profile', profile.toObj(), cb); + console.log('storeProfile() 6'); + SecureStorage.set('profile', profile.toObj(), function success(){ cb(); }, function error(err){ cb(err); }); + //storage.set('profile', profile.toObj(), cb); }; root.getProfile = function(cb) { - storage.get('profile', function(err, str) { - if (err || !str) - return cb(err); + console.log("getProfile() 6"); + + SecureStorage.get( + 'profile', + function success(str) { + $log.debug('get profile returned success.'); + decryptOnMobile(str, function(err, str) { + if (err) return cb(err); + var p, err; + try { + p = Profile.fromString(str); + } catch (e) { + $log.debug('Could not read profile:', e); + err = new Error('Could not read profile:' + p); + } + return cb(err, p); + }); + }, + function error(err) { + $log.debug('get profile returned error.'); + $log.debug('returning error.'); + // Callback requires no error and no profile for creation of new profiles + return cb(); + } + ); + + + + /* + storage.get('profile', function(err, str) { + $log.debug('get profile returned.'); + if (err || !str) { + $log.debug('get profile returned error: ' + err + ' with string: ' + str); + return cb(err); + } + + $log.debug('calling decrypt'); decryptOnMobile(str, function(err, str) { + $log.debug('decrypt returned.'); if (err) return cb(err); var p, err; try { @@ -140,8 +181,12 @@ angular.module('copayApp.services') return cb(err, p); }); }); + */ + + }; + // Is this ever used? root.deleteProfile = function(cb) { storage.remove('profile', cb); }; From 90d321033bebcb0632c570abe581a57f41c1fa69 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Thu, 31 May 2018 17:53:58 +1200 Subject: [PATCH 02/34] Working pretty roughly on iOS with cordova-plugin-secure-storage. --- app-template/config-template.xml | 1 + src/js/services/secureStorageService.js | 93 +++++++++++++++++++++++++ src/js/services/storageService.js | 14 ++-- 3 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 src/js/services/secureStorageService.js diff --git a/app-template/config-template.xml b/app-template/config-template.xml index 8031c8110..e348cbe52 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -72,6 +72,7 @@ + diff --git a/src/js/services/secureStorageService.js b/src/js/services/secureStorageService.js new file mode 100644 index 000000000..2c3a94703 --- /dev/null +++ b/src/js/services/secureStorageService.js @@ -0,0 +1,93 @@ +'use strict'; + +angular.module('copayApp.services').factory('secureStorageService', function($log, appConfigService, platformInfo) { + var root = {}; + + var ssIsReady = false; + var ssInitialisationFailed = false; + var pending = []; + + var ss = new cordova.plugins.SecureStorage( + function () { + console.log('ss Success'); + ssIsReady = true; + for (var i = 0; i < pending.length; i++) { + pending[i](); + } + pending = []; + }, + function (error) { + console.log('ss Error ' + error); + ssInitialisationFailed = true; + }, + appConfigService.packageNameId); + + + + root.get = function(key, cb) { + $log.debug('secureStorageService.get()'); + if (!ssIsReady) { + $log.debug("ss not ready."); + if (ssInitialisationFailed) { + $log.debug("returning error because initialisation failed."); + cb(new Error("Secure storage initialisation failed.")); + } else { + $log.debug("adding get to pending."); + pending.push(function(){ root.get(key, cb); }); + } + return + } + $log.debug("ss is ready."); + + ss.get( + function (value) { + console.log('ss Success, got ' + value); + cb(null, value); + }, + function (error) { + console.log('ss Error "' + error.message + '" ' + JSON.stringify(error)); + + if (error.message === 'Failure in SecureStorage.get() - The specified item could not be found in the keychain') { + $log.debug("Sending back null error."); + // The callback expects no error, but also no value, if it cannot be found. + cb(null); + } else { + cb(new Error(error)); + } + }, + key); + + }; + + root.set = function(key, value, cb) { + $log.debug('secureStorageService.set()'); + if (!ssIsReady) { + $log.debug("ss not ready."); + if (ssInitialisationFailed) { + $log.debug("returning error because initialisation failed."); + cb(new Error("Secure storage initialisation failed.")); + } else { + $log.debug("adding set to pending."); + pending.push(function(){ root.set(key, value, cb); }); + } + return + } + $log.debug("ss is ready."); + + ss.set( + function (value) { + console.log('ss Success, got ' + value); + cb(); + }, + function (error) { + console.log('ss Error ' + error); + cb(new Error(error)); + }, + key, value); + + }; + + + return root; +}); + diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 3d1ecfeef..05bf51a7a 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -1,6 +1,6 @@ 'use strict'; angular.module('copayApp.services') - .factory('storageService', function(logHeader, fileStorageService, localStorageService, sjcl, $log, lodash, platformInfo, $timeout) { + .factory('storageService', function(logHeader, fileStorageService, localStorageService, sjcl, $log, lodash, platformInfo, secureStorageService, $timeout) { var root = {}; var storage; @@ -116,15 +116,21 @@ angular.module('copayApp.services') }; root.storeNewProfile = function(profile, cb) { - storage.create('profile', profile.toObj(), cb); + //storage.create('profile', profile.toObj(), cb); + secureStorageService.set('profile', profile.toObj(), cb); }; root.storeProfile = function(profile, cb) { - storage.set('profile', profile.toObj(), cb); + //storage.set('profile', profile.toObj(), cb); + secureStorageService.set('profile', profile.toObj(), cb); }; root.getProfile = function(cb) { - storage.get('profile', function(err, str) { + $log.debug("getProfile() 31 7"); + + //storage.get('profile', function(err, str) { + secureStorageService.get('profile', function(err, str) { + if (err || !str) return cb(err); From 4e6eb3295d682bbb86b4ec0d4e632b2e12a6bc0f Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Thu, 31 May 2018 18:08:04 +1200 Subject: [PATCH 03/34] Now works on Android too. --- src/js/services/secureStorageService.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/services/secureStorageService.js b/src/js/services/secureStorageService.js index 2c3a94703..7c374521b 100644 --- a/src/js/services/secureStorageService.js +++ b/src/js/services/secureStorageService.js @@ -47,7 +47,8 @@ angular.module('copayApp.services').factory('secureStorageService', function($lo function (error) { console.log('ss Error "' + error.message + '" ' + JSON.stringify(error)); - if (error.message === 'Failure in SecureStorage.get() - The specified item could not be found in the keychain') { + if (error.message === 'Failure in SecureStorage.get() - The specified item could not be found in the keychain' || + error.message === 'Key [_SS_profile] not found.') { $log.debug("Sending back null error."); // The callback expects no error, but also no value, if it cannot be found. cb(null); From b20f67095329bba250105fa8ee961a79a572ae56 Mon Sep 17 00:00:00 2001 From: Sebastiaan Pasma Date: Thu, 31 May 2018 15:36:17 +0200 Subject: [PATCH 04/34] iPhone X fixes --- src/sass/views/amount.scss | 6 ++++++ src/sass/views/confirm.scss | 9 ++++++++- src/sass/views/walletDetails.scss | 3 +++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sass/views/amount.scss b/src/sass/views/amount.scss index 3000ea696..c712d85e5 100644 --- a/src/sass/views/amount.scss +++ b/src/sass/views/amount.scss @@ -474,4 +474,10 @@ } } } + background: #494949; + + ion-content { + margin-bottom: constant(safe-area-inset-bottom); /* iOS 11.0 */ + margin-bottom: env(safe-area-inset-bottom); /* iOS 11.2 */ + } } \ No newline at end of file diff --git a/src/sass/views/confirm.scss b/src/sass/views/confirm.scss index 9ceee92c4..47f61fd7b 100644 --- a/src/sass/views/confirm.scss +++ b/src/sass/views/confirm.scss @@ -1,5 +1,5 @@ #view-confirm { - background-color: #ffffff; + background-color: #494949; @extend .deflash-blue; .item-note { float: none; @@ -30,4 +30,11 @@ .toggle { cursor: pointer; } + ion-content { + background-color: #ffffff; + } + slide-to-accept, slide-to-accept-success { + margin-bottom: constant(safe-area-inset-bottom); /* iOS 11.0 */ + margin-bottom: env(safe-area-inset-bottom); /* iOS 11.2 */ + } } diff --git a/src/sass/views/walletDetails.scss b/src/sass/views/walletDetails.scss index 1a33de7b1..9e651f871 100644 --- a/src/sass/views/walletDetails.scss +++ b/src/sass/views/walletDetails.scss @@ -131,6 +131,7 @@ .bp-content { position: relative; height: 100%; + height: calc(100% - env(safe-area-inset-bottom) * 2); &.status-bar { margin-top: 20px; @@ -157,6 +158,8 @@ padding-top: 0; top: 0; + margin-bottom: 16px; + .scroll { background: rgb(248, 248, 249); min-height: 300px; From fdc9a8c37b8c620c0181c4f851a87cb93cc1f10b Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 1 Jun 2018 09:31:14 +1200 Subject: [PATCH 05/34] Tidy up. --- src/js/services/secureStorageService.js | 136 ++++++++++++------------ 1 file changed, 67 insertions(+), 69 deletions(-) diff --git a/src/js/services/secureStorageService.js b/src/js/services/secureStorageService.js index 7c374521b..989c1642a 100644 --- a/src/js/services/secureStorageService.js +++ b/src/js/services/secureStorageService.js @@ -3,89 +3,87 @@ angular.module('copayApp.services').factory('secureStorageService', function($log, appConfigService, platformInfo) { var root = {}; - var ssIsReady = false; - var ssInitialisationFailed = false; - var pending = []; + function CordovaSs() { + var isReady = false; + var initialisationFailed = false; + var pending = []; + + var storage = null; - var ss = new cordova.plugins.SecureStorage( - function () { - console.log('ss Success'); - ssIsReady = true; - for (var i = 0; i < pending.length; i++) { - pending[i](); - } - pending = []; - }, - function (error) { - console.log('ss Error ' + error); - ssInitialisationFailed = true; - }, - appConfigService.packageNameId); - - - root.get = function(key, cb) { - $log.debug('secureStorageService.get()'); - if (!ssIsReady) { - $log.debug("ss not ready."); - if (ssInitialisationFailed) { - $log.debug("returning error because initialisation failed."); + this.get = function(key, cb) { + if (!isReady) { + if (initialisationFailed) { cb(new Error("Secure storage initialisation failed.")); } else { - $log.debug("adding get to pending."); pending.push(function(){ root.get(key, cb); }); } return + } + + storage.get( + function (value) { + cb(null, value); + }, + function (error) { + if (error.message === 'Failure in SecureStorage.get() - The specified item could not be found in the keychain' || // iOS + error.message === 'Key [_SS_profile] not found.') { // Android + // The callback expects no error, but also no value, if it cannot be found. + cb(null); + } else { + cb(new Error(error)); + } + }, + key); } - $log.debug("ss is ready."); - ss.get( - function (value) { - console.log('ss Success, got ' + value); - cb(null, value); - }, - function (error) { - console.log('ss Error "' + error.message + '" ' + JSON.stringify(error)); - - if (error.message === 'Failure in SecureStorage.get() - The specified item could not be found in the keychain' || - error.message === 'Key [_SS_profile] not found.') { - $log.debug("Sending back null error."); - // The callback expects no error, but also no value, if it cannot be found. - cb(null); - } else { + this.set = function(key, value, cb) { + if (!isReady) { + if (initialisationFailed) { + cb(new Error("Secure storage initialisation failed.")); + } else { + pending.push(function(){ root.set(key, value, cb); }); + } + return + } + + storage.set( + function (value) { + cb(); + }, + function (error) { cb(new Error(error)); - } - }, - key); + }, + key, value); + } + if (platformInfo.isCordova) { + storage = new cordova.plugins.SecureStorage( + function () { + console.log('ss Success'); + isReady = true; + for (var i = 0; i < pending.length; i++) { + pending[i](); + } + spending = []; + }, + function (error) { + console.log('ss Error ' + error); + initialisationFailed = true; + }, + appConfigService.packageNameId); + } + + } + + var cordovaSs = new CordovaSs(); + + root.get = function(key, cb) { + cordovaSs.get(key, cb); }; root.set = function(key, value, cb) { - $log.debug('secureStorageService.set()'); - if (!ssIsReady) { - $log.debug("ss not ready."); - if (ssInitialisationFailed) { - $log.debug("returning error because initialisation failed."); - cb(new Error("Secure storage initialisation failed.")); - } else { - $log.debug("adding set to pending."); - pending.push(function(){ root.set(key, value, cb); }); - } - return - } - $log.debug("ss is ready."); - - ss.set( - function (value) { - console.log('ss Success, got ' + value); - cb(); - }, - function (error) { - console.log('ss Error ' + error); - cb(new Error(error)); - }, - key, value); - + cordovaSs.set(key, value, cb); }; From aaad6a1b4a7bfa5e940b23a0995a97a717f7f726 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 1 Jun 2018 10:19:26 +1200 Subject: [PATCH 06/34] Refactored to have the mobile and desktop secure storage contained with a more generic secure storage service. --- app-template/config-template.xml | 3 +- src/js/services/mobileSecureStorageService.js | 93 +++++++++++++++ src/js/services/secureStorageService.js | 108 ++++-------------- src/js/services/storageService.js | 2 +- 4 files changed, 120 insertions(+), 86 deletions(-) create mode 100644 src/js/services/mobileSecureStorageService.js diff --git a/app-template/config-template.xml b/app-template/config-template.xml index e348cbe52..39b67d212 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -72,7 +72,8 @@ - + + diff --git a/src/js/services/mobileSecureStorageService.js b/src/js/services/mobileSecureStorageService.js new file mode 100644 index 000000000..93a2ec591 --- /dev/null +++ b/src/js/services/mobileSecureStorageService.js @@ -0,0 +1,93 @@ +'use strict'; + +angular.module('copayApp.services').factory('mobileSecureStorageService', function($log, appConfigService, platformInfo) { + var root = {}; + + var isReady = false; + var initialisationFailed = false; + var pending = []; + + var storage = null; + + this.get = function(key, cb) { + if (!isReady) { + if (initialisationFailed) { + cb(new Error("mobileSecureStorageService initialisation failed.")); + } else { + pending.push(function(){ root.get(key, cb); }); + } + return + } + + storage.get( + function (value) { + cb(null, value); + }, + function (error) { + if (error.message === 'Failure in SecureStorage.get() - The specified item could not be found in the keychain' || // iOS + error.message === 'Key [_SS_profile] not found.') { // Android + // The callback expects no error, but also no value, if it cannot be found. + cb(null, null); + } else { + cb(new Error(error)); + } + }, + key); + } + + this.set = function(key, value, cb) { + if (!isReady) { + if (initialisationFailed) { + cb(new Error("mobileSecureStorageService initialisation failed.")); + } else { + pending.push(function(){ root.set(key, value, cb); }); + } + return + } + + storage.set( + function (value) { + cb(); + }, + function (error) { + cb(new Error(error)); + }, + key, value); + } + + if (platformInfo.isCordova) { + storage = new cordova.plugins.SecureStorage( + function () { + $log.debug('mobileSecureStorageService initialised.'); + isReady = true; + for (var i = 0; i < pending.length; i++) { + pending[i](); + } + pending = []; + }, + function (error) { + c$log.debug('mobileSecureStorageService initialisation failed. ' + error); + initialisationFailed = true; + }, + appConfigService.packageNameId); + } + + root.get = function(key, cb) { + if (platformInfo.isMobile) { + storage.get(key, cb); + } else { + cb(new Error('mobileSecureStorageService is only available on mobile.')); + } + }; + + root.set = function(key, value, cb) { + if (platformInfo.isMobile) { + storage.set(key, v, cb); + } else { + cb(new Error('mobileSecureStorageService is only available on mobile.')); + } + }; + + return root; +}); + diff --git a/src/js/services/secureStorageService.js b/src/js/services/secureStorageService.js index 989c1642a..c066109c2 100644 --- a/src/js/services/secureStorageService.js +++ b/src/js/services/secureStorageService.js @@ -1,92 +1,32 @@ 'use strict'; -angular.module('copayApp.services').factory('secureStorageService', function($log, appConfigService, platformInfo) { +angular.module('copayApp.services').factory('secureStorageService', function(desktopSecureStorageService, localStorageService, $log, mobileSecureStorageService, platformInfo) { var root = {}; - function CordovaSs() { - var isReady = false; - var initialisationFailed = false; - var pending = []; - - var storage = null; - - - this.get = function(key, cb) { - if (!isReady) { - if (initialisationFailed) { - cb(new Error("Secure storage initialisation failed.")); - } else { - pending.push(function(){ root.get(key, cb); }); - } - return - } - - storage.get( - function (value) { - cb(null, value); - }, - function (error) { - if (error.message === 'Failure in SecureStorage.get() - The specified item could not be found in the keychain' || // iOS - error.message === 'Key [_SS_profile] not found.') { // Android - // The callback expects no error, but also no value, if it cannot be found. - cb(null); - } else { - cb(new Error(error)); - } - }, - key); - } - - this.set = function(key, value, cb) { - if (!isReady) { - if (initialisationFailed) { - cb(new Error("Secure storage initialisation failed.")); - } else { - pending.push(function(){ root.set(key, value, cb); }); - } - return - } - - storage.set( - function (value) { - cb(); - }, - function (error) { - cb(new Error(error)); - }, - key, value); - } - - if (platformInfo.isCordova) { - storage = new cordova.plugins.SecureStorage( - function () { - console.log('ss Success'); - isReady = true; - for (var i = 0; i < pending.length; i++) { - pending[i](); - } - spending = []; - }, - function (error) { - console.log('ss Error ' + error); - initialisationFailed = true; - }, - appConfigService.packageNameId); - } - + // To make wrong code look wrong + function alteredKeyIndicatingDesireForSecureStorage(key) { + return key + ":desiredSecure"; } - var cordovaSs = new CordovaSs(); - - root.get = function(key, cb) { - cordovaSs.get(key, cb); - }; - - root.set = function(key, value, cb) { - cordovaSs.set(key, value, cb); - }; - + root.get = function(k, cb) { + if (platformInfo.isMobile) { + mobileSecureStorageService.get(k, cb); + } else if (platformInfo.isNW) { + desktopSecureStorageService.get(k, cb); + } else { // Browser + localStorageService.get(alteredKeyIndicatingDesireForSecureStorage(k), cb); + } + } + root.set = function(k, v, cb) { + if (platformInfo.isMobile) { + mobileSecureStorageService.set(k, v, cb); + } else if (platformInfo.isNW) { + desktopSecureStorageService.set(k, v, cb); + } else { // Browser + localStorageService.set(alteredKeyIndicatingDesireForSecureStorage(k), v, cb); + } + } + return root; -}); - +}); \ No newline at end of file diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 05bf51a7a..2cc6da730 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -126,7 +126,7 @@ angular.module('copayApp.services') }; root.getProfile = function(cb) { - $log.debug("getProfile() 31 7"); + $log.debug("getProfile() 1 8"); //storage.get('profile', function(err, str) { secureStorageService.get('profile', function(err, str) { From 17685dd810d46895e04fa7489eb9fcca66f1e1a2 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 1 Jun 2018 10:42:38 +1200 Subject: [PATCH 07/34] Fixed some issues after the refactor. --- src/js/services/mobileSecureStorageService.js | 104 +++++++++--------- src/js/services/secureStorageService.js | 3 + 2 files changed, 55 insertions(+), 52 deletions(-) diff --git a/src/js/services/mobileSecureStorageService.js b/src/js/services/mobileSecureStorageService.js index 93a2ec591..56c3e2df6 100644 --- a/src/js/services/mobileSecureStorageService.js +++ b/src/js/services/mobileSecureStorageService.js @@ -9,52 +9,6 @@ angular.module('copayApp.services').factory('mobileSecureStorageService', functi var storage = null; - this.get = function(key, cb) { - if (!isReady) { - if (initialisationFailed) { - cb(new Error("mobileSecureStorageService initialisation failed.")); - } else { - pending.push(function(){ root.get(key, cb); }); - } - return - } - - storage.get( - function (value) { - cb(null, value); - }, - function (error) { - if (error.message === 'Failure in SecureStorage.get() - The specified item could not be found in the keychain' || // iOS - error.message === 'Key [_SS_profile] not found.') { // Android - // The callback expects no error, but also no value, if it cannot be found. - cb(null, null); - } else { - cb(new Error(error)); - } - }, - key); - } - - this.set = function(key, value, cb) { - if (!isReady) { - if (initialisationFailed) { - cb(new Error("mobileSecureStorageService initialisation failed.")); - } else { - pending.push(function(){ root.set(key, value, cb); }); - } - return - } - - storage.set( - function (value) { - cb(); - }, - function (error) { - cb(new Error(error)); - }, - key, value); - } - if (platformInfo.isCordova) { storage = new cordova.plugins.SecureStorage( function () { @@ -73,19 +27,65 @@ angular.module('copayApp.services').factory('mobileSecureStorageService', functi } root.get = function(key, cb) { - if (platformInfo.isMobile) { - storage.get(key, cb); - } else { + + if (!platformInfo.isMobile) { cb(new Error('mobileSecureStorageService is only available on mobile.')); + return; } + + if (!isReady) { + if (initialisationFailed) { + cb(new Error('mobileSecureStorageService initialisation failed.')); + } else { + $log.debug('mss.get() queued.'); + pending.push(function(){ root.get(key, cb); }); + } + return; + } + + $log.debug('mss.get() running.'); + storage.get( + function (value) { + $log.debug('mss.get() succeeded.'); + cb(null, value); + }, + function (error) { + $log.debug('mss get failed. ' + error); + if (error.message === 'Failure in SecureStorage.get() - The specified item could not be found in the keychain' || // iOS + error.message === 'Key [_SS_profile] not found.') { // Android + // The callback expects no error, but also no value, if it cannot be found. + cb(null, null); + } else { + cb(new Error(error)); + } + }, + key); }; root.set = function(key, value, cb) { - if (platformInfo.isMobile) { - storage.set(key, v, cb); - } else { + + if (!platformInfo.isMobile) { cb(new Error('mobileSecureStorageService is only available on mobile.')); + } + + if (!isReady) { + if (initialisationFailed) { + cb(new Error('mobileSecureStorageService initialisation failed.')); + } else { + pending.push(function(){ root.set(key, value, cb); }); + } + return; } + + storage.set( + function (value) { + cb(); + }, + function (error) { + cb(new Error(error)); + }, + key, value); + }; return root; diff --git a/src/js/services/secureStorageService.js b/src/js/services/secureStorageService.js index c066109c2..e7179bf62 100644 --- a/src/js/services/secureStorageService.js +++ b/src/js/services/secureStorageService.js @@ -9,9 +9,12 @@ angular.module('copayApp.services').factory('secureStorageService', function(des } root.get = function(k, cb) { + $log.debug('ss.get()'); if (platformInfo.isMobile) { + $log.debug('ss.get() using mobile.'); mobileSecureStorageService.get(k, cb); } else if (platformInfo.isNW) { + $log.debug('ss.get() using desktop.'); desktopSecureStorageService.get(k, cb); } else { // Browser localStorageService.get(alteredKeyIndicatingDesireForSecureStorage(k), cb); From f483fd81d8902bcd01c05f740dc8ebfd309dbb77 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 1 Jun 2018 11:53:04 +1200 Subject: [PATCH 08/34] Removed deleteProfile() as it is not used. --- src/js/services/storageService.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 2cc6da730..df135a946 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -116,19 +116,16 @@ angular.module('copayApp.services') }; root.storeNewProfile = function(profile, cb) { - //storage.create('profile', profile.toObj(), cb); secureStorageService.set('profile', profile.toObj(), cb); }; root.storeProfile = function(profile, cb) { - //storage.set('profile', profile.toObj(), cb); secureStorageService.set('profile', profile.toObj(), cb); }; root.getProfile = function(cb) { $log.debug("getProfile() 1 8"); - //storage.get('profile', function(err, str) { secureStorageService.get('profile', function(err, str) { if (err || !str) @@ -148,10 +145,6 @@ angular.module('copayApp.services') }); }; - root.deleteProfile = function(cb) { - storage.remove('profile', cb); - }; - root.setFeedbackInfo = function(feedbackValues, cb) { storage.set('feedback', feedbackValues, cb); }; From c5121afd7ccd99db0ba02f0ad7c7d755f88c799c Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 1 Jun 2018 15:04:52 +1200 Subject: [PATCH 09/34] Placeholder desktopSecureStorageService. --- src/js/services/desktopSecureStorageService.js | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/js/services/desktopSecureStorageService.js diff --git a/src/js/services/desktopSecureStorageService.js b/src/js/services/desktopSecureStorageService.js new file mode 100644 index 000000000..6e148da2c --- /dev/null +++ b/src/js/services/desktopSecureStorageService.js @@ -0,0 +1,6 @@ +'use strict'; + +angular.module('copayApp.services').factory('desktopSecureStorageService', function($log) { + // Placeholder + return {}; +}); \ No newline at end of file From 8d94a244bcfd71934b85305f750a0735c97977ca Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 1 Jun 2018 15:25:08 +1200 Subject: [PATCH 10/34] Removed some debug messages. --- src/js/services/mobileSecureStorageService.js | 5 ----- src/js/services/secureStorageService.js | 3 --- src/js/services/storageService.js | 2 -- 3 files changed, 10 deletions(-) diff --git a/src/js/services/mobileSecureStorageService.js b/src/js/services/mobileSecureStorageService.js index 56c3e2df6..f9994fdf8 100644 --- a/src/js/services/mobileSecureStorageService.js +++ b/src/js/services/mobileSecureStorageService.js @@ -12,7 +12,6 @@ angular.module('copayApp.services').factory('mobileSecureStorageService', functi if (platformInfo.isCordova) { storage = new cordova.plugins.SecureStorage( function () { - $log.debug('mobileSecureStorageService initialised.'); isReady = true; for (var i = 0; i < pending.length; i++) { pending[i](); @@ -20,7 +19,6 @@ angular.module('copayApp.services').factory('mobileSecureStorageService', functi pending = []; }, function (error) { - c$log.debug('mobileSecureStorageService initialisation failed. ' + error); initialisationFailed = true; }, appConfigService.packageNameId); @@ -37,16 +35,13 @@ angular.module('copayApp.services').factory('mobileSecureStorageService', functi if (initialisationFailed) { cb(new Error('mobileSecureStorageService initialisation failed.')); } else { - $log.debug('mss.get() queued.'); pending.push(function(){ root.get(key, cb); }); } return; } - $log.debug('mss.get() running.'); storage.get( function (value) { - $log.debug('mss.get() succeeded.'); cb(null, value); }, function (error) { diff --git a/src/js/services/secureStorageService.js b/src/js/services/secureStorageService.js index e7179bf62..c066109c2 100644 --- a/src/js/services/secureStorageService.js +++ b/src/js/services/secureStorageService.js @@ -9,12 +9,9 @@ angular.module('copayApp.services').factory('secureStorageService', function(des } root.get = function(k, cb) { - $log.debug('ss.get()'); if (platformInfo.isMobile) { - $log.debug('ss.get() using mobile.'); mobileSecureStorageService.get(k, cb); } else if (platformInfo.isNW) { - $log.debug('ss.get() using desktop.'); desktopSecureStorageService.get(k, cb); } else { // Browser localStorageService.get(alteredKeyIndicatingDesireForSecureStorage(k), cb); diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index df135a946..7c4ad0a60 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -124,8 +124,6 @@ angular.module('copayApp.services') }; root.getProfile = function(cb) { - $log.debug("getProfile() 1 8"); - secureStorageService.get('profile', function(err, str) { if (err || !str) From 4109d4743f184b6e865615f735a4f3fdaff5ff26 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Mon, 4 Jun 2018 09:47:02 +1200 Subject: [PATCH 11/34] Loading profiles from all sources, in preparation for merge. --- src/js/models/profile.js | 7 +++ src/js/services/storageService.js | 87 +++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/src/js/models/profile.js b/src/js/models/profile.js index 74b0c33b9..d80087e7f 100644 --- a/src/js/models/profile.js +++ b/src/js/models/profile.js @@ -62,6 +62,13 @@ Profile.prototype.isDeviceChecked = function(ua) { return this.checkedUA == ua; }; +/** + * + * @param {Profile} other + */ +Profile.prototype.merge = function(other) { + throw 'Profile merge not implemented.'; +}; Profile.prototype.setChecked = function(ua, walletId) { if (this.checkedUA != ua) { diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 7c4ad0a60..75d34fe1a 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -123,9 +123,89 @@ angular.module('copayApp.services') secureStorageService.set('profile', profile.toObj(), cb); }; - root.getProfile = function(cb) { - secureStorageService.get('profile', function(err, str) { + /** + * @callback getProfileCallback + * @param {Error} error - falsy if profile not found. + * @param {Profile} profile - falsy if error or profile not found. + */ + /** + * + * @param {Profile} oldProfile + * @param {Profile} secureProfile - may be falsy if no secure profile found. + * @param {getProfileCallback} cb + */ + function _migrateProfiles(oldProfile, secureProfile, cb) { + if (secureProfile) { + + } else { + root.storeNewProfile(oldProfile, function(err) { + if (err) { + cb(err, null); + return; + } + + return; + }); + } + + }; + + /** + * + * @param {getProfileCallback} cb + */ + root.getProfile = function(cb) { + secureStorageService.get('profile', function(secureErr, secureStr) { + var secureProfile; + var oldProfile; + + if (secureErr) { + return cb(secureErr); + } + + if (secureStr) { + try { + secureProfile = Profile.fromString(secureStr); + } catch (e) { + var profileError = new Error('Could not read secure profile.'); + return cb(profileError, null); + } + } + + storage.get('profile', function(getErr, str) { + if (getErr) { + return cb(getErr); + } + + if (!str) { + if (secureProfile) { + return cb(null, secureProfile); + } else { + return cb(null, null); + } + } + + decryptOnMobile(getStr, function(err, str) { + if (err) return cb(err); + var p, err; + try { + oldProfile = Profile.fromString(str); + } catch (e) { + $log.debug('Could not read profile:', e); + err = new Error('Could not read profile.'); + return(err, null); + } + + // Now we have to do a migration + _migrateProfiles(oldProfile, secureProfile, cb); + + }); + }); + }); + }; + + /* if (err || !str) return cb(err); @@ -140,8 +220,7 @@ angular.module('copayApp.services') } return cb(err, p); }); - }); - }; + */ root.setFeedbackInfo = function(feedbackValues, cb) { storage.set('feedback', feedbackValues, cb); From 3aa9bef8036609e934eeaf69bf374c2ddd090e72 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Mon, 4 Jun 2018 14:37:54 +1200 Subject: [PATCH 12/34] The localStorageService now returns errors when they happen. --- src/js/services/localStorage.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/js/services/localStorage.js b/src/js/services/localStorage.js index c772b7eef..ba0db231b 100644 --- a/src/js/services/localStorage.js +++ b/src/js/services/localStorage.js @@ -20,8 +20,7 @@ angular.module('copayApp.services') if (isChromeApp || isNW) { chrome.storage.local.get(k, function(data) { - //TODO check for errors - return cb(null, data[k]); + return cb(chrome.runtime.lastError, data[k]); }); } else { return cb(null, ls.getItem(k)); @@ -56,16 +55,24 @@ angular.module('copayApp.services') obj[k] = v; - chrome.storage.local.set(obj, cb); + chrome.storage.local.set(obj, function(){ + cb(chrome.runtime.lastError); + }); } else { - ls.setItem(k, v); + try { + ls.setItem(k, v); + } catch (e) { + return cb(e); + } return cb(); } }; root.remove = function(k, cb) { if (isChromeApp || isNW) { - chrome.storage.local.remove(k, cb); + chrome.storage.local.remove(k, function(){ + cb(chrome.runtime.lastError); + }); } else { ls.removeItem(k); return cb(); From adf7115c9cc337dd48d0358e8634ad7731ea7ce3 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Mon, 4 Jun 2018 14:38:15 +1200 Subject: [PATCH 13/34] Merging profiles. --- src/js/models/profile.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/js/models/profile.js b/src/js/models/profile.js index d80087e7f..ac4b4828c 100644 --- a/src/js/models/profile.js +++ b/src/js/models/profile.js @@ -67,7 +67,22 @@ Profile.prototype.isDeviceChecked = function(ua) { * @param {Profile} other */ Profile.prototype.merge = function(other) { - throw 'Profile merge not implemented.'; + + var newCredentials = []; + + other.credentials.forEach(function(otherCredential) { + var credentialExists = false; + this.credentials.forEach(function(thisCredential) { + if (otherCredential.walletId === thisCredential.walletId) { + credentialExists = true; + } + }); + if (!credentialExists) { + newCredentials.push(otherCredential); + } + }); + + Array.prototype.push.apply(this.credentials, newCredentials); }; Profile.prototype.setChecked = function(ua, walletId) { From afe433d909e1da616803aacbaa34e15769981f12 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Mon, 4 Jun 2018 15:31:51 +1200 Subject: [PATCH 14/34] Starting to migrate profile storage. --- src/js/services/storageService.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 75d34fe1a..1d7d03738 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -131,20 +131,31 @@ angular.module('copayApp.services') /** * - * @param {Profile} oldProfile + * @param {Profile} oldProfile * @param {Profile} secureProfile - may be falsy if no secure profile found. * @param {getProfileCallback} cb */ function _migrateProfiles(oldProfile, secureProfile, cb) { if (secureProfile) { + secureProfile.merge(oldProfile); } else { - root.storeNewProfile(oldProfile, function(err) { + root.storeNewProfile(secureProfile, function(err) { if (err) { cb(err, null); return; } + storage.remove('profile', function(err){ + if (err) { + cb(err, null); + return; + } + + cb(null, securePofile); + + }); + return; }); } @@ -161,18 +172,22 @@ angular.module('copayApp.services') var oldProfile; if (secureErr) { - return cb(secureErr); + return cb(secureErr, null); } if (secureStr) { try { secureProfile = Profile.fromString(secureStr); + $log.error('profile: ' + JSON.stringify(secureProfile)); } catch (e) { - var profileError = new Error('Could not read secure profile.'); - return cb(profileError, null); + $log.error(e); + return cb(e, null); } } + // Ignore insecure stuff for now + return cb(null, secureProfile); + storage.get('profile', function(getErr, str) { if (getErr) { return cb(getErr); From cc45e916805d92e7c877f1c6e2a679558c7837b0 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Mon, 4 Jun 2018 20:23:01 +1200 Subject: [PATCH 15/34] Covered all the migration cases. --- src/js/services/storageService.js | 59 ++++++++++--------------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 1d7d03738..be9637652 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -136,30 +136,29 @@ angular.module('copayApp.services') * @param {getProfileCallback} cb */ function _migrateProfiles(oldProfile, secureProfile, cb) { + var newProfile = oldProfile; + if (secureProfile) { secureProfile.merge(oldProfile); + newProfile = secureProfile; + } - } else { - root.storeNewProfile(secureProfile, function(err) { - if (err) { - cb(err, null); + root.storeNewProfile(newProfile, function(storeErr) { + if (storeErr) { + cb(storeErr, null); + return; + } + + storage.remove('profile', function(removeErr){ + if (removeErr) { + cb(removeErr, null); return; } - storage.remove('profile', function(err){ - if (err) { - cb(err, null); - return; - } - - cb(null, securePofile); - - }); - - return; + cb(null, newProfile); }); - } + }); }; /** @@ -178,25 +177,23 @@ angular.module('copayApp.services') if (secureStr) { try { secureProfile = Profile.fromString(secureStr); - $log.error('profile: ' + JSON.stringify(secureProfile)); + $log.debug('profile: ' + JSON.stringify(secureProfile)); } catch (e) { $log.error(e); return cb(e, null); } } - // Ignore insecure stuff for now - return cb(null, secureProfile); - - storage.get('profile', function(getErr, str) { + storage.get('profile', function(getErr, getStr) { if (getErr) { return cb(getErr); } - if (!str) { + if (!getStr) { if (secureProfile) { return cb(null, secureProfile); } else { + // No profiles found. No errors either. return cb(null, null); } } @@ -212,7 +209,6 @@ angular.module('copayApp.services') return(err, null); } - // Now we have to do a migration _migrateProfiles(oldProfile, secureProfile, cb); }); @@ -220,23 +216,6 @@ angular.module('copayApp.services') }); }; - /* - if (err || !str) - return cb(err); - - decryptOnMobile(str, function(err, str) { - if (err) return cb(err); - var p, err; - try { - p = Profile.fromString(str); - } catch (e) { - $log.debug('Could not read profile:', e); - err = new Error('Could not read profile:' + p); - } - return cb(err, p); - }); - */ - root.setFeedbackInfo = function(feedbackValues, cb) { storage.set('feedback', feedbackValues, cb); }; From 16b5054ea297acc00536c0cfe5ef5951df515b25 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Tue, 5 Jun 2018 11:34:14 +1200 Subject: [PATCH 16/34] Now including app version is profile. --- src/js/models/profile.js | 20 ++++++++++++++++---- src/js/services/profileService.js | 2 +- src/js/services/storageService.js | 7 +++++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/js/models/profile.js b/src/js/models/profile.js index ac4b4828c..7690d1c2d 100644 --- a/src/js/models/profile.js +++ b/src/js/models/profile.js @@ -9,12 +9,12 @@ function Profile() { this.version = '1.0.0'; }; -Profile.create = function(opts) { - opts = opts || {}; +Profile.create = function(appVersion) { var x = new Profile(); + x.appVersion = appVersion; x.createdOn = Date.now(); - x.credentials = opts.credentials || []; + x.credentials = []; x.disclaimerAccepted = true; x.checked = {}; return x; @@ -23,6 +23,7 @@ Profile.create = function(opts) { Profile.fromObj = function(obj) { var x = new Profile(); + x.appVersion = obj.appVersion; x.createdOn = obj.createdOn; x.credentials = obj.credentials; x.disclaimerAccepted = obj.disclaimerAccepted; @@ -69,10 +70,12 @@ Profile.prototype.isDeviceChecked = function(ua) { Profile.prototype.merge = function(other) { var newCredentials = []; + var otherCredentialsLength = other.credentials.length; + var thisProfile = this; other.credentials.forEach(function(otherCredential) { var credentialExists = false; - this.credentials.forEach(function(thisCredential) { + thisProfile.credentials.forEach(function(thisCredential) { if (otherCredential.walletId === thisCredential.walletId) { credentialExists = true; } @@ -85,6 +88,15 @@ Profile.prototype.merge = function(other) { Array.prototype.push.apply(this.credentials, newCredentials); }; +/** + * It's a simple operation, but it means that all the profile logic stays + * in this file. + * @param {string} appVersion - ie "4.11.0" + */ +Profile.prototype.setAppVersion = function(appVersion) { + this.appVersion = appVersion; +} + Profile.prototype.setChecked = function(ua, walletId) { if (this.checkedUA != ua) { this.checkedUA = ua; diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index dac88169f..25f2a6852 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -706,7 +706,7 @@ angular.module('copayApp.services') configService.get(function(err) { if (err) $log.debug(err); - var p = Profile.create(); + var p = Profile.create(appConfigService.version); storageService.storeNewProfile(p, function(err) { if (err) return cb(err); root.bindProfile(p, function(err) { diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index be9637652..2dc3d7511 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -1,6 +1,6 @@ 'use strict'; angular.module('copayApp.services') - .factory('storageService', function(logHeader, fileStorageService, localStorageService, sjcl, $log, lodash, platformInfo, secureStorageService, $timeout) { + .factory('storageService', function(appConfigService, logHeader, fileStorageService, localStorageService, sjcl, $log, lodash, platformInfo, secureStorageService, $timeout) { var root = {}; var storage; @@ -136,11 +136,14 @@ angular.module('copayApp.services') * @param {getProfileCallback} cb */ function _migrateProfiles(oldProfile, secureProfile, cb) { - var newProfile = oldProfile; + var newProfile; if (secureProfile) { secureProfile.merge(oldProfile); newProfile = secureProfile; + } else { + newProfile = oldProfile; + newProfile.setAppVersion(appConfigService.version); } root.storeNewProfile(newProfile, function(storeErr) { From 35da3a5151bf91cf21107b75183bcfddd7895c65 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Wed, 6 Jun 2018 19:53:57 +1200 Subject: [PATCH 17/34] One test. --- Gruntfile.js | 11 ++++ app-template/package-template.json | 8 ++- src/js/services/rateService.spec.js | 53 +++++++++++++++++ test/karma.conf.js | 91 +++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 src/js/services/rateService.spec.js create mode 100644 test/karma.conf.js diff --git a/Gruntfile.js b/Gruntfile.js index b81f53f44..f9ed59621 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -152,11 +152,22 @@ module.exports = function(grunt) { src: [ 'src/js/app.js', 'src/js/routes.js', + 'src/js/directives/*.js', + '!src/js/directives/*.spec.js', + 'src/js/filters/*.js', + '!src/js/filters/*.spec.js', + 'src/js/models/*.js', + '!src/js/models/*.spec.js', + 'src/js/services/*.js', + '!src/js/services/*.spec.js', + 'src/js/controllers/**/*.js', + '!src/js/controllers/**/*.spec.js', + 'src/js/translations.js', 'src/js/appConfig.js', 'src/js/externalServices.js', diff --git a/app-template/package-template.json b/app-template/package-template.json index 660063183..75f93a3d0 100644 --- a/app-template/package-template.json +++ b/app-template/package-template.json @@ -113,8 +113,8 @@ "sign:android": "rm -f platforms/android/build/outputs/apk/android-release-signed-aligned.apk; jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ../bitcoin-com-release-key.jks -signedjar platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-unsigned.apk bitcoin-com && $ANDROID_HOME/build-tools/27.0.1/zipalign -v 4 platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-signed-aligned.apk", "apply:copay": "npm i fs-extra && cd app-template && node apply.js copay && npm i && cordova prepare", "apply:bitpay": "npm i fs-extra && cd app-template && node apply.js bitpay && npm i && cordova prepare", - "apply:bitcoincom": "npm i fs-extra && cd app-template && node apply.js bitcoincom && npm i && cordova prepare", - "test": "echo \"no package tests configured\"", + "apply:bitcoincom": "npm i fs-extra && cd app-template && node apply.js bitcoincom && npm i && cordova prepare", + "test": "karma start test/karma.conf.js --single-run", "clean": "trash platforms && trash plugins && cordova prepare", "unstage-package": "git reset package.json", "clean-all": "git clean -dfx" @@ -123,6 +123,10 @@ "cordova": "^6.3.1", "grunt": "^1.0.1", "ionic": "^3.6.0", + "jasmine-core": "^3.1.0", + "karma": "^2.0.2", + "karma-chrome-launcher": "^2.2.0", + "karma-jasmine": "^1.1.2", "trash-cli": "^1.4.0", "lodash": "^4.17.4", "pre-commit": "^1.1.3" diff --git a/src/js/services/rateService.spec.js b/src/js/services/rateService.spec.js new file mode 100644 index 000000000..35397eb7f --- /dev/null +++ b/src/js/services/rateService.spec.js @@ -0,0 +1,53 @@ +describe('rateService', function() { + var $httpBackend, rateService, requestHandler; + + beforeEach(function() { + module('ngLodash'); + module('copayApp.services'); + + inject(function($injector){ + $httpBackend = $injector.get('$httpBackend'); + + requestHandler = $httpBackend.when('GET', 'https://www.bitcoin.com/special/rates.json') + .respond([ + { + "code": "BTC", + "name": "Bitcoin", + "rate": 1 + }, + { + "code": "BCH_BTC", + "name": "Bitcoin Cash", + "rate": 6.739397 + }, + { + "code": "USD", + "name": "US Dollar", + "rate": 7602.04 + } + ]); + + rateService = $injector.get('rateService'); + + $httpBackend.flush(); + }); + }); + + afterEach(function() { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + + it('get rates', function() { + + $httpBackend.expectGET('https://www.bitcoin.com/special/rates.json'); + + rateService.updateRates(); + + $httpBackend.flush(); + + var usdRate = rateService.getRate('USD'); + + expect(usdRate).toEqual(7602.04); + }); +}); \ No newline at end of file diff --git a/test/karma.conf.js b/test/karma.conf.js new file mode 100644 index 000000000..002d40c91 --- /dev/null +++ b/test/karma.conf.js @@ -0,0 +1,91 @@ +// Karma configuration +// Generated on Tue Jun 05 2018 16:39:51 GMT+1200 (NZST) + +module.exports = function(config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '..', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], + + + // list of files / patterns to load in the browser + files: [ + 'node_modules/angular/angular.js', + + // From Gruntfile.js + 'bower_components/qrcode-generator/js/qrcode.js', + 'bower_components/qrcode-generator/js/qrcode_UTF8.js', + 'bower_components/moment/min/moment-with-locales.js', + 'bower_components/angular-moment/angular-moment.js', + 'bower_components/ng-lodash/build/ng-lodash.js', + 'bower_components/angular-qrcode/angular-qrcode.js', + 'bower_components/angular-gettext/dist/angular-gettext.js', + 'bower_components/ng-csv/build/ng-csv.js', + 'bower_components/ionic-toast/dist/ionic-toast.bundle.min.js', + 'bower_components/angular-clipboard/angular-clipboard.js', + 'bower_components/angular-md5/angular-md5.js', + 'bower_components/angular-mocks/angular-mocks.js', + 'bower_components/ngtouch/src/ngTouch.js', + 'angular-bitauth/angular-bitauth.js', + 'angular-bitcore-wallet-client/angular-bitcore-wallet-client.js', + + 'bower_components/ionic/release/js/ionic.bundle.min.js', + 'bitcoin-cash-js/bitcoin-cash-js.js', + + 'src/js/**/*.js' + ], + + + // list of files / patterns to exclude + exclude: [ + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['Chrome'], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: Infinity + }) +} From 84f90351592ff95eeda331ba1eadca8176eeb4f1 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Thu, 7 Jun 2018 20:56:24 +1200 Subject: [PATCH 18/34] One test passing on storageService. --- src/js/services/storageService.spec.js | 78 ++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/js/services/storageService.spec.js diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js new file mode 100644 index 000000000..e8c32e5b3 --- /dev/null +++ b/src/js/services/storageService.spec.js @@ -0,0 +1,78 @@ +describe('storageService on mobile', function(){ + var fileStorageServiceMock, + log, + platformInfoStub, + savedSecureProfile, + secureStorageService, + secureStorageServiceMock, + storageService; + + secureProfile = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528157581638,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K3NQsKcimdhieY7LeoSkS2W1mfaH6LcTujt8S8EWjcVttzvft9LUkdLd35CRBBLQmZwm3HXACsYZfcGh3T3z2TQLiSX8gJxn","xPubKey":"xpub6CJNjqNcCCV9f77rhB9k1CSa2kQiuEPRdyB9L8YfcLJuUjKszP3TKK65X34bpURnPYeXsrbHBL6e9NHSrUZocP4dK7u691745FMwKj4pSGg","requestPrivKey":"ce3279e705e2bce3f2809245dadb7ee50886c1be81a67a63d02ccc565a9dc1a9","requestPubKey":"035826166a59e896083dbcabb10b46d78b33bd842d2284fa8b9ff6ff1c59d8091c","copayerId":"ee7b433f9368afcf5eb1e93123ad3d1dc34ba75e1162376b2a44d0a790ff9620","publicKeyRing":[{"xPubKey":"xpub6CJNjqNcCCV9f77rhB9k1CSa2kQiuEPRdyB9L8YfcLJuUjKszP3TKK65X34bpURnPYeXsrbHBL6e9NHSrUZocP4dK7u691745FMwKj4pSGg","requestPubKey":"035826166a59e896083dbcabb10b46d78b33bd842d2284fa8b9ff6ff1c59d8091c"}],"walletId":"23c6433d-f981-41fa-94c6-8096afc4d397","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"bfdb31f5737b83790be533bd66bfffbbbd65eaa8d49a99f547683768756bec22","personalEncryptingKey":"M1aiow3pBWeSYMih3E/Acw==","sharedEncryptingKey":"6+P8AuOTZMFNgT+o3hD+BQ==","copayerName":"me","mnemonic":"echo caught churn turkey twin silent visit jewel warm hover bone kitchen","entropySource":"e1e07a2218c32122a3a3d03d578d2dfc465112d1a826830ebc88405bf4a3a606","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K3NQsKcimdhieY7LeoSkS2W1mfaH6LcTujt8S8EWjcVttzvft9LUkdLd35CRBBLQmZwm3HXACsYZfcGh3T3z2TQLiSX8gJxn","xPubKey":"xpub6CJNjqNcCCV9f77rhB9k1CSa2kQiuEPRdyB9L8YfcLJuUjKszP3TKK65X34bpURnPYeXsrbHBL6e9NHSrUZocP4dK7u691745FMwKj4pSGg","requestPrivKey":"ce3279e705e2bce3f2809245dadb7ee50886c1be81a67a63d02ccc565a9dc1a9","requestPubKey":"035826166a59e896083dbcabb10b46d78b33bd842d2284fa8b9ff6ff1c59d8091c","copayerId":"eb655f1ac4567e5a4a85ae007783ded41a51225bfb046377ce04fbafc8558a05","publicKeyRing":[{"xPubKey":"xpub6CJNjqNcCCV9f77rhB9k1CSa2kQiuEPRdyB9L8YfcLJuUjKszP3TKK65X34bpURnPYeXsrbHBL6e9NHSrUZocP4dK7u691745FMwKj4pSGg","requestPubKey":"035826166a59e896083dbcabb10b46d78b33bd842d2284fa8b9ff6ff1c59d8091c"}],"walletId":"c19b75e6-e0f4-4360-a0b5-87607559ee3c","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"c27b0d17bc62085ad6b08a8a4c967e65def306c642107ca3840380339d81eee9","personalEncryptingKey":"M1aiow3pBWeSYMih3E/Acw==","sharedEncryptingKey":"w5eq2OTn7v0fjnATHISeZg==","copayerName":"me","mnemonic":"echo caught churn turkey twin silent visit jewel warm hover bone kitchen","entropySource":"e1e07a2218c32122a3a3d03d578d2dfc465112d1a826830ebc88405bf4a3a606","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K3Wb3YBRHofV2poT3NCRL9yxhm9nYWEPJoTx4DrvfAsCtGSBFfiDXD4GvxuLosghdReCr65SzyHhYFwTLis3hMT8XkWjxT3v","xPubKey":"xpub6DWndawujFrKaQ1B5mFVeD51SuPPQkS4igUYRyoPHN7RnmJRZZwhRjeDYMhqZFLQQNu1sxsbMXXFB4b7kGYtUgFRMLRcBFF9jPbcgJ72iku","requestPrivKey":"ef9beed77a18fc2d56ddcede46aa306dd8277a196bbab971e99aac8eeb69a723","requestPubKey":"02781170de79d7bd3ea7cf8f293c7379575a0c340bbf9d81e88ec8b07a18c77394","copayerId":"d3e7adc7a6816b1eaebb7a8fae6683a9b5c249c6a6c9d0c0d6ea2e163a2ae0f6","publicKeyRing":[{"xPubKey":"xpub6DWndawujFrKaQ1B5mFVeD51SuPPQkS4igUYRyoPHN7RnmJRZZwhRjeDYMhqZFLQQNu1sxsbMXXFB4b7kGYtUgFRMLRcBFF9jPbcgJ72iku","requestPubKey":"02781170de79d7bd3ea7cf8f293c7379575a0c340bbf9d81e88ec8b07a18c77394"}],"walletId":"b97197ec-59a3-4aab-a716-2eb008899fd8","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"abbb8b79be569b2027b55bd1ed7d3c581314d432c2cc7933ff4c43311818955f","personalEncryptingKey":"+Arh5OgC4fS4SXVwnilPxA==","sharedEncryptingKey":"zRfn81E5mQlTWnekbRJ2GQ==","copayerName":"me","mnemonic":"twenty six jump dragon abuse dose pig muscle awful inject diagram alpha","entropySource":"026700d62c252a483a0434ffb9c2cf0ff333f77721affc97acb3c117056707cb","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K3Wb3YBRHofV2poT3NCRL9yxhm9nYWEPJoTx4DrvfAsCtGSBFfiDXD4GvxuLosghdReCr65SzyHhYFwTLis3hMT8XkWjxT3v","xPubKey":"xpub6DWndawujFrKaQ1B5mFVeD51SuPPQkS4igUYRyoPHN7RnmJRZZwhRjeDYMhqZFLQQNu1sxsbMXXFB4b7kGYtUgFRMLRcBFF9jPbcgJ72iku","requestPrivKey":"ef9beed77a18fc2d56ddcede46aa306dd8277a196bbab971e99aac8eeb69a723","requestPubKey":"02781170de79d7bd3ea7cf8f293c7379575a0c340bbf9d81e88ec8b07a18c77394","copayerId":"a77ccab4dd3251e005e9de214a9a29b7907dd79ab38e9046000223feb8d0578b","publicKeyRing":[{"xPubKey":"xpub6DWndawujFrKaQ1B5mFVeD51SuPPQkS4igUYRyoPHN7RnmJRZZwhRjeDYMhqZFLQQNu1sxsbMXXFB4b7kGYtUgFRMLRcBFF9jPbcgJ72iku","requestPubKey":"02781170de79d7bd3ea7cf8f293c7379575a0c340bbf9d81e88ec8b07a18c77394"}],"walletId":"7c0fd6ec-caa8-46d0-8664-8eb94d5234ef","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"779d0e969697bed9cee86719433afed30bb0f41a9a6acb93b380915c68013357","personalEncryptingKey":"+Arh5OgC4fS4SXVwnilPxA==","sharedEncryptingKey":"GHNFlK2m/uobw+94Gm1Etg==","copayerName":"me","mnemonic":"twenty six jump dragon abuse dose pig muscle awful inject diagram alpha","entropySource":"026700d62c252a483a0434ffb9c2cf0ff333f77721affc97acb3c117056707cb","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"23c6433d-f981-41fa-94c6-8096afc4d397":true,"c19b75e6-e0f4-4360-a0b5-87607559ee3c":true,"b97197ec-59a3-4aab-a716-2eb008899fd8":true,"7c0fd6ec-caa8-46d0-8664-8eb94d5234ef":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + + beforeEach(function(){ + module('ngLodash'); + module('bwcModule'); + module('copayApp.services'); + + fileStorageServiceMock = { + get: function(){} + }; + + log = { + debug: function(s){ console.log(s); }, + error: function(s){ console.log(s); }, + info: function(s){ console.log(s); } + }; + + platformInfoStub = { + isCordova: true, + isWP: false + }; + + secureStorageServiceMock = { + get: function(){} + }; + + + module(function($provide) { + $provide.value('fileStorageService', fileStorageServiceMock); + $provide.value('platformInfo', platformInfoStub); + $provide.value('secureStorageService', secureStorageServiceMock); + }); + + inject(function($injector){ + storageService = $injector.get('storageService'); + }); + + }); + + it('getProfile() from secure storage.', function() { + var error, profile; + + + spyOn(secureStorageServiceMock, 'get').and.callFake(function(k, cb){ + cb(null, secureProfile); + }); + + spyOn(fileStorageServiceMock, 'get').and.callFake(function(k, cb){ + cb(null, null); + }); + + /* + secureStorageServiceMock.spyOn('get').and.callFake(function(cb){ + cb(null, 'the profile') + }); + */ + + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(profile).toBeTruthy(); + expect(error).toBeFalsy(); + + }); + +}); \ No newline at end of file From accfea64b0a69efe42c2c2f3db222ebe95264fbe Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Thu, 7 Jun 2018 21:47:49 +1200 Subject: [PATCH 19/34] Test for getting from old storage. --- src/js/services/storageService.spec.js | 70 +++++++++++++++++++++----- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index e8c32e5b3..42e9de249 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -1,13 +1,18 @@ describe('storageService on mobile', function(){ var fileStorageServiceMock, log, + oldProfile, platformInfoStub, savedSecureProfile, secureStorageService, secureStorageServiceMock, storageService; - secureProfile = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528157581638,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K3NQsKcimdhieY7LeoSkS2W1mfaH6LcTujt8S8EWjcVttzvft9LUkdLd35CRBBLQmZwm3HXACsYZfcGh3T3z2TQLiSX8gJxn","xPubKey":"xpub6CJNjqNcCCV9f77rhB9k1CSa2kQiuEPRdyB9L8YfcLJuUjKszP3TKK65X34bpURnPYeXsrbHBL6e9NHSrUZocP4dK7u691745FMwKj4pSGg","requestPrivKey":"ce3279e705e2bce3f2809245dadb7ee50886c1be81a67a63d02ccc565a9dc1a9","requestPubKey":"035826166a59e896083dbcabb10b46d78b33bd842d2284fa8b9ff6ff1c59d8091c","copayerId":"ee7b433f9368afcf5eb1e93123ad3d1dc34ba75e1162376b2a44d0a790ff9620","publicKeyRing":[{"xPubKey":"xpub6CJNjqNcCCV9f77rhB9k1CSa2kQiuEPRdyB9L8YfcLJuUjKszP3TKK65X34bpURnPYeXsrbHBL6e9NHSrUZocP4dK7u691745FMwKj4pSGg","requestPubKey":"035826166a59e896083dbcabb10b46d78b33bd842d2284fa8b9ff6ff1c59d8091c"}],"walletId":"23c6433d-f981-41fa-94c6-8096afc4d397","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"bfdb31f5737b83790be533bd66bfffbbbd65eaa8d49a99f547683768756bec22","personalEncryptingKey":"M1aiow3pBWeSYMih3E/Acw==","sharedEncryptingKey":"6+P8AuOTZMFNgT+o3hD+BQ==","copayerName":"me","mnemonic":"echo caught churn turkey twin silent visit jewel warm hover bone kitchen","entropySource":"e1e07a2218c32122a3a3d03d578d2dfc465112d1a826830ebc88405bf4a3a606","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K3NQsKcimdhieY7LeoSkS2W1mfaH6LcTujt8S8EWjcVttzvft9LUkdLd35CRBBLQmZwm3HXACsYZfcGh3T3z2TQLiSX8gJxn","xPubKey":"xpub6CJNjqNcCCV9f77rhB9k1CSa2kQiuEPRdyB9L8YfcLJuUjKszP3TKK65X34bpURnPYeXsrbHBL6e9NHSrUZocP4dK7u691745FMwKj4pSGg","requestPrivKey":"ce3279e705e2bce3f2809245dadb7ee50886c1be81a67a63d02ccc565a9dc1a9","requestPubKey":"035826166a59e896083dbcabb10b46d78b33bd842d2284fa8b9ff6ff1c59d8091c","copayerId":"eb655f1ac4567e5a4a85ae007783ded41a51225bfb046377ce04fbafc8558a05","publicKeyRing":[{"xPubKey":"xpub6CJNjqNcCCV9f77rhB9k1CSa2kQiuEPRdyB9L8YfcLJuUjKszP3TKK65X34bpURnPYeXsrbHBL6e9NHSrUZocP4dK7u691745FMwKj4pSGg","requestPubKey":"035826166a59e896083dbcabb10b46d78b33bd842d2284fa8b9ff6ff1c59d8091c"}],"walletId":"c19b75e6-e0f4-4360-a0b5-87607559ee3c","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"c27b0d17bc62085ad6b08a8a4c967e65def306c642107ca3840380339d81eee9","personalEncryptingKey":"M1aiow3pBWeSYMih3E/Acw==","sharedEncryptingKey":"w5eq2OTn7v0fjnATHISeZg==","copayerName":"me","mnemonic":"echo caught churn turkey twin silent visit jewel warm hover bone kitchen","entropySource":"e1e07a2218c32122a3a3d03d578d2dfc465112d1a826830ebc88405bf4a3a606","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K3Wb3YBRHofV2poT3NCRL9yxhm9nYWEPJoTx4DrvfAsCtGSBFfiDXD4GvxuLosghdReCr65SzyHhYFwTLis3hMT8XkWjxT3v","xPubKey":"xpub6DWndawujFrKaQ1B5mFVeD51SuPPQkS4igUYRyoPHN7RnmJRZZwhRjeDYMhqZFLQQNu1sxsbMXXFB4b7kGYtUgFRMLRcBFF9jPbcgJ72iku","requestPrivKey":"ef9beed77a18fc2d56ddcede46aa306dd8277a196bbab971e99aac8eeb69a723","requestPubKey":"02781170de79d7bd3ea7cf8f293c7379575a0c340bbf9d81e88ec8b07a18c77394","copayerId":"d3e7adc7a6816b1eaebb7a8fae6683a9b5c249c6a6c9d0c0d6ea2e163a2ae0f6","publicKeyRing":[{"xPubKey":"xpub6DWndawujFrKaQ1B5mFVeD51SuPPQkS4igUYRyoPHN7RnmJRZZwhRjeDYMhqZFLQQNu1sxsbMXXFB4b7kGYtUgFRMLRcBFF9jPbcgJ72iku","requestPubKey":"02781170de79d7bd3ea7cf8f293c7379575a0c340bbf9d81e88ec8b07a18c77394"}],"walletId":"b97197ec-59a3-4aab-a716-2eb008899fd8","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"abbb8b79be569b2027b55bd1ed7d3c581314d432c2cc7933ff4c43311818955f","personalEncryptingKey":"+Arh5OgC4fS4SXVwnilPxA==","sharedEncryptingKey":"zRfn81E5mQlTWnekbRJ2GQ==","copayerName":"me","mnemonic":"twenty six jump dragon abuse dose pig muscle awful inject diagram alpha","entropySource":"026700d62c252a483a0434ffb9c2cf0ff333f77721affc97acb3c117056707cb","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K3Wb3YBRHofV2poT3NCRL9yxhm9nYWEPJoTx4DrvfAsCtGSBFfiDXD4GvxuLosghdReCr65SzyHhYFwTLis3hMT8XkWjxT3v","xPubKey":"xpub6DWndawujFrKaQ1B5mFVeD51SuPPQkS4igUYRyoPHN7RnmJRZZwhRjeDYMhqZFLQQNu1sxsbMXXFB4b7kGYtUgFRMLRcBFF9jPbcgJ72iku","requestPrivKey":"ef9beed77a18fc2d56ddcede46aa306dd8277a196bbab971e99aac8eeb69a723","requestPubKey":"02781170de79d7bd3ea7cf8f293c7379575a0c340bbf9d81e88ec8b07a18c77394","copayerId":"a77ccab4dd3251e005e9de214a9a29b7907dd79ab38e9046000223feb8d0578b","publicKeyRing":[{"xPubKey":"xpub6DWndawujFrKaQ1B5mFVeD51SuPPQkS4igUYRyoPHN7RnmJRZZwhRjeDYMhqZFLQQNu1sxsbMXXFB4b7kGYtUgFRMLRcBFF9jPbcgJ72iku","requestPubKey":"02781170de79d7bd3ea7cf8f293c7379575a0c340bbf9d81e88ec8b07a18c77394"}],"walletId":"7c0fd6ec-caa8-46d0-8664-8eb94d5234ef","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"779d0e969697bed9cee86719433afed30bb0f41a9a6acb93b380915c68013357","personalEncryptingKey":"+Arh5OgC4fS4SXVwnilPxA==","sharedEncryptingKey":"GHNFlK2m/uobw+94Gm1Etg==","copayerName":"me","mnemonic":"twenty six jump dragon abuse dose pig muscle awful inject diagram alpha","entropySource":"026700d62c252a483a0434ffb9c2cf0ff333f77721affc97acb3c117056707cb","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"23c6433d-f981-41fa-94c6-8096afc4d397":true,"c19b75e6-e0f4-4360-a0b5-87607559ee3c":true,"b97197ec-59a3-4aab-a716-2eb008899fd8":true,"7c0fd6ec-caa8-46d0-8664-8eb94d5234ef":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + oldProfile = '{"version":"1.0.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + secureProfile = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + secureProfileFromOldOnly = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + secureProfileMergedFromOld = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + beforeEach(function(){ module('ngLodash'); @@ -15,7 +20,8 @@ describe('storageService on mobile', function(){ module('copayApp.services'); fileStorageServiceMock = { - get: function(){} + get: function(){}, + remove: function(){} }; log = { @@ -30,7 +36,8 @@ describe('storageService on mobile', function(){ }; secureStorageServiceMock = { - get: function(){} + get: function(){}, + set: function(){} }; @@ -46,10 +53,45 @@ describe('storageService on mobile', function(){ }); + it('getProfile() from file storage.', function() { + var error, profile; + + spyOn(secureStorageServiceMock, 'get').and.callFake(function(k, cb){ + cb(null, null); + }); + + spyOn(fileStorageServiceMock, 'get').and.callFake(function(k, cb){ + cb(null, oldProfile); + }); + + spyOn(secureStorageServiceMock, 'set').and.callFake(function(k, v, cb){ + cb(null); + }); + + spyOn(fileStorageServiceMock, 'remove').and.callFake(function(k, cb){ + cb(null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error).toBeFalsy(); + expect(profile).toBeTruthy(); + expect(profile.appVersion).toBe('4.11.0'); + expect(profile.createdOn).toBe(1528363022385); + expect(profile.credentials[0].coin).toBe('bch'); + expect(profile.credentials[0].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[1].coin).toBe('btc'); + expect(profile.credentials[1].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + + + }); + it('getProfile() from secure storage.', function() { var error, profile; - spyOn(secureStorageServiceMock, 'get').and.callFake(function(k, cb){ cb(null, secureProfile); }); @@ -57,21 +99,25 @@ describe('storageService on mobile', function(){ spyOn(fileStorageServiceMock, 'get').and.callFake(function(k, cb){ cb(null, null); }); - - /* - secureStorageServiceMock.spyOn('get').and.callFake(function(cb){ - cb(null, 'the profile') - }); - */ - + //spyOn(secureStorageServiceMock, 'set').and.callFake(function(k, cb){ + // cb(null); + //}); + storageService.getProfile(function(err, p){ error = err; profile = p; }); - expect(profile).toBeTruthy(); expect(error).toBeFalsy(); + expect(profile).toBeTruthy(); + expect(profile.appVersion).toBe('4.11.0'); + expect(profile.createdOn).toBe(1528363260283); + expect(profile.credentials[0].coin).toBe('bch'); + expect(profile.credentials[0].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[1].coin).toBe('btc'); + expect(profile.credentials[1].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + }); From 0003604017b733aa4343491ca89eeedee7a82cdc Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 8 Jun 2018 08:12:24 +1200 Subject: [PATCH 20/34] Better use of mocks. --- src/js/services/storageService.spec.js | 46 ++++++++++++++------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index 42e9de249..e28f80cea 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -1,3 +1,4 @@ +// TODO: Error cases for all of these, at each step. describe('storageService on mobile', function(){ var fileStorageServiceMock, log, @@ -13,6 +14,11 @@ describe('storageService on mobile', function(){ secureProfileFromOldOnly = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; secureProfileMergedFromOld = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + log = { + debug: function(s){ console.log(s); }, + error: function(s){ console.log(s); }, + info: function(s){ console.log(s); } + }; beforeEach(function(){ module('ngLodash'); @@ -20,14 +26,8 @@ describe('storageService on mobile', function(){ module('copayApp.services'); fileStorageServiceMock = { - get: function(){}, - remove: function(){} - }; - - log = { - debug: function(s){ console.log(s); }, - error: function(s){ console.log(s); }, - info: function(s){ console.log(s); } + get: jasmine.createSpy(), + remove: jasmine.createSpy() }; platformInfoStub = { @@ -36,8 +36,8 @@ describe('storageService on mobile', function(){ }; secureStorageServiceMock = { - get: function(){}, - set: function(){} + get: jasmine.createSpy(), + set: jasmine.createSpy() }; @@ -56,19 +56,19 @@ describe('storageService on mobile', function(){ it('getProfile() from file storage.', function() { var error, profile; - spyOn(secureStorageServiceMock, 'get').and.callFake(function(k, cb){ + secureStorageServiceMock.get.and.callFake(function(k, cb){ cb(null, null); }); - spyOn(fileStorageServiceMock, 'get').and.callFake(function(k, cb){ + fileStorageServiceMock.get.and.callFake(function(k, cb){ cb(null, oldProfile); }); - spyOn(secureStorageServiceMock, 'set').and.callFake(function(k, v, cb){ + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ cb(null); }); - spyOn(fileStorageServiceMock, 'remove').and.callFake(function(k, cb){ + fileStorageServiceMock.remove.and.callFake(function(k, cb){ cb(null); }); @@ -81,28 +81,27 @@ describe('storageService on mobile', function(){ expect(profile).toBeTruthy(); expect(profile.appVersion).toBe('4.11.0'); expect(profile.createdOn).toBe(1528363022385); + expect(profile.credentials[0].coin).toBe('bch'); expect(profile.credentials[0].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[0].walletId).toBe('a8ea9291-1369-4862-90a1-d80a5d4bcc20'); + expect(profile.credentials[1].coin).toBe('btc'); expect(profile.credentials[1].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); - + expect(profile.credentials[1].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); }); it('getProfile() from secure storage.', function() { var error, profile; - spyOn(secureStorageServiceMock, 'get').and.callFake(function(k, cb){ + secureStorageServiceMock.get.and.callFake(function(k, cb){ cb(null, secureProfile); }); - spyOn(fileStorageServiceMock, 'get').and.callFake(function(k, cb){ + fileStorageServiceMock.get.and.callFake(function(k, cb){ cb(null, null); }); - - //spyOn(secureStorageServiceMock, 'set').and.callFake(function(k, cb){ - // cb(null); - //}); storageService.getProfile(function(err, p){ error = err; @@ -113,11 +112,14 @@ describe('storageService on mobile', function(){ expect(profile).toBeTruthy(); expect(profile.appVersion).toBe('4.11.0'); expect(profile.createdOn).toBe(1528363260283); + expect(profile.credentials[0].coin).toBe('bch'); expect(profile.credentials[0].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[0].walletId).toBe('9580929b-417d-4fce-bcbf-de8e16a51c25'); + expect(profile.credentials[1].coin).toBe('btc'); expect(profile.credentials[1].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); - + expect(profile.credentials[1].walletId).toBe('ef78459e-52b1-418a-b89d-4df2ef1d27ea'); }); From 02460bd3c57036eafce031e655d40d59e72c6eb1 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 8 Jun 2018 08:23:28 +1200 Subject: [PATCH 21/34] Uses the current app version when needed, when checking the appVersion of a profile. --- src/js/services/storageService.spec.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index e28f80cea..59f661d0d 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -1,6 +1,7 @@ // TODO: Error cases for all of these, at each step. describe('storageService on mobile', function(){ - var fileStorageServiceMock, + var appConfig, + fileStorageServiceMock, log, oldProfile, platformInfoStub, @@ -11,7 +12,7 @@ describe('storageService on mobile', function(){ oldProfile = '{"version":"1.0.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; secureProfile = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; - secureProfileFromOldOnly = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + secureProfileFromOldOnly = '{"version":"1.0.0","appVersion":"${appVersion}","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; secureProfileMergedFromOld = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; log = { @@ -48,9 +49,12 @@ describe('storageService on mobile', function(){ }); inject(function($injector){ + appConfig = $injector.get('appConfigService'); storageService = $injector.get('storageService'); }); + secureProfileFromOldOnly = secureProfileFromOldOnly.replace('${appVersion}', appConfig.version); + }); it('getProfile() from file storage.', function() { @@ -79,7 +83,7 @@ describe('storageService on mobile', function(){ expect(error).toBeFalsy(); expect(profile).toBeTruthy(); - expect(profile.appVersion).toBe('4.11.0'); + expect(profile.appVersion).toBe(appConfig.version); expect(profile.createdOn).toBe(1528363022385); expect(profile.credentials[0].coin).toBe('bch'); @@ -89,7 +93,6 @@ describe('storageService on mobile', function(){ expect(profile.credentials[1].coin).toBe('btc'); expect(profile.credentials[1].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); expect(profile.credentials[1].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); - }); it('getProfile() from secure storage.', function() { @@ -120,7 +123,6 @@ describe('storageService on mobile', function(){ expect(profile.credentials[1].coin).toBe('btc'); expect(profile.credentials[1].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); expect(profile.credentials[1].walletId).toBe('ef78459e-52b1-418a-b89d-4df2ef1d27ea'); - }); }); \ No newline at end of file From e52242bb1b37d487b44bfc78a31ac76af15e1889 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 8 Jun 2018 13:38:02 +1200 Subject: [PATCH 22/34] Testing profile merge. --- src/js/services/storageService.spec.js | 68 ++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index 59f661d0d..f00da3bfe 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -1,6 +1,8 @@ // TODO: Error cases for all of these, at each step. describe('storageService on mobile', function(){ var appConfig, + expectedOldProfileSavedToSecure, + expectedOldProfileMergedWithSecure, fileStorageServiceMock, log, oldProfile, @@ -10,11 +12,12 @@ describe('storageService on mobile', function(){ secureStorageServiceMock, storageService; + expectedOldProfileMergedWithSecure = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + expectedOldProfileSavedToSecure = '{"version":"1.0.0","appVersion":"${appVersion}","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; oldProfile = '{"version":"1.0.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; secureProfile = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; secureProfileFromOldOnly = '{"version":"1.0.0","appVersion":"${appVersion}","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; - secureProfileMergedFromOld = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; - + log = { debug: function(s){ console.log(s); }, error: function(s){ console.log(s); }, @@ -41,7 +44,6 @@ describe('storageService on mobile', function(){ set: jasmine.createSpy() }; - module(function($provide) { $provide.value('fileStorageService', fileStorageServiceMock); $provide.value('platformInfo', platformInfoStub); @@ -54,11 +56,12 @@ describe('storageService on mobile', function(){ }); secureProfileFromOldOnly = secureProfileFromOldOnly.replace('${appVersion}', appConfig.version); + expectedOldProfileSavedToSecure = expectedOldProfileSavedToSecure.replace('${appVersion}', appConfig.version); }); it('getProfile() from file storage.', function() { - var error, profile; + var error, profile, savedProfile; secureStorageServiceMock.get.and.callFake(function(k, cb){ cb(null, null); @@ -69,6 +72,7 @@ describe('storageService on mobile', function(){ }); secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + savedProfile = v; cb(null); }); @@ -83,6 +87,9 @@ describe('storageService on mobile', function(){ expect(error).toBeFalsy(); expect(profile).toBeTruthy(); + + expect(savedProfile).toBe(expectedOldProfileSavedToSecure); + expect(profile.appVersion).toBe(appConfig.version); expect(profile.createdOn).toBe(1528363022385); @@ -125,4 +132,57 @@ describe('storageService on mobile', function(){ expect(profile.credentials[1].walletId).toBe('ef78459e-52b1-418a-b89d-4df2ef1d27ea'); }); + it('getProfile() merge from local and secure storage.', function() { + var error, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, secureProfile); + }); + + fileStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + savedProfile = v; + cb(null); + }); + + fileStorageServiceMock.remove.and.callFake(function(k, cb){ + cb(null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error).toBeFalsy(); + expect(profile).toBeTruthy(); + + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); + + expect(profile.appVersion).toBe('4.11.0'); + expect(profile.createdOn).toBe(1528363260283); + + // Existing secure + expect(profile.credentials[0].coin).toBe('bch'); + expect(profile.credentials[0].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[0].walletId).toBe('9580929b-417d-4fce-bcbf-de8e16a51c25'); + + expect(profile.credentials[1].coin).toBe('btc'); + expect(profile.credentials[1].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[1].walletId).toBe('ef78459e-52b1-418a-b89d-4df2ef1d27ea'); + + // Old + expect(profile.credentials[2].coin).toBe('bch'); + expect(profile.credentials[2].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[2].walletId).toBe('a8ea9291-1369-4862-90a1-d80a5d4bcc20'); + + expect(profile.credentials[3].coin).toBe('btc'); + expect(profile.credentials[3].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[3].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); + + }); + }); \ No newline at end of file From 3aa9e70e6446dc17b80e19bbef21e0458fc02368 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 8 Jun 2018 14:07:46 +1200 Subject: [PATCH 23/34] All tests for profile migration. --- src/js/services/storageService.spec.js | 157 ++++++++++++++++++++++++- 1 file changed, 156 insertions(+), 1 deletion(-) diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index f00da3bfe..100aa981e 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -1,4 +1,3 @@ -// TODO: Error cases for all of these, at each step. describe('storageService on mobile', function(){ var appConfig, expectedOldProfileSavedToSecure, @@ -102,6 +101,102 @@ describe('storageService on mobile', function(){ expect(profile.credentials[1].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); }); + it('getProfile() from file storage, remove fails.', function() { + var error, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, null); + }); + + fileStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + savedProfile = v; + cb(null); + }); + + fileStorageServiceMock.remove.and.callFake(function(k, cb){ + cb(new Error('Remove error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Remove error.'); + expect(profile).toBeFalsy(); + + expect(savedProfile).toBe(expectedOldProfileSavedToSecure); + }); + + it('getProfile() from file storage, secure set fails, not removed.', function() { + var error, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, null); + }); + + fileStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + savedProfile = v; + cb(new Error('Set error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Set error.'); + expect(profile).toBeFalsy(); + + expect(savedProfile).toBe(expectedOldProfileSavedToSecure); + + expect(fileStorageServiceMock.remove.calls.any()).toBe(false); + }); + + it('getProfile(), secure get fails.', function() { + var error, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + cb(new Error('Secure get error.'), null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Secure get error.'); + expect(profile).toBeFalsy(); + }); + + it('getProfile(), secure get succeeds, file storage get fails.', function() { + var error, profile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, secureProfile); + }); + + fileStorageServiceMock.get.and.callFake(function(k, cb){ + cb(new Error('File storage get error.'), null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('File storage get error.'); + expect(profile).toBeFalsy(); + }); + it('getProfile() from secure storage.', function() { var error, profile; @@ -185,4 +280,64 @@ describe('storageService on mobile', function(){ }); + it('getProfile() merge from local and secure storage, secure set fails, not removed from local.', function() { + var error, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, secureProfile); + }); + + fileStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + savedProfile = v; + cb(new Error('Secure set error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Secure set error.'); + expect(profile).toBeFalsy(); + + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); + + expect(fileStorageServiceMock.remove.calls.any()).toBe(false); + }); + + it('getProfile() merge from local and secure storage, remove from local fails.', function() { + var error, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, secureProfile); + }); + + fileStorageServiceMock.get.and.callFake(function(k, cb){ + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + savedProfile = v; + cb(null); + }); + + fileStorageServiceMock.remove.and.callFake(function(k, cb){ + cb(new Error('Remove error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Remove error.'); + expect(profile).toBeFalsy(); + + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); + }); + }); \ No newline at end of file From a09069463a8abef55c299a0a08457a8d6b5ec20f Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 8 Jun 2018 14:31:35 +1200 Subject: [PATCH 24/34] Checking key names in tests. --- src/js/services/storageService.spec.js | 89 +++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index 100aa981e..767cb3283 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -1,3 +1,5 @@ + + describe('storageService on mobile', function(){ var appConfig, expectedOldProfileSavedToSecure, @@ -60,22 +62,26 @@ describe('storageService on mobile', function(){ }); it('getProfile() from file storage.', function() { - var error, profile, savedProfile; + var error, keySecureGet, keyFileGet, keySecureSet, keyFileRemove, profile, savedProfile; secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; cb(null, null); }); fileStorageServiceMock.get.and.callFake(function(k, cb){ + keyFileGet = k; cb(null, oldProfile); }); secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; savedProfile = v; cb(null); }); fileStorageServiceMock.remove.and.callFake(function(k, cb){ + keyFileRemove = k; cb(null); }); @@ -87,7 +93,13 @@ describe('storageService on mobile', function(){ expect(error).toBeFalsy(); expect(profile).toBeTruthy(); + expect(keySecureGet).toBe('profile'); + expect(keyFileGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyFileRemove).toBe('profile'); + expect(savedProfile).toBe(expectedOldProfileSavedToSecure); + expect(fileStorageServiceMock.remove.calls.any()).toBe(true); expect(profile.appVersion).toBe(appConfig.version); expect(profile.createdOn).toBe(1528363022385); @@ -102,22 +114,26 @@ describe('storageService on mobile', function(){ }); it('getProfile() from file storage, remove fails.', function() { - var error, profile, savedProfile; + var error, keySecureGet, keyFileGet, keySecureSet, keyFileRemove, profile, profile, savedProfile; secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; cb(null, null); }); fileStorageServiceMock.get.and.callFake(function(k, cb){ + keyFileGet = k; cb(null, oldProfile); }); secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; savedProfile = v; cb(null); }); fileStorageServiceMock.remove.and.callFake(function(k, cb){ + keyFileRemove = k; cb(new Error('Remove error.')); }); @@ -129,21 +145,29 @@ describe('storageService on mobile', function(){ expect(error.message).toBe('Remove error.'); expect(profile).toBeFalsy(); + expect(keySecureGet).toBe('profile'); + expect(keyFileGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyFileRemove).toBe('profile'); + expect(savedProfile).toBe(expectedOldProfileSavedToSecure); }); it('getProfile() from file storage, secure set fails, not removed.', function() { - var error, profile, savedProfile; + var error, keySecureGet, keyFileGet, keySecureSet, profile, profile, savedProfile; secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; cb(null, null); }); fileStorageServiceMock.get.and.callFake(function(k, cb){ + keyFileGet = k; cb(null, oldProfile); }); secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; savedProfile = v; cb(new Error('Set error.')); }); @@ -156,15 +180,20 @@ describe('storageService on mobile', function(){ expect(error.message).toBe('Set error.'); expect(profile).toBeFalsy(); + expect(keySecureGet).toBe('profile'); + expect(keyFileGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(savedProfile).toBe(expectedOldProfileSavedToSecure); expect(fileStorageServiceMock.remove.calls.any()).toBe(false); }); it('getProfile(), secure get fails.', function() { - var error, profile, savedProfile; + var error, keySecureGet, profile, profile, savedProfile; secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; cb(new Error('Secure get error.'), null); }); @@ -175,16 +204,22 @@ describe('storageService on mobile', function(){ expect(error.message).toBe('Secure get error.'); expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + + expect(fileStorageServiceMock.remove.calls.any()).toBe(false); }); it('getProfile(), secure get succeeds, file storage get fails.', function() { - var error, profile; + var error, keySecureGet, keyFileGet, profile, profile; secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; cb(null, secureProfile); }); fileStorageServiceMock.get.and.callFake(function(k, cb){ + keyFileGet = k; cb(new Error('File storage get error.'), null); }); @@ -195,16 +230,23 @@ describe('storageService on mobile', function(){ expect(error.message).toBe('File storage get error.'); expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + expect(keyFileGet).toBe('profile'); + + expect(fileStorageServiceMock.remove.calls.any()).toBe(false); }); it('getProfile() from secure storage.', function() { - var error, profile; + var error, keySecureGet, keyFileGet, profile, profile; secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; cb(null, secureProfile); }); fileStorageServiceMock.get.and.callFake(function(k, cb){ + keyFileGet = k; cb(null, null); }); @@ -215,6 +257,10 @@ describe('storageService on mobile', function(){ expect(error).toBeFalsy(); expect(profile).toBeTruthy(); + + expect(keySecureGet).toBe('profile'); + expect(keyFileGet).toBe('profile'); + expect(profile.appVersion).toBe('4.11.0'); expect(profile.createdOn).toBe(1528363260283); @@ -228,22 +274,26 @@ describe('storageService on mobile', function(){ }); it('getProfile() merge from local and secure storage.', function() { - var error, profile, savedProfile; + var error, keySecureGet, keyFileGet, keySecureSet, keyFileRemove, profile, profile, savedProfile; secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; cb(null, secureProfile); }); fileStorageServiceMock.get.and.callFake(function(k, cb){ + keyFileGet = k; cb(null, oldProfile); }); secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; savedProfile = v; cb(null); }); fileStorageServiceMock.remove.and.callFake(function(k, cb){ + keyFileRemove = k; cb(null); }); @@ -255,6 +305,11 @@ describe('storageService on mobile', function(){ expect(error).toBeFalsy(); expect(profile).toBeTruthy(); + expect(keySecureGet).toBe('profile'); + expect(keyFileGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyFileRemove).toBe('profile'); + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); expect(profile.appVersion).toBe('4.11.0'); @@ -281,17 +336,20 @@ describe('storageService on mobile', function(){ }); it('getProfile() merge from local and secure storage, secure set fails, not removed from local.', function() { - var error, profile, savedProfile; + var error, keySecureGet, keyFileGet, keySecureSet, profile, profile, savedProfile; secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; cb(null, secureProfile); }); fileStorageServiceMock.get.and.callFake(function(k, cb){ + keyFileGet = k; cb(null, oldProfile); }); secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; savedProfile = v; cb(new Error('Secure set error.')); }); @@ -304,28 +362,36 @@ describe('storageService on mobile', function(){ expect(error.message).toBe('Secure set error.'); expect(profile).toBeFalsy(); + expect(keySecureGet).toBe('profile'); + expect(keyFileGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); expect(fileStorageServiceMock.remove.calls.any()).toBe(false); }); it('getProfile() merge from local and secure storage, remove from local fails.', function() { - var error, profile, savedProfile; + var error, keySecureGet, keyFileGet, keySecureSet, keyFileRemove, profile, profile, savedProfile; secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; cb(null, secureProfile); }); fileStorageServiceMock.get.and.callFake(function(k, cb){ + keyFileGet = k; cb(null, oldProfile); }); secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k savedProfile = v; cb(null); }); fileStorageServiceMock.remove.and.callFake(function(k, cb){ + keyFileRemove = k; cb(new Error('Remove error.')); }); @@ -337,6 +403,11 @@ describe('storageService on mobile', function(){ expect(error.message).toBe('Remove error.'); expect(profile).toBeFalsy(); + expect(keySecureGet).toBe('profile'); + expect(keyFileGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyFileRemove).toBe('profile'); + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); }); From 522a7cd3cf3b64423b753149ef0accc7a9ae1cc5 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 8 Jun 2018 14:49:01 +1200 Subject: [PATCH 25/34] Migration tests for desktop. --- src/js/services/storageService.spec.js | 411 +++++++++++++++++++++++++ 1 file changed, 411 insertions(+) diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index 767cb3283..316a909d8 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -1,4 +1,415 @@ +describe('storageService on desktop', function(){ + var appConfig, + expectedOldProfileSavedToSecure, + expectedOldProfileMergedWithSecure, + localStorageServiceMock, + log, + oldProfile, + platformInfoStub, + savedSecureProfile, + secureStorageService, + secureStorageServiceMock, + storageService; + expectedOldProfileMergedWithSecure = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + expectedOldProfileSavedToSecure = '{"version":"1.0.0","appVersion":"${appVersion}","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + oldProfile = '{"version":"1.0.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + secureProfile = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + secureProfileFromOldOnly = '{"version":"1.0.0","appVersion":"${appVersion}","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + + log = { + debug: function(s){ console.log(s); }, + error: function(s){ console.log(s); }, + info: function(s){ console.log(s); } + }; + + beforeEach(function(){ + module('ngLodash'); + module('bwcModule'); + module('copayApp.services'); + + localStorageServiceMock = { + get: jasmine.createSpy(), + remove: jasmine.createSpy() + }; + + platformInfoStub = { + isCordova: false + }; + + secureStorageServiceMock = { + get: jasmine.createSpy(), + set: jasmine.createSpy() + }; + + module(function($provide) { + $provide.value('localStorageService', localStorageServiceMock); + //$provide.value('$log', log); // Handy for debugging test failures + $provide.value('platformInfo', platformInfoStub); + $provide.value('secureStorageService', secureStorageServiceMock); + }); + + inject(function($injector){ + appConfig = $injector.get('appConfigService'); + storageService = $injector.get('storageService'); + }); + + secureProfileFromOldOnly = secureProfileFromOldOnly.replace('${appVersion}', appConfig.version); + expectedOldProfileSavedToSecure = expectedOldProfileSavedToSecure.replace('${appVersion}', appConfig.version); + + }); + + it('getProfile() from local storage.', function() { + var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, null); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfile = v; + cb(null); + }); + + localStorageServiceMock.remove.and.callFake(function(k, cb){ + keyLocalRemove = k; + cb(null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error).toBeFalsy(); + expect(profile).toBeTruthy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyLocalRemove).toBe('profile'); + + expect(savedProfile).toBe(expectedOldProfileSavedToSecure); + expect(localStorageServiceMock.remove.calls.any()).toBe(true); + + expect(profile.appVersion).toBe(appConfig.version); + expect(profile.createdOn).toBe(1528363022385); + + expect(profile.credentials[0].coin).toBe('bch'); + expect(profile.credentials[0].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[0].walletId).toBe('a8ea9291-1369-4862-90a1-d80a5d4bcc20'); + + expect(profile.credentials[1].coin).toBe('btc'); + expect(profile.credentials[1].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[1].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); + }); + + it('getProfile() from file storage, remove fails.', function() { + var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, null); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfile = v; + cb(null); + }); + + localStorageServiceMock.remove.and.callFake(function(k, cb){ + keyLocalRemove = k; + cb(new Error('Remove error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Remove error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyLocalRemove).toBe('profile'); + + expect(savedProfile).toBe(expectedOldProfileSavedToSecure); + }); + + it('getProfile() from file storage, secure set fails, not removed.', function() { + var error, keySecureGet, keyLocalGet, keySecureSet, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, null); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfile = v; + cb(new Error('Set error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Set error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + + expect(savedProfile).toBe(expectedOldProfileSavedToSecure); + + expect(localStorageServiceMock.remove.calls.any()).toBe(false); + }); + + it('getProfile(), secure get fails.', function() { + var error, keySecureGet, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(new Error('Secure get error.'), null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Secure get error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + + expect(localStorageServiceMock.remove.calls.any()).toBe(false); + }); + + it('getProfile(), secure get succeeds, file storage get fails.', function() { + var error, keySecureGet, keyLocalGet, profile, profile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, secureProfile); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(new Error('File storage get error.'), null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('File storage get error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + + expect(localStorageServiceMock.remove.calls.any()).toBe(false); + }); + + it('getProfile() from secure storage.', function() { + var error, keySecureGet, keyLocalGet, profile, profile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, secureProfile); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error).toBeFalsy(); + expect(profile).toBeTruthy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + + expect(profile.appVersion).toBe('4.11.0'); + expect(profile.createdOn).toBe(1528363260283); + + expect(profile.credentials[0].coin).toBe('bch'); + expect(profile.credentials[0].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[0].walletId).toBe('9580929b-417d-4fce-bcbf-de8e16a51c25'); + + expect(profile.credentials[1].coin).toBe('btc'); + expect(profile.credentials[1].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[1].walletId).toBe('ef78459e-52b1-418a-b89d-4df2ef1d27ea'); + }); + + it('getProfile() merge from local and secure storage.', function() { + var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, secureProfile); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfile = v; + cb(null); + }); + + localStorageServiceMock.remove.and.callFake(function(k, cb){ + keyLocalRemove = k; + cb(null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error).toBeFalsy(); + expect(profile).toBeTruthy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyLocalRemove).toBe('profile'); + + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); + + expect(profile.appVersion).toBe('4.11.0'); + expect(profile.createdOn).toBe(1528363260283); + + // Existing secure + expect(profile.credentials[0].coin).toBe('bch'); + expect(profile.credentials[0].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[0].walletId).toBe('9580929b-417d-4fce-bcbf-de8e16a51c25'); + + expect(profile.credentials[1].coin).toBe('btc'); + expect(profile.credentials[1].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[1].walletId).toBe('ef78459e-52b1-418a-b89d-4df2ef1d27ea'); + + // Old + expect(profile.credentials[2].coin).toBe('bch'); + expect(profile.credentials[2].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[2].walletId).toBe('a8ea9291-1369-4862-90a1-d80a5d4bcc20'); + + expect(profile.credentials[3].coin).toBe('btc'); + expect(profile.credentials[3].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[3].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); + + }); + + it('getProfile() merge from local and secure storage, secure set fails, not removed from local.', function() { + var error, keySecureGet, keyLocalGet, keySecureSet, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, secureProfile); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfile = v; + cb(new Error('Secure set error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Secure set error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); + + expect(localStorageServiceMock.remove.calls.any()).toBe(false); + }); + + it('getProfile() merge from local and secure storage, remove from local fails.', function() { + var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, secureProfile); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k + savedProfile = v; + cb(null); + }); + + localStorageServiceMock.remove.and.callFake(function(k, cb){ + keyLocalRemove = k; + cb(new Error('Remove error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Remove error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyLocalRemove).toBe('profile'); + + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); + }); + +}); describe('storageService on mobile', function(){ var appConfig, From da9559433fdb87bf445dcffbeb7457168f198b5a Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 8 Jun 2018 15:06:56 +1200 Subject: [PATCH 26/34] First test for the secureStorageService. --- src/js/services/secureStorageService.spec.js | 49 ++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/js/services/secureStorageService.spec.js diff --git a/src/js/services/secureStorageService.spec.js b/src/js/services/secureStorageService.spec.js new file mode 100644 index 000000000..e22563536 --- /dev/null +++ b/src/js/services/secureStorageService.spec.js @@ -0,0 +1,49 @@ +describe('secureStorageService on desktop', function(){ + var desktopSss, + sss; + + beforeEach(function(){ + module('ngLodash'); + module('copayApp.services'); + + desktopSss = { + get: jasmine.createSpy(), + set: jasmine.createSpy() + }; + + platformInfoStub = { + isNW: true + }; + + module(function($provide) { + $provide.value('desktopSecureStorageService', desktopSss); + //$provide.value('$log', log); // Handy for debugging test failures + $provide.value('platformInfo', platformInfoStub); + }); + + inject(function($injector){ + sss = $injector.get('secureStorageService'); + }); + + }); + + it('get succeeds', function() { + var error, key, result; + + desktopSss.get.and.callFake(function(k, cb){ + key = k; + cb(null, 'The result 1.'); + }); + + sss.get('a123', function(e, res) { + error = e; + result = res; + }); + + expect(error).toBeFalsy(); + expect(result).toBe('The result 1.'); + expect(key).toBe('a123'); + }); + +}); + \ No newline at end of file From f4642b1953c4c52c959ee9d45b0d090553f83d75 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 8 Jun 2018 16:19:50 +1200 Subject: [PATCH 27/34] All tests for secure storage service on desktop. --- src/js/services/secureStorageService.spec.js | 55 +++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/js/services/secureStorageService.spec.js b/src/js/services/secureStorageService.spec.js index e22563536..0b2684895 100644 --- a/src/js/services/secureStorageService.spec.js +++ b/src/js/services/secureStorageService.spec.js @@ -17,7 +17,6 @@ describe('secureStorageService on desktop', function(){ module(function($provide) { $provide.value('desktopSecureStorageService', desktopSss); - //$provide.value('$log', log); // Handy for debugging test failures $provide.value('platformInfo', platformInfoStub); }); @@ -27,6 +26,24 @@ describe('secureStorageService on desktop', function(){ }); + it('get fails', function() { + var error, key, result; + + desktopSss.get.and.callFake(function(k, cb){ + key = k; + cb(new Error('Get error.'), null); + }); + + sss.get('a1234', function(e, res) { + error = e; + result = res; + }); + + expect(error.message).toBe('Get error.'); + expect(result).toBeFalsy(); + expect(key).toBe('a1234'); + }); + it('get succeeds', function() { var error, key, result; @@ -45,5 +62,41 @@ describe('secureStorageService on desktop', function(){ expect(key).toBe('a123'); }); + it('set fails', function() { + var error, key, value; + + desktopSss.set.and.callFake(function(k, v, cb){ + key = k; + value = v; + cb(new Error('Set error.')); + }); + + sss.set('a12345', 'The value 1.', function(e) { + error = e; + }); + + expect(error.message).toBe('Set error.'); + expect(key).toBe('a12345'); + expect(value).toBe('The value 1.'); + }); + + it('set succeeds', function() { + var error, key, value; + + desktopSss.set.and.callFake(function(k, v, cb){ + key = k; + value = v; + cb(null); + }); + + sss.set('ab123', 'The value 2.', function(e) { + error = e; + }); + + expect(error).toBeFalsy(); + expect(key).toBe('ab123'); + expect(value).toBe('The value 2.') + }); + }); \ No newline at end of file From 18581e9608881147f3d0e31edc1783202b883c08 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Fri, 8 Jun 2018 16:24:15 +1200 Subject: [PATCH 28/34] Test for secureStorageService on mobile and browser. --- src/js/services/secureStorageService.spec.js | 206 +++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/src/js/services/secureStorageService.spec.js b/src/js/services/secureStorageService.spec.js index 0b2684895..abfa5d947 100644 --- a/src/js/services/secureStorageService.spec.js +++ b/src/js/services/secureStorageService.spec.js @@ -1,3 +1,105 @@ +describe('secureStorageService in browser', function(){ + var localStorage, + sss; + + beforeEach(function(){ + module('ngLodash'); + module('copayApp.services'); + + localStorage = { + get: jasmine.createSpy(), + set: jasmine.createSpy() + }; + + platformInfoStub = { + }; + + module(function($provide) { + $provide.value('localStorageService', localStorage); + $provide.value('platformInfo', platformInfoStub); + }); + + inject(function($injector){ + sss = $injector.get('secureStorageService'); + }); + + }); + + it('get fails', function() { + var error, key, result; + + localStorage.get.and.callFake(function(k, cb){ + key = k; + cb(new Error('Get error.'), null); + }); + + sss.get('a1234', function(e, res) { + error = e; + result = res; + }); + + expect(error.message).toBe('Get error.'); + expect(result).toBeFalsy(); + expect(key).toBe('a1234:desiredSecure'); + }); + + it('get succeeds', function() { + var error, key, result; + + localStorage.get.and.callFake(function(k, cb){ + key = k; + cb(null, 'The result 1.'); + }); + + sss.get('a123', function(e, res) { + error = e; + result = res; + }); + + expect(error).toBeFalsy(); + expect(result).toBe('The result 1.'); + expect(key).toBe('a123:desiredSecure'); + }); + + it('set fails', function() { + var error, key, value; + + localStorage.set.and.callFake(function(k, v, cb){ + key = k; + value = v; + cb(new Error('Set error.')); + }); + + sss.set('a12345', 'The value 1.', function(e) { + error = e; + }); + + expect(error.message).toBe('Set error.'); + expect(key).toBe('a12345:desiredSecure'); + expect(value).toBe('The value 1.'); + }); + + it('set succeeds', function() { + var error, key, value; + + localStorage.set.and.callFake(function(k, v, cb){ + key = k; + value = v; + cb(null); + }); + + sss.set('ab123', 'The value 2.', function(e) { + error = e; + }); + + expect(error).toBeFalsy(); + expect(key).toBe('ab123:desiredSecure'); + expect(value).toBe('The value 2.') + }); + +}); + + describe('secureStorageService on desktop', function(){ var desktopSss, sss; @@ -99,4 +201,108 @@ describe('secureStorageService on desktop', function(){ }); }); + +describe('secureStorageService on mobile', function(){ + var mobileSss, + sss; + + beforeEach(function(){ + module('ngLodash'); + module('copayApp.services'); + + mobileSss = { + get: jasmine.createSpy(), + set: jasmine.createSpy() + }; + + platformInfoStub = { + isMobile: true + }; + + module(function($provide) { + $provide.value('mobileSecureStorageService', mobileSss); + $provide.value('platformInfo', platformInfoStub); + }); + + inject(function($injector){ + sss = $injector.get('secureStorageService'); + }); + + }); + + it('get fails', function() { + var error, key, result; + + mobileSss.get.and.callFake(function(k, cb){ + key = k; + cb(new Error('Get error.'), null); + }); + + sss.get('a1234', function(e, res) { + error = e; + result = res; + }); + + expect(error.message).toBe('Get error.'); + expect(result).toBeFalsy(); + expect(key).toBe('a1234'); + }); + + it('get succeeds', function() { + var error, key, result; + + mobileSss.get.and.callFake(function(k, cb){ + key = k; + cb(null, 'The result 1.'); + }); + + sss.get('a123', function(e, res) { + error = e; + result = res; + }); + + expect(error).toBeFalsy(); + expect(result).toBe('The result 1.'); + expect(key).toBe('a123'); + }); + + it('set fails', function() { + var error, key, value; + + mobileSss.set.and.callFake(function(k, v, cb){ + key = k; + value = v; + cb(new Error('Set error.')); + }); + + sss.set('a12345', 'The value 1.', function(e) { + error = e; + }); + + expect(error.message).toBe('Set error.'); + expect(key).toBe('a12345'); + expect(value).toBe('The value 1.'); + }); + + it('set succeeds', function() { + var error, key, value; + + mobileSss.set.and.callFake(function(k, v, cb){ + key = k; + value = v; + cb(null); + }); + + sss.set('ab123', 'The value 2.', function(e) { + error = e; + }); + + expect(error).toBeFalsy(); + expect(key).toBe('ab123'); + expect(value).toBe('The value 2.') + }); + +}); + + \ No newline at end of file From 12990d7f71a68f3fffa746c9054a7aae2d5573c6 Mon Sep 17 00:00:00 2001 From: Sam Cheng Hung Date: Fri, 8 Jun 2018 12:06:12 +0530 Subject: [PATCH 29/34] Update: Changes icon design and color scheme for default wallet colors --- src/js/services/configService.js | 4 +- src/sass/variables.scss | 4 +- www/css/main.css | 20 ++++++---- www/img/icon-wallet.svg | 63 +------------------------------- 4 files changed, 18 insertions(+), 73 deletions(-) diff --git a/src/js/services/configService.js b/src/js/services/configService.js index 1e46da03a..e8ed93d88 100644 --- a/src/js/services/configService.js +++ b/src/js/services/configService.js @@ -115,8 +115,8 @@ angular.module('copayApp.services').factory('configService', function(storageSer bitcoinAlias: 'btc', bitcoinCashAlias: 'bch', - bitcoinWalletColor: '#fab915', // Observatory - bitcoinCashWalletColor: '#26B03C', // Dollar Green + bitcoinWalletColor: '#535353', // Dark Grey + bitcoinCashWalletColor: '#eeb640', // Observatory homeSectionIsHidden: { services: false diff --git a/src/sass/variables.scss b/src/sass/variables.scss index e5bd2712d..cb21c030a 100644 --- a/src/sass/variables.scss +++ b/src/sass/variables.scss @@ -33,8 +33,8 @@ $v-wallet-color-map: ( 3: (color: #d0b136, name: 'Metallic Gold'), 4: (color: #9edd72, name: 'Feijoa'), 5: (color: #29bb9c, name: 'Shamrock'), - 6: (color: #26B03C, name: 'Dollar Green'), - 7: (color: #fab915, name: 'Observatory'), + 6: (color: #eeb640, name: 'Light Orange'), + 7: (color: #535353, name: 'Dark Grey'), 8: (color: #77dada, name: 'Turquoise Blue'), 9: (color: #4a90e2, name: 'Cornflower Blue'), 10: (color: #484ed3, name: 'Free Speech Blue'), diff --git a/www/css/main.css b/www/css/main.css index 4e7faac0a..46db3b975 100644 --- a/www/css/main.css +++ b/www/css/main.css @@ -10726,6 +10726,12 @@ textarea.d-block { #tab-home .card .item-sub:before { width: 90%; } } +#tab-home .card-banner { + padding: 0; } + #tab-home .card-banner__img { + width: 100%; + display: block; } + #tab-home .wallet-coin-logo { vertical-align: middle; margin-right: 5px; } @@ -11305,13 +11311,13 @@ textarea.d-block { /* background-color and color defaults should be the same */ .wallet-background-color-default { - background-color: #fab915; } + background-color: #535353; } .wallet-color-default { - color: #fab915; } + color: #535353; } .cashwallet-color-default { - color: #26B03C; } + color: #eeb640; } /* generate classes for all colors */ .wallet-color-0 { @@ -11357,17 +11363,17 @@ textarea.d-block { margin-left: 2.4rem; } .wallet-color-6 { - background: #26B03C; } + background: #eeb640; } .wallet-color-6:before { - content: "Dollar Green"; + content: "Light Orange"; margin-left: 2.4rem; } .wallet-color-7 { - background: #fab915; } + background: #535353; } .wallet-color-7:before { - content: "Observatory"; + content: "Dark Grey"; margin-left: 2.4rem; } .wallet-color-8 { diff --git a/www/img/icon-wallet.svg b/www/img/icon-wallet.svg index fba9bca0b..74c7055f2 100644 --- a/www/img/icon-wallet.svg +++ b/www/img/icon-wallet.svg @@ -1,62 +1 @@ - -image/svg+xml - \ No newline at end of file +icon-wallet \ No newline at end of file From 078f5bd61d5ba429904023f744e2cf2541eaefdf Mon Sep 17 00:00:00 2001 From: Sam Cheng Hung Date: Fri, 8 Jun 2018 12:20:37 +0530 Subject: [PATCH 30/34] Update: Changes shadow specification for wallet icons --- src/sass/icons.scss | 2 +- www/css/main.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sass/icons.scss b/src/sass/icons.scss index 4693025f6..7d14f8886 100644 --- a/src/sass/icons.scss +++ b/src/sass/icons.scss @@ -40,7 +40,7 @@ border-radius: $v-icon-border-radius; width: 40px; height: 40px; - box-shadow: $v-hovering-box-shadow; + box-shadow: 0px 0px 9px 0px rgba(0, 0, 0, 0.3); background-repeat:no-repeat; background-clip: padding-box; background-size: 103%; diff --git a/www/css/main.css b/www/css/main.css index 46db3b975..b4e67edac 100644 --- a/www/css/main.css +++ b/www/css/main.css @@ -10005,7 +10005,7 @@ ion-view.deflash-blue:before, ion-view#view-amount:before, ion-view#view-confirm border-radius: 3px; width: 40px; height: 40px; - box-shadow: 0px 6px 12px 0px rgba(0, 0, 0, 0.3); + box-shadow: 0px 0px 9px 0px rgba(0, 0, 0, 0.3); background-repeat: no-repeat; background-clip: padding-box; background-size: 103%; } From 435c2cacd47354d19eb96c03eb54bb0b52fa6e40 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Mon, 11 Jun 2018 12:23:39 +1200 Subject: [PATCH 31/34] Desktop using local storage only. --- src/js/services/storageService.js | 58 ++-- src/js/services/storageService.spec.js | 381 ++++++++++++++++++++++++- 2 files changed, 422 insertions(+), 17 deletions(-) diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 2dc3d7511..de4aa9b54 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -129,6 +129,37 @@ angular.module('copayApp.services') * @param {Profile} profile - falsy if error or profile not found. */ + + /** + * @param {Error} error + * @param {String} profileStr - containing the profile + * @param {getProfileCallback} cb + */ + function _onOldProfileRetrieved(error, profileStr, cb) { + if (error) { + return cb(error, null); + } + + if (!profileStr) { + // No profiles found. No errors either. + return cb(null, null); + } + + decryptOnMobile(profileStr, function(decryptErr, decryptedStr) { + if (decryptErr) return cb(decryptErr, null); + var profile; + try { + profile = Profile.fromString(decryptedStr); + } catch (e) { + $log.debug('Could not read profile:', e); + return(new Error('Could not read profile.'), null); + } + cb(null, profile) + }); + } + + + /** * * @param {Profile} oldProfile @@ -169,6 +200,13 @@ angular.module('copayApp.services') * @param {getProfileCallback} cb */ root.getProfile = function(cb) { + if (platformInfo.isNW) { + storage.get('profile', function(getErr, getStr) { + _onOldProfileRetrieved(getErr, getStr, cb); + }); + return + } + secureStorageService.get('profile', function(secureErr, secureStr) { var secureProfile; var oldProfile; @@ -188,11 +226,12 @@ angular.module('copayApp.services') } storage.get('profile', function(getErr, getStr) { - if (getErr) { - return cb(getErr); + _onOldProfileRetrieved(getErr, getStr, function(oldErr, oldProfile){ + if (oldErr) { + return cb(oldErr, null); } - if (!getStr) { + if (!oldProfile) { if (secureProfile) { return cb(null, secureProfile); } else { @@ -200,20 +239,7 @@ angular.module('copayApp.services') return cb(null, null); } } - - decryptOnMobile(getStr, function(err, str) { - if (err) return cb(err); - var p, err; - try { - oldProfile = Profile.fromString(str); - } catch (e) { - $log.debug('Could not read profile:', e); - err = new Error('Could not read profile.'); - return(err, null); - } - _migrateProfiles(oldProfile, secureProfile, cb); - }); }); }); diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index 316a909d8..88ed99d5f 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -1,4 +1,4 @@ -describe('storageService on desktop', function(){ +xdescribe('storageService on desktop', function(){ var appConfig, expectedOldProfileSavedToSecure, expectedOldProfileMergedWithSecure, @@ -411,6 +411,385 @@ describe('storageService on desktop', function(){ }); +describe('storageService on desktop using old storage', function(){ + var appConfig, + localStorageServiceMock, + log, + oldProfile, + platformInfoStub, + secureStorageService, + secureStorageServiceMock, + storageService; + + oldProfile = '{"version":"1.0.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + + log = { + debug: function(s){ console.log(s); }, + error: function(s){ console.log(s); }, + info: function(s){ console.log(s); } + }; + + beforeEach(function(){ + module('ngLodash'); + module('bwcModule'); + module('copayApp.services'); + + localStorageServiceMock = { + get: jasmine.createSpy(), + remove: jasmine.createSpy() + }; + + platformInfoStub = { + isCordova: false, + isNW: true + }; + + secureStorageServiceMock = { + get: jasmine.createSpy(), + set: jasmine.createSpy() + }; + + module(function($provide) { + $provide.value('localStorageService', localStorageServiceMock); + //$provide.value('$log', log); // Handy for debugging test failures + $provide.value('platformInfo', platformInfoStub); + $provide.value('secureStorageService', secureStorageServiceMock); + }); + + inject(function($injector){ + appConfig = $injector.get('appConfigService'); + storageService = $injector.get('storageService'); + }); + + secureProfileFromOldOnly = secureProfileFromOldOnly.replace('${appVersion}', appConfig.version); + expectedOldProfileSavedToSecure = expectedOldProfileSavedToSecure.replace('${appVersion}', appConfig.version); + + }); + + fit('getProfile() from local storage.', function() { + var error, keyLocalGet, profile; + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error).toBeFalsy(); + expect(profile).toBeTruthy(); + + expect(keyLocalGet).toBe('profile'); + + expect(localStorageServiceMock.remove.calls.any()).toBe(false); + expect(secureStorageServiceMock.get.calls.any()).toBe(false); + expect(secureStorageServiceMock.set.calls.any()).toBe(false); + + expect(profile.appVersion).toBeUndefined(); + expect(profile.createdOn).toBe(1528363022385); + + expect(profile.credentials[0].coin).toBe('bch'); + expect(profile.credentials[0].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[0].walletId).toBe('a8ea9291-1369-4862-90a1-d80a5d4bcc20'); + + expect(profile.credentials[1].coin).toBe('btc'); + expect(profile.credentials[1].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[1].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); + }); + + fit('getProfile() from local storage, get fails.', function() { + var error, keyLocalGet, profile; + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(new Error('Local get error.'), null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBeFalsy('Local get error.'); + expect(profile).toBeFalsy(); + + expect(keyLocalGet).toBe('profile'); + + expect(localStorageServiceMock.remove.calls.any()).toBe(false); + expect(secureStorageServiceMock.get.calls.any()).toBe(false); + expect(secureStorageServiceMock.set.calls.any()).toBe(false); + + expect(profile.appVersion).toBeUndefined(); + expect(profile.createdOn).toBe(1528363022385); + }); + + it('getProfile() from file storage, remove fails.', function() { + var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, null); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfile = v; + cb(null); + }); + + localStorageServiceMock.remove.and.callFake(function(k, cb){ + keyLocalRemove = k; + cb(new Error('Remove error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Remove error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyLocalRemove).toBe('profile'); + + expect(savedProfile).toBe(expectedOldProfileSavedToSecure); + }); + + it('getProfile(), secure get fails.', function() { + var error, keySecureGet, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(new Error('Secure get error.'), null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Secure get error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + + expect(localStorageServiceMock.remove.calls.any()).toBe(false); + }); + + it('getProfile(), secure get succeeds, file storage get fails.', function() { + var error, keySecureGet, keyLocalGet, profile, profile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, secureProfile); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(new Error('File storage get error.'), null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('File storage get error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + + expect(localStorageServiceMock.remove.calls.any()).toBe(false); + }); + + it('getProfile() from secure storage.', function() { + var error, keySecureGet, keyLocalGet, profile, profile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, secureProfile); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error).toBeFalsy(); + expect(profile).toBeTruthy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + + expect(profile.appVersion).toBe('4.11.0'); + expect(profile.createdOn).toBe(1528363260283); + + expect(profile.credentials[0].coin).toBe('bch'); + expect(profile.credentials[0].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[0].walletId).toBe('9580929b-417d-4fce-bcbf-de8e16a51c25'); + + expect(profile.credentials[1].coin).toBe('btc'); + expect(profile.credentials[1].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[1].walletId).toBe('ef78459e-52b1-418a-b89d-4df2ef1d27ea'); + }); + + it('getProfile() merge from local and secure storage.', function() { + var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, secureProfile); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfile = v; + cb(null); + }); + + localStorageServiceMock.remove.and.callFake(function(k, cb){ + keyLocalRemove = k; + cb(null); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error).toBeFalsy(); + expect(profile).toBeTruthy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyLocalRemove).toBe('profile'); + + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); + + expect(profile.appVersion).toBe('4.11.0'); + expect(profile.createdOn).toBe(1528363260283); + + // Existing secure + expect(profile.credentials[0].coin).toBe('bch'); + expect(profile.credentials[0].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[0].walletId).toBe('9580929b-417d-4fce-bcbf-de8e16a51c25'); + + expect(profile.credentials[1].coin).toBe('btc'); + expect(profile.credentials[1].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); + expect(profile.credentials[1].walletId).toBe('ef78459e-52b1-418a-b89d-4df2ef1d27ea'); + + // Old + expect(profile.credentials[2].coin).toBe('bch'); + expect(profile.credentials[2].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[2].walletId).toBe('a8ea9291-1369-4862-90a1-d80a5d4bcc20'); + + expect(profile.credentials[3].coin).toBe('btc'); + expect(profile.credentials[3].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); + expect(profile.credentials[3].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); + + }); + + it('getProfile() merge from local and secure storage, secure set fails, not removed from local.', function() { + var error, keySecureGet, keyLocalGet, keySecureSet, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, secureProfile); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfile = v; + cb(new Error('Secure set error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Secure set error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); + + expect(localStorageServiceMock.remove.calls.any()).toBe(false); + }); + + it('getProfile() merge from local and secure storage, remove from local fails.', function() { + var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, profile, savedProfile; + + secureStorageServiceMock.get.and.callFake(function(k, cb){ + keySecureGet = k; + cb(null, secureProfile); + }); + + localStorageServiceMock.get.and.callFake(function(k, cb){ + keyLocalGet = k; + cb(null, oldProfile); + }); + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k + savedProfile = v; + cb(null); + }); + + localStorageServiceMock.remove.and.callFake(function(k, cb){ + keyLocalRemove = k; + cb(new Error('Remove error.')); + }); + + storageService.getProfile(function(err, p){ + error = err; + profile = p; + }); + + expect(error.message).toBe('Remove error.'); + expect(profile).toBeFalsy(); + + expect(keySecureGet).toBe('profile'); + expect(keyLocalGet).toBe('profile'); + expect(keySecureSet).toBe('profile'); + expect(keyLocalRemove).toBe('profile'); + + expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); + }); + +}); + describe('storageService on mobile', function(){ var appConfig, expectedOldProfileSavedToSecure, From c9c27e838c47ca4f0fb8411833f3570b18025d0c Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Mon, 11 Jun 2018 12:39:25 +1200 Subject: [PATCH 32/34] Corrected the name on some things. --- src/js/services/storageService.spec.js | 288 +------------------------ 1 file changed, 9 insertions(+), 279 deletions(-) diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index 88ed99d5f..c9b4fb3a1 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -111,7 +111,7 @@ xdescribe('storageService on desktop', function(){ expect(profile.credentials[1].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); }); - it('getProfile() from file storage, remove fails.', function() { + it('getProfile() from local storage, remove fails.', function() { var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, profile, savedProfile; secureStorageServiceMock.get.and.callFake(function(k, cb){ @@ -151,7 +151,7 @@ xdescribe('storageService on desktop', function(){ expect(savedProfile).toBe(expectedOldProfileSavedToSecure); }); - it('getProfile() from file storage, secure set fails, not removed.', function() { + it('getProfile() from local storage, secure set fails, not removed.', function() { var error, keySecureGet, keyLocalGet, keySecureSet, profile, profile, savedProfile; secureStorageServiceMock.get.and.callFake(function(k, cb){ @@ -208,7 +208,7 @@ xdescribe('storageService on desktop', function(){ expect(localStorageServiceMock.remove.calls.any()).toBe(false); }); - it('getProfile(), secure get succeeds, file storage get fails.', function() { + it('getProfile(), secure get succeeds, local storage get fails.', function() { var error, keySecureGet, keyLocalGet, profile, profile; secureStorageServiceMock.get.and.callFake(function(k, cb){ @@ -218,7 +218,7 @@ xdescribe('storageService on desktop', function(){ localStorageServiceMock.get.and.callFake(function(k, cb){ keyLocalGet = k; - cb(new Error('File storage get error.'), null); + cb(new Error('Local storage get error.'), null); }); storageService.getProfile(function(err, p){ @@ -226,7 +226,7 @@ xdescribe('storageService on desktop', function(){ profile = p; }); - expect(error.message).toBe('File storage get error.'); + expect(error.message).toBe('Local storage get error.'); expect(profile).toBeFalsy(); expect(keySecureGet).toBe('profile'); @@ -411,7 +411,7 @@ xdescribe('storageService on desktop', function(){ }); -describe('storageService on desktop using old storage', function(){ +describe('storageService on desktop using local storage', function(){ var appConfig, localStorageServiceMock, log, @@ -440,7 +440,6 @@ describe('storageService on desktop using old storage', function(){ }; platformInfoStub = { - isCordova: false, isNW: true }; @@ -460,13 +459,9 @@ describe('storageService on desktop using old storage', function(){ appConfig = $injector.get('appConfigService'); storageService = $injector.get('storageService'); }); - - secureProfileFromOldOnly = secureProfileFromOldOnly.replace('${appVersion}', appConfig.version); - expectedOldProfileSavedToSecure = expectedOldProfileSavedToSecure.replace('${appVersion}', appConfig.version); - }); - fit('getProfile() from local storage.', function() { + it('getProfile().', function() { var error, keyLocalGet, profile; localStorageServiceMock.get.and.callFake(function(k, cb){ @@ -500,7 +495,7 @@ describe('storageService on desktop using old storage', function(){ expect(profile.credentials[1].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); }); - fit('getProfile() from local storage, get fails.', function() { + it('getProfile(), get fails.', function() { var error, keyLocalGet, profile; localStorageServiceMock.get.and.callFake(function(k, cb){ @@ -513,7 +508,7 @@ describe('storageService on desktop using old storage', function(){ profile = p; }); - expect(error.message).toBeFalsy('Local get error.'); + expect(error.message).toBe('Local get error.'); expect(profile).toBeFalsy(); expect(keyLocalGet).toBe('profile'); @@ -521,271 +516,6 @@ describe('storageService on desktop using old storage', function(){ expect(localStorageServiceMock.remove.calls.any()).toBe(false); expect(secureStorageServiceMock.get.calls.any()).toBe(false); expect(secureStorageServiceMock.set.calls.any()).toBe(false); - - expect(profile.appVersion).toBeUndefined(); - expect(profile.createdOn).toBe(1528363022385); - }); - - it('getProfile() from file storage, remove fails.', function() { - var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, profile, savedProfile; - - secureStorageServiceMock.get.and.callFake(function(k, cb){ - keySecureGet = k; - cb(null, null); - }); - - localStorageServiceMock.get.and.callFake(function(k, cb){ - keyLocalGet = k; - cb(null, oldProfile); - }); - - secureStorageServiceMock.set.and.callFake(function(k, v, cb){ - keySecureSet = k; - savedProfile = v; - cb(null); - }); - - localStorageServiceMock.remove.and.callFake(function(k, cb){ - keyLocalRemove = k; - cb(new Error('Remove error.')); - }); - - storageService.getProfile(function(err, p){ - error = err; - profile = p; - }); - - expect(error.message).toBe('Remove error.'); - expect(profile).toBeFalsy(); - - expect(keySecureGet).toBe('profile'); - expect(keyLocalGet).toBe('profile'); - expect(keySecureSet).toBe('profile'); - expect(keyLocalRemove).toBe('profile'); - - expect(savedProfile).toBe(expectedOldProfileSavedToSecure); - }); - - it('getProfile(), secure get fails.', function() { - var error, keySecureGet, profile, profile, savedProfile; - - secureStorageServiceMock.get.and.callFake(function(k, cb){ - keySecureGet = k; - cb(new Error('Secure get error.'), null); - }); - - storageService.getProfile(function(err, p){ - error = err; - profile = p; - }); - - expect(error.message).toBe('Secure get error.'); - expect(profile).toBeFalsy(); - - expect(keySecureGet).toBe('profile'); - - expect(localStorageServiceMock.remove.calls.any()).toBe(false); - }); - - it('getProfile(), secure get succeeds, file storage get fails.', function() { - var error, keySecureGet, keyLocalGet, profile, profile; - - secureStorageServiceMock.get.and.callFake(function(k, cb){ - keySecureGet = k; - cb(null, secureProfile); - }); - - localStorageServiceMock.get.and.callFake(function(k, cb){ - keyLocalGet = k; - cb(new Error('File storage get error.'), null); - }); - - storageService.getProfile(function(err, p){ - error = err; - profile = p; - }); - - expect(error.message).toBe('File storage get error.'); - expect(profile).toBeFalsy(); - - expect(keySecureGet).toBe('profile'); - expect(keyLocalGet).toBe('profile'); - - expect(localStorageServiceMock.remove.calls.any()).toBe(false); - }); - - it('getProfile() from secure storage.', function() { - var error, keySecureGet, keyLocalGet, profile, profile; - - secureStorageServiceMock.get.and.callFake(function(k, cb){ - keySecureGet = k; - cb(null, secureProfile); - }); - - localStorageServiceMock.get.and.callFake(function(k, cb){ - keyLocalGet = k; - cb(null, null); - }); - - storageService.getProfile(function(err, p){ - error = err; - profile = p; - }); - - expect(error).toBeFalsy(); - expect(profile).toBeTruthy(); - - expect(keySecureGet).toBe('profile'); - expect(keyLocalGet).toBe('profile'); - - expect(profile.appVersion).toBe('4.11.0'); - expect(profile.createdOn).toBe(1528363260283); - - expect(profile.credentials[0].coin).toBe('bch'); - expect(profile.credentials[0].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); - expect(profile.credentials[0].walletId).toBe('9580929b-417d-4fce-bcbf-de8e16a51c25'); - - expect(profile.credentials[1].coin).toBe('btc'); - expect(profile.credentials[1].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); - expect(profile.credentials[1].walletId).toBe('ef78459e-52b1-418a-b89d-4df2ef1d27ea'); - }); - - it('getProfile() merge from local and secure storage.', function() { - var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, profile, savedProfile; - - secureStorageServiceMock.get.and.callFake(function(k, cb){ - keySecureGet = k; - cb(null, secureProfile); - }); - - localStorageServiceMock.get.and.callFake(function(k, cb){ - keyLocalGet = k; - cb(null, oldProfile); - }); - - secureStorageServiceMock.set.and.callFake(function(k, v, cb){ - keySecureSet = k; - savedProfile = v; - cb(null); - }); - - localStorageServiceMock.remove.and.callFake(function(k, cb){ - keyLocalRemove = k; - cb(null); - }); - - storageService.getProfile(function(err, p){ - error = err; - profile = p; - }); - - expect(error).toBeFalsy(); - expect(profile).toBeTruthy(); - - expect(keySecureGet).toBe('profile'); - expect(keyLocalGet).toBe('profile'); - expect(keySecureSet).toBe('profile'); - expect(keyLocalRemove).toBe('profile'); - - expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); - - expect(profile.appVersion).toBe('4.11.0'); - expect(profile.createdOn).toBe(1528363260283); - - // Existing secure - expect(profile.credentials[0].coin).toBe('bch'); - expect(profile.credentials[0].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); - expect(profile.credentials[0].walletId).toBe('9580929b-417d-4fce-bcbf-de8e16a51c25'); - - expect(profile.credentials[1].coin).toBe('btc'); - expect(profile.credentials[1].mnemonic).toBe('forget camera antique cement army ahead quantum leisure claim behind climb eight'); - expect(profile.credentials[1].walletId).toBe('ef78459e-52b1-418a-b89d-4df2ef1d27ea'); - - // Old - expect(profile.credentials[2].coin).toBe('bch'); - expect(profile.credentials[2].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); - expect(profile.credentials[2].walletId).toBe('a8ea9291-1369-4862-90a1-d80a5d4bcc20'); - - expect(profile.credentials[3].coin).toBe('btc'); - expect(profile.credentials[3].mnemonic).toBe('morning conduct milk catch victory smoke ship little dutch original legal gadget'); - expect(profile.credentials[3].walletId).toBe('f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b'); - - }); - - it('getProfile() merge from local and secure storage, secure set fails, not removed from local.', function() { - var error, keySecureGet, keyLocalGet, keySecureSet, profile, profile, savedProfile; - - secureStorageServiceMock.get.and.callFake(function(k, cb){ - keySecureGet = k; - cb(null, secureProfile); - }); - - localStorageServiceMock.get.and.callFake(function(k, cb){ - keyLocalGet = k; - cb(null, oldProfile); - }); - - secureStorageServiceMock.set.and.callFake(function(k, v, cb){ - keySecureSet = k; - savedProfile = v; - cb(new Error('Secure set error.')); - }); - - storageService.getProfile(function(err, p){ - error = err; - profile = p; - }); - - expect(error.message).toBe('Secure set error.'); - expect(profile).toBeFalsy(); - - expect(keySecureGet).toBe('profile'); - expect(keyLocalGet).toBe('profile'); - expect(keySecureSet).toBe('profile'); - - expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); - - expect(localStorageServiceMock.remove.calls.any()).toBe(false); - }); - - it('getProfile() merge from local and secure storage, remove from local fails.', function() { - var error, keySecureGet, keyLocalGet, keySecureSet, keyLocalRemove, profile, profile, savedProfile; - - secureStorageServiceMock.get.and.callFake(function(k, cb){ - keySecureGet = k; - cb(null, secureProfile); - }); - - localStorageServiceMock.get.and.callFake(function(k, cb){ - keyLocalGet = k; - cb(null, oldProfile); - }); - - secureStorageServiceMock.set.and.callFake(function(k, v, cb){ - keySecureSet = k - savedProfile = v; - cb(null); - }); - - localStorageServiceMock.remove.and.callFake(function(k, cb){ - keyLocalRemove = k; - cb(new Error('Remove error.')); - }); - - storageService.getProfile(function(err, p){ - error = err; - profile = p; - }); - - expect(error.message).toBe('Remove error.'); - expect(profile).toBeFalsy(); - - expect(keySecureGet).toBe('profile'); - expect(keyLocalGet).toBe('profile'); - expect(keySecureSet).toBe('profile'); - expect(keyLocalRemove).toBe('profile'); - - expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); }); }); From 149b956b7c63c3228c64f7cf1c301a78a6e6c436 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Mon, 11 Jun 2018 14:09:39 +1200 Subject: [PATCH 33/34] Storing profile on desktop without using secure storage. --- src/js/services/storageService.js | 9 ++- src/js/services/storageService.spec.js | 102 ++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index de4aa9b54..a2d85950b 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -116,11 +116,16 @@ angular.module('copayApp.services') }; root.storeNewProfile = function(profile, cb) { - secureStorageService.set('profile', profile.toObj(), cb); + root.storeProfile(profile, cb); }; root.storeProfile = function(profile, cb) { - secureStorageService.set('profile', profile.toObj(), cb); + var profileString = profile.toObj(); + if (platformInfo.isNW) { + storage.set('profile', profileString, cb); + } else { + secureStorageService.set('profile', profileString, cb); + } }; /** diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index c9b4fb3a1..8d1bb8be8 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -409,6 +409,9 @@ xdescribe('storageService on desktop', function(){ expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); }); + + + }); describe('storageService on desktop using local storage', function(){ @@ -416,13 +419,15 @@ describe('storageService on desktop using local storage', function(){ localStorageServiceMock, log, oldProfile, + oldProfileString, platformInfoStub, secureStorageService, secureStorageServiceMock, storageService; - oldProfile = '{"version":"1.0.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; - + oldProfileString = '{"version":"1.0.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; + oldProfile = Profile.fromString(oldProfileString); + log = { debug: function(s){ console.log(s); }, error: function(s){ console.log(s); }, @@ -436,7 +441,8 @@ describe('storageService on desktop using local storage', function(){ localStorageServiceMock = { get: jasmine.createSpy(), - remove: jasmine.createSpy() + remove: jasmine.createSpy(), + set: jasmine.createSpy() }; platformInfoStub = { @@ -466,7 +472,7 @@ describe('storageService on desktop using local storage', function(){ localStorageServiceMock.get.and.callFake(function(k, cb){ keyLocalGet = k; - cb(null, oldProfile); + cb(null, oldProfileString); }); storageService.getProfile(function(err, p){ @@ -518,6 +524,94 @@ describe('storageService on desktop using local storage', function(){ expect(secureStorageServiceMock.set.calls.any()).toBe(false); }); + it('storeNewProfile() to local storage.', function() { + var error, keyLocalSet, savedProfileString; + + localStorageServiceMock.set.and.callFake(function(k, v, cb){ + keyLocalSet = k; + savedProfileString = v; + cb(null); + }); + + storageService.storeNewProfile(oldProfile, function(err){ + error = err; + }); + + expect(error).toBeFalsy(); + expect(savedProfileString).toBeTruthy(); + + expect(keyLocalSet).toBe('profile'); + + expect(savedProfileString).toBe(oldProfileString); + expect(secureStorageServiceMock.set.calls.any()).toBe(false); + }); + + it('storeNewProfile() to local storage, set fails.', function() { + var error, keyLocalSet, savedProfileString; + + localStorageServiceMock.set.and.callFake(function(k, v, cb){ + keyLocalSet = k; + savedProfileString = v; + cb(new Error('Local set failed.')); + }); + + storageService.storeNewProfile(oldProfile, function(err){ + error = err; + }); + + expect(error.message).toBe('Local set failed.'); + expect(savedProfileString).toBe(oldProfileString); + + expect(keyLocalSet).toBe('profile'); + + expect(savedProfileString).toBe(oldProfileString); + expect(secureStorageServiceMock.set.calls.any()).toBe(false); + }); + + it('storeProfile() to local storage.', function() { + var error, keyLocalSet, savedProfileString; + + localStorageServiceMock.set.and.callFake(function(k, v, cb){ + keyLocalSet = k; + savedProfileString = v; + cb(null); + }); + + storageService.storeProfile(oldProfile, function(err){ + error = err; + }); + + expect(error).toBeFalsy(); + expect(savedProfileString).toBeTruthy(); + + expect(keyLocalSet).toBe('profile'); + + expect(savedProfileString).toBe(oldProfileString); + expect(secureStorageServiceMock.set.calls.any()).toBe(false); + }); + + it('storeProfile() to local storage, set fails.', function() { + var error, keyLocalSet, savedProfileString; + + localStorageServiceMock.set.and.callFake(function(k, v, cb){ + keyLocalSet = k; + savedProfileString = v; + cb(new Error('Local set failed.')); + }); + + storageService.storeProfile(oldProfile, function(err){ + error = err; + }); + + expect(error.message).toBe('Local set failed.'); + expect(savedProfileString).toBe(oldProfileString); + + expect(keyLocalSet).toBe('profile'); + + expect(savedProfileString).toBe(oldProfileString); + expect(secureStorageServiceMock.set.calls.any()).toBe(false); + }); + }); describe('storageService on mobile', function(){ From 7209800b3c1561055696baeb9c16854c96d12996 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Mon, 11 Jun 2018 14:21:15 +1200 Subject: [PATCH 34/34] Tests for storing profile on mobile. --- src/js/services/storageService.spec.js | 95 +++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/src/js/services/storageService.spec.js b/src/js/services/storageService.spec.js index 8d1bb8be8..493678b97 100644 --- a/src/js/services/storageService.spec.js +++ b/src/js/services/storageService.spec.js @@ -623,6 +623,7 @@ describe('storageService on mobile', function(){ oldProfile, platformInfoStub, savedSecureProfile, + secureProfileObj, secureStorageService, secureStorageServiceMock, storageService; @@ -632,7 +633,8 @@ describe('storageService on mobile', function(){ oldProfile = '{"version":"1.0.0","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; secureProfile = '{"version":"1.0.0","appVersion":"4.11.0","createdOn":1528363260283,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"81f52508c14d50cdde2ad527920f209cbf51162b0dbaa7ceac298ed6d34d1ff8","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"9580929b-417d-4fce-bcbf-de8e16a51c25","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"54dd6773fec23b07eff5cda33fd0ad2591de31db356c67cd3e5dc67211d7c8ac","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"PptIrH74qd63DPMC1LQ/dQ==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K4Mge6QumKYh1aSYLB26z6QhkDz8tJLuXdumCJy9PYBrHMrTW3boiaodkVNTciR7PcPAcLXZeUWSehMJc3GXJp1uR68x3Nh5","xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPrivKey":"8fde6c8da5cf59cc0b19e87ea102aef2799047b9062f3e08668a92ef4582e040","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2","copayerId":"6f3c19e90d6eb9096a57199d53494fd6d62852ffaaa62fb5a5baef9f65753ce1","publicKeyRing":[{"xPubKey":"xpub6CGZNmTZ9KmHyxgbqZhfcJKwhrgN5EfHh2P7YppRXPGvUg6QkAuErmaQQa3cjyS9NMuFnvxm1eNUcbUEuiVikzUmZmVrtVcU7uvjWUNrRTG","requestPubKey":"0366db5dd83550ebefa8946d770e68ea8bb0e197076713bb681fb80d6fbc4278b2"}],"walletId":"ef78459e-52b1-418a-b89d-4df2ef1d27ea","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"2ac4835b2c883e095f4b187d712e53701781cb0d24e8813e736fd2d8a3219fec","personalEncryptingKey":"r5Tpd+/YD6uGXKZeeqZBPg==","sharedEncryptingKey":"WMcSMqfwZ+qfhP58S9l6OA==","copayerName":"me","mnemonic":"forget camera antique cement army ahead quantum leisure claim behind climb eight","entropySource":"fc2357f9d0176aa3a571bdfdea9e12cd16c27019e87b80ab0f08ddf15101d532","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"9580929b-417d-4fce-bcbf-de8e16a51c25":true,"ef78459e-52b1-418a-b89d-4df2ef1d27ea":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; secureProfileFromOldOnly = '{"version":"1.0.0","appVersion":"${appVersion}","createdOn":1528363022385,"credentials":[{"coin":"bch","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"cc5667792d8378ad61dc30a65bafea3d03d9179c5615d9f183738b002d978659","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"a8ea9291-1369-4862-90a1-d80a5d4bcc20","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"8437d2824b17f31d548fc2855577e9092ac5a7f9c985e5329acab34a8e786fb8","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"ZhMBX+t9/0n2kCasR5KH0w==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"},{"coin":"btc","network":"livenet","xPrivKey":"xprv9s21ZrQH143K2vd69iX1D5R2Acdjx6hzsSncBqnTri7UUad3SxSxFGukcjCUBKfWtZx3KGVjSd94ypEz4gB5RzATenxCEVPPZsgVJpoXkRq","xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPrivKey":"c1cac5328bf71c0f73f64ef868ddea66356ba797f87af4939390d58a7ff1aeda","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d","copayerId":"8430d4ca7a324ce0176e782c2d48f333666bd8f9b66fdd432a7f1ad1c80341ec","publicKeyRing":[{"xPubKey":"xpub6CZLbRhS7jEN2UT3ZhGeia6jPxr4guckZDa7ogncrrES2GyMj7Pq5U4oYLV2FhAMuuYA8qzxWV3TDXXDSkGTaqHstjRANCgCjrMDA1r7AN8","requestPubKey":"02b41c465aaf8f41192f2444a07c6e64d6147a080c5b82a6e73b3b232f11e1575d"}],"walletId":"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b","walletName":"Personal Wallet","m":1,"n":1,"walletPrivKey":"30df9228ff38258afe363a29cb02bff6d76f9f66ed36250de493717f4c941cc1","personalEncryptingKey":"qZmFZypS3TufwM5+WzvNJw==","sharedEncryptingKey":"2wQyQJGV3vyRPE/uil9ZRA==","copayerName":"me","mnemonic":"morning conduct milk catch victory smoke ship little dutch original legal gadget","entropySource":"3f88849ae9522574a2aaab870594b25a4e90b9dc632724ef3675fc3c49aa93b9","mnemonicHasPassphrase":false,"derivationStrategy":"BIP44","account":0,"compliantDerivation":true,"addressType":"P2PKH"}],"disclaimerAccepted":true,"checked":{"a8ea9291-1369-4862-90a1-d80a5d4bcc20":true,"f4ff4629-ff53-4bc7-8c98-e7c8e0149d3b":true},"checkedUA":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}'; - + secureProfileObj = Profile.fromString(secureProfile); + log = { debug: function(s){ console.log(s); }, error: function(s){ console.log(s); }, @@ -646,7 +648,8 @@ describe('storageService on mobile', function(){ fileStorageServiceMock = { get: jasmine.createSpy(), - remove: jasmine.createSpy() + remove: jasmine.createSpy(), + set: jasmine.createSpy() }; platformInfoStub = { @@ -1025,4 +1028,92 @@ describe('storageService on mobile', function(){ expect(savedProfile).toBe(expectedOldProfileMergedWithSecure); }); + it('storeNewProfile().', function() { + var error, keySecureSet, savedProfileString; + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfileString = v; + cb(null); + }); + + storageService.storeNewProfile(secureProfileObj, function(err){ + error = err; + }); + + expect(error).toBeFalsy(); + expect(savedProfileString).toBeTruthy(); + + expect(keySecureSet).toBe('profile'); + + expect(savedProfileString).toBe(secureProfile); + expect(fileStorageServiceMock.set.calls.any()).toBe(false); + }); + + it('storeNewProfile(), secure set fails.', function() { + var error, keySecureSet, savedProfileString; + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfileString = v; + cb(new Error('Secure set failed.')); + }); + + storageService.storeNewProfile(secureProfileObj, function(err){ + error = err; + }); + + expect(error.message).toBe('Secure set failed.'); + expect(savedProfileString).toBeTruthy(); + + expect(keySecureSet).toBe('profile'); + + expect(savedProfileString).toBe(secureProfile); + expect(fileStorageServiceMock.set.calls.any()).toBe(false); + }); + + it('storeProfile().', function() { + var error, keySecureSet, savedProfileString; + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfileString = v; + cb(null); + }); + + storageService.storeProfile(secureProfileObj, function(err){ + error = err; + }); + + expect(error).toBeFalsy(); + expect(savedProfileString).toBeTruthy(); + + expect(keySecureSet).toBe('profile'); + + expect(savedProfileString).toBe(secureProfile); + expect(fileStorageServiceMock.set.calls.any()).toBe(false); + }); + + it('storeProfile(), secure set fails.', function() { + var error, keySecureSet, savedProfileString; + + secureStorageServiceMock.set.and.callFake(function(k, v, cb){ + keySecureSet = k; + savedProfileString = v; + cb(new Error('Secure set failed.')); + }); + + storageService.storeProfile(secureProfileObj, function(err){ + error = err; + }); + + expect(error.message).toBe('Secure set failed.'); + expect(savedProfileString).toBeTruthy(); + + expect(keySecureSet).toBe('profile'); + + expect(savedProfileString).toBe(secureProfile); + expect(fileStorageServiceMock.set.calls.any()).toBe(false); + }); + }); \ No newline at end of file