add adnOnionRequestCounter for sendViaOnion, use lokiRpcUtils.sendOnionRequestLsrpcDest

pull/1100/head
Ryan Tharp 6 years ago
parent 2a889f5d99
commit d4011aaf6d

@ -36,12 +36,8 @@ const snodeHttpsAgent = new https.Agent({
const timeoutDelay = ms => new Promise(resolve => setTimeout(resolve, ms)); const timeoutDelay = ms => new Promise(resolve => setTimeout(resolve, ms));
const sendViaOnion = async ( let adnOnionRequestCounter = 0;
srvPubKey, const sendViaOnion = async (srvPubKey, url, pFetchOptions, options = {}) => {
url,
pFetchOptions,
options = {}
) => {
if (!srvPubKey) { if (!srvPubKey) {
log.error( log.error(
'loki_app_dot_net:::sendViaOnion - called without a server public key' 'loki_app_dot_net:::sendViaOnion - called without a server public key'
@ -49,7 +45,19 @@ const sendViaOnion = async (
return {}; return {};
} }
// set retry count
let adnOnionRequestCount;
if (options.retry === undefined) {
// eslint-disable-next-line no-param-reassign
options.retry = 0;
adnOnionRequestCounter += 1; // increment counter
adnOnionRequestCount = 0 + adnOnionRequestCounter; // copy value
} else {
adnOnionRequestCount = options.counter;
}
const fetchOptions = pFetchOptions; // make lint happy const fetchOptions = pFetchOptions; // make lint happy
// safety issue with file server, just safer to have this // safety issue with file server, just safer to have this
if (fetchOptions.headers === undefined) { if (fetchOptions.headers === undefined) {
fetchOptions.headers = {}; fetchOptions.headers = {};
@ -57,16 +65,16 @@ const sendViaOnion = async (
const payloadObj = { const payloadObj = {
method: fetchOptions.method, method: fetchOptions.method,
headers: {...fetchOptions.headers, bob: "kob" }, body: fetchOptions.body,
// no initial /
endpoint: url.pathname.replace(/^\//, ''),
headers: { ...fetchOptions.headers },
}; };
//console.log('payloadObj', payloadObj) if (url.search) {
//if (fetchOptions.body === undefined) fetchOptions.body = ''; payloadObj.endpoint += `?${url.search}`;
payloadObj.body = fetchOptions.body; // might need to b64 if binary... }
//console.log('body', payloadObj.body)
console.log('loki_app_dot_net:::sendViaOnion - payloadObj', payloadObj)
// from https://github.com/sindresorhus/is-stream/blob/master/index.js // from https://github.com/sindresorhus/is-stream/blob/master/index.js
let fileUpload = false;
if ( if (
payloadObj.body && payloadObj.body &&
typeof payloadObj.body === 'object' && typeof payloadObj.body === 'object' &&
@ -80,116 +88,76 @@ const sendViaOnion = async (
payloadObj.body = { payloadObj.body = {
fileUpload: fData.toString('base64'), fileUpload: fData.toString('base64'),
}; };
fileUpload = true;
} }
const pathNodes = await lokiSnodeAPI.getOnionPath(); const pathNodes = await lokiSnodeAPI.getOnionPath();
if (!pathNodes || !pathNodes.length) { if (!pathNodes || !pathNodes.length) {
log.warn( log.warn(
'loki_app_dot_net:::sendViaOnion - failing, no path available' `loki_app_dot_net:::sendViaOnion #${adnOnionRequestCount} - failing, no path available`
); );
return {}; return {};
} }
//console.log('loki_app_dot_net:::sendViaOnion - ourPubKey', StringView.arrayBufferToHex(srvPubKey).substr(0,32), '...', StringView.arrayBufferToHex(srvPubKey).substr(32)) // do the request
//console.log('loki_app_dot_net:::sendViaOnion - pathNodes', pathNodes) let result;
// pathNodes = [''] try {
const guardUrl = `https://${pathNodes[0].ip}:${pathNodes[0].port}/onion_req`; result = await lokiRpcUtils.sendOnionRequestLsrpcDest(
// first parameter takes an arrayBuffer 0,
const destCtx = await lokiRpcUtils.encryptForPubKey(srvPubKey, payloadObj); pathNodes,
srvPubKey,
const tPayload = destCtx.ciphertext; url.host,
const reqJson = { payloadObj,
ciphertext: dcodeIO.ByteBuffer.wrap(tPayload).toString('base64'), adnOnionRequestCount
ephemeral_key: StringView.arrayBufferToHex(destCtx),
};
const reqStr = JSON.stringify(reqJson);
const snPubkey = StringView.hexToArrayBuffer(pathNodes[0].pubkey_x25519);
const guardCtx = await lokiRpcUtils.encryptForPubKey(snPubkey, reqStr);
//const guardCtx = await lokiRpcUtils.encryptForRelay(pathNodes[0], StringView.arrayBufferToHex(srvPubKey), destCtx);
// we don't want a destination so don't need a relay at all
// const guardPayloadObj = await lokiRpcUtils.makeOnionRequest(pathNodes, destCtx, StringView.arrayBufferToHex(srvPubKey));
//const guardCtx = destCtx;
const ciphertextBase64 = dcodeIO.ByteBuffer.wrap(
guardCtx.ciphertext
).toString('base64');
const guardPayloadObj = {
ciphertext: ciphertextBase64,
ephemeral_key: StringView.arrayBufferToHex(guardCtx.ephemeral_key),
host: url.host,
target: '/loki/v1/lsrpc',
};
const firstHopOptions = {
method: 'POST',
body: JSON.stringify(guardPayloadObj),
// we are talking to a snode...
agent: snodeHttpsAgent,
};
const encryptedResult = await nodeFetch(guardUrl, firstHopOptions);
// weird this doesn't need NODE_TLS_REJECT_UNAUTHORIZED = '0'
const result = await lokiRpcUtils.processOnionResponse(0, encryptedResult, destCtx.symmetricKey, true);
console.log('result', result)
let response = {};
let txtResponse = '';
/*
const txtResponse = await result.text();
if (txtResponse.match(/^Service node is not ready: not in any swarm/i)) {
// mark snode bad
const randomPoolRemainingCount = lokiSnodeAPI.markRandomNodeUnreachable(
randSnode
); );
log.warn( } catch (e) {
`loki_app_dot_net:::sendViaOnion - Marking random snode bad, internet address ${ log.error(
randSnode.ip 'loki_app_dot_net:::sendViaOnion - lokiRpcUtils error',
}:${ e.code,
randSnode.port e.message
}. ${randomPoolRemainingCount} snodes remaining in randomPool`
); );
// retry (hopefully with new snode) return {};
// FIXME: max number of retries...
return sendViaOnion(srvPubKey, url, fetchOptions, options);
} }
let response = {}; // handle error/retries
try { if (!result.status) {
// it's no longer JSON log.error(
response = txtResponse; `loki_app_dot_net:::sendViaOnion #${adnOnionRequestCount} - Retry #${
} catch (e) { options.retry
log.warn( } Couldnt handle onion request, retrying`,
`loki_app_dot_net:::sendViaOnion - Could not parse outer JSON [${txtResponse}]`, payloadObj
url,
); );
// eslint-disable-next-line no-param-reassign
options.retry += 1;
// eslint-disable-next-line no-param-reassign
options.counter = adnOnionRequestCount;
return sendViaOnion(srvPubKey, url, pFetchOptions, options);
} }
// convert base64 in response to binary // get the return variables we need
const ivAndCiphertextResponse = dcodeIO.ByteBuffer.wrap( let response = {};
response, let txtResponse = '';
'base64' let body = '';
).toArrayBuffer();
const decrypted = await libloki.crypto.DHDecrypt(
symKey,
ivAndCiphertextResponse
);
const textDecoder = new TextDecoder();
const respStr = textDecoder.decode(decrypted);
// replace response
try { try {
response = options.textResponse ? respStr : JSON.parse(respStr); body = JSON.parse(result.body);
} catch (e) { } catch (e) {
log.warn( log.error(
`loki_app_dot_net:::sendViaOnion - Could not parse inner JSON [${respStr}]`, `loki_app_dot_net:::sendViaOnion #${adnOnionRequestCount} - Cant decode JSON body`,
url, result.body
); );
} }
*/ const code = result.status;
txtResponse = JSON.stringify(body);
response = body;
response.headers = result.headers;
log.debug(
`loki_app_dot_net:::sendViaOnion #${adnOnionRequestCount} - ADN GCM body length`,
txtResponse.length,
'code',
code,
'headers',
response.headers
);
return { result, txtResponse, response }; return { result, txtResponse, response };
}; };
@ -257,7 +225,11 @@ const sendToProxy = async (
payloadObj.body = false; // free memory payloadObj.body = false; // free memory
// make temporary key for this request/response // make temporary key for this request/response
const ephemeralKey = await libsignal.Curve.async.generateKeyPair(); // const ephemeralKey = await libsignal.Curve.generateKeyPair(); // sync
// async maybe preferable to avoid cpu spikes
// tho I think sync might be more apt in certain cases here...
// like sending
const ephemeralKey = await libloki.crypto.generateEphemeralKeyPair();
// mix server pub key with our priv key // mix server pub key with our priv key
const symKey = await libsignal.Curve.async.calculateAgreement( const symKey = await libsignal.Curve.async.calculateAgreement(
@ -430,8 +402,7 @@ const serverRequest = async (endpoint, options = {}) => {
fetchOptions, fetchOptions,
options options
)); ));
} else } else if (
if (
window.lokiFeatureFlags.useSnodeProxy && window.lokiFeatureFlags.useSnodeProxy &&
FILESERVER_HOSTS.includes(host) FILESERVER_HOSTS.includes(host)
) { ) {

Loading…
Cancel
Save