tor-browser

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

browser_closeCapPortalTabCanonicalURL.js (7543B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const { HttpServer } = ChromeUtils.importESModule(
      7  "resource://testing-common/httpd.sys.mjs"
      8 );
      9 const LOGIN_LINK = `<html><body><a href="/unlock">login</a></body></html>`;
     10 const LOGIN_URL = "http://localhost:8080/login";
     11 const CANONICAL_SUCCESS_URL = "http://localhost:8080/success";
     12 const CPS = Cc["@mozilla.org/network/captive-portal-service;1"].getService(
     13  Ci.nsICaptivePortalService
     14 );
     15 const META_CANONICAL_CONTENT = `<meta http-equiv=\"refresh\" content=\"0;url=http://support.mozilla.org:8080/sumo\"/>`;
     16 
     17 const cps = Cc["@mozilla.org/network/captive-portal-service;1"].getService(
     18  Ci.nsICaptivePortalService
     19 );
     20 
     21 let server;
     22 let loginPageShown = false;
     23 let showSumo = false;
     24 const SUMO_URL = "https://support.mozilla.org:8080/sumo";
     25 
     26 function redirectHandler(request, response) {
     27  if (showSumo) {
     28    response.setHeader("Content-Type", "text/html");
     29    response.bodyOutputStream.write(
     30      META_CANONICAL_CONTENT,
     31      META_CANONICAL_CONTENT.length
     32    );
     33    return;
     34  }
     35  if (loginPageShown) {
     36    return;
     37  }
     38  response.setStatusLine(request.httpVersion, 302, "captive");
     39  response.setHeader("Content-Type", "text/html");
     40  response.setHeader("Location", LOGIN_URL);
     41 }
     42 
     43 function sumoHandler(request, response) {
     44  response.setHeader("Content-Type", "text/html");
     45  let content = `
     46 <!DOCTYPE html>
     47 <html lang="en">
     48  <head>
     49    <meta charset="utf-8"/>
     50  </head>
     51  <body>
     52    Testing
     53  </body>
     54 </html>
     55 `;
     56  response.bodyOutputStream.write(content, content.length);
     57 }
     58 
     59 function loginHandler(request, response) {
     60  response.setHeader("Content-Type", "text/html");
     61  response.bodyOutputStream.write(LOGIN_LINK, LOGIN_LINK.length);
     62  loginPageShown = true;
     63 }
     64 
     65 function unlockHandler(request, response) {
     66  response.setStatusLine(request.httpVersion, 302, "login complete");
     67  response.setHeader("Content-Type", "text/html");
     68  response.setHeader("Location", CANONICAL_SUCCESS_URL);
     69 }
     70 
     71 add_setup(async function () {
     72  // Set up a mock server for handling captive portal redirect.
     73  server = new HttpServer();
     74  server.identity.add("http", "support.mozilla.org", 8080);
     75  server.registerPathHandler("/success", redirectHandler);
     76  server.registerPathHandler("/login", loginHandler);
     77  server.registerPathHandler("/unlock", unlockHandler);
     78  server.registerPathHandler("/sumo", sumoHandler);
     79  server.start(8080);
     80  registerCleanupFunction(async () => await server.stop());
     81  info("Mock server is now set up for captive portal redirect");
     82 
     83  await SpecialPowers.pushPrefEnv({
     84    set: [
     85      ["captivedetect.canonicalURL", CANONICAL_SUCCESS_URL],
     86      ["captivedetect.canonicalContent", META_CANONICAL_CONTENT],
     87      ["network.dns.native-is-localhost", true],
     88    ],
     89  });
     90 });
     91 
     92 // This test checks if the captive portal tab is removed after the
     93 // sucess/abort events are fired, assuming the tab has already redirected
     94 // to the canonical URL before they are fired.
     95 add_task(async function checkCaptivePortalTabCloseOnCanonicalURL_one() {
     96  await portalDetected();
     97  let errorTab = await openCaptivePortalErrorTab();
     98  let tab = await openCaptivePortalLoginTab(errorTab, LOGIN_URL);
     99  let browser = tab.linkedBrowser;
    100 
    101  let redirectedToCanonicalURL = BrowserTestUtils.browserLoaded(
    102    browser,
    103    false,
    104    CANONICAL_SUCCESS_URL
    105  );
    106  let errorPageReloaded = BrowserTestUtils.waitForErrorPage(
    107    errorTab.linkedBrowser
    108  );
    109 
    110  await SpecialPowers.spawn(browser, [], async () => {
    111    let doc = content.document;
    112    let loginButton = doc.querySelector("a");
    113    await ContentTaskUtils.waitForCondition(
    114      () => loginButton,
    115      "Login button on the captive portal tab is visible"
    116    );
    117    info("Clicking the login button on the captive portal tab page");
    118    await EventUtils.synthesizeMouseAtCenter(loginButton, {}, content);
    119  });
    120 
    121  await redirectedToCanonicalURL;
    122  info(
    123    "Re-direct to canonical URL in the captive portal tab was succcessful after login"
    124  );
    125 
    126  let tabClosed = BrowserTestUtils.waitForTabClosing(tab);
    127  Services.obs.notifyObservers(null, "captive-portal-login-success");
    128  await tabClosed;
    129  info(
    130    "Captive portal tab was closed on re-direct to canonical URL after login as expected"
    131  );
    132 
    133  await errorPageReloaded;
    134  info("Captive portal error page was reloaded");
    135  gBrowser.removeTab(errorTab);
    136 });
    137 
    138 // This test checks if the captive portal tab is removed on location change
    139 // i.e. when it is re-directed to the canonical URL long after success/abort
    140 // event handlers are executed.
    141 add_task(async function checkCaptivePortalTabCloseOnCanonicalURL_two() {
    142  loginPageShown = false;
    143  await portalDetected();
    144  let errorTab = await openCaptivePortalErrorTab();
    145  let tab = await openCaptivePortalLoginTab(errorTab, LOGIN_URL);
    146  let browser = tab.linkedBrowser;
    147 
    148  let redirectedToCanonicalURL = BrowserTestUtils.waitForLocationChange(
    149    gBrowser,
    150    CANONICAL_SUCCESS_URL
    151  );
    152  let errorPageReloaded = BrowserTestUtils.waitForErrorPage(
    153    errorTab.linkedBrowser
    154  );
    155 
    156  Services.obs.notifyObservers(null, "captive-portal-login-success");
    157  await TestUtils.waitForCondition(
    158    () => CPS.state == CPS.UNLOCKED_PORTAL,
    159    "Captive portal is released"
    160  );
    161 
    162  let tabClosed = BrowserTestUtils.waitForTabClosing(tab);
    163  await SpecialPowers.spawn(browser, [], async () => {
    164    let doc = content.document;
    165    let loginButton = doc.querySelector("a");
    166    await ContentTaskUtils.waitForCondition(
    167      () => loginButton,
    168      "Login button on the captive portal tab is visible"
    169    );
    170    info("Clicking the login button on the captive portal tab page");
    171    await EventUtils.synthesizeMouseAtCenter(loginButton, {}, content);
    172  });
    173 
    174  await redirectedToCanonicalURL;
    175  info(
    176    "Re-direct to canonical URL in the captive portal tab was succcessful after login"
    177  );
    178  await tabClosed;
    179  info(
    180    "Captive portal tab was closed on re-direct to canonical URL after login as expected"
    181  );
    182 
    183  await errorPageReloaded;
    184  info("Captive portal error page was reloaded");
    185  gBrowser.removeTab(errorTab);
    186 });
    187 
    188 // Test that the captive portal page is closed after a successful login
    189 // even if it's self-refreshed to support.mozilla.org
    190 add_task(async function checkCaptivePortalTabCloseOnCanonicalURL_three() {
    191  loginPageShown = false;
    192  await portalDetected();
    193  let errorTab = await openCaptivePortalErrorTab();
    194  let tab = await openCaptivePortalLoginTab(errorTab, LOGIN_URL);
    195  let browser = tab.linkedBrowser;
    196 
    197  let errorPageReloaded = BrowserTestUtils.waitForErrorPage(
    198    errorTab.linkedBrowser
    199  );
    200 
    201  let tabClosed = BrowserTestUtils.waitForTabClosing(tab);
    202  showSumo = true;
    203  await SpecialPowers.spawn(browser, [], async () => {
    204    let doc = content.document;
    205    let loginButton = doc.querySelector("a");
    206    await ContentTaskUtils.waitForCondition(
    207      () => loginButton,
    208      "Login button on the captive portal tab is visible"
    209    );
    210    info("Clicking the login button on the captive portal tab page");
    211    await EventUtils.synthesizeMouseAtCenter(loginButton, {}, content);
    212  });
    213 
    214  Services.obs.notifyObservers(null, "captive-portal-login-success");
    215 
    216  await TestUtils.waitForCondition(
    217    () => CPS.state == CPS.UNLOCKED_PORTAL,
    218    "Captive portal is released"
    219  );
    220 
    221  await tabClosed;
    222  info(
    223    "Captive portal tab was closed on re-direct to canonical URL after login as expected"
    224  );
    225 
    226  await errorPageReloaded;
    227  info("Captive portal error page was reloaded");
    228  showSumo = false;
    229  gBrowser.removeTab(errorTab);
    230 });