| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -416,87 +416,87 @@ class LokiSnodeAPI {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    });
 | 
					 | 
					 | 
					 | 
					    });
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  }
 | 
					 | 
					 | 
					 | 
					  }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // FIXME: need a lock because it is being called multiple times in parallel
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  async buildNewOnionPaths() {
 | 
					 | 
					 | 
					 | 
					  async buildNewOnionPaths() {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // Note: this function may be called concurrently, so
 | 
					 | 
					 | 
					 | 
					    // Note: this function may be called concurrently
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // might consider blocking the other calls
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const _ = window.Lodash;
 | 
					 | 
					 | 
					 | 
					    return primitives.allowOnlyOneAtATime('buildNewOnionPaths', async () => {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					      const _ = window.Lodash;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    log.info('LokiSnodeAPI::buildNewOnionPaths - building new onion paths');
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const allNodes = await this.getRandomSnodePool();
 | 
					 | 
					 | 
					 | 
					      log.info('LokiSnodeAPI::buildNewOnionPaths - building new onion paths');
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    if (this.guardNodes.length === 0) {
 | 
					 | 
					 | 
					 | 
					      const allNodes = await this.getRandomSnodePool();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      // Not cached, load from DB
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      const nodes = await window.libloki.storage.getGuardNodes();
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (nodes.length === 0) {
 | 
					 | 
					 | 
					 | 
					      if (this.guardNodes.length === 0) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        log.warn(
 | 
					 | 
					 | 
					 | 
					        // Not cached, load from DB
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          'LokiSnodeAPI::buildNewOnionPaths - no guard nodes in DB. Will be selecting new guards nodes...'
 | 
					 | 
					 | 
					 | 
					        const nodes = await window.libloki.storage.getGuardNodes();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        );
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      } 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) {
 | 
					 | 
					 | 
					 | 
					        if (nodes.length === 0) {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          log.warn(
 | 
					 | 
					 | 
					 | 
					          log.warn(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            `LokiSnodeAPI::buildNewOnionPaths - could not find some guard nodes: ${
 | 
					 | 
					 | 
					 | 
					            'LokiSnodeAPI::buildNewOnionPaths - no guard nodes in DB. Will be selecting new guards nodes...'
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					              this.guardNodes.length
 | 
					 | 
					 | 
					 | 
					          );
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            }/${edKeys.length} left`
 | 
					 | 
					 | 
					 | 
					        } 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 guard nodes is still empty (the old nodes are now invalid), select new ones:
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (this.guardNodes.length === 0) {
 | 
					 | 
					 | 
					 | 
					        if (this.guardNodes.length === 0) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        this.guardNodes = await this.selectGuardNodes();
 | 
					 | 
					 | 
					 | 
					          this.guardNodes = await this.selectGuardNodes();
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      }
 | 
					 | 
					 | 
					 | 
					      }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    }
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // TODO: select one guard node and 2 other nodes randomly
 | 
					 | 
					 | 
					 | 
					      // TODO: select one guard node and 2 other nodes randomly
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    let otherNodes = _.difference(allNodes, this.guardNodes);
 | 
					 | 
					 | 
					 | 
					      let otherNodes = _.difference(allNodes, this.guardNodes);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    if (otherNodes.length < 2) {
 | 
					 | 
					 | 
					 | 
					      if (otherNodes.length < 2) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      log.warn(
 | 
					 | 
					 | 
					 | 
					        log.warn(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        'LokiSnodeAPI::buildNewOnionPaths - Too few nodes to build an onion path! Refreshing pool and retrying'
 | 
					 | 
					 | 
					 | 
					          'LokiSnodeAPI::buildNewOnionPaths - Too few nodes to build an onion path! Refreshing pool and retrying'
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      );
 | 
					 | 
					 | 
					 | 
					        );
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      await this.refreshRandomPool();
 | 
					 | 
					 | 
					 | 
					        await this.refreshRandomPool();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      await this.buildNewOnionPaths();
 | 
					 | 
					 | 
					 | 
					        await this.buildNewOnionPaths();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      return;
 | 
					 | 
					 | 
					 | 
					        return;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    }
 | 
					 | 
					 | 
					 | 
					      }
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    otherNodes = _.shuffle(otherNodes);
 | 
					 | 
					 | 
					 | 
					      otherNodes = _.shuffle(otherNodes);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const guards = _.shuffle(this.guardNodes);
 | 
					 | 
					 | 
					 | 
					      const guards = _.shuffle(this.guardNodes);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // Create path for every guard node:
 | 
					 | 
					 | 
					 | 
					      // Create path for every guard node:
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const nodesNeededPerPaths = window.lokiFeatureFlags.onionRequestHops - 1;
 | 
					 | 
					 | 
					 | 
					      const nodesNeededPerPaths = window.lokiFeatureFlags.onionRequestHops - 1;
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // Each path needs X (nodesNeededPerPaths) nodes in addition to the guard node:
 | 
					 | 
					 | 
					 | 
					      // Each path needs X (nodesNeededPerPaths) nodes in addition to the guard node:
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const maxPath = Math.floor(
 | 
					 | 
					 | 
					 | 
					      const maxPath = Math.floor(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      Math.min(
 | 
					 | 
					 | 
					 | 
					        Math.min(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        guards.length,
 | 
					 | 
					 | 
					 | 
					          guards.length,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        nodesNeededPerPaths
 | 
					 | 
					 | 
					 | 
					          nodesNeededPerPaths
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          ? otherNodes.length / nodesNeededPerPaths
 | 
					 | 
					 | 
					 | 
					            ? otherNodes.length / nodesNeededPerPaths
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          : otherNodes.length
 | 
					 | 
					 | 
					 | 
					            : otherNodes.length
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      )
 | 
					 | 
					 | 
					 | 
					        )
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    );
 | 
					 | 
					 | 
					 | 
					      );
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // TODO: might want to keep some of the existing paths
 | 
					 | 
					 | 
					 | 
					      // TODO: might want to keep some of the existing paths
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    this.onionPaths = [];
 | 
					 | 
					 | 
					 | 
					      this.onionPaths = [];
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    for (let i = 0; i < maxPath; i += 1) {
 | 
					 | 
					 | 
					 | 
					      for (let i = 0; i < maxPath; i += 1) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      const path = [guards[i]];
 | 
					 | 
					 | 
					 | 
					        const path = [guards[i]];
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      for (let j = 0; j < nodesNeededPerPaths; j += 1) {
 | 
					 | 
					 | 
					 | 
					        for (let j = 0; j < nodesNeededPerPaths; j += 1) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        path.push(otherNodes[i * nodesNeededPerPaths + j]);
 | 
					 | 
					 | 
					 | 
					          path.push(otherNodes[i * nodesNeededPerPaths + j]);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        this.onionPaths.push({ path, bad: false });
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      }
 | 
					 | 
					 | 
					 | 
					      }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      this.onionPaths.push({ path, bad: false });
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    }
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    log.info(`Built ${this.onionPaths.length} onion paths`, this.onionPaths);
 | 
					 | 
					 | 
					 | 
					      log.info(`Built ${this.onionPaths.length} onion paths`, this.onionPaths);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    });
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  }
 | 
					 | 
					 | 
					 | 
					  }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  async getRandomSnodeAddress() {
 | 
					 | 
					 | 
					 | 
					  async getRandomSnodeAddress() {
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
 
 |