add adnOnionRequestCounter for sendViaOnion, use lokiRpcUtils.sendOnionRequestLsrpcDest

pull/1100/head
Ryan Tharp 5 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 sendViaOnion = async (
srvPubKey,
url,
pFetchOptions,
options = {}
) => {
let adnOnionRequestCounter = 0;
const sendViaOnion = async (srvPubKey, url, pFetchOptions, options = {}) => {
if (!srvPubKey) {
log.error(
'loki_app_dot_net:::sendViaOnion - called without a server public key'
@ -49,7 +45,19 @@ const sendViaOnion = async (
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
// safety issue with file server, just safer to have this
if (fetchOptions.headers === undefined) {
fetchOptions.headers = {};
@ -57,16 +65,16 @@ const sendViaOnion = async (
const payloadObj = {
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 (fetchOptions.body === undefined) fetchOptions.body = '';
payloadObj.body = fetchOptions.body; // might need to b64 if binary...
//console.log('body', payloadObj.body)
console.log('loki_app_dot_net:::sendViaOnion - payloadObj', payloadObj)
if (url.search) {
payloadObj.endpoint += `?${url.search}`;
}
// from https://github.com/sindresorhus/is-stream/blob/master/index.js
let fileUpload = false;
if (
payloadObj.body &&
typeof payloadObj.body === 'object' &&
@ -80,116 +88,76 @@ const sendViaOnion = async (
payloadObj.body = {
fileUpload: fData.toString('base64'),
};
fileUpload = true;
}
const pathNodes = await lokiSnodeAPI.getOnionPath();
if (!pathNodes || !pathNodes.length) {
log.warn(
'loki_app_dot_net:::sendViaOnion - failing, no path available'
`loki_app_dot_net:::sendViaOnion #${adnOnionRequestCount} - failing, no path available`
);
return {};
}
//console.log('loki_app_dot_net:::sendViaOnion - ourPubKey', StringView.arrayBufferToHex(srvPubKey).substr(0,32), '...', StringView.arrayBufferToHex(srvPubKey).substr(32))
//console.log('loki_app_dot_net:::sendViaOnion - pathNodes', pathNodes)
// pathNodes = ['']
const guardUrl = `https://${pathNodes[0].ip}:${pathNodes[0].port}/onion_req`;
// first parameter takes an arrayBuffer
const destCtx = await lokiRpcUtils.encryptForPubKey(srvPubKey, payloadObj);
const tPayload = destCtx.ciphertext;
const reqJson = {
ciphertext: dcodeIO.ByteBuffer.wrap(tPayload).toString('base64'),
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
// do the request
let result;
try {
result = await lokiRpcUtils.sendOnionRequestLsrpcDest(
0,
pathNodes,
srvPubKey,
url.host,
payloadObj,
adnOnionRequestCount
);
log.warn(
`loki_app_dot_net:::sendViaOnion - Marking random snode bad, internet address ${
randSnode.ip
}:${
randSnode.port
}. ${randomPoolRemainingCount} snodes remaining in randomPool`
} catch (e) {
log.error(
'loki_app_dot_net:::sendViaOnion - lokiRpcUtils error',
e.code,
e.message
);
// retry (hopefully with new snode)
// FIXME: max number of retries...
return sendViaOnion(srvPubKey, url, fetchOptions, options);
return {};
}
let response = {};
try {
// it's no longer JSON
response = txtResponse;
} catch (e) {
log.warn(
`loki_app_dot_net:::sendViaOnion - Could not parse outer JSON [${txtResponse}]`,
url,
// handle error/retries
if (!result.status) {
log.error(
`loki_app_dot_net:::sendViaOnion #${adnOnionRequestCount} - Retry #${
options.retry
} Couldnt handle onion request, retrying`,
payloadObj
);
// 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
const ivAndCiphertextResponse = dcodeIO.ByteBuffer.wrap(
response,
'base64'
).toArrayBuffer();
const decrypted = await libloki.crypto.DHDecrypt(
symKey,
ivAndCiphertextResponse
);
const textDecoder = new TextDecoder();
const respStr = textDecoder.decode(decrypted);
// replace response
// get the return variables we need
let response = {};
let txtResponse = '';
let body = '';
try {
response = options.textResponse ? respStr : JSON.parse(respStr);
body = JSON.parse(result.body);
} catch (e) {
log.warn(
`loki_app_dot_net:::sendViaOnion - Could not parse inner JSON [${respStr}]`,
url,
log.error(
`loki_app_dot_net:::sendViaOnion #${adnOnionRequestCount} - Cant decode JSON body`,
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 };
};
@ -257,7 +225,11 @@ const sendToProxy = async (
payloadObj.body = false; // free memory
// 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
const symKey = await libsignal.Curve.async.calculateAgreement(
@ -430,8 +402,7 @@ const serverRequest = async (endpoint, options = {}) => {
fetchOptions,
options
));
} else
if (
} else if (
window.lokiFeatureFlags.useSnodeProxy &&
FILESERVER_HOSTS.includes(host)
) {

Loading…
Cancel
Save