move onionPath building to outside of index.ts

pull/1624/head
Audric Ackermann 4 years ago
parent c91f866d95
commit 8cb50ebc91
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -353,8 +353,6 @@ window.clipboard = clipboard;
window.seedNodeList = JSON.parse(config.seedNodeList);
const { OnionPaths } = require('./ts/session/onions');
const { locale: localFromEnv } = config;
window.i18n = i18n.setup(localFromEnv, localeMessages);
@ -375,8 +373,6 @@ window.moment.updateLocale(localeSetForMoment, {
},
});
window.OnionPaths = OnionPaths;
window.libsession = require('./ts/session');
window.models = require('./ts/models');

@ -155,7 +155,7 @@ const triggerSyncIfNeeded = async () => {
const doAppStartUp = (dispatch: Dispatch<any>) => {
if (window.lokiFeatureFlags.useOnionRequests || window.lokiFeatureFlags.useFileOnionRequests) {
// Initialize paths for onion requests
void OnionPaths.getInstance().buildNewOnionPaths();
void OnionPaths.buildNewOnionPaths();
}
// init the messageQueue. In the constructor, we add all not send messages

@ -1,300 +1,3 @@
import { getGuardNodes, updateGuardNodes } from '../../../ts/data/data';
import * as SnodePool from '../snode_api/snodePool';
import _ from 'lodash';
import { default as insecureNodeFetch } from 'node-fetch';
import { UserUtils } from '../utils';
import { snodeHttpsAgent } from '../snode_api/onions';
import { allowOnlyOneAtATime } from '../utils/Promise';
import * as OnionPaths from './onionPath';
export type Snode = SnodePool.Snode;
const desiredGuardCount = 3;
const minimumGuardCount = 2;
interface SnodePath {
path: Array<Snode>;
bad: boolean;
}
export class OnionPaths {
private static instance: OnionPaths | null;
private static readonly onionRequestHops = 3;
private onionPaths: Array<SnodePath> = [];
// This array is meant to store nodes will full info,
// so using GuardNode would not be correct (there is
// some naming issue here it seems)
private guardNodes: Array<Snode> = [];
private onionRequestCounter = 0; // Request index for debugging
private constructor() {}
public static getInstance() {
if (OnionPaths.instance) {
return OnionPaths.instance;
}
OnionPaths.instance = new OnionPaths();
return OnionPaths.instance;
}
public async buildNewOnionPaths() {
// this function may be called concurrently make sure we only have one inflight
return allowOnlyOneAtATime('buildNewOnionPaths', async () => {
await this.buildNewOnionPathsWorker();
});
}
public async getOnionPath(toExclude?: { pubkey_ed25519: string }): Promise<Array<Snode>> {
const { log, CONSTANTS } = window;
let goodPaths = this.onionPaths.filter(x => !x.bad);
let attemptNumber = 0;
while (goodPaths.length < minimumGuardCount) {
log.error(
`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
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;
}
// Select a path that doesn't contain `toExclude`
const otherPaths = paths.filter(
path => !_.some(path.path, node => node.pubkey_ed25519 === toExclude.pubkey_ed25519)
);
if (otherPaths.length === 0) {
// This should never happen!
// well it did happen, should we
// await this.buildNewOnionPaths();
// and restart call?
log.error(
'LokiSnodeAPI::getOnionPath - no paths without',
toExclude.pubkey_ed25519,
'path count',
paths.length,
'goodPath count',
goodPaths.length,
'paths',
paths
);
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;
}
public markPathAsBad(path: Array<Snode>) {
// TODO: we might want to remove the nodes from the
// node pool (but we don't know which node on the path
// is causing issues)
this.onionPaths.forEach(p => {
if (_.isEqual(p.path, path)) {
// eslint-disable-next-line no-param-reassign
p.bad = true;
}
});
}
public assignOnionRequestNumber() {
this.onionRequestCounter += 1;
return this.onionRequestCounter;
}
private async testGuardNode(snode: Snode) {
const { log } = window;
log.info('Testing a candidate guard node ', snode);
// Send a post request and make sure it is OK
const endpoint = '/storage_rpc/v1';
const url = `https://${snode.ip}:${snode.port}${endpoint}`;
const ourPK = UserUtils.getOurPubKeyStrFromCache();
const pubKey = window.getStoragePubKey(ourPK); // truncate if testnet
const method = 'get_snodes_for_pubkey';
const params = { pubKey };
const body = {
jsonrpc: '2.0',
id: '0',
method,
params,
};
const fetchOptions = {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
timeout: 10000, // 10s, we want a smaller timeout for testing
agent: snodeHttpsAgent,
};
let response;
try {
// Log this line for testing
// curl -k -X POST -H 'Content-Type: application/json' -d '"+fetchOptions.body.replace(/"/g, "\\'")+"'", url
window.log.info('insecureNodeFetch => plaintext for testGuardNode');
response = await insecureNodeFetch(url, fetchOptions);
} catch (e) {
if (e.type === 'request-timeout') {
log.warn('test timeout for node,', snode);
}
return false;
}
if (!response.ok) {
const tg = await response.text();
log.info('Node failed the guard test:', snode);
}
return response.ok;
}
private async selectGuardNodes(): Promise<Array<Snode>> {
const { log } = window;
// `getRandomSnodePool` is expected to refresh itself on low nodes
const nodePool = await SnodePool.getRandomSnodePool();
if (nodePool.length < desiredGuardCount) {
log.error('Could not select guard nodes. Not enough nodes in the pool: ', nodePool.length);
return [];
}
const shuffled = _.shuffle(nodePool);
let guardNodes: Array<Snode> = [];
// The use of await inside while is intentional:
// we only want to repeat if the await fails
// eslint-disable-next-line-no-await-in-loop
while (guardNodes.length < 3) {
if (shuffled.length < desiredGuardCount) {
log.error('Not enought nodes in the pool');
break;
}
const candidateNodes = shuffled.splice(0, desiredGuardCount);
// Test all three nodes at once
// eslint-disable-next-line no-await-in-loop
const idxOk = await Promise.all(candidateNodes.map(n => this.testGuardNode(n)));
const goodNodes = _.zip(idxOk, candidateNodes)
.filter(x => x[0])
.map(x => x[1]) as Array<Snode>;
guardNodes = _.concat(guardNodes, goodNodes);
}
if (guardNodes.length < desiredGuardCount) {
log.error(`COULD NOT get enough guard nodes, only have: ${guardNodes.length}`);
}
log.info('new guard nodes: ', guardNodes);
const edKeys = guardNodes.map(n => n.pubkey_ed25519);
await updateGuardNodes(edKeys);
return guardNodes;
}
private async buildNewOnionPathsWorker() {
const { log } = window;
log.info('LokiSnodeAPI::buildNewOnionPaths - building new onion paths');
const allNodes = await SnodePool.getRandomSnodePool();
if (this.guardNodes.length === 0) {
// Not cached, load from DB
const nodes = await getGuardNodes();
if (nodes.length === 0) {
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);
this.guardNodes = allNodes.filter(x => edKeys.indexOf(x.pubkey_ed25519) !== -1);
if (this.guardNodes.length < edKeys.length) {
log.warn(
`LokiSnodeAPI::buildNewOnionPaths - could not find some guard nodes: ${this.guardNodes.length}/${edKeys.length} left`
);
}
}
// If guard nodes is still empty (the old nodes are now invalid), select new ones:
if (this.guardNodes.length < minimumGuardCount) {
// TODO: don't throw away potentially good guard nodes
this.guardNodes = await this.selectGuardNodes();
}
}
// TODO: select one guard node and 2 other nodes randomly
let otherNodes = _.difference(allNodes, this.guardNodes);
if (otherNodes.length < 2) {
log.warn(
'LokiSnodeAPI::buildNewOnionPaths - Too few nodes to build an onion path! Refreshing pool and retrying'
);
await SnodePool.refreshRandomPool();
await this.buildNewOnionPaths();
return;
}
otherNodes = _.shuffle(otherNodes);
const guards = _.shuffle(this.guardNodes);
// Create path for every guard node:
const nodesNeededPerPaths = OnionPaths.onionRequestHops - 1;
// Each path needs X (nodesNeededPerPaths) nodes in addition to the guard node:
const maxPath = Math.floor(
Math.min(
guards.length,
nodesNeededPerPaths ? otherNodes.length / nodesNeededPerPaths : otherNodes.length
)
);
// TODO: might want to keep some of the existing paths
this.onionPaths = [];
for (let i = 0; i < maxPath; i += 1) {
const path = [guards[i]];
for (let j = 0; j < nodesNeededPerPaths; j += 1) {
path.push(otherNodes[i * nodesNeededPerPaths + j]);
}
this.onionPaths.push({ path, bad: false });
}
log.info(`Built ${this.onionPaths.length} onion paths`);
}
}
export { OnionPaths };

@ -0,0 +1,287 @@
import { getGuardNodes, updateGuardNodes } from '../../../ts/data/data';
import * as SnodePool from '../snode_api/snodePool';
import _ from 'lodash';
import { default as insecureNodeFetch } from 'node-fetch';
import { UserUtils } from '../utils';
import { snodeHttpsAgent } from '../snode_api/onions';
import { allowOnlyOneAtATime } from '../utils/Promise';
const desiredGuardCount = 3;
const minimumGuardCount = 2;
interface SnodePath {
path: Array<SnodePool.Snode>;
bad: boolean;
}
const onionRequestHops = 3;
let onionPaths: Array<SnodePath> = [];
// This array is meant to store nodes will full info,
// so using GuardNode would not be correct (there is
// some naming issue here it seems)
let guardNodes: Array<SnodePool.Snode> = [];
let onionRequestCounter = 0; // Request index for debugging
export async function buildNewOnionPaths() {
// this function may be called concurrently make sure we only have one inflight
return allowOnlyOneAtATime('buildNewOnionPaths', async () => {
await buildNewOnionPathsWorker();
});
}
export async function getOnionPath(toExclude?: SnodePool.Snode): Promise<Array<SnodePool.Snode>> {
const { log } = window;
let goodPaths = onionPaths.filter(x => !x.bad);
let attemptNumber = 0;
while (goodPaths.length < minimumGuardCount) {
log.error(
`Must have at least 2 good onion paths, actual: ${goodPaths.length}, attempt #${attemptNumber} fetching more...`
);
// eslint-disable-next-line no-await-in-loop
await buildNewOnionPaths();
// should we add a delay? buildNewOnionPaths should act as one
// reload goodPaths now
attemptNumber += 1;
goodPaths = 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;
}
// Select a path that doesn't contain `toExclude`
const otherPaths = paths.filter(
path => !_.some(path.path, node => node.pubkey_ed25519 === toExclude.pubkey_ed25519)
);
if (otherPaths.length === 0) {
// This should never happen!
// well it did happen, should we
// await this.buildNewOnionPaths();
// and restart call?
log.error(
'LokiSnodeAPI::getOnionPath - no paths without',
toExclude.pubkey_ed25519,
'path count',
paths.length,
'goodPath count',
goodPaths.length,
'paths',
paths
);
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;
}
export function markPathAsBad(path: Array<SnodePool.Snode>) {
// TODO: we might want to remove the nodes from the
// node pool (but we don't know which node on the path
// is causing issues)
onionPaths.forEach(p => {
if (_.isEqual(p.path, path)) {
// eslint-disable-next-line no-param-reassign
p.bad = true;
}
});
}
export function assignOnionRequestNumber() {
onionRequestCounter += 1;
return onionRequestCounter;
}
async function testGuardNode(snode: SnodePool.Snode) {
const { log } = window;
log.info('Testing a candidate guard node ', snode);
// Send a post request and make sure it is OK
const endpoint = '/storage_rpc/v1';
const url = `https://${snode.ip}:${snode.port}${endpoint}`;
const ourPK = UserUtils.getOurPubKeyStrFromCache();
const pubKey = window.getStoragePubKey(ourPK); // truncate if testnet
const method = 'get_snodes_for_pubkey';
const params = { pubKey };
const body = {
jsonrpc: '2.0',
id: '0',
method,
params,
};
const fetchOptions = {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
timeout: 10000, // 10s, we want a smaller timeout for testing
agent: snodeHttpsAgent,
};
let response;
try {
// Log this line for testing
// curl -k -X POST -H 'Content-Type: application/json' -d '"+fetchOptions.body.replace(/"/g, "\\'")+"'", url
window.log.info('insecureNodeFetch => plaintext for testGuardNode');
response = await insecureNodeFetch(url, fetchOptions);
} catch (e) {
if (e.type === 'request-timeout') {
log.warn('test timeout for node,', snode);
}
return false;
}
if (!response.ok) {
const tg = await response.text();
log.info('Node failed the guard test:', snode);
}
return response.ok;
}
async function selectGuardNodes(): Promise<Array<SnodePool.Snode>> {
const { log } = window;
// `getRandomSnodePool` is expected to refresh itself on low nodes
const nodePool = await SnodePool.getRandomSnodePool();
if (nodePool.length < desiredGuardCount) {
log.error('Could not select guard nodes. Not enough nodes in the pool: ', nodePool.length);
return [];
}
const shuffled = _.shuffle(nodePool);
let selectedGuardNodes: Array<SnodePool.Snode> = [];
// The use of await inside while is intentional:
// we only want to repeat if the await fails
// eslint-disable-next-line-no-await-in-loop
while (selectedGuardNodes.length < 3) {
if (shuffled.length < desiredGuardCount) {
log.error('Not enought nodes in the pool');
break;
}
const candidateNodes = shuffled.splice(0, desiredGuardCount);
// Test all three nodes at once
// eslint-disable-next-line no-await-in-loop
const idxOk = await Promise.all(candidateNodes.map(testGuardNode));
const goodNodes = _.zip(idxOk, candidateNodes)
.filter(x => x[0])
.map(x => x[1]) as Array<SnodePool.Snode>;
selectedGuardNodes = _.concat(selectedGuardNodes, goodNodes);
}
if (guardNodes.length < desiredGuardCount) {
log.error(`COULD NOT get enough guard nodes, only have: ${guardNodes.length}`);
}
log.info('new guard nodes: ', guardNodes);
const edKeys = guardNodes.map(n => n.pubkey_ed25519);
await updateGuardNodes(edKeys);
return guardNodes;
}
async function buildNewOnionPathsWorker() {
const { log } = window;
log.info('LokiSnodeAPI::buildNewOnionPaths - building new onion paths');
const allNodes = await SnodePool.getRandomSnodePool();
if (guardNodes.length === 0) {
// Not cached, load from DB
const nodes = await getGuardNodes();
if (nodes.length === 0) {
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);
guardNodes = allNodes.filter(x => edKeys.indexOf(x.pubkey_ed25519) !== -1);
if (guardNodes.length < edKeys.length) {
log.warn(
`LokiSnodeAPI::buildNewOnionPaths - could not find some guard nodes: ${guardNodes.length}/${edKeys.length} left`
);
}
}
// If guard nodes is still empty (the old nodes are now invalid), select new ones:
if (guardNodes.length < minimumGuardCount) {
// TODO: don't throw away potentially good guard nodes
guardNodes = await selectGuardNodes();
}
}
// TODO: select one guard node and 2 other nodes randomly
let otherNodes = _.difference(allNodes, guardNodes);
if (otherNodes.length < 2) {
log.warn(
'LokiSnodeAPI::buildNewOnionPaths - Too few nodes to build an onion path! Refreshing pool and retrying'
);
await SnodePool.refreshRandomPool();
await buildNewOnionPaths();
return;
}
otherNodes = _.shuffle(otherNodes);
const guards = _.shuffle(guardNodes);
// Create path for every guard node:
const nodesNeededPerPaths = onionRequestHops - 1;
// Each path needs X (nodesNeededPerPaths) nodes in addition to the guard node:
const maxPath = Math.floor(
Math.min(
guards.length,
nodesNeededPerPaths ? otherNodes.length / nodesNeededPerPaths : otherNodes.length
)
);
// TODO: might want to keep some of the existing paths
onionPaths = [];
for (let i = 0; i < maxPath; i += 1) {
const path = [guards[i]];
for (let j = 0; j < nodesNeededPerPaths; j += 1) {
path.push(otherNodes[i * nodesNeededPerPaths + j]);
}
onionPaths.push({ path, bad: false });
}
log.info(`Built ${onionPaths.length} onion paths`);
}

@ -109,7 +109,7 @@ const buildSendViaOnionPayload = (url: URL, fetchOptions: OnionFetchOptions) =>
export const getOnionPathForSending = async (requestNumber: number) => {
let pathNodes: Array<Snode> = [];
try {
pathNodes = await OnionPaths.getInstance().getOnionPath();
pathNodes = await OnionPaths.getOnionPath();
} catch (e) {
window.log.error(`sendViaOnion #${requestNumber} - getOnionPath Error ${e.code} ${e.message}`);
}
@ -124,7 +124,7 @@ export const getOnionPathForSending = async (requestNumber: number) => {
const initOptionsWithDefaults = (options: OnionFetchBasicOptions) => {
const defaultFetchBasicOptions = {
retry: 0,
requestNumber: OnionPaths.getInstance().assignOnionRequestNumber(),
requestNumber: OnionPaths.assignOnionRequestNumber(),
};
return _.defaults(options, defaultFetchBasicOptions);
};

@ -1,7 +1,6 @@
import _ from 'lodash';
import { Snode } from '../onions';
import { SendParams, storeOnNode } from '../snode_api/serviceNodeAPI';
import { getSwarm } from '../snode_api/snodePool';
import { getSwarm, Snode } from '../snode_api/snodePool';
import { firstTrue } from '../utils/Promise';
const DEFAULT_CONNECTIONS = 3;

@ -6,6 +6,8 @@ import { lokiOnionFetch, snodeHttpsAgent, SnodeResponse } from './onions';
interface FetchOptions {
method: string;
body?: string;
agent?: any;
}
// A small wrapper around node-fetch which deserializes response
@ -18,7 +20,7 @@ async function lokiFetch(
const timeout = 10000;
const method = options.method || 'GET';
const fetchOptions: any = {
const fetchOptions = {
...options,
timeout,
method,
@ -28,7 +30,7 @@ async function lokiFetch(
// Absence of targetNode indicates that we want a direct connection
// (e.g. to connect to a seed node for the first time)
if (window.lokiFeatureFlags.useOnionRequests && targetNode) {
const fetchResult = await lokiOnionFetch(fetchOptions.body, targetNode);
const fetchResult = await lokiOnionFetch(targetNode, fetchOptions.body);
if (!fetchResult) {
return undefined;
}

@ -196,13 +196,24 @@ const processOnionResponse = async (
): Promise<SnodeResponse | RequestError> => {
const { log, libloki } = window;
let content;
try {
content = await response.text();
} catch (e) {
window.log.warn(e);
content = '';
}
// if (response.status !== 200) {
// debugger;
// }
if (abortSignal?.aborted) {
log.warn(`(${reqIdx}) [path] Call aborted`);
return RequestError.ABORTED;
}
// FIXME: 401/500 handling?
// detect SNode is deregisted?
if (response.status === 502) {
log.warn(`(${reqIdx}) [path] Got 502: snode not found`);
@ -229,10 +240,8 @@ const processOnionResponse = async (
}
if (response.status !== 200) {
const rsp = await response.text();
log.warn(
`(${reqIdx}) [path] lokiRpc::processOnionResponse - fetch unhandled error code: ${response.status}: ${rsp}`
`(${reqIdx}) [path] lokiRpc::processingOnionResponse - fetch unhandled error code: ${response.status}: ${content}`
);
// FIXME audric
// this is pretty strong but on the current setup.
@ -241,15 +250,15 @@ const processOnionResponse = async (
return RequestError.BAD_PATH;
}
let ciphertext = await response.text();
let ciphertext = content;
if (!ciphertext) {
log.warn(
`(${reqIdx}) [path] lokiRpc::processOnionResponse - Target node return empty ciphertext`
`(${reqIdx}) [path] lokiRpc::processingOnionResponse - Target node return empty ciphertext`
);
return RequestError.OTHER;
}
if (debug) {
log.debug(`(${reqIdx}) [path] lokiRpc::processOnionResponse - ciphertext`, ciphertext);
log.debug(`(${reqIdx}) [path] lokiRpc::processingOnionResponse - ciphertext`, ciphertext);
}
let plaintext;
@ -266,26 +275,26 @@ const processOnionResponse = async (
if (debug) {
log.debug(
`(${reqIdx}) [path] lokiRpc::processOnionResponse - ciphertextBuffer`,
`(${reqIdx}) [path] lokiRpc::processingOnionResponse - ciphertextBuffer`,
toHex(ciphertextBuffer)
);
}
const plaintextBuffer = await libloki.crypto.DecryptAESGCM(symmetricKey, ciphertextBuffer);
if (debug) {
log.debug('lokiRpc::processOnionResponse - plaintextBuffer', plaintextBuffer.toString());
log.debug('lokiRpc::processingOnionResponse - plaintextBuffer', plaintextBuffer.toString());
}
plaintext = new TextDecoder().decode(plaintextBuffer);
} catch (e) {
log.error(`(${reqIdx}) [path] lokiRpc::processOnionResponse - decode error`, e);
log.error(`(${reqIdx}) [path] lokiRpc::processingOnionResponse - decode error`, e);
log.error(
`(${reqIdx}) [path] lokiRpc::processOnionResponse - symmetricKey`,
`(${reqIdx}) [path] lokiRpc::processingOnionResponse - symmetricKey`,
toHex(symmetricKey)
);
if (ciphertextBuffer) {
log.error(
`(${reqIdx}) [path] lokiRpc::processOnionResponse - ciphertextBuffer`,
`(${reqIdx}) [path] lokiRpc::processingOnionResponse - ciphertextBuffer`,
toHex(ciphertextBuffer)
);
}
@ -293,7 +302,7 @@ const processOnionResponse = async (
}
if (debug) {
log.debug('lokiRpc::processOnionResponse - plaintext', plaintext);
log.debug('lokiRpc::processingOnionResponse - plaintext', plaintext);
}
try {
@ -307,7 +316,7 @@ const processOnionResponse = async (
return jsonRes;
} catch (e) {
log.error(
`(${reqIdx}) [path] lokiRpc::processOnionResponse - parse error outer json ${e.code} ${e.message} json: '${plaintext}'`
`(${reqIdx}) [path] lokiRpc::processingOnionResponse - parse error outer json ${e.code} ${e.message} json: '${plaintext}'`
);
return RequestError.OTHER;
}
@ -430,6 +439,8 @@ const sendOnionRequest = async (
id
);
const guardNode = nodePath[0];
const guardFetchOptions = {
method: 'POST',
body: payload,
@ -438,10 +449,8 @@ const sendOnionRequest = async (
abortSignal,
};
const target = '/onion_req/v2';
const guardUrl = `https://${nodePath[0].ip}:${nodePath[0].port}${target}`;
// no logs for that one as we do need to call insecureNodeFetch to our guardNode
const guardUrl = `https://${guardNode.ip}:${guardNode.port}/onion_req/v2`;
// no logs for that one insecureNodeFetch as we do need to call insecureNodeFetch to our guardNode
// window.log.info('insecureNodeFetch => plaintext for sendOnionRequest');
const response = await insecureNodeFetch(guardUrl, guardFetchOptions);
@ -452,7 +461,7 @@ async function sendOnionRequestSnodeDest(
reqIdx: any,
nodePath: Array<Snode>,
targetNode: Snode,
plaintext: any
plaintext?: string
) {
return sendOnionRequest(
reqIdx,
@ -492,27 +501,30 @@ function getPathString(pathObjArr: Array<any>): string {
return pathObjArr.map(node => `${node.ip}:${node.port}`).join(', ');
}
export async function lokiOnionFetch(body: any, targetNode: Snode): Promise<SnodeResponse | false> {
export async function lokiOnionFetch(
targetNode: Snode,
body?: string
): Promise<SnodeResponse | false> {
const { log } = window;
// Loop until the result is not BAD_PATH
// tslint:disable-next-line no-constant-condition
// tslint:disable no-constant-condition
while (true) {
// Get a path excluding `targetNode`:
// eslint-disable-next-line no-await-in-loop
const path = await OnionPaths.getInstance().getOnionPath(targetNode);
const thisIdx = OnionPaths.getInstance().assignOnionRequestNumber();
// eslint-disable no-await-in-loop
const path = await OnionPaths.getOnionPath(targetNode);
const thisIdx = OnionPaths.assignOnionRequestNumber();
// At this point I only care about BAD_PATH
// eslint-disable-next-line no-await-in-loop
console.warn('lokiOnionFetch with path', path);
path[2].pubkey_ed25519 = '11edd12a6f29011a1beb5b245a06b16548f2796eec4057a6c191700ffa780f5c';
const result = await sendOnionRequestSnodeDest(thisIdx, path, targetNode, body);
if (result === RequestError.BAD_PATH) {
log.error(
`[path] Error on the path: ${getPathString(path)} to ${targetNode.ip}:${targetNode.port}`
);
OnionPaths.getInstance().markPathAsBad(path);
OnionPaths.markPathAsBad(path);
return false;
} else if (result === RequestError.OTHER) {
// could mean, fail to parse results

@ -1,4 +1,4 @@
import { Snode } from '../onions';
import { Snode } from '../snode_api/snodePool';
type SimpleFunction<T> = (arg: T) => void;
type Return<T> = Promise<T> | T;

Loading…
Cancel
Save