tor-browser

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

test_FirefoxBridgeExtensionUtils.js (11507B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const { FirefoxBridgeExtensionUtils } = ChromeUtils.importESModule(
      7  "resource:///modules/FirefoxBridgeExtensionUtils.sys.mjs"
      8 );
      9 
     10 const OLD_FIREFOX_SHELL_OPEN_COMMAND_PATH = `${FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL}\\shell\\open\\command`;
     11 const OLD_FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH = `${FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL}\\shell\\open\\command`;
     12 const FIREFOX_SHELL_OPEN_COMMAND_PATH = `${FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL}\\shell\\open\\command`;
     13 const FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH = `${FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL}\\shell\\open\\command`;
     14 
     15 class StubbedRegistryKey {
     16  #children;
     17  #originalChildren;
     18  #closeCalled;
     19  #deletedChildren;
     20  #openedForRead;
     21  #values;
     22 
     23  constructor(children, values) {
     24    this.#children = children;
     25    this.#values = values;
     26    this.#originalChildren = new Map(children);
     27 
     28    this.#closeCalled = false;
     29    this.#openedForRead = false;
     30    this.#deletedChildren = new Set([]);
     31  }
     32 
     33  get ACCESS_READ() {
     34    return 0;
     35  }
     36 
     37  reset() {
     38    this.#closeCalled = false;
     39    this.#deletedChildren = new Set([]);
     40    this.#children = new Map(this.#originalChildren);
     41  }
     42 
     43  open(_accessLevel) {
     44    this.#openedForRead = true;
     45  }
     46 
     47  get wasOpenedForRead() {
     48    return this.#openedForRead;
     49  }
     50 
     51  openChild(path, accessLevel) {
     52    const result = this.#children.get(path);
     53    result?.open(accessLevel);
     54    return result;
     55  }
     56 
     57  hasChild(path) {
     58    return this.#children.has(path);
     59  }
     60 
     61  close() {
     62    this.#closeCalled = true;
     63  }
     64 
     65  removeChild(path) {
     66    this.#deletedChildren.add(path);
     67 
     68    // delete the actual child if it's in there
     69    this.#children.delete(path);
     70  }
     71 
     72  isChildDeleted(path) {
     73    return this.#deletedChildren.has(path);
     74  }
     75 
     76  getChildName(index) {
     77    let i = 0;
     78    for (const [key] of this.#children) {
     79      if (i == index) {
     80        return key;
     81      }
     82      i++;
     83    }
     84 
     85    return undefined;
     86  }
     87 
     88  readStringValue(name) {
     89    return this.#values.get(name);
     90  }
     91 
     92  get childCount() {
     93    return this.#children.size;
     94  }
     95 
     96  getValueType(entryName) {
     97    if (typeof this.readStringValue(entryName) == "string") {
     98      return Ci.nsIWindowsRegKey.TYPE_STRING;
     99    }
    100 
    101    throw new Error(`${entryName} not found in registry`);
    102  }
    103 
    104  get wasCloseCalled() {
    105    return this.#closeCalled;
    106  }
    107 
    108  getValueName(index) {
    109    let i = 0;
    110    for (const [key] of this.#values) {
    111      if (i == index) {
    112        return key;
    113      }
    114      i++;
    115    }
    116 
    117    return undefined;
    118  }
    119 
    120  get valueCount() {
    121    return this.#values.size;
    122  }
    123 }
    124 
    125 class StubbedDeleteBridgeProtocolRegistryEntryHelper {
    126  #applicationPath;
    127  #registryRootKey;
    128 
    129  constructor({ applicationPath, registryRootKey }) {
    130    this.#applicationPath = applicationPath;
    131    this.#registryRootKey = registryRootKey;
    132  }
    133 
    134  getApplicationPath() {
    135    return this.#applicationPath;
    136  }
    137 
    138  openRegistryRoot() {
    139    return this.#registryRootKey;
    140  }
    141 
    142  deleteRegistryTree(root, toDeletePath) {
    143    // simplify this for tests
    144    root.removeChild(toDeletePath);
    145  }
    146 }
    147 
    148 add_task(async function test_DeleteWhenSameFirefoxInstall() {
    149  for (let protocols of [
    150    [
    151      FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL,
    152      FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL,
    153      OLD_FIREFOX_SHELL_OPEN_COMMAND_PATH,
    154      OLD_FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH,
    155    ],
    156    [
    157      FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL,
    158      FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL,
    159      FIREFOX_SHELL_OPEN_COMMAND_PATH,
    160      FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH,
    161    ],
    162  ]) {
    163    let [publicProtocol, privateProtocol, publicPath, privatePath] = protocols;
    164    const applicationPath = "testPath";
    165 
    166    const firefoxEntries = new Map();
    167    firefoxEntries.set("", `\"${applicationPath}\" -osint -url \"%1\"`);
    168 
    169    const firefoxProtocolRegKey = new StubbedRegistryKey(
    170      new Map(),
    171      firefoxEntries
    172    );
    173 
    174    const firefoxPrivateEntries = new Map();
    175    firefoxPrivateEntries.set(
    176      "",
    177      `\"${applicationPath}\" -osint -private-window \"%1\"`
    178    );
    179    const firefoxPrivateProtocolRegKey = new StubbedRegistryKey(
    180      new Map(),
    181      firefoxPrivateEntries
    182    );
    183 
    184    const children = new Map();
    185    children.set(publicPath, firefoxProtocolRegKey);
    186    children.set(privatePath, firefoxPrivateProtocolRegKey);
    187 
    188    const registryRootKey = new StubbedRegistryKey(children, new Map());
    189 
    190    const stubbedDeleteBridgeProtocolRegistryHelper =
    191      new StubbedDeleteBridgeProtocolRegistryEntryHelper({
    192        applicationPath,
    193        registryRootKey,
    194      });
    195 
    196    FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries(
    197      publicProtocol,
    198      privateProtocol,
    199      stubbedDeleteBridgeProtocolRegistryHelper
    200    );
    201 
    202    ok(registryRootKey.wasCloseCalled, "Root key closed");
    203 
    204    ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened");
    205    ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed");
    206    ok(
    207      registryRootKey.isChildDeleted(publicProtocol),
    208      "Firefox protocol registry entry deleted"
    209    );
    210 
    211    ok(
    212      firefoxPrivateProtocolRegKey.wasOpenedForRead,
    213      "Firefox private key opened"
    214    );
    215    ok(
    216      firefoxPrivateProtocolRegKey.wasCloseCalled,
    217      "Firefox private key closed"
    218    );
    219    ok(
    220      registryRootKey.isChildDeleted(privateProtocol),
    221      "Firefox private protocol registry entry deleted"
    222    );
    223  }
    224 });
    225 
    226 add_task(async function test_DeleteWhenDifferentFirefoxInstall() {
    227  for (let protocols of [
    228    [
    229      FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL,
    230      FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL,
    231      OLD_FIREFOX_SHELL_OPEN_COMMAND_PATH,
    232      OLD_FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH,
    233    ],
    234    [
    235      FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL,
    236      FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL,
    237      FIREFOX_SHELL_OPEN_COMMAND_PATH,
    238      FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH,
    239    ],
    240  ]) {
    241    let [publicProtocol, privateProtocol, publicPath, privatePath] = protocols;
    242    const applicationPath = "testPath";
    243    const badApplicationPath = "testPath2";
    244 
    245    const firefoxEntries = new Map();
    246    firefoxEntries.set("", `\"${badApplicationPath}\" -osint -url \"%1\"`);
    247 
    248    const firefoxProtocolRegKey = new StubbedRegistryKey(
    249      new Map(),
    250      firefoxEntries
    251    );
    252 
    253    const firefoxPrivateEntries = new Map();
    254    firefoxPrivateEntries.set(
    255      "",
    256      `\"${badApplicationPath}\" -osint -private-window \"%1\"`
    257    );
    258    const firefoxPrivateProtocolRegKey = new StubbedRegistryKey(
    259      new Map(),
    260      firefoxPrivateEntries
    261    );
    262 
    263    const children = new Map();
    264    children.set(publicPath, firefoxProtocolRegKey);
    265    children.set(privatePath, firefoxPrivateProtocolRegKey);
    266 
    267    const registryRootKey = new StubbedRegistryKey(children, new Map());
    268 
    269    const stubbedDeleteBridgeProtocolRegistryHelper =
    270      new StubbedDeleteBridgeProtocolRegistryEntryHelper({
    271        applicationPath,
    272        registryRootKey,
    273      });
    274 
    275    FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries(
    276      publicProtocol,
    277      privateProtocol,
    278      stubbedDeleteBridgeProtocolRegistryHelper
    279    );
    280 
    281    ok(registryRootKey.wasCloseCalled, "Root key closed");
    282 
    283    ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened");
    284    ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed");
    285    ok(
    286      !registryRootKey.isChildDeleted(publicProtocol),
    287      "Firefox protocol registry entry not deleted"
    288    );
    289 
    290    ok(
    291      firefoxPrivateProtocolRegKey.wasOpenedForRead,
    292      "Firefox private key opened"
    293    );
    294    ok(
    295      firefoxPrivateProtocolRegKey.wasCloseCalled,
    296      "Firefox private key closed"
    297    );
    298    ok(
    299      !registryRootKey.isChildDeleted(privateProtocol),
    300      "Firefox private protocol registry entry not deleted"
    301    );
    302  }
    303 });
    304 
    305 add_task(async function test_DeleteWhenNoRegistryEntries() {
    306  for (let protocols of [
    307    [
    308      FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL,
    309      FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL,
    310      OLD_FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH,
    311    ],
    312    [
    313      FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL,
    314      FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL,
    315      FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH,
    316    ],
    317  ]) {
    318    let [publicProtocol, privateProtocol, privatePath] = protocols;
    319    const applicationPath = "testPath";
    320 
    321    const firefoxPrivateEntries = new Map();
    322    const firefoxPrivateProtocolRegKey = new StubbedRegistryKey(
    323      new Map(),
    324      firefoxPrivateEntries
    325    );
    326 
    327    const children = new Map();
    328    children.set(privatePath, firefoxPrivateProtocolRegKey);
    329 
    330    const registryRootKey = new StubbedRegistryKey(children, new Map());
    331 
    332    const stubbedDeleteBridgeProtocolRegistryHelper =
    333      new StubbedDeleteBridgeProtocolRegistryEntryHelper({
    334        applicationPath,
    335        registryRootKey,
    336      });
    337 
    338    FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries(
    339      publicProtocol,
    340      privateProtocol,
    341      stubbedDeleteBridgeProtocolRegistryHelper
    342    );
    343 
    344    ok(registryRootKey.wasCloseCalled, "Root key closed");
    345 
    346    ok(
    347      firefoxPrivateProtocolRegKey.wasOpenedForRead,
    348      "Firefox private key opened"
    349    );
    350    ok(
    351      firefoxPrivateProtocolRegKey.wasCloseCalled,
    352      "Firefox private key closed"
    353    );
    354    ok(
    355      !registryRootKey.isChildDeleted(publicProtocol),
    356      "Firefox protocol registry entry deleted when it shouldn't be"
    357    );
    358    ok(
    359      !registryRootKey.isChildDeleted(privateProtocol),
    360      "Firefox private protocol registry deleted when it shouldn't be"
    361    );
    362  }
    363 });
    364 
    365 add_task(async function test_DeleteWhenUnexpectedRegistryEntries() {
    366  for (let protocols of [
    367    [
    368      FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL,
    369      FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL,
    370      OLD_FIREFOX_SHELL_OPEN_COMMAND_PATH,
    371    ],
    372    [
    373      FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL,
    374      FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL,
    375      FIREFOX_SHELL_OPEN_COMMAND_PATH,
    376    ],
    377  ]) {
    378    let [publicProtocol, privateProtocol, publicPath] = protocols;
    379    const applicationPath = "testPath";
    380 
    381    const firefoxEntries = new Map();
    382    firefoxEntries.set("", `\"${applicationPath}\" -osint -url \"%1\"`);
    383    firefoxEntries.set("extraEntry", "extraValue");
    384    const firefoxProtocolRegKey = new StubbedRegistryKey(
    385      new Map(),
    386      firefoxEntries
    387    );
    388 
    389    const children = new Map();
    390    children.set(publicPath, firefoxProtocolRegKey);
    391 
    392    const registryRootKey = new StubbedRegistryKey(children, new Map());
    393 
    394    const stubbedDeleteBridgeProtocolRegistryHelper =
    395      new StubbedDeleteBridgeProtocolRegistryEntryHelper({
    396        applicationPath,
    397        registryRootKey,
    398      });
    399 
    400    FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries(
    401      publicProtocol,
    402      privateProtocol,
    403      stubbedDeleteBridgeProtocolRegistryHelper
    404    );
    405 
    406    ok(registryRootKey.wasCloseCalled, "Root key closed");
    407 
    408    ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened");
    409    ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed");
    410    ok(
    411      !registryRootKey.isChildDeleted(publicProtocol),
    412      "Firefox protocol registry entry deleted when it shouldn't be"
    413    );
    414    ok(
    415      !registryRootKey.isChildDeleted(privateProtocol),
    416      "Firefox private protocol registry deleted when it shouldn't be"
    417    );
    418  }
    419 });