diff --git a/www/js/app.js b/www/js/app.js index f84094f92ba81e926ef10eff6f384d3714c3bae9..bbffa2b347dff4a32b72d035674f013e7bc2981e 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -130,6 +130,7 @@ angular.module('cesium', ['ionic', 'ionic-material', 'ngMessages', 'pascalprecht if (sameUrl) event.preventDefault(); } }); + // Configures $urlRouter's listener *after* the previous listener $urlRouter.listen(); diff --git a/www/js/controllers/join-controllers.js b/www/js/controllers/join-controllers.js index 0c9d21d7aac77ab2b94c40b5b9e34824f4e3b6bc..318fe49c2c0a5a096f166a08b13b7991dee3efee 100644 --- a/www/js/controllers/join-controllers.js +++ b/www/js/controllers/join-controllers.js @@ -135,7 +135,7 @@ function JoinModalController($scope, $state, $interval, $timeout, Device, UIUtil $scope.showPassword = false; $scope.formData.computing=false; $scope.smallscreen = UIUtils.screen.isSmall(); - $scope.userIdPattern = BMA.constants.regex.USER_ID; + $scope.userIdPattern = BMA.constants.regexp.USER_ID; // Read input parameters $scope.currency = parameters.currency; diff --git a/www/js/controllers/network-controllers.js b/www/js/controllers/network-controllers.js index e3dbf98e011a3afd5f1fb108e5adcc4fde252019..77b9d80a73ab8c83397a968104667f92f2e38857 100644 --- a/www/js/controllers/network-controllers.js +++ b/www/js/controllers/network-controllers.js @@ -210,7 +210,7 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win $scope.load(); // Update location href - if ($scope.eanbleLocationHref) { + if ($scope.enableLocationHref) { $location.search({type: $scope.search.type}).replace(); } }; @@ -377,7 +377,7 @@ function NetworkLookupModalController($scope, $controller, parameters) { $scope.search.endpointFilter = angular.isDefined(parameters.endpointFilter) ? parameters.endpointFilter : $scope.search.endpointFilter; $scope.expertMode = angular.isDefined(parameters.expertMode) ? parameters.expertMode : $scope.expertMode; $scope.ionItemClass = parameters.ionItemClass || 'item-border-large'; - $scope.eanbleLocationHref = false; + $scope.enableLocationHref = false; $scope.helptipPrefix = ''; $scope.selectPeer = function(peer) { @@ -535,6 +535,9 @@ function PeerViewController($scope, $q, $window, $state, UIUtils, csWot, BMA) { }) .then(function(){ $scope.loading = false; + }) + .catch(function() { + $scope.loading = false; }); }); @@ -598,7 +601,11 @@ function PeerViewController($scope, $q, $window, $state, UIUtils, csWot, BMA) { .then(function(json) { $scope.node.pubkey = json.pubkey; $scope.node.currency = json.currency; - }), + }) + .catch(function(err){ + console.error(err && err.message || err); + }) + , // Get known peers $scope.node.network.peers() @@ -634,7 +641,11 @@ function PeerViewController($scope, $q, $window, $state, UIUtils, csWot, BMA) { $scope.current = json; }) ]) - .catch(UIUtils.onError(useTor ? "PEER.VIEW.ERROR.LOADING_TOR_NODE_ERROR" : "PEER.VIEW.ERROR.LOADING_NODE_ERROR")); + .catch(function(err) { + console.error(err && err.message || err); + UIUtils.onError(useTor ? "PEER.VIEW.ERROR.LOADING_TOR_NODE_ERROR" : "PEER.VIEW.ERROR.LOADING_NODE_ERROR")(err); + throw err; + }); }; $scope.selectPeer = function(peer) { diff --git a/www/js/controllers/transfer-controllers.js b/www/js/controllers/transfer-controllers.js index 027a3d643285b30480769206d166a27fe9ecb7b8..cdeb870030d7b3541ff5a1f7c5595d863a81bfd9 100644 --- a/www/js/controllers/transfer-controllers.js +++ b/www/js/controllers/transfer-controllers.js @@ -238,7 +238,7 @@ function TransferModalController($scope, $q, $translate, $timeout, $filter, $foc $scope.form.amount.$error = $scope.form.amount.$error || {}; $scope.form.amount.$error.min = true; } - else if ($scope.form.amount.$error && $scope.form.amount.$error.min){ + else if ($scope.form.amount && $scope.form.amount.$error && $scope.form.amount.$error.min){ delete $scope.form.amount.$error.min; } @@ -249,7 +249,7 @@ function TransferModalController($scope, $q, $translate, $timeout, $filter, $foc $scope.form.amount.$error = $scope.form.amount.$error || {}; $scope.form.amount.$error = {max: true}; } - else if ($scope.form.amount.$error && $scope.form.amount.$error.max){ + else if ($scope.form.amount && $scope.form.amount.$error && $scope.form.amount.$error.max){ delete $scope.form.amount.$error.max; } diff --git a/www/js/controllers/wot-controllers.js b/www/js/controllers/wot-controllers.js index e9248ac1b393e6455582f1c48d621ba43d71032c..c3c245f045070428b747ebe53192fc1d39268ec7 100644 --- a/www/js/controllers/wot-controllers.js +++ b/www/js/controllers/wot-controllers.js @@ -653,7 +653,8 @@ function WotLookupModalController($scope, $controller, $focus, csWallet, paramet $scope.select = function(identity){ $scope.closeModal({ pubkey: identity.pubkey, - uid: identity.uid + uid: identity.uid, + name: identity.name && identity.name.replace(/<\/?em>/ig, '') }); }; diff --git a/www/js/entities/peer.js b/www/js/entities/peer.js index a05550948c43f982a6718011b5ec15754ff76ab3..cd9649e3caab64f1112122bd1e7834b83c6c3110 100644 --- a/www/js/entities/peer.js +++ b/www/js/entities/peer.js @@ -59,7 +59,8 @@ Peer.prototype.json = function() { Peer.prototype.getBMA = function() { if (this.bma) return this.bma; var bma = null; - var bmaRegex = this.regex.BMA_REGEXP; + var bmaRegex = this.regexp.BMA_REGEXP; + var bmasRegex = this.regexp.BMAS_REGEXP; this.endpoints.forEach(function(ep){ var matches = !bma && bmaRegex.exec(ep); if (matches) { @@ -67,7 +68,20 @@ Peer.prototype.getBMA = function() { "dns": matches[2] || '', "ipv4": matches[4] || '', "ipv6": matches[6] || '', - "port": matches[8] || 80 + "port": matches[8] || 80, + "useSsl": matches[8] == 443, + "useBma": true + }; + } + matches = !bma && bmasRegex.exec(ep); + if (matches) { + bma = { + "dns": matches[2] || '', + "ipv4": matches[4] || '', + "ipv6": matches[6] || '', + "port": matches[8] || 80, + "useSsl": true, + "useBma": true }; } }); diff --git a/www/js/platform.js b/www/js/platform.js index 75af3383367fb9a5f95196a8f1d5a34d33a473c9..cfda3b040f421a536f03fa825d3cf151b8e8fdc3 100644 --- a/www/js/platform.js +++ b/www/js/platform.js @@ -382,8 +382,8 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] // Workaround to add "".startsWith() if not present if (typeof String.prototype.startsWith !== 'function') { console.debug("Adding String.prototype.startsWith() -> was missing on this platform"); - String.prototype.startsWith = function(prefix) { - return this.indexOf(prefix) === 0; + String.prototype.startsWith = function(prefix, position) { + return this.indexOf(prefix, position) === 0; }; } diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js index 83857770147602cec64f57b7962118a3cc41e966..3a8f2aa6cf363b6801e4cfa753b62a9ee21f491c 100644 --- a/www/js/services/bma-services.js +++ b/www/js/services/bma-services.js @@ -230,10 +230,19 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. that.isAlive = function() { return csHttp.get(that.host, that.port, '/node/summary', that.useSsl)() .then(function(json) { - var isDuniter = json && json.duniter && json.duniter.software && json.duniter.version && true; - var isCompatible = isDuniter && csHttp.version.isCompatible(csSettings.data.minVersion, json.duniter.version); - if (isDuniter && !isCompatible) { - console.error('[BMA] Uncompatible version [{0}] - expected at least [{1}]'.format(json.duniter.version, csSettings.data.minVersion)); + var software = json && json.duniter && json.duniter.software; + var isCompatible = true; + + // Check duniter min version + if (software === 'duniter' && json.duniter.version && true) { + isCompatible = csHttp.version.isCompatible(csSettings.data.minVersion, json.duniter.version); + } + // TODO: check other software (DURS, Juniter, etc.) + else { + console.debug('[BMA] Unknown node software [{0} v{1}]: could not check compatibility.'.format(software || '?', json.duniter.version || '?')); + } + if (!isCompatible) { + console.error('[BMA] Incompatible node [{0} v{1}]: expected at least v{2}'.format(software, json.duniter.version, csSettings.data.minVersion)); } return isCompatible; }) diff --git a/www/js/services/network-services.js b/www/js/services/network-services.js index 9a49bf4cfd1e36a6bb31ba073d0179a0264ec2f7..1484840cdbc45ef36f6e13ca2839a66943571b7e 100644 --- a/www/js/services/network-services.js +++ b/www/js/services/network-services.js @@ -527,9 +527,11 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi // Get Version jobs.push(peer.api.node.summary() .then(function(res){ - peer.version = res && res.duniter && res.duniter.version; + peer.software = res && res.duniter && res.duniter.software || undefined; + peer.version = res && res.duniter && res.duniter.version || '?'; }) .catch(function() { + peer.software = undefined; peer.version = '?'; // continue })); diff --git a/www/js/services/settings-services.js b/www/js/services/settings-services.js index ae153061d2a8465a7319d181dc746e5258a1912d..d2dd574d94391c9a1833d1e1bf3f31ee9bbda3f7 100644 --- a/www/js/services/settings-services.js +++ b/www/js/services/settings-services.js @@ -52,12 +52,21 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) STORAGE_KEY: 'settings', // for version >= v1.1.0 KEEP_AUTH_IDLE_SESSION: 9999 }, - defaultSettings = angular.merge({ + // Settings that user cannot change himself (only config can override this values) + fixedSettings = { timeout : 4000, cacheTimeMs: 60000, /*1 min*/ useRelative: false, timeWarningExpireMembership: 2592000 * 2 /*=2 mois*/, timeWarningExpire: 2592000 * 3 /*=3 mois*/, + minVersion: '1.1.0', + newIssueUrl: "https://git.duniter.org/clients/cesium-grp/cesium/issues/new", + userForumUrl: "https://forum.monnaie-libre.fr", + latestReleaseUrl: "https://api.github.com/repos/duniter/cesium/releases/latest", + duniterLatestReleaseUrl: "https://api.github.com/repos/duniter/duniter/releases/latest", + httpsMode: false + }, + defaultSettings = angular.merge({ useLocalStorage: true, // override to false if no device useLocalStorageEncryption: true, walletHistoryTimeSecond: 30 * 24 * 60 * 60 /*30 days*/, @@ -66,15 +75,9 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) rememberMe: true, keepAuthIdle: 10 * 60, showUDHistory: true, - httpsMode: false, expertMode: false, decimalCount: 4, uiEffects: true, - minVersion: '1.1.0', - newIssueUrl: "https://git.duniter.org/clients/cesium-grp/cesium/issues/new", - userForumUrl: "https://forum.monnaie-libre.fr", - latestReleaseUrl: "https://api.github.com/repos/duniter/cesium/releases/latest", - duniterLatestReleaseUrl: "https://api.github.com/repos/duniter/duniter/releases/latest", blockValidityWindow: 6, helptip: { enable: true, @@ -101,7 +104,9 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) locale: { id: fixLocaleWithLog(csConfig.defaultLanguage || $translate.use()) // use config locale if set, or browser default } - }, csConfig), + }, + fixedSettings, + csConfig), data = {}, previousData, @@ -201,17 +206,10 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) // Delete temporary properties, if false if (!newData.node.temporary || !data.node.temporary) delete data.node.temporary; - // Always force the usage of default settings - // This is a workaround for DEV (TODO: implement edition in settings ?) - data.timeWarningExpire = defaultSettings.timeWarningExpire; - data.timeWarningExpireMembership = defaultSettings.timeWarningExpireMembership; - data.cacheTimeMs = defaultSettings.cacheTimeMs; - data.timeout = defaultSettings.timeout; - data.minVersion = defaultSettings.minVersion; - data.latestReleaseUrl = defaultSettings.latestReleaseUrl; - data.duniterLatestReleaseUrl = defaultSettings.duniterLatestReleaseUrl; - data.newIssueUrl = defaultSettings.newIssueUrl; - data.userForumUrl = defaultSettings.userForumUrl; + // Force some fixed settings + _.keys(fixedSettings).forEach(function(key) { + data[key] = defaultSettings[key]; // This will apply fixed value (override by config.js file) + }); // Apply the new locale (only if need) // will produce an event cached by onLocaleChange(); diff --git a/www/js/services/wot-services.js b/www/js/services/wot-services.js index bfd0f88476cc58acf25771d763a31c5c7a865c0e..50224409a2cf21a063c8557675496da804a4b73d 100644 --- a/www/js/services/wot-services.js +++ b/www/js/services/wot-services.js @@ -684,20 +684,19 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c return $q.all([ // Get parameters - BMA.blockchain.parameters() + csCurrency.parameters() .then(function(res) { parameters = res; - }), // Get current time - BMA.blockchain.current() + csCurrency.blockchain.current() .then(function(current) { medianTime = current.medianTime; }) .catch(function(err){ // Special case for currency init (root block not exists): use now if (err && err.ucode == BMA.errorCodes.NO_CURRENT_BLOCK) { - medianTime = Math.trunc(Date.now()/1000); + medianTime = moment.utc().unix(); } else { throw err; diff --git a/www/plugins/es/js/services/blockchain-services.js b/www/plugins/es/js/services/blockchain-services.js index dd768ba36d1d8c1c2bf2f8c769222bf40d109047..824aa3a437d2f83d8edc706d1412d6bd1b3cb705 100644 --- a/www/plugins/es/js/services/blockchain-services.js +++ b/www/plugins/es/js/services/blockchain-services.js @@ -36,17 +36,18 @@ angular.module('cesium.es.blockchain.services', ['cesium.services', 'cesium.es.h get: esHttp.get('/:currency/block/:number/_source') } }, - regex: { + regexp: { ES_CORE_API_ENDPOINT: exact(CONSTANTS.ES_CORE_API_ENDPOINT) } }; + exports.regex = exports.regexp; // deprecated function exact(regexpContent) { return new RegExp('^' + regexpContent + '$'); } exports.node.parseEndPoint = function(endpoint) { - var matches = REGEX.ES_CORE_API_ENDPOINT.exec(endpoint); + var matches = exports.regexp.ES_CORE_API_ENDPOINT.exec(endpoint); if (!matches) return; return { dns: matches[2] || '', diff --git a/www/plugins/es/js/services/http-services.js b/www/plugins/es/js/services/http-services.js index e4c8d4490c1a34878b4290c3c87a34da5b805e76..371c129e60c6a1d4e3f229e81c04c8ddadeb883d 100644 --- a/www/plugins/es/js/services/http-services.js +++ b/www/plugins/es/js/services/http-services.js @@ -14,12 +14,13 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic console.debug('[ES] [https] Enable SSL (forced by config or detected in URL)'); } - function Factory(host, port, wsPort, useSsl) { + function EsHttp(host, port, wsPort, useSsl) { var that = this, constants = { - ES_USER_API_ENDPOINT: 'ES_USER_API( ([a-z_][a-z0-9-_.]*))?( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))' + ES_USER_API_ENDPOINT: 'ES_USER_API( ([a-z_][a-z0-9-_.]*))?( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))', + MAX_UPLOAD_BODY_SIZE: csConfig.plugins && csConfig.plugins.es && csConfig.plugins.es.maxUploadBodySize || 2097152 /*=2M*/ }, regexp = { IMAGE_SRC: exact('data:([A-Za-z//]+);base64,(.+)'), @@ -138,6 +139,11 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic return that.start(true /*skipInit*/); }; + that.byteCount = function (s) { + s = (typeof s == 'string') ? s : JSON.stringify(s); + return encodeURI(s).split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./).length - 1; + }; + that.getUrl = function(path) { return csHttp.getUrl(that.host, that.port, path, that.useSsl); }; @@ -204,7 +210,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic .then(function(json) { var software = json && json.duniter && json.duniter.software || 'unknown'; if (software === "cesium-plus-pod" || software === "duniter4j-elasticsearch") return true; - console.error("[ES] [http] Not a Duniter4j ES node, but a {0} node".format(software)); + console.error("[ES] [http] Not a Cesium+ Pod, but a {0} node. Please check '/node/summary'".format(software)); return false; }) .catch(function() { @@ -383,6 +389,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic // Replace URL in description var urls = parseUrlsFromText(content); _.forEach(urls, function(url){ + // Make sure protocol is defined var href = (url.startsWith('http://') || url.startsWith('https://')) ? url : ('http://' + url); // Redirect URL to the function 'openLink', to open a new window if need (e.g. desktop app) var link = '<a on-tap=\"openLink($event, \'{0}\')\" href=\"{1}\" target="_blank">{2}</a>'.format(href, href, truncUrlFilter(url)); @@ -398,9 +405,9 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic // Replace user tags var userTags = parseTagsFromText(content, '@'); - _.forEach(userTags, function(uid){ - var link = '<a ui-sref=\"{0}({uid: \'{1}\'})\">@{2}</a>'.format(options.uidState, uid, uid); - content = content.replace('@'+uid, link); + _.forEach(userTags, function(tag){ + var link = '<a ui-sref=\"{0}({uid: \'{1}\'})\">@{2}</a>'.format(options.uidState, tag, tag); + content = content.replace('@'+tag, link); }); } return content; @@ -468,23 +475,29 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic fillRecordTags(obj, options.tagFields); } - //console.debug("Will send obj: ", obj); - var str = JSON.stringify(obj); - - return CryptoUtils.util.hash(str) - .then(function(hash) { - return CryptoUtils.sign(hash, keypair) - .then(function(signature) { - // Prepend hash+signature - str = '{"hash":"{0}","signature":"{1}",'.format(hash, signature) + str.substring(1); - // Send data - return postRequest(str, params) - .then(function (id){ - return id; - }); - }); - }); - }); + var str = JSON.stringify(obj); + + return CryptoUtils.util.hash(str) + .then(function(hash) { + return CryptoUtils.sign(hash, keypair) + .then(function(signature) { + // Prepend hash+signature + str = '{"hash":"{0}","signature":"{1}",'.format(hash, signature) + str.substring(1); + // Send data + return postRequest(str, params) + .then(function (id){ + return id; + }) + .catch(function(err) { + var bodyLength = that.byteCount(obj); + if (bodyLength > constants.MAX_UPLOAD_BODY_SIZE) { + throw {message: 'ERROR.ES_MAX_UPLOAD_BODY_SIZE', length: bodyLength}; + } + throw err; + }); + }); + }); + }); }; } @@ -638,6 +651,10 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic sameAsSettings: isSameNodeAsSettings, isFallback: isFallbackNode }, + network: { + peering: that.get('/network/peering'), + peers: that.get('/network/peers') + }, record: { post: postRecord, remove: removeRecord @@ -661,10 +678,10 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic } - var service = new Factory(); + var service = new EsHttp(); service.instance = function(host, port, wsPort, useSsl) { - return new Factory(host, port, wsPort, useSsl); + return new EsHttp(host, port, wsPort, useSsl); }; return service; diff --git a/www/templates/network/item_content_peer.html b/www/templates/network/item_content_peer.html index 37adfd83c21f44f077516afc0f3f244a000bc65b..deffb8e8506eb3942d19f81fc72ab2ea580c101c 100644 --- a/www/templates/network/item_content_peer.html +++ b/www/templates/network/item_content_peer.html @@ -54,7 +54,9 @@ <span ng-if=":rebind:peer.uid"><i class="ion-lock-combination"></i>{{:rebind:peer.difficulty||'?'}}</span> <span ng-if=":rebind:!peer.uid" translate>PEER.MIRROR</span> </h3> - <h4 class="hidden-sm hidden-xs gray">{{:rebind: peer.version ? ('v'+peer.version) : ''}}</h4> + <h4 class="hidden-sm hidden-xs gray"> + {{:rebind: peer.software !== 'duniter' ? peer.software : ''}} + {{:rebind: peer.version ? ('v'+peer.version) : ''}}</h4> </div> <div class="col col-20 no-padding text-center"> <span id="{{$index === 0 ? helptipPrefix + '-peer-0-block' : ''}}"