Commit bfb27a37 authored by henry's avatar henry Committed by Richard Pospesel
Browse files

fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser

Bug 42184: Make torconnect redirect compatible with blank home page.
parent 0776eab4
Loading
Loading
Loading
Loading
+75 −1
Original line number Diff line number Diff line
@@ -2,4 +2,78 @@

import { RemotePageChild } from "resource://gre/actors/RemotePageChild.sys.mjs";

export class TorConnectChild extends RemotePageChild {}
export class TorConnectChild extends RemotePageChild {
  /**
   * Whether we have redirected the page (after bootstrapping) or not.
   *
   * @type {boolean}
   */
  #redirected = false;

  /**
   * If bootstrapping is complete, or TorConnect is disabled, we redirect the
   * page.
   */
  async #maybeRedirect() {
    if (await this.sendQuery("torconnect:should-show")) {
      // Enabled and not yet bootstrapped.
      return;
    }
    if (this.#redirected) {
      return;
    }
    this.#redirected = true;

    const redirect = new URLSearchParams(
      new URL(this.contentWindow.document.location.href).search
    ).get("redirect");

    // Fallback in error cases:
    let replaceURI = "about:tor";
    try {
      const url = new URL(
        redirect
          ? decodeURIComponent(redirect)
          : // NOTE: We expect no redirect when address is entered manually, or
            // about:torconnect is opened from preferences or urlbar.
            // Go to the home page.
            await this.sendQuery("torconnect:home-page")
      );
      // Do not allow javascript URI. See tor-browser#41766
      if (
        ["about:", "file:", "https:", "http:"].includes(url.protocol) ||
        // Allow blank page. See tor-browser#42184.
        // Blank page's are given as a chrome URL rather than "about:blank".
        url.href === "chrome://browser/content/blanktab.html"
      ) {
        replaceURI = url.href;
      } else {
        console.error(`Scheme is not allowed "${redirect}"`);
      }
    } catch {
      console.error(`Invalid redirect URL "${redirect}"`);
    }

    // Replace the destination to prevent "about:torconnect" entering the
    // history.
    // NOTE: This is done here, in the window actor, rather than in content
    // because we have the privilege to redirect to a "chrome:" uri here (for
    // when the HomePage is set to be blank).
    this.contentWindow.location.replace(replaceURI);
  }

  actorCreated() {
    super.actorCreated();
    // about:torconnect could need to be immediately redirected. E.g. if it is
    // reached after bootstrapping.
    this.#maybeRedirect();
  }

  receiveMessage(message) {
    super.receiveMessage(message);

    if (message.name === "torconnect:state-change") {
      this.#maybeRedirect();
    }
  }
}
+13 −0
Original line number Diff line number Diff line
// Copyright (c) 2021, The Tor Project, Inc.

import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";

const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
import {
  InternetStatus,
@@ -15,6 +17,12 @@ import {

const BroadcastTopic = "about-torconnect:broadcast";

const lazy = {};

XPCOMUtils.defineLazyModuleGetters(lazy, {
  HomePage: "resource:///modules/HomePage.jsm",
});

/*
This object is basically a marshalling interface between the TorConnect module
and a particular about:torconnect page
@@ -167,6 +175,11 @@ export class TorConnectParent extends JSWindowActorParent {

  async receiveMessage(message) {
    switch (message.name) {
      case "torconnect:should-show":
        return Promise.resolve(TorConnect.shouldShowTorConnect);
      case "torconnect:home-page":
        // If there are multiple home pages, just load the first one.
        return Promise.resolve(TorConnect.fixupURIs(lazy.HomePage.get())[0]);
      case "torconnect:set-quickstart":
        TorSettings.quickstart.enabled = message.data;
        TorSettings.saveToPrefs().applySettings();
+0 −26
Original line number Diff line number Diff line
@@ -136,10 +136,6 @@ class AboutTorConnect {
    tryBridgeButton: document.querySelector(this.selectors.buttons.tryBridge),
  });

  // a redirect url can be passed as a query parameter for the page to
  // forward us to once bootstrap completes (otherwise the window will just close)
  redirect = null;

  uiState = {
    currentState: UIStates.ConnectToTor,
    allowAutomaticLocation: true,
@@ -425,11 +421,6 @@ class AboutTorConnect {
    this.setLongText(TorStrings.settings.torPreferencesDescription);
    this.setProgress("", showProgressbar, 100);
    this.hideButtons();

    // redirects page to the requested redirect url, removes about:torconnect
    // from the page stack, so users cannot accidentally go 'back' to the
    // now unresponsive page
    window.location.replace(this.redirect);
  }

  update_Disabled(state) {
@@ -822,23 +813,6 @@ class AboutTorConnect {
  }

  async init() {
    // if the user gets here manually or via the button in the urlbar
    // then we will redirect to about:tor
    this.redirect = "about:tor";

    // see if a user has a final destination after bootstrapping
    let params = new URLSearchParams(new URL(document.location.href).search);
    if (params.has("redirect")) {
      try {
        const redirect = new URL(decodeURIComponent(params.get("redirect")));
        if (/^(?:https?|about):$/.test(redirect.protocol)) {
          this.redirect = redirect.href;
        }
      } catch (e) {
        console.error(e, `Invalid redirect URL "${params.get("redirect")}"!`);
      }
    }

    let args = await RPMSendQuery("torconnect:get-init-args");

    // various constants