From 95f85f416eca9857f864d35f71a5698d77e96856 Mon Sep 17 00:00:00 2001
From: blavenie <benoit.lavenier@e-is.pro>
Date: Thu, 9 Mar 2017 18:14:20 +0100
Subject: [PATCH] - Add cross-domain local storage - need for HTTPS/HTTP mode
 (when config has httpsMode=clever) - Change default config to use G1

---
 app/config.json                               |  14 +-
 gulpfile.js                                   |  22 +-
 www/https-storage.html                        |  11 +
 www/js/app.js                                 |  27 +-
 www/js/config.js                              |  21 +-
 www/js/controllers/settings-controllers.js    |  27 +-
 www/js/services/bma-services.js               | 123 +++-
 www/js/services/cache-services.js             | 141 ++---
 www/js/services/crypto-services.js            |  11 +-
 www/js/services/currency-services.js          |   6 +-
 www/js/services/device-services.js            |  51 +-
 www/js/services/http-services.js              |   8 +-
 www/js/services/network-services.js           |  33 +-
 www/js/services/plugin-services.js            |   2 +-
 www/js/services/settings-services.js          | 138 +++--
 www/js/services/storage-services.js           | 224 +++++--
 www/js/services/wallet-services.js            |  68 +-
 .../es/js/controllers/app-controllers.js      |   7 +-
 .../es/js/controllers/network-controllers.js  |   7 +-
 .../es/js/controllers/wot-controllers.js      |   7 +-
 www/plugins/es/js/services/http-services.js   |  65 +-
 .../es/js/services/settings-services.js       | 584 +++++++++---------
 www/sync-storage.html                         |   9 -
 www/templates/settings/settings.html          |   2 +-
 24 files changed, 934 insertions(+), 674 deletions(-)
 create mode 100644 www/https-storage.html
 delete mode 100644 www/sync-storage.html

diff --git a/app/config.json b/app/config.json
index b26417bc..792fe7ec 100644
--- a/app/config.json
+++ b/app/config.json
@@ -7,26 +7,26 @@
     "timeout": 10000,
     "timeWarningExpireMembership": 5184000,
     "timeWarningExpire": 7776000,
-    "useLocalStorage": true,
-    "useRelative": true,
+    "useLocalStorage": false,
+    "useRelative": false,
     "initPhase": false,
     "expertMode": false,
