From 1008fe6537e3f55d7c9525dfa4f7e82cc689a6aa Mon Sep 17 00:00:00 2001
From: blavenie <benoit.lavenier@e-is.pro>
Date: Thu, 14 Mar 2019 18:49:47 +0100
Subject: [PATCH] [enh] Allow to save secondary wallets without encryption

---
 www/i18n/locale-en-GB.json                    |  3 +
 www/i18n/locale-en.json                       |  3 +
 www/i18n/locale-fr-FR.json                    |  9 ++-
 www/js/controllers/settings-controllers.js    | 36 ++++++---
 www/js/controllers/wallets-controllers.js     |  7 +-
 www/js/services/settings-services.js          | 24 +++---
 www/js/services/utils-services.js             | 18 ++---
 www/js/services/wallet-services.js            | 80 +++++++++++--------
 .../es/js/services/notification-services.js   |  4 +-
 www/plugins/es/js/services/social-services.js |  2 +-
 www/templates/settings/settings.html          | 23 +++++-
 11 files changed, 136 insertions(+), 73 deletions(-)

diff --git a/www/i18n/locale-en-GB.json b/www/i18n/locale-en-GB.json
index 681aabdd..8704a380 100644
--- a/www/i18n/locale-en-GB.json
+++ b/www/i18n/locale-en-GB.json
@@ -135,6 +135,9 @@
     "PEER_CHANGED_TEMPORARY": "Address used temporarily",
     "USE_LOCAL_STORAGE": "Enable local storage",
     "USE_LOCAL_STORAGE_HELP": "Allows you to save your settings",
+    "WALLETS_SETTINGS": "My wallets",
+    "USE_WALLETS_ENCRYPTION": "Secure the list",
+    "USE_WALLETS_ENCRYPTION_HELP": "Enables you to encrypt the list of your wallets. Authentication required to access it.",
     "ENABLE_HELPTIP": "Enable contextual help tips",
     "ENABLE_UI_EFFECTS": "Enable visual effects",
     "HISTORY_SETTINGS": "Account operations",
diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json
index a9cc920f..13310cd1 100644
--- a/www/i18n/locale-en.json
+++ b/www/i18n/locale-en.json
@@ -135,6 +135,9 @@
     "PEER_CHANGED_TEMPORARY": "Address used temporarily",
     "USE_LOCAL_STORAGE": "Enable local storage",
     "USE_LOCAL_STORAGE_HELP": "Allows you to save your settings",
+    "WALLETS_SETTINGS": "My wallets",
+    "USE_WALLETS_ENCRYPTION": "Secure the list",
+    "USE_WALLETS_ENCRYPTION_HELP": "Enables you to encrypt the list of your wallets. Authentication required to access it.",
     "ENABLE_HELPTIP": "Enable contextual help tips",
     "ENABLE_UI_EFFECTS": "Enable visual effects",
     "HISTORY_SETTINGS": "Account operations",
diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json
index 77dd988a..a526546b 100644
--- a/www/i18n/locale-fr-FR.json
+++ b/www/i18n/locale-fr-FR.json
@@ -135,11 +135,14 @@
     "PEER_CHANGED_TEMPORARY": "Adresse utilisée temporairement",
     "USE_LOCAL_STORAGE": "Activer le stockage local",
     "USE_LOCAL_STORAGE_HELP": "Permet de sauvegarder vos paramètres",
+    "WALLETS_SETTINGS": "Mes portefeuilles",
+    "USE_WALLETS_ENCRYPTION": "Sécuriser la liste (chiffrement)",
+    "USE_WALLETS_ENCRYPTION_HELP": "Permet de chiffrer la liste de vos portefeuilles. Authentification requise pour y accéder.",
     "ENABLE_HELPTIP": "Activer les bulles d'aide contextuelles",
     "ENABLE_UI_EFFECTS": "Activer les effets visuels",
-    "HISTORY_SETTINGS": "Liste des opérations",
+    "HISTORY_SETTINGS": "Mes opérations",
     "DISPLAY_UD_HISTORY": "Afficher les dividendes produits ?",
-    "TX_HISTORY_AUTO_REFRESH": "Activer le rafraichissement automatique ?",
+    "TX_HISTORY_AUTO_REFRESH": "Rafraichir automatiquement",
     "TX_HISTORY_AUTO_REFRESH_HELP": "Rafraîchi le solde et les opérations automatiquement, à chaque nouveau bloc du réseau.",
     "AUTHENTICATION_SETTINGS": "Authentification",
     "KEEP_AUTH": "Expiration de l'authentification",
