diff --git a/js/modules/loki_app_dot_net_api.js b/js/modules/loki_app_dot_net_api.js index ef56f8c1b..ecc8e9d3c 100644 --- a/js/modules/loki_app_dot_net_api.js +++ b/js/modules/loki_app_dot_net_api.js @@ -269,7 +269,7 @@ const serverRequest = async (endpoint, options = {}) => { )); } else { // disable check for .loki - process.env.NODE_TLS_REJECT_UNAUTHORIZED = url.host.match(/\.loki$/i) + process.env.NODE_TLS_REJECT_UNAUTHORIZED = host.match(/\.loki$/i) ? '0' : '1'; result = await nodeFetch(url, fetchOptions); @@ -298,7 +298,7 @@ const serverRequest = async (endpoint, options = {}) => { url ); } - if (mode === '_sendToProxy') { + if (mode === 'sendToProxy') { // if we can detect, certain types of failures, we can retry... if (e.code === 'ECONNRESET') { // retry with counter? @@ -658,7 +658,7 @@ class LokiAppDotNetServerAPI { try { const res = await this.proxyFetch( - `${this.baseServerUrl}/loki/v1/submit_challenge`, + new URL(`${this.baseServerUrl}/loki/v1/submit_challenge`), fetchOptions, { textResponse: true } ); @@ -683,7 +683,8 @@ class LokiAppDotNetServerAPI { } const urlStr = urlObj.toString(); const endpoint = urlStr.replace(`${this.baseServerUrl}/`, ''); - const { response, result } = await this._sendToProxy( + const { response, result } = await sendToProxy( + this.pubKey, endpoint, finalOptions, options @@ -694,8 +695,8 @@ class LokiAppDotNetServerAPI { json: () => response, }; } - const urlStr = urlObj.toString(); - if (urlStr.match(/\.loki\//)) { + const host = urlObj.host.toLowerCase(); + if (host.match(/\.loki$/)) { process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; } const result = nodeFetch(urlObj, fetchOptions, options); diff --git a/js/modules/loki_message_api.js b/js/modules/loki_message_api.js index a26757159..fc9352ea7 100644 --- a/js/modules/loki_message_api.js +++ b/js/modules/loki_message_api.js @@ -206,6 +206,18 @@ class LokiMessageAPI { targetNode ); + // do not return true if we get false here... + if (result === false) { + log.warn( + `loki_message:::_sendToNode - Got false from ${targetNode.ip}:${ + targetNode.port + }` + ); + successiveFailures += 1; + // eslint-disable-next-line no-continue + continue; + } + // Make sure we aren't doing too much PoW const currentDifficulty = window.storage.get('PoWDifficulty', null); if ( @@ -387,6 +399,15 @@ class LokiMessageAPI { nodeData ); + if (result === false) { + // make a note of it because of caller doesn't care... + log.warn( + `loki_message:::_retrieveNextMessages - lokiRpc returned false to ${ + nodeData.ip + }:${nodeData.port}` + ); + } + return result.messages || []; } diff --git a/js/modules/loki_rpc.js b/js/modules/loki_rpc.js index 78255f506..a643633c9 100644 --- a/js/modules/loki_rpc.js +++ b/js/modules/loki_rpc.js @@ -192,14 +192,24 @@ const processOnionResponse = async (reqIdx, response, sharedKey, useAesGcm) => { const sendToProxy = async (options = {}, targetNode, retryNumber = 0) => { const _ = window.Lodash; - const snodePool = await lokiSnodeAPI.getRandomSnodePool(); + let snodePool = await lokiSnodeAPI.getRandomSnodePool(); if (snodePool.length < 2) { log.error( - 'Not enough service nodes for a proxy request, only have: ', - snodePool.length + 'lokiRpc::sendToProxy - Not enough service nodes for a proxy request, only have:', + snodePool.length, + 'snode, attempting refresh' ); - return false; + await lokiSnodeAPI.refreshRandomPool(); + snodePool = await lokiSnodeAPI.getRandomSnodePool(); + if (snodePool.length < 2) { + log.error( + 'lokiRpc::sendToProxy - Not enough service nodes for a proxy request, only have:', + snodePool.length, + 'failing' + ); + return false; + } } // Making sure the proxy node is not the same as the target node: @@ -292,7 +302,11 @@ const sendToProxy = async (options = {}, targetNode, retryNumber = 0) => { // it's likely a net problem or an actual problem on the target node // lets mark the target node bad for now // we'll just rotate it back in if it's a net problem - log.warn(`Failing ${targetNode.ip}:${targetNode.port} after 5 retries`); + log.warn( + `lokiRpc:::sendToProxy - Failing ${targetNode.ip}:${ + targetNode.port + } after 5 retries` + ); if (options.ourPubKey) { lokiSnodeAPI.unreachableNode(options.ourPubKey, targetNode); } @@ -329,7 +343,11 @@ const sendToProxy = async (options = {}, targetNode, retryNumber = 0) => { // avoid base64 decode failure // usually a 500 but not always // could it be a timeout? - log.warn('Server did not return any data for', options, targetNode); + log.warn( + 'lokiRpc:::sendToProxy - Server did not return any data for', + options, + targetNode + ); return false; } @@ -404,6 +422,7 @@ const sendToProxy = async (options = {}, targetNode, retryNumber = 0) => { }; // A small wrapper around node-fetch which deserializes response +// returns nodeFetch response or false const lokiFetch = async (url, options = {}, targetNode = null) => { const timeout = options.timeout || 10000; const method = options.method || 'GET'; @@ -454,6 +473,22 @@ const lokiFetch = async (url, options = {}, targetNode = null) => { if (window.lokiFeatureFlags.useSnodeProxy && targetNode) { const result = await sendToProxy(fetchOptions, targetNode); + if (result === false) { + // should we retry? + log.warn(`lokiRpc:::lokiFetch - sendToProxy returned false`); + // one case is: + // snodePool didn't have enough + // even after a refresh + // likely a network disconnect? + // but not all cases... + /* + log.warn( + 'lokiRpc:::lokiFetch - useSnodeProxy failure, could not refresh randomPool, offline?' + ); + */ + // pass the false value up + return false; + } // if not result, maybe we should throw?? return result ? result.json() : {}; } diff --git a/js/modules/loki_snode_api.js b/js/modules/loki_snode_api.js index 9642d64e0..0152a584a 100644 --- a/js/modules/loki_snode_api.js +++ b/js/modules/loki_snode_api.js @@ -97,18 +97,36 @@ class LokiSnodeAPI { async selectGuardNodes() { const _ = window.Lodash; - const nodePool = await this.getRandomSnodePool(); + let nodePool = await this.getRandomSnodePool(); if (nodePool.length === 0) { log.error(`Could not select guarn nodes: node pool is empty`); return []; } - const shuffled = _.shuffle(nodePool); + let shuffled = _.shuffle(nodePool); let guardNodes = []; const DESIRED_GUARD_COUNT = 3; + if (shuffled.length < DESIRED_GUARD_COUNT) { + log.error( + `Could not select guarn nodes: node pool is not big enough, pool size ${ + shuffled.length + }, need ${DESIRED_GUARD_COUNT}, attempting to refresh randomPool` + ); + await this.refreshRandomPool(); + nodePool = await this.getRandomSnodePool(); + shuffled = _.shuffle(nodePool); + if (shuffled.length < DESIRED_GUARD_COUNT) { + log.error( + `Could not select guarn nodes: node pool is not big enough, pool size ${ + shuffled.length + }, need ${DESIRED_GUARD_COUNT}, failing...` + ); + return []; + } + } // The use of await inside while is intentional: // we only want to repeat if the await fails @@ -490,6 +508,7 @@ class LokiSnodeAPI { throw new window.textsecure.SeedNodeError('Failed to contact seed node'); } log.info('loki_snodes:::refreshRandomPoolPromise - RESOLVED'); + delete this.refreshRandomPoolPromise; // clear any lock } // unreachableNode.url is like 9hrje1bymy7hu6nmtjme9idyu3rm8gr3mkstakjyuw1997t7w4ny.snode diff --git a/package.json b/package.json index ee6822cbc..e4b371f68 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-messenger-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.0.4", + "version": "1.0.5", "license": "GPL-3.0", "author": { "name": "Loki Project", diff --git a/yarn.lock b/yarn.lock index ff06052c3..82f776d6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6065,6 +6065,11 @@ lodash-es@^4.2.1: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== +lodash-es@^4.2.1: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" + integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== + lodash.assign@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" @@ -8746,8 +8751,8 @@ redent@^1.0.0: resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" + loose-envify "^1.4.0" + symbol-observable "^1.2.0" reduce-css-calc@^1.2.6: version "1.3.0" @@ -11213,7 +11218,7 @@ write-file-atomic@^1.1.4: dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" - slide "^1.1.5" + signal-exit "^3.0.2" write-file-atomic@^3.0.0: version "3.0.3"