tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

fxrui.js (8672B)


      1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /* import-globals-from common.js */
      7 /* import-globals-from permissions.js */
      8 
      9 // Configuration vars
     10 let homeURL = "https://webxr.today/";
     11 // Bug 1586294 - Localize the privacy policy URL (Services.urlFormatter?)
     12 let privacyPolicyURL = "https://www.mozilla.org/en-US/privacy/firefox/";
     13 let reportIssueURL = "https://mzl.la/fxr";
     14 let licenseURL =
     15  "https://mixedreality.mozilla.org/FirefoxRealityPC/license.html";
     16 
     17 // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/browser
     18 let browser = null;
     19 // Keep track of the current Permissions request to only allow one outstanding
     20 // request/prompt at a time.
     21 let currentPermissionRequest = null;
     22 // And, keep a queue of pending Permissions requests to resolve when the
     23 // current request finishes
     24 let pendingPermissionRequests = [];
     25 // The following variable map to UI elements whose behavior changes depending
     26 // on some state from the browser control
     27 let urlInput = null;
     28 let secureIcon = null;
     29 let backButton = null;
     30 let forwardButton = null;
     31 let refreshButton = null;
     32 let stopButton = null;
     33 
     34 const { PrivateBrowsingUtils } = ChromeUtils.importESModule(
     35  "resource://gre/modules/PrivateBrowsingUtils.sys.mjs"
     36 );
     37 const { AppConstants } = ChromeUtils.importESModule(
     38  "resource://gre/modules/AppConstants.sys.mjs"
     39 );
     40 const { XPCOMUtils } = ChromeUtils.importESModule(
     41  "resource://gre/modules/XPCOMUtils.sys.mjs"
     42 );
     43 
     44 // Note: FxR UI uses a fork of browser-fullScreenAndPointerLock.js which removes
     45 // the dependencies on browser.js.
     46 // Bug 1587946 - Rationalize the fork of browser-fullScreenAndPointerLock.js
     47 XPCOMUtils.defineLazyScriptGetter(
     48  this,
     49  "FullScreen",
     50  "chrome://fxr/content/fxr-fullScreen.js"
     51 );
     52 ChromeUtils.defineLazyGetter(this, "gSystemPrincipal", () =>
     53  Services.scriptSecurityManager.getSystemPrincipal()
     54 );
     55 
     56 window.addEventListener(
     57  "DOMContentLoaded",
     58  () => {
     59    urlInput = document.getElementById("eUrlInput");
     60    secureIcon = document.getElementById("eUrlSecure");
     61    backButton = document.getElementById("eBack");
     62    forwardButton = document.getElementById("eForward");
     63    refreshButton = document.getElementById("eRefresh");
     64    stopButton = document.getElementById("eStop");
     65 
     66    setupBrowser();
     67    setupNavButtons();
     68    setupUrlBar();
     69  },
     70  { once: true }
     71 );
     72 
     73 // Create XUL browser object
     74 function setupBrowser() {
     75  // Note: createXULElement is undefined when this page is not loaded
     76  // via chrome protocol
     77  if (document.createXULElement) {
     78    browser = document.createXULElement("browser");
     79    browser.setAttribute("type", "content");
     80    browser.setAttribute("remote", "true");
     81    browser.classList.add("browser_instance");
     82    document.getElementById("eBrowserContainer").appendChild(browser);
     83 
     84    browser.loadUrlWithSystemPrincipal = function (url) {
     85      this.loadURI(url, { triggeringPrincipal: gSystemPrincipal });
     86    };
     87 
     88    // Expose this function for Permissions to be used on this browser element
     89    // in other parts of the frontend
     90    browser.fxrPermissionPrompt = permissionPrompt;
     91 
     92    urlInput.value = homeURL;
     93    browser.loadUrlWithSystemPrincipal(homeURL);
     94 
     95    browser.addProgressListener(
     96      {
     97        QueryInterface: ChromeUtils.generateQI([
     98          "nsIWebProgressListener",
     99          "nsISupportsWeakReference",
    100        ]),
    101        onLocationChange() {
    102          // When URL changes, update the URL in the URL bar and update
    103          // whether the back/forward buttons are enabled.
    104          urlInput.value = browser.currentURI.spec;
    105 
    106          backButton.disabled = !browser.canGoBack;
    107          forwardButton.disabled = !browser.canGoForward;
    108        },
    109        onStateChange(aWebProgress, aRequest, aStateFlags) {
    110          if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
    111            // Network requests are complete. Disable (hide) the stop button
    112            // and enable (show) the refresh button
    113            refreshButton.disabled = false;
    114            stopButton.disabled = true;
    115          } else {
    116            // Network requests are outstanding. Disable (hide) the refresh
    117            // button and enable (show) the stop button
    118            refreshButton.disabled = true;
    119            stopButton.disabled = false;
    120          }
    121        },
    122        onSecurityChange(aWebProgress, aRequest, aState) {
    123          // Update the Secure Icon when the security status of the
    124          // content changes
    125          if (aState & Ci.nsIWebProgressListener.STATE_IS_SECURE) {
    126            secureIcon.style.visibility = "visible";
    127          } else {
    128            secureIcon.style.visibility = "hidden";
    129          }
    130        },
    131      },
    132      Ci.nsIWebProgress.NOTIFY_LOCATION |
    133        Ci.nsIWebProgress.NOTIFY_SECURITY |
    134        Ci.nsIWebProgress.NOTIFY_STATE_REQUEST
    135    );
    136 
    137    FullScreen.init();
    138 
    139    // Send this notification to start and allow background scripts for
    140    // WebExtensions, since this FxR UI doesn't participate in typical
    141    // startup activities
    142    Services.obs.notifyObservers(window, "extensions-late-startup");
    143  }
    144 }
    145 
    146 function setupNavButtons() {
    147  let aryNavButtons = [
    148    "eBack",
    149    "eForward",
    150    "eRefresh",
    151    "eStop",
    152    "eHome",
    153    "ePrefs",
    154  ];
    155 
    156  function navButtonHandler() {
    157    if (!this.disabled) {
    158      switch (this.id) {
    159        case "eBack":
    160          browser.goBack();
    161          break;
    162 
    163        case "eForward":
    164          browser.goForward();
    165          break;
    166 
    167        case "eRefresh":
    168          browser.reload();
    169          break;
    170 
    171        case "eStop":
    172          browser.stop();
    173          break;
    174 
    175        case "eHome":
    176          browser.loadUrlWithSystemPrincipal(homeURL);
    177          break;
    178 
    179        case "ePrefs":
    180          openSettings();
    181          break;
    182      }
    183    }
    184  }
    185 
    186  for (let btnName of aryNavButtons) {
    187    let elem = document.getElementById(btnName);
    188    elem.addEventListener("click", navButtonHandler);
    189  }
    190 }
    191 
    192 function setupUrlBar() {
    193  // Navigate to new value when the user presses "Enter"
    194  urlInput.addEventListener("keypress", async function (e) {
    195    if (e.key == "Enter") {
    196      // Use the URL Fixup Service in case the user wants to search instead
    197      // of directly navigating to a location.
    198      await Services.search.init();
    199 
    200      let valueToFixUp = urlInput.value;
    201      let flags =
    202        Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
    203        Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
    204      if (PrivateBrowsingUtils.isWindowPrivate(window)) {
    205        flags |= Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
    206      }
    207      let { preferredURI } = Services.uriFixup.getFixupURIInfo(
    208        valueToFixUp,
    209        flags
    210      );
    211 
    212      browser.loadUrlWithSystemPrincipal(preferredURI.spec);
    213      browser.focus();
    214    }
    215  });
    216 
    217  // Upon focus, highlight the whole URL
    218  urlInput.addEventListener("focus", function () {
    219    urlInput.select();
    220  });
    221 }
    222 
    223 //
    224 // Code to manage Settings UI
    225 //
    226 
    227 function openSettings() {
    228  let browserSettingsUI = document.createXULElement("browser");
    229  browserSettingsUI.setAttribute("type", "chrome");
    230  browserSettingsUI.classList.add("browser_settings");
    231 
    232  showModalContainer(browserSettingsUI);
    233 
    234  browserSettingsUI.loadURI("chrome://fxr/content/prefs.html", {
    235    triggeringPrincipal: gSystemPrincipal,
    236  });
    237 }
    238 
    239 function closeSettings() {
    240  clearModalContainer();
    241 }
    242 
    243 function showPrivacyPolicy() {
    244  closeSettings();
    245  browser.loadUrlWithSystemPrincipal(privacyPolicyURL);
    246 }
    247 
    248 function showLicenseInfo() {
    249  closeSettings();
    250  browser.loadUrlWithSystemPrincipal(licenseURL);
    251 }
    252 
    253 function showReportIssue() {
    254  closeSettings();
    255  browser.loadUrlWithSystemPrincipal(reportIssueURL);
    256 }
    257 
    258 //
    259 // Code to manage Permissions UI
    260 //
    261 
    262 function permissionPrompt(aRequest) {
    263  let newPrompt;
    264  if (aRequest instanceof Ci.nsIContentPermissionRequest) {
    265    newPrompt = new FxrContentPrompt(aRequest, this, finishPrompt);
    266  } else {
    267    newPrompt = new FxrWebRTCPrompt(aRequest, this, finishPrompt);
    268  }
    269 
    270  if (currentPermissionRequest) {
    271    // There is already an outstanding request running. Cache this new request
    272    // to be prompted later
    273    pendingPermissionRequests.push(newPrompt);
    274  } else {
    275    currentPermissionRequest = newPrompt;
    276    currentPermissionRequest.showPrompt();
    277  }
    278 }
    279 
    280 function finishPrompt() {
    281  if (pendingPermissionRequests.length) {
    282    // Prompt the next request
    283    currentPermissionRequest = pendingPermissionRequests.shift();
    284    currentPermissionRequest.showPrompt();
    285  } else {
    286    currentPermissionRequest = null;
    287  }
    288 }