@@ -159,7 +162,7 @@
     "PLUGINS_SETTINGS": "Extensions",
     "BTN_RESET": "Restaurer les valeurs par défaut",
     "EXPERT_MODE": "Activer le mode expert",
-    "EXPERT_MODE_HELP": "Permet un affichage plus détaillé",
+    "EXPERT_MODE_HELP": "Permet un affichage plus détaillé.",
     "BLOCK_VALIDITY_WINDOW": "Délai d'incertitude des blocs",
     "BLOCK_VALIDITY_WINDOW_SHORT": "Délai d'incertitude",
     "BLOCK_VALIDITY_WINDOW_HELP": "Délai avant de considérer qu'une information est validée",
diff --git a/www/js/controllers/settings-controllers.js b/www/js/controllers/settings-controllers.js
index 56f53743..163c1d9d 100644
--- a/www/js/controllers/settings-controllers.js
+++ b/www/js/controllers/settings-controllers.js
@@ -121,9 +121,9 @@ function SettingsController($scope, $q, $window, $ionicHistory, $ionicPopup, $ti
     $scope.formData.locale = (csSettings.data.locale && csSettings.data.locale.id && _.findWhere($scope.locales, {id: csSettings.data.locale.id})) ||
       _.findWhere($scope.locales, {id: csSettings.defaultSettings.locale.id});
 
-    $scope.loading = false;
 
-    $timeout(function() {
+    return $timeout(function() {
+      $scope.loading = false;
       // Set Ink
       UIUtils.ink({selector: '.item'});
       $scope.showHelpTip();
@@ -284,14 +284,22 @@ function SettingsController($scope, $q, $window, $ionicHistory, $ionicPopup, $ti
     $scope.saving = true;
 
     // Async - to avoid UI lock
-    $timeout(function() {
+    return $timeout(function() {
       // Make sure to format helptip
       $scope.cleanupHelpTip();
 
+      // Applying
       csSettings.apply($scope.formData);
-      csSettings.store();
-      $scope.saving = false;
-    }, 100);
+
+      // Store
+      return csSettings.store();
+
+    }, 100)
+    .then(function() {
+      //return $timeout(function() {
+        $scope.saving = false;
+      //}, 100);
+    });
   };
 
   $scope.onDataChanged = function(oldValue, newValue, scope) {
@@ -305,14 +313,24 @@ function SettingsController($scope, $q, $window, $ionicHistory, $ionicPopup, $ti
       }, 500);
     }
 
-    var updated = !angular.equals(oldValue, newValue);
-    if (updated) {
-      //console.debug('Detected settings update: will save it');
+    // Changes from the current scope: save changes
+    if ((scope === $scope) && !angular.equals(oldValue, newValue)) {
       $scope.save();
     }
   };
   $scope.$watch('formData', $scope.onDataChanged, true);
 
+  // Detected changes from outside (e.g. enabling encryption on wallet can be rollback if user cancel auth)
+  csSettings.api.data.on.changed($scope, function(data) {
+    if ($scope.loading || $scope.saving || $scope.pendingSaving) return;
+
+    var updated = !angular.equals(data.useLocalStorageEncryption, $scope.formData.useLocalStorageEncryption);
+    if (updated) {
+      console.debug('[settings] Settings changed (outside the settings page). Reloading...');
+      $scope.load();
+    }
+  });
+
   $scope.getServer = function() {
     if (!$scope.formData.node || !$scope.formData.node.host) return '';
     return csHttp.getServer($scope.formData.node.host, $scope.formData.node.port);
diff --git a/www/js/controllers/wallets-controllers.js b/www/js/controllers/wallets-controllers.js
index 0c464919..04cc8f04 100644
--- a/www/js/controllers/wallets-controllers.js
+++ b/www/js/controllers/wallets-controllers.js
@@ -71,8 +71,7 @@ angular.module('cesium.wallets.controllers', ['cesium.services', 'cesium.currenc
 ;
 
 function WalletListController($scope, $controller, $state, $timeout, $q, $translate, $ionicPopover, $ionicPopup,
-                              ModalUtils,
-                              UIUtils, Modals, csCurrency, csSettings, csWallet){
+                              ModalUtils, UIUtils, Modals, csCurrency, csSettings, csWallet){
   'ngInject';
 
   $scope.settings = csSettings.data;
@@ -175,7 +174,7 @@ function WalletListController($scope, $controller, $state, $timeout, $q, $transl
     if (!wallet) return $q.reject("Missing 'wallet' argument");
 
     // Make sure auth on the main wallet
-    if (!csWallet.isAuth()) {
+    if (!csWallet.isAuth() && csSettings.data.useLocalStorageEncryption) {
       return csWallet.auth({minData: true})
         .then(function() {
           return $scope.addNewWallet(wallet); // loop
@@ -464,7 +463,7 @@ function WalletListController($scope, $controller, $state, $timeout, $q, $transl
   // Detect changes in settings useRelative
   $scope.$watch('settings.useRelative', function(newVal, oldVal) {
     if (!$scope.formData || $scope.loading || (newVal === oldVal)) return;
-    $scope.formData.useRelative = $scope.settings.useRelative;
+    $scope.formData.useRelative = csSettings.data.useRelative;
     $scope.updateView();
   }, true);
 }
diff --git a/www/js/services/settings-services.js b/www/js/services/settings-services.js
index d2dd574d..84e41195 100644
--- a/www/js/services/settings-services.js
+++ b/www/js/services/settings-services.js
@@ -68,7 +68,7 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config'])
   },
   defaultSettings = angular.merge({
     useLocalStorage: true, // override to false if no device
-    useLocalStorageEncryption: true,
+    useLocalStorageEncryption: false,
     walletHistoryTimeSecond: 30 * 24 * 60 * 60 /*30 days*/,
     walletHistorySliceSecond: 5 * 24 * 60 * 60 /*download using 5 days slice*/,
     walletHistoryAutoRefresh: true, // override to false if device
@@ -148,7 +148,7 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config'])
     var hasChanged = previousData && !angular.equals(previousData, data);
     previousData = angular.copy(data);
     if (hasChanged) {
-      api.data.raise.changed(data);
+      return api.data.raise.changed(data);
     }
   },
 
@@ -192,7 +192,13 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config'])
       .then(emitChangedEvent);
   },
 
+  /**
+   * Apply new settings (can be partial)
+   * @param newData
+   */
   applyData = function(newData) {
+    if (!newData) return; // skip empty
+
     var localeChanged = false;
     if (newData.locale && newData.locale.id) {
       // Fix previously stored locale (could use bad format)
@@ -200,16 +206,16 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config'])
       localeChanged = !data.locale || newData.locale.id !== data.locale.id || newData.locale.id !== $translate.use();
     }
 
-    // Apply stored settings
+    // Force some fixed settings, before merging
+    _.keys(fixedSettings).forEach(function(key) {
+      newData[key] = defaultSettings[key]; // This will apply fixed value (override by config.js file)
+    });
+
+    // Apply new settings
     angular.merge(data, newData);
 
     // Delete temporary properties, if false
-    if (!newData.node.temporary || !data.node.temporary) delete data.node.temporary;
-
-    // Force some fixed settings
-    _.keys(fixedSettings).forEach(function(key) {
-      data[key] = defaultSettings[key]; // This will apply fixed value (override by config.js file)
-    });
+    if (newData && newData.node && !newData.node.temporary || !data.node.temporary) delete data.node.temporary;
 
     // Apply the new locale (only if need)
     // will produce an event cached by onLocaleChange();
diff --git a/www/js/services/utils-services.js b/www/js/services/utils-services.js
index 5a058037..bf515227 100644
--- a/www/js/services/utils-services.js
+++ b/www/js/services/utils-services.js
@@ -15,11 +15,12 @@ angular.module('cesium.utils.services', [])
   };
 })
 
-.factory('UIUtils', function($ionicLoading, $ionicPopup, $ionicConfig, $translate, $q, ionicMaterialInk, ionicMaterialMotion, $window, $timeout,
+.factory('UIUtils', function($ionicLoading, $ionicPopup, $ionicConfig, $ionicHistory, $translate, $q,
+                             ionicMaterialInk, ionicMaterialMotion, $window, $timeout,
                              // removeIf(no-device)
                              $cordovaToast,
                              // endRemoveIf(no-device)
-                             $ionicPopover, $state, $rootScope, screenmatch, csSettings) {
+                             $ionicPopover, $state, $rootScope, screenmatch) {
   'ngInject';
 
 
@@ -692,9 +693,10 @@ angular.module('cesium.utils.services', [])
     if (exports.motion.enable === enable) return; // same
     console.debug('[UI] [effects] ' + (enable ? 'Enable' : 'Disable'));
 
+    exports.motion.enable = enable;
     if (enable) {
       $ionicConfig.views.transition('platform');
-      exports.motion = raw.motion;
+      angular.merge(exports.motion, raw.motion);
     }
     else {
       $ionicConfig.views.transition('none');
@@ -702,7 +704,7 @@ angular.module('cesium.utils.services', [])
         class: undefined,
         show: function(){}
       };
-      exports.motion = {
+      angular.merge(exports.motion, {
         enable : false,
         default: nothing,
         fadeSlideIn: nothing,
@@ -714,8 +716,10 @@ angular.module('cesium.utils.services', [])
         fadeIn: nothing,
         toggleOn: toggleOn,
         toggleOff: toggleOff
-      };
+      });
+      $rootScope.motion = nothing;
     }
+    $ionicHistory.clearCache();
   }
 
   raw.motion = {
@@ -784,10 +788,6 @@ angular.module('cesium.utils.services', [])
     }, timeout || 900);
   }
 
-  csSettings.api.data.on.changed($rootScope, function(data) {
-    setEffects(data.uiEffects);
-  });
-
   exports = {
     alert: {
       error: alertError,
diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js
index 5762f3ce..09408729 100644
--- a/www/js/services/wallet-services.js
+++ b/www/js/services/wallet-services.js
@@ -468,17 +468,17 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
       var content; // Init only if used
       var secureContent; // Init only if used
 
-      // Add readTime
-      if (data.notifications && data.notifications.readTime) {
+      // Add time
+      if (data.notifications && data.notifications.time) {
         content = content || {};
         content.notifications = {
-          readTime: data.notifications.readTime
+          time: data.notifications.time
         };
       }
-      if (data.invitations && data.invitations.readTime) {
+      if (data.invitations && data.invitations.time) {
         content = content || {};
         content.invitations = {
-          readTime: data.invitations.readTime
+          time: data.invitations.time
         };
       }
 
@@ -510,7 +510,9 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
 
       // Encryption is enable, but user not auth: use the session storage
       // (and keep the local storage value)
-      if (!isAuth()) return sessionStorage.put(storageKey, contentStr||null);
+      if (!isAuth()) {
+        return sessionStorage.put(storageKey, contentStr||null);
+      }
 
       return $q.all([
         // Get a unique nonce
@@ -1924,16 +1926,6 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
         if (isAuth()) unauth();
       }, this);
       listeners.push(listener);
-
-      // Delegate start() to the parent wallet
-      /*exports.start = function() {
-        if (started) return $q.when();
-        return parentWallet.start()
-          .then(function() {
-            started = true;
-            startPromise=null;
-          });
-      };*/
     },
 
     createNewChildWallet = function(options) {
@@ -2181,27 +2173,49 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
     function onSettingsChanged(allSettings) {
       var newSettings = getWalletSettings(allSettings);
       var hasChanged = !angular.equals(settings, newSettings);
-      if (hasChanged) {
-        var useStorageChanged = !angular.equals(settings.useLocalStorage, newSettings.useLocalStorage) ||
-          !angular.equals(settings.useLocalStorageEncryption, newSettings.useLocalStorageEncryption);
-        var keepAuthIdleChanged = !angular.equals(settings.keepAuthIdle, newSettings.keepAuthIdle);
+      if (!hasChanged) return; // skip
+
+      var useEncryptionChanged = !angular.equals(settings.useLocalStorageEncryption, newSettings.useLocalStorageEncryption);
+      var useStorageChanged = !angular.equals(settings.useLocalStorage, newSettings.useLocalStorage) || useEncryptionChanged;
+      var keepAuthIdleChanged = !angular.equals(settings.keepAuthIdle, newSettings.keepAuthIdle);
 
-        settings = newSettings;
+      settings = newSettings;
 
-        if (keepAuthIdleChanged) {
-          checkAuthIdle();
+      if (keepAuthIdleChanged) {
+        checkAuthIdle();
+      }
+
+      // Local storage option changed
+      if (useStorageChanged) {
+
+        // If disabled, then reset the store
+        if (!settings.useLocalStorage) {
+          resetStore(data.pubkey);
         }
+        // If storage enable
+        else {
+          // Store login data
+          return store()
+            .then(function() {
 
-        if (useStorageChanged) {
-          // Reset stored data
-          if (!settings.useLocalStorage) {
-            resetStore(data.pubkey);
-          }
-          else {
-            // Or stored login data
-            store();
-            storeData();
-          }
+              // Encryption enable: auth before saving data
+              if (data.childrenCount > 0 && useEncryptionChanged && settings.useLocalStorageEncryption) {
+                return auth({minData: true, silent: true})
+                  .catch(function(err){
+                    // user not auth: revert encryption to false
+                    if (err == 'CANCELLED') {
+                      csSettings.apply({useLocalStorageEncryption: false});
+                      return csSettings.store();
+                    }
+                    else {
+                      throw err;
+                    }
+                  });
+              }
+            })
+
+            // Store other data (children wallet, ...)
+            .then(storeData);
         }
       }
     }
diff --git a/www/plugins/es/js/services/notification-services.js b/www/plugins/es/js/services/notification-services.js
index d7faaaed..630c0dcf 100644
--- a/www/plugins/es/js/services/notification-services.js
+++ b/www/plugins/es/js/services/notification-services.js
@@ -350,7 +350,7 @@ angular.module('cesium.es.notification.services', ['cesium.platform', 'cesium.es
     // Load unread notifications count
     loadUnreadNotificationsCount(
         data.pubkey, {
-          readTime: data.notifications && data.notifications.readTime || 0,
+          readTime: data.notifications && data.notifications.time || 0,
           excludeCodes: constants.EXCLUDED_CODES
         })
       .then(function(unreadCount) {
@@ -365,7 +365,7 @@ angular.module('cesium.es.notification.services', ['cesium.platform', 'cesium.es
               message: 'COMMON.NOTIFICATION.HAS_UNREAD',
               count: unreadCount,
               state: 'app.view_notifications'
-            }, data.ui || data.name || data.pubkey.substr(0,8));
+            }, data.ui || data.name || data.pubkey && data.pubkey.substr(0,8));
           }, 500);
         }
 
diff --git a/www/plugins/es/js/services/social-services.js b/www/plugins/es/js/services/social-services.js
index 37305a2d..ee9ad619 100644
--- a/www/plugins/es/js/services/social-services.js
+++ b/www/plugins/es/js/services/social-services.js
@@ -52,7 +52,7 @@ angular.module('cesium.es.social.services', ['cesium.es.crypto.services'])
               urlToMatch = url.substring(0, slashPathIndex);
             }
           }
-          //console.log("match URI, try to match: " + urlToMatch);
+          //console.debug("match URI, try to match: " + urlToMatch);
           _.keys(regexp.socials).forEach(function(key){
             if (regexp.socials[key].test(urlToMatch)) {
               type = key;
diff --git a/www/templates/settings/settings.html b/www/templates/settings/settings.html
index 5a0ba402..226af7bf 100644
--- a/www/templates/settings/settings.html
+++ b/www/templates/settings/settings.html
@@ -74,16 +74,17 @@
         </label>
       </div>
 
-     <!-- <div class="item item-toggle dark item-text-wrap">
+      <!--div class="item item-toggle dark item-text-wrap">
         <div class="input-label" ng-bind-html="'SETTINGS.ENABLE_UI_EFFECTS' | translate">
         </div>
         <label class="toggle toggle-royal">
-          <input type="checkbox" ng-model="formData.enableUuiEffects" >
+          <input type="checkbox" ng-model="formData.uiEffects" >
           <div class="track">
             <div class="handle"></div>
           </div>
         </label>
-      </div>-->
+      </div-->
+
       <!-- Allow extension here -->
       <cs-extension-point name="common"></cs-extension-point>
 
@@ -127,6 +128,22 @@
         <div class="item-note dark">{{formData.keyringFile}}</div>
       </div>
 
+      <span class="item item-divider">
+        {{'SETTINGS.WALLETS_SETTINGS' | translate}}
+      </span>
+
+      <div class="item item-toggle item-text-wrap dark">
+        <span class="input-label" ng-class="{'gray': !formData.useLocalStorage}" translate>SETTINGS.USE_WALLETS_ENCRYPTION</span>
+        <h4 class="gray" ng-bind-html="'SETTINGS.USE_WALLETS_ENCRYPTION_HELP' | translate">
+        </h4>
+        <label class="toggle toggle-royal">
+          <input type="checkbox" ng-model="formData.useLocalStorageEncryption" ng-disabled="!formData.useLocalStorage">
+          <div class="track">
+            <div class="handle"></div>
+          </div>
+        </label>
+      </div>
+
       <span class="item item-divider" translate>SETTINGS.HISTORY_SETTINGS</span>
 
       <div class="item item-toggle dark">
-- 
GitLab