From e5e71c4577b17eb983e5c18ec0fcff4e8b63a1a3 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 15:39:34 -0700 Subject: [PATCH 01/14] move window.LokiPublicChatAPI.setClockParams() out --- js/background.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/js/background.js b/js/background.js index d5b0d682f..cbddde7d3 100644 --- a/js/background.js +++ b/js/background.js @@ -124,9 +124,6 @@ 'loki/session_icon_128.png', ]); - // Set server-client time difference - window.LokiPublicChatAPI.setClockParams(); - // We add this to window here because the default Node context is erased at the end // of preload.js processing window.setImmediate = window.nodeSetImmediate; From c8d1ef17e535bd817a3c47e7cc825e61f9e87db9 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 15:41:07 -0700 Subject: [PATCH 02/14] setClockParams(), getTimeDifferential(), getServerTime(), and call it --- js/expire.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/js/expire.js b/js/expire.js index 0d4750c3b..ba200c41e 100644 --- a/js/expire.js +++ b/js/expire.js @@ -52,6 +52,8 @@ } // no message logged means serverRequest never returned... }; + + // don't wait for this to finish checkForUpgrades(); window.extension = window.extension || {}; @@ -91,4 +93,45 @@ // yes we know cb(expiredVersion); }; + + const getServerTime = async () => { + let timestamp = NaN; + + try { + const res = await window.tokenlessFileServerAdnAPI.serverRequest( + 'loki/v1/time' + ); + if (res.statusCode === 200) { + timestamp = res.response; + } + } catch (e) { + return timestamp; + } + + return Number(timestamp); + }; + + const getTimeDifferential = async () => { + // Get time differential between server and client in seconds + const serverTime = await getServerTime(); + const clientTime = Math.ceil(Date.now() / 1000); + + if (Number.isNaN(serverTime)) { + log.error('expire:::getTimeDifferential - serverTime is not valid'); + return 0; + } + return serverTime - clientTime; + }; + + // require for PoW to work + const setClockParams = async () => { + // Set server-client time difference + const maxTimeDifferential = 30 + 15; // + 15 for onion requests + const timeDifferential = await getTimeDifferential(); + log.info('expire:::setClockParams - Clock difference', timeDifferential); + + window.clientClockSynced = Math.abs(timeDifferential) < maxTimeDifferential; + return window.clientClockSynced; + }; + setClockParams(); })(); From 9ecdcbf581aab37b32dd17109b355e019e3262cd Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 15:41:57 -0700 Subject: [PATCH 03/14] use tokenlessFileServerAdnAPI for RSS requests --- js/modules/loki_rss_api.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/modules/loki_rss_api.js b/js/modules/loki_rss_api.js index 566a2afc1..fb6763c97 100644 --- a/js/modules/loki_rss_api.js +++ b/js/modules/loki_rss_api.js @@ -63,7 +63,7 @@ class LokiRssAPI extends EventEmitter { log.warn('LokiRssAPI unsupported rss feed', this.feedUrl); return; } - const result = await window.lokiFileServerAPI._server.serverRequest( + const result = await window.tokenlessFileServerAdnAPI.serverRequest( map[this.feedUrl] ); if (!result) { @@ -77,6 +77,7 @@ class LokiRssAPI extends EventEmitter { if (!result.response.data) { log.error( 'LokiRssAPI rss proxy error, no data, response', + typeof result.response, result.response ); return; From ba87eeecdae8fa91b8355a261b909aae63d36e5c Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 15:42:34 -0700 Subject: [PATCH 04/14] fix logging variable, expose BAD_PATH --- js/modules/loki_rpc.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/modules/loki_rpc.js b/js/modules/loki_rpc.js index dfbce16ae..794c26fd6 100644 --- a/js/modules/loki_rpc.js +++ b/js/modules/loki_rpc.js @@ -670,7 +670,7 @@ const lokiFetch = async (url, options = {}, targetNode = null) => { const result = await response.json(); log.warn( `lokirpc:::lokiFetch ${type} - wrong swarm, now looking at snodes`, - result.snode + result.snodes ); const newSwarm = result.snodes ? result.snodes : []; throw new textsecure.WrongSwarmError(newSwarm); @@ -859,5 +859,6 @@ const lokiRpc = ( module.exports = { lokiRpc, + BAD_PATH, sendOnionRequestLsrpcDest, }; From 355005b0c1f5089c0a515c168a776fbdc63f0cef Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 15:59:06 -0700 Subject: [PATCH 05/14] buildNewOnionPaths() refresh if too few nodes, mark markPathAsBad as non-async, getOnionPath() retry until good paths, logging adjustment, guards --- js/modules/loki_snode_api.js | 170 ++++++++++++++++++++++------------- 1 file changed, 107 insertions(+), 63 deletions(-) diff --git a/js/modules/loki_snode_api.js b/js/modules/loki_snode_api.js index d6d030493..013bce0b5 100644 --- a/js/modules/loki_snode_api.js +++ b/js/modules/loki_snode_api.js @@ -26,11 +26,8 @@ async function tryGetSnodeListFromLokidSeednode( seedNodes = window.seedNodeList ) { if (!seedNodes.length) { - log.error( - `loki_snodes:::tryGetSnodeListFromLokidSeednode - no seedNodes given`, - seedNodes, - 'window', - window.seedNodeList + log.info( + 'LokiSnodeAPI::tryGetSnodeListFromLokidSeednode - seedNodes are empty' ); return []; } @@ -47,13 +44,10 @@ async function tryGetSnodeListFromLokidSeednode( }, }; // FIXME: use sample - const seedNode = seedNodes.splice( - Math.floor(Math.random() * seedNodes.length), - 1 - )[0]; + const seedNode = seedNodes[Math.floor(Math.random() * seedNodes.length)]; if (!seedNode) { - log.error( - `loki_snodes:::tryGetSnodeListFromLokidSeednode - seedNode selection failure - seedNodes`, + log.warn( + 'LokiSnodeAPI::tryGetSnodeListFromLokidSeednode - Could not select random snodes from', seedNodes ); return []; @@ -102,29 +96,40 @@ async function tryGetSnodeListFromLokidSeednode( snodes = await getSnodesFromSeedUrl(tryUrl); // throw before clearing the lock, so the retries can kick in if (snodes.length === 0) { + log.warn( + `LokiSnodeAPI::tryGetSnodeListFromLokidSeednode - ${ + seedNode.url + } did not return any snodes, falling back to IP`, + seedNode.ip_url + ); // fall back on ip_url const tryIpUrl = new URL(seedNode.ip_url); snodes = await getSnodesFromSeedUrl(tryIpUrl); if (snodes.length === 0) { + log.warn( + `LokiSnodeAPI::tryGetSnodeListFromLokidSeednode - ${ + seedNode.ip_url + } did not return any snodes` + ); // does this error message need to be exactly this? throw new window.textsecure.SeedNodeError( 'Failed to contact seed node' ); } } - if (snodes.length) { - log.info( - `loki_snodes:::tryGetSnodeListFromLokidSeednode - got ${ - snodes.length - } service nodes from seed` - ); - } + log.info( + `LokiSnodeAPI::tryGetSnodeListFromLokidSeednode - ${ + seedNode.url + } returned ${snodes.length} snodes` + ); return snodes; } catch (e) { log.warn( - 'loki_snodes:::tryGetSnodeListFromLokidSeednode - error', + 'LokiSnodeAPI::tryGetSnodeListFromLokidSeednode - error', e.code, - e.message + e.message, + 'on', + seedNode ); if (snodes.length === 0) { throw new window.textsecure.SeedNodeError('Failed to contact seed node'); @@ -138,11 +143,8 @@ async function getSnodeListFromLokidSeednode( retries = 0 ) { if (!seedNodes.length) { - log.error( - `loki_snodes:::getSnodeListFromLokidSeednode - no seedNodes given`, - seedNodes, - 'window', - window.seedNodeList + log.info( + 'LokiSnodeAPI::getSnodeListFromLokidSeednode - seedNodes are empty' ); return []; } @@ -151,7 +153,7 @@ async function getSnodeListFromLokidSeednode( snodes = await tryGetSnodeListFromLokidSeednode(seedNodes); } catch (e) { log.warn( - 'loki_snodes:::getSnodeListFromLokidSeednode - error', + 'LokiSnodeAPI::getSnodeListFromLokidSeednode - error', e.code, e.message ); @@ -159,13 +161,15 @@ async function getSnodeListFromLokidSeednode( if (retries < SEED_NODE_RETRIES) { setTimeout(() => { log.info( - 'loki_snodes:::refreshRandomPoolPromise - Retrying initialising random snode pool, try #', - retries + 'LokiSnodeAPI::getSnodeListFromLokidSeednode - Retrying initialising random snode pool, try #', + retries, + 'seed nodes total', + seedNodes.length ); getSnodeListFromLokidSeednode(seedNodes, retries + 1); }, retries * retries * 5000); } else { - log.error('loki_snodes:::getSnodeListFromLokidSeednode - failing'); + log.error('LokiSnodeAPI::getSnodeListFromLokidSeednode - failing'); throw new window.textsecure.SeedNodeError('Failed to contact seed node'); } } @@ -241,6 +245,8 @@ class LokiSnodeAPI { let response; try { + // Log this line for testing + // curl -k -X POST -H 'Content-Type: application/json' -d '"+fetchOptions.body.replace(/"/g, "\\'")+"'", url response = await nodeFetch(url, fetchOptions); } catch (e) { if (e.type === 'request-timeout') { @@ -333,21 +339,34 @@ class LokiSnodeAPI { async getOnionPath(toExclude = null) { const _ = window.Lodash; - const goodPaths = this.onionPaths.filter(x => !x.bad); + let goodPaths = this.onionPaths.filter(x => !x.bad); - if (goodPaths.length < 2) { + let attemptNumber = 0; + while (goodPaths.length < 2) { log.error( - `Must have at least 2 good onion paths, actual: ${goodPaths.length}` + `Must have at least 2 good onion paths, actual: ${ + goodPaths.length + }, attempt #${attemptNumber} fetching more...` ); + // eslint-disable-next-line no-await-in-loop await this.buildNewOnionPaths(); // should we add a delay? buildNewOnionPaths should act as one + // reload goodPaths now - return this.getOnionPath(toExclude); + attemptNumber += 1; + goodPaths = this.onionPaths.filter(x => !x.bad); } const paths = _.shuffle(goodPaths); if (!toExclude) { + if (!paths[0]) { + log.error('LokiSnodeAPI::getOnionPath - no path in', paths); + return []; + } + if (!paths[0].path) { + log.error('LokiSnodeAPI::getOnionPath - no path in', paths[0]); + } return paths[0].path; } @@ -375,11 +394,21 @@ class LokiSnodeAPI { throw new Error('No onion paths available after filtering'); } + if (!otherPaths[0].path) { + log.error( + 'LokiSnodeAPI::getOnionPath - otherPaths no path in', + otherPaths[0] + ); + } + return otherPaths[0].path; } - async markPathAsBad(path) { + markPathAsBad(path) { this.onionPaths.forEach(p => { + if (!p.path) { + log.error('LokiSnodeAPI::markPathAsBad - no path in', p); + } if (p.path === path) { // eslint-disable-next-line no-param-reassign p.bad = true; @@ -387,13 +416,14 @@ class LokiSnodeAPI { }); } + // FIXME: need a lock because it is being called multiple times in parallel async buildNewOnionPaths() { // Note: this function may be called concurrently, so // might consider blocking the other calls const _ = window.Lodash; - log.info('building new onion paths'); + log.info('LokiSnodeAPI::buildNewOnionPaths - building new onion paths'); const allNodes = await this.getRandomSnodePool(); @@ -402,7 +432,9 @@ class LokiSnodeAPI { const nodes = await window.libloki.storage.getGuardNodes(); if (nodes.length === 0) { - log.warn('no guard nodes in DB. Will be selecting new guards nodes...'); + log.warn( + 'LokiSnodeAPI::buildNewOnionPaths - no guard nodes in DB. Will be selecting new guards nodes...' + ); } else { // We only store the nodes' keys, need to find full entries: const edKeys = nodes.map(x => x.ed25519PubKey); @@ -412,9 +444,9 @@ class LokiSnodeAPI { if (this.guardNodes.length < edKeys.length) { log.warn( - `could not find some guard nodes: ${this.guardNodes.length}/${ - edKeys.length - } left` + `LokiSnodeAPI::buildNewOnionPaths - could not find some guard nodes: ${ + this.guardNodes.length + }/${edKeys.length} left` ); } } @@ -429,8 +461,11 @@ class LokiSnodeAPI { let otherNodes = _.difference(allNodes, this.guardNodes); if (otherNodes.length < 2) { - log.error('Too few nodes to build an onion path!'); - return; + log.warn( + 'LokiSnodeAPI::buildNewOnionPaths - Too few nodes to build an onion path! Refreshing pool and retrying' + ); + await this.refreshRandomPool(); + return this.buildNewOnionPaths(); } otherNodes = _.shuffle(otherNodes); @@ -498,7 +533,7 @@ class LokiSnodeAPI { await this.refreshRandomPool(); } catch (e) { log.error( - `loki_snode:::getRandomProxySnodeAddress - error ${e.code} ${ + `LokiSnodeAPI::getRandomProxySnodeAddress - error ${e.code} ${ e.message }` ); @@ -512,7 +547,7 @@ class LokiSnodeAPI { if (!goodPool.length) { // FIXME: retry log.warn( - `loki_snode:::getRandomProxySnodeAddress - no good versions yet` + `LokiSnodeAPI::getRandomProxySnodeAddress - no good versions yet` ); return false; } @@ -544,7 +579,7 @@ class LokiSnodeAPI { } else { // maybe already marked bad... log.debug( - `loki_snode:::_getVersion - can't find ${node.ip}:${ + `LokiSnodeAPI::_getVersion - can't find ${node.ip}:${ node.port } in randomSnodePool` ); @@ -561,7 +596,7 @@ class LokiSnodeAPI { const randomNodesLeft = this.getRandomPoolLength(); // clean up these error messages to be a little neater log.warn( - `loki_snode:::_getVersion - ${node.ip}:${ + `LokiSnodeAPI::_getVersion - ${node.ip}:${ node.port } is offline, removing, leaving ${randomNodesLeft} in the randomPool` ); @@ -569,7 +604,7 @@ class LokiSnodeAPI { // ENOTFOUND could mean no internet or hiccup } else if (retries < SNODE_VERSION_RETRIES) { log.warn( - 'loki_snode:::_getVersion - Error', + 'LokiSnodeAPI::_getVersion - Error', e.code, e.message, `on ${node.ip}:${node.port} retrying in 1s` @@ -580,7 +615,7 @@ class LokiSnodeAPI { this.markRandomNodeUnreachable(node); const randomNodesLeft = this.getRandomPoolLength(); log.warn( - `loki_snode:::_getVersion - failing to get version for ${node.ip}:${ + `LokiSnodeAPI::_getVersion - failing to get version for ${node.ip}:${ node.port }, removing, leaving ${randomNodesLeft} in the randomPool` ); @@ -620,7 +655,7 @@ class LokiSnodeAPI { */ } catch (e) { log.error( - `loki_snode:::_getAllVerionsForRandomSnodePool - error`, + `LokiSnodeAPI::_getAllVerionsForRandomSnodePool - error`, e.code, e.message ); @@ -640,7 +675,7 @@ class LokiSnodeAPI { return curVal; }, []); log.debug( - `loki_snode:::_getAllVerionsForRandomSnodePool - ${ + `LokiSnodeAPI::_getAllVerionsForRandomSnodePool - ${ versions.length } versions retrieved from network!:`, versions.join(',') @@ -678,14 +713,14 @@ class LokiSnodeAPI { pubkey_ed25519: snode.pubkey_ed25519, })); log.info( - 'loki_snodes:::refreshRandomPool - Refreshed random snode pool with', + 'LokiSnodeAPI::refreshRandomPool - Refreshed random snode pool with', this.randomSnodePool.length, 'snodes' ); // start polling versions but no need to await it this._getAllVerionsForRandomSnodePool(); } catch (e) { - log.warn('loki_snodes:::refreshRandomPool - error', e.code, e.message); + log.warn('LokiSnodeAPI::refreshRandomPool - error', e.code, e.message); /* log.error( 'loki_snodes:::refreshRandomPoolPromise - Giving up trying to contact seed node' @@ -707,7 +742,7 @@ class LokiSnodeAPI { const swarmNodes = [...conversation.get('swarmNodes')]; if (typeof unreachableNode === 'string') { log.warn( - 'loki_snodes:::unreachableNode - String passed as unreachableNode to unreachableNode' + 'LokiSnodeAPI::unreachableNode - String passed as unreachableNode to unreachableNode' ); return swarmNodes; } @@ -724,7 +759,7 @@ class LokiSnodeAPI { }); if (!found) { log.warn( - `loki_snodes:::unreachableNode - snode ${unreachableNode.ip}:${ + `LokiSnodeAPI::unreachableNode - snode ${unreachableNode.ip}:${ unreachableNode.port } has already been marked as bad` ); @@ -732,7 +767,7 @@ class LokiSnodeAPI { try { await conversation.updateSwarmNodes(filteredNodes); } catch (e) { - log.error(`loki_snodes:::unreachableNode - error ${e.code} ${e.message}`); + log.error(`LokiSnodeAPI::unreachableNode - error ${e.code} ${e.message}`); throw e; } return filteredNodes; @@ -770,7 +805,7 @@ class LokiSnodeAPI { node.address ); log.debug( - `loki_snode:::getSwarmNodesForPubKey - ${j} ${node.ip}:${ + `LokiSnodeAPI::getSwarmNodesForPubKey - ${j} ${node.ip}:${ node.port }` ); @@ -799,7 +834,7 @@ class LokiSnodeAPI { return filteredNodes; } catch (e) { log.error( - `loki_snodes:::updateSwarmNodes - error ${e.code} ${e.message}` + `LokiSnodeAPI::updateSwarmNodes - error ${e.code} ${e.message}` ); throw new window.textsecure.ReplayableError({ message: 'Could not get conversation', @@ -812,6 +847,10 @@ class LokiSnodeAPI { async refreshSwarmNodesForPubKey(pubKey) { // FIXME: handle rejections const newNodes = await this._getFreshSwarmNodes(pubKey); + log.debug( + 'LokiSnodeAPI::refreshSwarmNodesForPubKey - newNodes', + newNodes.length + ); const filteredNodes = this.updateSwarmNodes(pubKey, newNodes); return filteredNodes; } @@ -823,7 +862,7 @@ class LokiSnodeAPI { newSwarmNodes = await this._getSwarmNodes(pubKey); } catch (e) { log.error( - 'loki_snodes:::_getFreshSwarmNodes - error', + 'LokiSnodeAPI::_getFreshSwarmNodes - error', e.code, e.message ); @@ -929,7 +968,7 @@ class LokiSnodeAPI { // get snodes for pubkey from random snode async _getSnodesForPubkey(pubKey) { - let snode = {}; + let snode = { ip: '', port: 0 }; try { snode = await this.getRandomSnodeAddress(); const result = await lokiRpc( @@ -945,7 +984,7 @@ class LokiSnodeAPI { ); if (!result) { log.warn( - `loki_snode:::_getSnodesForPubkey - lokiRpc on ${snode.ip}:${ + `LokiSnodeAPI::_getSnodesForPubkey - lokiRpc on ${snode.ip}:${ snode.port } returned falsish value`, result @@ -955,7 +994,7 @@ class LokiSnodeAPI { if (!result.snodes) { // we hit this when snode gives 500s log.warn( - `loki_snode:::_getSnodesForPubkey - lokiRpc on ${snode.ip}:${ + `LokiSnodeAPI::_getSnodesForPubkey - lokiRpc on ${snode.ip}:${ snode.port } returned falsish value for snodes`, result @@ -968,7 +1007,7 @@ class LokiSnodeAPI { this.markRandomNodeUnreachable(snode); const randomPoolRemainingCount = this.getRandomPoolLength(); log.error( - 'loki_snodes:::_getSnodesForPubkey - error', + 'LokiSnodeAPI::_getSnodesForPubkey - error', e.code, e.message, `for ${snode.ip}:${ @@ -985,9 +1024,14 @@ class LokiSnodeAPI { const questions = [...Array(RANDOM_SNODES_TO_USE_FOR_PUBKEY_SWARM).keys()]; // FIXME: handle rejections await Promise.all( - questions.map(async () => { + questions.map(async qNum => { // allow exceptions to pass through upwards const resList = await this._getSnodesForPubkey(pubKey); + log.info( + `LokiSnodeAPI::_getSwarmNodes - question ${qNum} got`, + resList.length, + 'snodes' + ); resList.map(item => { const hasItem = snodes.some(n => compareSnodes(n, item)); if (!hasItem) { @@ -997,7 +1041,7 @@ class LokiSnodeAPI { }); }) ); - // should we only activate entries that are in all results? + // should we only activate entries that are in all results? yes return snodes; } } From b8fb24853d15f73aec72faa963ef1ce917e6b4f2 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 16:06:02 -0700 Subject: [PATCH 06/14] move out clock stuff, validOpenGroupServer() checks for lsrpc/pubkey and make private, findOrCreateServer sets pubkeys (enabled OR) if we have one --- js/modules/loki_public_chat_api.js | 171 ++++++++++++++++++----------- 1 file changed, 106 insertions(+), 65 deletions(-) diff --git a/js/modules/loki_public_chat_api.js b/js/modules/loki_public_chat_api.js index 7d9222876..e48c830ba 100644 --- a/js/modules/loki_public_chat_api.js +++ b/js/modules/loki_public_chat_api.js @@ -1,14 +1,94 @@ -/* global log, window, process, URL */ +/* global log, window, process, URL, dcodeIO */ const EventEmitter = require('events'); -const nodeFetch = require('node-fetch'); const LokiAppDotNetAPI = require('./loki_app_dot_net_api'); +const nodeFetch = require('node-fetch'); + +const validOpenGroupServer = async serverUrl => { + // test to make sure it's online (and maybe has a valid SSL cert) + try { + const url = new URL(serverUrl); + + if (window.lokiFeatureFlags.useFileOnionRequests) { + // check for LSRPC + + // this is safe (as long as node's in your trust model) + // because + const result = await window.tokenlessFileServerAdnAPI.serverRequest( + `loki/v1/getOpenGroupKey/${url.hostname}` + ); + // console.log('loki_public_chat::validOpenGroupServer - result', result); + // console.log('loki_public_chat::validOpenGroupServer - meta', result.response.meta); + if (result.response.meta.code === 200) { + // supports it + const obj = JSON.parse(result.response.data); + const pubKey = dcodeIO.ByteBuffer.wrap( + obj.data, + 'base64' + ).toArrayBuffer(); + // verify it works... + // get around the FILESERVER_HOSTS filter + /* + const res = await LokiAppDotNetAPI.serverRequest(url.toString(), { + srvPubKey: pubKey, + }); + */ + const res = await LokiAppDotNetAPI.sendViaOnion( + pubKey, + url, + { method: 'GET' }, + { noJson: true } + ); + if (res.result.status === 200) { + log.info( + `loki_public_chat::validOpenGroupServer - onion routing enabled on ${url.toString()}` + ); + // save pubkey for use... + window.lokiPublicChatAPI.openGroupPubKeys[serverUrl] = pubKey; + return true; + } + // otherwise fall back + } else if (result.response.meta.code === 404) { + // doesn't support it + // console.log('loki_public_chat::validOpenGroupServer - no onion routing available'); + // fallback + } else { + // unknown error code + log.warn( + 'loki_public_chat::validOpenGroupServer - unknown error code', + result.response.meta + ); + // fallback + } + } + log.info( + `loki_public_chat::validOpenGroupServer - directly contacting ${url.toString()}` + ); + + // allow .loki (may only need an agent but not sure + // until we have a .loki to test with) + process.env.NODE_TLS_REJECT_UNAUTHORIZED = url.host.match(/\.loki$/i) + ? '0' + : '1'; + await nodeFetch(serverUrl); + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'; + // const txt = await res.text(); + } catch (e) { + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'; + log.warn(`loki_public_chat::validOpenGroupServer - failing to create ${serverUrl}`, e.code, e.message); + // bail out if not valid enough + return false; + } + return true; +}; + class LokiPublicChatFactoryAPI extends EventEmitter { constructor(ourKey) { super(); this.ourKey = ourKey; this.servers = []; this.allMembers = []; + this.openGroupPubKeys = {}; // Multidevice states this.primaryUserProfileName = {}; } @@ -24,37 +104,20 @@ class LokiPublicChatFactoryAPI extends EventEmitter { await Promise.all(this.servers.map(server => server.close())); } - static async validServer(serverUrl) { - // test to make sure it's online (and maybe has a valid SSL cert) - try { - const url = new URL(serverUrl); - // allow .loki (may only need an agent but not sure - // until we have a .loki to test with) - process.env.NODE_TLS_REJECT_UNAUTHORIZED = url.host.match(/\.loki$/i) - ? '0' - : '1'; - // FIXME: use proxy when we have open groups that work with proxy - await nodeFetch(serverUrl); - process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'; - // const txt = await res.text(); - } catch (e) { - process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'; - log.warn(`failing to created ${serverUrl}`, e.code, e.message); - // bail out if not valid enough - return false; - } - return true; - } - // server getter/factory async findOrCreateServer(serverUrl) { let thisServer = this.servers.find( server => server.baseServerUrl === serverUrl ); if (!thisServer) { - log.info(`LokiAppDotNetAPI creating ${serverUrl}`); - - if (!await this.constructor.validServer(serverUrl)) { + log.info(`loki_public_chat::findOrCreateServer - creating ${serverUrl}`); + + const serverIsValid = await validOpenGroupServer(serverUrl); + if (!serverIsValid) { + // FIXME: add toast? + log.error( + `loki_public_chat::findOrCreateServer - error: ${serverUrl} is not valid` + ); return null; } @@ -65,15 +128,29 @@ class LokiPublicChatFactoryAPI extends EventEmitter { thisServer = new StubAppDotNetAPI(this.ourKey, serverUrl); } else { thisServer = new LokiAppDotNetAPI(this.ourKey, serverUrl); + if (this.openGroupPubKeys[serverUrl]) { + thisServer.getPubKeyForUrl(); + if (!thisServer.pubKeyHex) { + log.warn( + `loki_public_chat::findOrCreateServer - failed to set public key` + ); + } + } } const gotToken = await thisServer.getOrRefreshServerToken(); if (!gotToken) { - log.warn(`Invalid server ${serverUrl}`); + log.warn( + `loki_public_chat::findOrCreateServer - Invalid server ${serverUrl}` + ); return null; } if (window.isDev) { - log.info(`set token ${thisServer.token} for ${serverUrl}`); + log.info( + `loki_public_chat::findOrCreateServer - set token ${ + thisServer.token + } for ${serverUrl}` + ); } this.servers.push(thisServer); @@ -81,42 +158,6 @@ class LokiPublicChatFactoryAPI extends EventEmitter { return thisServer; } - static async getServerTime() { - const url = `${window.getDefaultFileServer()}/loki/v1/time`; - let timestamp = NaN; - - try { - const res = await nodeFetch(url); - if (res.ok) { - timestamp = await res.text(); - } - } catch (e) { - return timestamp; - } - - return Number(timestamp); - } - - static async getTimeDifferential() { - // Get time differential between server and client in seconds - const serverTime = await this.getServerTime(); - const clientTime = Math.ceil(Date.now() / 1000); - - if (Number.isNaN(serverTime)) { - return 0; - } - return serverTime - clientTime; - } - - static async setClockParams() { - // Set server-client time difference - const maxTimeDifferential = 30; - const timeDifferential = await this.getTimeDifferential(); - - window.clientClockSynced = Math.abs(timeDifferential) < maxTimeDifferential; - return window.clientClockSynced; - } - // channel getter/factory async findOrCreateChannel(serverUrl, channelId, conversationId) { const server = await this.findOrCreateServer(serverUrl); From bb963b77f1268b43391ada579421c37554d880e9 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 16:40:57 -0700 Subject: [PATCH 07/14] expose serverRequest/sendViaOnion, sendViaOnion fix querystring/bad path response handling/handle text responses, getPubKeyForUrl check window.lokiPublicChatAPI.openGroupPubKeys for this.baseServerUrl --- js/modules/loki_app_dot_net_api.js | 133 +++++++++++++++++------------ 1 file changed, 80 insertions(+), 53 deletions(-) diff --git a/js/modules/loki_app_dot_net_api.js b/js/modules/loki_app_dot_net_api.js index e6645cf69..dd6d22ad1 100644 --- a/js/modules/loki_app_dot_net_api.js +++ b/js/modules/loki_app_dot_net_api.js @@ -65,15 +65,15 @@ const sendViaOnion = async (srvPubKey, url, fetchOptions, options = {}) => { } const payloadObj = { - method: fetchOptions.method, - body: fetchOptions.body, + method: fetchOptions.method || 'GET', + body: fetchOptions.body || '', // safety issue with file server, just safer to have this headers: fetchOptions.headers || {}, // no initial / endpoint: url.pathname.replace(/^\//, ''), }; if (url.search) { - payloadObj.endpoint += `?${url.search}`; + payloadObj.endpoint += url.search; } // from https://github.com/sindresorhus/is-stream/blob/master/index.js @@ -132,6 +132,10 @@ const sendViaOnion = async (srvPubKey, url, fetchOptions, options = {}) => { return {}; } + if (result === lokiRpcUtils.BAD_PATH) { + return {}; + } + // handle error/retries if (!result.status) { log.error( @@ -147,22 +151,49 @@ const sendViaOnion = async (srvPubKey, url, fetchOptions, options = {}) => { }); } + if (options.noJson) { + return { + result, + txtResponse: result.body, + response: { + data: result.body, + headers: result.headers, + }, + }; + } + // get the return variables we need let response = {}; let txtResponse = ''; - let body = ''; - try { - body = JSON.parse(result.body); - } catch (e) { - log.error( - `loki_app_dot_net:::sendViaOnion #${ - options.requestNumber - } - Cant decode JSON body`, - result.body + + let { body } = result; + if (typeof body === 'string') { + // adn does uses this path + // log.info(`loki_app_dot_net:::sendViaOnion - got text response ${url.toString()}`); + txtResponse = result.body; + try { + body = JSON.parse(result.body); + } catch (e) { + log.error( + `loki_app_dot_net:::sendViaOnion #${ + options.requestNumber + } - Cant decode JSON body`, + typeof result.body, + result.body + ); + } + } else { + // why is + // https://chat-dev.lokinet.org/loki/v1/channel/1/deletes?count=200&since_id= + // difference in response than all the other calls.... + log.info( + `loki_app_dot_net:::sendViaOnion - got object response ${url.toString()}` ); } // result.status has the http response code - txtResponse = JSON.stringify(body); + if (!txtResponse) { + txtResponse = JSON.stringify(body); + } response = body; response.headers = result.headers; @@ -224,8 +255,7 @@ const sendToProxy = async (srvPubKey, endpoint, fetchOptions, options = {}) => { // make temporary key for this request/response // async maybe preferable to avoid cpu spikes - // tho I think sync might be more apt in certain cases here... - // like sending + // but I think sync might be more apt in cases like sending... const ephemeralKey = await libloki.crypto.generateEphemeralKeyPair(); // mix server pub key with our priv key @@ -389,10 +419,14 @@ const serverRequest = async (endpoint, options = {}) => { FILESERVER_HOSTS.includes(host) ) { mode = 'sendViaOnion'; - // url.search automatically includes the ? part - // const search = url.search || ''; - // strip first slash - // const endpointWithQS = `${url.pathname}${search}`.replace(/^\//, ''); + ({ response, txtResponse, result } = await sendViaOnion( + srvPubKey, + url, + fetchOptions, + options + )); + } else if (window.lokiFeatureFlags.useFileOnionRequests && srvPubKey) { + mode = 'sendViaOnionOG'; ({ response, txtResponse, result } = await sendViaOnion( srvPubKey, url, @@ -422,9 +456,11 @@ const serverRequest = async (endpoint, options = {}) => { result = await nodeFetch(url, fetchOptions); // always make sure this check is enabled process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'; + txtResponse = await result.text(); // cloudflare timeouts (504s) will be html... response = options.textResponse ? txtResponse : JSON.parse(txtResponse); + // result.status will always be 200 // emulate the correct http code if available if (response && response.meta && response.meta.code) { @@ -574,55 +610,39 @@ class LokiAppDotNetServerAPI { getPubKeyForUrl() { // Hard coded let pubKeyAB; - if (urlPubkeyMap) { + if (urlPubkeyMap && urlPubkeyMap[this.baseServerUrl]) { pubKeyAB = window.Signal.Crypto.base64ToArrayBuffer( urlPubkeyMap[this.baseServerUrl] ); } - // else will fail validation later - - // if in proxy mode, don't allow "file-dev."... - // it only supports "file."... host. - if ( - window.lokiFeatureFlags.useSnodeProxy && - !window.lokiFeatureFlags.useOnionRequests - ) { - pubKeyAB = window.Signal.Crypto.base64ToArrayBuffer( - LOKIFOUNDATION_FILESERVER_PUBKEY - ); - } // do we have their pubkey locally? // FIXME: this._server won't be set yet... // can't really do this for the file server because we'll need the key // before we can communicate with lsrpc - /* - // get remote pubKey - this._server.serverRequest('loki/v1/public_key').then(keyRes => { - // we don't need to delay to protect identity because the token request - // should only be done over lokinet-lite - this.delayToken = true; - if (keyRes.err || !keyRes.response || !keyRes.response.data) { - if (keyRes.err) { - log.error(`Error ${keyRes.err}`); - } - } else { - // store it - this.pubKey = dcodeIO.ByteBuffer.wrap( - keyRes.response.data, - 'base64' - ).toArrayBuffer(); - // write it to a file + if (window.lokiFeatureFlags.useFileOnionRequests) { + if ( + window.lokiPublicChatAPI && + window.lokiPublicChatAPI.openGroupPubKeys && + window.lokiPublicChatAPI.openGroupPubKeys[this.baseServerUrl] + ) { + pubKeyAB = + window.lokiPublicChatAPI.openGroupPubKeys[this.baseServerUrl]; } - }); - */ + } else if (window.lokiFeatureFlags.useSnodeProxy) { + // if in proxy mode, replace with "file."... + // it only supports this host... + pubKeyAB = window.Signal.Crypto.base64ToArrayBuffer( + LOKIFOUNDATION_FILESERVER_PUBKEY + ); + } + // else will fail validation later // now that key is loaded, lets verify if (pubKeyAB && pubKeyAB.byteLength && pubKeyAB.byteLength !== 33) { log.error('FILESERVER PUBKEY is invalid, length:', pubKeyAB.byteLength); process.exit(1); } - this.pubKey = pubKeyAB; this.pubKeyHex = StringView.arrayBufferToHex(pubKeyAB); @@ -1099,7 +1119,11 @@ class LokiAppDotNetServerAPI { if (res.err || !res.response || !res.response.data) { if (res.err) { - log.error(`getUsers Error ${res.err}`); + log.error( + `loki_app_dot_net:::getUsers - Error: ${res.err} for ${pubKeys.join( + ',' + )}` + ); } return []; } @@ -2333,4 +2357,7 @@ class LokiPublicChannelAPI { } } +LokiAppDotNetServerAPI.serverRequest = serverRequest; +LokiAppDotNetServerAPI.sendViaOnion = sendViaOnion; + module.exports = LokiAppDotNetServerAPI; From 3c6e58e54bd9f5b2085e6381a3ad316f987c1c8b Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 16:41:25 -0700 Subject: [PATCH 08/14] build paths if useFileOnionRequests is on and useOnionRequests is not --- js/background.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/background.js b/js/background.js index cbddde7d3..af6dba3ae 100644 --- a/js/background.js +++ b/js/background.js @@ -286,7 +286,7 @@ // Update zoom window.updateZoomFactor(); - if (window.lokiFeatureFlags.useOnionRequests) { + if (window.lokiFeatureFlags.useOnionRequests || window.lokiFeatureFlags.useFileOnionRequests) { // Initialize paths for onion requests window.lokiSnodeAPI.buildNewOnionPaths(); } From ef92602615d50e6e446e1fa304ea5e1dc6cf90ca Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 16:53:28 -0700 Subject: [PATCH 09/14] dead code cleanup --- js/modules/loki_public_chat_api.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/js/modules/loki_public_chat_api.js b/js/modules/loki_public_chat_api.js index e48c830ba..4b17cc30e 100644 --- a/js/modules/loki_public_chat_api.js +++ b/js/modules/loki_public_chat_api.js @@ -27,12 +27,7 @@ const validOpenGroupServer = async serverUrl => { 'base64' ).toArrayBuffer(); // verify it works... - // get around the FILESERVER_HOSTS filter - /* - const res = await LokiAppDotNetAPI.serverRequest(url.toString(), { - srvPubKey: pubKey, - }); - */ + // get around the FILESERVER_HOSTS filter by not using serverRequest const res = await LokiAppDotNetAPI.sendViaOnion( pubKey, url, @@ -48,19 +43,15 @@ const validOpenGroupServer = async serverUrl => { return true; } // otherwise fall back - } else if (result.response.meta.code === 404) { - // doesn't support it - // console.log('loki_public_chat::validOpenGroupServer - no onion routing available'); - // fallback - } else { + } else if (result.response.meta.code !== 404) { // unknown error code log.warn( 'loki_public_chat::validOpenGroupServer - unknown error code', result.response.meta ); - // fallback } } + // doesn't support it, fallback log.info( `loki_public_chat::validOpenGroupServer - directly contacting ${url.toString()}` ); From 51cd3bbe3b99acbcca1754c35c48590ba976c9c4 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 16:54:40 -0700 Subject: [PATCH 10/14] more dead code cleanup --- js/modules/loki_public_chat_api.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/modules/loki_public_chat_api.js b/js/modules/loki_public_chat_api.js index 4b17cc30e..1b04de705 100644 --- a/js/modules/loki_public_chat_api.js +++ b/js/modules/loki_public_chat_api.js @@ -17,8 +17,6 @@ const validOpenGroupServer = async serverUrl => { const result = await window.tokenlessFileServerAdnAPI.serverRequest( `loki/v1/getOpenGroupKey/${url.hostname}` ); - // console.log('loki_public_chat::validOpenGroupServer - result', result); - // console.log('loki_public_chat::validOpenGroupServer - meta', result.response.meta); if (result.response.meta.code === 200) { // supports it const obj = JSON.parse(result.response.data); From 291ae531d95f431a7b5ca4057a2971ff5c9b5971 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 18:05:40 -0700 Subject: [PATCH 11/14] lint --- js/background.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/js/background.js b/js/background.js index af6dba3ae..59a405071 100644 --- a/js/background.js +++ b/js/background.js @@ -286,7 +286,10 @@ // Update zoom window.updateZoomFactor(); - if (window.lokiFeatureFlags.useOnionRequests || window.lokiFeatureFlags.useFileOnionRequests) { + if ( + window.lokiFeatureFlags.useOnionRequests || + window.lokiFeatureFlags.useFileOnionRequests + ) { // Initialize paths for onion requests window.lokiSnodeAPI.buildNewOnionPaths(); } From 06fb96ab07cd8ff4968db8d6fe44e816e9968f32 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 18:05:51 -0700 Subject: [PATCH 12/14] lint --- js/modules/loki_public_chat_api.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/modules/loki_public_chat_api.js b/js/modules/loki_public_chat_api.js index 1b04de705..2bc3bd3b4 100644 --- a/js/modules/loki_public_chat_api.js +++ b/js/modules/loki_public_chat_api.js @@ -64,7 +64,11 @@ const validOpenGroupServer = async serverUrl => { // const txt = await res.text(); } catch (e) { process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'; - log.warn(`loki_public_chat::validOpenGroupServer - failing to create ${serverUrl}`, e.code, e.message); + log.warn( + `loki_public_chat::validOpenGroupServer - failing to create ${serverUrl}`, + e.code, + e.message + ); // bail out if not valid enough return false; } From 048b5558c1c328aa5f60bac7fc0b1f62ed962294 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 18:25:33 -0700 Subject: [PATCH 13/14] lint --- js/modules/loki_snode_api.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/modules/loki_snode_api.js b/js/modules/loki_snode_api.js index 013bce0b5..de0c8bf24 100644 --- a/js/modules/loki_snode_api.js +++ b/js/modules/loki_snode_api.js @@ -465,7 +465,8 @@ class LokiSnodeAPI { 'LokiSnodeAPI::buildNewOnionPaths - Too few nodes to build an onion path! Refreshing pool and retrying' ); await this.refreshRandomPool(); - return this.buildNewOnionPaths(); + await this.buildNewOnionPaths(); + return; } otherNodes = _.shuffle(otherNodes); From 9e4e524807f4895429e3afc29c86c1b8dd58e03c Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Mon, 8 Jun 2020 16:38:19 -0700 Subject: [PATCH 14/14] lint --- js/modules/loki_app_dot_net_api.js | 8 ++--- js/modules/loki_public_chat_api.js | 4 +-- js/modules/loki_snode_api.js | 56 ++++++++---------------------- 3 files changed, 19 insertions(+), 49 deletions(-) diff --git a/js/modules/loki_app_dot_net_api.js b/js/modules/loki_app_dot_net_api.js index 7ff2c011f..d0493a7bc 100644 --- a/js/modules/loki_app_dot_net_api.js +++ b/js/modules/loki_app_dot_net_api.js @@ -169,9 +169,7 @@ const sendViaOnion = async (srvPubKey, url, fetchOptions, options = {}) => { body = JSON.parse(result.body); } catch (e) { log.error( - `loki_app_dot_net:::sendViaOnion #${ - options.requestNumber - } - Cant decode JSON body`, + `loki_app_dot_net:::sendViaOnion #${options.requestNumber} - Cant decode JSON body`, typeof result.body, result.body ); @@ -181,7 +179,9 @@ const sendViaOnion = async (srvPubKey, url, fetchOptions, options = {}) => { // https://chat-dev.lokinet.org/loki/v1/channel/1/deletes?count=200&since_id= // difference in response than all the other calls.... log.info( - `loki_app_dot_net:::sendViaOnion #${options.requestNumber} - got object response ${url.toString()}` + `loki_app_dot_net:::sendViaOnion #${ + options.requestNumber + } - got object response ${url.toString()}` ); } // result.status has the http response code diff --git a/js/modules/loki_public_chat_api.js b/js/modules/loki_public_chat_api.js index 2bc3bd3b4..647588ef2 100644 --- a/js/modules/loki_public_chat_api.js +++ b/js/modules/loki_public_chat_api.js @@ -140,9 +140,7 @@ class LokiPublicChatFactoryAPI extends EventEmitter { } if (window.isDev) { log.info( - `loki_public_chat::findOrCreateServer - set token ${ - thisServer.token - } for ${serverUrl}` + `loki_public_chat::findOrCreateServer - set token ${thisServer.token} for ${serverUrl}` ); } diff --git a/js/modules/loki_snode_api.js b/js/modules/loki_snode_api.js index 6ede5dea6..390825f4f 100644 --- a/js/modules/loki_snode_api.js +++ b/js/modules/loki_snode_api.js @@ -98,9 +98,7 @@ async function tryGetSnodeListFromLokidSeednode( // throw before clearing the lock, so the retries can kick in if (snodes.length === 0) { log.warn( - `loki_snode_api::tryGetSnodeListFromLokidSeednode - ${ - seedNode.url - } did not return any snodes, falling back to IP`, + `loki_snode_api::tryGetSnodeListFromLokidSeednode - ${seedNode.url} did not return any snodes, falling back to IP`, seedNode.ip_url ); // fall back on ip_url @@ -108,9 +106,7 @@ async function tryGetSnodeListFromLokidSeednode( snodes = await getSnodesFromSeedUrl(tryIpUrl); if (snodes.length === 0) { log.warn( - `loki_snode_api::tryGetSnodeListFromLokidSeednode - ${ - seedNode.ip_url - } did not return any snodes` + `loki_snode_api::tryGetSnodeListFromLokidSeednode - ${seedNode.ip_url} did not return any snodes` ); // does this error message need to be exactly this? throw new window.textsecure.SeedNodeError( @@ -120,9 +116,7 @@ async function tryGetSnodeListFromLokidSeednode( } if (snodes.length) { log.info( - `loki_snode_api::tryGetSnodeListFromLokidSeednode - ${ - seedNode.url - } returned ${snodes.length} snodes` + `loki_snode_api::tryGetSnodeListFromLokidSeednode - ${seedNode.url} returned ${snodes.length} snodes` ); } return snodes; @@ -344,9 +338,7 @@ class LokiSnodeAPI { let attemptNumber = 0; while (goodPaths.length < MIN_GUARD_COUNT) { log.error( - `Must have at least 2 good onion paths, actual: ${ - goodPaths.length - }, attempt #${attemptNumber} fetching more...` + `Must have at least 2 good onion paths, actual: ${goodPaths.length}, attempt #${attemptNumber} fetching more...` ); // eslint-disable-next-line no-await-in-loop await this.buildNewOnionPaths(); @@ -444,9 +436,7 @@ class LokiSnodeAPI { if (this.guardNodes.length < edKeys.length) { log.warn( - `LokiSnodeAPI::buildNewOnionPaths - could not find some guard nodes: ${ - this.guardNodes.length - }/${edKeys.length} left` + `LokiSnodeAPI::buildNewOnionPaths - could not find some guard nodes: ${this.guardNodes.length}/${edKeys.length} left` ); } } @@ -535,9 +525,7 @@ class LokiSnodeAPI { await this.refreshRandomPool(); } catch (e) { log.error( - `LokiSnodeAPI::getRandomProxySnodeAddress - error ${e.code} ${ - e.message - }` + `LokiSnodeAPI::getRandomProxySnodeAddress - error ${e.code} ${e.message}` ); throw e; } @@ -581,9 +569,7 @@ class LokiSnodeAPI { } else { // maybe already marked bad... log.debug( - `LokiSnodeAPI::_getVersion - can't find ${node.ip}:${ - node.port - } in randomSnodePool` + `LokiSnodeAPI::_getVersion - can't find ${node.ip}:${node.port} in randomSnodePool` ); } } @@ -598,9 +584,7 @@ class LokiSnodeAPI { const randomNodesLeft = this.getRandomPoolLength(); // clean up these error messages to be a little neater log.warn( - `LokiSnodeAPI::_getVersion - ${node.ip}:${ - node.port - } is offline, removing, leaving ${randomNodesLeft} in the randomPool` + `LokiSnodeAPI::_getVersion - ${node.ip}:${node.port} is offline, removing, leaving ${randomNodesLeft} in the randomPool` ); // if not ECONNREFUSED, it's mostly ECONNRESETs // ENOTFOUND could mean no internet or hiccup @@ -617,9 +601,7 @@ class LokiSnodeAPI { this.markRandomNodeUnreachable(node); const randomNodesLeft = this.getRandomPoolLength(); log.warn( - `LokiSnodeAPI::_getVersion - failing to get version for ${node.ip}:${ - node.port - }, removing, leaving ${randomNodesLeft} in the randomPool` + `LokiSnodeAPI::_getVersion - failing to get version for ${node.ip}:${node.port}, removing, leaving ${randomNodesLeft} in the randomPool` ); } // maybe throw? @@ -677,9 +659,7 @@ class LokiSnodeAPI { return curVal; }, []); log.debug( - `LokiSnodeAPI::_getAllVerionsForRandomSnodePool - ${ - versions.length - } versions retrieved from network!:`, + `LokiSnodeAPI::_getAllVerionsForRandomSnodePool - ${versions.length} versions retrieved from network!:`, versions.join(',') ); } @@ -761,9 +741,7 @@ class LokiSnodeAPI { }); if (!found) { log.warn( - `LokiSnodeAPI::unreachableNode - snode ${unreachableNode.ip}:${ - unreachableNode.port - } has already been marked as bad` + `LokiSnodeAPI::unreachableNode - snode ${unreachableNode.ip}:${unreachableNode.port} has already been marked as bad` ); } try { @@ -807,9 +785,7 @@ class LokiSnodeAPI { node.address ); log.debug( - `LokiSnodeAPI::getSwarmNodesForPubKey - ${j} ${node.ip}:${ - node.port - }` + `LokiSnodeAPI::getSwarmNodesForPubKey - ${j} ${node.ip}:${node.port}` ); swarmNodes[j] = { ...node, @@ -1035,9 +1011,7 @@ class LokiSnodeAPI { ); if (!result) { log.warn( - `LokiSnodeAPI::_getSnodesForPubkey - lokiRpc on ${snode.ip}:${ - snode.port - } returned falsish value`, + `LokiSnodeAPI::_getSnodesForPubkey - lokiRpc on ${snode.ip}:${snode.port} returned falsish value`, result ); return []; @@ -1045,9 +1019,7 @@ class LokiSnodeAPI { if (!result.snodes) { // we hit this when snode gives 500s log.warn( - `LokiSnodeAPI::_getSnodesForPubkey - lokiRpc on ${snode.ip}:${ - snode.port - } returned falsish value for snodes`, + `LokiSnodeAPI::_getSnodesForPubkey - lokiRpc on ${snode.ip}:${snode.port} returned falsish value for snodes`, result ); return [];