tor-browser

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

test_extensionsettings.js (19894B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 "use strict";
      4 
      5 const { AddonTestUtils } = ChromeUtils.importESModule(
      6  "resource://testing-common/AddonTestUtils.sys.mjs"
      7 );
      8 const { AddonManager } = ChromeUtils.importESModule(
      9  "resource://gre/modules/AddonManager.sys.mjs"
     10 );
     11 
     12 AddonTestUtils.init(this);
     13 AddonTestUtils.overrideCertDB();
     14 AddonTestUtils.appInfo = getAppInfo();
     15 AddonTestUtils.usePrivilegedSignatures = false;
     16 ExtensionTestUtils.init(this);
     17 
     18 const server = AddonTestUtils.createHttpServer({ hosts: ["example.com"] });
     19 const BASE_URL = `http://example.com/data`;
     20 
     21 let addonID = "policytest2@mozilla.com";
     22 let themeID = "policytheme@mozilla.com";
     23 let policyOnlyID = "policy_installed_only@mozilla.com";
     24 
     25 let fileURL;
     26 
     27 function waitForAddonInstall(addonId) {
     28  return new Promise(resolve => {
     29    let listener = {
     30      onInstallEnded(install, addon) {
     31        if (addon.id == addonId) {
     32          AddonManager.removeInstallListener(listener);
     33          resolve();
     34        }
     35      },
     36      onDownloadFailed() {
     37        AddonManager.removeInstallListener(listener);
     38        resolve();
     39      },
     40      onInstallFailed() {
     41        AddonManager.removeInstallListener(listener);
     42        resolve();
     43      },
     44    };
     45    AddonManager.addInstallListener(listener);
     46  });
     47 }
     48 
     49 add_setup(async function setup() {
     50  await AddonTestUtils.promiseStartupManager();
     51 
     52  let webExtensionFile = AddonTestUtils.createTempWebExtensionFile({
     53    manifest: {
     54      browser_specific_settings: {
     55        gecko: {
     56          id: addonID,
     57        },
     58      },
     59    },
     60  });
     61  server.registerFile("/data/policy_test.xpi", webExtensionFile);
     62  fileURL = Services.io
     63    .newFileURI(webExtensionFile)
     64    .QueryInterface(Ci.nsIFileURL);
     65 
     66  let policyOnlyExtensionFile = AddonTestUtils.createTempWebExtensionFile({
     67    manifest: {
     68      name: "Enterprise Policy Only Test Extension",
     69      browser_specific_settings: {
     70        gecko: {
     71          id: policyOnlyID,
     72          admin_install_only: true,
     73        },
     74      },
     75    },
     76  });
     77  server.registerFile(
     78    "/data/policy_installed_only.xpi",
     79    policyOnlyExtensionFile
     80  );
     81 
     82  server.registerFile(
     83    "/data/amosigned-sha1only.xpi",
     84    do_get_file("amosigned-sha1only.xpi")
     85  );
     86 });
     87 
     88 add_task(async function test_extensionsettings() {
     89  await setupPolicyEngineWithJson({
     90    policies: {
     91      ExtensionSettings: {
     92        "extension1@mozilla.com": {
     93          blocked_install_message: "Extension1 error message.",
     94        },
     95        "*": {
     96          blocked_install_message: "Generic error message.",
     97        },
     98      },
     99    },
    100  });
    101 
    102  let extensionSettings = Services.policies.getExtensionSettings(
    103    "extension1@mozilla.com"
    104  );
    105  equal(
    106    extensionSettings.blocked_install_message,
    107    "Extension1 error message.",
    108    "Should have extension specific message."
    109  );
    110  extensionSettings = Services.policies.getExtensionSettings(
    111    "extension2@mozilla.com"
    112  );
    113  equal(
    114    extensionSettings.blocked_install_message,
    115    "Generic error message.",
    116    "Should have generic message."
    117  );
    118 });
    119 
    120 add_task(async function test_addon_blocked() {
    121  await setupPolicyEngineWithJson({
    122    policies: {
    123      ExtensionSettings: {
    124        "policytest2@mozilla.com": {
    125          installation_mode: "blocked",
    126        },
    127      },
    128    },
    129  });
    130 
    131  let install = await AddonManager.getInstallForURL(
    132    BASE_URL + "/policy_test.xpi"
    133  );
    134  await install.install();
    135  notEqual(install.addon, null, "Addon should not be null");
    136  equal(install.addon.appDisabled, true, "Addon should be disabled");
    137  await install.addon.uninstall();
    138 });
    139 
    140 add_task(async function test_addon_allowed() {
    141  await setupPolicyEngineWithJson({
    142    policies: {
    143      ExtensionSettings: {
    144        "policytest2@mozilla.com": {
    145          installation_mode: "allowed",
    146        },
    147        "*": {
    148          installation_mode: "blocked",
    149        },
    150      },
    151    },
    152  });
    153 
    154  let install = await AddonManager.getInstallForURL(
    155    BASE_URL + "/policy_test.xpi"
    156  );
    157  await install.install();
    158  notEqual(install.addon, null, "Addon should not be null");
    159  await assertManagementAPIInstallType(install.addon.id, "normal");
    160  equal(install.addon.appDisabled, false, "Addon should not be disabled");
    161  equal(
    162    install.addon.isInstalledByEnterprisePolicy,
    163    false,
    164    "Addon should NOT be marked as installed by enterprise policy"
    165  );
    166 
    167  await install.addon.uninstall();
    168 });
    169 
    170 add_task(async function test_addon_uninstalled() {
    171  let install = await AddonManager.getInstallForURL(
    172    BASE_URL + "/policy_test.xpi"
    173  );
    174  await install.install();
    175  notEqual(install.addon, null, "Addon should not be null");
    176 
    177  await Promise.all([
    178    AddonTestUtils.promiseAddonEvent("onUninstalled"),
    179    setupPolicyEngineWithJson({
    180      policies: {
    181        ExtensionSettings: {
    182          "*": {
    183            installation_mode: "blocked",
    184          },
    185        },
    186      },
    187    }),
    188  ]);
    189  let addon = await AddonManager.getAddonByID(addonID);
    190  equal(addon, null, "Addon should be null");
    191 });
    192 
    193 add_task(async function test_addon_forceinstalled() {
    194  await Promise.all([
    195    AddonTestUtils.promiseInstallEvent("onInstallEnded"),
    196    setupPolicyEngineWithJson({
    197      policies: {
    198        ExtensionSettings: {
    199          "policytest2@mozilla.com": {
    200            installation_mode: "force_installed",
    201            install_url: BASE_URL + "/policy_test.xpi",
    202          },
    203        },
    204      },
    205    }),
    206  ]);
    207  let addon = await AddonManager.getAddonByID(addonID);
    208  notEqual(addon, null, "Addon should not be null");
    209  equal(addon.appDisabled, false, "Addon should not be disabled");
    210  equal(
    211    addon.permissions & AddonManager.PERM_CAN_UNINSTALL,
    212    0,
    213    "Addon should not be able to be uninstalled."
    214  );
    215  equal(
    216    addon.permissions & AddonManager.PERM_CAN_DISABLE,
    217    0,
    218    "Addon should not be able to be disabled."
    219  );
    220  await assertManagementAPIInstallType(addon.id, "admin");
    221 
    222  await addon.uninstall();
    223 });
    224 
    225 add_task(async function test_addon_normalinstalled() {
    226  await Promise.all([
    227    AddonTestUtils.promiseInstallEvent("onInstallEnded"),
    228    setupPolicyEngineWithJson({
    229      policies: {
    230        ExtensionSettings: {
    231          "policytest2@mozilla.com": {
    232            installation_mode: "normal_installed",
    233            install_url: BASE_URL + "/policy_test.xpi",
    234          },
    235        },
    236      },
    237    }),
    238  ]);
    239  let addon = await AddonManager.getAddonByID(addonID);
    240  notEqual(addon, null, "Addon should not be null");
    241  equal(addon.appDisabled, false, "Addon should not be disabled");
    242  equal(
    243    addon.permissions & AddonManager.PERM_CAN_UNINSTALL,
    244    0,
    245    "Addon should not be able to be uninstalled."
    246  );
    247  notEqual(
    248    addon.permissions & AddonManager.PERM_CAN_DISABLE,
    249    0,
    250    "Addon should be able to be disabled."
    251  );
    252  await assertManagementAPIInstallType(addon.id, "admin");
    253 
    254  await addon.uninstall();
    255 });
    256 
    257 add_task(async function test_extensionsettings_string() {
    258  await setupPolicyEngineWithJson({
    259    policies: {
    260      ExtensionSettings: '{"*": {"installation_mode": "blocked"}}',
    261    },
    262  });
    263 
    264  let extensionSettings = Services.policies.getExtensionSettings("*");
    265  equal(extensionSettings.installation_mode, "blocked");
    266 });
    267 
    268 add_task(async function test_extensionsettings_string() {
    269  let restrictedDomains = Services.prefs.getCharPref(
    270    "extensions.webextensions.restrictedDomains"
    271  );
    272  await setupPolicyEngineWithJson({
    273    policies: {
    274      ExtensionSettings:
    275        '{"*": {"restricted_domains": ["example.com","example.org"]}}',
    276    },
    277  });
    278 
    279  let newRestrictedDomains = Services.prefs.getCharPref(
    280    "extensions.webextensions.restrictedDomains"
    281  );
    282  equal(newRestrictedDomains, restrictedDomains + ",example.com,example.org");
    283 });
    284 
    285 add_task(async function test_theme() {
    286  let themeFile = AddonTestUtils.createTempWebExtensionFile({
    287    manifest: {
    288      browser_specific_settings: {
    289        gecko: {
    290          id: themeID,
    291        },
    292      },
    293      theme: {},
    294    },
    295  });
    296 
    297  server.registerFile("/data/policy_theme.xpi", themeFile);
    298 
    299  await Promise.all([
    300    AddonTestUtils.promiseInstallEvent("onInstallEnded"),
    301    setupPolicyEngineWithJson({
    302      policies: {
    303        ExtensionSettings: {
    304          "policytheme@mozilla.com": {
    305            installation_mode: "normal_installed",
    306            install_url: BASE_URL + "/policy_theme.xpi",
    307          },
    308        },
    309      },
    310    }),
    311  ]);
    312  let currentTheme = Services.prefs.getCharPref("extensions.activeThemeID");
    313  equal(currentTheme, themeID, "Theme should be active");
    314  let addon = await AddonManager.getAddonByID(themeID);
    315  await addon.uninstall();
    316 });
    317 
    318 add_task(async function test_addon_normalinstalled_file() {
    319  await Promise.all([
    320    AddonTestUtils.promiseInstallEvent("onInstallEnded"),
    321    setupPolicyEngineWithJson({
    322      policies: {
    323        ExtensionSettings: {
    324          "policytest2@mozilla.com": {
    325            installation_mode: "normal_installed",
    326            install_url: fileURL.spec,
    327          },
    328        },
    329      },
    330    }),
    331  ]);
    332  let addon = await AddonManager.getAddonByID(addonID);
    333  notEqual(addon, null, "Addon should not be null");
    334  equal(addon.appDisabled, false, "Addon should not be disabled");
    335  equal(
    336    addon.permissions & AddonManager.PERM_CAN_UNINSTALL,
    337    0,
    338    "Addon should not be able to be uninstalled."
    339  );
    340  notEqual(
    341    addon.permissions & AddonManager.PERM_CAN_DISABLE,
    342    0,
    343    "Addon should be able to be disabled."
    344  );
    345  await assertManagementAPIInstallType(addon.id, "admin");
    346 
    347  await addon.uninstall();
    348 });
    349 
    350 add_task(async function test_allow_weak_signatures() {
    351  // Make sure weak signatures are restricted.
    352  const resetWeakSignaturePref =
    353    AddonTestUtils.setWeakSignatureInstallAllowed(false);
    354 
    355  const id = "amosigned-xpi@tests.mozilla.org";
    356  const perAddonSettings = {
    357    installation_mode: "normal_installed",
    358    install_url: BASE_URL + "/amosigned-sha1only.xpi",
    359  };
    360 
    361  info(
    362    "Sanity check: expect install to fail if not allowed through enterprise policy settings"
    363  );
    364  await Promise.all([
    365    AddonTestUtils.promiseInstallEvent("onDownloadFailed"),
    366    setupPolicyEngineWithJson({
    367      policies: {
    368        ExtensionSettings: {
    369          [id]: { ...perAddonSettings },
    370        },
    371      },
    372    }),
    373  ]);
    374  let addon = await AddonManager.getAddonByID(id);
    375  equal(addon, null, "Add-on not installed");
    376 
    377  info(
    378    "Expect install to be allowed through per-addon enterprise policy settings"
    379  );
    380  await Promise.all([
    381    AddonTestUtils.promiseInstallEvent("onInstallEnded"),
    382    setupPolicyEngineWithJson({
    383      policies: {
    384        ExtensionSettings: {
    385          [id]: {
    386            ...perAddonSettings,
    387            temporarily_allow_weak_signatures: true,
    388          },
    389        },
    390      },
    391    }),
    392  ]);
    393  addon = await AddonManager.getAddonByID(id);
    394  notEqual(addon, null, "Add-on not installed");
    395  await addon.uninstall();
    396 
    397  info(
    398    "Expect install to be allowed through global enterprise policy settings"
    399  );
    400  await Promise.all([
    401    AddonTestUtils.promiseInstallEvent("onInstallEnded"),
    402    setupPolicyEngineWithJson({
    403      policies: {
    404        ExtensionSettings: {
    405          "*": { temporarily_allow_weak_signatures: true },
    406          [id]: { ...perAddonSettings },
    407        },
    408      },
    409    }),
    410  ]);
    411  addon = await AddonManager.getAddonByID(id);
    412  notEqual(addon, null, "Add-on installed");
    413  await addon.uninstall();
    414 
    415  info(
    416    "Expect install to fail if allowed globally but disallowed by per-addon settings"
    417  );
    418  await Promise.all([
    419    AddonTestUtils.promiseInstallEvent("onDownloadFailed"),
    420    setupPolicyEngineWithJson({
    421      policies: {
    422        ExtensionSettings: {
    423          "*": { temporarily_allow_weak_signatures: true },
    424          [id]: {
    425            ...perAddonSettings,
    426            temporarily_allow_weak_signatures: false,
    427          },
    428        },
    429      },
    430    }),
    431  ]);
    432  addon = await AddonManager.getAddonByID(id);
    433  equal(addon, null, "Add-on not installed");
    434 
    435  info(
    436    "Expect install to be allowed through per addon setting when globally disallowed"
    437  );
    438  await Promise.all([
    439    AddonTestUtils.promiseInstallEvent("onInstallEnded"),
    440    setupPolicyEngineWithJson({
    441      policies: {
    442        ExtensionSettings: {
    443          "*": { temporarily_allow_weak_signatures: false },
    444          [id]: {
    445            ...perAddonSettings,
    446            temporarily_allow_weak_signatures: true,
    447          },
    448        },
    449      },
    450    }),
    451  ]);
    452  addon = await AddonManager.getAddonByID(id);
    453  notEqual(addon, null, "Add-on installed");
    454  await addon.uninstall();
    455 
    456  resetWeakSignaturePref();
    457 });
    458 
    459 add_task(async function test_policy_installed_only_addon() {
    460  const cleanupTestAddon = async () => {
    461    const addon = await AddonManager.getAddonByID(policyOnlyID);
    462    if (addon) {
    463      await addon.uninstall();
    464    }
    465  };
    466  registerCleanupFunction(cleanupTestAddon);
    467 
    468  info(
    469    "Expect the test addon to install successfully when installed by the policy"
    470  );
    471  let installPromise = waitForAddonInstall(policyOnlyID);
    472  await setupPolicyEngineWithJson({
    473    policies: {
    474      ExtensionSettings: {
    475        [policyOnlyID]: {
    476          install_url: `${BASE_URL}/policy_installed_only.xpi`,
    477          installation_mode: "force_installed",
    478          updates_disabled: true,
    479        },
    480      },
    481    },
    482  });
    483  await installPromise;
    484  let addon = await AddonManager.getAddonByID(policyOnlyID);
    485  Assert.notEqual(addon, null, "Addon expected to be installed successfully.");
    486  Assert.deepEqual(
    487    addon.installTelemetryInfo,
    488    { source: "enterprise-policy" },
    489    "Got the expected addon.installTelemetryInfo"
    490  );
    491 
    492  info(
    493    "Remove the ExtensionSettings and verify the addon becomes appDisabled on XPIDatabase.verifySignatures calls"
    494  );
    495  await setupPolicyEngineWithJson({
    496    policies: {
    497      ExtensionSettings: {
    498        // NOTE: an empty ExtensionSettings config would not be reflected
    499        // by data returned by Services.policy.getExtensionSettings calls,
    500        // on the contrary setting new policy data with an unrelated addon-id
    501        // forces the ExtensionSettings data to be refreshed.
    502        "someother-addon@test": { updates_disabled: true },
    503      },
    504    },
    505  });
    506 
    507  {
    508    const { XPIExports } = ChromeUtils.importESModule(
    509      "resource://gre/modules/addons/XPIExports.sys.mjs"
    510    );
    511    await XPIExports.XPIDatabase.verifySignatures();
    512  }
    513 
    514  addon = await AddonManager.getAddonByID(policyOnlyID);
    515  Assert.notEqual(addon, null, "Addon expected to still be installed");
    516  Assert.equal(addon.appDisabled, true, "Expect the addon to be appDisabled");
    517 
    518  await cleanupTestAddon();
    519  addon = await AddonManager.getAddonByID(policyOnlyID);
    520  Assert.equal(addon, null, "Addon expected to not be installed anymore");
    521 
    522  info(
    523    "Expect the test addon to NOT install successfully when not installed by the policy"
    524  );
    525  // Setting back the extension settings with installation_mode set to force_installed
    526  // will install the extension again, and so we need to wait for that and uninstall
    527  // it first (otherwise the addon may endup being installed when the test task is
    528  // completed and trigger an intermittent failure).
    529  installPromise = waitForAddonInstall(policyOnlyID);
    530  await setupPolicyEngineWithJson({
    531    policies: {
    532      ExtensionSettings: {
    533        [policyOnlyID]: {
    534          install_url: `${BASE_URL}/policy_installed_only.xpi`,
    535          installation_mode: "force_installed",
    536          updates_disabled: true,
    537        },
    538      },
    539    },
    540  });
    541  await installPromise;
    542  await cleanupTestAddon();
    543 
    544  await setupPolicyEngineWithJson({
    545    policies: {
    546      ExtensionSettings: {
    547        // NOTE: an empty ExtensionSettings config would not be reflected
    548        // by data returned by Services.policy.getExtensionSettings calls,
    549        // on the contrary setting new policy data with an unrelated addon-id
    550        // forces the ExtensionSettings data to be refreshed.
    551        "someother-addon@test": { updates_disabled: true },
    552      },
    553    },
    554  });
    555 
    556  const { messages } = await AddonTestUtils.promiseConsoleOutput(async () => {
    557    installPromise = waitForAddonInstall(policyOnlyID);
    558    const install = await AddonManager.getInstallForURL(
    559      `${BASE_URL}/policy_installed_only.xpi`,
    560      { telemetryInfo: { source: "not-enterprise-policy" } }
    561    );
    562    await Assert.rejects(
    563      install.install(),
    564      /Install failed/,
    565      "Expect the install method to reject"
    566    );
    567    await installPromise;
    568 
    569    addon = await AddonManager.getAddonByID(policyOnlyID);
    570    Assert.equal(addon, null, "Addon expected to not be installed");
    571  });
    572 
    573  AddonTestUtils.checkMessages(
    574    messages,
    575    {
    576      expected: [
    577        {
    578          message:
    579            /This addon can only be installed through Enterprise Policies/,
    580        },
    581      ],
    582    },
    583    "Got the expect error logged on installing enterprise only extension"
    584  );
    585 });
    586 
    587 add_task(async function test_private_browsing() {
    588  async function assertPrivateBrowsingAccess({
    589    addonId,
    590    extensionSettings,
    591    extensionManifest = {},
    592    expectedPrivateBrowsingAccess,
    593    message,
    594  }) {
    595    await setupPolicyEngineWithJson({
    596      policies: {
    597        ExtensionSettings: {
    598          [addonId]: { ...extensionSettings },
    599        },
    600      },
    601    });
    602 
    603    let ext = ExtensionTestUtils.loadExtension({
    604      manifest: {
    605        browser_specific_settings: {
    606          gecko: { id: addonId },
    607        },
    608        ...extensionManifest,
    609      },
    610      useAddonManager: "temporary",
    611      background() {
    612        browser.test.onMessage.addListener(async msg => {
    613          switch (msg) {
    614            case "checkPrivateBrowsing": {
    615              let isAllowed =
    616                await browser.extension.isAllowedIncognitoAccess();
    617              browser.test.sendMessage("privateBrowsing", isAllowed);
    618              break;
    619            }
    620          }
    621        });
    622      },
    623    });
    624 
    625    await ext.startup();
    626 
    627    ext.sendMessage("checkPrivateBrowsing");
    628    let isAllowedIncognitoAccess = await ext.awaitMessage("privateBrowsing");
    629    Assert.equal(
    630      isAllowedIncognitoAccess,
    631      expectedPrivateBrowsingAccess,
    632      message
    633    );
    634 
    635    let addon = await AddonManager.getAddonByID(ext.id);
    636    // Sanity check (to ensure the test extension used in this test are not privileged).
    637    ok(!addon.isPrivileged, "Addon should not be privileged");
    638 
    639    let expectLocked = typeof extensionSettings?.private_browsing === "boolean";
    640    Assert.equal(
    641      !(
    642        addon.permissions & AddonManager.PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS
    643      ),
    644      expectLocked,
    645      `Addon should ${expectLocked ? "NOT" : ""} be able to change private browsing setting.`
    646    );
    647 
    648    await ext.unload();
    649  }
    650 
    651  await assertPrivateBrowsingAccess({
    652    addonId: "privatebrowsing-granted-nonprivileged@test",
    653    extensionSettings: { private_browsing: true },
    654    expectedPrivateBrowsingAccess: true,
    655    message:
    656      "Should have access to private browsing (set to true in policy extension setting)",
    657  });
    658 
    659  await assertPrivateBrowsingAccess({
    660    addonId: "privatebrowsing-revoked-nonprivileged@test",
    661    extensionSettings: { private_browsing: false },
    662    expectedPrivateBrowsingAccess: false,
    663    message:
    664      "Should NOT have access to private browsing (set to false in policy extension setting)",
    665  });
    666 
    667  await assertPrivateBrowsingAccess({
    668    addonId: "privatebrowsing-nosetting-nonprivileged@test",
    669    extensionSettings: {},
    670    expectedPrivateBrowsingAccess: false,
    671    message:
    672      "Should NOT have access to private browsing (NOT set in policy extension setting)",
    673  });
    674 
    675  await assertPrivateBrowsingAccess({
    676    addonId: "privatebrowsing-notallowed-nonprivileged@test",
    677    extensionSettings: { private_browsing: true },
    678    extensionManifest: {
    679      incognito: "not_allowed",
    680    },
    681    expectedPrivateBrowsingAccess: false,
    682    message:
    683      "incognito 'not_allowed' extensions should NOT have access to private browser",
    684  });
    685 });