tor-browser

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

browser_cookies_serviceWorker.js (14838B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const TEST_CROSS_SITE_DOMAIN = "https://example.net/";
      7 const TEST_CROSS_SITE_PAGE =
      8  TEST_CROSS_SITE_DOMAIN + TEST_PATH + "file_empty.html";
      9 
     10 add_setup(async function () {
     11  await SpecialPowers.pushPrefEnv({
     12    set: [
     13      ["dom.serviceWorkers.enabled", true],
     14      ["dom.serviceWorkers.testing.enabled", true],
     15    ],
     16  });
     17 
     18  Services.cookies.removeAll();
     19 });
     20 
     21 function registerSW(browser) {
     22  return SpecialPowers.spawn(browser, [], async _ => {
     23    let reg =
     24      await content.navigator.serviceWorker.register("serviceWorker.js");
     25 
     26    await ContentTaskUtils.waitForCondition(() => {
     27      return reg.active && reg.active.state === "activated";
     28    }, "The service worker is activated");
     29 
     30    ok(
     31      content.navigator.serviceWorker.controller,
     32      "The service worker controls the document successfully."
     33    );
     34  });
     35 }
     36 
     37 function fetchCookiesFromSW(browser) {
     38  return SpecialPowers.spawn(browser, [], async _ => {
     39    return new content.Promise(resolve => {
     40      content.navigator.serviceWorker.addEventListener("message", event => {
     41        resolve(event.data.content);
     42      });
     43 
     44      content.navigator.serviceWorker.controller.postMessage({
     45        action: "fetch",
     46        url: `cookies.sjs`,
     47      });
     48    });
     49  });
     50 }
     51 
     52 function setCookiesFromSW(browser, cookies) {
     53  let setCookieQuery = "";
     54 
     55  for (let cookie of cookies) {
     56    setCookieQuery += `Set-Cookie=${cookie}&`;
     57  }
     58 
     59  return SpecialPowers.spawn(browser, [setCookieQuery], async query => {
     60    return new content.Promise(resolve => {
     61      content.navigator.serviceWorker.addEventListener("message", event => {
     62        resolve(event.data.content);
     63      });
     64 
     65      content.navigator.serviceWorker.controller.postMessage({
     66        action: "fetch",
     67        url: `cookies.sjs?${query}`,
     68      });
     69    });
     70  });
     71 }
     72 
     73 function unregisterSW(browser) {
     74  return SpecialPowers.spawn(browser, [], async _ => {
     75    const regs = await content.navigator.serviceWorker.getRegistrations();
     76    for (const reg of regs) {
     77      await reg.unregister();
     78    }
     79  });
     80 }
     81 
     82 /**
     83 * Verify a first-party service worker can access both SameSite=None and
     84 * SameSite=Lax cookies set in the first-party context.
     85 */
     86 add_task(async function testCookiesWithFirstPartyServiceWorker() {
     87  info("Open a tab");
     88  let tab = await BrowserTestUtils.openNewForegroundTab(
     89    gBrowser,
     90    TEST_TOP_PAGE
     91  );
     92 
     93  info("Writing cookies to the first-party context.");
     94  await SpecialPowers.spawn(tab.linkedBrowser, [], async _ => {
     95    const cookies = [
     96      "foo=bar; SameSite=None; Secure",
     97      "fooLax=barLax; SameSite=Lax; Secure",
     98    ];
     99 
    100    let query = "";
    101 
    102    for (let cookie of cookies) {
    103      query += `Set-Cookie=${cookie}&`;
    104    }
    105 
    106    await content.fetch(`cookies.sjs?${query}`);
    107  });
    108 
    109  info("Register a service worker and trigger a fetch request to get cookies.");
    110  await registerSW(tab.linkedBrowser);
    111  let cookieStr = await fetchCookiesFromSW(tab.linkedBrowser);
    112 
    113  is(cookieStr, "foo=bar; fooLax=barLax", "The cookies are expected");
    114 
    115  info("Set cookies from the service worker.");
    116  await setCookiesFromSW(tab.linkedBrowser, [
    117    "foo=barSW; SameSite=None; Secure",
    118    "fooLax=barLaxSW; SameSite=Lax; Secure",
    119  ]);
    120 
    121  info("Get cookies from the service worker.");
    122  cookieStr = await fetchCookiesFromSW(tab.linkedBrowser);
    123 
    124  is(cookieStr, "foo=barSW; fooLax=barLaxSW", "The cookies are expected");
    125 
    126  await unregisterSW(tab.linkedBrowser);
    127  BrowserTestUtils.removeTab(tab);
    128  Services.cookies.removeAll();
    129 });
    130 
    131 /**
    132 * Verify a cross-site service worker can only access cookies set in the
    133 * same cross-site context.
    134 */
    135 add_task(async function testCookiesWithCrossSiteServiceWorker() {
    136  // Disable blocking third-party cookies.
    137  await SpecialPowers.pushPrefEnv({
    138    set: [["network.cookie.cookieBehavior.optInPartitioning", false]],
    139  });
    140 
    141  info("Open a cross-site tab");
    142  let crossSiteTab = await BrowserTestUtils.openNewForegroundTab(
    143    gBrowser,
    144    TEST_CROSS_SITE_PAGE
    145  );
    146 
    147  info("Writing cookies to the cross site in the first-party context.");
    148  await SpecialPowers.spawn(crossSiteTab.linkedBrowser, [], async _ => {
    149    const cookies = [
    150      "foo=bar; SameSite=None; Secure",
    151      "fooLax=barLax; SameSite=Lax; Secure",
    152    ];
    153 
    154    let query = "";
    155 
    156    for (let cookie of cookies) {
    157      query += `Set-Cookie=${cookie}&`;
    158    }
    159 
    160    await content.fetch(`cookies.sjs?${query}`);
    161  });
    162 
    163  info("Open a tab");
    164  let tab = await BrowserTestUtils.openNewForegroundTab(
    165    gBrowser,
    166    TEST_TOP_PAGE
    167  );
    168 
    169  info("Load a cross-site iframe");
    170  let crossSiteBc = await SpecialPowers.spawn(
    171    tab.linkedBrowser,
    172    [TEST_CROSS_SITE_PAGE],
    173    async url => {
    174      let ifr = content.document.createElement("iframe");
    175 
    176      await new content.Promise(resolve => {
    177        ifr.onload = resolve;
    178        ifr.src = url;
    179        content.document.body.appendChild(ifr);
    180      });
    181 
    182      return ifr.browsingContext;
    183    }
    184  );
    185 
    186  info("Write cookies in the cross-site iframe");
    187  await SpecialPowers.spawn(crossSiteBc, [], async _ => {
    188    const cookies = [
    189      "foo=crossBar; SameSite=None; Secure",
    190      "fooLax=crossBarLax; SameSite=Lax; Secure",
    191    ];
    192 
    193    let query = "";
    194 
    195    for (let cookie of cookies) {
    196      query += `Set-Cookie=${cookie}&`;
    197    }
    198 
    199    await content.fetch(`cookies.sjs?${query}`);
    200  });
    201 
    202  info(
    203    "Register a service worker and trigger a fetch request to get cookies in cross-site context."
    204  );
    205  await registerSW(crossSiteBc);
    206  let cookieStr = await fetchCookiesFromSW(crossSiteBc);
    207 
    208  is(
    209    cookieStr,
    210    "foo=crossBar",
    211    "Only the SameSite=None cookie set in the third-party iframe is available."
    212  );
    213 
    214  info("Set cookies from the third-party service worker.");
    215  await setCookiesFromSW(crossSiteBc, [
    216    "foo=crossBarSW; SameSite=None; Secure",
    217    "fooLax=crossBarLaxSW; SameSite=Lax; Secure",
    218  ]);
    219 
    220  info("Get cookies from the third-party service worker.");
    221  cookieStr = await fetchCookiesFromSW(crossSiteBc);
    222 
    223  is(
    224    cookieStr,
    225    "foo=crossBarSW",
    226    "Only the SameSite=None cookie set in the third-party service worker is available."
    227  );
    228 
    229  await unregisterSW(crossSiteBc);
    230  BrowserTestUtils.removeTab(crossSiteTab);
    231  BrowserTestUtils.removeTab(tab);
    232  Services.cookies.removeAll();
    233 });
    234 
    235 /**
    236 * Verify a cross-site service worker can only access partitioned cookies set in
    237 * the same cross-site context if third-party cookies are blocked.
    238 */
    239 add_task(async function testPartitionedCookiesWithCrossSiteServiceWorker() {
    240  // Enable blocking third-party cookies.
    241  await SpecialPowers.pushPrefEnv({
    242    set: [
    243      ["network.cookie.cookieBehavior.optInPartitioning", true],
    244      ["network.cookie.CHIPS.enabled", true],
    245    ],
    246  });
    247 
    248  info("Open a tab");
    249  let tab = await BrowserTestUtils.openNewForegroundTab(
    250    gBrowser,
    251    TEST_TOP_PAGE
    252  );
    253 
    254  info("Load a cross-site iframe");
    255  let crossSiteBc = await SpecialPowers.spawn(
    256    tab.linkedBrowser,
    257    [TEST_CROSS_SITE_PAGE],
    258    async url => {
    259      let ifr = content.document.createElement("iframe");
    260 
    261      await new content.Promise(resolve => {
    262        ifr.onload = resolve;
    263        ifr.src = url;
    264        content.document.body.appendChild(ifr);
    265      });
    266 
    267      return ifr.browsingContext;
    268    }
    269  );
    270 
    271  info("Write cookies in the cross-site iframe");
    272  await SpecialPowers.spawn(crossSiteBc, [], async _ => {
    273    const cookies = [
    274      "foo=crossBar; SameSite=None; Secure",
    275      "fooLax=crossBarLax; SameSite=Lax; Secure",
    276      "fooPartitioned=crossBar; SameSite=None; Secure; Partitioned;",
    277      "fooLaxPartitioned=crossBarLax; SameSite=Lax; Secure; Partitioned;",
    278    ];
    279 
    280    let query = "";
    281 
    282    for (let cookie of cookies) {
    283      query += `Set-Cookie=${cookie}&`;
    284    }
    285 
    286    await content.fetch(`cookies.sjs?${query}`);
    287  });
    288 
    289  info(
    290    "Register a service worker and trigger a fetch request to get cookies in cross-site context."
    291  );
    292  await registerSW(crossSiteBc);
    293  let cookieStr = await fetchCookiesFromSW(crossSiteBc);
    294 
    295  is(
    296    cookieStr,
    297    "fooPartitioned=crossBar",
    298    "Only the SameSite=None partitioned cookie set in the third-party iframe is available."
    299  );
    300 
    301  info("Set cookies from the third-party service worker.");
    302  await setCookiesFromSW(crossSiteBc, [
    303    "foo=crossBarSW; SameSite=None; Secure",
    304    "fooLax=crossBarLaxSW; SameSite=Lax; Secure",
    305    "fooPartitioned=crossBarSW; SameSite=None; Secure; Partitioned;",
    306    "fooLaxPartitioned=crossBarLaxSW; SameSite=Lax; Secure; Partitioned;",
    307  ]);
    308 
    309  info("Get cookies from the third-party service worker.");
    310  cookieStr = await fetchCookiesFromSW(crossSiteBc);
    311 
    312  is(
    313    cookieStr,
    314    "fooPartitioned=crossBarSW",
    315    "Only the SameSite=None partitioned cookie set in the third-party service worker is available."
    316  );
    317 
    318  await unregisterSW(crossSiteBc);
    319  BrowserTestUtils.removeTab(tab);
    320  Services.cookies.removeAll();
    321 });
    322 
    323 /**
    324 * Verify a ABA service worker can only access cookies set in the ABA context.
    325 */
    326 add_task(async function testCookiesWithABAServiceWorker() {
    327  // Disable blocking third-party cookies.
    328  await SpecialPowers.pushPrefEnv({
    329    set: [["network.cookie.cookieBehavior.optInPartitioning", false]],
    330  });
    331 
    332  info("Open a tab");
    333  let tab = await BrowserTestUtils.openNewForegroundTab(
    334    gBrowser,
    335    TEST_TOP_PAGE
    336  );
    337 
    338  info("Writing cookies to the first-party context.");
    339  await SpecialPowers.spawn(tab.linkedBrowser, [], async _ => {
    340    const cookies = [
    341      "foo=bar; SameSite=None; Secure",
    342      "fooLax=barLax; SameSite=Lax; Secure",
    343    ];
    344 
    345    let query = "";
    346 
    347    for (let cookie of cookies) {
    348      query += `Set-Cookie=${cookie}&`;
    349    }
    350 
    351    await content.fetch(`cookies.sjs?${query}`);
    352  });
    353 
    354  info("Load a ABA iframe");
    355  let crossSiteBc = await SpecialPowers.spawn(
    356    tab.linkedBrowser,
    357    [TEST_CROSS_SITE_PAGE],
    358    async url => {
    359      let ifr = content.document.createElement("iframe");
    360 
    361      await new content.Promise(resolve => {
    362        ifr.onload = resolve;
    363        ifr.src = url;
    364        content.document.body.appendChild(ifr);
    365      });
    366 
    367      return ifr.browsingContext;
    368    }
    369  );
    370 
    371  let ABABc = await SpecialPowers.spawn(
    372    crossSiteBc,
    373    [TEST_TOP_PAGE],
    374    async url => {
    375      let ifr = content.document.createElement("iframe");
    376 
    377      await new content.Promise(resolve => {
    378        ifr.onload = resolve;
    379        ifr.src = url;
    380        content.document.body.appendChild(ifr);
    381      });
    382 
    383      return ifr.browsingContext;
    384    }
    385  );
    386 
    387  info(
    388    "Register a service worker and trigger a fetch request to get cookies in the ABA context."
    389  );
    390 
    391  await registerSW(ABABc);
    392  let cookieStr = await fetchCookiesFromSW(ABABc);
    393  is(cookieStr, "", "No cookie should be available in ABA context.");
    394 
    395  info("Set cookies in the ABA iframe");
    396  await SpecialPowers.spawn(ABABc, [], async _ => {
    397    const cookies = [
    398      "fooABA=barABA; SameSite=None; Secure",
    399      "fooABALax=BarABALax; SameSite=Lax; Secure",
    400    ];
    401 
    402    let query = "";
    403 
    404    for (let cookie of cookies) {
    405      query += `Set-Cookie=${cookie}&`;
    406    }
    407 
    408    await content.fetch(`cookies.sjs?${query}`);
    409  });
    410 
    411  info("Get cookies in the ABA service worker.");
    412  cookieStr = await fetchCookiesFromSW(ABABc);
    413 
    414  is(
    415    cookieStr,
    416    "fooABA=barABA",
    417    "Only the SameSite=None cookie set in ABA iframe is available."
    418  );
    419 
    420  info("Set cookies from the service worker in ABA context");
    421  await setCookiesFromSW(ABABc, [
    422    "fooABA=barABASW; SameSite=None; Secure",
    423    "fooABALax=BarABALaxSW; SameSite=Lax; Secure",
    424  ]);
    425 
    426  info("Get cookies from the service worker in the ABA context.");
    427  cookieStr = await fetchCookiesFromSW(ABABc);
    428 
    429  is(
    430    cookieStr,
    431    "fooABA=barABASW",
    432    "Only the SameSite=None cookie set in ABA service worker is available."
    433  );
    434 
    435  await unregisterSW(ABABc);
    436  BrowserTestUtils.removeTab(tab);
    437  Services.cookies.removeAll();
    438 });
    439 
    440 /**
    441 * Verify a ABA service worker can only access partitioned cookies set in the
    442 * ABA context if third-party cookies are blocked.
    443 */
    444 add_task(async function testCookiesWithABAServiceWorker() {
    445  // Disable blocking third-party cookies.
    446  await SpecialPowers.pushPrefEnv({
    447    set: [
    448      ["network.cookie.cookieBehavior.optInPartitioning", true],
    449      ["network.cookie.CHIPS.enabled", true],
    450    ],
    451  });
    452 
    453  info("Open a tab");
    454  let tab = await BrowserTestUtils.openNewForegroundTab(
    455    gBrowser,
    456    TEST_TOP_PAGE
    457  );
    458 
    459  info("Load a ABA iframe");
    460  let crossSiteBc = await SpecialPowers.spawn(
    461    tab.linkedBrowser,
    462    [TEST_CROSS_SITE_PAGE],
    463    async url => {
    464      let ifr = content.document.createElement("iframe");
    465 
    466      await new content.Promise(resolve => {
    467        ifr.onload = resolve;
    468        ifr.src = url;
    469        content.document.body.appendChild(ifr);
    470      });
    471 
    472      return ifr.browsingContext;
    473    }
    474  );
    475 
    476  let ABABc = await SpecialPowers.spawn(
    477    crossSiteBc,
    478    [TEST_TOP_PAGE],
    479    async url => {
    480      let ifr = content.document.createElement("iframe");
    481 
    482      await new content.Promise(resolve => {
    483        ifr.onload = resolve;
    484        ifr.src = url;
    485        content.document.body.appendChild(ifr);
    486      });
    487 
    488      return ifr.browsingContext;
    489    }
    490  );
    491 
    492  info("Set cookies in the ABA iframe");
    493  await SpecialPowers.spawn(ABABc, [], async _ => {
    494    const cookies = [
    495      "fooABA=barABA; SameSite=None; Secure",
    496      "fooABALax=BarABALax; SameSite=Lax; Secure",
    497      "fooABAPartitioned=barABA; SameSite=None; Secure; Partitioned;",
    498      "fooABALaxPartitioned=BarABALax; SameSite=Lax; Secure; Partitioned;",
    499    ];
    500 
    501    let query = "";
    502 
    503    for (let cookie of cookies) {
    504      query += `Set-Cookie=${cookie}&`;
    505    }
    506 
    507    await content.fetch(`cookies.sjs?${query}`);
    508  });
    509 
    510  info(
    511    "Register a service worker and trigger a fetch request to get cookies in the ABA context."
    512  );
    513 
    514  await registerSW(ABABc);
    515 
    516  info("Get cookies in the ABA service worker.");
    517  let cookieStr = await fetchCookiesFromSW(ABABc);
    518 
    519  is(
    520    cookieStr,
    521    "fooABAPartitioned=barABA",
    522    "Only the SameSite=None partitioned cookie set in ABA iframe is available."
    523  );
    524 
    525  info("Set cookies from the service worker in ABA context");
    526  await setCookiesFromSW(ABABc, [
    527    "fooABA=barABASW; SameSite=None; Secure",
    528    "fooABALax=BarABALaxSW; SameSite=Lax; Secure",
    529    "fooABAPartitioned=barABASW; SameSite=None; Secure; Partitioned;",
    530    "fooABALaxPartitioned=BarABALaxSW; SameSite=Lax; Secure; Partitioned;",
    531  ]);
    532 
    533  info("Get cookies from the service worker in the ABA context.");
    534  cookieStr = await fetchCookiesFromSW(ABABc);
    535 
    536  is(
    537    cookieStr,
    538    "fooABAPartitioned=barABASW",
    539    "Only the SameSite=None partitioned cookie set in ABA service worker is available."
    540  );
    541 
    542  await unregisterSW(ABABc);
    543  BrowserTestUtils.removeTab(tab);
    544  Services.cookies.removeAll();
    545 });