-    "decimalCount": 4,
+    "decimalCount": 2,
     "httpsMode": false,
     "helptip": {
       "enable": true,
       "installDocUrl": "https://github.com/duniter/duniter/blob/master/doc/install-a-node.md"
     },
     "node": {
-      "host": "gtest.duniter.org",
-      "port": "10900"
+      "host": "g1.duniter.org",
+      "port": "443"
     },
     "plugins":{
       "es": {
         "enable": true,
         "askEnable": false,
-        "host": "data.gtest.duniter.fr",
-        "port": "80",
+        "host": "g1.data.duniter.fr",
+        "port": "443",
         "notifications": {
           "txSent": true,
           "txReceived": true,
diff --git a/gulpfile.js b/gulpfile.js
index 85d1be9c..da6f6224 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -31,7 +31,6 @@ var rev = require('gulp-rev');
 var revReplace = require('gulp-rev-replace');
 var clean = require('gulp-clean');
 var htmlmin = require('gulp-htmlmin');
-var deleteEmpty = require('delete-empty');
 var jshint = require('gulp-jshint');
 var sourcemaps = require('gulp-sourcemaps');
 
@@ -261,6 +260,11 @@ gulp.task('copy-files:web', ['clean:tmp', 'clean:web', 'sass', 'config'], functi
       .pipe(rename("debug.html"))
       .pipe(gulp.dest(tmpPath)),
 
+    // Copy https-storage.html
+    gulp.src('./www/https-storage.html')
+      .pipe(htmlmin())
+      .pipe(gulp.dest(tmpPath)),
+
     // Copy fonts
     gulp.src('./www/fonts/**/*.*')
       .pipe(gulp.dest(tmpPath + '/fonts')),
@@ -357,12 +361,23 @@ gulp.task('debug-files:web', ['ng_annotate:web', 'ng_annotate-plugin:web'], func
     .on('end', done);
 });
 
-gulp.task('optimize-files:web', ['debug-files:web'], function(done) {
+gulp.task('https-storage-files:web', ['debug-files:web'], function(done) {
+  var tmpPath = './platforms/web/www';
+
+  // Process https-storage.html file
+  gulp.src(tmpPath + '/https-storage.html')
+    .pipe(useref())             // Concatenate with gulp-useref
+    .pipe(gulp.dest(tmpPath))
+    .on('end', done);
+});
+
+gulp.task('optimize-files:web', ['https-storage-files:web'], function(done) {
   var tmpPath = './platforms/web/www';
   var jsFilter = filter(["**/*.js", '!**/config.js'], { restore: true });
   var cssFilter = filter("**/*.css", { restore: true });
   var revFilesFilter = filter(['**/*', '!**/index.html', '!**/config.js'], { restore: true });
 
+  // Process index.html
   gulp.src(tmpPath + '/index.html')
     .pipe(useref())             // Concatenate with gulp-useref
     // Process JS
@@ -380,8 +395,7 @@ gulp.task('optimize-files:web', ['debug-files:web'], function(done) {
     .pipe(rev())                // Rename the concatenated files
     .pipe(revFilesFilter.restore)
 
-    // Substitute in new filenames
-    .pipe(revReplace())
+    .pipe(revReplace())         // Substitute in new filenames
     .pipe(gulp.dest(tmpPath))
     .on('end', done);
 });
diff --git a/www/https-storage.html b/www/https-storage.html
new file mode 100644
index 00000000..56f67c12
--- /dev/null
+++ b/www/https-storage.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <!-- build:js dist_js/https-storage.js -->
+  <script src="lib/ionic/js/angular/angular-xdLocalStoragePostMessageApi.min.js"></script>
+  <!-- endbuild -->
+</head>
+<body>
+  This is the frame used for Cross-Domain local storage, when using config with httpsMode='clever'
+</body>
+</html>
diff --git a/www/js/app.js b/www/js/app.js
index 8670bf0d..d44f3488 100644
--- a/www/js/app.js
+++ b/www/js/app.js
@@ -302,7 +302,7 @@ angular.module('cesium', ['ionic', 'ionic-material', 'ngMessages', 'pascalprecht
     $ionicConfigProvider.views.maxCache(5);
   })
 
-.run(function($rootScope, $translate, $state, $window, xdLocalStorage, Device, UIUtils, $ionicConfig, PluginService, csWallet, csSettings, csConfig) {
+.run(function($rootScope, $translate, $state, $window, xdLocalStorage, ionicReady, Device, UIUtils, $ionicConfig, PluginService, csWallet, csSettings, csConfig) {
   'ngInject';
 
   $rootScope.config = csConfig;
@@ -377,22 +377,8 @@ angular.module('cesium', ['ionic', 'ionic-material', 'ngMessages', 'pascalprecht
     });
   }
 
-  if (csConfig.httpsMode === 'clever' && $window.location.protocol !== 'https:') {
-    var href = $window.location.href;
-    var hashIndex = href.indexOf('#');
-    var rootPath = (hashIndex != -1) ? href.substr(0, hashIndex) : href;
-    var httpsFrame = (csConfig.httpsModeDebug ? 'http' : 'https') + rootPath.substr(4) + 'sync-storage.html';
-
-    xdLocalStorage.init({iframeUrl: httpsFrame})
-     .then(function () {
-         //an option function to be called once the iframe was loaded and ready for action
-         console.debug('[app] Cross-domain local storage started');
-         csSettings.start();
-     });
-   }
-
-  // We use 'Device.ready()' instead of '$ionicPlatform.ready()', because this one is callable many times
-  Device.ready()
+  // We use 'ionicReady()' instead of '$ionicPlatform.ready()', because this one is callable many times
+  ionicReady()
     .then(function() {
 
       // Keyboard
@@ -413,13 +399,14 @@ angular.module('cesium', ['ionic', 'ionic-material', 'ngMessages', 'pascalprecht
         console.log('Disable UI effects - plateform\'s grade is not [a] but [' + ionic.Platform.grade + ']');
         UIUtils.setEffects(false);
       }
-    })
-    // Status bar style
-    .then(function() {
+
+      // Status bar style
       if (window.StatusBar) {
         // org.apache.cordova.statusbar required
         StatusBar.styleDefault();
       }
+
+      return csSettings.ready();
     });
 
   // Update some translations, when locale changed
diff --git a/www/js/config.js b/www/js/config.js
index 0b3a8289..a1841eee 100644
--- a/www/js/config.js
+++ b/www/js/config.js
@@ -16,27 +16,26 @@ angular.module("cesium.config", [])
 	"timeout": 10000,
 	"timeWarningExpireMembership": 5184000,
 	"timeWarningExpire": 7776000,
-	"useLocalStorage": true,
-	"useRelative": true,
+	"useLocalStorage": false,
+	"useRelative": false,
 	"initPhase": false,
 	"expertMode": false,
-	"decimalCount": 4,
-	"httpsMode": "clever",
-  "httpsModeDebug": true,
+	"decimalCount": 2,
+	"httpsMode": false,
 	"helptip": {
 		"enable": true,
 		"installDocUrl": "https://github.com/duniter/duniter/blob/master/doc/install-a-node.md"
 	},
 	"node": {
-		"host": "gtest.duniter.org",
-		"port": "10900"
+		"host": "g1.duniter.org",
+		"port": "443"
 	},
 	"plugins": {
 		"es": {
 			"enable": true,
 			"askEnable": false,
-			"host": "data.gtest.duniter.fr",
-			"port": "80",
+			"host": "g1.data.duniter.fr",
+			"port": "443",
 			"notifications": {
 				"txSent": true,
 				"txReceived": true,
@@ -46,8 +45,8 @@ angular.module("cesium.config", [])
 		}
 	},
 	"version": "0.11.1",
-	"build": "2017-03-08T14:25:14.195Z",
+	"build": "2017-03-09T16:46:53.787Z",
 	"newIssueUrl": "https://github.com/duniter/cesium/issues/new?labels=bug"
 })
 
-;
+;
\ No newline at end of file
diff --git a/www/js/controllers/settings-controllers.js b/www/js/controllers/settings-controllers.js
index 85291c56..2c4627a2 100644
--- a/www/js/controllers/settings-controllers.js
+++ b/www/js/controllers/settings-controllers.js
@@ -28,10 +28,11 @@ function SettingsController($scope, $q, $ionicPopup, $timeout, $translate, csHtt
   $scope.popupData = {}; // need for the node popup
   $scope.loading = true;
   $scope.nodePopup = {};
+  $scope.bma = BMA;
 
 
   $scope.$on('$ionicView.enter', function() {
-    $scope.load();
+    csSettings.ready().then($scope.load);
   });
 
   $scope.setPopupForm = function(popupForm) {
@@ -81,13 +82,12 @@ function SettingsController($scope, $q, $ionicPopup, $timeout, $translate, csHtt
   $scope.changeNode= function(node) {
     $scope.showNodePopup(node || $scope.formData.node)
     .then(function(newNode) {
-      console.log(newNode);
       if (newNode.host === $scope.formData.node.host &&
         newNode.port === $scope.formData.node.port) {
         return; // same node = nothing to do
       }
       UIUtils.loading.show();
-      var nodeBMA = BMA.instance(newNode.host, newNode.port);
+      var nodeBMA = BMA.instance(newNode.host, newNode.port, undefined, true /*cache*/);
       nodeBMA.isAlive()
         .then(function(alive) {
           if (!alive) {
@@ -190,10 +190,29 @@ function SettingsController($scope, $q, $ionicPopup, $timeout, $translate, csHtt
       $scope.saving = false;
     }, 100);
   };
-  $scope.$watch('formData', $scope.save, true);
+
+  $scope.onDataChanged = function(oldValue, newValue, scope) {
+    if ($scope.loading || $scope.pendingSaving) return $q.when();
+    if ($scope.saving) {
+      $scope.pendingSaving = true;
+      // Retry later
+      return $timeout(function() {
+        $scope.pendingSaving = false;
+        return $scope.onDataChanged(oldValue, newValue, scope);
+      }, 500);
+    }
+
+    var updated = !angular.equals(oldValue, newValue);
+    if (updated) {
+      //console.debug('Detected settings update: will save it');
+      $scope.save();
+    }
+  };
+  $scope.$watch('formData', $scope.onDataChanged, true);
 
 
   $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/services/bma-services.js b/www/js/services/bma-services.js
index 1ebeb051..22909ff1 100644
--- a/www/js/services/bma-services.js
+++ b/www/js/services/bma-services.js
@@ -2,7 +2,7 @@
 
 angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.services', 'cesium.settings.services'])
 
-.factory('BMA', function($q, Api, Device, csSettings, csHttp, csCache, $rootScope, $timeout) {
+.factory('BMA', function($q, Api, Device, csSettings, csHttp, $rootScope, $timeout) {
   'ngInject';
 
   function BMA(host, port, useSsl, useCache) {
@@ -41,24 +41,37 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
         regexp: regexp
       },
       listeners,
-      that = this;
+      that = this,
+      startPromise,
+      started = false;
 
     that.date = {now: csHttp.date.now};
     that.api = new Api(this, 'BMA-' + that.server);
+    that.init = init;
 
-    init(host, port, useSsl, useCache);
+    if (host) {
+      init(host, port, useSsl, useCache);
+    }
 
     function init(host, port, useSsl, useCache) {
-      if (!host) {
-        throw new Error('new BMA() need mandatory argument [host]');
-      }
       that.alive = false;
       that.cache = _emptyCache();
+
+      // Use settings as default, if exists
+      if (csSettings.data && csSettings.data.node) {
+        host = host || csSettings.data.node.host;
+        port = port || csSettings.data.node.port;
+        useSsl = angular.isDefined(useSsl) ? useSsl : (csSettings.data.node.port == 443 || csSettings.data.node.useSsl);
+        useCache =  angular.isDefined(useCache) ? useCache : true;
+      }
+
+      if (!host) {
+        return; // could not init yet
+      }
       that.host = host;
       that.port = port || 80;
       that.useSsl = angular.isDefined(useSsl) ? useSsl : (that.port == 443);
       that.useCache = angular.isDefined(useCache) ? useCache : false;
-
       that.server = csHttp.getServer(host, port);
       that.url = csHttp.getUrl(host, port, useSsl);
     }
@@ -89,9 +102,19 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
     };
 
     get = function (path, cacheTime) {
+
       cacheTime = that.useCache && cacheTime;
       var cacheKey = path + (cacheTime ? ('#'+cacheTime) : '');
-      return function(params) {
+
+      var getRequest = function(params) {
+
+        if (!started) {
+          console.debug('[BMA] get waiting start finished...');
+          return that.ready().then(function() {
+            return getRequest(params);
+          });
+        }
+
         var request = that.cache.getByPath[cacheKey];
         if (!request) {
           if (cacheTime) {
@@ -104,10 +127,19 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
         }
         return request(params);
       };
+
+      return getRequest;
     };
 
     post = function(path) {
-      return function(obj, params) {
+      postRequest = function(obj, params) {
+        if (!started) {
+          console.debug('[BMA] post waiting start finished...');
+          return that.ready().then(function() {
+            return postRequest(obj, params);
+          });
+        }
+
         var request = that.cache.postByPath[path];
         if (!request) {
           request =  csHttp.post(that.host, that.port, path, that.useSsl);
@@ -115,6 +147,8 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
         }
         return request(obj, params);
       };
+
+      return postRequest;
     };
 
     ws = function(path) {
@@ -129,7 +163,7 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
     };
 
     that.isAlive = function() {
-      return that.node.summary()
+      return csHttp.get(that.host, that.port, '/node/summary', that.useSsl)()
         .then(function(json) {
           var isDuniter = json && json.duniter && json.duniter.software == 'duniter' && json.duniter.version;
           var isCompatible = isDuniter && csHttp.version.isCompatible(csSettings.data.minVersion, json.duniter.version);
@@ -167,17 +201,44 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
       }
     }
 
+    that.isStarted = function() {
+      return started;
+    };
+
+    that.ready = function() {
+      if (started) return $q.when();
+      return startPromise || that.start();
+    };
+
     that.start = function() {
+      if (startPromise) return startPromise;
+
+      if (!that.host) {
+        return csSettings.ready()
+          .then(function() {
+            that.init();
+
+            // Always enable cache
+            that.useCache = true;
+
+            return that.start(); // recursive call
+          });
+      }
 
       console.debug('[BMA] Starting [{0}]...'.format(that.server));
       var now = new Date().getTime();
 
-      return that.isAlive()
+      startPromise = $q.all([
+          csSettings.ready,
+          that.isAlive()
+        ])
         .then(function(alive) {
           that.alive = alive;
           if (!alive) {
             // TODO : alert user ?
             console.error('[BMA] Could not start [{0}]: node unreachable'.format(that.server));
+            started = true;
+            startPromise = null;
             return false;
           }
 
@@ -188,8 +249,11 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
           console.debug('[BMA] Started in '+(new Date().getTime()-now)+'ms');
 
           that.api.node.raise.start();
+          started = true;
+          startPromise = null;
           return true;
         });
+      return startPromise;
     };
 
     that.stop = function() {
@@ -201,6 +265,7 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
     };
 
     that.restart = function() {
+      csHttp.cache.clear();
       that.stop();
       return $timeout(function() {
         that.start();
@@ -223,10 +288,6 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
         BMAS_ENDPOINT: exact(regexp.BMAS_ENDPOINT)
       },
       node: {
-        server: that.server,
-        url: that.url,
-        host: host,
-        port: port,
         summary: get('/node/summary', csHttp.cache.LONG),
         same: function(host2, port2) {
           return host2 == host && ((!port && !port2) || (port == port2));
@@ -286,13 +347,26 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
     };
 
     exports.node.parseEndPoint = function(endpoint) {
+      // Try BMA
       var matches = exports.regex.BMA_ENDPOINT.exec(endpoint);
+      if (matches) {
+        return {
+          "dns": matches[2] || '',
+          "ipv4": matches[4] || '',
+          "ipv6": matches[6] || '',
+          "port": matches[8] || 80,
+          "useSsl": matches[8] && matches[8] == 443
+        };
+      }
+      // Try BMAS
+      matches = exports.regex.BMAS_ENDPOINT.exec(endpoint);;
       if (!matches) return;
       return {
         "dns": matches[2] || '',
         "ipv4": matches[4] || '',
         "ipv6": matches[6] || '',
-        "port": matches[8] || 80
+        "port": matches[8] || 80,
+        "useSsl": true
       };
     };
 
@@ -528,14 +602,12 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
     angular.merge(that, exports);
   }
 
-  var service = new BMA(
-    csSettings.data.node.host,
-    csSettings.data.node.port,
-    csSettings.data.node.port == 443 || csSettings.data.node.useSsl,
-    true /*cache*/);
+  var service = new BMA();
 
   service.instance = function(host, port, useSsl, useCache) {
-    return new BMA(host, port, useSsl, useCache);
+    var bma = new BMA();
+    bma.init(host, port, useSsl, useCache);
+    return bma;
   };
 
   service.lightInstance = function(host, port, useSsl) {
@@ -559,10 +631,11 @@ angular.module('cesium.bma.services', ['ngResource', 'ngApi', 'cesium.http.servi
       }
     };
   };
-  /*Device.ready().then(function() {
+
+  // default action
+  Device.ready().then(function() {
     return service.start();
-  });*/
-  service.start();
+  });
 
   return service;
 })
diff --git a/www/js/services/cache-services.js b/www/js/services/cache-services.js
index 83bc2947..24836804 100644
--- a/www/js/services/cache-services.js
+++ b/www/js/services/cache-services.js
@@ -3,89 +3,84 @@ angular.module('cesium.cache.services', ['ngResource', 'angular-cache'])
 .factory('csCache', function($http, csSettings, CacheFactory) {
   'ngInject';
 
-  function factory() {
+  var
+    constants = {
+      LONG: 1 * 60  * 60 * 1000 /*5 min*/,
+      SHORT: csSettings.defaultSettings.cacheTimeMs
+    },
+    cacheNames = []
+  ;
 
-    var
-      constants = {
-        LONG: 1 * 60  * 60 * 1000 /*5 min*/,
-        SHORT: csSettings.data.cacheTimeMs
-      },
-      cacheNames = []
-    ;
-
-    function getOrCreateCache(prefix, maxAge, onExpire){
-      prefix = prefix || 'csCache-';
-      maxAge = maxAge || constants.cache.SHORT;
-      var cacheName = prefix + maxAge;
-      if (!onExpire) {
-        if (!cacheNames[cacheName]) {
-          cacheNames[cacheName] = true;
-        }
-        return CacheFactory.get(cacheName) ||
-          CacheFactory.createCache(cacheName, {
-            maxAge: maxAge,
-            deleteOnExpire: 'aggressive',
-            //cacheFlushInterval: 60 * 60 * 1000, //  clear itself every hour
-            recycleFreq: Math.max(maxAge - 1000, 5 * 60 * 1000 /*5min*/),
-            storageMode: 'memory'
-              // FIXME : enable this when cache is cleaning on rollback
-              //csSettings.data.useLocalStorage ? 'localStorage' : 'memory'
-          });
+  function getOrCreateCache(prefix, maxAge, onExpire){
+    prefix = prefix || 'csCache-';
+    maxAge = maxAge || constants.SHORT;
+    var cacheName = prefix + maxAge;
+    if (!onExpire) {
+      if (!cacheNames[cacheName]) {
+        cacheNames[cacheName] = true;
       }
-      else {
-        var counter = 1;
-        while(CacheFactory.get(cacheName + counter)) {
-          counter++;
-        }
-        cacheName = cacheName + counter;
-        if (!cacheNames[cacheName]) {
-          cacheNames[cacheName] = true;
-        }
-        return CacheFactory.createCache(cacheName, {
-            maxAge: maxAge,
-            deleteOnExpire: 'aggressive',
-            //cacheFlushInterval: 60 * 60 * 1000, // This cache will clear itself every hour
-            recycleFreq: maxAge,
-            onExpire: onExpire,
-            storageMode: 'memory'
-              // FIXME : enable this when cache is cleaning on rollback
-              //csSettings.data.useLocalStorage ? 'localStorage' : 'memory'
-          });
+      return CacheFactory.get(cacheName) ||
+        CacheFactory.createCache(cacheName, {
+          maxAge: maxAge,
+          deleteOnExpire: 'aggressive',
+          //cacheFlushInterval: 60 * 60 * 1000, //  clear itself every hour
+          recycleFreq: Math.max(maxAge - 1000, 5 * 60 * 1000 /*5min*/),
+          storageMode: 'memory'
+            // FIXME : enable this when cache is cleaning on rollback
+            //csSettings.data.useLocalStorage ? 'localStorage' : 'memory'
+        });
+    }
+    else {
+      var counter = 1;
+      while(CacheFactory.get(cacheName + counter)) {
+        counter++;
+      }
+      cacheName = cacheName + counter;
+      if (!cacheNames[cacheName]) {
+        cacheNames[cacheName] = true;
       }
+      return CacheFactory.createCache(cacheName, {
+          maxAge: maxAge,
+          deleteOnExpire: 'aggressive',
+          //cacheFlushInterval: 60 * 60 * 1000, // This cache will clear itself every hour
+          recycleFreq: maxAge,
+          onExpire: onExpire,
+          storageMode: 'memory'
+            // FIXME : enable this when cache is cleaning on rollback
+            //csSettings.data.useLocalStorage ? 'localStorage' : 'memory'
+        });
     }
+  }
+
+  function clearAllCaches() {
+    console.debug("[cache] cleaning all caches");
+    _.forEach(_.keys(cacheNames), function(cacheName) {
+      var cache = CacheFactory.get(cacheName);
+      if (cache) {
+        cache.removeAll();
+      }
+    });
+  }
 
-    function clearAllCaches() {
-      console.debug("[http] cleaning all caches");
-      _.forEach(_.keys(cacheNames), function(cacheName) {
-        var cache = CacheFactory.get(cacheName);
+  function clearFromPrefix(cachePrefix) {
+    _.forEach(_.keys(cacheNames), function(cacheName) {
+      if (cacheName.startsWith(cachePrefix)) {
+        var cache = CacheFactory.get(cacheNames);
         if (cache) {
           cache.removeAll();
         }
-      });
-    }
-
-    function clearFromPrefix(cachePrefix) {
-      _.forEach(_.keys(cacheNames), function(cacheName) {
-        if (cacheName.startsWith(cachePrefix)) {
-          var cache = CacheFactory.get(cacheNames);
-          if (cache) {
-            cache.removeAll();
-          }
-        }
-      });
-    }
-
-    return {
-      get: getOrCreateCache,
-      clear: clearFromPrefix,
-      clearAll: clearAllCaches,
-      constants: {
-        LONG : constants.LONG,
-        SHORT: constants.SHORT
       }
-    };
+    });
   }
 
-  return factory();
+  return {
+    get: getOrCreateCache,
+    clear: clearFromPrefix,
+    clearAll: clearAllCaches,
+    constants: {
+      LONG : constants.LONG,
+      SHORT: constants.SHORT
+    }
+  };
 })
 ;
diff --git a/www/js/services/crypto-services.js b/www/js/services/crypto-services.js
index c710479e..630f7ba4 100644
--- a/www/js/services/crypto-services.js
+++ b/www/js/services/crypto-services.js
@@ -2,7 +2,7 @@
 
 angular.module('cesium.crypto.services', ['ngResource', 'cesium.device.services'])
 
-  .factory('CryptoUtils', function($q, $timeout, Device) {
+  .factory('CryptoUtils', function($q, $timeout, ionicReady) {
     'ngInject';
 
     /**
@@ -606,13 +606,18 @@ angular.module('cesium.crypto.services', ['ngResource', 'cesium.device.services'
 
     var service = new CryptoAbstractService();
 
-    Device.ready().then(function() {
+    var isDevice = true;
+    // removeIf(device)
+    isDevice = false;
+    // endRemoveIf(device)
+
+    ionicReady().then(function() {
       var now = new Date().getTime();
 
       var serviceImpl;
 
       // Use Cordova plugin implementation, when exists
-      if (Device.enable && window.plugins && window.plugins.MiniSodium && crypto && crypto.getRandomValues) {
+      if (isDevice && window.plugins && window.plugins.MiniSodium && crypto && crypto.getRandomValues) {
         console.debug('[crypto] Loading Cordova MiniSodium implementation...');
         serviceImpl = new CordovaServiceFactory();
       }
diff --git a/www/js/services/currency-services.js b/www/js/services/currency-services.js
index ba0b5809..6f7b2dcf 100644
--- a/www/js/services/currency-services.js
+++ b/www/js/services/currency-services.js
@@ -26,9 +26,9 @@ angular.module('cesium.currency.services', ['ngResource', 'ngApi', 'cesium.bma.s
             data.currencies.push({
                 name: res.currency,
                 peer: {
-                  host: BMA.node.host,
-                  port: BMA.node.port,
-                  server: BMA.node.server
+                  host: BMA.host,
+                  port: BMA.port,
+                  server: BMA.server
                 },
                 parameters: res
               });
diff --git a/www/js/services/device-services.js b/www/js/services/device-services.js
index 8f0df0a2..6e2598e6 100644
--- a/www/js/services/device-services.js
+++ b/www/js/services/device-services.js
@@ -1,12 +1,25 @@
 
-angular.module('cesium.device.services', ['ngResource', 'cesium.utils.services'])
+angular.module('cesium.device.services', ['ngResource', 'cesium.utils.services', 'cesium.settings.services'])
+
+  // Replace the '$ionicPlatform.ready()', to enable multiple calls
+  // See http://stealthcode.co/multiple-calls-to-ionicplatform-ready/
+  .factory('ionicReady', function($ionicPlatform) {
+    var readyPromise;
+
+    return function () {
+      if (!readyPromise) {
+        readyPromise = $ionicPlatform.ready();
+      }
+      return readyPromise;
+    };
+  })
 
   .factory('Device',
     function($translate, $ionicPopup, $q,
       // removeIf(no-device)
       $cordovaClipboard, $cordovaBarcodeScanner, $cordovaCamera,
       // endRemoveIf(no-device)
-      $ionicPlatform) {
+      ionicReady, csSettings) {
       'ngInject';
 
       var
@@ -14,7 +27,6 @@ angular.module('cesium.device.services', ['ngResource', 'cesium.utils.services']
           MAX_HEIGHT: 400,
           MAX_WIDTH: 400
         },
-        readyPromise,
         exports = {
           // workaround to quickly no is device or not (even before the ready() event)
           enable: true
@@ -118,13 +130,14 @@ angular.module('cesium.device.services', ['ngResource', 'cesium.utils.services']
         return deferred.promise;
       }
 
-      // Replace the '$ionicPlatform.ready()', to enable multiple calls
-      readyPromise = $ionicPlatform.ready();
-      function ready() {
-        return readyPromise;
-      }
+      exports.clipboard = {copy: copy};
+      exports.camera = {
+          getPicture : getPicture,
+          scan: scan
+        };
 
-      readyPromise.then(function(){
+      var started = false;
+      var startPromise = ionicReady().then(function(){
 
         var enableCamera = !!navigator.camera;
         exports.enable = enableCamera;
@@ -141,16 +154,24 @@ angular.module('cesium.device.services', ['ngResource', 'cesium.utils.services']
         else {
           console.debug('[device] Ionic platform ready - no device detected.');
         }
+
+        started = true;
+        startPromise = null;
       });
 
-      exports.ready = function() {
+      var readyPromise;
+
+      // backward compat
+      exports.ready = function () {
+        if (!readyPromise) {
+          readyPromise = $q.all([
+            ionicReady(),
+            csSettings.ready()
+          ]);
+        }
         return readyPromise;
       };
-      exports.clipboard = {copy: copy};
-      exports.camera = {
-          getPicture : getPicture,
-          scan: scan
-        };
+
       return exports;
     })
 
diff --git a/www/js/services/http-services.js b/www/js/services/http-services.js
index 92948c43..1edcf835 100644
--- a/www/js/services/http-services.js
+++ b/www/js/services/http-services.js
@@ -258,6 +258,12 @@ angular.module('cesium.http.services', ['ngResource', 'cesium.cache.services'])
     return true;
   }
 
+  var cache = angular.copy(csCache.constants);
+  cache.clear = function() {
+    console.debug('[http] Cleaning cache...');
+    csCache.clear(cachePrefix);
+  };
+
   return {
     get: getResource,
     getWithCache: getResourceWithCache,
@@ -275,7 +281,7 @@ angular.module('cesium.http.services', ['ngResource', 'cesium.cache.services'])
     version: {
       isCompatible: isVersionCompatible
     },
-    cache: csCache.constants
+    cache: cache
   };
 })
 ;
diff --git a/www/js/services/network-services.js b/www/js/services/network-services.js
index 56ff6a1e..86e44091 100644
--- a/www/js/services/network-services.js
+++ b/www/js/services/network-services.js
@@ -485,21 +485,24 @@ angular.module('cesium.network.services', ['ngResource', 'ngApi', 'cesium.bma.se
 
       start = function(bma, options) {
         options = options || {};
-        return $q(function(resolve, reject) {
-          close();
-          data.bma = bma ? bma : BMA;
-          data.filter = options.filter ? angular.merge(data.filter, options.filter) : data.filter;
-          data.sort = options.sort ? angular.merge(data.sort, options.sort) : data.sort;
-          data.expertMode = angular.isDefined(options.expertMode) ?options.expertMode : data.expertMode;
-          console.info('[network] Starting network from [{0}]'.format(bma.node.server));
-          var now = new Date();
-          startListeningOnSocket(resolve, reject);
-          loadPeers()
-            .then(function(peers){
-              resolve(peers);
-              console.debug('[network] Started in '+(new Date().getTime() - now.getTime())+'ms');
-            });
-        });
+        return BMA.ready()
+          .then(function() {
+            close();
+            data.bma = bma ? bma : BMA;
+            data.filter = options.filter ? angular.merge(data.filter, options.filter) : data.filter;
+            data.sort = options.sort ? angular.merge(data.sort, options.sort) : data.sort;
+            data.expertMode = angular.isDefined(options.expertMode) ?options.expertMode : data.expertMode;
+            console.info('[network] Starting network from [{0}]'.format(bma.server));
+            var now = new Date();
+
+            startListeningOnSocket();
+
+            return loadPeers()
+              .then(function(peers){
+                console.debug('[network] Started in '+(new Date().getTime() - now.getTime())+'ms');
+                return peers;
+              });
+          });
       },
 
       close = function() {
diff --git a/www/js/services/plugin-services.js b/www/js/services/plugin-services.js
index ad88ff3b..05e94d74 100644
--- a/www/js/services/plugin-services.js
+++ b/www/js/services/plugin-services.js
@@ -32,7 +32,7 @@ angular.module('cesium.plugin.services', [])
     return this;
   };
 
-  this.$get = ['$injector', '$state', function pluginFactory($injector, $state) {
+  this.$get = ['$injector', '$state', function($injector, $state) {
 
     var currentExtensionPointName;
 
diff --git a/www/js/services/settings-services.js b/www/js/services/settings-services.js
index c6f39b47..7f632d5a 100644
--- a/www/js/services/settings-services.js
+++ b/www/js/services/settings-services.js
@@ -1,7 +1,7 @@
 
-angular.module('cesium.settings.services', ['ngResource', 'ngApi', 'cesium.config', 'cesium.device.services'])
+angular.module('cesium.settings.services', ['ngResource', 'ngApi', 'cesium.config'])
 
-.factory('csSettings', function($rootScope, $q, Api, localStorage, $translate, csConfig, Device) {
+.factory('csSettings', function($rootScope, $q, Api, localStorage, $translate, csConfig) {
   'ngInject';
 
   // Define app locales
@@ -54,10 +54,10 @@ angular.module('cesium.settings.services', ['ngResource', 'ngApi', 'cesium.confi
     useRelative: false,
     timeWarningExpireMembership: 2592000 * 2 /*=2 mois*/,
     timeWarningExpire: 2592000 * 3 /*=3 mois*/,
-    useLocalStorage: Device.enable, // on mobile device, use local storage by default
+    useLocalStorage: true, // override to false if no device
     walletHistoryTimeSecond: 30 * 24 * 60 * 60 /*30 days*/,
     walletHistorySliceSecond: 5 * 24 * 60 * 60 /*download using 5 days slice*/,
-    rememberMe: Device.enable, // on mobile device, remember me by default
+    rememberMe: true, // override to false if no device
     showUDHistory: true,
     showLoginSalt: false,
     initPhase: false, // For currency start (when block #0 not written)
@@ -89,11 +89,21 @@ angular.module('cesium.settings.services', ['ngResource', 'ngApi', 'cesium.confi
     }
   }, csConfig),
 
+
+
   data = {},
   previousData,
+  started = false,
+  startPromise,
+  api = new Api(this, "csSettings");
 
-  api = new Api(this, "csSettings"),
+  // Change some defaults, when no device
+  // removeIf(device)
+  defaultSettings.useLocalStorage = false;
+  defaultSettings.rememberMe = false;
+  // endRemoveIf(device)
 
+  var
   reset = function() {
     _.keys(data).forEach(function(key){
       delete data[key];
@@ -127,15 +137,30 @@ angular.module('cesium.settings.services', ['ngResource', 'ngApi', 'cesium.confi
   },
 
   store = function() {
+    if (!started) {
+      console.debug('[setting] Waiting start finished...');
+      return startPromise.then(store);
+    }
+
+    var promise;
     if (data.useLocalStorage) {
-      localStorage.setObject(constants.STORAGE_KEY, data);
+      promise = localStorage.setObject(constants.STORAGE_KEY, data);
     }
     else {
-      localStorage.setObject(constants.STORAGE_KEY, null);
+      promise  = localStorage.setObject(constants.STORAGE_KEY, null);
     }
 
-    // Emit event on store
-    return api.data.raisePromise.store(data)
+    return promise
+      .then(function() {
+        if (data.useLocalStorage) {
+          console.debug('[setting] Saved');
+        }
+
+        // Emit event on store
+        return api.data.raisePromise.store(data);
+      })
+
+      // Emit event on store
       .then(emitChangedEvent);
   },
 
@@ -166,54 +191,22 @@ angular.module('cesium.settings.services', ['ngResource', 'ngApi', 'cesium.confi
 
   restore = function() {
     var now = new Date().getTime();
-    return $q(function(resolve, reject){
-      console.debug("[settings] Loading from local storage...");
-      var storedData = localStorage.getObject(constants.STORAGE_KEY);
-
-      var finishRestore = function() {
-        emitChangedEvent();
-        resolve();
-      };
-
-      // No settings stored
-      if (!storedData) {
-        console.debug("[settings] No settings in local storage. Using defaults.");
-        applyData(defaultSettings);
-        finishRestore();
-        return;
-      }
-
-      // Workaround to get node info from Cesium < 0.2.0
-      if (storedData.DUNITER_NODE) {
-        var nodePart = storedData.DUNITER_NODE.split(':');
-        if (nodePart.length == 1 || nodePart.length == 2) {
-          storedData.node = {
-            host: nodePart[0],
-            port: nodePart[1] // could be undefined, but that's fine
-          };
-        }
-        delete storedData.DUNITER_NODE;
-      }
-      if (storedData.DUNITER_NODE_ES) {
-        var esNodePart = storedData.DUNITER_NODE_ES.split(':');
-        if (esNodePart.length == 1 || esNodePart.length == 2) {
-          storedData.plugins = {
-            es: {
-              enable: true,
-              host: esNodePart[0],
-              port: esNodePart[1] // could be undefined, but that's fine
-            }
-          };
-        }
-        delete storedData.DUNITER_NODE_ES;
-      }
-
-      // Apply stored data
-      applyData(storedData);
-
-      console.debug('[settings] Loaded from local storage in '+(new Date().getTime()-now)+'ms');
-      finishRestore();
-    });
+    return localStorage.getObject(constants.STORAGE_KEY)
+        .then(function(storedData) {
+          // No settings stored
+          if (!storedData) {
+            console.debug("[settings] No settings in local storage. Using defaults.");
+            applyData(defaultSettings);
+            emitChangedEvent();
+            return;
+          }
+
+          // Apply stored data
+          applyData(storedData);
+
+          console.debug('[settings] Loaded from local storage in '+(new Date().getTime()-now)+'ms');
+          emitChangedEvent();
+        });
   },
 
     // Detect locale sucessuf changes, then apply to vendor libs
@@ -243,8 +236,30 @@ angular.module('cesium.settings.services', ['ngResource', 'ngApi', 'cesium.confi
     api.locale.raise.changed(locale);
   },
 
+
+  ready = function() {
+    if (started) return $q.when();
+    return startPromise || start();
+  },
+
   start = function() {
-    restore().then(api.data.raise.ready);
+    console.debug('[settings] Starting...');
+
+    startPromise = localStorage.ready()
+
+      // Restore
+      .then(restore)
+
+      // Emit ready event
+      .then(function() {
+        console.debug('[settings] Started');
+        started = true;
+        startPromise = null;
+        // Emit event
+        api.data.raise.ready(data);
+      });
+
+    return startPromise;
   };
 
   $rootScope.$on('$translateChangeSuccess', onLocaleChange);
@@ -256,10 +271,13 @@ angular.module('cesium.settings.services', ['ngResource', 'ngApi', 'cesium.confi
   api.registerEvent('locale', 'changed');
 
   // Apply default settings. This is required on some browser (web or mobile - see #361)
-  applyData(defaultSettings);
+  //applyData(defaultSettings);
+
+  // Default action
+  start();
 
   return {
-    start : start,
+    ready: ready,
     data: data,
     getByPath: getByPath,
     reset: reset,
diff --git a/www/js/services/storage-services.js b/www/js/services/storage-services.js
index 45574bdd..5451b647 100644
--- a/www/js/services/storage-services.js
+++ b/www/js/services/storage-services.js
@@ -1,61 +1,107 @@
-angular.module('cesium.storage.services', ['ngResource', 'ngResource', 'xdLocalStorage',
- 'cesium.device.services', 'cesium.config'])
+angular.module('cesium.storage.services', ['ngResource', 'ngResource', 'xdLocalStorage', 'ngApi', 'cesium.config'])
 
-.factory('localStorage', function($window, $q, $rootScope, Device, csConfig, xdLocalStorage) {
+.factory('localStorage', function($window, $q, $rootScope, $timeout, ionicReady, csConfig, Api, xdLocalStorage) {
   'ngInject';
 
   var
     appName = "Cesium",
-    localStorage = $window.localStorage,
+    api = new Api(this, "localStorage"),
+    started = false,
+    startPromise,
+    tryInitSecureStorage = true, // default for device (override later)
     exports = {
+      api: api,
       useHttpsFrame: false,
-      unsecure: {},
-      https: {},
+      standard: {
+        storage: null
+      },
+      xd: {
+        enable: false
+      },
       secure: {
         storage: null
       }
     };
 
-  /* -- Use default default browser implementation -- */
+  // removeIf(device)
+  // Use this workaround to avoid the use of Device service (could cause a circular reference)
+  tryInitSecureStorage = false;
+  // endRemoveIf(device)
+
+  /* -- Use standard browser implementation -- */
 
-  exports.unsecure.put = function(key, value) {
-    localStorage[key] = value;
+  exports.standard.put = function(key, value) {
+    exports.standard.storage[key] = value;
+    return $q.when();
   };
 
-  exports.unsecure.get = function(key, defaultValue) {
-    return localStorage[key] || defaultValue;
+  exports.standard.get = function(key, defaultValue) {
+    return $q.when(exports.standard.storage[key] || defaultValue);
   };
 
-  exports.unsecure.setObject = function(key, value) {
-    localStorage[key] = JSON.stringify(value);
+  exports.standard.setObject = function(key, value) {
+    exports.standard.storage[key] = JSON.stringify(value);
+    return $q.when();
   };
 
-  exports.unsecure.getObject = function(key) {
-    return JSON.parse(localStorage[key] || '{}');
+  exports.standard.getObject = function(key) {
+    return $q.when(JSON.parse(exports.standard.storage[key] || '{}'));
   };
 
 
-  /* -- Use of HTTPS frame -- */
+  /* -- Use of cross-domain HTTPS iframe -- */
   // See https://github.com/ofirdagan/cross-domain-local-storage
 
-  exports.https.put = function(key, value) {
-    console.log('TODO: setting [{0}] into https frame'.format(key));
-  };
+  exports.xd.put = function(key, value) {
+    if (!started) {
+      console.debug('[storage] Waiting start finished...');
+      return startPromise.then(function(){
+        return exports.xd.put(key, value);
+      });
+    }
 
-  exports.https.get = function(key, defaultValue) {
-    console.log('TODO: getting [{0}] from https frame'.format(key));
-    return localStorage[key] || defaultValue;
+    xdLocalStorage.setItem(key, value);
   };
 
-  exports.https.setObject = function(key, value) {
-    console.log('TODO: setting object [{0}] into https frame'.format(key));
+  exports.xd.get = function(key, defaultValue) {
+    if (!started) {
+      console.debug('[storage] Waiting start finished...');
+      return startPromise.then(function(){
+        return exports.xd.get(key, defaultValue);
+      });
+    }
+
+    return xdLocalStorage.getItem(key).then(function(response){
+      return (response && response.value) || defaultValue;
+    });
   };
 
-  exports.https.getObject = function(key) {
-    console.log('TODO: getting object [{0}] from https frame'.format(key));
-    return JSON.parse(localStorage[key] || '{}');
+  exports.xd.setObject = function(key, value) {
+    if (!started) {
+      console.debug('[storage] Waiting start finished...');
+      return startPromise.then(function(){
+        return exports.xd.setObject(key, value);
+      });
+    }
+
+    if (!value) {
+      return xdLocalStorage.removeItem(key);
+    }
+    return xdLocalStorage.setItem(key, JSON.stringify(value));
   };
 
+  exports.xd.getObject = function(key, defaultObject) {
+    if (!started) {
+      console.debug('[storage] Waiting start finished...');
+      return startPromise.then(function(){
+        return exports.xd.getObject(key, defaultObject);
+      });
+    }
+
+    return xdLocalStorage.getItem(key).then(function(response){
+      return response && response.value && JSON.parse(response.value) || defaultObject;
+    });
+  };
 
   /* -- Use secure storage (using a cordova plugin) -- */
 
@@ -104,48 +150,128 @@ angular.module('cesium.storage.services', ['ngResource', 'ngResource', 'xdLocalS
   exports.secure.getObject = function(key) {
     return exports.secure.get(key)
       .then(function(value) {
-        return JSON.parse(localStorage[key] || '{}');
+        return (value && JSON.parse(value)) || {};
       });
   };
 
-  // Copy HTTPS functions as default function
-  if (csConfig.httpsMode === 'clever' && $window.location.protocol !== 'https:') {
-    _.forEach(_.keys(exports.https), function(key) {
-      exports[key] = exports.https[key];
+  function initStandardStorage() {
+    console.debug('[storage] Starting [standard mode]...');
+   exports.standard.storage = $window.localStorage;
+    // Set standard storage as default
+    _.forEach(_.keys(exports.standard), function(key) {
+      exports[key] = exports.standard[key];
     });
+
+    return $q.when();
   }
 
-  else {
-    // Copy unsecure function as default function
-    _.forEach(_.keys(exports.unsecure), function(key) {
-      exports[key] = exports.unsecure[key];
+  function initXdStorage() {
+    // Compute the HTTPS iframe url
+    var href = $window.location.href;
+    var hashIndex = href.indexOf('#');
+    var rootPath = (hashIndex != -1) ? href.substr(0, hashIndex) : href;
+    var iframeUrl = 'https' + rootPath.substr(4);
+    if (iframeUrl.charAt(iframeUrl.length-1) != '/') iframeUrl += '/'; // end slash
+    iframeUrl += 'https-storage.html';
+
+    console.debug('[storage] Starting [cross-domain mode] using iframe [{0}]'.format(iframeUrl));
+
+    // Set cross-domain storage as default
+    _.forEach(_.keys(exports.xd), function(key) {
+      exports[key] = exports.xd[key];
     });
-  }
 
+    var isOK = false;
+    var deferred = $q.defer();
+
+    // Timeout, in case the frame could not be loaded
+    $timeout(function() {
+      if (!isOK) {
+        // TODO: alert user ?
+        console.error('[storage] https frame not loaded (timeout). Trying standard mode...');
+        deferred.resolve(initStandardStorage());
+      }
+    }, csConfig.timeout);
 
-  Device.ready().then(function() {
+    xdLocalStorage.init({iframeUrl: iframeUrl})
+      .then(function() {
+        isOK = true;
+        deferred.resolve();
+      })
+      .catch(function(err) {
+        console.error('[storage] Could not init cross-domain storage. Trying standard mode...', err);
+        deferred.resolve(initStandardStorage());
+      });
+    return deferred.promise;
+  }
 
-    function replaceSecureStorage() {
-      exports.secure = exports.unsecure;
-      exports.secure.storage = null;
-    }
+  function initSecureStorage() {
+    console.debug('[storage] Starting [secure mode]...');
+    // Set secure storage as default
+    _.forEach(_.keys(exports.secure), function(key) {
+      exports[key] = exports.secure[key];
+    });
 
-    if (Device.enable) {
+    var deferred = $q.defer();
+
+    ionicReady().then(function() {
+      if (!cordova.plugins || !cordova.plugins.SecureStorage) {
+        deferred.resolve(initStandardStorage());
+        return;
+      }
       exports.secure.storage = new cordova.plugins.SecureStorage(
         function () {
-          console.log('[storage] Secure storage initialized.');
+          deferred.resolve();
         },
-        function (error) {
-          console.error('[storage] Could not use secure storage: ' + error);
-          replaceSecureStorage();
+        function (err) {
+          console.error('[storage] Could not use secure storage. Will use standard.', err);
+          deferred.resolve(initStandardStorage());
         },
         appName);
+    });
+
+    return deferred.promise;
+  }
+
+  exports.isStarted = function() {
+    return started;
+  };
+
+  exports.ready = function() {
+    if (started) return $q.when();
+    return startPromise || start();
+  };
+
+  function start() {
+    if (startPromise) return startPromise;
+
+    var now = new Date().getTime();
+
+    // Is site on both HTTPS and HTTP: Need to use cross-domain storage
+    if (csConfig.httpsMode === 'clever' && $window.location.protocol !== 'https:') {
+      startPromise = initXdStorage();
     }
+
+    // Use Cordova secure storage plugin
+    else if (tryInitSecureStorage) {
+      startPromise = initSecureStorage();
+    }
+
+    // Use default browser local storage
     else {
-      replaceSecureStorage();
+      startPromise = initStandardStorage();
     }
 
-  });
+    return startPromise
+      .then(function() {
+        console.debug('[storage] Started in ' + (new Date().getTime() - now) + 'ms');
+        started = true;
+        startPromise = null;
+      });
+  }
+
+  // default action
+  start();
 
   return exports;
 })
diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js
index 3d1b9566..28900f88 100644
--- a/www/js/services/wallet-services.js
+++ b/www/js/services/wallet-services.js
@@ -257,45 +257,41 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser
     },
 
     restore = function() {
-      return $q(function(resolve, reject){
-        var dataStr = localStorage.get(constants.STORAGE_KEY);
-        if (!dataStr) {
-          resolve();
-          return;
-        }
-        fromJson(dataStr, false)
-        .then(function(storedData){
-          if (storedData && storedData.keypair && storedData.pubkey) {
-            data.keypair = storedData.keypair;
-            data.pubkey = storedData.pubkey;
-            if (storedData.tx && storedData.tx.pendings) {
-              data.tx.pendings = storedData.tx.pendings;
-            }
-            data.loaded = false;
+      return localStorage.get(constants.STORAGE_KEY)
+        .then(function(dataStr) {
+          if (!dataStr) return;
+          return fromJson(dataStr, false)
+            .then(function(storedData){
+              if (storedData && storedData.keypair && storedData.pubkey) {
+                data.keypair = storedData.keypair;
+                data.pubkey = storedData.pubkey;
+                if (storedData.tx && storedData.tx.pendings) {
+                  data.tx.pendings = storedData.tx.pendings;
+                }
+                data.loaded = false;
 
-            return $q.all([
-              // Call extend api
-              api.data.raisePromise.login(data),
+                return $q.all([
+                  // Call extend api
+                  api.data.raisePromise.login(data),
 
-              // Load parameters
-              // This prevent timeout error, when loading a market record after a browser refresh (e.g. F5)
-              loadParameters(),
+                  // Load parameters
+                  // This prevent timeout error, when loading a market record after a browser refresh (e.g. F5)
+                  loadParameters(),
 
-              // Load current UD is need by features tour
-              loadCurrentUD()
-            ]);
-          }
-          else {
-            // Load parameters
-            // This prevent timeout error, when loading a market record after a browser refresh (e.g. F5)
-            return loadParameters();
-          }
-        })
-        .then(function(){
-          resolve(data);
-        })
-        .catch(function(err){reject(err);});
-      });
+                  // Load current UD is need by features tour
+                  loadCurrentUD()
+                ]);
+              }
+              else {
+                // Load parameters
+                // This prevent timeout error, when loading a market record after a browser refresh (e.g. F5)
+                return loadParameters();
+              }
+            })
+            .then(function(){
+              return data;
+            });
+        });
     },
 
     getData = function() {
diff --git a/www/plugins/es/js/controllers/app-controllers.js b/www/plugins/es/js/controllers/app-controllers.js
index 7f6b5f15..2c148eb4 100644
--- a/www/plugins/es/js/controllers/app-controllers.js
+++ b/www/plugins/es/js/controllers/app-controllers.js
@@ -126,11 +126,8 @@ function ESMenuExtendController($scope, $state, PluginService, csSettings, UIUti
                     !!csSettings.data.plugins.host;
   };
 
-  csSettings.api.data.on.changed($scope, function() {
-    $scope.updateView();
-  });
-
-  $scope.updateView();
+  csSettings.api.data.on.changed($scope, $scope.updateView);
+  csSettings.api.data.on.ready($scope, $scope.updateView);
 
 }
 
diff --git a/www/plugins/es/js/controllers/network-controllers.js b/www/plugins/es/js/controllers/network-controllers.js
index 63152e02..c9562af2 100644
--- a/www/plugins/es/js/controllers/network-controllers.js
+++ b/www/plugins/es/js/controllers/network-controllers.js
@@ -33,9 +33,6 @@ function ESNetworkViewExtendController($scope, PluginService, csSettings) {
       !!csSettings.data.plugins.host;
   };
 
-  csSettings.api.data.on.changed($scope, function() {
-    $scope.updateView();
-  });
-
-  $scope.updateView();
+  csSettings.api.data.on.changed($scope, $scope.updateView);
+  csSettings.api.data.on.ready($scope, $scope.updateView);
 }
diff --git a/www/plugins/es/js/controllers/wot-controllers.js b/www/plugins/es/js/controllers/wot-controllers.js
index 3c77fbc0..2770a739 100644
--- a/www/plugins/es/js/controllers/wot-controllers.js
+++ b/www/plugins/es/js/controllers/wot-controllers.js
@@ -53,11 +53,8 @@ function ESWotIdentityViewController($scope, $ionicPopover, $q, UIUtils, Modals,
       !!csSettings.data.plugins.host;
   };
 
-  csSettings.api.data.on.changed($scope, function() {
-    $scope.updateView();
-  });
-
-  $scope.updateView();
+  csSettings.api.data.on.changed($scope, $scope.updateView);
+  csSettings.api.data.on.ready($scope, $scope.updateView);
 
   /* -- modals -- */
 
diff --git a/www/plugins/es/js/services/http-services.js b/www/plugins/es/js/services/http-services.js
index 436c9930..c68cd548 100644
--- a/www/plugins/es/js/services/http-services.js
+++ b/www/plugins/es/js/services/http-services.js
@@ -17,13 +17,26 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic
       };
 
     that.cache = _emptyCache();
-    that.alive = false;
-    that.host = host;
-    that.port = port || 80;
-    that.wsPort = wsPort || port || 80;
-    that.useSsl = angular.isDefined(useSsl) ? useSsl : false;
-    that.server = csHttp.getServer(host, port);
     that.api = new Api(this, "esHttp");
+    that.init = init;
+
+    init(host, port, wsPort, useSsl);
+
+    function init(host, port, wsPort, useSsl) {
+      // Use settings as default
+      if (csSettings.data) {
+        host = host || (csSettings.data.plugins && csSettings.data.plugins.es ? csSettings.data.plugins.es.host : null);
+        port = port || (host ? csSettings.data.plugins.es.port : null);
+        wsPort = wsPort || (host ? csSettings.data.plugins.es.wsPort : null);
+      }
+
+      that.alive = false;
+      that.host = host;
+      that.port = port || 80;
+      that.wsPort = wsPort || port || 80;
+      that.useSsl = angular.isDefined(useSsl) ? useSsl : false;
+      that.server = csHttp.getServer(host, port);
+    }
 
     function exact(regexpContent) {
       return new RegExp('^' + regexpContent + '$');
@@ -50,11 +63,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic
     };
 
     that.copy = function(otherNode) {
-      that.host = otherNode.host;
-      that.port = otherNode.port;
-      that.wsPort = otherNode.wsPort || otherNode.port;
-      that.useSsl = otherNode.useSsl;
-      that.server = csHttp.getServer(host, port);
+      that.init(otherNode.host, otherNode.port, otherNode.wsPort, otherNode.useSsl);
       return that.restart();
     };
 
@@ -110,19 +119,22 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic
 
     that.start = function() {
 
-      console.debug('[ES] [http] Starting on [{0}]...'.format(that.server));
-      var now = new Date().getTime();
-
-      return that.isAlive()
-        .then(function(alive) {
-          that.alive = alive;
-          if (!alive) {
-            console.error('[ES] [http] Could not start [{0}]: node unreachable'.format(that.server));
-            return false;
-          }
-          console.debug('[ES] [http] Started in '+(new Date().getTime()-now)+'ms');
-          that.api.node.raise.start();
-          return true;
+      return csSettings.ready()
+        .then(service.init)
+        .then(function() {
+          console.debug('[ES] [http] Starting on [{0}]...'.format(that.server));
+          var now = new Date().getTime();
+          return that.isAlive()
+            .then(function(alive) {
+              that.alive = alive;
+              if (!alive) {
+                console.error('[ES] [http] Could not start [{0}]: node unreachable'.format(that.server));
+                return false;
+              }
+              console.debug('[ES] [http] Started in '+(new Date().getTime()-now)+'ms');
+              that.api.node.raise.start();
+              return true;
+            });
         });
     };
 
@@ -423,11 +435,8 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic
     angular.merge(that, exports);
   }
 
-  var host = csSettings.data.plugins && csSettings.data.plugins.es ? csSettings.data.plugins.es.host : null;
-  var port = host ? csSettings.data.plugins.es.port : null;
-  var wsPort = host ? csSettings.data.plugins.es.wsPort : null;
 
-  var service = new Factory(host, port, wsPort);
+  var service = new Factory();
 
   service.instance = function(host, port, wsPort) {
     return new Factory(host, port, wsPort);
diff --git a/www/plugins/es/js/services/settings-services.js b/www/plugins/es/js/services/settings-services.js
index d35307e0..aeba31e1 100644
--- a/www/plugins/es/js/services/settings-services.js
+++ b/www/plugins/es/js/services/settings-services.js
@@ -14,340 +14,336 @@ angular.module('cesium.es.settings.services', ['cesium.services', 'cesium.es.htt
                             csConfig, csSettings, CryptoUtils, Device, UIUtils, csWallet) {
   'ngInject';
 
-  function Factory() {
-
-    var
-      SETTINGS_SAVE_SPEC = {
-        includes: ['locale', 'showUDHistory', 'useRelative', 'useLocalStorage', 'expertMode'],
-        excludes: ['time'],
-        plugins: {
-          es: {
-            excludes: ['enable', 'host', 'port', 'wsPort']
-          }
-        },
-        helptip: {
-          excludes: ['installDocUrl']
+  var
+    SETTINGS_SAVE_SPEC = {
+      includes: ['locale', 'showUDHistory', 'useRelative', 'useLocalStorage', 'expertMode'],
+      excludes: ['time'],
+      plugins: {
+        es: {
+          excludes: ['enable', 'host', 'port', 'wsPort']
         }
       },
-      defaultSettings = angular.merge({
-          plugins: {
-            es: {
-              askEnable: false,
-              notifications: {
-                readTime: true,
-                txSent: true,
-                txReceived: true,
-                certSent: true,
-                certReceived: true
-              },
-              invitations: {
-                readTime: true
-              }
+      helptip: {
+        excludes: ['installDocUrl']
+      }
+    },
+    defaultSettings = angular.merge({
+        plugins: {
+          es: {
+            askEnable: false,
+            notifications: {
+              readTime: true,
+              txSent: true,
+              txReceived: true,
+              certSent: true,
+              certReceived: true
+            },
+            invitations: {
+              readTime: true
             }
           }
-      }, {plugins: {es: csConfig.plugins && csConfig.plugins.es || {}}}),
-      that = this,
-      previousRemoteData,
-      listeners,
-      ignoreSettingsChanged = false
-    ;
+        }
+    }, {plugins: {es: csConfig.plugins && csConfig.plugins.es || {}}}),
+    that = this,
+    previousRemoteData,
+    listeners,
+    ignoreSettingsChanged = false
+  ;
+
+  that.get = esHttp.get('/user/settings/:id');
+  that.add = esHttp.record.post('/user/settings');
+  that.update = esHttp.record.post('/user/settings/:id/_update');
+
+  that.isEnable = function() {
+    return csSettings.data.plugins &&
+      csSettings.data.plugins.es &&
+      csSettings.data.plugins.es.enable &&
+      !!csSettings.data.plugins.es.host;
+  };
+
+  function copyUsingSpec(data, copySpec) {
+    var result = {};
+
+    // Add implicit includes
+    if (copySpec.includes) {
+      _.forEach(_.keys(copySpec), function(key) {
+        if (key != "includes" && key != "excludes") {
+          copySpec.includes.push(key);
+        }
+      });
+    }
 
-    that.get = esHttp.get('/user/settings/:id');
-    that.add = esHttp.record.post('/user/settings');
-    that.update = esHttp.record.post('/user/settings/:id/_update');
-
-    that.isEnable = function() {
-      return csSettings.data.plugins &&
-        csSettings.data.plugins.es &&
-        csSettings.data.plugins.es.enable &&
-        !!csSettings.data.plugins.es.host;
-    };
-
-    function copyUsingSpec(data, copySpec) {
-      var result = {};
-
-      // Add implicit includes
-      if (copySpec.includes) {
-        _.forEach(_.keys(copySpec), function(key) {
-          if (key != "includes" && key != "excludes") {
-            copySpec.includes.push(key);
-          }
-        });
+    _.forEach(_.keys(data), function(key) {
+      if ((!copySpec.includes || _.contains(copySpec.includes, key)) &&
+        (!copySpec.excludes || !_.contains(copySpec.excludes, key))) {
+        if (data[key] && (typeof data[key] == 'object') &&
+          copySpec[key] && (typeof copySpec[key] == 'object')) {
+          result[key] = copyUsingSpec(data[key], copySpec[key]);
+        }
+        else {
+          result[key] = data[key];
+        }
       }
+    });
+    return result;
+  }
 
-      _.forEach(_.keys(data), function(key) {
-        if ((!copySpec.includes || _.contains(copySpec.includes, key)) &&
-          (!copySpec.excludes || !_.contains(copySpec.excludes, key))) {
-          if (data[key] && (typeof data[key] == 'object') &&
-            copySpec[key] && (typeof copySpec[key] == 'object')) {
-            result[key] = copyUsingSpec(data[key], copySpec[key]);
-          }
-          else {
-            result[key] = data[key];
-          }
+  // Load settings
+  function loadSettings(pubkey, keypair) {
+    var now = new Date().getTime();
+    return $q.all([
+        CryptoUtils.box.keypair.fromSignKeypair(keypair),
+        that.get({id: pubkey})
+          .catch(function(err){
+            if (err && err.ucode && err.ucode == 404) {
+              return null; // not found
+            }
+            else {
+              throw err;
+            }
+          })])
+      .then(function(res) {
+        var boxKeypair = res[0];
+        res = res[1];
+        if (!res || !res._source) {
+          return;
+        }
+        var record = res._source;
+        // Do not apply if same version
+        if (record.time === csSettings.data.time) {
+          console.debug('[ES] [settings] Loaded user settings in '+ (new Date().getTime()-now) +'ms (no update need)');
+          return;
         }
+        var nonce = CryptoUtils.util.decode_base58(record.nonce);
+        // Decrypt settings content
+        return CryptoUtils.box.open(record.content, nonce, boxKeypair.boxPk, boxKeypair.boxSk)
+          .then(function(json) {
+            var settings = JSON.parse(json || '{}');
+            settings.time = record.time;
+            console.debug('[ES] [settings] Loaded user settings in '+ (new Date().getTime()-now) +'ms');
+            return settings;
+          })
+          // if error: skip stored content
+          .catch(function(err){
+            console.error('[ES] [settings] Could not read stored settings: ' + (err && err.message || 'decryption error'));
+            // make sure to remove time, to be able to save it again
+            delete csSettings.data.time;
+            return null;
+          });
       });
-      return result;
-    }
+  }
 
-    // Load settings
-    function loadSettings(pubkey, keypair) {
-      var now = new Date().getTime();
-      return $q.all([
-          CryptoUtils.box.keypair.fromSignKeypair(keypair),
-          that.get({id: pubkey})
-            .catch(function(err){
-              if (err && err.ucode && err.ucode == 404) {
-                return null; // not found
-              }
-              else {
-                throw err;
-              }
-            })])
-        .then(function(res) {
-          var boxKeypair = res[0];
-          res = res[1];
-          if (!res || !res._source) {
-            return;
-          }
-          var record = res._source;
-          // Do not apply if same version
-          if (record.time === csSettings.data.time) {
-            console.debug('[ES] [settings] Loaded user settings in '+ (new Date().getTime()-now) +'ms (no update need)');
-            return;
-          }
-          var nonce = CryptoUtils.util.decode_base58(record.nonce);
-          // Decrypt settings content
-          return CryptoUtils.box.open(record.content, nonce, boxKeypair.boxPk, boxKeypair.boxSk)
-            .then(function(json) {
-              var settings = JSON.parse(json || '{}');
-              settings.time = record.time;
-              console.debug('[ES] [settings] Loaded user settings in '+ (new Date().getTime()-now) +'ms');
-              return settings;
-            })
-            // if error: skip stored content
-            .catch(function(err){
-              console.error('[ES] [settings] Could not read stored settings: ' + (err && err.message || 'decryption error'));
-              // make sure to remove time, to be able to save it again
-              delete csSettings.data.time;
-              return null;
-            });
-        });
-    }
+  function onSettingsReset(data, deferred) {
+    deferred = deferred || $q.defer();
+    angular.merge(data, defaultSettings);
+    deferred.resolve(data);
+    return deferred.promise;
+  }
 
-    function onSettingsReset(data, deferred) {
-      deferred = deferred || $q.defer();
-      angular.merge(data, defaultSettings);
-      deferred.resolve(data);
+  function onWalletLogin(data, deferred) {
+    deferred = deferred || $q.defer();
+    if (!data || !data.pubkey || !data.keypair) {
+      deferred.resolve();
       return deferred.promise;
     }
 
-    function onWalletLogin(data, deferred) {
-      deferred = deferred || $q.defer();
-      if (!data || !data.pubkey || !data.keypair) {
-        deferred.resolve();
-        return deferred.promise;
-      }
-
-      // Waiting to load crypto libs
-      if (!CryptoUtils.isLoaded()) {
-        console.debug('[ES] [settings] Waiting crypto lib loading...');
-        return $timeout(function() {
-          return onWalletLogin(data, deferred);
-        }, 50);
-      }
+    // Waiting to load crypto libs
+    if (!CryptoUtils.isLoaded()) {
+      console.debug('[ES] [settings] Waiting crypto lib loading...');
+      return $timeout(function() {
+        return onWalletLogin(data, deferred);
+      }, 50);
+    }
 
-      console.debug('[ES] [settings] Loading user settings...');
+    console.debug('[ES] [settings] Loading user settings...');
 
-      // Load settings
-      loadSettings(data.pubkey, data.keypair)
-        .then(function(settings) {
-          if (!settings) return; // not found or up to date
-          angular.merge(csSettings.data, settings);
+    // Load settings
+    loadSettings(data.pubkey, data.keypair)
+      .then(function(settings) {
+        if (!settings) return; // not found or up to date
+        angular.merge(csSettings.data, settings);
 
-          // Remember for comparison
-          previousRemoteData = settings;
+        // Remember for comparison
+        previousRemoteData = settings;
 
-          console.debug('[ES] [settings] Successfully load settings from ES');
-          return storeSettingsLocally();
-        })
-      .then(function() {
-        deferred.resolve(data);
+        console.debug('[ES] [settings] Successfully load settings from ES');
+        return storeSettingsLocally();
       })
-      .catch(function(err){
-        deferred.reject(err);
-      });
+    .then(function() {
+      deferred.resolve(data);
+    })
+    .catch(function(err){
+      deferred.reject(err);
+    });
 
-      return deferred.promise;
-    }
+    return deferred.promise;
+  }
 
-    // Listen for settings changed
-    function onSettingsChanged(data) {
-      // avoid recursive call, because storeSettingsLocally() could emit event again
-      if (ignoreSettingsChanged) return;
+  // Listen for settings changed
+  function onSettingsChanged(data) {
+    // avoid recursive call, because storeSettingsLocally() could emit event again
+    if (ignoreSettingsChanged) return;
 
-      var wasEnable = listeners && listeners.length > 0;
+    var wasEnable = listeners && listeners.length > 0;
 
-      refreshState();
+    refreshState();
 
-      var isEnable = that.isEnable();
-      if (csWallet.isLogin()) {
-        if (!wasEnable && isEnable) {
+    var isEnable = that.isEnable();
+    if (csWallet.isLogin()) {
+      if (!wasEnable && isEnable) {
 
-          onWalletLogin(csWallet.data);
-        }
-        else {
-          storeSettingsRemotely(data);
-        }
+        onWalletLogin(csWallet.data);
+      }
+      else {
+        storeSettingsRemotely(data);
       }
     }
+  }
 
-    function storeSettingsLocally() {
-      if (ignoreSettingsChanged) return $q.when();
-      ignoreSettingsChanged = true;
-      return csSettings.store()
-        .then(function(){
-          ignoreSettingsChanged = false;
-        })
-        .catch(function(err) {
-          ignoreSettingsChanged = false;
-          throw err;
-        });
-    }
-
-    function storeSettingsRemotely(data) {
-      if (!csWallet.isLogin()) return $q.when();
-
-      var filteredData = copyUsingSpec(data, SETTINGS_SAVE_SPEC);
-      if (previousRemoteData && angular.equals(filteredData, previousRemoteData)) {
-        return $q.when();
-      }
+  function storeSettingsLocally() {
+    if (ignoreSettingsChanged) return $q.when();
+    ignoreSettingsChanged = true;
+    return csSettings.store()
+      .then(function(){
+        ignoreSettingsChanged = false;
+      })
+      .catch(function(err) {
+        ignoreSettingsChanged = false;
+        throw err;
+      });
+  }
 
-      // Waiting to load crypto libs
-      if (!CryptoUtils.isLoaded()) {
-        console.debug('[ES] [settings] Waiting crypto lib loading...');
-        return $timeout(function() {
-          return storeSettingsRemotely();
-        }, 50);
-      }
+  function storeSettingsRemotely(data) {
+    if (!csWallet.isLogin()) return $q.when();
 
-      var time = esHttp.date.now();
-      console.debug('[ES] [settings] Saving user settings... at time ' + time);
-
-      return $q.all([
-          CryptoUtils.box.keypair.fromSignKeypair(csWallet.data.keypair),
-          CryptoUtils.util.random_nonce()
-        ])
-        .then(function(res) {
-          var boxKeypair = res[0];
-          var nonce = res[1];
-
-          var record = {
-            issuer: csWallet.data.pubkey,
-            nonce: CryptoUtils.util.encode_base58(nonce),
-            time: time
-          };
-
-          var json = JSON.stringify(filteredData);
-
-          return CryptoUtils.box.pack(json, nonce, boxKeypair.boxPk, boxKeypair.boxSk)
-            .then(function(cypherText) {
-              record.content = cypherText;
-              // create or update
-              return !data.time ?
-                that.add(record) :
-                that.update(record, {id: record.issuer});
-            });
-        })
-        .then(function() {
-          // Update settings version, then store (on local store only)
-          csSettings.data.time = time;
-          previousRemoteData = filteredData;
-          console.debug('[ES] [settings] Saved user settings in ' + (esHttp.date.now() - time) + 'ms');
-          return storeSettingsLocally();
-        })
-        .catch(function(err) {
-          console.error(err);
-          throw err;
-        })
-      ;
+    var filteredData = copyUsingSpec(data, SETTINGS_SAVE_SPEC);
+    if (previousRemoteData && angular.equals(filteredData, previousRemoteData)) {
+      return $q.when();
     }
 
-    function removeListeners() {
-      _.forEach(listeners, function(remove){
-        remove();
-      });
-      listeners = [];
+    // Waiting to load crypto libs
+    if (!CryptoUtils.isLoaded()) {
+      console.debug('[ES] [settings] Waiting crypto lib loading...');
+      return $timeout(function() {
+        return storeSettingsRemotely();
+      }, 50);
     }
 
-    function addListeners() {
-      // Extend csWallet.login()
-      listeners = [
-        csSettings.api.data.on.reset($rootScope, onSettingsReset, this),
-        csWallet.api.data.on.login($rootScope, onWalletLogin, this)
-      ];
-    }
+    var time = esHttp.date.now();
+    console.debug('[ES] [settings] Saving user settings... at time ' + time);
+
+    return $q.all([
+        CryptoUtils.box.keypair.fromSignKeypair(csWallet.data.keypair),
+        CryptoUtils.util.random_nonce()
+      ])
+      .then(function(res) {
+        var boxKeypair = res[0];
+        var nonce = res[1];
+
+        var record = {
+          issuer: csWallet.data.pubkey,
+          nonce: CryptoUtils.util.encode_base58(nonce),
+          time: time
+        };
+
+        var json = JSON.stringify(filteredData);
+
+        return CryptoUtils.box.pack(json, nonce, boxKeypair.boxPk, boxKeypair.boxSk)
+          .then(function(cypherText) {
+            record.content = cypherText;
+            // create or update
+            return !data.time ?
+              that.add(record) :
+              that.update(record, {id: record.issuer});
+          });
+      })
+      .then(function() {
+        // Update settings version, then store (on local store only)
+        csSettings.data.time = time;
+        previousRemoteData = filteredData;
+        console.debug('[ES] [settings] Saved user settings in ' + (esHttp.date.now() - time) + 'ms');
+        return storeSettingsLocally();
+      })
+      .catch(function(err) {
+        console.error(err);
+        throw err;
+      })
+    ;
+  }
+
+  function removeListeners() {
+    _.forEach(listeners, function(remove){
+      remove();
+    });
+    listeners = [];
+  }
 
-    function refreshState() {
-      var enable = that.isEnable();
+  function addListeners() {
+    // Extend csWallet.login()
+    listeners = [
+      csSettings.api.data.on.reset($rootScope, onSettingsReset, this),
+      csWallet.api.data.on.login($rootScope, onWalletLogin, this)
+    ];
+  }
 
-      // Disable
-      if (!enable && listeners && listeners.length > 0) {
-        console.debug("[ES] [settings] Disable");
-        removeListeners();
-        return esHttp.stop();
-      }
+  function refreshState() {
+    var enable = that.isEnable();
 
-      // Enable
-      else if (enable && (!listeners || listeners.length === 0)) {
-        return esHttp.start()
-          .then(function(started) {
-            if (!started) {
-              // TODO : alert user ?
-              console.error('[ES] node could not be started !!');
-            }
-            else {
-              console.debug("[ES] [settings] Enable");
-              addListeners();
-              if (csWallet.isLogin()) {
-                return onWalletLogin(csWallet.data);
-              }
+    // Disable
+    if (!enable && listeners && listeners.length > 0) {
+      console.debug("[ES] [settings] Disable");
+      removeListeners();
+      return esHttp.stop();
+    }
+
+    // Enable
+    else if (enable && (!listeners || listeners.length === 0)) {
+      return esHttp.start()
+        .then(function(started) {
+          if (!started) {
+            // TODO : alert user ?
+            console.error('[ES] node could not be started !!');
+          }
+          else {
+            console.debug("[ES] [settings] Enable");
+            addListeners();
+            if (csWallet.isLogin()) {
+              return onWalletLogin(csWallet.data);
             }
-          });
-      }
+          }
+        });
     }
+  }
 
-    Device.ready().then(function() {
+  csSettings.ready().then(function() {
 
-      csSettings.api.data.on.changed($rootScope, onSettingsChanged, this);
-      esHttp.api.node.on.stop($rootScope, function() {
-        previousRemoteData = null;
-      }, this);
-      return refreshState();
-    })
+    csSettings.api.data.on.changed($rootScope, onSettingsChanged, this);
+    esHttp.api.node.on.stop($rootScope, function() {
+      previousRemoteData = null;
+    }, this);
+    return refreshState();
+  })
 
-    .then(function() {
-      // Ask (once) user to enable ES plugin
-      if (csConfig.plugins && csConfig.plugins.es && csConfig.plugins.es.askEnable && // if config ask enable
-        csSettings.data.plugins.es && !csSettings.data.plugins.es.enable && // AND user settings has disable plugin
-        csSettings.data.plugins.es.askEnable // AND user has not yet answer 'NO'
-      ) {
-        return UIUtils.alert.confirm('ES_SETTINGS.CONFIRM.ASK_ENABLE', 'ES_SETTINGS.CONFIRM.ASK_ENABLE_TITLE',
-          {
-            cancelText: 'COMMON.BTN_NO',
-            okText: 'COMMON.BTN_YES'
-          })
-          .then(function (confirm) {
-            if (confirm) {
-              csSettings.data.plugins.es.enable = true;
-            }
-            csSettings.data.plugins.es.askEnable = false;
-            return csSettings.store();
-          });
-      }
-    });
-  }
+  .then(function() {
+    // Ask (once) user to enable ES plugin
+    if (csConfig.plugins && csConfig.plugins.es && csConfig.plugins.es.askEnable && // if config ask enable
+      csSettings.data.plugins.es && !csSettings.data.plugins.es.enable && // AND user settings has disable plugin
+      csSettings.data.plugins.es.askEnable // AND user has not yet answer 'NO'
+    ) {
+      return UIUtils.alert.confirm('ES_SETTINGS.CONFIRM.ASK_ENABLE', 'ES_SETTINGS.CONFIRM.ASK_ENABLE_TITLE',
+        {
+          cancelText: 'COMMON.BTN_NO',
+          okText: 'COMMON.BTN_YES'
+        })
+        .then(function (confirm) {
+          if (confirm) {
+            csSettings.data.plugins.es.enable = true;
+          }
+          csSettings.data.plugins.es.askEnable = false;
+          return csSettings.store();
+        });
+    }
+  });
 
-  return new Factory();
-})
-;
+  return that;
+});
diff --git a/www/sync-storage.html b/www/sync-storage.html
deleted file mode 100644
index a1b1a840..00000000
--- a/www/sync-storage.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <script src="lib/ionic/js/angular/angular-xdLocalStoragePostMessageApi.min.js"></script>
-</head>
-<body>
-  This is the HTTPS Frame content
-</body>
-</html>
diff --git a/www/templates/settings/settings.html b/www/templates/settings/settings.html
index a07236ed..4d8208cd 100644
--- a/www/templates/settings/settings.html
+++ b/www/templates/settings/settings.html
@@ -125,7 +125,7 @@
         <div class="input-label">
         {{'SETTINGS.PEER' | translate}}
         </div>
-        <span class="item-note dark">{{getServer()}}</ng-if></span>
+        <span class="item-note dark">{{bma.server}}</ng-if></span>
       </div>
       <div class="item item-text-wrap item-toggle dark hidden-xs hidden-sm">
         <div class="input-label" ng-bind-html="'SETTINGS.EXPERT_MODE' | translate"></div>
-- 
GitLab