richard pushed to branch tor-browser-115.4.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
-
f83bd860
by Henry Wilkes at 2023-11-06T23:18:21+00:00
-
f0ddec98
by Henry Wilkes at 2023-11-06T23:18:28+00:00
4 changed files:
- browser/components/torconnect/TorConnectChild.sys.mjs
- browser/components/torconnect/TorConnectParent.sys.mjs
- browser/components/torconnect/content/aboutTorConnect.js
- browser/modules/TorConnect.sys.mjs
Changes:
... | ... | @@ -2,4 +2,78 @@ |
2 | 2 | |
3 | 3 | import { RemotePageChild } from "resource://gre/actors/RemotePageChild.sys.mjs";
|
4 | 4 | |
5 | -export class TorConnectChild extends RemotePageChild {} |
|
5 | +export class TorConnectChild extends RemotePageChild {
|
|
6 | + /**
|
|
7 | + * Whether we have redirected the page (after bootstrapping) or not.
|
|
8 | + *
|
|
9 | + * @type {boolean}
|
|
10 | + */
|
|
11 | + #redirected = false;
|
|
12 | + |
|
13 | + /**
|
|
14 | + * If bootstrapping is complete, or TorConnect is disabled, we redirect the
|
|
15 | + * page.
|
|
16 | + */
|
|
17 | + async #maybeRedirect() {
|
|
18 | + if (await this.sendQuery("torconnect:should-show")) {
|
|
19 | + // Enabled and not yet bootstrapped.
|
|
20 | + return;
|
|
21 | + }
|
|
22 | + if (this.#redirected) {
|
|
23 | + return;
|
|
24 | + }
|
|
25 | + this.#redirected = true;
|
|
26 | + |
|
27 | + const redirect = new URLSearchParams(
|
|
28 | + new URL(this.contentWindow.document.location.href).search
|
|
29 | + ).get("redirect");
|
|
30 | + |
|
31 | + // Fallback in error cases:
|
|
32 | + let replaceURI = "about:tor";
|
|
33 | + try {
|
|
34 | + const url = new URL(
|
|
35 | + redirect
|
|
36 | + ? decodeURIComponent(redirect)
|
|
37 | + : // NOTE: We expect no redirect when address is entered manually, or
|
|
38 | + // about:torconnect is opened from preferences or urlbar.
|
|
39 | + // Go to the home page.
|
|
40 | + await this.sendQuery("torconnect:home-page")
|
|
41 | + );
|
|
42 | + // Do not allow _javascript_ URI. See tor-browser#41766
|
|
43 | + if (
|
|
44 | + ["about:", "file:", "https:", "http:"].includes(url.protocol) ||
|
|
45 | + // Allow blank page. See tor-browser#42184.
|
|
46 | + // Blank page's are given as a chrome URL rather than "about:blank".
|
|
47 | + url.href === "chrome://browser/content/blanktab.html"
|
|
48 | + ) {
|
|
49 | + replaceURI = url.href;
|
|
50 | + } else {
|
|
51 | + console.error(`Scheme is not allowed "${redirect}"`);
|
|
52 | + }
|
|
53 | + } catch {
|
|
54 | + console.error(`Invalid redirect URL "${redirect}"`);
|
|
55 | + }
|
|
56 | + |
|
57 | + // Replace the destination to prevent "about:torconnect" entering the
|
|
58 | + // history.
|
|
59 | + // NOTE: This is done here, in the window actor, rather than in content
|
|
60 | + // because we have the privilege to redirect to a "chrome:" uri here (for
|
|
61 | + // when the HomePage is set to be blank).
|
|
62 | + this.contentWindow.location.replace(replaceURI);
|
|
63 | + }
|
|
64 | + |
|
65 | + actorCreated() {
|
|
66 | + super.actorCreated();
|
|
67 | + // about:torconnect could need to be immediately redirected. E.g. if it is
|
|
68 | + // reached after bootstrapping.
|
|
69 | + this.#maybeRedirect();
|
|
70 | + }
|
|
71 | + |
|
72 | + receiveMessage(message) {
|
|
73 | + super.receiveMessage(message);
|
|
74 | + |
|
75 | + if (message.name === "torconnect:state-change") {
|
|
76 | + this.#maybeRedirect();
|
|
77 | + }
|
|
78 | + }
|
|
79 | +} |
1 | 1 | // Copyright (c) 2021, The Tor Project, Inc.
|
2 | 2 | |
3 | +import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
|
4 | + |
|
3 | 5 | const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
|
4 | 6 | import {
|
5 | 7 | InternetStatus,
|
... | ... | @@ -15,6 +17,12 @@ import { |
15 | 17 | |
16 | 18 | const BroadcastTopic = "about-torconnect:broadcast";
|
17 | 19 | |
20 | +const lazy = {};
|
|
21 | + |
|
22 | +XPCOMUtils.defineLazyModuleGetters(lazy, {
|
|
23 | + HomePage: "resource:///modules/HomePage.jsm",
|
|
24 | +});
|
|
25 | + |
|
18 | 26 | /*
|
19 | 27 | This object is basically a marshalling interface between the TorConnect module
|
20 | 28 | and a particular about:torconnect page
|
... | ... | @@ -167,6 +175,11 @@ export class TorConnectParent extends JSWindowActorParent { |
167 | 175 | |
168 | 176 | async receiveMessage(message) {
|
169 | 177 | switch (message.name) {
|
178 | + case "torconnect:should-show":
|
|
179 | + return Promise.resolve(TorConnect.shouldShowTorConnect);
|
|
180 | + case "torconnect:home-page":
|
|
181 | + // If there are multiple home pages, just load the first one.
|
|
182 | + return Promise.resolve(TorConnect.fixupURIs(lazy.HomePage.get())[0]);
|
|
170 | 183 | case "torconnect:set-quickstart":
|
171 | 184 | TorSettings.quickstart.enabled = message.data;
|
172 | 185 | TorSettings.saveToPrefs().applySettings();
|
... | ... | @@ -136,10 +136,6 @@ class AboutTorConnect { |
136 | 136 | tryBridgeButton: document.querySelector(this.selectors.buttons.tryBridge),
|
137 | 137 | });
|
138 | 138 | |
139 | - // a redirect url can be passed as a query parameter for the page to
|
|
140 | - // forward us to once bootstrap completes (otherwise the window will just close)
|
|
141 | - redirect = null;
|
|
142 | - |
|
143 | 139 | uiState = {
|
144 | 140 | currentState: UIStates.ConnectToTor,
|
145 | 141 | allowAutomaticLocation: true,
|
... | ... | @@ -425,11 +421,6 @@ class AboutTorConnect { |
425 | 421 | this.setLongText(TorStrings.settings.torPreferencesDescription);
|
426 | 422 | this.setProgress("", showProgressbar, 100);
|
427 | 423 | this.hideButtons();
|
428 | - |
|
429 | - // redirects page to the requested redirect url, removes about:torconnect
|
|
430 | - // from the page stack, so users cannot accidentally go 'back' to the
|
|
431 | - // now unresponsive page
|
|
432 | - window.location.replace(this.redirect);
|
|
433 | 424 | }
|
434 | 425 | |
435 | 426 | update_Disabled(state) {
|
... | ... | @@ -822,23 +813,6 @@ class AboutTorConnect { |
822 | 813 | }
|
823 | 814 | |
824 | 815 | async init() {
|
825 | - // if the user gets here manually or via the button in the urlbar
|
|
826 | - // then we will redirect to about:tor
|
|
827 | - this.redirect = "about:tor";
|
|
828 | - |
|
829 | - // see if a user has a final destination after bootstrapping
|
|
830 | - let params = new URLSearchParams(new URL(document.location.href).search);
|
|
831 | - if (params.has("redirect")) {
|
|
832 | - try {
|
|
833 | - const redirect = new URL(decodeURIComponent(params.get("redirect")));
|
|
834 | - if (/^(?:https?|about):$/.test(redirect.protocol)) {
|
|
835 | - this.redirect = redirect.href;
|
|
836 | - }
|
|
837 | - } catch (e) {
|
|
838 | - console.error(e, `Invalid redirect URL "${params.get("redirect")}"!`);
|
|
839 | - }
|
|
840 | - }
|
|
841 | - |
|
842 | 816 | let args = await RPMSendQuery("torconnect:get-init-args");
|
843 | 817 | |
844 | 818 | // various constants
|
... | ... | @@ -1156,67 +1156,54 @@ export const TorConnect = (() => { |
1156 | 1156 | return `about:torconnect?redirect=${encodeURIComponent(url)}`;
|
1157 | 1157 | },
|
1158 | 1158 | |
1159 | + /**
|
|
1160 | + * Convert the given object into a list of valid URIs.
|
|
1161 | + *
|
|
1162 | + * The object is either from the user's homepage preference (which may
|
|
1163 | + * contain multiple domains separated by "|") or uris passed to the browser
|
|
1164 | + * via command-line.
|
|
1165 | + *
|
|
1166 | + * @param {string|string[]} uriVariant - The string to extract uris from.
|
|
1167 | + *
|
|
1168 | + * @return {string[]} - The array of uris found.
|
|
1169 | + */
|
|
1170 | + fixupURIs(uriVariant) {
|
|
1171 | + let uriArray;
|
|
1172 | + if (typeof uriVariant === "string") {
|
|
1173 | + uriArray = uriVariant.split("|");
|
|
1174 | + } else if (
|
|
1175 | + Array.isArray(uriVariant) &&
|
|
1176 | + uriVariant.every(entry => typeof entry === "string")
|
|
1177 | + ) {
|
|
1178 | + uriArray = uriVariant;
|
|
1179 | + } else {
|
|
1180 | + // about:tor as safe fallback
|
|
1181 | + console.error(
|
|
1182 | + `TorConnect: received unknown variant '${JSON.stringify(uriVariant)}'`
|
|
1183 | + );
|
|
1184 | + uriArray = ["about:tor"];
|
|
1185 | + }
|
|
1186 | + |
|
1187 | + // Attempt to convert user-supplied string to a uri, fallback to
|
|
1188 | + // about:tor if cannot convert to valid uri object
|
|
1189 | + return uriArray.map(
|
|
1190 | + uriString =>
|
|
1191 | + Services.uriFixup.getFixupURIInfo(
|
|
1192 | + uriString,
|
|
1193 | + Ci.nsIURIFixup.FIXUP_FLAG_NONE
|
|
1194 | + ).preferredURI?.spec ?? "about:tor"
|
|
1195 | + );
|
|
1196 | + },
|
|
1197 | + |
|
1159 | 1198 | // called from browser.js on browser startup, passed in either the user's homepage(s)
|
1160 | 1199 | // or uris passed via command-line; we want to replace them with about:torconnect uris
|
1161 | 1200 | // which redirect after bootstrapping
|
1162 | 1201 | getURIsToLoad(uriVariant) {
|
1163 | - // convert the object we get from browser.js
|
|
1164 | - let uriStrings = (v => {
|
|
1165 | - // an interop array
|
|
1166 | - if (v instanceof Ci.nsIArray) {
|
|
1167 | - // Transform the nsIArray of nsISupportsString's into a JS Array of
|
|
1168 | - // JS strings.
|
|
1169 | - return Array.from(
|
|
1170 | - v.enumerate(Ci.nsISupportsString),
|
|
1171 | - supportStr => supportStr.data
|
|
1172 | - );
|
|
1173 | - // an interop string
|
|
1174 | - } else if (v instanceof Ci.nsISupportsString) {
|
|
1175 | - return [v.data];
|
|
1176 | - // a js string
|
|
1177 | - } else if (typeof v === "string") {
|
|
1178 | - return v.split("|");
|
|
1179 | - // a js array of js strings
|
|
1180 | - } else if (
|
|
1181 | - Array.isArray(v) &&
|
|
1182 | - v.reduce((allStrings, entry) => {
|
|
1183 | - return allStrings && typeof entry === "string";
|
|
1184 | - }, true)
|
|
1185 | - ) {
|
|
1186 | - return v;
|
|
1187 | - }
|
|
1188 | - // about:tor as safe fallback
|
|
1189 | - console.log(
|
|
1190 | - `TorConnect: getURIsToLoad() received unknown variant '${JSON.stringify(
|
|
1191 | - v
|
|
1192 | - )}'`
|
|
1193 | - );
|
|
1194 | - return ["about:tor"];
|
|
1195 | - })(uriVariant);
|
|
1196 | - |
|
1197 | - // will attempt to convert user-supplied string to a uri, fallback to about:tor if cannot convert
|
|
1198 | - // to valid uri object
|
|
1199 | - let uriStringToUri = uriString => {
|
|
1200 | - const fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_NONE;
|
|
1201 | - let uri = Services.uriFixup.getFixupURIInfo(
|
|
1202 | - uriString,
|
|
1203 | - fixupFlags
|
|
1204 | - ).preferredURI;
|
|
1205 | - return uri ? uri : Services.io.newURI("about:tor");
|
|
1206 | - };
|
|
1207 | - let uris = uriStrings.map(uriStringToUri);
|
|
1208 | - |
|
1209 | - // assume we have a valid uri and generate an about:torconnect redirect uri
|
|
1210 | - let redirectUrls = uris.map(uri => this.getRedirectURL(uri.spec));
|
|
1211 | - |
|
1202 | + const uris = this.fixupURIs(uriVariant);
|
|
1212 | 1203 | console.log(
|
1213 | - `TorConnect: Will load after bootstrap => [${uris
|
|
1214 | - .map(uri => {
|
|
1215 | - return uri.spec;
|
|
1216 | - })
|
|
1217 | - .join(", ")}]`
|
|
1204 | + `TorConnect: Will load after bootstrap => [${uris.join(", ")}]`
|
|
1218 | 1205 | );
|
1219 | - return redirectUrls;
|
|
1206 | + return uris.map(uri => this.getRedirectURL(uri));
|
|
1220 | 1207 | },
|
1221 | 1208 | };
|
1222 | 1209 | return retval;
|