From bb963b77f1268b43391ada579421c37554d880e9 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 27 May 2020 16:40:57 -0700 Subject: [PATCH] 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;