tor-browser

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

browser_UserContextManager.js (9052B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const { UserContextManagerClass } = ChromeUtils.importESModule(
      7  "chrome://remote/content/shared/UserContextManager.sys.mjs"
      8 );
      9 
     10 add_task(async function test_invalid() {
     11  const userContextManager = new UserContextManagerClass();
     12 
     13  // Check invalid types for hasUserContextId/getInternalIdById which expects
     14  // a string.
     15  for (const value of [null, undefined, 1, [], {}]) {
     16    is(userContextManager.hasUserContextId(value), false);
     17    is(userContextManager.getInternalIdById(value), null);
     18  }
     19 
     20  // Check an invalid value for hasUserContextId/getInternalIdById which expects
     21  // either "default" or a UUID from Services.uuid.generateUUID.
     22  is(userContextManager.hasUserContextId("foo"), false);
     23  is(userContextManager.getInternalIdById("foo"), null);
     24 
     25  // Check invalid types for getIdByInternalId which expects a number.
     26  for (const value of [null, undefined, "foo", [], {}]) {
     27    is(userContextManager.getIdByInternalId(value), null);
     28  }
     29 
     30  userContextManager.destroy();
     31 });
     32 
     33 add_task(async function test_default_context() {
     34  const userContextManager = new UserContextManagerClass();
     35  ok(
     36    userContextManager.hasUserContextId("default"),
     37    `Context id default is known by the manager`
     38  );
     39  ok(
     40    userContextManager.getUserContextIds().includes("default"),
     41    `Context id default is listed by the manager`
     42  );
     43  is(
     44    userContextManager.getInternalIdById("default"),
     45    0,
     46    "Default user context has the expected internal id"
     47  );
     48 
     49  userContextManager.destroy();
     50 });
     51 
     52 add_task(async function test_new_internal_contexts() {
     53  info("Create a new user context with ContextualIdentityService");
     54  const beforeInternalId =
     55    ContextualIdentityService.create("before").userContextId;
     56 
     57  info("Create the UserContextManager");
     58  const userContextManager = new UserContextManagerClass();
     59 
     60  const beforeContextId =
     61    userContextManager.getIdByInternalId(beforeInternalId);
     62  assertContextAvailable(userContextManager, beforeContextId, beforeInternalId);
     63 
     64  info("Create another user context with ContextualIdentityService");
     65  const afterInternalId =
     66    ContextualIdentityService.create("after").userContextId;
     67  const afterContextId = userContextManager.getIdByInternalId(afterInternalId);
     68  assertContextAvailable(userContextManager, afterContextId, afterInternalId);
     69 
     70  info("Delete both user contexts");
     71  ContextualIdentityService.remove(beforeInternalId);
     72  ContextualIdentityService.remove(afterInternalId);
     73  assertContextRemoved(userContextManager, afterContextId, afterInternalId);
     74  assertContextRemoved(userContextManager, beforeContextId, beforeInternalId);
     75 
     76  userContextManager.destroy();
     77 });
     78 
     79 add_task(async function test_create_remove_context() {
     80  const userContextManager = new UserContextManagerClass();
     81 
     82  for (const closeContextTabs of [true, false]) {
     83    info("Create two contexts via createContext");
     84    const userContextId1 = userContextManager.createContext();
     85    const internalId1 = userContextManager.getInternalIdById(userContextId1);
     86    assertContextAvailable(userContextManager, userContextId1);
     87 
     88    const userContextId2 = userContextManager.createContext();
     89    const internalId2 = userContextManager.getInternalIdById(userContextId2);
     90    assertContextAvailable(userContextManager, userContextId2);
     91 
     92    info("Create tabs in various user contexts");
     93    const url = "https://example.com/document-builder.sjs?html=tab";
     94    const tabDefault = await addTab(gBrowser, url);
     95    const tabContext1 = await addTab(gBrowser, url, {
     96      userContextId: internalId1,
     97    });
     98    const tabContext2 = await addTab(gBrowser, url, {
     99      userContextId: internalId2,
    100    });
    101 
    102    info("Remove the user context 1 via removeUserContext");
    103    userContextManager.removeUserContext(userContextId1, { closeContextTabs });
    104 
    105    assertContextRemoved(userContextManager, userContextId1, internalId1);
    106    if (closeContextTabs) {
    107      ok(!gBrowser.tabs.includes(tabContext1), "Tab context 1 is closed");
    108    } else {
    109      ok(gBrowser.tabs.includes(tabContext1), "Tab context 1 is not closed");
    110    }
    111    ok(gBrowser.tabs.includes(tabDefault), "Tab default is not closed");
    112    ok(gBrowser.tabs.includes(tabContext2), "Tab context 2 is not closed");
    113 
    114    info("Remove the user context 2 via removeUserContext");
    115    userContextManager.removeUserContext(userContextId2, { closeContextTabs });
    116    assertContextRemoved(userContextManager, userContextId2, internalId2);
    117    if (closeContextTabs) {
    118      ok(!gBrowser.tabs.includes(tabContext2), "Tab context 2 is closed");
    119    } else {
    120      ok(gBrowser.tabs.includes(tabContext2), "Tab context 2 is not closed");
    121    }
    122    ok(gBrowser.tabs.includes(tabDefault), "Tab default is not closed");
    123  }
    124 
    125  userContextManager.destroy();
    126 });
    127 
    128 add_task(async function test_create_context_prefix() {
    129  const userContextManager = new UserContextManagerClass();
    130 
    131  info("Create a context with a custom prefix via createContext");
    132  const userContextId = userContextManager.createContext("test_prefix");
    133  const internalId = userContextManager.getInternalIdById(userContextId);
    134  const identity =
    135    ContextualIdentityService.getPublicIdentityFromId(internalId);
    136  ok(
    137    identity.name.startsWith("test_prefix"),
    138    "The new identity used the provided prefix"
    139  );
    140 
    141  userContextManager.removeUserContext(userContextId);
    142  userContextManager.destroy();
    143 });
    144 
    145 add_task(async function test_events() {
    146  const manager = new UserContextManagerClass();
    147  const userContextCreatedEvents = [];
    148  const userContextDeletedEvents = [];
    149  manager.on("user-context-created", (name, data) =>
    150    userContextCreatedEvents.push(data)
    151  );
    152  manager.on("user-context-deleted", (name, data) =>
    153    userContextDeletedEvents.push(data)
    154  );
    155 
    156  const contextId1 = manager.createContext();
    157  is(userContextCreatedEvents.length, 1);
    158  is(userContextCreatedEvents[0].userContextId, contextId1);
    159  is(userContextDeletedEvents.length, 0);
    160 
    161  manager.removeUserContext(contextId1);
    162  is(userContextCreatedEvents.length, 1);
    163  is(userContextDeletedEvents.length, 1);
    164  is(userContextDeletedEvents[0].userContextId, contextId1);
    165 
    166  manager.destroy();
    167 });
    168 
    169 add_task(async function test_several_managers() {
    170  const manager1 = new UserContextManagerClass();
    171  const manager2 = new UserContextManagerClass();
    172 
    173  info("Create a context via manager1");
    174  const contextId1 = manager1.createContext();
    175  const internalId = manager1.getInternalIdById(contextId1);
    176  assertContextUnknown(manager2, contextId1);
    177 
    178  info("Retrieve the corresponding user context id in manager2");
    179  const contextId2 = manager2.getIdByInternalId(internalId);
    180  is(
    181    typeof contextId2,
    182    "string",
    183    "manager2 has a valid id for the user context created by manager 1"
    184  );
    185 
    186  Assert.notEqual(
    187    contextId1,
    188    contextId2,
    189    "manager1 and manager2 have different ids for the same internal context id"
    190  );
    191 
    192  info("Remove the user context via manager2");
    193  manager2.removeUserContext(contextId2);
    194 
    195  info("Check that the user context is removed from both managers");
    196  assertContextRemoved(manager1, contextId1, internalId);
    197  assertContextRemoved(manager2, contextId2, internalId);
    198 
    199  manager1.destroy();
    200  manager2.destroy();
    201 });
    202 
    203 function assertContextAvailable(manager, contextId, expectedInternalId = null) {
    204  ok(
    205    manager.getUserContextIds().includes(contextId),
    206    `Context id ${contextId} is listed by the manager`
    207  );
    208  ok(
    209    manager.hasUserContextId(contextId),
    210    `Context id ${contextId} is known by the manager`
    211  );
    212 
    213  const internalId = manager.getInternalIdById(contextId);
    214  if (expectedInternalId != null) {
    215    is(internalId, expectedInternalId, "Internal id has the expected value");
    216  }
    217 
    218  is(
    219    typeof internalId,
    220    "number",
    221    `Context id ${contextId} corresponds to a valid internal id (${internalId})`
    222  );
    223  is(
    224    manager.getIdByInternalId(internalId),
    225    contextId,
    226    `Context id ${contextId} is returned for internal id ${internalId}`
    227  );
    228  ok(
    229    ContextualIdentityService.getPublicUserContextIds().includes(internalId),
    230    `User context for context id ${contextId} is found by ContextualIdentityService`
    231  );
    232 }
    233 
    234 function assertContextUnknown(manager, contextId) {
    235  ok(
    236    !manager.getUserContextIds().includes(contextId),
    237    `Context id ${contextId} is not listed by the manager`
    238  );
    239  ok(
    240    !manager.hasUserContextId(contextId),
    241    `Context id ${contextId} is not known by the manager`
    242  );
    243  is(
    244    manager.getInternalIdById(contextId),
    245    null,
    246    `Context id ${contextId} does not match any internal id`
    247  );
    248 }
    249 
    250 function assertContextRemoved(manager, contextId, internalId) {
    251  assertContextUnknown(manager, contextId);
    252  is(
    253    manager.getIdByInternalId(internalId),
    254    null,
    255    `Internal id ${internalId} cannot be converted to user context id`
    256  );
    257  ok(
    258    !ContextualIdentityService.getPublicUserContextIds().includes(internalId),
    259    `Internal id ${internalId} is not found in ContextualIdentityService`
    260  );
    261 }