[tbb-commits] [Git][tpo/applications/tor-browser][tor-browser-115.3.0esr-13.0-1] 2 commits: fixup! Bug 40933: Add tor-launcher functionality
richard (@richard)
git at gitlab.torproject.org
Wed Sep 27 19:48:59 UTC 2023
richard pushed to branch tor-browser-115.3.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
14e1b34c by Pier Angelo Vendrame at 2023-09-27T19:39:39+00:00
fixup! Bug 40933: Add tor-launcher functionality
Bug 42131: Check for existing circuits during initialization.
- - - - -
4b7f4df4 by Pier Angelo Vendrame at 2023-09-27T19:39:39+00:00
fixup! Bug 40933: Add tor-launcher functionality
Bug 42132: Poll for circuit information when we did not collect its data
already.
- - - - -
2 changed files:
- toolkit/components/tor-launcher/TorControlPort.sys.mjs
- toolkit/components/tor-launcher/TorProvider.sys.mjs
Changes:
=====================================
toolkit/components/tor-launcher/TorControlPort.sys.mjs
=====================================
@@ -272,6 +272,11 @@ class AsyncSocket {
*
* @typedef {string} NodeFingerprint
*/
+/**
+ * @typedef {object} CircuitInfo
+ * @property {CircuitID} id
+ * @property {NodeFingerprint[]} nodes
+ */
/**
* @typedef {object} Bridge
* @property {string} transport The transport of the bridge, or vanilla if not
@@ -729,12 +734,14 @@ export class TorController {
/**
* Ask Tor a list of circuits.
*
- * @returns {string[]} An array with a string for each line
+ * @returns {CircuitInfo[]} An array with a string for each line
*/
async getCircuits() {
const circuits = await this.#getInfo("circuit-status");
- // TODO: Do more parsing once we move the event parsing to this class!
- return circuits.split(/\r?\n/);
+ return circuits
+ .split(/\r?\n/)
+ .map(this.#parseCircBuilt.bind(this))
+ .filter(circ => circ);
}
// Configuration
@@ -1022,25 +1029,15 @@ export class TorController {
this.#eventHandler.onBootstrapStatus(status);
break;
case "CIRC":
- const builtEvent =
- /^(?<ID>[a-zA-Z0-9]{1,16})\sBUILT\s(?<Path>(,?\$([0-9a-fA-F]{40})(?:~[a-zA-Z0-9]{1,19})?)+)/.exec(
- data.groups.data
- );
+ const maybeCircuit = this.#parseCircBuilt(data.groups.data);
const closedEvent = /^(?<ID>[a-zA-Z0-9]{1,16})\sCLOSED/.exec(
data.groups.data
);
- if (builtEvent) {
- const fp = /\$([0-9a-fA-F]{40})/g;
- const nodes = Array.from(builtEvent.groups.Path.matchAll(fp), g =>
- g[1].toUpperCase()
+ if (maybeCircuit) {
+ this.#eventHandler.onCircuitBuilt(
+ maybeCircuit.id,
+ maybeCircuit.nodes
);
- // In some cases, we might already receive SOCKS credentials in the
- // line. However, this might be a problem with onion services: we get
- // also a 4-hop circuit that we likely do not want to show to the
- // user, especially because it is used only temporarily, and it would
- // need a technical explaination.
- // const credentials = this.#parseCredentials(data.groups.data);
- this.#eventHandler.onCircuitBuilt(builtEvent.groups.ID, nodes);
} else if (closedEvent) {
this.#eventHandler.onCircuitClosed(closedEvent.groups.ID);
}
@@ -1068,7 +1065,7 @@ export class TorController {
}
}
- // Other helpers
+ // Parsers
/**
* Parse a bootstrap status line.
@@ -1099,15 +1096,32 @@ export class TorController {
}
/**
- * Throw an exception when value is not a string.
+ * Parse a CIRC BUILT event or a GETINFO circuit-status.
*
- * @param {any} value The value to check
- * @param {string} name The name of the `value` argument
+ * @param {string} line The line to parse
+ * @returns {CircuitInfo?} The ID and nodes of the circuit, or null if the
+ * parsing failed.
*/
- #expectString(value, name) {
- if (typeof value !== "string" && !(value instanceof String)) {
- throw new Error(`The ${name} argument is expected to be a string.`);
+ #parseCircBuilt(line) {
+ const builtEvent =
+ /^(?<ID>[a-zA-Z0-9]{1,16})\sBUILT\s(?<Path>(,?\$([0-9a-fA-F]{40})(?:~[a-zA-Z0-9]{1,19})?)+)/.exec(
+ line
+ );
+ if (!builtEvent) {
+ return null;
}
+ const fp = /\$([0-9a-fA-F]{40})/g;
+ const nodes = Array.from(builtEvent.groups.Path.matchAll(fp), g =>
+ g[1].toUpperCase()
+ );
+ // In some cases, we might already receive SOCKS credentials in the
+ // line. However, this might be a problem with Onion services: we get
+ // also a 4-hop circuit that we likely do not want to show to the
+ // user, especially because it is used only temporarily, and it would
+ // need a technical explaination.
+ // So we do not try to extract them for now. Otherwise, we could do
+ // const credentials = this.#parseCredentials(line);
+ return { id: builtEvent.groups.ID, nodes };
}
/**
@@ -1146,6 +1160,20 @@ export class TorController {
)
);
}
+
+ // Other helpers
+
+ /**
+ * Throw an exception when value is not a string.
+ *
+ * @param {any} value The value to check
+ * @param {string} name The name of the `value` argument
+ */
+ #expectString(value, name) {
+ if (typeof value !== "string" && !(value instanceof String)) {
+ throw new Error(`The ${name} argument is expected to be a string.`);
+ }
+ }
}
/**
=====================================
toolkit/components/tor-launcher/TorProvider.sys.mjs
=====================================
@@ -137,7 +137,7 @@ export class TorProvider {
* built before the new identity but not yet used. If we cleaned the map, we
* risked of not having the data about it.
*
- * @type {Map<CircuitID, NodeFingerprint[]>}
+ * @type {Map<CircuitID, Promise<NodeFingerprint[]>>}
*/
#circuits = new Map();
/**
@@ -204,6 +204,11 @@ export class TorProvider {
logger.debug(`Notifying ${TorProviderTopics.ProcessIsReady}`);
Services.obs.notifyObservers(null, TorProviderTopics.ProcessIsReady);
+
+ // If we are using an external Tor daemon, we might need to fetch circuits
+ // already, in case streams use them. Do not await because we do not want to
+ // block the intialization on this (it should not fail anyway...).
+ this.#fetchCircuits();
}
/**
@@ -799,6 +804,16 @@ export class TorProvider {
return crypto.getRandomValues(new Uint8Array(kPasswordLen));
}
+ /**
+ * Ask Tor the circuits it already knows to populate our circuit map with the
+ * circuits that were already open before we started listening for events.
+ */
+ async #fetchCircuits() {
+ for (const { id, nodes } of await this.#controller.getCircuits()) {
+ this.onCircuitBuilt(id, nodes);
+ }
+ }
+
// Notification handlers
/**
@@ -983,18 +998,35 @@ export class TorProvider {
* @param {CircuitID} circuitId The ID of the circuit used by the stream
* @param {string} username The SOCKS username
* @param {string} password The SOCKS password
- * @returns
*/
- onStreamSucceeded(streamId, circuitId, username, password) {
+ async onStreamSucceeded(streamId, circuitId, username, password) {
if (!username || !password) {
return;
}
logger.debug("Stream succeeded event", username, password, circuitId);
- const circuit = this.#circuits.get(circuitId);
+ let circuit = this.#circuits.get(circuitId);
if (!circuit) {
- logger.error(
- "Seen a STREAM SUCCEEDED with an unknown circuit. Not notifying observers."
- );
+ circuit = new Promise((resolve, reject) => {
+ this.#controlConnection.getCircuits().then(circuits => {
+ for (const { id, nodes } of circuits) {
+ if (id === circuitId) {
+ resolve(nodes);
+ return;
+ }
+ // Opportunistically collect circuits, since we are iterating them.
+ this.#circuits.set(id, nodes);
+ }
+ logger.error(
+ `Seen a STREAM SUCCEEDED with circuit ${circuitId}, but Tor did not send information about it.`
+ );
+ reject();
+ });
+ });
+ this.#circuits.set(circuitId, circuit);
+ }
+ try {
+ circuit = await circuit;
+ } catch {
return;
}
Services.obs.notifyObservers(
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/c978614edd6577dd449e591aa05a41e850d8c356...4b7f4df4ca05e86ff078310dbf6509c2da02326f
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/c978614edd6577dd449e591aa05a41e850d8c356...4b7f4df4ca05e86ff078310dbf6509c2da02326f
You're receiving this email because of your account on gitlab.torproject.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tbb-commits/attachments/20230927/58d640f3/attachment-0001.htm>
More information about the tbb-commits
mailing list