diff --git a/js/modules/loki_app_dot_net_api.js b/js/modules/loki_app_dot_net_api.js index 1df3418d3..c08b6a112 100644 --- a/js/modules/loki_app_dot_net_api.js +++ b/js/modules/loki_app_dot_net_api.js @@ -294,12 +294,7 @@ class LokiAppDotNetServerAPI { } } - static async _sendToProxy( - fetchOptions, - endpoint, - method, - { ephemeralKey, symKey, iv } - ) { + async _sendToProxy(fetchOptions, method, headers, endpoint) { const randSnode = await lokiSnodeAPI.getRandomSnodeAddress(); const url = `https://${randSnode.ip}:${randSnode.port}/file_proxy`; @@ -308,7 +303,7 @@ class LokiAppDotNetServerAPI { body: fetchOptions.body, // might need to b64 if binary... endpoint, method, - headers: fetchOptions.headers, + headers, }; // from https://github.com/sindresorhus/is-stream/blob/master/index.js @@ -334,6 +329,18 @@ class LokiAppDotNetServerAPI { ); payloadObj.body = false; // free memory + // make temporary key for this request/response + const ephemeralKey = libsignal.Curve.generateKeyPair(); + + // mix server pub key with our priv key + const symKey = libsignal.Curve.calculateAgreement( + this.pubKey, // server's pubkey + ephemeralKey.privKey // our privkey + ); + + // some randomness + const iv = libsignal.crypto.getRandomBytes(IV_LENGTH); + // encrypt payloadData with symmetric Key using iv const cipherBody = await libsignal.crypto.encrypt(symKey, payloadData, iv); @@ -371,7 +378,25 @@ class LokiAppDotNetServerAPI { 'X-Loki-File-Server-Headers': JSON.stringify(finalRequestHeader), }, }; - return nodeFetch(url, firstHopOptions); + const result = await nodeFetch(url, firstHopOptions); + + const txtResponse = await result.text(); + let response = JSON.parse(txtResponse); + + if (response.meta && response.meta.code === 200) { + const cipherBuffer = dcodeIO.ByteBuffer.wrap( + response.data, + 'base64' + ).toArrayBuffer(); + const decryped = await libsignal.crypto.decrypt(symKey, cipherBuffer, iv); + const textDecoder = new TextDecoder(); + const json = textDecoder.decode(decryped); + // replace response + response = JSON.parse(json); + } else { + log.warn('file server secure_rpc gave an non-200 response'); + } + return { result, txtResponse, response }; } // make a request to the server @@ -389,8 +414,8 @@ class LokiAppDotNetServerAPI { url.search = new URLSearchParams(params); } const fetchOptions = {}; + const headers = {}; try { - const headers = {}; if (forceFreshToken) { await this.getOrRefreshServerToken(true); } @@ -414,81 +439,35 @@ class LokiAppDotNetServerAPI { }; } + let response; let result; - let response = null; - let TxtResponse = ''; - if ( - window.lokiFeatureFlags.useSnodeProxy && - (this.baseServerUrl === 'https://file-dev.lokinet.org' || - this.baseServerUrl === 'https://file.lokinet.org') - ) { - try { - // make temporary key for this request/response - const ephemeralKey = libsignal.Curve.generateKeyPair(); - // mix server pub key with our priv key - const symKey = libsignal.Curve.calculateAgreement( - this.pubKey, // server's pubkey - ephemeralKey.privKey // our privkey - ); - - // some randomness - const iv = libsignal.crypto.getRandomBytes(IV_LENGTH); - - result = await this.constructor._sendToProxy( + let txtResponse; + let mode = 'nodeFetch'; + try { + if ( + window.lokiFeatureFlags.useSnodeProxy && + (this.baseServerUrl === 'https://file-dev.lokinet.org' || + this.baseServerUrl === 'https://file.lokinet.org') + ) { + mode = '_sendToProxy'; + // have to send headers because fetchOptions.headers isn't readable + ({ response, txtResponse, result } = await this._sendToProxy( fetchOptions, - endpoint, method, - { ephemeralKey, symKey, iv } - ); - - TxtResponse = await result.text(); - response = JSON.parse(TxtResponse); - - if (response.meta && response.meta.code === 200) { - try { - const cipherBuffer = dcodeIO.ByteBuffer.wrap( - response.data, - 'base64' - ).toArrayBuffer(); - const decryped = await libsignal.crypto.decrypt( - symKey, - cipherBuffer, - iv - ); - const textDecoder = new TextDecoder(); - const json = textDecoder.decode(decryped); - // replace response - response = JSON.parse(json); - } catch (e) { - // useless with the ephemeralKey and iv - log.warn(`serverRequest useSnodeProxy parse ${e} ${TxtResponse}`); - return { - err: e, - statusCode: result.status, - }; - } - } else { - log.warn('file server secure_rpc gave an non-200 response'); - } - } catch (e) { - log.info('serverRequest _sendToProxy error:', e); - return { - err: e, - }; - } - } else { - try { + headers, + endpoint + )); + } else { result = await nodeFetch(url, fetchOptions || undefined); - TxtResponse = await result.text(); - response = JSON.parse(TxtResponse); - } catch (e) { - log.info('serverRequest nodeFetch error:', JSON.stringify(e)); - return { - err: e, - }; + txtResponse = await result.text(); + response = JSON.parse(txtResponse); } + } catch (e) { + log.info(`serverRequest ${mode} error json: ${txtResponse}`); + return { + err: e, + }; } - // if it's a response style with a meta if (result.status !== 200) { if (!forceFreshToken && (!response.meta || response.meta.code === 401)) { @@ -767,6 +746,7 @@ class LokiAppDotNetServerAPI { contentType: 'application/octet-stream', name: 'content', filename: 'attachment', + knownLength: buffer.byteLength, }); return this.uploadData(formData); @@ -1510,6 +1490,7 @@ class LokiPublicChannelAPI { const primaryPubKey = slavePrimaryMap[slaveKey]; // send out remaining messages for this merged identity + /* eslint-disable no-param-reassign */ if (slavePrimaryMap[slaveKey]) { // rewrite source, profile messageData.source = primaryPubKey; @@ -1520,6 +1501,7 @@ class LokiPublicChannelAPI { messageData.message.profile.avatar = avatar; messageData.message.profileKey = profileKey; } + /* eslint-enable no-param-reassign */ this.chatAPI.emit('publicMessage', { message: messageData, });