diff options
Diffstat (limited to 'browser/components/enterprisepolicies/tests')
116 files changed, 9752 insertions, 0 deletions
diff --git a/browser/components/enterprisepolicies/tests/browser/301.sjs b/browser/components/enterprisepolicies/tests/browser/301.sjs new file mode 100644 index 0000000000..adf0f0891d --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/301.sjs @@ -0,0 +1,8 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +function handleRequest(request, response) { + response.setStatusLine(request.httpVersion, 301, "Moved Permanently"); + response.setHeader("Location", "policy_websitefilter_block.html"); +} diff --git a/browser/components/enterprisepolicies/tests/browser/302.sjs b/browser/components/enterprisepolicies/tests/browser/302.sjs new file mode 100644 index 0000000000..4aee85baac --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/302.sjs @@ -0,0 +1,8 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +function handleRequest(request, response) { + response.setStatusLine(request.httpVersion, 302, "Moved Temporarily"); + response.setHeader("Location", "policy_websitefilter_block.html"); +} diff --git a/browser/components/enterprisepolicies/tests/browser/404.sjs b/browser/components/enterprisepolicies/tests/browser/404.sjs new file mode 100644 index 0000000000..923e8082b1 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/404.sjs @@ -0,0 +1,3 @@ +function handleRequest(request, response) { + response.setStatusLine(request.httpVersion, 404, "Not Found"); +} diff --git a/browser/components/enterprisepolicies/tests/browser/browser.toml b/browser/components/enterprisepolicies/tests/browser/browser.toml new file mode 100644 index 0000000000..25ac681e5b --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser.toml @@ -0,0 +1,122 @@ +[DEFAULT] +support-files = [ + "head.js", + "opensearch.html", + "opensearchEngine.xml", + "policytest_v0.1.xpi", + "policytest_v0.2.xpi", + "policy_websitefilter_block.html", + "policy_websitefilter_exception.html", + "policy_websitefilter_savelink.html", + "../../../../../toolkit/components/antitracking/test/browser/page.html", + "../../../../../toolkit/components/antitracking/test/browser/subResources.sjs", + "extensionsettings.html", + "301.sjs", + "302.sjs", + "404.sjs", +] + +["browser_policies_getActivePolicies.js"] +skip-if = ["os != 'mac'"] + +["browser_policies_notice_in_aboutpreferences.js"] + +["browser_policies_setAndLockPref_API.js"] + +["browser_policy_allowfileselectiondialogs.js"] + +["browser_policy_app_auto_update.js"] +skip-if = ["os == 'win' && msix"] # Updater is disabled in MSIX builds + +["browser_policy_app_update.js"] +skip-if = ["os == 'win' && msix"] # Updater is disabled in MSIX builds + +["browser_policy_background_app_update.js"] +skip-if = ["os == 'win' && msix"] # Updater is disabled in MSIX builds + +["browser_policy_block_about.js"] + +["browser_policy_block_about_support.js"] + +["browser_policy_block_set_desktop_background.js"] + +["browser_policy_bookmarks.js"] + +["browser_policy_cookie_settings.js"] +https_first_disabled = true + +["browser_policy_disable_feedback_commands.js"] + +["browser_policy_disable_fxaccounts.js"] +skip-if = ["verify && debug && os == 'mac'"] + +["browser_policy_disable_masterpassword.js"] + +["browser_policy_disable_password_reveal.js"] + +["browser_policy_disable_pocket.js"] + +["browser_policy_disable_popup_blocker.js"] + +["browser_policy_disable_privatebrowsing.js"] + +["browser_policy_disable_profile_import.js"] + +["browser_policy_disable_profile_reset.js"] + +["browser_policy_disable_safemode.js"] + +["browser_policy_disable_shield.js"] + +["browser_policy_disable_telemetry.js"] + +["browser_policy_display_bookmarks.js"] + +["browser_policy_display_menu.js"] + +["browser_policy_downloads.js"] +support-files = [ + "!/browser/components/downloads/test/browser/foo.txt", + "!/browser/components/downloads/test/browser/foo.txt^headers^", +] + +["browser_policy_extensions.js"] + +["browser_policy_extensionsettings.js"] +https_first_disabled = true + +["browser_policy_extensionsettings2.js"] + +["browser_policy_firefoxhome.js"] + +["browser_policy_firefoxsuggest.js"] + +["browser_policy_handlers.js"] + +["browser_policy_masterpassword.js"] + +["browser_policy_masterpassword_aboutlogins.js"] + +["browser_policy_masterpassword_doorhanger.js"] + +["browser_policy_offertosavelogins.js"] + +["browser_policy_override_postupdatepage.js"] + +["browser_policy_pageinfo_permissions.js"] + +["browser_policy_passwordmanager.js"] + +["browser_policy_search_engine.js"] + +["browser_policy_searchbar.js"] + +["browser_policy_set_homepage.js"] + +["browser_policy_set_startpage.js"] + +["browser_policy_support_menu.js"] + +["browser_policy_usermessaging.js"] + +["browser_policy_websitefilter.js"] diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policies_getActivePolicies.js b/browser/components/enterprisepolicies/tests/browser/browser_policies_getActivePolicies.js new file mode 100644 index 0000000000..547f5e7598 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policies_getActivePolicies.js @@ -0,0 +1,52 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_active_policies() { + await setupPolicyEngineWithJson({ + policies: { + DisablePrivateBrowsing: true, + }, + }); + + let expected = { + DisablePrivateBrowsing: true, + }; + + Assert.deepEqual( + await Services.policies.getActivePolicies(), + expected, + "Active policies parsed correctly" + ); +}); + +add_task(async function test_wrong_policies() { + await setupPolicyEngineWithJson({ + policies: { + BlockAboutSupport: [true], + }, + }); + + let expected = {}; + + Assert.deepEqual( + await Services.policies.getActivePolicies(), + expected, + "Wrong policies ignored" + ); +}); + +add_task(async function test_content_process() { + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () { + try { + Services.policies.getActivePolicies(); + } catch (ex) { + is( + ex.result, + Cr.NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED, + "Function getActivePolicies() doesn't have a valid definition in the content process" + ); + } + }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policies_notice_in_aboutpreferences.js b/browser/components/enterprisepolicies/tests/browser/browser_policies_notice_in_aboutpreferences.js new file mode 100644 index 0000000000..75c17ddf36 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policies_notice_in_aboutpreferences.js @@ -0,0 +1,19 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_notice_in_aboutprefences() { + await setupPolicyEngineWithJson({ + policies: { + DummyPolicy: true, + }, + }); + + await BrowserTestUtils.withNewTab("about:preferences", async browser => { + ok( + !browser.contentDocument.getElementById("policies-container").hidden, + "The Policies notice was made visible in about:preferences" + ); + }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policies_setAndLockPref_API.js b/browser/components/enterprisepolicies/tests/browser/browser_policies_setAndLockPref_API.js new file mode 100644 index 0000000000..0cad8e5aa3 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policies_setAndLockPref_API.js @@ -0,0 +1,179 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +let { Policies, setAndLockPref, PoliciesUtils } = ChromeUtils.importESModule( + "resource:///modules/policies/Policies.sys.mjs" +); + +add_task(async function test_API_directly() { + await setupPolicyEngineWithJson(""); + setAndLockPref("policies.test.boolPref", true); + checkLockedPref("policies.test.boolPref", true); + + // Check that a previously-locked pref can be changed + // (it will be unlocked first). + setAndLockPref("policies.test.boolPref", false); + checkLockedPref("policies.test.boolPref", false); + + setAndLockPref("policies.test.intPref", 2); + checkLockedPref("policies.test.intPref", 2); + + setAndLockPref("policies.test.stringPref", "policies test"); + checkLockedPref("policies.test.stringPref", "policies test"); + + PoliciesUtils.setDefaultPref( + "policies.test.lockedPref", + "policies test", + true + ); + checkLockedPref("policies.test.lockedPref", "policies test"); + + // Test that user values do not override the prefs, and the get*Pref call + // still return the value set through setAndLockPref + Services.prefs.setBoolPref("policies.test.boolPref", true); + checkLockedPref("policies.test.boolPref", false); + + Services.prefs.setIntPref("policies.test.intPref", 10); + checkLockedPref("policies.test.intPref", 2); + + Services.prefs.setStringPref("policies.test.stringPref", "policies test"); + checkLockedPref("policies.test.stringPref", "policies test"); + + try { + // Test that a non-integer value is correctly rejected, even though + // typeof(val) == "number" + setAndLockPref("policies.test.intPref", 1.5); + ok(false, "Integer value should be rejected"); + } catch (ex) { + ok(true, "Integer value was rejected"); + } +}); + +add_task(async function test_API_through_policies() { + // Ensure that the values received by the policies have the correct + // type to make sure things are properly working. + + // Implement functions to handle the three simple policies + // that will be added to the schema. + Policies.bool_policy = { + onBeforeUIStartup(manager, param) { + setAndLockPref("policies.test2.boolPref", param); + }, + }; + + Policies.int_policy = { + onBeforeUIStartup(manager, param) { + setAndLockPref("policies.test2.intPref", param); + }, + }; + + Policies.string_policy = { + onBeforeUIStartup(manager, param) { + setAndLockPref("policies.test2.stringPref", param); + }, + }; + + await setupPolicyEngineWithJson( + // policies.json + { + policies: { + bool_policy: true, + int_policy: 42, + string_policy: "policies test 2", + }, + }, + + // custom schema + { + properties: { + bool_policy: { + type: "boolean", + }, + + int_policy: { + type: "integer", + }, + + string_policy: { + type: "string", + }, + }, + } + ); + + is( + Services.policies.status, + Ci.nsIEnterprisePolicies.ACTIVE, + "Engine is active" + ); + + // The expected values come from config_setAndLockPref.json + checkLockedPref("policies.test2.boolPref", true); + checkLockedPref("policies.test2.intPref", 42); + checkLockedPref("policies.test2.stringPref", "policies test 2"); + + delete Policies.bool_policy; + delete Policies.int_policy; + delete Policies.string_policy; +}); + +add_task(async function test_pref_tracker() { + // Tests the test harness functionality that tracks usage of + // the setAndLockPref and setDefualtPref APIs. + + let defaults = Services.prefs.getDefaultBranch(""); + + // Test prefs that had a default value and got changed to another + defaults.setIntPref("test1.pref1", 10); + defaults.setStringPref("test1.pref2", "test"); + + setAndLockPref("test1.pref1", 20); + PoliciesUtils.setDefaultPref("test1.pref2", "NEW VALUE"); + setAndLockPref("test1.pref3", "NEW VALUE"); + PoliciesUtils.setDefaultPref("test1.pref4", 20); + + PoliciesPrefTracker.restoreDefaultValues(); + + is( + Services.prefs.getIntPref("test1.pref1"), + 10, + "Expected value for test1.pref1" + ); + is( + Services.prefs.getStringPref("test1.pref2"), + "test", + "Expected value for test1.pref2" + ); + is( + Services.prefs.prefIsLocked("test1.pref1"), + false, + "test1.pref1 got unlocked" + ); + ok( + !Services.prefs.getStringPref("test1.pref3", undefined), + "test1.pref3 should have had its value unset" + ); + is( + Services.prefs.getIntPref("test1.pref4", -1), + -1, + "test1.pref4 should have had its value unset" + ); + + // Test a pref that had a default value and a user value + defaults.setIntPref("test2.pref1", 10); + Services.prefs.setIntPref("test2.pref1", 20); + + setAndLockPref("test2.pref1", 20); + + PoliciesPrefTracker.restoreDefaultValues(); + + is(Services.prefs.getIntPref("test2.pref1"), 20, "Correct user value"); + is(defaults.getIntPref("test2.pref1"), 10, "Correct default value"); + is( + Services.prefs.prefIsLocked("test2.pref1"), + false, + "felipe pref is not locked" + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_allowfileselectiondialogs.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_allowfileselectiondialogs.js new file mode 100644 index 0000000000..94f6bba631 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_allowfileselectiondialogs.js @@ -0,0 +1,166 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_setup(async function setup() { + await setupPolicyEngineWithJson({ + policies: { + AllowFileSelectionDialogs: false, + }, + }); +}); + +add_task(async function test_file_commands_disabled() { + // Since testing will apply the policy after the browser has already started, + // we will need to open a new window to actually see changes from the policy + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + + let savePageCommand = newWin.document.getElementById("Browser:SavePage"); + let openFileCommand = newWin.document.getElementById("Browser:OpenFile"); + + Assert.equal( + savePageCommand.getAttribute("disabled"), + "true", + "Browser:SavePage command is disabled" + ); + Assert.equal( + openFileCommand.getAttribute("disabled"), + "true", + "Browser:OpenFile command is disabled" + ); + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_file_buttons_disabled() { + // Since testing will apply the policy after the browser has already started, + // we will need to open a new window to actually see changes from the policy + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + + newWin.CustomizableUI.addWidgetToArea("save-page-button", "nav-bar"); + newWin.CustomizableUI.addWidgetToArea("open-file-button", "nav-bar"); + + let savePageButton = newWin.document.getElementById("save-page-button"); + let openFileButton = newWin.document.getElementById("open-file-button"); + + Assert.equal( + savePageButton.getAttribute("disabled"), + "true", + "save-page-button is disabled" + ); + Assert.equal( + openFileButton.getAttribute("disabled"), + "true", + "open-file-button is disabled" + ); + + newWin.CustomizableUI.reset(); + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_context_menu_items_disabled() { + await BrowserTestUtils.withNewTab("https://example.org/", async browser => { + let contextMenu = document.getElementById("contentAreaContextMenu"); + let promiseContextMenuOpen = BrowserTestUtils.waitForEvent( + contextMenu, + "popupshown" + ); + + await BrowserTestUtils.synthesizeMouse( + "a", + 0, + 0, + { + type: "contextmenu", + button: 2, + centered: true, + }, + browser + ); + + await promiseContextMenuOpen; + + for (let item of [ + "context-saveimage", + "context-savepage", + "context-savelink", + "context-savevideo", + "context-saveaudio", + "context-video-saveimage", + "context-saveaudio", + ]) { + Assert.equal( + document.getElementById(item).disabled, + true, + `${item} item is disabled` + ); + } + + contextMenu.hidePopup(); + }); +}); + +add_task(async function test_notification() { + // Since testing will apply the policy after the browser has already started, + // we will need to open a new window to actually see changes from the policy + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + + await BrowserTestUtils.withNewTab( + { gBrowser: newWin.gBrowser, url: "https://example.org/" }, + async browser => { + await SpecialPowers.spawn(browser, [], async function () { + let elem = content.document.createElement("input"); + elem.setAttribute("type", "file"); + + content.document.notifyUserGestureActivation(); + elem.showPicker(); + }); + + let notificationBox = browser.getTabBrowser().getNotificationBox(browser); + + let notification = await TestUtils.waitForCondition(() => + notificationBox.getNotificationWithValue("filepicker-blocked") + ); + + Assert.ok( + notification, + "filepicker-blocked notification appears when showPicker is called" + ); + } + ); + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_cancel_event() { + await BrowserTestUtils.withNewTab("https://example.org/", async browser => { + let eventType = await SpecialPowers.spawn(browser, [], async function () { + let elem = content.document.createElement("input"); + elem.setAttribute("type", "file"); + let cancelPromise = new Promise(resolve => + elem.addEventListener("cancel", resolve, { once: true }) + ); + content.document.notifyUserGestureActivation(); + elem.showPicker(); + let event = await cancelPromise; + return event.type; + }); + + Assert.equal( + eventType, + "cancel", + "cancel event should be dispatched when showPicker is called" + ); + }); +}); + +add_task(async function test_nsIFilePicker_open() { + let picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); + + picker.init(window, "", Ci.nsIFilePicker.modeSave); + + let result = await new Promise(resolve => picker.open(res => resolve(res))); + + Assert.equal( + result, + Ci.nsIFilePicker.returnCancel, + "nsIFilePicker.open callback should immediately answer returnCancel" + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_app_auto_update.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_app_auto_update.js new file mode 100644 index 0000000000..0cae8369e4 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_app_auto_update.js @@ -0,0 +1,77 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; +ChromeUtils.defineESModuleGetters(this, { + UpdateUtils: "resource://gre/modules/UpdateUtils.sys.mjs", +}); + +async function test_app_update_auto(expectedEnabled, expectedLocked) { + let actualEnabled = await UpdateUtils.getAppUpdateAutoEnabled(); + is( + actualEnabled, + expectedEnabled, + `Actual auto update enabled setting should match the expected value of ${expectedEnabled}` + ); + + let actualLocked = UpdateUtils.appUpdateAutoSettingIsLocked(); + is( + actualLocked, + expectedLocked, + `Auto update enabled setting ${ + expectedLocked ? "should" : "should not" + } be locked` + ); + + let setSuccess = true; + try { + await UpdateUtils.setAppUpdateAutoEnabled(actualEnabled); + } catch (error) { + setSuccess = false; + } + is( + setSuccess, + !expectedLocked, + `Setting auto update ${expectedLocked ? "should" : "should not"} fail` + ); + + await BrowserTestUtils.withNewTab("about:preferences", browser => { + is( + browser.contentDocument.getElementById("updateSettingsContainer").hidden, + expectedLocked, + `When auto update ${ + expectedLocked ? "is" : "isn't" + } locked, the corresponding preferences entry ${ + expectedLocked ? "should" : "shouldn't" + } be hidden` + ); + }); +} + +add_task(async function test_app_auto_update_policy() { + let originalUpdateAutoValue = await UpdateUtils.getAppUpdateAutoEnabled(); + registerCleanupFunction(async () => { + await UpdateUtils.setAppUpdateAutoEnabled(originalUpdateAutoValue); + }); + + await UpdateUtils.setAppUpdateAutoEnabled(true); + await test_app_update_auto(true, false); + + await setupPolicyEngineWithJson({ + policies: { + AppAutoUpdate: false, + }, + }); + await test_app_update_auto(false, true); + + await setupPolicyEngineWithJson({}); + await UpdateUtils.setAppUpdateAutoEnabled(false); + await test_app_update_auto(false, false); + + await setupPolicyEngineWithJson({ + policies: { + AppAutoUpdate: true, + }, + }); + await test_app_update_auto(true, true); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_app_update.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_app_update.js new file mode 100644 index 0000000000..14a9c92bc5 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_app_update.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; +ChromeUtils.defineESModuleGetters(this, { + UpdateUtils: "resource://gre/modules/UpdateUtils.sys.mjs", +}); +var updateService = Cc["@mozilla.org/updates/update-service;1"].getService( + Ci.nsIApplicationUpdateService +); + +// This test is intended to ensure that nsIUpdateService::canCheckForUpdates +// is true before the "DisableAppUpdate" policy is applied. Testing that +// nsIUpdateService::canCheckForUpdates is false after the "DisableAppUpdate" +// policy is applied needs to occur in a different test since the policy does +// not properly take effect unless it is applied during application startup. +add_task(async function test_updates_pre_policy() { + // Turn off automatic update before we set app.update.disabledForTesting to + // false so that we don't cause an actual update. + let originalUpdateAutoValue = await UpdateUtils.getAppUpdateAutoEnabled(); + await UpdateUtils.setAppUpdateAutoEnabled(false); + registerCleanupFunction(async () => { + await UpdateUtils.setAppUpdateAutoEnabled(originalUpdateAutoValue); + }); + + await SpecialPowers.pushPrefEnv({ + set: [["app.update.disabledForTesting", false]], + }); + + is( + Services.policies.isAllowed("appUpdate"), + true, + "Since no policies have been set, appUpdate should be allowed by default" + ); + + is( + updateService.canCheckForUpdates, + true, + "Should be able to check for updates before any policies are in effect." + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_background_app_update.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_background_app_update.js new file mode 100644 index 0000000000..a529e79be7 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_background_app_update.js @@ -0,0 +1,99 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + UpdateUtils: "resource://gre/modules/UpdateUtils.sys.mjs", +}); + +const PREF_NAME = "app.update.background.enabled"; + +async function test_background_update_pref(expectedEnabled, expectedLocked) { + let actualEnabled = await UpdateUtils.readUpdateConfigSetting(PREF_NAME); + is( + actualEnabled, + expectedEnabled, + `Actual background update enabled setting should be ${expectedEnabled}` + ); + + let actualLocked = UpdateUtils.appUpdateSettingIsLocked(PREF_NAME); + is( + actualLocked, + expectedLocked, + `Background update enabled setting ${ + expectedLocked ? "should" : "should not" + } be locked` + ); + + let setSuccess = true; + try { + await UpdateUtils.writeUpdateConfigSetting(PREF_NAME, actualEnabled); + } catch (error) { + setSuccess = false; + } + is( + setSuccess, + !expectedLocked, + `Setting background update pref ${ + expectedLocked ? "should" : "should not" + } fail` + ); + + if (AppConstants.MOZ_UPDATE_AGENT) { + let shouldShowUI = + !expectedLocked && UpdateUtils.PER_INSTALLATION_PREFS_SUPPORTED; + await BrowserTestUtils.withNewTab("about:preferences", browser => { + is( + browser.contentDocument.getElementById("backgroundUpdate").hidden, + !shouldShowUI, + `When background update ${ + expectedLocked ? "is" : "isn't" + } locked, and per-installation prefs ${ + UpdateUtils.PER_INSTALLATION_PREFS_SUPPORTED ? "are" : "aren't" + } supported, the corresponding preferences entry ${ + shouldShowUI ? "shouldn't" : "should" + } be hidden` + ); + }); + } else { + // The backgroundUpdate element is #ifdef'ed out if MOZ_UPDATER and + // MOZ_UPDATE_AGENT are not both defined. + info( + "Warning: UI testing skipped because support for background update is " + + "not present" + ); + } +} + +add_task(async function test_background_app_update_policy() { + const origBackgroundUpdateVal = await UpdateUtils.readUpdateConfigSetting( + PREF_NAME + ); + registerCleanupFunction(async () => { + await UpdateUtils.writeUpdateConfigSetting( + PREF_NAME, + origBackgroundUpdateVal + ); + }); + + await UpdateUtils.writeUpdateConfigSetting(PREF_NAME, true); + await test_background_update_pref(true, false); + + await setupPolicyEngineWithJson({ + policies: { + BackgroundAppUpdate: false, + }, + }); + await test_background_update_pref(false, true); + + await setupPolicyEngineWithJson({}); + await UpdateUtils.writeUpdateConfigSetting(PREF_NAME, false); + await test_background_update_pref(false, false); + + await setupPolicyEngineWithJson({ + policies: { + BackgroundAppUpdate: true, + }, + }); + await test_background_update_pref(true, true); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_block_about.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_block_about.js new file mode 100644 index 0000000000..1c8956356f --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_block_about.js @@ -0,0 +1,50 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const ABOUT_CONTRACT = "@mozilla.org/network/protocol/about;1?what="; + +const policiesToTest = [ + { + policies: { + BlockAboutAddons: true, + }, + urls: ["about:addons", "about:ADDONS"], + }, + { + policies: { + BlockAboutConfig: true, + }, + urls: ["about:config", "about:Config"], + }, + { + policies: { + BlockAboutProfiles: true, + }, + urls: ["about:profiles", "about:pRofiles"], + }, + { + policies: { + BlockAboutSupport: true, + }, + urls: ["about:support", "about:suPPort"], + }, +]; + +add_task(async function testAboutTask() { + for (let policyToTest of policiesToTest) { + let policyJSON = { policies: {} }; + policyJSON.policies = policyToTest.policies; + for (let url of policyToTest.urls) { + if (url.startsWith("about")) { + let feature = url.split(":")[1].toLowerCase(); + let aboutModule = Cc[ABOUT_CONTRACT + feature].getService( + Ci.nsIAboutModule + ); + let chromeURL = aboutModule.getChromeURI(Services.io.newURI(url)).spec; + await testPageBlockedByPolicy(chromeURL, policyJSON); + } + await testPageBlockedByPolicy(url, policyJSON); + } + } +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_block_about_support.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_block_about_support.js new file mode 100644 index 0000000000..925aa0cdfd --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_block_about_support.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +add_setup(async function () { + await setupPolicyEngineWithJson({ + policies: { + BlockAboutSupport: true, + }, + }); +}); + +add_task(async function test_help_menu() { + buildHelpMenu(); + let troubleshootingInfoMenu = document.getElementById("troubleShooting"); + is( + troubleshootingInfoMenu.getAttribute("disabled"), + "true", + "The `More Troubleshooting Information` item should be disabled" + ); +}); + +add_task(async function test_about_memory() { + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:memory" + ); + + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + let aboutSupportLink = content.document.querySelector( + "a[href='about:support']" + ); + + Assert.ok( + !aboutSupportLink, + "The link to about:support at the bottom of the page should not exist" + ); + }); + + await BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_block_set_desktop_background.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_block_set_desktop_background.js new file mode 100644 index 0000000000..0a36fee5a8 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_block_set_desktop_background.js @@ -0,0 +1,50 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +add_setup(async function () { + await setupPolicyEngineWithJson({ + policies: { + DisableSetDesktopBackground: true, + }, + }); +}); + +add_task(async function test_check_set_desktop_background() { + const imageUrl = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gwMDAsTBZbkNwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABNElEQVQ4y8WSsU0DURBE3yyWIaAJaqAAN4DPSL6AlIACKIEOyJEgRsIgOOkiInJqgAKowNg7BHdn7MOksNl+zZ//dvbDf5cAiklp22BdVtXdeTEpDYDB9m1VzU6OJuVp2NdEQCaI96fH2YHG4+mDduKYNMYINTcjcGbXzQVDEAphG0k48zUsajIbnAiMIXThpW8EICE0RAK4dvoKg9NIcTiQ589otyHOZLnwqK5nLwBFUZ4igc3iM0d1ff8CMC6mZ6Ihiaqq3gi1aUAnArD00SW1fq5OLBg0ymYmSZsR2/t4e/rGyCLW0sbp3oq+yTYqVgytQWui2FS7XYF7GFprY921T4CNQt8zr47dNzCkIX7y/jBtH+v+RGMQrc828W8pApnZbmEVQp/Ae7BlOy2ttib81/UFc+WRWEbjckIAAAAASUVORK5CYII="; + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + imageUrl, + true + ); + + // Right click on the image and wait for the context menu to open + let contextMenu = document.getElementById("contentAreaContextMenu"); + let promiseContextMenuOpen = BrowserTestUtils.waitForEvent( + contextMenu, + "popupshown" + ); + await BrowserTestUtils.synthesizeMouse( + "img", + 0, + 0, + { + type: "contextmenu", + button: 2, + centered: true, + }, + gBrowser.selectedBrowser + ); + await promiseContextMenuOpen; + info("Context Menu Shown"); + + let buttonElement = document.getElementById("context-setDesktopBackground"); + is( + buttonElement.hidden, + true, + 'The "Set Desktop Background" context menu element should be hidden' + ); + contextMenu.hidePopup(); + BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_bookmarks.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_bookmarks.js new file mode 100644 index 0000000000..36435d0b5b --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_bookmarks.js @@ -0,0 +1,316 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const FAVICON_DATA = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gwMDAsTBZbkNwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABNElEQVQ4y8WSsU0DURBE3yyWIaAJaqAAN4DPSL6AlIACKIEOyJEgRsIgOOkiInJqgAKowNg7BHdn7MOksNl+zZ//dvbDf5cAiklp22BdVtXdeTEpDYDB9m1VzU6OJuVp2NdEQCaI96fH2YHG4+mDduKYNMYINTcjcGbXzQVDEAphG0k48zUsajIbnAiMIXThpW8EICE0RAK4dvoKg9NIcTiQ589otyHOZLnwqK5nLwBFUZ4igc3iM0d1ff8CMC6mZ6Ihiaqq3gi1aUAnArD00SW1fq5OLBg0ymYmSZsR2/t4e/rGyCLW0sbp3oq+yTYqVgytQWui2FS7XYF7GFprY921T4CNQt8zr47dNzCkIX7y/jBtH+v+RGMQrc828W8pApnZbmEVQp/Ae7BlOy2ttib81/UFc+WRWEbjckIAAAAASUVORK5CYII="; + +const { BookmarksPolicies } = ChromeUtils.importESModule( + "resource:///modules/policies/BookmarksPolicies.sys.mjs" +); + +let CURRENT_POLICY; + +const basePath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://mochi.test:8888" +); + +const BASE_POLICY = { + policies: { + DisplayBookmarksToolbar: true, + Bookmarks: [ + { + Title: "Bookmark 1", + URL: "https://bookmark1.example.com/", + Favicon: FAVICON_DATA, + }, + { + Title: "Bookmark 2", + URL: "https://bookmark2.example.com/", + Favicon: `${basePath}/404.sjs`, + }, + { + Title: "Bookmark 3", + URL: "https://bookmark3.example.com/", + Folder: "Folder 1", + }, + { + Title: "Bookmark 4", + URL: "https://bookmark4.example.com/", + Placement: "menu", + }, + { + Title: "Bookmark 5", + URL: "https://bookmark5.example.com/", + Folder: "Folder 1", + }, + { + Title: "Bookmark 6", + URL: "https://bookmark6.example.com/", + Placement: "menu", + Folder: "Folder 2", + }, + ], + }, +}; + +/* + * ================================= + * = HELPER FUNCTIONS FOR THE TEST = + * ================================= + */ +function deepClone(obj) { + return JSON.parse(JSON.stringify(obj)); +} + +function findBookmarkInPolicy(bookmark) { + // Find the entry in the given policy that corresponds + // to this bookmark object from Places. + for (let entry of CURRENT_POLICY.policies.Bookmarks) { + if (entry.Title == bookmark.title) { + return entry; + } + } + return null; +} + +async function promiseAllChangesMade({ itemsToAdd, itemsToRemove }) { + return new Promise(resolve => { + let listener = events => { + for (const event of events) { + switch (event.type) { + case "bookmark-added": + itemsToAdd--; + if (itemsToAdd == 0 && itemsToRemove == 0) { + PlacesUtils.observers.removeListener( + ["bookmark-added", "bookmark-removed"], + listener + ); + resolve(); + } + break; + case "bookmark-removed": + itemsToRemove--; + if (itemsToAdd == 0 && itemsToRemove == 0) { + PlacesUtils.observers.removeListener( + ["bookmark-added", "bookmark-removed"], + listener + ); + resolve(); + } + break; + } + } + }; + PlacesUtils.observers.addListener( + ["bookmark-added", "bookmark-removed"], + listener + ); + }); +} + +/* + * ================== + * = CHECK FUNCTION = + * ================== + * + * Performs all the checks comparing what was given in + * the policy JSON with what was retrieved from Places. + */ +async function check({ expectedNumberOfFolders }) { + let bookmarks = [], + folders = []; + + await PlacesUtils.bookmarks.fetch( + { guidPrefix: BookmarksPolicies.BOOKMARK_GUID_PREFIX }, + r => { + bookmarks.push(r); + } + ); + await PlacesUtils.bookmarks.fetch( + { guidPrefix: BookmarksPolicies.FOLDER_GUID_PREFIX }, + r => { + folders.push(r); + } + ); + + let foldersToGuids = new Map(); + + for (let folder of folders) { + is( + folder.type, + PlacesUtils.bookmarks.TYPE_FOLDER, + "Correct type for folder" + ); + foldersToGuids.set(folder.title, folder.guid); + } + + // For simplification and accuracy purposes, the number of expected + // folders is manually specified in the test. + is( + folders.length, + expectedNumberOfFolders, + "Correct number of folders expected" + ); + is( + foldersToGuids.size, + expectedNumberOfFolders, + "There aren't two different folders with the same name" + ); + + is( + CURRENT_POLICY.policies.Bookmarks.length, + bookmarks.length, + "The correct number of bookmarks exist" + ); + + for (let bookmark of bookmarks) { + is( + bookmark.type, + PlacesUtils.bookmarks.TYPE_BOOKMARK, + "Correct type for bookmark" + ); + + let entry = findBookmarkInPolicy(bookmark); + + is(bookmark.title, entry.Title, "Title matches"); + is(bookmark.url.href, entry.URL, "URL matches"); + + let expectedPlacementGuid; + if (entry.Folder) { + expectedPlacementGuid = foldersToGuids.get(entry.Folder); + } else { + expectedPlacementGuid = + entry.Placement == "menu" + ? PlacesUtils.bookmarks.menuGuid + : PlacesUtils.bookmarks.toolbarGuid; + } + + is(bookmark.parentGuid, expectedPlacementGuid, "Correctly placed"); + } +} + +/* + * ================ + * = ACTUAL TESTS = + * ================ + * + * Note: the order of these tests is important, as we want to test not + * only the end result of each configuration, but also the diff algorithm + * that will add or remove bookmarks depending on how the policy changed. + */ + +add_task(async function test_initial_bookmarks() { + // Make a copy of the policy because we will be adding/removing entries from it + CURRENT_POLICY = deepClone(BASE_POLICY); + + await Promise.all([ + promiseAllChangesMade({ + itemsToAdd: 8, // 6 bookmarks + 2 folders + itemsToRemove: 0, + }), + setupPolicyEngineWithJson(CURRENT_POLICY), + ]); + + await check({ expectedNumberOfFolders: 2 }); +}); + +add_task(async function checkFavicon() { + let bookmark1url = CURRENT_POLICY.policies.Bookmarks[0].URL; + + let result = await new Promise(resolve => { + PlacesUtils.favicons.getFaviconDataForPage( + Services.io.newURI(bookmark1url), + (uri, _, data) => resolve({ uri, data }) + ); + }); + + is( + result.uri.spec, + "fake-favicon-uri:" + bookmark1url, + "Favicon URI is correct" + ); + // data is an array of octets, which will be a bit hard to compare against + // FAVICON_DATA, which is base64 encoded. Checking the expected length should + // be good indication that this is working properly. + is(result.data.length, 464, "Favicon data has the correct length"); + + let faviconsExpiredNotification = TestUtils.topicObserved( + "places-favicons-expired" + ); + PlacesUtils.favicons.expireAllFavicons(); + await faviconsExpiredNotification; +}); + +add_task(async function test_remove_Bookmark_2() { + // Continuing from the previous policy: + // + // Remove the 2nd bookmark. It is inside "Folder 1", but that + // folder won't be empty, so it must not be removed. + CURRENT_POLICY.policies.Bookmarks.splice(3, 1); + + await Promise.all([ + promiseAllChangesMade({ + itemsToAdd: 0, + itemsToRemove: 1, // 1 bookmark + }), + setupPolicyEngineWithJson(CURRENT_POLICY), + ]); + + await check({ expectedNumberOfFolders: 2 }); +}); + +add_task(async function test_remove_Bookmark_5() { + // Continuing from the previous policy: + // + // Remove the last bookmark in the policy, + // which means the "Folder 2" should also disappear + CURRENT_POLICY.policies.Bookmarks.splice(-1, 1); + + await Promise.all([ + promiseAllChangesMade({ + itemsToAdd: 0, + itemsToRemove: 2, // 1 bookmark and 1 folder + }), + setupPolicyEngineWithJson(CURRENT_POLICY), + ]); + + await check({ expectedNumberOfFolders: 1 }); +}); + +add_task(async function test_revert_to_original_policy() { + CURRENT_POLICY = deepClone(BASE_POLICY); + + // Reverts to the original policy, which means that: + // - "Bookmark 2" + // - "Bookmark 5" + // - "Folder 2" + // should be recreated + await Promise.all([ + promiseAllChangesMade({ + itemsToAdd: 3, // 2 bookmarks and 1 folder + itemsToRemove: 0, + }), + setupPolicyEngineWithJson(CURRENT_POLICY), + ]); + + await check({ expectedNumberOfFolders: 2 }); +}); + +// Leave this one at the end, so that it cleans up any +// bookmarks created during this test. +add_task(async function test_empty_all_bookmarks() { + CURRENT_POLICY = { policies: { Bookmarks: [] } }; + + await Promise.all([ + promiseAllChangesMade({ + itemsToAdd: 0, + itemsToRemove: 8, // 6 bookmarks and 2 folders + }), + setupPolicyEngineWithJson(CURRENT_POLICY), + ]); + + check({ expectedNumberOfFolders: 0 }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js new file mode 100644 index 0000000000..3657a8f34f --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js @@ -0,0 +1,339 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const { UrlClassifierTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/UrlClassifierTestUtils.sys.mjs" +); +Services.cookies.QueryInterface(Ci.nsICookieService); + +function restore_prefs() { + Services.prefs.clearUserPref("network.cookie.cookieBehavior"); + Services.prefs.clearUserPref( + "network.cookieJarSettings.unblocked_for_testing" + ); +} + +registerCleanupFunction(restore_prefs); + +async function fake_profile_change() { + await new Promise(resolve => { + Services.obs.addObserver(function waitForDBClose() { + Services.obs.removeObserver(waitForDBClose, "cookie-db-closed"); + resolve(); + }, "cookie-db-closed"); + Services.cookies + .QueryInterface(Ci.nsIObserver) + .observe(null, "profile-before-change", null); + }); + await new Promise(resolve => { + Services.obs.addObserver(function waitForDBOpen() { + Services.obs.removeObserver(waitForDBOpen, "cookie-db-read"); + resolve(); + }, "cookie-db-read"); + Services.cookies + .QueryInterface(Ci.nsIObserver) + .observe(null, "profile-do-change", ""); + }); +} + +async function test_cookie_settings({ + cookiesEnabled, + thirdPartyCookiesEnabled, + rejectTrackers, + cookieJarSettingsLocked, +}) { + let firstPartyURI = NetUtil.newURI("https://example.com/"); + let thirdPartyURI = NetUtil.newURI("https://example.org/"); + let channel = NetUtil.newChannel({ + uri: firstPartyURI, + loadUsingSystemPrincipal: true, + }); + channel.QueryInterface( + Ci.nsIHttpChannelInternal + ).forceAllowThirdPartyCookie = true; + Services.cookies.removeAll(); + Services.cookies.setCookieStringFromHttp( + firstPartyURI, + "key=value; SameSite=None; Secure;", + channel + ); + Services.cookies.setCookieStringFromHttp( + thirdPartyURI, + "key=value; SameSite=None; Secure;", + channel + ); + + let expectedFirstPartyCookies = 1; + let expectedThirdPartyCookies = 1; + if (!cookiesEnabled) { + expectedFirstPartyCookies = 0; + } + if (!cookiesEnabled || !thirdPartyCookiesEnabled) { + expectedThirdPartyCookies = 0; + } + is( + Services.cookies.countCookiesFromHost(firstPartyURI.host), + expectedFirstPartyCookies, + "Number of first-party cookies should match expected" + ); + is( + Services.cookies.countCookiesFromHost(thirdPartyURI.host), + expectedThirdPartyCookies, + "Number of third-party cookies should match expected" + ); + + // Add a cookie so we can check if it persists past the end of the session + // but, first remove existing cookies set by this host to put us in a known state + Services.cookies.removeAll(); + Services.cookies.setCookieStringFromHttp( + firstPartyURI, + "key=value; max-age=1000; SameSite=None; Secure;", + channel + ); + + await fake_profile_change(); + + // Now check if the cookie persisted or not + let expectedCookieCount = 1; + if (!cookiesEnabled) { + expectedCookieCount = 0; + } + is( + Services.cookies.countCookiesFromHost(firstPartyURI.host), + expectedCookieCount, + "Number of cookies was not what expected after restarting session" + ); + + is( + Services.prefs.prefIsLocked("network.cookie.cookieBehavior"), + cookieJarSettingsLocked, + "Cookie behavior pref lock status should be what is expected" + ); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:preferences" + ); + + BrowserTestUtils.removeTab(tab); + + if (rejectTrackers) { + tab = await BrowserTestUtils.addTab( + gBrowser, + "http://example.net/browser/browser/components/enterprisepolicies/tests/browser/page.html" + ); + let browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + // Load the script twice + { + let src = content.document.createElement("script"); + let p = new content.Promise((resolve, reject) => { + src.onload = resolve; + src.onerror = reject; + }); + content.document.body.appendChild(src); + src.src = + "https://tracking.example.org/browser/browser/components/enterprisepolicies/tests/browser/subResources.sjs?what=script"; + await p; + } + { + let src = content.document.createElement("script"); + let p = new content.Promise(resolve => { + src.onload = resolve; + }); + content.document.body.appendChild(src); + src.src = + "https://tracking.example.org/browser/browser/components/enterprisepolicies/tests/browser/subResources.sjs?what=script"; + await p; + } + }); + BrowserTestUtils.removeTab(tab); + await fetch( + "https://tracking.example.org/browser/browser/components/enterprisepolicies/tests/browser/subResources.sjs?result&what=script" + ) + .then(r => r.text()) + .then(text => { + is(text, "0", '"Reject Tracker" pref should match what is expected'); + }); + } +} + +add_task(async function prepare_tracker_tables() { + await UrlClassifierTestUtils.addTestTrackers(); +}); + +add_task(async function test_initial_state() { + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + await test_cookie_settings({ + cookiesEnabled: true, + thirdPartyCookiesEnabled: true, + cookieJarSettingsLocked: false, + }); + restore_prefs(); +}); + +add_task(async function test_undefined_unlocked() { + Services.prefs.setIntPref("network.cookie.cookieBehavior", 3); + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + await setupPolicyEngineWithJson({ + policies: { + Cookies: {}, + }, + }); + is( + Services.prefs.getIntPref("network.cookie.cookieBehavior", undefined), + 3, + "An empty cookie policy should not have changed the cookieBehavior preference" + ); + restore_prefs(); +}); + +add_task(async function test_disabled() { + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + await setupPolicyEngineWithJson({ + policies: { + Cookies: { + Default: false, + }, + }, + }); + + await test_cookie_settings({ + cookiesEnabled: false, + thirdPartyCookiesEnabled: true, + cookieJarSettingsLocked: false, + }); + restore_prefs(); +}); + +add_task(async function test_third_party_disabled() { + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + await setupPolicyEngineWithJson({ + policies: { + Cookies: { + AcceptThirdParty: "never", + }, + }, + }); + + await test_cookie_settings({ + cookiesEnabled: true, + thirdPartyCookiesEnabled: false, + cookieJarSettingsLocked: false, + }); + restore_prefs(); +}); + +add_task(async function test_disabled_and_third_party_disabled() { + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + await setupPolicyEngineWithJson({ + policies: { + Cookies: { + Default: false, + AcceptThirdParty: "never", + }, + }, + }); + + await test_cookie_settings({ + cookiesEnabled: false, + thirdPartyCookiesEnabled: false, + cookieJarSettingsLocked: false, + }); + restore_prefs(); +}); + +add_task(async function test_disabled_and_third_party_disabled_locked() { + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + await setupPolicyEngineWithJson({ + policies: { + Cookies: { + Default: false, + AcceptThirdParty: "never", + Locked: true, + }, + }, + }); + + await test_cookie_settings({ + cookiesEnabled: false, + thirdPartyCookiesEnabled: false, + cookieJarSettingsLocked: true, + }); + restore_prefs(); +}); + +add_task(async function test_undefined_locked() { + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + await setupPolicyEngineWithJson({ + policies: { + Cookies: { + Locked: true, + }, + }, + }); + + await test_cookie_settings({ + cookiesEnabled: true, + thirdPartyCookiesEnabled: true, + cookieJarSettingsLocked: true, + }); + restore_prefs(); +}); + +add_task(async function test_cookie_reject_trackers() { + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + await setupPolicyEngineWithJson({ + policies: { + Cookies: { + RejectTracker: true, + }, + }, + }); + + await test_cookie_settings({ + cookiesEnabled: true, + thirdPartyCookiesEnabled: true, + rejectTrackers: true, + cookieJarSettingsLocked: false, + }); + restore_prefs(); +}); + +add_task(async function prepare_tracker_tables() { + await UrlClassifierTestUtils.cleanupTestTrackers(); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_feedback_commands.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_feedback_commands.js new file mode 100644 index 0000000000..b89788e1cf --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_feedback_commands.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* the buidHelpMenu() function comes from browser/base/content/utilityOverlay.js */ + +const NORMAL_PAGE = "http://example.com"; +const PHISH_PAGE = "http://www.itisatrap.org/firefox/its-a-trap.html"; + +async function checkItemsAreDisabled(url) { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + // The phishing page doesn't send a load notification + waitForLoad: false, + waitForStateStop: true, + }, + async function checkItems() { + buildHelpMenu(); + + let reportMenu = document.getElementById( + "menu_HelpPopup_reportPhishingtoolmenu" + ); + is( + reportMenu.getAttribute("disabled"), + "true", + "The `Report Deceptive Site` item should be disabled" + ); + + let errorMenu = document.getElementById( + "menu_HelpPopup_reportPhishingErrortoolmenu" + ); + is( + errorMenu.getAttribute("disabled"), + "true", + "The `This isn’t a deceptive site` item should be disabled" + ); + } + ); +} + +add_task(async function test_policy_feedback_commands() { + await setupPolicyEngineWithJson({ + policies: { + DisableFeedbackCommands: true, + }, + }); + + /* from browser/base/content/utilityOverlay.js */ + buildHelpMenu(); + + let feedbackPageMenu = document.getElementById("feedbackPage"); + is( + feedbackPageMenu.getAttribute("disabled"), + "true", + "The `Submit Feedback...` item should be disabled" + ); + + await checkItemsAreDisabled(NORMAL_PAGE); + await checkItemsAreDisabled(PHISH_PAGE); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_fxaccounts.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_fxaccounts.js new file mode 100644 index 0000000000..a2cd9a3baa --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_fxaccounts.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_policy_disable_fxaccounts() { + await setupPolicyEngineWithJson({}); + + is(gSync.FXA_ENABLED, true, "Sync is enabled before setting the policy."); + + await setupPolicyEngineWithJson({ + policies: { + DisableFirefoxAccounts: true, + }, + }); + + is(gSync.FXA_ENABLED, false, "Sync is disabled after setting the policy."); +}); + +add_task(async function test_policy_disable_accounts() { + await setupPolicyEngineWithJson({}); + + is(gSync.FXA_ENABLED, true, "Sync is enabled before setting the policy."); + + await setupPolicyEngineWithJson({ + policies: { + DisableAccounts: true, + }, + }); + + is(gSync.FXA_ENABLED, false, "Sync is disabled after setting the policy."); +}); + +add_task(async function test_both_disable_accounts_policies() { + await setupPolicyEngineWithJson({}); + + is(gSync.FXA_ENABLED, true, "Sync is enabled before setting the policy."); + + // When both accounts policies are set, DisableAccounts should take precedence. + await setupPolicyEngineWithJson({ + policies: { + DisableFirefoxAccounts: false, + DisableAccounts: true, + }, + }); + + is(gSync.FXA_ENABLED, false, "Sync is disabled after setting the policy."); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js new file mode 100644 index 0000000000..7f3748fdc5 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js @@ -0,0 +1,90 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const MASTER_PASSWORD = "omgsecret!"; +const mpToken = Cc["@mozilla.org/security/pk11tokendb;1"] + .getService(Ci.nsIPK11TokenDB) + .getInternalKeyToken(); + +async function checkDeviceManager({ buttonIsDisabled }) { + let deviceManagerWindow = window.openDialog( + "chrome://pippki/content/device_manager.xhtml", + "", + "" + ); + await BrowserTestUtils.waitForEvent(deviceManagerWindow, "load"); + + let tree = deviceManagerWindow.document.getElementById("device_tree"); + ok(tree, "The device tree exists"); + + // Find and select the item related to the internal key token + for (let i = 0; i < tree.view.rowCount; i++) { + tree.view.selection.select(i); + + try { + let selected_token = deviceManagerWindow.selected_slot.getToken(); + if (selected_token.isInternalKeyToken) { + break; + } + } catch (e) {} + } + + // Check to see if the button was updated correctly + let changePwButton = + deviceManagerWindow.document.getElementById("change_pw_button"); + is( + changePwButton.getAttribute("disabled") == "true", + buttonIsDisabled, + "Change Password button is in the correct state: " + buttonIsDisabled + ); + + await BrowserTestUtils.closeWindow(deviceManagerWindow); +} + +async function checkAboutPreferences({ checkboxIsDisabled }) { + await BrowserTestUtils.withNewTab( + "about:preferences#privacy", + async browser => { + is( + browser.contentDocument.getElementById("useMasterPassword").disabled, + checkboxIsDisabled, + "Master Password checkbox is in the correct state: " + + checkboxIsDisabled + ); + } + ); +} + +add_task(async function test_policy_disable_masterpassword() { + ok(!mpToken.hasPassword, "Starting the test with no password"); + + // No password and no policy: access to setting a primary password + // should be enabled. + await checkDeviceManager({ buttonIsDisabled: false }); + await checkAboutPreferences({ checkboxIsDisabled: false }); + + await setupPolicyEngineWithJson({ + policies: { + DisableMasterPasswordCreation: true, + }, + }); + + // With the `DisableMasterPasswordCreation: true` policy active, the + // UI entry points for creating a Primary Password should be disabled. + await checkDeviceManager({ buttonIsDisabled: true }); + await checkAboutPreferences({ checkboxIsDisabled: true }); + + mpToken.changePassword("", MASTER_PASSWORD); + ok(mpToken.hasPassword, "Master password was set"); + + // If a Primary Password is already set, there's no point in disabling + // the + await checkDeviceManager({ buttonIsDisabled: false }); + await checkAboutPreferences({ checkboxIsDisabled: false }); + + // Clean up + mpToken.changePassword(MASTER_PASSWORD, ""); + ok(!mpToken.hasPassword, "Master password was cleaned up"); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_password_reveal.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_password_reveal.js new file mode 100644 index 0000000000..503d421da7 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_password_reveal.js @@ -0,0 +1,43 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_hidden_reveal_password() { + await setupPolicyEngineWithJson({ + policies: { + DisablePasswordReveal: true, + }, + }); + + let aboutLoginsTab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + url: "about:logins", + }); + + let browser = gBrowser.selectedBrowser; + + await SpecialPowers.spawn(browser, [], () => { + let loginList = Cu.waiveXrays(content.document.querySelector("login-list")); + let createButton = loginList._createLoginButton; + ok( + !createButton.disabled, + "Create button should not be disabled initially" + ); + let loginItem = Cu.waiveXrays(content.document.querySelector("login-item")); + + createButton.click(); + + let passwordReveal = loginItem.shadowRoot.querySelector( + ".reveal-password-checkbox" + ); + is(passwordReveal.hidden, true, "Password reveal button should be hidden"); + + // Bug 1696948 + let passwordInput = loginItem.shadowRoot.querySelector( + "input[name='password']" + ); + isnot(passwordInput, null, "Password field should be in the DOM"); + }); + BrowserTestUtils.removeTab(aboutLoginsTab); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_pocket.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_pocket.js new file mode 100644 index 0000000000..414b855f8c --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_pocket.js @@ -0,0 +1,29 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const PREF_POCKET = "extensions.pocket.enabled"; + +async function checkPocket(shouldBeEnabled) { + return BrowserTestUtils.waitForCondition(() => { + return ( + !!CustomizableUI.getWidget("save-to-pocket-button") == shouldBeEnabled + ); + }, "Expecting Pocket to be " + shouldBeEnabled); +} + +add_task(async function test_disable_firefox_screenshots() { + await BrowserTestUtils.withNewTab("data:text/html,Test", async function () { + // Sanity check to make sure Pocket is enabled on tests + await checkPocket(true); + + await setupPolicyEngineWithJson({ + policies: { + DisablePocket: true, + }, + }); + + await checkPocket(false); + }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_popup_blocker.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_popup_blocker.js new file mode 100644 index 0000000000..b9573c7614 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_popup_blocker.js @@ -0,0 +1,149 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +function restore_prefs() { + Services.prefs.clearUserPref("dom.disable_open_during_load"); +} + +let ORIGINAL_PREF_VALUE = undefined; +add_setup(async function () { + // It seems that this pref is given a special testing value for some reason. + // Unset that value for this test, but save the old value + if (Services.prefs.prefHasUserValue("dom.disable_open_during_load")) { + ORIGINAL_PREF_VALUE = Services.prefs.getBoolPref( + "dom.disable_open_during_load" + ); + Services.prefs.clearUserPref("dom.disable_open_during_load"); + } +}); +registerCleanupFunction(async function cleanup_prefs() { + if (ORIGINAL_PREF_VALUE === undefined) { + Services.prefs.clearUserPref("dom.disable_open_during_load"); + } else { + Services.prefs.setBoolPref( + "dom.disable_open_during_load", + ORIGINAL_PREF_VALUE + ); + } +}); + +async function test_popup_blocker_disabled({ disabled, locked }) { + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:preferences#privacy" + ); + await SpecialPowers.spawn( + tab.linkedBrowser, + [{ disabled, locked }], + // eslint-disable-next-line no-shadow + async function ({ disabled, locked }) { + let checkbox = content.document.getElementById("popupPolicy"); + is( + checkbox.checked, + !disabled, + "Checkbox checked state should match policy's Block status" + ); + is( + checkbox.disabled, + locked, + "Checkbox disabled state should match policy's Locked status" + ); + } + ); + BrowserTestUtils.removeTab(tab); + + is( + Services.prefs.prefIsLocked("dom.disable_open_during_load"), + locked, + "Flash pref lock state should match policy lock state" + ); +} + +add_task(async function test_initial_state() { + await test_popup_blocker_disabled({ disabled: false, locked: false }); +}); + +add_task(async function test_empty_policy() { + await setupPolicyEngineWithJson({ + policies: { + PopupBlocking: {}, + }, + }); + + await test_popup_blocker_disabled({ disabled: false, locked: false }); + + restore_prefs(); +}); + +add_task(async function test_block() { + await setupPolicyEngineWithJson({ + policies: { + PopupBlocking: { + Default: true, + }, + }, + }); + + await test_popup_blocker_disabled({ disabled: false, locked: false }); + + restore_prefs(); +}); + +add_task(async function test_block_locked() { + await setupPolicyEngineWithJson({ + policies: { + PopupBlocking: { + Default: true, + Locked: true, + }, + }, + }); + + await test_popup_blocker_disabled({ disabled: false, locked: true }); + + restore_prefs(); +}); + +add_task(async function test_locked() { + await setupPolicyEngineWithJson({ + policies: { + PopupBlocking: { + Locked: true, + }, + }, + }); + + await test_popup_blocker_disabled({ disabled: false, locked: true }); + + restore_prefs(); +}); + +add_task(async function test_disabled() { + await setupPolicyEngineWithJson({ + policies: { + PopupBlocking: { + Default: false, + }, + }, + }); + + await test_popup_blocker_disabled({ disabled: true, locked: false }); + + restore_prefs(); +}); + +add_task(async function test_disabled_locked() { + await setupPolicyEngineWithJson({ + policies: { + PopupBlocking: { + Default: false, + Locked: true, + }, + }, + }); + + await test_popup_blocker_disabled({ disabled: true, locked: true }); + + restore_prefs(); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_privatebrowsing.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_privatebrowsing.js new file mode 100644 index 0000000000..044282f473 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_privatebrowsing.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_setup(async function () { + await setupPolicyEngineWithJson({ + policies: { + DisablePrivateBrowsing: true, + }, + }); +}); + +add_task(async function test_privatebrowsing_disabled() { + is( + PrivateBrowsingUtils.enabled, + false, + "Private browsing should be disabled" + ); + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let privateBrowsingCommand = newWin.document.getElementById( + "Tools:PrivateBrowsing" + ); + is( + privateBrowsingCommand.hidden, + true, + "The private browsing command should be hidden" + ); + await BrowserTestUtils.closeWindow(newWin); + + await testPageBlockedByPolicy("about:privatebrowsing"); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_profile_import.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_profile_import.js new file mode 100644 index 0000000000..9993e578e0 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_profile_import.js @@ -0,0 +1,100 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +async function openLibrary() { + return new Promise(resolve => { + let library = window.openDialog( + "chrome://browser/content/places/places.xhtml", + "", + "chrome,toolbar=yes,dialog=no,resizable" + ); + waitForFocus(() => resolve(library), library); + }); +} + +add_task(async function test_disable_profile_import() { + await setupPolicyEngineWithJson({ + policies: { + DisableProfileImport: true, + }, + }); + let library = await openLibrary(); + + let menu = library.document.getElementById("maintenanceButtonPopup"); + let promisePopupShown = BrowserTestUtils.waitForEvent(menu, "popupshown"); + menu.openPopup(); + await promisePopupShown; + + let profileImportButton = library.document.getElementById("browserImport"); + is( + profileImportButton.disabled, + true, + "Profile Import button should be disabled" + ); + + let promisePopupHidden = BrowserTestUtils.waitForEvent(menu, "popuphidden"); + menu.hidePopup(); + await promisePopupHidden; + + await BrowserTestUtils.closeWindow(library); + + checkLockedPref("browser.newtabpage.activity-stream.migrationExpired", true); +}); + +add_task(async function test_file_menu() { + gFileMenu.updateImportCommandEnabledState(); + + let command = document.getElementById("cmd_file_importFromAnotherBrowser"); + ok( + command.getAttribute("disabled"), + "The `Import from Another Browser…` File menu item command should be disabled" + ); + + if (Services.appinfo.OS == "Darwin") { + // We would need to have a lot of boilerplate to open the menus on Windows + // and Linux to test this there. + let menuitem = document.getElementById("menu_importFromAnotherBrowser"); + ok( + menuitem.disabled, + "The `Import from Another Browser…` File menu item should be disabled" + ); + } +}); + +add_task(async function test_import_button() { + await PlacesUIUtils.maybeAddImportButton(); + ok( + !document.getElementById("import-button"), + "Import button should be hidden." + ); +}); + +add_task(async function test_prefs_entrypoint() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.migrate.preferences-entrypoint.enabled", true]], + }); + + let finalPaneEvent = Services.prefs.getBoolPref("identity.fxaccounts.enabled") + ? "sync-pane-loaded" + : "privacy-pane-loaded"; + let finalPrefPaneLoaded = TestUtils.topicObserved(finalPaneEvent, () => true); + await BrowserTestUtils.withNewTab( + "about:preferences#general-migrate", + async browser => { + await finalPrefPaneLoaded; + await browser.contentWindow.customElements.whenDefined( + "migration-wizard" + ); + let doc = browser.contentDocument; + ok( + !doc.getElementById("dataMigrationGroup"), + "Should remove import entrypoint in prefs if disabled via policy." + ); + ok( + !doc.getElementById("migrationWizardDialog").open, + "Should not have opened the migration wizard." + ); + } + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_profile_reset.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_profile_reset.js new file mode 100644 index 0000000000..09bcdb2d85 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_profile_reset.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +let { ResetProfile } = ChromeUtils.importESModule( + "resource://gre/modules/ResetProfile.sys.mjs" +); + +// For this test to work properly, this profile actually needs to be +// "reset-able", which requires that it be recognized by the profile service +add_setup(async function () { + let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile); + let profileName = profileDirectory.leafName; + let profileService = Cc["@mozilla.org/toolkit/profile-service;1"].getService( + Ci.nsIToolkitProfileService + ); + let createdProfile = profileService.createProfile( + profileDirectory, + profileName + ); + profileService.flush(); + registerCleanupFunction(async function cleanup() { + // Pass false to remove it from the profile service without deleting files. + createdProfile.remove(false); + }); +}); + +async function test_reset_disabled({ disabled }) { + is( + ResetProfile.resetSupported(), + !disabled, + "Reset should only be supported if policy has not been applied" + ); + is( + Services.prefs.getBoolPref("browser.disableResetPrompt", undefined), + disabled, + "Reset prompt should only be shown if policy has not been applied" + ); + is( + Services.prefs.prefIsLocked("browser.disableResetPrompt"), + disabled, + "Reset prompt pref should be locked if the policy has been applied" + ); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:support" + ); + await SpecialPowers.spawn( + tab.linkedBrowser, + [{ disabled }], + async function ({ + // eslint-disable-next-line no-shadow + disabled, + }) { + let resetBox = content.document.getElementById("reset-box"); + let elementStyle = content.window.getComputedStyle(resetBox); + let expectedDisplayValue = disabled ? "none" : "block"; + is( + elementStyle.display, + expectedDisplayValue, + "about:support Reset button box should be hidden" + ); + } + ); + await BrowserTestUtils.removeTab(tab); +} + +add_task(async function test_initial_conditions() { + await test_reset_disabled({ disabled: false }); +}); + +add_task(async function test_policy_disable_reset() { + await setupPolicyEngineWithJson({ + policies: { + DisableProfileRefresh: true, + }, + }); + await test_reset_disabled({ disabled: true }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_safemode.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_safemode.js new file mode 100644 index 0000000000..a2787079d0 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_safemode.js @@ -0,0 +1,57 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +add_setup(async function () { + await setupPolicyEngineWithJson({ + policies: { + DisableSafeMode: true, + }, + }); +}); + +add_task(async function test_help_menu() { + buildHelpMenu(); + let safeModeMenu = document.getElementById("helpSafeMode"); + is( + safeModeMenu.getAttribute("disabled"), + "true", + "The `Restart with Add-ons Disabled...` item should be disabled" + ); +}); + +add_task(async function test_safemode_from_about_support() { + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:support" + ); + + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + let button = content.document.getElementById("restart-in-safe-mode-button"); + is( + button.getAttribute("disabled"), + "true", + "The `Restart with Add-ons Disabled...` button should be disabled" + ); + }); + + await BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_safemode_from_about_profiles() { + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:profiles" + ); + + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + let button = content.document.getElementById("restart-in-safe-mode-button"); + is( + button.getAttribute("disabled"), + "true", + "The `Restart with Add-ons Disabled...` button should be disabled" + ); + }); + + await BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_shield.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_shield.js new file mode 100644 index 0000000000..ef36a0d36c --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_shield.js @@ -0,0 +1,68 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_policy_disable_shield() { + const { RecipeRunner } = ChromeUtils.importESModule( + "resource://normandy/lib/RecipeRunner.sys.mjs" + ); + const { BaseAction } = ChromeUtils.importESModule( + "resource://normandy/actions/BaseAction.sys.mjs" + ); + const { BaseStudyAction } = ChromeUtils.importESModule( + "resource://normandy/actions/BaseStudyAction.sys.mjs" + ); + + const baseAction = new BaseAction(); + const baseStudyAction = new BaseStudyAction(); + + await SpecialPowers.pushPrefEnv({ + set: [ + ["app.normandy.api_url", "https://localhost/selfsupport-dummy/"], + ["app.shield.optoutstudies.enabled", true], + ], + }); + + ok(RecipeRunner, "RecipeRunner exists"); + + RecipeRunner.checkPrefs(); + ok(RecipeRunner.enabled, "RecipeRunner is enabled"); + + baseAction._preExecution(); + is( + baseAction.state, + BaseAction.STATE_PREPARING, + "Base action is not disabled" + ); + + baseStudyAction._preExecution(); + is( + baseStudyAction.state, + BaseAction.STATE_PREPARING, + "Base study action is not disabled" + ); + + await setupPolicyEngineWithJson({ + policies: { + DisableFirefoxStudies: true, + }, + }); + + RecipeRunner.checkPrefs(); + ok(RecipeRunner.enabled, "RecipeRunner is still enabled"); + + baseAction._preExecution(); + is( + baseAction.state, + BaseAction.STATE_PREPARING, + "Base action is not disabled" + ); + + baseStudyAction._preExecution(); + is( + baseStudyAction.state, + BaseAction.STATE_DISABLED, + "Base study action is disabled" + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_telemetry.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_telemetry.js new file mode 100644 index 0000000000..3070df0d88 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_telemetry.js @@ -0,0 +1,28 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_policy_disable_telemetry() { + const { TelemetryReportingPolicy } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryReportingPolicy.sys.mjs" + ); + + ok(TelemetryReportingPolicy, "TelemetryReportingPolicy exists"); + is(TelemetryReportingPolicy.canUpload(), true, "Telemetry is enabled"); + + await setupPolicyEngineWithJson({ + policies: { + DisableTelemetry: true, + }, + }); + + is(TelemetryReportingPolicy.canUpload(), false, "Telemetry is disabled"); + is( + Services.prefs.getBoolPref("toolkit.telemetry.archive.enabled"), + false, + "Telemetry archive should be disabled." + ); + + await testPageBlockedByPolicy("about:telemetry"); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_display_bookmarks.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_display_bookmarks.js new file mode 100644 index 0000000000..8c43cbc8e1 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_display_bookmarks.js @@ -0,0 +1,86 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Since testing will apply the policy after the browser has already started, +// we will need to open a new window to actually see the toolbar + +add_task(async function test_personaltoolbar_shown_old() { + await setupPolicyEngineWithJson({ + policies: { + DisplayBookmarksToolbar: true, + }, + }); + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let menuBar = newWin.document.getElementById("PersonalToolbar"); + is( + menuBar.getAttribute("collapsed"), + "false", + "The bookmarks toolbar should not be hidden" + ); + + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_personaltoolbar_shown() { + await setupPolicyEngineWithJson({ + policies: { + DisplayBookmarksToolbar: "always", + }, + }); + + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let menuBar = newWin.document.getElementById("PersonalToolbar"); + is( + menuBar.getAttribute("collapsed"), + "false", + "The bookmarks toolbar should not be hidden" + ); + + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_personaltoolbar_hidden() { + await setupPolicyEngineWithJson({ + policies: { + DisplayBookmarksToolbar: "never", + }, + }); + + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let menuBar = newWin.document.getElementById("PersonalToolbar"); + is( + menuBar.getAttribute("collapsed"), + "true", + "The bookmarks toolbar should be hidden" + ); + + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_personaltoolbar_newtabonly() { + await setupPolicyEngineWithJson({ + policies: { + DisplayBookmarksToolbar: "newtab", + }, + }); + + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let menuBar = newWin.document.getElementById("PersonalToolbar"); + is( + menuBar.getAttribute("collapsed"), + "true", + "The bookmarks toolbar should be hidden" + ); + + await BrowserTestUtils.openNewForegroundTab(newWin.gBrowser, "about:newtab"); + menuBar = newWin.document.getElementById("PersonalToolbar"); + is( + menuBar.getAttribute("collapsed"), + "false", + "The bookmarks toolbar should not be hidden" + ); + + await BrowserTestUtils.closeWindow(newWin); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_display_menu.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_display_menu.js new file mode 100644 index 0000000000..9560a1aaf1 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_display_menu.js @@ -0,0 +1,84 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_menu_shown_boolean() { + await setupPolicyEngineWithJson({ + policies: { + DisplayMenuBar: true, + }, + }); + + // Since testing will apply the policy after the browser has already started, + // we will need to open a new window to actually see the menu bar + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let menubar = newWin.document.getElementById("toolbar-menubar"); + is( + menubar.getAttribute("autohide"), + "false", + "The menu bar should not be hidden" + ); + + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_menu_shown_string() { + await setupPolicyEngineWithJson({ + policies: { + DisplayMenuBar: "default-on", + }, + }); + + // Since testing will apply the policy after the browser has already started, + // we will need to open a new window to actually see the menu bar + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let menubar = newWin.document.getElementById("toolbar-menubar"); + is( + menubar.getAttribute("autohide"), + "false", + "The menu bar should not be hidden" + ); + + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_menubar_on() { + await setupPolicyEngineWithJson({ + policies: { + DisplayMenuBar: "always", + }, + }); + + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let menubar = newWin.document.getElementById("toolbar-menubar"); + is( + menubar.hasAttribute("inactive"), + false, + "Menu bar should not have inactive" + ); + is( + menubar.hasAttribute("toolbarname"), + false, + "Menu bar should not have a toolbarname" + ); + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_menubar_off() { + await setupPolicyEngineWithJson({ + policies: { + DisplayMenuBar: "never", + }, + }); + + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let menubar = newWin.document.getElementById("toolbar-menubar"); + is(menubar.hasAttribute("inactive"), true, "Menu bar should have inactive"); + is( + menubar.hasAttribute("toolbarname"), + false, + "Menu bar should not have a toolbarname" + ); + await BrowserTestUtils.closeWindow(newWin); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_downloads.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_downloads.js new file mode 100644 index 0000000000..163745aaaf --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_downloads.js @@ -0,0 +1,147 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const UCT_URI = "chrome://mozapps/content/downloads/unknownContentType.xhtml"; + +add_task(async function test_defaultdownload() { + await setupPolicyEngineWithJson({ + policies: { + DefaultDownloadDirectory: "${home}/Downloads", + PromptForDownloadLocation: false, + }, + }); + + await BrowserTestUtils.withNewTab("about:preferences", async browser => { + is( + browser.contentDocument.getElementById("alwaysAsk").disabled, + true, + "alwaysAsk should be disabled." + ); + let home = Services.dirsvc.get("Home", Ci.nsIFile).path; + is( + Services.prefs.getStringPref("browser.download.dir"), + home + "/Downloads", + "browser.download.dir should be ${home}/Downloads." + ); + is( + Services.prefs.getBoolPref("browser.download.useDownloadDir"), + true, + "browser.download.useDownloadDir should be true." + ); + is( + Services.prefs.prefIsLocked("browser.download.useDownloadDir"), + true, + "browser.download.useDownloadDir should be locked." + ); + }); +}); + +add_task(async function test_download() { + await setupPolicyEngineWithJson({ + policies: { + DownloadDirectory: "${home}/Documents", + }, + }); + + await BrowserTestUtils.withNewTab("about:preferences", async browser => { + is( + browser.contentDocument.getElementById("alwaysAsk").disabled, + true, + "alwaysAsk should be disabled." + ); + is( + browser.contentDocument.getElementById("downloadFolder").disabled, + true, + "downloadFolder should be disabled." + ); + is( + browser.contentDocument.getElementById("chooseFolder").disabled, + true, + "chooseFolder should be disabled." + ); + let home = Services.dirsvc.get("Home", Ci.nsIFile).path; + is( + Services.prefs.getStringPref("browser.download.dir"), + home + "/Documents", + "browser.download.dir should be ${home}/Documents." + ); + is( + Services.prefs.getBoolPref("browser.download.useDownloadDir"), + true, + "browser.download.useDownloadDir should be true." + ); + is( + Services.prefs.prefIsLocked("browser.download.useDownloadDir"), + true, + "browser.download.useDownloadDir should be locked." + ); + }); +}); + +async function setDownloadDir() { + let tmpDir = PathUtils.join( + PathUtils.tempDir, + "testsavedir" + Math.floor(Math.random() * 2 ** 32) + ); + // Create this dir if it doesn't exist (ignores existing dirs) + await IOUtils.makeDirectory(tmpDir); + registerCleanupFunction(async function () { + try { + await IOUtils.remove(tmpDir, { recursive: true }); + } catch (e) { + console.error(e); + } + }); + Services.prefs.setIntPref("browser.download.folderList", 2); + Services.prefs.setCharPref("browser.download.dir", tmpDir); + return tmpDir; +} + +add_task(async function test_tmpdir_download() { + await setupPolicyEngineWithJson({ + policies: { + StartDownloadsInTempDirectory: true, + }, + }); + + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.download.always_ask_before_handling_new_types", true], + ["browser.helperApps.deleteTempFileOnExit", true], + ], + }); + + let dlDir = new FileUtils.File(await setDownloadDir()); + registerCleanupFunction(() => { + Services.prefs.clearUserPref("browser.download.dir"); + Services.prefs.clearUserPref("browser.download.folderList"); + }); + + // Wait for the download prompting dialog + let dialogPromise = BrowserTestUtils.domWindowOpenedAndLoaded( + null, + win => win.document.documentURI == UCT_URI + ); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: "https://example.com/browser/browser/components/downloads/test/browser/foo.txt", + waitForLoad: false, + waitForStop: true, + }, + async function () { + let dialogWin = await dialogPromise; + let tempFile = dialogWin.dialog.mLauncher.targetFile; + isnot( + tempFile.parent.path, + dlDir.path, + "Should not have put temp file in the downloads dir." + ); + + dialogWin.close(); + } + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_extensions.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_extensions.js new file mode 100644 index 0000000000..7d1313548b --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_extensions.js @@ -0,0 +1,117 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const ADDON_ID = "policytest@mozilla.com"; +const BASE_URL = + "http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser"; + +async function isExtensionLocked(win, addonID) { + let addonCard = await TestUtils.waitForCondition(() => { + return win.document.querySelector(`addon-card[addon-id="${addonID}"]`); + }, `Get addon-card for "${addonID}"`); + let disableBtn = addonCard.querySelector('[action="toggle-disabled"]'); + let removeBtn = addonCard.querySelector('panel-item[action="remove"]'); + ok(removeBtn.disabled, "Remove button should be disabled"); + ok(disableBtn.hidden, "Disable button should be hidden"); +} + +add_task(async function test_addon_install() { + let installPromise = waitForAddonInstall(ADDON_ID); + await setupPolicyEngineWithJson({ + policies: { + Extensions: { + Install: [`${BASE_URL}/policytest_v0.1.xpi`], + Locked: [ADDON_ID], + }, + }, + }); + await installPromise; + let addon = await AddonManager.getAddonByID(ADDON_ID); + isnot(addon, null, "Addon not installed."); + is(addon.version, "0.1", "Addon version is correct"); + + Assert.deepEqual( + addon.installTelemetryInfo, + { source: "enterprise-policy" }, + "Got the expected addon.installTelemetryInfo" + ); +}); + +add_task(async function test_addon_locked() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser); + const win = await BrowserOpenAddonsMgr("addons://list/extension"); + + await isExtensionLocked(win, ADDON_ID); + + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_addon_reinstall() { + // Test that uninstalling and reinstalling the same addon ID works as expected. + // This can be used to update an addon. + + let uninstallPromise = waitForAddonUninstall(ADDON_ID); + let installPromise = waitForAddonInstall(ADDON_ID); + await setupPolicyEngineWithJson({ + policies: { + Extensions: { + Uninstall: [ADDON_ID], + Install: [`${BASE_URL}/policytest_v0.2.xpi`], + }, + }, + }); + + // Older version was uninstalled + await uninstallPromise; + + // New version was installed + await installPromise; + + let addon = await AddonManager.getAddonByID(ADDON_ID); + isnot( + addon, + null, + "Addon still exists because the policy was used to update it." + ); + is(addon.version, "0.2", "New version is correct"); +}); + +add_task(async function test_addon_uninstall() { + EnterprisePolicyTesting.resetRunOnceState(); + + let uninstallPromise = waitForAddonUninstall(ADDON_ID); + await setupPolicyEngineWithJson({ + policies: { + Extensions: { + Uninstall: [ADDON_ID], + }, + }, + }); + await uninstallPromise; + let addon = await AddonManager.getAddonByID(ADDON_ID); + is(addon, null, "Addon should be uninstalled."); +}); + +add_task(async function test_addon_download_failure() { + // Test that if the download fails, the runOnce pref + // is cleared so that the download will happen again. + + let installPromise = waitForAddonInstall(ADDON_ID); + await setupPolicyEngineWithJson({ + policies: { + Extensions: { + Install: [`${BASE_URL}/policytest_invalid.xpi`], + }, + }, + }); + + await installPromise; + is( + Services.prefs.prefHasUserValue( + "browser.policies.runOncePerModification.extensionsInstall" + ), + false, + "runOnce pref should be unset" + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings.js new file mode 100644 index 0000000000..08dbcff6e2 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings.js @@ -0,0 +1,261 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const BASE_URL = + "http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser/"; + +/** + * Wait for the given PopupNotification to display + * + * @param {string} name + * The name of the notification to wait for. + * + * @returns {Promise} + * Resolves with the notification window. + */ +function promisePopupNotificationShown(name) { + return new Promise(resolve => { + function popupshown() { + let notification = PopupNotifications.getNotification(name); + if (!notification) { + return; + } + + ok(notification, `${name} notification shown`); + ok(PopupNotifications.isPanelOpen, "notification panel open"); + + PopupNotifications.panel.removeEventListener("popupshown", popupshown); + resolve(PopupNotifications.panel.firstElementChild); + } + + PopupNotifications.panel.addEventListener("popupshown", popupshown); + }); +} + +add_setup(async function setupTestEnvironment() { + // Once InstallTrigger is removed, the tests targeting InstallTrigger should + // be removed or adapted to don't use InstallTrigger. + await SpecialPowers.pushPrefEnv({ + set: [ + ["extensions.InstallTrigger.enabled", true], + ["extensions.InstallTriggerImpl.enabled", true], + // Relax the user input requirements while running this test. + ["xpinstall.userActivation.required", false], + ], + }); +}); + +add_task(async function test_install_source_blocked_link() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "*": { + install_sources: ["http://blocks.other.install.sources/*"], + }, + }, + }, + }); + let popupPromise = promisePopupNotificationShown( + "addon-install-policy-blocked" + ); + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: BASE_URL + "extensionsettings.html", + waitForStateStop: true, + }); + + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.document.getElementById("policytest").click(); + }); + await popupPromise; + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_install_source_blocked_installtrigger() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "*": { + install_sources: ["http://blocks.other.install.sources/*"], + blocked_install_message: "blocked_install_message", + }, + }, + }, + }); + let popupPromise = promisePopupNotificationShown( + "addon-install-policy-blocked" + ); + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: BASE_URL + "extensionsettings.html", + waitForStateStop: true, + }); + + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.document.getElementById("policytest_installtrigger").click(); + }); + let popup = await popupPromise; + let description = popup.querySelector(".popup-notification-description"); + ok( + description.textContent.endsWith("blocked_install_message"), + "Custom install message present" + ); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_install_source_blocked_otherdomain() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "*": { + install_sources: ["http://mochi.test/*"], + }, + }, + }, + }); + let popupPromise = promisePopupNotificationShown( + "addon-install-policy-blocked" + ); + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: BASE_URL + "extensionsettings.html", + waitForStateStop: true, + }); + + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.document.getElementById("policytest_otherdomain").click(); + }); + await popupPromise; + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_install_source_blocked_direct() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "*": { + install_sources: ["http://blocks.other.install.sources/*"], + }, + }, + }, + }); + let popupPromise = promisePopupNotificationShown( + "addon-install-policy-blocked" + ); + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: BASE_URL + "extensionsettings.html", + waitForStateStop: true, + }); + + await SpecialPowers.spawn( + tab.linkedBrowser, + [{ baseUrl: BASE_URL }], + async function ({ baseUrl }) { + content.document.location.href = baseUrl + "policytest_v0.1.xpi"; + } + ); + await popupPromise; + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_install_source_allowed_link() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "*": { + install_sources: ["http://mochi.test/*"], + }, + }, + }, + }); + let popupPromise = promisePopupNotificationShown("addon-webext-permissions"); + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: BASE_URL + "extensionsettings.html", + waitForStateStop: true, + }); + + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.document.getElementById("policytest").click(); + }); + await popupPromise; + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_install_source_allowed_installtrigger() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "*": { + install_sources: ["http://mochi.test/*"], + }, + }, + }, + }); + let popupPromise = promisePopupNotificationShown("addon-webext-permissions"); + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: BASE_URL + "extensionsettings.html", + waitForStateStop: true, + }); + + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.document.getElementById("policytest_installtrigger").click(); + }); + await popupPromise; + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_install_source_allowed_otherdomain() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "*": { + install_sources: ["http://mochi.test/*", "http://example.org/*"], + }, + }, + }, + }); + let popupPromise = promisePopupNotificationShown("addon-webext-permissions"); + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: BASE_URL + "extensionsettings.html", + waitForStateStop: true, + }); + + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.document.getElementById("policytest_otherdomain").click(); + }); + await popupPromise; + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_install_source_allowed_direct() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "*": { + install_sources: ["http://mochi.test/*"], + }, + }, + }, + }); + let popupPromise = promisePopupNotificationShown("addon-webext-permissions"); + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: BASE_URL + "extensionsettings.html", + waitForStateStop: true, + }); + + await SpecialPowers.spawn( + tab.linkedBrowser, + [{ baseUrl: BASE_URL }], + async function ({ baseUrl }) { + content.document.location.href = baseUrl + "policytest_v0.1.xpi"; + } + ); + await popupPromise; + BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings2.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings2.js new file mode 100644 index 0000000000..612448ee4e --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings2.js @@ -0,0 +1,71 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const ADDON_ID = "policytest@mozilla.com"; +const BASE_URL = + "http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser"; + +async function isExtensionLockedAndUpdateDisabled(win, addonID) { + let addonCard = await BrowserTestUtils.waitForCondition(() => { + return win.document.querySelector(`addon-card[addon-id="${addonID}"]`); + }, `Get addon-card for "${addonID}"`); + let disableBtn = addonCard.querySelector('[action="toggle-disabled"]'); + let removeBtn = addonCard.querySelector('panel-item[action="remove"]'); + ok(removeBtn.disabled, "Remove button should be disabled"); + ok(disableBtn.hidden, "Disable button should be hidden"); + let updateRow = addonCard.querySelector(".addon-detail-row-updates"); + is(updateRow.hidden, true, "Update row should be hidden"); +} + +add_task(async function test_addon_install() { + let installPromise = waitForAddonInstall(ADDON_ID); + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "policytest@mozilla.com": { + install_url: `${BASE_URL}/policytest_v0.1.xpi`, + installation_mode: "force_installed", + updates_disabled: true, + }, + }, + }, + }); + await installPromise; + let addon = await AddonManager.getAddonByID(ADDON_ID); + isnot(addon, null, "Addon not installed."); + is(addon.version, "0.1", "Addon version is correct"); + + Assert.deepEqual( + addon.installTelemetryInfo, + { source: "enterprise-policy" }, + "Got the expected addon.installTelemetryInfo" + ); +}); + +add_task(async function test_addon_locked_update_disabled() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser); + const win = await BrowserOpenAddonsMgr( + "addons://detail/" + encodeURIComponent(ADDON_ID) + ); + + await isExtensionLockedAndUpdateDisabled(win, ADDON_ID); + + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_addon_uninstall() { + let uninstallPromise = waitForAddonUninstall(ADDON_ID); + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "policytest@mozilla.com": { + installation_mode: "blocked", + }, + }, + }, + }); + await uninstallPromise; + let addon = await AddonManager.getAddonByID(ADDON_ID); + is(addon, null, "Addon should be uninstalled."); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_firefoxhome.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_firefoxhome.js new file mode 100644 index 0000000000..b1b269451b --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_firefoxhome.js @@ -0,0 +1,129 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.newtabpage.activity-stream.feeds.section.highlights", true], + ], + }); +}); + +add_task(async function test_firefox_home_without_policy_without_pocket() { + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: "about:home", + waitForStateStop: true, + }); + + await SpecialPowers.spawn(tab.linkedBrowser, [], function () { + let search = content.document.querySelector(".search-wrapper"); + isnot(search, null, "Search section should be there."); + let topsites = content.document.querySelector( + "section[data-section-id='topsites']" + ); + isnot(topsites, null, "Top Sites section should be there."); + let highlights = content.document.querySelector( + "section[data-section-id='highlights']" + ); + isnot(highlights, null, "Highlights section should be there."); + }); + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async function test_firefox_home_with_policy() { + await SpecialPowers.pushPrefEnv({ + set: [ + [ + "browser.newtabpage.activity-stream.discoverystream.endpointSpocsClear", + "", + ], + ], + }); + + await setupPolicyEngineWithJson({ + policies: { + FirefoxHome: { + Search: false, + TopSites: false, + Highlights: false, + }, + }, + }); + + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: "about:home", + waitForStateStop: true, + }); + + await SpecialPowers.spawn(tab.linkedBrowser, [], function () { + let search = content.document.querySelector(".search-wrapper"); + is(search, null, "Search section should not be there."); + let topsites = content.document.querySelector( + "section[data-section-id='topsites']" + ); + is(topsites, null, "Top Sites section should not be there."); + let highlights = content.document.querySelector( + "section[data-section-id='highlights']" + ); + is(highlights, null, "Highlights section should not be there."); + }); + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async function test_firefoxhome_preferences_set() { + await SpecialPowers.pushPrefEnv({ + set: [ + [ + "browser.newtabpage.activity-stream.discoverystream.endpointSpocsClear", + "", + ], + ], + }); + + await setupPolicyEngineWithJson({ + policies: { + FirefoxHome: { + Search: false, + TopSites: false, + SponsoredTopSites: false, + Highlights: false, + Pocket: false, + SponsoredPocket: false, + Locked: true, + }, + }, + }); + + await BrowserTestUtils.withNewTab("about:preferences#home", async browser => { + let data = { + Search: "browser.newtabpage.activity-stream.showSearch", + TopSites: "browser.newtabpage.activity-stream.feeds.topsites", + SponsoredTopSites: + "browser.newtabpage.activity-stream.showSponsoredTopSites", + Highlights: "browser.newtabpage.activity-stream.feeds.section.highlights", + Pocket: "browser.newtabpage.activity-stream.feeds.section.topstories", + SponsoredPocket: "browser.newtabpage.activity-stream.showSponsored", + }; + for (let [section, preference] of Object.entries(data)) { + is( + browser.contentDocument.querySelector( + `checkbox[preference='${preference}']` + ).disabled, + true, + `${section} checkbox should be disabled` + ); + } + }); + await setupPolicyEngineWithJson({ + policies: { + FirefoxHome: {}, + }, + }); + await SpecialPowers.popPrefEnv(); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_firefoxsuggest.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_firefoxsuggest.js new file mode 100644 index 0000000000..2aba89613d --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_firefoxsuggest.js @@ -0,0 +1,61 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_firefox_suggest_with_policy() { + await setupPolicyEngineWithJson({ + policies: { + FirefoxSuggest: { + WebSuggestions: false, + SponsoredSuggestions: true, + ImproveSuggest: true, + Locked: true, + }, + }, + }); + + await BrowserTestUtils.withNewTab( + "about:preferences#search", + async browser => { + is( + browser.contentDocument.getElementById("firefoxSuggestNonsponsored") + .checked, + false, + "Web suggestions is disabled" + ); + is( + browser.contentDocument.getElementById("firefoxSuggestSponsored") + .checked, + true, + "Sponsored suggestions is enabled" + ); + is( + browser.contentDocument.getElementById( + "firefoxSuggestDataCollectionSearchToggle" + ).pressed, + true, + "Improve suggest is enabled" + ); + is( + browser.contentDocument.getElementById("firefoxSuggestNonsponsored") + .disabled, + true, + "Web suggestions is disabled" + ); + is( + browser.contentDocument.getElementById("firefoxSuggestSponsored") + .disabled, + true, + "Sponsored suggestions is enabled" + ); + is( + browser.contentDocument.getElementById( + "firefoxSuggestDataCollectionSearchToggle" + ).disabled, + true, + "Improve suggest is enabled" + ); + } + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_handlers.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_handlers.js new file mode 100644 index 0000000000..45debf73c9 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_handlers.js @@ -0,0 +1,183 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const gMIMEService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); + +const gExternalProtocolService = Cc[ + "@mozilla.org/uriloader/external-protocol-service;1" +].getService(Ci.nsIExternalProtocolService); + +const gHandlerService = Cc[ + "@mozilla.org/uriloader/handler-service;1" +].getService(Ci.nsIHandlerService); + +// This seems odd, but for test purposes, this just has to be a file that we know exists, +// and by using this file, we don't have to worry about different platforms. +let exeFile = Services.dirsvc.get("XREExeF", Ci.nsIFile); + +add_task(async function test_valid_handlers() { + await setupPolicyEngineWithJson({ + policies: { + Handlers: { + mimeTypes: { + "application/marimba": { + action: "useHelperApp", + ask: true, + handlers: [ + { + name: "Launch", + path: exeFile.path, + }, + ], + }, + }, + schemes: { + fake_scheme: { + action: "useHelperApp", + ask: false, + handlers: [ + { + name: "Name", + uriTemplate: "https://www.example.org/?%s", + }, + ], + }, + }, + extensions: { + txt: { + action: "saveToDisk", + ask: false, + }, + }, + }, + }, + }); + + let handlerInfo = gMIMEService.getFromTypeAndExtension( + "application/marimba", + "" + ); + is(handlerInfo.preferredAction, handlerInfo.useHelperApp); + is(handlerInfo.alwaysAskBeforeHandling, true); + is(handlerInfo.preferredApplicationHandler.name, "Launch"); + is(handlerInfo.preferredApplicationHandler.executable.path, exeFile.path); + + handlerInfo.preferredApplicationHandler = null; + gHandlerService.store(handlerInfo); + + handlerInfo = handlerInfo = gMIMEService.getFromTypeAndExtension( + "application/marimba", + "" + ); + is(handlerInfo.preferredApplicationHandler, null); + + gHandlerService.remove(handlerInfo); + + handlerInfo = gExternalProtocolService.getProtocolHandlerInfo("fake_scheme"); + is(handlerInfo.preferredAction, handlerInfo.useHelperApp); + is(handlerInfo.alwaysAskBeforeHandling, false); + is(handlerInfo.preferredApplicationHandler.name, "Name"); + is( + handlerInfo.preferredApplicationHandler.uriTemplate, + "https://www.example.org/?%s" + ); + + handlerInfo.preferredApplicationHandler = null; + gHandlerService.store(handlerInfo); + + handlerInfo = gExternalProtocolService.getProtocolHandlerInfo("fake_scheme"); + is(handlerInfo.preferredApplicationHandler, null); + + gHandlerService.remove(handlerInfo); + + handlerInfo = gMIMEService.getFromTypeAndExtension("", "txt"); + is(handlerInfo.preferredAction, handlerInfo.saveToDisk); + is(handlerInfo.alwaysAskBeforeHandling, false); + + handlerInfo.preferredApplicationHandler = null; + gHandlerService.store(handlerInfo); + handlerInfo = gMIMEService.getFromTypeAndExtension("", "txt"); + is(handlerInfo.preferredApplicationHandler, null); + + gHandlerService.remove(handlerInfo); +}); + +add_task(async function test_no_handler() { + await setupPolicyEngineWithJson({ + policies: { + Handlers: { + schemes: { + no_handler: { + action: "useHelperApp", + }, + }, + }, + }, + }); + + let handlerInfo = + gExternalProtocolService.getProtocolHandlerInfo("no_handler"); + is(handlerInfo.preferredAction, handlerInfo.alwaysAsk); + is(handlerInfo.alwaysAskBeforeHandling, true); + is(handlerInfo.preferredApplicationHandler, null); + + gHandlerService.remove(handlerInfo); +}); + +add_task(async function test_bad_web_handler1() { + await setupPolicyEngineWithJson({ + policies: { + Handlers: { + schemes: { + bas_web_handler1: { + action: "useHelperApp", + handlers: [ + { + name: "Name", + uriTemplate: "http://www.example.org/?%s", + }, + ], + }, + }, + }, + }, + }); + + let handlerInfo = + gExternalProtocolService.getProtocolHandlerInfo("bad_web_handler1"); + is(handlerInfo.preferredAction, handlerInfo.alwaysAsk); + is(handlerInfo.alwaysAskBeforeHandling, true); + is(handlerInfo.preferredApplicationHandler, null); + + gHandlerService.remove(handlerInfo); +}); + +add_task(async function test_bad_web_handler2() { + await setupPolicyEngineWithJson({ + policies: { + Handlers: { + schemes: { + bas_web_handler1: { + action: "useHelperApp", + handlers: [ + { + name: "Name", + uriTemplate: "http://www.example.org/", + }, + ], + }, + }, + }, + }, + }); + + let handlerInfo = + gExternalProtocolService.getProtocolHandlerInfo("bad_web_handler1"); + is(handlerInfo.preferredAction, handlerInfo.alwaysAsk); + is(handlerInfo.alwaysAskBeforeHandling, true); + is(handlerInfo.preferredApplicationHandler, null); + + gHandlerService.remove(handlerInfo); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_masterpassword.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_masterpassword.js new file mode 100644 index 0000000000..872eb5a652 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_masterpassword.js @@ -0,0 +1,95 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +let { LoginTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/LoginTestUtils.sys.mjs" +); + +// Test that once a password is set, you can't unset it +add_task(async function test_policy_masterpassword_set() { + await setupPolicyEngineWithJson({ + policies: { + PrimaryPassword: true, + }, + }); + + LoginTestUtils.primaryPassword.enable(); + + await BrowserTestUtils.withNewTab( + "about:preferences#privacy", + async browser => { + is( + browser.contentDocument.getElementById("useMasterPassword").disabled, + true, + "Master Password checkbox should be disabled" + ); + } + ); + + LoginTestUtils.primaryPassword.disable(); +}); + +// Test that password can't be removed in changemp.xhtml +add_task(async function test_policy_nochangemp() { + await setupPolicyEngineWithJson({ + policies: { + PrimaryPassword: true, + }, + }); + + LoginTestUtils.primaryPassword.enable(); + + let changeMPWindow = window.openDialog( + "chrome://mozapps/content/preferences/changemp.xhtml", + "", + "" + ); + await BrowserTestUtils.waitForEvent(changeMPWindow, "load"); + + is( + changeMPWindow.document.getElementById("admin").hidden, + true, + "Admin message should not be visible because there is a password." + ); + + changeMPWindow.document.getElementById("oldpw").value = + LoginTestUtils.primaryPassword.masterPassword; + + is( + changeMPWindow.document.getElementById("changemp").getButton("accept") + .disabled, + true, + "OK button should not be enabled if there is an old password." + ); + + await BrowserTestUtils.closeWindow(changeMPWindow); + + LoginTestUtils.primaryPassword.disable(); +}); + +// Test that admin message shows +add_task(async function test_policy_admin() { + await setupPolicyEngineWithJson({ + policies: { + PrimaryPassword: true, + }, + }); + + let changeMPWindow = window.openDialog( + "chrome://mozapps/content/preferences/changemp.xhtml", + "", + "" + ); + await BrowserTestUtils.waitForEvent(changeMPWindow, "load"); + + is( + changeMPWindow.document.getElementById("admin").hidden, + false, + true, + "Admin message should not be hidden because there is not a password." + ); + + await BrowserTestUtils.closeWindow(changeMPWindow); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_masterpassword_aboutlogins.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_masterpassword_aboutlogins.js new file mode 100644 index 0000000000..91cc9ebc2e --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_masterpassword_aboutlogins.js @@ -0,0 +1,76 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +let { LoginTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/LoginTestUtils.sys.mjs" +); + +// Test that create in about:logins asks for primary password +add_task(async function test_policy_admin() { + await setupPolicyEngineWithJson({ + policies: { + PrimaryPassword: true, + }, + }); + + let aboutLoginsTab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + url: "about:logins", + }); + + let browser = gBrowser.selectedBrowser; + + // Fake the subdialog + let dialogURL = ""; + let originalOpenDialog = window.openDialog; + window.openDialog = function (aDialogURL, unused, unused2, aCallback) { + dialogURL = aDialogURL; + if (aCallback) { + aCallback(); + } + }; + + await SpecialPowers.spawn(browser, [], async () => { + let loginList = Cu.waiveXrays(content.document.querySelector("login-list")); + let createButton = loginList._createLoginButton; + ok( + !createButton.disabled, + "Create button should not be disabled initially" + ); + let loginItem = Cu.waiveXrays(content.document.querySelector("login-item")); + + createButton.click(); + + let usernameInput = loginItem.shadowRoot.querySelector( + "input[name='username']" + ); + let originInput = loginItem.shadowRoot.querySelector( + "input[name='origin']" + ); + let passwordInput = loginItem.shadowRoot.querySelector( + "input[name='password']" + ); + + originInput.value = "https://www.example.org"; + usernameInput.value = "testuser1"; + passwordInput.value = "testpass1"; + + let saveChangesButton = loginItem.shadowRoot.querySelector( + ".save-changes-button" + ); + saveChangesButton.click(); + }); + await TestUtils.waitForCondition( + () => dialogURL, + "wait for open to get called asynchronously" + ); + is( + dialogURL, + "chrome://mozapps/content/preferences/changemp.xhtml", + "clicking on the save-changes-button should open the masterpassword dialog" + ); + window.openDialog = originalOpenDialog; + BrowserTestUtils.removeTab(aboutLoginsTab); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_masterpassword_doorhanger.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_masterpassword_doorhanger.js new file mode 100644 index 0000000000..224ad1d275 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_masterpassword_doorhanger.js @@ -0,0 +1,76 @@ +/** + * Test that the doorhanger notification for password saving is populated with + * the correct values in various password capture cases. + */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/toolkit/components/passwordmgr/test/browser/head.js", + this +); + +add_task(async function test_policy_masterpassword_doorhanger() { + await setupPolicyEngineWithJson({ + policies: { + PrimaryPassword: true, + }, + }); + + let username = "username"; + let password = "password"; + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: + "https://example.com/browser/toolkit/components/" + + "passwordmgr/test/browser/form_basic.html", + }, + async function (browser) { + await SimpleTest.promiseFocus(browser.ownerGlobal); + + // Update the form with credentials from the test case. + info(`update form with username: ${username}, password: ${password}`); + await changeContentFormValues(browser, { + "#form-basic-username": username, + "#form-basic-password": password, + }); + + // Submit the form with the new credentials. This will cause the doorhanger + // notification to be displayed. + let formSubmittedPromise = listenForTestNotification("ShowDoorhanger"); + await SpecialPowers.spawn(browser, [], async function () { + let doc = this.content.document; + doc.getElementById("form-basic").submit(); + }); + await formSubmittedPromise; + + let expectedDoorhanger = "password-save"; + + info("Waiting for doorhanger of type: " + expectedDoorhanger); + let notif = await waitForDoorhanger(browser, expectedDoorhanger); + + // Fake the subdialog + let dialogURL = ""; + let originalOpenDialog = window.openDialog; + window.openDialog = function (aDialogURL, unused, unused2, aCallback) { + dialogURL = aDialogURL; + if (aCallback) { + aCallback(); + } + }; + + await clickDoorhangerButton(notif, REMEMBER_BUTTON); + + await TestUtils.waitForCondition( + () => dialogURL, + "wait for open to get called asynchronously" + ); + is( + dialogURL, + "chrome://mozapps/content/preferences/changemp.xhtml", + "clicking on the checkbox should open the masterpassword dialog" + ); + window.openDialog = originalOpenDialog; + } + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_offertosavelogins.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_offertosavelogins.js new file mode 100644 index 0000000000..5ad1fe44d1 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_offertosavelogins.js @@ -0,0 +1,23 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_policy_offertosavelogins() { + await setupPolicyEngineWithJson({ + policies: { + OfferToSaveLogins: false, + }, + }); + + await BrowserTestUtils.withNewTab( + "about:preferences#privacy", + async browser => { + is( + browser.contentDocument.getElementById("savePasswords").disabled, + true, + "Save passwords is disabled" + ); + } + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_override_postupdatepage.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_override_postupdatepage.js new file mode 100644 index 0000000000..7eef7cffc1 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_override_postupdatepage.js @@ -0,0 +1,132 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// This test was based on the test browser_bug538331.js + +const UPDATE_PROVIDED_PAGE = "https://default.example.com/"; +const POLICY_PROVIDED_PAGE = "https://policy.example.com/"; + +const PREF_MSTONE = "browser.startup.homepage_override.mstone"; + +/* + * The important parts for this test are: + * - actions="showURL" + * - openURL="${UPDATE_PROVIDED_PAGE}" + */ +const XML_UPDATE = `<?xml version="1.0"?> +<updates xmlns="http://www.mozilla.org/2005/app-update"> + <update appVersion="1.0" buildID="20080811053724" channel="nightly" + displayVersion="Version 1.0" installDate="1238441400314" + isCompleteUpdate="true" name="Update Test 1.0" type="minor" + detailsURL="http://example.com/" previousAppVersion="1.0" + serviceURL="https://example.com/" statusText="The Update was successfully installed" + foregroundDownload="true" + actions="showURL" + openURL="${UPDATE_PROVIDED_PAGE}"> + <patch type="complete" URL="http://example.com/" size="775" selected="true" state="succeeded"/> + </update> +</updates>`; + +add_task(async function test_override_postupdate_page() { + let originalMstone = Services.prefs.getCharPref(PREF_MSTONE); + // Set the preferences needed for the test: they will be cleared up + // after it runs. + await SpecialPowers.pushPrefEnv({ set: [[PREF_MSTONE, originalMstone]] }); + + registerCleanupFunction(async () => { + let activeUpdateFile = getActiveUpdateFile(); + activeUpdateFile.remove(false); + reloadUpdateManagerData(true); + }); + + writeUpdatesToXMLFile(XML_UPDATE); + reloadUpdateManagerData(false); + + is( + getPostUpdatePage(), + UPDATE_PROVIDED_PAGE, + "Post-update page was provided by active-update.xml." + ); + + // Now perform the same action but set the policy to override this page + await setupPolicyEngineWithJson({ + policies: { + OverridePostUpdatePage: POLICY_PROVIDED_PAGE, + }, + }); + + is( + getPostUpdatePage(), + POLICY_PROVIDED_PAGE, + "Post-update page was provided by policy." + ); +}); + +function getPostUpdatePage() { + Services.prefs.setCharPref(PREF_MSTONE, "PreviousMilestone"); + return Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler) + .defaultArgs; +} + +/** + * Removes the updates.xml file and returns the nsIFile for the + * active-update.xml file. + * + * @returns {nsIFile} + * The nsIFile for the active-update.xml file. + */ +function getActiveUpdateFile() { + let updateRootDir = Services.dirsvc.get("UpdRootD", Ci.nsIFile); + let updatesFile = updateRootDir.clone(); + updatesFile.append("updates.xml"); + if (updatesFile.exists()) { + // The following is non-fatal. + try { + updatesFile.remove(false); + } catch (e) {} + } + let activeUpdateFile = updateRootDir.clone(); + activeUpdateFile.append("active-update.xml"); + return activeUpdateFile; +} + +/** + * Reloads the update xml files. + * + * @param {boolean} [skipFiles] + * If true, the update xml files will not be read and the metadata will + * be reset. If false (the default), the update xml files will be read + * to populate the update metadata. + */ +function reloadUpdateManagerData(skipFiles = false) { + Cc["@mozilla.org/updates/update-manager;1"] + .getService(Ci.nsIUpdateManager) + .QueryInterface(Ci.nsIObserver) + .observe(null, "um-reload-update-data", skipFiles ? "skip-files" : ""); +} + +/** + * Writes the updates specified to the active-update.xml file. + * + * @param {string} aText + * The updates represented as a string to write to the active-update.xml file. + */ +function writeUpdatesToXMLFile(aText) { + const PERMS_FILE = 0o644; + + const MODE_WRONLY = 0x02; + const MODE_CREATE = 0x08; + const MODE_TRUNCATE = 0x20; + + let activeUpdateFile = getActiveUpdateFile(); + if (!activeUpdateFile.exists()) { + activeUpdateFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); + } + let fos = Cc["@mozilla.org/network/file-output-stream;1"].createInstance( + Ci.nsIFileOutputStream + ); + let flags = MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE; + fos.init(activeUpdateFile, flags, PERMS_FILE, 0); + fos.write(aText, aText.length); + fos.close(); +} diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_pageinfo_permissions.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_pageinfo_permissions.js new file mode 100644 index 0000000000..4921464782 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_pageinfo_permissions.js @@ -0,0 +1,76 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +const TEST_ORIGIN = "https://example.com"; + +/* Verifies that items on the page info page are properly disabled + when the corresponding policies are locked */ +add_task(async function test_pageinfo_permissions() { + await setupPolicyEngineWithJson({ + policies: { + Permissions: { + Camera: { + BlockNewRequests: true, + Locked: true, + }, + Microphone: { + BlockNewRequests: true, + Locked: true, + }, + Location: { + BlockNewRequests: true, + Locked: true, + }, + Notifications: { + BlockNewRequests: true, + Locked: true, + }, + VirtualReality: { + BlockNewRequests: true, + Locked: true, + }, + Autoplay: { + Default: "block-audio", + Locked: true, + }, + }, + InstallAddonsPermission: { + Default: false, + }, + PopupBlocking: { + Locked: true, + }, + Cookies: { + Locked: true, + }, + }, + }); + + let permissions = [ + "geo", + "autoplay-media", + "install", + "popup", + "desktop-notification", + "cookie", + "camera", + "microphone", + "xr", + ]; + + await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function (browser) { + let pageInfo = BrowserPageInfo(TEST_ORIGIN, "permTab"); + await BrowserTestUtils.waitForEvent(pageInfo, "load"); + + for (let i = 0; i < permissions.length; i++) { + let permission = permissions[i]; + let checkbox = await TestUtils.waitForCondition(() => + pageInfo.document.getElementById(`${permission}Def`) + ); + + ok(checkbox.disabled, `${permission} checkbox should be disabled`); + } + + pageInfo.close(); + }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_passwordmanager.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_passwordmanager.js new file mode 100644 index 0000000000..f62d6cbf50 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_passwordmanager.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_pwmanager_blocked() { + await setupPolicyEngineWithJson({ + policies: { + PasswordManagerEnabled: false, + }, + }); + + await BrowserTestUtils.withNewTab( + "about:preferences#privacy", + async browser => { + is( + browser.contentDocument.getElementById("showPasswords").disabled, + true, + "showPasswords should be disabled." + ); + } + ); + + await testPageBlockedByPolicy("about:logins"); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_search_engine.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_search_engine.js new file mode 100644 index 0000000000..c0b7b20535 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_search_engine.js @@ -0,0 +1,109 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + CustomizableUITestUtils: + "resource://testing-common/CustomizableUITestUtils.sys.mjs", +}); + +let gCUITestUtils = new CustomizableUITestUtils(window); + +add_task(async function test_setup() { + await gCUITestUtils.addSearchBar(); + registerCleanupFunction(() => { + gCUITestUtils.removeSearchBar(); + }); +}); + +// |shouldWork| should be true if opensearch is expected to work and false if +// it is not. +async function test_opensearch(shouldWork) { + let searchBar = BrowserSearch.searchBar; + + let rootDir = getRootDirectory(gTestPath); + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + rootDir + "opensearch.html" + ); + let searchPopup = document.getElementById("PopupSearchAutoComplete"); + let promiseSearchPopupShown = BrowserTestUtils.waitForEvent( + searchPopup, + "popupshown" + ); + let searchBarButton = searchBar.querySelector(".searchbar-search-button"); + + searchBarButton.click(); + await promiseSearchPopupShown; + let oneOffsContainer = searchPopup.searchOneOffsContainer; + let engineElement = oneOffsContainer.querySelector( + ".searchbar-engine-one-off-add-engine" + ); + if (shouldWork) { + ok(engineElement, "There should be search engines available to add"); + ok( + searchBar.getAttribute("addengines"), + "Search bar should have addengines attribute" + ); + } else { + is( + engineElement, + null, + "There should be no search engines available to add" + ); + ok( + !searchBar.getAttribute("addengines"), + "Search bar should not have addengines attribute" + ); + } + await BrowserTestUtils.removeTab(tab); +} + +add_task(async function test_opensearch_works() { + // Clear out policies so we can test with no policies applied + await setupPolicyEngineWithJson({ + policies: {}, + }); + // Ensure that opensearch works before we make sure that it can be properly + // disabled + await test_opensearch(true); +}); + +add_task(async function setup_prevent_installs() { + await setupPolicyEngineWithJson({ + policies: { + SearchEngines: { + PreventInstalls: true, + }, + }, + }); +}); + +add_task(async function test_prevent_install_ui() { + // Check that about:preferences does not prompt user to install search engines + // if that feature is disabled + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:preferences#search" + ); + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + let linkContainer = content.document.getElementById("addEnginesBox"); + if (!linkContainer.hidden) { + await ContentTaskUtils.waitForMutationCondition( + linkContainer, + { attributeFilter: ["hidden"] }, + () => linkContainer.hidden + ); + } + ok( + linkContainer.hidden, + '"Find more search engines" link should be hidden' + ); + }); + await BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_opensearch_disabled() { + // Check that search engines cannot be added via opensearch + await test_opensearch(false); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_searchbar.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_searchbar.js new file mode 100644 index 0000000000..af892f2813 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_searchbar.js @@ -0,0 +1,36 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_setup(async function () { + await setupPolicyEngineWithJson({ + policies: { + SearchBar: "separate", + }, + }); +}); + +add_task(async function test_menu_shown() { + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let placement = CustomizableUI.getPlacementOfWidget("search-container"); + isnot(placement, null, "Search bar has a placement"); + is( + placement.area, + CustomizableUI.AREA_NAVBAR, + "Search bar is in the nav bar" + ); + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_menu_shown() { + await setupPolicyEngineWithJson({ + policies: { + SearchBar: "unified", + }, + }); + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let placement = CustomizableUI.getPlacementOfWidget("search-container"); + is(placement, null, "Search bar has no placement"); + await BrowserTestUtils.closeWindow(newWin); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_set_homepage.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_set_homepage.js new file mode 100644 index 0000000000..0c586fc45f --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_set_homepage.js @@ -0,0 +1,115 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +registerCleanupFunction(function restore_pref_values() { + // These two prefs are set as user prefs in case the "Locked" + // option from this policy was not used. In this case, it won't + // be tracked nor restored by the PoliciesPrefTracker. + Services.prefs.clearUserPref("browser.startup.homepage"); +}); + +add_task(async function homepage_test_simple() { + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + URL: "http://example1.com/", + }, + }, + }); + await check_homepage({ expectedURL: "http://example1.com/" }); +}); + +add_task(async function homepage_test_repeat_same_policy_value() { + // Simulate homepage change after policy applied + Services.prefs.setStringPref( + "browser.startup.homepage", + "http://example2.com/" + ); + Services.prefs.setIntPref("browser.startup.page", 3); + + // Policy should have no effect. Homepage has not been locked and policy value + // has not changed. We should be respecting the homepage that the user gave. + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + URL: "http://example1.com/", + }, + }, + }); + await check_homepage({ + expectedURL: "http://example2.com/", + expectedPageVal: 3, + }); + Services.prefs.clearUserPref("browser.startup.page"); + Services.prefs.clearUserPref("browser.startup.homepage"); +}); + +add_task(async function homepage_test_empty_additional() { + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + URL: "http://example1.com/", + Additional: [], + }, + }, + }); + await check_homepage({ expectedURL: "http://example1.com/" }); +}); + +add_task(async function homepage_test_single_additional() { + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + URL: "http://example1.com/", + Additional: ["http://example2.com/"], + }, + }, + }); + await check_homepage({ + expectedURL: "http://example1.com/|http://example2.com/", + }); +}); + +add_task(async function homepage_test_multiple_additional() { + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + URL: "http://example1.com/", + Additional: ["http://example2.com/", "http://example3.com/"], + }, + }, + }); + await check_homepage({ + expectedURL: + "http://example1.com/|http://example2.com/|http://example3.com/", + }); +}); + +add_task(async function homepage_test_locked() { + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + URL: "http://example4.com/", + Additional: ["http://example5.com/", "http://example6.com/"], + Locked: true, + }, + }, + }); + await check_homepage({ + expectedURL: + "http://example4.com/|http://example5.com/|http://example6.com/", + locked: true, + }); +}); + +add_task(async function homepage_test_anchor_link() { + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + URL: "http://example1.com/#test", + }, + }, + }); + await check_homepage({ expectedURL: "http://example1.com/#test" }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_set_startpage.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_set_startpage.js new file mode 100644 index 0000000000..bc28cdd51a --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_set_startpage.js @@ -0,0 +1,68 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +add_setup(async function () { + // browser.startup.page is set by unittest-required/user.js, + // but we need the default value + await SpecialPowers.pushPrefEnv({ + clear: [["browser.startup.page"]], + }); +}); + +add_task(async function homepage_test_startpage_homepage() { + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + URL: "http://example1.com/#test", + StartPage: "homepage", + }, + }, + }); + await check_homepage({ + expectedURL: "http://example1.com/#test", + expectedPageVal: 1, + }); +}); + +add_task(async function homepage_test_startpage_homepage_locked() { + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + URL: "http://example1.com/#test", + StartPage: "homepage-locked", + Locked: true, + }, + }, + }); + await check_homepage({ + expectedURL: "http://example1.com/#test", + expectedPageVal: 1, + locked: true, + }); +}); + +add_task(async function homepage_test_startpage_none() { + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + StartPage: "none", + }, + }, + }); + await check_homepage({ + expectedURL: "chrome://browser/content/blanktab.html", + expectedPageVal: 1, + }); +}); + +add_task(async function homepage_test_startpage_restore() { + await setupPolicyEngineWithJson({ + policies: { + Homepage: { + StartPage: "previous-session", + }, + }, + }); + await check_homepage({ expectedPageVal: 3 }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_support_menu.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_support_menu.js new file mode 100644 index 0000000000..d0a833484a --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_support_menu.js @@ -0,0 +1,68 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +add_setup(async function () { + await setupPolicyEngineWithJson({ + policies: { + SupportMenu: { + Title: "Title", + URL: "https://example.com/", + AccessKey: "T", + }, + }, + }); +}); + +add_task(async function test_help_menu() { + is( + Services.policies.getSupportMenu().URL.href, + "https://example.com/", + "The policy should have the correct URL." + ); + buildHelpMenu(); + let supportMenu = document.getElementById("helpPolicySupport"); + is(supportMenu.hidden, false, "The policy menu should be visible."); + is( + supportMenu.getAttribute("label"), + "Title", + "The policy menu should have the correct title." + ); + is( + supportMenu.getAttribute("accesskey"), + "T", + "The policy menu should have the correct access key." + ); +}); + +add_task(async function test_help_menu_app_menu() { + is( + Services.policies.getSupportMenu().URL.href, + "https://example.com/", + "The policy should have the correct URL." + ); + let menuButton = document.getElementById("PanelUI-menu-button"); + menuButton.click(); + await BrowserTestUtils.waitForEvent(window.PanelUI.mainView, "ViewShown"); + + let helpButtonId = "appMenu-help-button2"; + document.getElementById(helpButtonId).click(); + await BrowserTestUtils.waitForEvent( + document.getElementById("PanelUI-helpView"), + "ViewShown" + ); + + let supportMenu = document.getElementById("appMenu_helpPolicySupport"); + is(supportMenu.hidden, false, "The policy menu should be visible."); + is( + supportMenu.getAttribute("label"), + "Title", + "The policy menu should have the correct title." + ); + is( + supportMenu.getAttribute("accesskey"), + "T", + "The policy menu should have the correct access key." + ); + window.PanelUI.hide(); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_usermessaging.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_usermessaging.js new file mode 100644 index 0000000000..d8a3381779 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_usermessaging.js @@ -0,0 +1,21 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_notice_in_aboutprefences() { + await setupPolicyEngineWithJson({ + policies: { + UserMessaging: { + MoreFromMozilla: false, + }, + }, + }); + + await BrowserTestUtils.withNewTab("about:preferences", async browser => { + let moreFromMozillaCategory = browser.contentDocument.getElementById( + "category-more-from-mozilla" + ); + ok(moreFromMozillaCategory.hidden, "The category is hidden"); + }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_websitefilter.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_websitefilter.js new file mode 100644 index 0000000000..be51e76dce --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_websitefilter.js @@ -0,0 +1,186 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const SUPPORT_FILES_PATH = + "http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser/"; +const BLOCKED_PAGE = "policy_websitefilter_block.html"; +const EXCEPTION_PAGE = "policy_websitefilter_exception.html"; +const SAVELINKAS_PAGE = "policy_websitefilter_savelink.html"; + +async function clearWebsiteFilter() { + await setupPolicyEngineWithJson({ + policies: { + WebsiteFilter: { + Block: [], + Exceptions: [], + }, + }, + }); +} + +add_task(async function test_http() { + await setupPolicyEngineWithJson({ + policies: { + WebsiteFilter: { + Block: ["*://mochi.test/*policy_websitefilter_*"], + Exceptions: ["*://mochi.test/*_websitefilter_exception*"], + }, + }, + }); + + await checkBlockedPage(SUPPORT_FILES_PATH + BLOCKED_PAGE, true); + await checkBlockedPage( + "view-source:" + SUPPORT_FILES_PATH + BLOCKED_PAGE, + true + ); + await checkBlockedPage( + "about:reader?url=" + SUPPORT_FILES_PATH + BLOCKED_PAGE, + true + ); + await checkBlockedPage( + "about:READER?url=" + SUPPORT_FILES_PATH + BLOCKED_PAGE, + true + ); + await checkBlockedPage(SUPPORT_FILES_PATH + EXCEPTION_PAGE, false); + + await checkBlockedPage(SUPPORT_FILES_PATH + "301.sjs", true); + + await checkBlockedPage(SUPPORT_FILES_PATH + "302.sjs", true); + await clearWebsiteFilter(); +}); + +add_task(async function test_http_mixed_case() { + await setupPolicyEngineWithJson({ + policies: { + WebsiteFilter: { + Block: ["*://mochi.test/*policy_websitefilter_*"], + Exceptions: ["*://mochi.test/*_websitefilter_exception*"], + }, + }, + }); + + await checkBlockedPage(SUPPORT_FILES_PATH + BLOCKED_PAGE.toUpperCase(), true); + await checkBlockedPage( + SUPPORT_FILES_PATH + EXCEPTION_PAGE.toUpperCase(), + false + ); + await clearWebsiteFilter(); +}); + +add_task(async function test_file() { + await setupPolicyEngineWithJson({ + policies: { + WebsiteFilter: { + Block: ["file:///*"], + }, + }, + }); + + await checkBlockedPage("file:///this_should_be_blocked", true); + await clearWebsiteFilter(); +}); + +add_task(async function test_savelink() { + await setupPolicyEngineWithJson({ + policies: { + WebsiteFilter: { + Block: ["*://mochi.test/*policy_websitefilter_block*"], + }, + }, + }); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + SUPPORT_FILES_PATH + SAVELINKAS_PAGE + ); + + let contextMenu = document.getElementById("contentAreaContextMenu"); + let promiseContextMenuOpen = BrowserTestUtils.waitForEvent( + contextMenu, + "popupshown" + ); + await BrowserTestUtils.synthesizeMouse( + "#savelink_blocked", + 0, + 0, + { + type: "contextmenu", + button: 2, + centered: true, + }, + gBrowser.selectedBrowser + ); + await promiseContextMenuOpen; + + let saveLink = document.getElementById("context-savelink"); + is(saveLink.disabled, true, "Save Link As should be disabled"); + + let promiseContextMenuHidden = BrowserTestUtils.waitForEvent( + contextMenu, + "popuphidden" + ); + contextMenu.hidePopup(); + await promiseContextMenuHidden; + + promiseContextMenuOpen = BrowserTestUtils.waitForEvent( + contextMenu, + "popupshown" + ); + await BrowserTestUtils.synthesizeMouse( + "#savelink_notblocked", + 0, + 0, + { + type: "contextmenu", + button: 2, + centered: true, + }, + gBrowser.selectedBrowser + ); + await promiseContextMenuOpen; + + saveLink = document.getElementById("context-savelink"); + is(saveLink.disabled, false, "Save Link As should not be disabled"); + + promiseContextMenuHidden = BrowserTestUtils.waitForEvent( + contextMenu, + "popuphidden" + ); + contextMenu.hidePopup(); + await promiseContextMenuHidden; + + BrowserTestUtils.removeTab(tab); + await clearWebsiteFilter(); +}); + +add_task(async function test_http_json_policy() { + await setupPolicyEngineWithJson({ + policies: { + WebsiteFilter: `{ + "Block": ["*://mochi.test/*policy_websitefilter_*"], + "Exceptions": ["*://mochi.test/*_websitefilter_exception*"] + }`, + }, + }); + + await checkBlockedPage(SUPPORT_FILES_PATH + BLOCKED_PAGE, true); + await checkBlockedPage( + "view-source:" + SUPPORT_FILES_PATH + BLOCKED_PAGE, + true + ); + await checkBlockedPage( + "about:reader?url=" + SUPPORT_FILES_PATH + BLOCKED_PAGE, + true + ); + await checkBlockedPage( + "about:READER?url=" + SUPPORT_FILES_PATH + BLOCKED_PAGE, + true + ); + await checkBlockedPage(SUPPORT_FILES_PATH + EXCEPTION_PAGE, false); + + await checkBlockedPage(SUPPORT_FILES_PATH + "301.sjs", true); + + await checkBlockedPage(SUPPORT_FILES_PATH + "302.sjs", true); + await clearWebsiteFilter(); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/disable_app_update/browser.toml b/browser/components/enterprisepolicies/tests/browser/disable_app_update/browser.toml new file mode 100644 index 0000000000..280c6e2838 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_app_update/browser.toml @@ -0,0 +1,9 @@ +[DEFAULT] +prefs = [ + "app.update.disabledForTesting=false", + "browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json'", +] +support-files = ["config_disable_app_update.json"] +skip-if = ["os == 'win' && msix"] # Updater is disabled in MSIX builds + +["browser_policy_disable_app_update.js"] diff --git a/browser/components/enterprisepolicies/tests/browser/disable_app_update/browser_policy_disable_app_update.js b/browser/components/enterprisepolicies/tests/browser/disable_app_update/browser_policy_disable_app_update.js new file mode 100644 index 0000000000..2f68436882 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_app_update/browser_policy_disable_app_update.js @@ -0,0 +1,122 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.sys.mjs", +}); + +var updateService = Cc["@mozilla.org/updates/update-service;1"].getService( + Ci.nsIApplicationUpdateService +); + +add_task(async function test_updates_post_policy() { + is( + Services.policies.isAllowed("appUpdate"), + false, + "appUpdate should be disabled by policy." + ); + + is( + updateService.canCheckForUpdates, + false, + "Should not be able to check for updates with DisableAppUpdate enabled." + ); +}); + +add_task(async function test_update_preferences_ui() { + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:preferences" + ); + + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + let setting = content.document.getElementById("updateSettingsContainer"); + is( + setting.hidden, + true, + "Update choices should be disabled when app update is locked by policy" + ); + }); + + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_update_about_ui() { + let aboutDialog = await waitForAboutDialog(); + let panelId = "policyDisabled"; + + await BrowserTestUtils.waitForCondition( + () => aboutDialog.gAppUpdater?.selectedPanel?.id == panelId, + 'Waiting for expected panel ID - expected "' + panelId + '"' + ); + is( + aboutDialog.gAppUpdater.selectedPanel.id, + panelId, + "The About Dialog panel Id should equal " + panelId + ); + + // Make sure that we still remain on the "disabled by policy" panel after + // `AppUpdater.stop()` is called. + aboutDialog.gAppUpdater._appUpdater.stop(); + is( + aboutDialog.gAppUpdater.selectedPanel.id, + panelId, + "The About Dialog panel Id should still equal " + panelId + ); + + aboutDialog.close(); +}); + +/** + * Waits for the About Dialog to load. + * + * @returns {Promise} + * A promise that returns the domWindow for the About Dialog and resolves when + * the About Dialog loads. + */ +function waitForAboutDialog() { + return new Promise(resolve => { + var listener = { + onOpenWindow: aXULWindow => { + Services.wm.removeListener(listener); + + async function aboutDialogOnLoad() { + domwindow.removeEventListener("load", aboutDialogOnLoad, true); + let chromeURI = "chrome://browser/content/aboutDialog.xhtml"; + is( + domwindow.document.location.href, + chromeURI, + "About dialog appeared" + ); + resolve(domwindow); + } + + var domwindow = aXULWindow.docShell.domWindow; + domwindow.addEventListener("load", aboutDialogOnLoad, true); + }, + onCloseWindow: aXULWindow => {}, + }; + + Services.wm.addListener(listener); + openAboutDialog(); + }); +} + +add_task(async function test_no_update_intervention() { + await BrowserTestUtils.withNewTab("about:blank", async () => { + let context = await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: "update firefox", + waitForFocus, + fireInputEvent: true, + }); + for (let result of context.results) { + Assert.notEqual(result.type, UrlbarUtils.RESULT_TYPE.TIP); + } + await UrlbarTestUtils.promisePopupClose(window, () => + window.gURLBar.blur() + ); + }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json b/browser/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json new file mode 100644 index 0000000000..f36622021f --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json @@ -0,0 +1,5 @@ +{ + "policies": { + "DisableAppUpdate": true + } +} diff --git a/browser/components/enterprisepolicies/tests/browser/disable_default_bookmarks/bookmarks_policies.json b/browser/components/enterprisepolicies/tests/browser/disable_default_bookmarks/bookmarks_policies.json new file mode 100644 index 0000000000..117768efb3 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_default_bookmarks/bookmarks_policies.json @@ -0,0 +1,5 @@ +{ + "policies": { + "NoDefaultBookmarks": true + } +} diff --git a/browser/components/enterprisepolicies/tests/browser/disable_default_bookmarks/browser.toml b/browser/components/enterprisepolicies/tests/browser/disable_default_bookmarks/browser.toml new file mode 100644 index 0000000000..5066dfd4d3 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_default_bookmarks/browser.toml @@ -0,0 +1,5 @@ +[DEFAULT] +prefs = ["browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/disable_default_bookmarks/bookmarks_policies.json'"] +support-files = ["bookmarks_policies.json"] + +["browser_policy_no_default_bookmarks.js"] diff --git a/browser/components/enterprisepolicies/tests/browser/disable_default_bookmarks/browser_policy_no_default_bookmarks.js b/browser/components/enterprisepolicies/tests/browser/disable_default_bookmarks/browser_policy_no_default_bookmarks.js new file mode 100644 index 0000000000..aecd088ab3 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_default_bookmarks/browser_policy_no_default_bookmarks.js @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// This test must run in a separate folder because the +// No Default Bookmarks policy needs to be present on +// the first run of the profile, and not dinamically loaded +// like most of the policies tested in the main test folder. + +add_task(async function test_no_default_bookmarks() { + let firstBookmarkOnToolbar = await PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0, + }); + + let firstBookmarkOnMenu = await PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: 0, + }); + + is(firstBookmarkOnToolbar, null, "No bookmarks on toolbar"); + is(firstBookmarkOnMenu, null, "No bookmarks on menu"); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/disable_developer_tools/browser.toml b/browser/components/enterprisepolicies/tests/browser/disable_developer_tools/browser.toml new file mode 100644 index 0000000000..0220e7b692 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_developer_tools/browser.toml @@ -0,0 +1,5 @@ +[DEFAULT] +prefs = ["browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/disable_developer_tools/config_disable_developer_tools.json'"] +support-files = ["config_disable_developer_tools.json"] + +["browser_policy_disable_developer_tools.js"] diff --git a/browser/components/enterprisepolicies/tests/browser/disable_developer_tools/browser_policy_disable_developer_tools.js b/browser/components/enterprisepolicies/tests/browser/disable_developer_tools/browser_policy_disable_developer_tools.js new file mode 100644 index 0000000000..27794aabbb --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_developer_tools/browser_policy_disable_developer_tools.js @@ -0,0 +1,87 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { EnterprisePolicyTesting } = ChromeUtils.importESModule( + "resource://testing-common/EnterprisePolicyTesting.sys.mjs" +); +var updateService = Cc["@mozilla.org/updates/update-service;1"].getService( + Ci.nsIApplicationUpdateService +); + +add_task(async function test_updates_post_policy() { + is( + Services.policies.isAllowed("devtools"), + false, + "devtools should be disabled by policy." + ); + + is( + Services.prefs.getBoolPref("devtools.policy.disabled"), + true, + "devtools dedicated disabled pref is set to true" + ); + + Services.prefs.setBoolPref("devtools.policy.disabled", false); + + is( + Services.prefs.getBoolPref("devtools.policy.disabled"), + true, + "devtools dedicated disabled pref can not be updated" + ); + + await testPageBlockedByPolicy("about:devtools-toolbox"); + await testPageBlockedByPolicy("about:debugging"); + await testPageBlockedByPolicy("about:profiling"); + + let testURL = "data:text/html;charset=utf-8,test"; + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + testURL, + false + ); + + let menuButton = document.getElementById("PanelUI-menu-button"); + menuButton.click(); + await BrowserTestUtils.waitForEvent(window.PanelUI.mainView, "ViewShown"); + let moreToolsButtonId = "appMenu-more-button2"; + document.getElementById(moreToolsButtonId).click(); + await BrowserTestUtils.waitForEvent( + document.getElementById("appmenu-moreTools"), + "ViewShown" + ); + is( + document.getElementById("appmenu-developer-tools-view").children.length, + 2, + "The developer tools are properly populated" + ); + window.PanelUI.hide(); + + BrowserTestUtils.removeTab(tab); +}); + +// Copied from ../head.js. head.js was never intended to be used with tests +// that use a JSON file versus calling setupPolicyEngineWithJson so I have +// to copy this function here versus including it. +async function testPageBlockedByPolicy(page, policyJSON) { + if (policyJSON) { + await EnterprisePolicyTesting.setupPolicyEngineWithJson(policyJSON); + } + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:blank" }, + async browser => { + BrowserTestUtils.startLoadingURIString(browser, page); + await BrowserTestUtils.browserLoaded(browser, false, page, true); + await SpecialPowers.spawn(browser, [page], async function (innerPage) { + ok( + content.document.documentURI.startsWith( + "about:neterror?e=blockedByPolicy" + ), + content.document.documentURI + + " should start with about:neterror?e=blockedByPolicy" + ); + }); + } + ); +} diff --git a/browser/components/enterprisepolicies/tests/browser/disable_developer_tools/config_disable_developer_tools.json b/browser/components/enterprisepolicies/tests/browser/disable_developer_tools/config_disable_developer_tools.json new file mode 100644 index 0000000000..08c393dec6 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_developer_tools/config_disable_developer_tools.json @@ -0,0 +1,5 @@ +{ + "policies": { + "DisableDeveloperTools": true + } +} diff --git a/browser/components/enterprisepolicies/tests/browser/disable_forget_button/browser.toml b/browser/components/enterprisepolicies/tests/browser/disable_forget_button/browser.toml new file mode 100644 index 0000000000..0acb35194f --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_forget_button/browser.toml @@ -0,0 +1,5 @@ +[DEFAULT] +prefs = ["browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/disable_forget_button/forget_button.json'"] +support-files = ["forget_button.json"] + +["browser_policy_disable_forgetbutton.js"] diff --git a/browser/components/enterprisepolicies/tests/browser/disable_forget_button/browser_policy_disable_forgetbutton.js b/browser/components/enterprisepolicies/tests/browser/disable_forget_button/browser_policy_disable_forgetbutton.js new file mode 100644 index 0000000000..723aad5d75 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_forget_button/browser_policy_disable_forgetbutton.js @@ -0,0 +1,9 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_policy_disable_forget_button() { + let widget = CustomizableUI.getWidget("panic-button"); + isnot(widget.type, "view", "Forget Button was not created"); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/disable_forget_button/forget_button.json b/browser/components/enterprisepolicies/tests/browser/disable_forget_button/forget_button.json new file mode 100644 index 0000000000..30baf64df4 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_forget_button/forget_button.json @@ -0,0 +1,5 @@ +{ + "policies": { + "DisableForgetButton": true + } +} diff --git a/browser/components/enterprisepolicies/tests/browser/disable_fxscreenshots/browser.toml b/browser/components/enterprisepolicies/tests/browser/disable_fxscreenshots/browser.toml new file mode 100644 index 0000000000..233a767a1c --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_fxscreenshots/browser.toml @@ -0,0 +1,8 @@ +[DEFAULT] +prefs = [ + "browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/disable_fxscreenshots/config_disable_fxscreenshots.json'", + "extensions.screenshots.disabled=false", +] +support-files = ["config_disable_fxscreenshots.json"] + +["browser_policy_disable_fxscreenshots.js"] diff --git a/browser/components/enterprisepolicies/tests/browser/disable_fxscreenshots/browser_policy_disable_fxscreenshots.js b/browser/components/enterprisepolicies/tests/browser/disable_fxscreenshots/browser_policy_disable_fxscreenshots.js new file mode 100644 index 0000000000..e2b9232aa3 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_fxscreenshots/browser_policy_disable_fxscreenshots.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const PREF_DISABLE_FX_SCREENSHOTS = "extensions.screenshots.disabled"; + +async function checkScreenshots(shouldBeEnabled) { + return BrowserTestUtils.waitForCondition(() => { + return ( + !!PageActions.actionForID("screenshots_mozilla_org") == shouldBeEnabled + ); + }, "Expecting screenshots to be " + shouldBeEnabled); +} + +add_task(async function test_disable_firefox_screenshots() { + // Dynamically toggling the PREF_DISABLE_FX_SCREENSHOTS is very finicky, because + // that pref is being watched, and it makes the Firefox Screenshots system add-on + // to start or stop, causing intermittency. + // + // Firefox Screenshots is disabled by default on tests (in + // testing/profiles/common/user.js). What we do here to test this policy is to enable + // it on this specific test folder (through browser.ini) and then we let the policy + // engine be responsible for disabling Firefox Screenshots in this case. + + is( + Services.prefs.getBoolPref(PREF_DISABLE_FX_SCREENSHOTS), + true, + "Screenshots pref is disabled" + ); + + await BrowserTestUtils.withNewTab("data:text/html,Test", async function () { + await checkScreenshots(false); + }); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/disable_fxscreenshots/config_disable_fxscreenshots.json b/browser/components/enterprisepolicies/tests/browser/disable_fxscreenshots/config_disable_fxscreenshots.json new file mode 100644 index 0000000000..4caf055394 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/disable_fxscreenshots/config_disable_fxscreenshots.json @@ -0,0 +1,5 @@ +{ + "policies": { + "DisableFirefoxScreenshots": true + } +} diff --git a/browser/components/enterprisepolicies/tests/browser/extensionsettings.html b/browser/components/enterprisepolicies/tests/browser/extensionsettings.html new file mode 100644 index 0000000000..da70ebdf59 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/extensionsettings.html @@ -0,0 +1,28 @@ + +<!DOCTYPE html> +<html> +<head> +<meta charset="UTF-8"> +<script type="text/javascript"> +function installTrigger(url) { + try { + InstallTrigger.install({extension: url}); + } catch (err) { + dump(`Failed to execute InstallTrigger.install: ${err}\n`); + } + return false; +} +</script> +</head> +<body> +<p> +<a id="policytest" href="policytest_v0.1.xpi">policytest@mozilla.com</a> +</p> +<p> +<a id="policytest_installtrigger" onclick="return installTrigger(this.href);" href="policytest_v0.1.xpi">policytest@mozilla.com</a> +</p> +<p> +<a id="policytest_otherdomain" href="http://example.org:80/browser/browser/components/enterprisepolicies/tests/browser/policytest_v0.1.xpi">policytest@mozilla.com</a> +</p> +</body> +</html> diff --git a/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/browser.toml b/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/browser.toml new file mode 100644 index 0000000000..58b8322d72 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/browser.toml @@ -0,0 +1,5 @@ +[DEFAULT] +prefs = ["browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/disable_hardware_acceleration.json'"] +support-files = ["disable_hardware_acceleration.json"] + +["browser_policy_hardware_acceleration.js"] diff --git a/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/browser_policy_hardware_acceleration.js b/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/browser_policy_hardware_acceleration.js new file mode 100644 index 0000000000..436bd410d1 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/browser_policy_hardware_acceleration.js @@ -0,0 +1,13 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_policy_hardware_acceleration() { + let winUtils = Services.wm.getMostRecentWindow("").windowUtils; + let layerManager = winUtils.layerManagerType; + ok( + layerManager == "Basic" || layerManager == "WebRender (Software)", + "Hardware acceleration disabled" + ); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/disable_hardware_acceleration.json b/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/disable_hardware_acceleration.json new file mode 100644 index 0000000000..acbdc0a3f4 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/disable_hardware_acceleration.json @@ -0,0 +1,5 @@ +{ + "policies": { + "HardwareAcceleration": false + } +} diff --git a/browser/components/enterprisepolicies/tests/browser/head.js b/browser/components/enterprisepolicies/tests/browser/head.js new file mode 100644 index 0000000000..bb08173aa9 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/head.js @@ -0,0 +1,251 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const { EnterprisePolicyTesting, PoliciesPrefTracker } = + ChromeUtils.importESModule( + "resource://testing-common/EnterprisePolicyTesting.sys.mjs" + ); + +ChromeUtils.defineESModuleGetters(this, { + HomePage: "resource:///modules/HomePage.sys.mjs", +}); + +PoliciesPrefTracker.start(); + +async function setupPolicyEngineWithJson(json, customSchema) { + PoliciesPrefTracker.restoreDefaultValues(); + if (typeof json != "object") { + let filePath = getTestFilePath(json ? json : "non-existing-file.json"); + return EnterprisePolicyTesting.setupPolicyEngineWithJson( + filePath, + customSchema + ); + } + return EnterprisePolicyTesting.setupPolicyEngineWithJson(json, customSchema); +} + +function checkLockedPref(prefName, prefValue) { + EnterprisePolicyTesting.checkPolicyPref(prefName, prefValue, true); +} + +function checkUnlockedPref(prefName, prefValue) { + EnterprisePolicyTesting.checkPolicyPref(prefName, prefValue, false); +} + +// Checks that a page was blocked by seeing if it was replaced with about:neterror +async function checkBlockedPage(url, expectedBlocked) { + let newTab = BrowserTestUtils.addTab(gBrowser); + gBrowser.selectedTab = newTab; + + if (expectedBlocked) { + let promise = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser); + BrowserTestUtils.startLoadingURIString(gBrowser, url); + await promise; + is( + newTab.linkedBrowser.documentURI.spec.startsWith( + "about:neterror?e=blockedByPolicy" + ), + true, + "Should be blocked by policy" + ); + } else { + let promise = BrowserTestUtils.browserStopped(gBrowser, url); + BrowserTestUtils.startLoadingURIString(gBrowser, url); + await promise; + + is( + newTab.linkedBrowser.documentURI.spec, + url, + "Should not be blocked by policy" + ); + } + BrowserTestUtils.removeTab(newTab); +} + +async function check_homepage({ + expectedURL, + expectedPageVal = -1, + locked = false, +}) { + if (expectedURL) { + is(HomePage.get(), expectedURL, "Homepage URL should match expected"); + is( + Services.prefs.prefIsLocked("browser.startup.homepage"), + locked, + "Lock status of browser.startup.homepage should match expected" + ); + } + if (expectedPageVal != -1) { + is( + Services.prefs.getIntPref("browser.startup.page", -1), + expectedPageVal, + "Pref page value should match expected" + ); + is( + Services.prefs.prefIsLocked("browser.startup.page"), + locked, + "Lock status of browser.startup.page should match expected" + ); + } + + // Test that UI is disabled when the Locked property is enabled + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:preferences" + ); + await ContentTask.spawn( + tab.linkedBrowser, + { expectedURL, expectedPageVal, locked }, + // eslint-disable-next-line no-shadow + async function ({ expectedURL, expectedPageVal, locked }) { + if (expectedPageVal != -1) { + // Only check restore checkbox for StartPage + let browserRestoreSessionCheckbox = content.document.getElementById( + "browserRestoreSession" + ); + is( + browserRestoreSessionCheckbox.disabled, + locked, + "Disabled status of session restore status should match expected" + ); + let shouldBeChecked = expectedPageVal === 3; + is( + browserRestoreSessionCheckbox.checked, + shouldBeChecked, + "Session restore status checkbox should be: " + + (shouldBeChecked ? "checked" : "unchecked") + ); + } + + if (!expectedURL) { + // If only StartPage was changed, no need to check these + return; + } + await content.gotoPref("paneHome"); + + let homepageTextbox = content.document.getElementById("homePageUrl"); + // Unfortunately this test does not work because the new UI does not fill + // default values into the URL box at the moment. + // is(homepageTextbox.value, expectedURL, + // "Homepage URL should match expected"); + + // Wait for rendering to be finished + await ContentTaskUtils.waitForCondition( + () => + content.document.getElementById("useCurrentBtn").disabled === locked + ); + + is( + homepageTextbox.disabled, + locked, + "Homepage URL text box disabled status should match expected" + ); + is( + content.document.getElementById("homeMode").disabled, + locked, + "Home mode drop down disabled status should match expected" + ); + is( + content.document.getElementById("useCurrentBtn").disabled, + locked, + '"Use current page" button disabled status should match expected' + ); + is( + content.document.getElementById("useBookmarkBtn").disabled, + locked, + '"Use bookmark" button disabled status should match expected' + ); + is( + content.document.getElementById("restoreDefaultHomePageBtn").disabled, + locked, + '"Restore defaults" button disabled status should match expected' + ); + } + ); + await BrowserTestUtils.removeTab(tab); +} + +add_setup(async function policies_headjs_startWithCleanSlate() { + if (Services.policies.status != Ci.nsIEnterprisePolicies.INACTIVE) { + await setupPolicyEngineWithJson(""); + } + is( + Services.policies.status, + Ci.nsIEnterprisePolicies.INACTIVE, + "Engine is inactive at the start of the test" + ); +}); + +registerCleanupFunction(async function policies_headjs_finishWithCleanSlate() { + if (Services.policies.status != Ci.nsIEnterprisePolicies.INACTIVE) { + await setupPolicyEngineWithJson(""); + } + is( + Services.policies.status, + Ci.nsIEnterprisePolicies.INACTIVE, + "Engine is inactive at the end of the test" + ); + + EnterprisePolicyTesting.resetRunOnceState(); + PoliciesPrefTracker.stop(); +}); + +function waitForAddonInstall(addonId) { + return new Promise(resolve => { + let listener = { + onInstallEnded(install, addon) { + if (addon.id == addonId) { + AddonManager.removeInstallListener(listener); + resolve(); + } + }, + onDownloadFailed() { + AddonManager.removeInstallListener(listener); + resolve(); + }, + onInstallFailed() { + AddonManager.removeInstallListener(listener); + resolve(); + }, + }; + AddonManager.addInstallListener(listener); + }); +} + +function waitForAddonUninstall(addonId) { + return new Promise(resolve => { + let listener = {}; + listener.onUninstalled = addon => { + if (addon.id == addonId) { + AddonManager.removeAddonListener(listener); + resolve(); + } + }; + AddonManager.addAddonListener(listener); + }); +} + +async function testPageBlockedByPolicy(page, policyJSON) { + if (policyJSON) { + await EnterprisePolicyTesting.setupPolicyEngineWithJson(policyJSON); + } + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:blank" }, + async browser => { + BrowserTestUtils.startLoadingURIString(browser, page); + await BrowserTestUtils.browserLoaded(browser, false, page, true); + await SpecialPowers.spawn(browser, [page], async function (innerPage) { + ok( + content.document.documentURI.startsWith( + "about:neterror?e=blockedByPolicy" + ), + content.document.documentURI + + " should start with about:neterror?e=blockedByPolicy" + ); + }); + } + ); +} diff --git a/browser/components/enterprisepolicies/tests/browser/homepage_button/browser.toml b/browser/components/enterprisepolicies/tests/browser/homepage_button/browser.toml new file mode 100644 index 0000000000..1566f801a5 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/homepage_button/browser.toml @@ -0,0 +1,5 @@ +[DEFAULT] +prefs = ["browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/homepage_button/homepage_policies.json'"] +support-files = ["homepage_policies.json"] + +["browser_show_home_button_with_homepage_policy.js"] diff --git a/browser/components/enterprisepolicies/tests/browser/homepage_button/browser_show_home_button_with_homepage_policy.js b/browser/components/enterprisepolicies/tests/browser/homepage_button/browser_show_home_button_with_homepage_policy.js new file mode 100644 index 0000000000..c1eafb0a52 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/homepage_button/browser_show_home_button_with_homepage_policy.js @@ -0,0 +1,9 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_homepage_button_with_homepage() { + let homeButton = window.document.getElementById("home-button"); + isnot(homeButton, null, "The home button should be visible"); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/homepage_button/homepage_policies.json b/browser/components/enterprisepolicies/tests/browser/homepage_button/homepage_policies.json new file mode 100644 index 0000000000..960e68348e --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/homepage_button/homepage_policies.json @@ -0,0 +1,7 @@ +{ + "policies": { + "Homepage": { + "URL": "http://example1.com/" + } + } +} diff --git a/browser/components/enterprisepolicies/tests/browser/managedbookmarks/browser.toml b/browser/components/enterprisepolicies/tests/browser/managedbookmarks/browser.toml new file mode 100644 index 0000000000..752893e958 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/managedbookmarks/browser.toml @@ -0,0 +1,7 @@ +[DEFAULT] +prefs = ["browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/managedbookmarks/managedbookmarks.json'"] +support-files = ["managedbookmarks.json"] + +skip-if = ["os == 'linux'"] # Popup timeout issue - see Bug 1742167 + +["browser_policy_managedbookmarks.js"] diff --git a/browser/components/enterprisepolicies/tests/browser/managedbookmarks/browser_policy_managedbookmarks.js b/browser/components/enterprisepolicies/tests/browser/managedbookmarks/browser_policy_managedbookmarks.js new file mode 100644 index 0000000000..494f49978c --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/managedbookmarks/browser_policy_managedbookmarks.js @@ -0,0 +1,210 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_policy_managedbookmarks() { + let managedBookmarksMenu = + window.document.getElementById("managed-bookmarks"); + + is( + managedBookmarksMenu.hidden, + false, + "Managed bookmarks button should be visible." + ); + is( + managedBookmarksMenu.label, + "Folder 1", + "Managed bookmarks buttons should have correct label" + ); + + let popupShownPromise = BrowserTestUtils.waitForEvent( + managedBookmarksMenu.menupopup, + "popupshown", + false + ); + let popupHiddenPromise = BrowserTestUtils.waitForEvent( + managedBookmarksMenu.menupopup, + "popuphidden", + false + ); + managedBookmarksMenu.open = true; + await popupShownPromise; + + is( + managedBookmarksMenu.menupopup.children[0].label, + "Bookmark 1", + "Bookmark should have correct label" + ); + is( + managedBookmarksMenu.menupopup.children[0].link, + "https://example.com/", + "Bookmark should have correct link" + ); + is( + managedBookmarksMenu.menupopup.children[1].label, + "Bookmark 2", + "Bookmark should have correct label" + ); + is( + managedBookmarksMenu.menupopup.children[1].link, + "https://bookmark2.example.com/", + "Bookmark should have correct link" + ); + let subFolder = managedBookmarksMenu.menupopup.children[2]; + is(subFolder.label, "Folder 2", "Subfolder should have correct label"); + is( + subFolder.menupopup.children[0].label, + "Bookmark 3", + "Bookmark should have correct label" + ); + is( + subFolder.menupopup.children[0].link, + "https://bookmark3.example.com/", + "Bookmark should have correct link" + ); + is( + subFolder.menupopup.children[1].label, + "Bookmark 4", + "Bookmark should have correct link" + ); + is( + subFolder.menupopup.children[1].link, + "https://bookmark4.example.com/", + "Bookmark should have correct label" + ); + subFolder = managedBookmarksMenu.menupopup.children[3]; + await TestUtils.waitForCondition(() => { + // Need to wait for Fluent to translate + return subFolder.label == "Subfolder"; + }, "Subfolder should have correct label"); + is( + subFolder.menupopup.children[0].label, + "Bookmark 5", + "Bookmark should have correct label" + ); + is( + subFolder.menupopup.children[0].link, + "https://bookmark5.example.com/", + "Bookmark should have correct link" + ); + is( + subFolder.menupopup.children[1].label, + "Bookmark 6", + "Bookmark should have correct link" + ); + is( + subFolder.menupopup.children[1].link, + "https://bookmark6.example.com/", + "Bookmark should have correct label" + ); + + managedBookmarksMenu.open = false; + await popupHiddenPromise; +}); + +add_task(async function test_open_managedbookmark() { + let managedBookmarksMenu = + window.document.getElementById("managed-bookmarks"); + + let promise = BrowserTestUtils.waitForEvent( + managedBookmarksMenu.menupopup, + "popupshown", + false + ); + managedBookmarksMenu.open = true; + await promise; + + let context = document.getElementById("placesContext"); + let openContextMenuPromise = BrowserTestUtils.waitForEvent( + context, + "popupshown" + ); + EventUtils.synthesizeMouseAtCenter( + managedBookmarksMenu.menupopup.children[0], + { + button: 2, + type: "contextmenu", + } + ); + await openContextMenuPromise; + info("Opened context menu"); + + ok( + document.getElementById("placesContext_open:newprivatewindow").hidden, + "Private Browsing menu should be hidden" + ); + ok( + document.getElementById("placesContext_openContainer:tabs").hidden, + "Open in Tabs should be hidden" + ); + ok( + document.getElementById("placesContext_delete").hidden, + "Delete should be hidden" + ); + + let tabCreatedPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true); + + let openInNewTabOption = document.getElementById("placesContext_open:newtab"); + context.activateItem(openInNewTabOption); + info("Click open in new tab"); + + let lastOpenedTab = await tabCreatedPromise; + Assert.equal( + lastOpenedTab.linkedBrowser.currentURI.spec, + "https://example.com/", + "Should have opened the correct URI" + ); + await BrowserTestUtils.removeTab(lastOpenedTab); +}); + +add_task(async function test_copy_managedbookmark() { + let managedBookmarksMenu = + window.document.getElementById("managed-bookmarks"); + + let promise = BrowserTestUtils.waitForEvent( + managedBookmarksMenu.menupopup, + "popupshown", + false + ); + managedBookmarksMenu.open = true; + await promise; + + let context = document.getElementById("placesContext"); + let openContextMenuPromise = BrowserTestUtils.waitForEvent( + context, + "popupshown" + ); + EventUtils.synthesizeMouseAtCenter( + managedBookmarksMenu.menupopup.children[0], + { + button: 2, + type: "contextmenu", + } + ); + await openContextMenuPromise; + info("Opened context menu"); + + let copyOption = document.getElementById("placesContext_copy"); + + await new Promise((resolve, reject) => { + SimpleTest.waitForClipboard( + "https://example.com/", + () => { + context.activateItem(copyOption); + }, + resolve, + () => { + ok(false, "Clipboard copy failed"); + reject(); + } + ); + }); + + let popupHidden = BrowserTestUtils.waitForEvent( + managedBookmarksMenu.menupopup, + "popuphidden" + ); + managedBookmarksMenu.menupopup.hidePopup(); + await popupHidden; +}); diff --git a/browser/components/enterprisepolicies/tests/browser/managedbookmarks/managedbookmarks.json b/browser/components/enterprisepolicies/tests/browser/managedbookmarks/managedbookmarks.json new file mode 100644 index 0000000000..e93d910d87 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/managedbookmarks/managedbookmarks.json @@ -0,0 +1,44 @@ +{ + "policies": { + "DisablePrivateBrowsing": true, + "DisplayBookmarksToolbar": true, + "ManagedBookmarks": [ + { + "toplevel_name": "Folder 1" + }, + { + "name": "Bookmark 1", + "url": "https://example.com/" + }, + { + "name": "Bookmark 2", + "url": "https://bookmark2.example.com/" + }, + { + "children": [ + { + "name": "Bookmark 3", + "url": "https://bookmark3.example.com/" + }, + { + "name": "Bookmark 4", + "url": "https://bookmark4.example.com/" + } + ], + "name": "Folder 2" + }, + { + "children": [ + { + "name": "Bookmark 5", + "url": "https://bookmark5.example.com/" + }, + { + "name": "Bookmark 6", + "url": "https://bookmark6.example.com/" + } + ] + } + ] + } +} diff --git a/browser/components/enterprisepolicies/tests/browser/opensearch.html b/browser/components/enterprisepolicies/tests/browser/opensearch.html new file mode 100644 index 0000000000..b3f12d6bd4 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/opensearch.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="UTF-8"> +<link rel="search" type="application/opensearchdescription+xml" title="newEngine" href="http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser/opensearchEngine.xml"> +</head> +<body></body> +</html> diff --git a/browser/components/enterprisepolicies/tests/browser/opensearchEngine.xml b/browser/components/enterprisepolicies/tests/browser/opensearchEngine.xml new file mode 100644 index 0000000000..21ddc4b9a9 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/opensearchEngine.xml @@ -0,0 +1,12 @@ +<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" + xmlns:moz="http://www.mozilla.org/2006/browser/search/"> + <ShortName>Foo</ShortName> + <Description>Foo Search</Description> + <InputEncoding>utf-8</InputEncoding> + <Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC</Image> + <Url type="text/html" method="GET" template="http://mochi.test:8888/browser/browser/components/search/test/?search"> + <Param name="test" value="{searchTerms}"/> + </Url> + <moz:SearchForm>http://mochi.test:8888/browser/browser/components/search/test/</moz:SearchForm> + <moz:Alias>fooalias</moz:Alias> +</OpenSearchDescription> diff --git a/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_block.html b/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_block.html new file mode 100644 index 0000000000..dd6596615d --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_block.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <title>This page should be blocked</title> + </head> + <body> + This page should not be seen. + </body> +</html> diff --git a/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_exception.html b/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_exception.html new file mode 100644 index 0000000000..bf389aac31 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_exception.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <title>This page should not be blocked</title> + </head> + <body> + This page should be seen. + </body> +</html> diff --git a/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_savelink.html b/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_savelink.html new file mode 100644 index 0000000000..d2ec93eac5 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_savelink.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <title>Save Link As test</title> + </head> + <body> + <a id="savelink_blocked" href="http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_block.html">Should not be saveable</a><br/> + <a id="savelink_notblocked" href="http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_no_block.html">Should be saveable</a> +</body> +</html> diff --git a/browser/components/enterprisepolicies/tests/browser/policytest_v0.1.xpi b/browser/components/enterprisepolicies/tests/browser/policytest_v0.1.xpi Binary files differnew file mode 100644 index 0000000000..ee2a6289ee --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/policytest_v0.1.xpi diff --git a/browser/components/enterprisepolicies/tests/browser/policytest_v0.2.xpi b/browser/components/enterprisepolicies/tests/browser/policytest_v0.2.xpi Binary files differnew file mode 100644 index 0000000000..59d589eba9 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/policytest_v0.2.xpi diff --git a/browser/components/enterprisepolicies/tests/browser/show_home_button/browser.toml b/browser/components/enterprisepolicies/tests/browser/show_home_button/browser.toml new file mode 100644 index 0000000000..018c55ce38 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/show_home_button/browser.toml @@ -0,0 +1,4 @@ +[DEFAULT] +support-files = ["../head.js"] + +["browser_policy_show_home_button.js"] diff --git a/browser/components/enterprisepolicies/tests/browser/show_home_button/browser_policy_show_home_button.js b/browser/components/enterprisepolicies/tests/browser/show_home_button/browser_policy_show_home_button.js new file mode 100644 index 0000000000..c1d7242dc0 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/show_home_button/browser_policy_show_home_button.js @@ -0,0 +1,38 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* import-globals-from ../head.js */ + +"use strict"; + +add_task(async function test_home_button_shown_boolean() { + await setupPolicyEngineWithJson({ + policies: { + ShowHomeButton: true, + }, + }); + + // Since testing will apply the policy after the browser has already started, + // we will need to open a new window to actually see the menu bar + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let homeButton = newWin.document.getElementById("home-button"); + isnot(homeButton, null, "The home button should be visible"); + + await BrowserTestUtils.closeWindow(newWin); +}); + +add_task(async function test_home_button_hidden_boolean() { + await setupPolicyEngineWithJson({ + policies: { + ShowHomeButton: false, + }, + }); + + // Since testing will apply the policy after the browser has already started, + // we will need to open a new window to actually see the menu bar + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let homeButton = newWin.document.getElementById("home-button"); + is(homeButton, null, "The home button should be gone"); + + await BrowserTestUtils.closeWindow(newWin); +}); diff --git a/browser/components/enterprisepolicies/tests/browser/show_home_button/show_home_button_policies.json b/browser/components/enterprisepolicies/tests/browser/show_home_button/show_home_button_policies.json new file mode 100644 index 0000000000..960e68348e --- /dev/null +++ b/browser/components/enterprisepolicies/tests/browser/show_home_button/show_home_button_policies.json @@ -0,0 +1,7 @@ +{ + "policies": { + "Homepage": { + "URL": "http://example1.com/" + } + } +} diff --git a/browser/components/enterprisepolicies/tests/moz.build b/browser/components/enterprisepolicies/tests/moz.build new file mode 100644 index 0000000000..d1f5dfe7c4 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/moz.build @@ -0,0 +1,20 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +BROWSER_CHROME_MANIFESTS += [ + "browser/browser.toml", + "browser/disable_app_update/browser.toml", + "browser/disable_default_bookmarks/browser.toml", + "browser/disable_developer_tools/browser.toml", + "browser/disable_forget_button/browser.toml", + "browser/disable_fxscreenshots/browser.toml", + "browser/hardware_acceleration/browser.toml", + "browser/homepage_button/browser.toml", + "browser/managedbookmarks/browser.toml", + "browser/show_home_button/browser.toml", +] + +XPCSHELL_TESTS_MANIFESTS += ["xpcshell/xpcshell.toml"] diff --git a/browser/components/enterprisepolicies/tests/xpcshell/config_popups_cookies_addons.json b/browser/components/enterprisepolicies/tests/xpcshell/config_popups_cookies_addons.json new file mode 100644 index 0000000000..256358b204 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/config_popups_cookies_addons.json @@ -0,0 +1,17 @@ +{ + "policies": { + "PopupBlocking": { + "Allow": ["https://www.allow.com", "https://www.pre-existing-deny.com"] + }, + + "Cookies": { + "Allow": ["https://www.allow.com", "https://www.pre-existing-deny.com"], + + "Block": ["https://www.deny.com", "https://www.pre-existing-allow.com"] + }, + + "InstallAddonsPermission": { + "Allow": ["https://www.allow.com", "https://www.pre-existing-deny.com"] + } + } +} diff --git a/browser/components/enterprisepolicies/tests/xpcshell/head.js b/browser/components/enterprisepolicies/tests/xpcshell/head.js new file mode 100644 index 0000000000..8b81261538 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/head.js @@ -0,0 +1,150 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const lazy = {}; + +const { Preferences } = ChromeUtils.importESModule( + "resource://gre/modules/Preferences.sys.mjs" +); +const { SearchSettings } = ChromeUtils.importESModule( + "resource://gre/modules/SearchSettings.sys.mjs" +); +const { updateAppInfo, getAppInfo } = ChromeUtils.importESModule( + "resource://testing-common/AppInfo.sys.mjs" +); +const { FileTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/FileTestUtils.sys.mjs" +); +const { PermissionTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PermissionTestUtils.sys.mjs" +); +ChromeUtils.defineESModuleGetters(lazy, { + SearchTestUtils: "resource://testing-common/SearchTestUtils.sys.mjs", +}); +const { EnterprisePolicyTesting } = ChromeUtils.importESModule( + "resource://testing-common/EnterprisePolicyTesting.sys.mjs" +); + +updateAppInfo({ + name: "XPCShell", + ID: "xpcshell@tests.mozilla.org", + version: "48", + platformVersion: "48", +}); + +// This initializes the policy engine for xpcshell tests +let policies = Cc["@mozilla.org/enterprisepolicies;1"].getService( + Ci.nsIObserver +); +policies.observe(null, "policies-startup", null); + +SearchSettings.SETTINGS_INVALIDATION_DELAY = 100; + +async function setupPolicyEngineWithJson(json, customSchema) { + if (typeof json != "object") { + let filePath = do_get_file(json ? json : "non-existing-file.json").path; + return EnterprisePolicyTesting.setupPolicyEngineWithJson( + filePath, + customSchema + ); + } + return EnterprisePolicyTesting.setupPolicyEngineWithJson(json, customSchema); +} + +/** + * Loads a new enterprise policy, and re-initialise the search service + * with the new policy. Also waits for the search service to write the settings + * file to disk. + * + * @param {object} json + * The enterprise policy to use. + * @param {object} customSchema + * A custom schema to use to validate the enterprise policy. + */ +async function setupPolicyEngineWithJsonWithSearch(json, customSchema) { + Services.search.wrappedJSObject.reset(); + if (typeof json != "object") { + let filePath = do_get_file(json ? json : "non-existing-file.json").path; + await EnterprisePolicyTesting.setupPolicyEngineWithJson( + filePath, + customSchema + ); + } else { + await EnterprisePolicyTesting.setupPolicyEngineWithJson(json, customSchema); + } + let settingsWritten = lazy.SearchTestUtils.promiseSearchNotification( + "write-settings-to-disk-complete" + ); + await Services.search.init(); + return settingsWritten; +} + +function checkLockedPref(prefName, prefValue) { + equal( + Preferences.locked(prefName), + true, + `Pref ${prefName} is correctly locked` + ); + strictEqual( + Preferences.get(prefName), + prefValue, + `Pref ${prefName} has the correct value` + ); +} + +function checkUnlockedPref(prefName, prefValue) { + equal( + Preferences.locked(prefName), + false, + `Pref ${prefName} is correctly unlocked` + ); + strictEqual( + Preferences.get(prefName), + prefValue, + `Pref ${prefName} has the correct value` + ); +} + +function checkUserPref(prefName, prefValue) { + strictEqual( + Preferences.get(prefName), + prefValue, + `Pref ${prefName} has the correct value` + ); +} + +function checkClearPref(prefName, prefValue) { + equal( + Services.prefs.prefHasUserValue(prefName), + false, + `Pref ${prefName} has no user value` + ); +} + +function checkDefaultPref(prefName, prefValue) { + let defaultPrefBranch = Services.prefs.getDefaultBranch(""); + let prefType = defaultPrefBranch.getPrefType(prefName); + notEqual( + prefType, + Services.prefs.PREF_INVALID, + `Pref ${prefName} is set on the default branch` + ); + strictEqual( + Preferences.get(prefName), + prefValue, + `Pref ${prefName} has the correct value` + ); +} + +function checkUnsetPref(prefName) { + let defaultPrefBranch = Services.prefs.getDefaultBranch(""); + let prefType = defaultPrefBranch.getPrefType(prefName); + equal( + prefType, + Services.prefs.PREF_INVALID, + `Pref ${prefName} is not set on the default branch` + ); +} diff --git a/browser/components/enterprisepolicies/tests/xpcshell/policytest_v0.1.xpi b/browser/components/enterprisepolicies/tests/xpcshell/policytest_v0.1.xpi Binary files differnew file mode 100644 index 0000000000..ee2a6289ee --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/policytest_v0.1.xpi diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_3rdparty.js b/browser/components/enterprisepolicies/tests/xpcshell/test_3rdparty.js new file mode 100644 index 0000000000..0f53cc80c9 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_3rdparty.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +add_task(async function setup() { + await setupPolicyEngineWithJson({ + policies: { + "3rdparty": { + Extensions: { + "3rdparty-policy@mozilla.com": { + string: "value", + }, + }, + }, + }, + }); + + let extensionPolicy = Services.policies.getExtensionPolicy( + "3rdparty-policy@mozilla.com" + ); + deepEqual(extensionPolicy, { string: "value" }); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_addon_update.js b/browser/components/enterprisepolicies/tests/xpcshell/test_addon_update.js new file mode 100644 index 0000000000..0133aa3a40 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_addon_update.js @@ -0,0 +1,156 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { AddonTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/AddonTestUtils.sys.mjs" +); +const { AddonManager } = ChromeUtils.importESModule( + "resource://gre/modules/AddonManager.sys.mjs" +); +const { ExtensionTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/ExtensionXPCShellUtils.sys.mjs" +); + +AddonTestUtils.init(this); +AddonTestUtils.overrideCertDB(); +AddonTestUtils.appInfo = getAppInfo(); +ExtensionTestUtils.init(this); + +const server = AddonTestUtils.createHttpServer({ hosts: ["example.com"] }); +const BASE_URL = `http://example.com/data`; + +let TEST_NAME = "updatable.xpi"; + +/* Test that when a local file addon is updated, + the new version gets installed. */ +add_task(async function test_local_addon_update() { + await AddonTestUtils.promiseStartupManager(); + + let tmpDir = Services.dirsvc.get("TmpD", Ci.nsIFile); + let id = "updatable1@test"; + let xpi1 = AddonTestUtils.createTempWebExtensionFile({ + manifest: { + version: "1.0", + browser_specific_settings: { + gecko: { id }, + }, + }, + }); + xpi1.copyTo(tmpDir, TEST_NAME); + let extension = ExtensionTestUtils.expectExtension(id); + await Promise.all([ + extension.awaitStartup(), + setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "updatable1@test": { + installation_mode: "force_installed", + install_url: Services.io.newFileURI(tmpDir).spec + "/" + TEST_NAME, + }, + }, + }, + }), + ]); + let addon = await AddonManager.getAddonByID(id); + notEqual(addon, null, "Addon should not be null"); + equal(addon.version, "1.0", "Addon 1.0 installed"); + + let xpi2 = AddonTestUtils.createTempWebExtensionFile({ + manifest: { + version: "2.0", + browser_specific_settings: { + gecko: { id }, + }, + }, + }); + // overwrite the test file + xpi2.copyTo(tmpDir, TEST_NAME); + + extension = ExtensionTestUtils.expectExtension(id); + await Promise.all([ + extension.awaitStartup(), + setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "updatable1@test": { + installation_mode: "force_installed", + install_url: Services.io.newFileURI(tmpDir).spec + "/" + TEST_NAME, + }, + }, + }, + }), + ]); + + addon = await AddonManager.getAddonByID(id); + equal(addon.version, "2.0", "Addon 2.0 installed"); + + let xpifile = tmpDir.clone(); + xpifile.append(TEST_NAME); + xpifile.remove(false); +}); + +/* Test that when the url changes, + the new version gets installed. */ +add_task(async function test_newurl_addon_update() { + let id = "updatable2@test"; + + let xpi1 = AddonTestUtils.createTempWebExtensionFile({ + manifest: { + version: "1.0", + browser_specific_settings: { + gecko: { id }, + }, + }, + }); + server.registerFile("/data/policy_test1.xpi", xpi1); + + let xpi2 = AddonTestUtils.createTempWebExtensionFile({ + manifest: { + version: "2.0", + browser_specific_settings: { + gecko: { id }, + }, + }, + }); + server.registerFile("/data/policy_test2.xpi", xpi2); + + let extension = ExtensionTestUtils.expectExtension(id); + await Promise.all([ + extension.awaitStartup(), + setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "updatable2@test": { + installation_mode: "force_installed", + install_url: `${BASE_URL}/policy_test1.xpi`, + }, + }, + }, + }), + ]); + let addon = await AddonManager.getAddonByID(id); + notEqual(addon, null, "Addon should not be null"); + equal(addon.version, "1.0", "Addon 1.0 installed"); + + extension = ExtensionTestUtils.expectExtension(id); + await Promise.all([ + extension.awaitStartup(), + setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "updatable2@test": { + installation_mode: "force_installed", + install_url: `${BASE_URL}/policy_test2.xpi`, + }, + }, + }, + }), + ]); + + addon = await AddonManager.getAddonByID(id); + equal(addon.version, "2.0", "Addon 2.0 installed"); + + await AddonTestUtils.promiseShutdownManager(); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_appupdatepin.js b/browser/components/enterprisepolicies/tests/xpcshell/test_appupdatepin.js new file mode 100644 index 0000000000..6be2aa0b50 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_appupdatepin.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { TelemetryTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/TelemetryTestUtils.sys.mjs" +); + +/** + * Note that these tests only ensure that the pin is properly added to the + * update URL and to the telemetry. They do not test that the update applied + * will be of the correct version. This is because we are not attempting to have + * Firefox check if the update provided is valid given the pin, we are leaving + * it to the update server (Balrog) to find and serve the correct version. + */ + +async function test_update_pin(pinString, pinIsValid = true) { + await setupPolicyEngineWithJson({ + policies: { + AppUpdateURL: "https://www.example.com/update.xml", + AppUpdatePin: pinString, + }, + }); + Services.telemetry.clearScalars(); + + equal( + Services.policies.status, + Ci.nsIEnterprisePolicies.ACTIVE, + "Engine is active" + ); + + let policies = Services.policies.getActivePolicies(); + equal( + "AppUpdatePin" in policies, + pinIsValid, + "AppUpdatePin policy should only be active if the pin was valid." + ); + + let checker = Cc["@mozilla.org/updates/update-checker;1"].getService( + Ci.nsIUpdateChecker + ); + let updateURL = await checker.getUpdateURL(checker.BACKGROUND_CHECK); + + let expected = pinIsValid + ? `https://www.example.com/update.xml?pin=${pinString}` + : "https://www.example.com/update.xml"; + + equal(updateURL, expected, "App Update URL should match expected URL."); + + let scalars = TelemetryTestUtils.getProcessScalars("parent", false, true); + if (pinIsValid) { + TelemetryTestUtils.assertScalar( + scalars, + "update.version_pin", + pinString, + "Update pin telemetry should be set" + ); + } else { + TelemetryTestUtils.assertScalarUnset(scalars, "update.version_pin"); + } +} + +add_task(async function test_app_update_pin() { + await test_update_pin("102."); + await test_update_pin("102.0."); + await test_update_pin("102.1."); + await test_update_pin("102.1.1", false); + await test_update_pin("102.1.1.", false); + await test_update_pin("102", false); + await test_update_pin("foobar", false); + await test_update_pin("-102.1.", false); + await test_update_pin("102.-1.", false); + await test_update_pin("102a.1.", false); + await test_update_pin("102.1a.", false); + await test_update_pin("0102.1.", false); + // Should not accept version numbers that will never be in Balrog's pinning + // table (i.e. versions before 102.0). + await test_update_pin("101.1.", false); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_appupdateurl.js b/browser/components/enterprisepolicies/tests/xpcshell/test_appupdateurl.js new file mode 100644 index 0000000000..48d04e1a8d --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_appupdateurl.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_app_update_URL() { + await setupPolicyEngineWithJson({ + policies: { + AppUpdateURL: "https://www.example.com/", + }, + }); + + equal( + Services.policies.status, + Ci.nsIEnterprisePolicies.ACTIVE, + "Engine is active" + ); + + let checker = Cc["@mozilla.org/updates/update-checker;1"].getService( + Ci.nsIUpdateChecker + ); + let expected = await checker.getUpdateURL(checker.BACKGROUND_CHECK); + + equal("https://www.example.com/", expected, "Correct app update URL"); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_bug1658259.js b/browser/components/enterprisepolicies/tests/xpcshell/test_bug1658259.js new file mode 100644 index 0000000000..1449e664c2 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_bug1658259.js @@ -0,0 +1,44 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_bug1658259_1() { + await setupPolicyEngineWithJson({ + policies: { + OfferToSaveLogins: false, + OfferToSaveLoginsDefault: true, + }, + }); + checkLockedPref("signon.rememberSignons", false); +}); + +add_task(async function test_bug1658259_2() { + await setupPolicyEngineWithJson({ + policies: { + OfferToSaveLogins: true, + OfferToSaveLoginsDefault: false, + }, + }); + checkLockedPref("signon.rememberSignons", true); +}); + +add_task(async function test_bug1658259_3() { + await setupPolicyEngineWithJson({ + policies: { + OfferToSaveLoginsDefault: true, + OfferToSaveLogins: false, + }, + }); + checkLockedPref("signon.rememberSignons", false); +}); + +add_task(async function test_bug1658259_4() { + await setupPolicyEngineWithJson({ + policies: { + OfferToSaveLoginsDefault: false, + OfferToSaveLogins: true, + }, + }); + checkLockedPref("signon.rememberSignons", true); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_cleanup.js b/browser/components/enterprisepolicies/tests/xpcshell/test_cleanup.js new file mode 100644 index 0000000000..4171987cbb --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_cleanup.js @@ -0,0 +1,84 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +async function checkMessages(expectedResult) { + let onBeforeAddons = false; + let onProfileAfterChange = false; + let onBeforeUIStartup = false; + let onAllWindowsRestored = false; + + let errorListener = { + observe(subject) { + let message = subject.wrappedJSObject.arguments[0]; + if (message.includes("_cleanup from onBeforeAddons")) { + onBeforeAddons = true; + } else if (message.includes("_cleanup from onProfileAfterChange")) { + onProfileAfterChange = true; + } else if (message.includes("_cleanup from onBeforeUIStartup")) { + onBeforeUIStartup = true; + } else if (message.includes("_cleanup from onAllWindowsRestored")) { + onAllWindowsRestored = true; + } + }, + }; + + Services.console.registerListener(errorListener); + + const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService( + Ci.nsIConsoleAPIStorage + ); + ConsoleAPIStorage.addLogEventListener( + errorListener.observe, + Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal) + ); + + await setupPolicyEngineWithJson({ + policies: {}, + }); + + equal( + onBeforeAddons, + expectedResult, + "onBeforeAddons should be " + expectedResult + ); + equal( + onProfileAfterChange, + expectedResult, + "onProfileAfterChange should be" + expectedResult + ); + equal( + onBeforeUIStartup, + expectedResult, + "onBeforeUIStartup should be" + expectedResult + ); + equal( + onAllWindowsRestored, + expectedResult, + "onAllWindowsRestored should be" + expectedResult + ); +} + +/* If there is no existing policy, cleanup should not run. */ +add_task(async function test_cleanup_no_policy() { + await checkMessages(false); +}); + +add_task(async function setup_policy() { + await setupPolicyEngineWithJson({ + policies: { + BlockAboutConfig: true, + }, + }); +}); + +/* Since there was a policy, cleanup should run. */ +add_task(async function test_cleanup_with_policy() { + await checkMessages(true); +}); + +/* Since cleanup was already done, cleanup should not run again. */ +add_task(async function test_cleanup_after_policy() { + await checkMessages(false); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_clear_blocked_cookies.js b/browser/components/enterprisepolicies/tests/xpcshell/test_clear_blocked_cookies.js new file mode 100644 index 0000000000..571ae95a1b --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_clear_blocked_cookies.js @@ -0,0 +1,118 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const HOSTNAME_DOMAIN = "browser_policy_clear_blocked_cookies.com"; +const ORIGIN_DOMAIN = "browser_policy_clear_blocked_cookies.org"; + +add_task(async function setup() { + const expiry = Date.now() + 24 * 60 * 60; + Services.cookies.add( + HOSTNAME_DOMAIN, + "/", + "secure", + "true", + true, + false, + false, + expiry, + {}, + Ci.nsICookie.SAMESITE_NONE, + Ci.nsICookie.SCHEME_HTTPS + ); + Services.cookies.add( + HOSTNAME_DOMAIN, + "/", + "insecure", + "true", + false, + false, + false, + expiry, + {}, + Ci.nsICookie.SAMESITE_NONE, + Ci.nsICookie.SCHEME_HTTP + ); + Services.cookies.add( + ORIGIN_DOMAIN, + "/", + "secure", + "true", + true, + false, + false, + expiry, + {}, + Ci.nsICookie.SAMESITE_NONE, + Ci.nsICookie.SCHEME_HTTPS + ); + Services.cookies.add( + ORIGIN_DOMAIN, + "/", + "insecure", + "true", + false, + false, + false, + expiry, + {}, + Ci.nsICookie.SAMESITE_NONE, + Ci.nsICookie.SCHEME_HTTP + ); + Services.cookies.add( + "example.net", + "/", + "secure", + "true", + true, + false, + false, + expiry, + {}, + Ci.nsICookie.SAMESITE_NONE, + Ci.nsICookie.SCHEME_HTTPS + ); + await setupPolicyEngineWithJson({ + policies: { + Cookies: { + Block: [`http://${HOSTNAME_DOMAIN}`, `https://${ORIGIN_DOMAIN}:8080`], + }, + }, + }); +}); + +function retrieve_all_cookies(host) { + const values = []; + for (let cookie of Services.cookies.getCookiesFromHost(host, {})) { + values.push({ + host: cookie.host, + name: cookie.name, + path: cookie.path, + }); + } + return values; +} + +add_task(async function test_cookies_for_blocked_sites_cleared() { + const cookies = { + hostname: retrieve_all_cookies(HOSTNAME_DOMAIN), + origin: retrieve_all_cookies(ORIGIN_DOMAIN), + keep: retrieve_all_cookies("example.net"), + }; + const expected = { + hostname: [], + origin: [], + keep: [{ host: "example.net", name: "secure", path: "/" }], + }; + equal( + JSON.stringify(cookies), + JSON.stringify(expected), + "All stored cookies for blocked origins should be cleared" + ); +}); + +add_task(function teardown() { + for (let host of [HOSTNAME_DOMAIN, ORIGIN_DOMAIN, "example.net"]) { + Services.cookies.removeCookiesWithOriginAttributes("{}", host); + } +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_containers.js b/browser/components/enterprisepolicies/tests/xpcshell/test_containers.js new file mode 100644 index 0000000000..0f6a0190ac --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_containers.js @@ -0,0 +1,37 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + ContextualIdentityService: + "resource://gre/modules/ContextualIdentityService.sys.mjs", +}); + +add_task(async function setup() { + Services.prefs.setBoolPref("privacy.userContext.enabled", true); + do_get_profile(); +}); + +add_task(async function test_containers_default() { + await setupPolicyEngineWithJson({ + policies: { + Containers: { + Default: [ + { + name: "Test Container", + icon: "cart", + color: "orange", + }, + ], + }, + }, + }); + let identities = ContextualIdentityService.getPublicIdentities(); + equal(identities.length, 1); + ContextualIdentityService.getPublicIdentities().forEach(identity => { + equal(identity.name, "Test Container"); + equal(identity.icon, "cart"); + equal(identity.color, "orange"); + }); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_defaultbrowsercheck.js b/browser/components/enterprisepolicies/tests/xpcshell/test_defaultbrowsercheck.js new file mode 100644 index 0000000000..ff54669f4f --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_defaultbrowsercheck.js @@ -0,0 +1,52 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; +const { ShellService } = ChromeUtils.importESModule( + "resource:///modules/ShellService.sys.mjs" +); + +add_task(async function test_default_browser_check() { + ShellService._checkedThisSession = false; + // On a normal profile, the default is true. However, this gets set to false on the + // testing profile. Let's start with true for a sanity check. + + ShellService.shouldCheckDefaultBrowser = true; + equal(ShellService.shouldCheckDefaultBrowser, true, "Sanity check"); + + await setupPolicyEngineWithJson({ + policies: { + DontCheckDefaultBrowser: true, + }, + }); + + equal( + ShellService.shouldCheckDefaultBrowser, + false, + "Policy changed it to not check" + ); + + // Try to change it to true and check that it doesn't take effect + ShellService.shouldCheckDefaultBrowser = true; + + equal(ShellService.shouldCheckDefaultBrowser, false, "Policy is enforced"); +}); + +add_task(async function test_default_browser_check() { + await setupPolicyEngineWithJson({ + policies: { + DontCheckDefaultBrowser: false, + }, + }); + + equal( + ShellService.shouldCheckDefaultBrowser, + true, + "Policy changed it to check" + ); + + // Try to change it to false and check that it doesn't take effect + ShellService.shouldCheckDefaultBrowser = false; + + equal(ShellService.shouldCheckDefaultBrowser, true, "Policy is enforced"); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_empty_policy.js b/browser/components/enterprisepolicies/tests/xpcshell/test_empty_policy.js new file mode 100644 index 0000000000..5047eeb4e0 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_empty_policy.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_empty_policy() { + await setupPolicyEngineWithJson({ + policies: { + Certificates: {}, + }, + }); + + equal( + Services.policies.status, + Ci.nsIEnterprisePolicies.INACTIVE, + "Engine is not active" + ); +}); + +add_task(async function test_empty_array() { + await setupPolicyEngineWithJson({ + policies: { + RequestedLocales: [], + }, + }); + + equal( + Services.policies.status, + Ci.nsIEnterprisePolicies.ACTIVE, + "Engine is active" + ); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_exempt_domain_file_type_pairs_from_file_type_download_warnings.js b/browser/components/enterprisepolicies/tests/xpcshell/test_exempt_domain_file_type_pairs_from_file_type_download_warnings.js new file mode 100644 index 0000000000..5d93391ce9 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_exempt_domain_file_type_pairs_from_file_type_download_warnings.js @@ -0,0 +1,66 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_exempt_xxx() { + await setupPolicyEngineWithJson({ + policies: { + ExemptDomainFileTypePairsFromFileTypeDownloadWarnings: [ + { + file_extension: "jnlp", + domains: ["example.com", "www.example.edu"], + }, + ], + }, + }); + equal( + Services.policies.isExemptExecutableExtension( + "https://www.example.edu", + "jnlp" + ), + true + ); + equal( + Services.policies.isExemptExecutableExtension( + "https://example.edu", + "jnlp" + ), + false + ); + equal( + Services.policies.isExemptExecutableExtension( + "https://example.com", + "jnlp" + ), + true + ); + equal( + Services.policies.isExemptExecutableExtension( + "https://www.example.com", + "jnlp" + ), + true + ); + equal( + Services.policies.isExemptExecutableExtension( + "https://wwwexample.com", + "jnlp" + ), + false + ); + equal( + Services.policies.isExemptExecutableExtension( + "https://www.example.org", + "jnlp" + ), + false + ); + equal( + Services.policies.isExemptExecutableExtension( + "https://www.example.edu", + "exe" + ), + false + ); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_extensions.js b/browser/components/enterprisepolicies/tests/xpcshell/test_extensions.js new file mode 100644 index 0000000000..66cd49e004 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_extensions.js @@ -0,0 +1,83 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const { AddonTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/AddonTestUtils.sys.mjs" +); +const { AddonManager } = ChromeUtils.importESModule( + "resource://gre/modules/AddonManager.sys.mjs" +); + +AddonTestUtils.init(this); +AddonTestUtils.overrideCertDB(); +AddonTestUtils.appInfo = getAppInfo(); + +const server = AddonTestUtils.createHttpServer({ hosts: ["example.com"] }); +const BASE_URL = `http://example.com/data`; + +let addonID = "policytest2@mozilla.com"; + +add_task(async function setup() { + await AddonTestUtils.promiseStartupManager(); + + let webExtensionFile = AddonTestUtils.createTempWebExtensionFile({ + manifest: { + browser_specific_settings: { + gecko: { + id: addonID, + }, + }, + }, + }); + + server.registerFile("/data/policy_test.xpi", webExtensionFile); +}); + +add_task(async function test_addon_forceinstalled_remote() { + await Promise.all([ + AddonTestUtils.promiseInstallEvent("onInstallEnded"), + setupPolicyEngineWithJson({ + policies: { + Extensions: { + Install: [BASE_URL + "/policy_test.xpi"], + Locked: [addonID], + }, + }, + }), + ]); + let addon = await AddonManager.getAddonByID(addonID); + notEqual(addon, null, "Addon should not be null"); + equal(addon.appDisabled, false, "Addon should not be disabled"); + equal( + addon.permissions & AddonManager.PERM_CAN_UNINSTALL, + 0, + "Addon should not be able to be uninstalled." + ); + equal( + addon.permissions & AddonManager.PERM_CAN_DISABLE, + 0, + "Addon should not be able to be disabled." + ); + await addon.uninstall(); +}); + +add_task(async function test_addon_forceinstalled_local() { + let addonID2 = "policytest@mozilla.com"; + + let file = Services.dirsvc.get("CurWorkD", Ci.nsIFile); + file.append("policytest_v0.1.xpi"); + await Promise.all([ + AddonTestUtils.promiseInstallEvent("onInstallEnded"), + setupPolicyEngineWithJson({ + policies: { + Extensions: { + Install: [file.path], + }, + }, + }), + ]); + let addon = await AddonManager.getAddonByID(addonID2); + notEqual(addon, null, "Addon should not be null"); + await addon.uninstall(); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_extensionsettings.js b/browser/components/enterprisepolicies/tests/xpcshell/test_extensionsettings.js new file mode 100644 index 0000000000..ee329a65f8 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_extensionsettings.js @@ -0,0 +1,291 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const { AddonTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/AddonTestUtils.sys.mjs" +); +const { AddonManager } = ChromeUtils.importESModule( + "resource://gre/modules/AddonManager.sys.mjs" +); + +AddonTestUtils.init(this); +AddonTestUtils.overrideCertDB(); +AddonTestUtils.appInfo = getAppInfo(); + +const server = AddonTestUtils.createHttpServer({ hosts: ["example.com"] }); +const BASE_URL = `http://example.com/data`; + +let addonID = "policytest2@mozilla.com"; +let themeID = "policytheme@mozilla.com"; + +let fileURL; + +add_task(async function setup() { + await AddonTestUtils.promiseStartupManager(); + + let webExtensionFile = AddonTestUtils.createTempWebExtensionFile({ + manifest: { + browser_specific_settings: { + gecko: { + id: addonID, + }, + }, + }, + }); + + server.registerFile("/data/policy_test.xpi", webExtensionFile); + fileURL = Services.io + .newFileURI(webExtensionFile) + .QueryInterface(Ci.nsIFileURL); +}); + +add_task(async function test_extensionsettings() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "extension1@mozilla.com": { + blocked_install_message: "Extension1 error message.", + }, + "*": { + blocked_install_message: "Generic error message.", + }, + }, + }, + }); + + let extensionSettings = Services.policies.getExtensionSettings( + "extension1@mozilla.com" + ); + equal( + extensionSettings.blocked_install_message, + "Extension1 error message.", + "Should have extension specific message." + ); + extensionSettings = Services.policies.getExtensionSettings( + "extension2@mozilla.com" + ); + equal( + extensionSettings.blocked_install_message, + "Generic error message.", + "Should have generic message." + ); +}); + +add_task(async function test_addon_blocked() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "policytest2@mozilla.com": { + installation_mode: "blocked", + }, + }, + }, + }); + + let install = await AddonManager.getInstallForURL( + BASE_URL + "/policy_test.xpi" + ); + await install.install(); + notEqual(install.addon, null, "Addon should not be null"); + equal(install.addon.appDisabled, true, "Addon should be disabled"); + await install.addon.uninstall(); +}); + +add_task(async function test_addon_allowed() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "policytest2@mozilla.com": { + installation_mode: "allowed", + }, + "*": { + installation_mode: "blocked", + }, + }, + }, + }); + + let install = await AddonManager.getInstallForURL( + BASE_URL + "/policy_test.xpi" + ); + await install.install(); + notEqual(install.addon, null, "Addon should not be null"); + equal(install.addon.appDisabled, false, "Addon should not be disabled"); + await install.addon.uninstall(); +}); + +add_task(async function test_addon_uninstalled() { + let install = await AddonManager.getInstallForURL( + BASE_URL + "/policy_test.xpi" + ); + await install.install(); + notEqual(install.addon, null, "Addon should not be null"); + + await Promise.all([ + AddonTestUtils.promiseAddonEvent("onUninstalled"), + setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "*": { + installation_mode: "blocked", + }, + }, + }, + }), + ]); + let addon = await AddonManager.getAddonByID(addonID); + equal(addon, null, "Addon should be null"); +}); + +add_task(async function test_addon_forceinstalled() { + await Promise.all([ + AddonTestUtils.promiseInstallEvent("onInstallEnded"), + setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "policytest2@mozilla.com": { + installation_mode: "force_installed", + install_url: BASE_URL + "/policy_test.xpi", + }, + }, + }, + }), + ]); + let addon = await AddonManager.getAddonByID(addonID); + notEqual(addon, null, "Addon should not be null"); + equal(addon.appDisabled, false, "Addon should not be disabled"); + equal( + addon.permissions & AddonManager.PERM_CAN_UNINSTALL, + 0, + "Addon should not be able to be uninstalled." + ); + equal( + addon.permissions & AddonManager.PERM_CAN_DISABLE, + 0, + "Addon should not be able to be disabled." + ); + await addon.uninstall(); +}); + +add_task(async function test_addon_normalinstalled() { + await Promise.all([ + AddonTestUtils.promiseInstallEvent("onInstallEnded"), + setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "policytest2@mozilla.com": { + installation_mode: "normal_installed", + install_url: BASE_URL + "/policy_test.xpi", + }, + }, + }, + }), + ]); + let addon = await AddonManager.getAddonByID(addonID); + notEqual(addon, null, "Addon should not be null"); + equal(addon.appDisabled, false, "Addon should not be disabled"); + equal( + addon.permissions & AddonManager.PERM_CAN_UNINSTALL, + 0, + "Addon should not be able to be uninstalled." + ); + notEqual( + addon.permissions & AddonManager.PERM_CAN_DISABLE, + 0, + "Addon should be able to be disabled." + ); + await addon.uninstall(); +}); + +add_task(async function test_extensionsettings_string() { + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: '{"*": {"installation_mode": "blocked"}}', + }, + }); + + let extensionSettings = Services.policies.getExtensionSettings("*"); + equal(extensionSettings.installation_mode, "blocked"); +}); + +add_task(async function test_extensionsettings_string() { + let restrictedDomains = Services.prefs.getCharPref( + "extensions.webextensions.restrictedDomains" + ); + await setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: + '{"*": {"restricted_domains": ["example.com","example.org"]}}', + }, + }); + + let newRestrictedDomains = Services.prefs.getCharPref( + "extensions.webextensions.restrictedDomains" + ); + equal(newRestrictedDomains, restrictedDomains + ",example.com,example.org"); +}); + +add_task(async function test_theme() { + let themeFile = AddonTestUtils.createTempWebExtensionFile({ + manifest: { + browser_specific_settings: { + gecko: { + id: themeID, + }, + }, + theme: {}, + }, + }); + + server.registerFile("/data/policy_theme.xpi", themeFile); + + await Promise.all([ + AddonTestUtils.promiseInstallEvent("onInstallEnded"), + setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "policytheme@mozilla.com": { + installation_mode: "normal_installed", + install_url: BASE_URL + "/policy_theme.xpi", + }, + }, + }, + }), + ]); + let currentTheme = Services.prefs.getCharPref("extensions.activeThemeID"); + equal(currentTheme, themeID, "Theme should be active"); + let addon = await AddonManager.getAddonByID(themeID); + await addon.uninstall(); +}); + +add_task(async function test_addon_normalinstalled_file() { + await Promise.all([ + AddonTestUtils.promiseInstallEvent("onInstallEnded"), + setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "policytest2@mozilla.com": { + installation_mode: "normal_installed", + install_url: fileURL.spec, + }, + }, + }, + }), + ]); + let addon = await AddonManager.getAddonByID(addonID); + notEqual(addon, null, "Addon should not be null"); + equal(addon.appDisabled, false, "Addon should not be disabled"); + equal( + addon.permissions & AddonManager.PERM_CAN_UNINSTALL, + 0, + "Addon should not be able to be uninstalled." + ); + notEqual( + addon.permissions & AddonManager.PERM_CAN_DISABLE, + 0, + "Addon should be able to be disabled." + ); + + await addon.uninstall(); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_macosparser_unflatten.js b/browser/components/enterprisepolicies/tests/xpcshell/test_macosparser_unflatten.js new file mode 100644 index 0000000000..096852612c --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_macosparser_unflatten.js @@ -0,0 +1,110 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +let { macOSPoliciesParser } = ChromeUtils.importESModule( + "resource://gre/modules/policies/macOSPoliciesParser.sys.mjs" +); + +add_task(async function test_object_unflatten() { + // Note: these policies are just examples and they won't actually + // run through the policy engine on this test. We're just testing + // that the unflattening algorithm produces the correct output. + let input = { + DisplayBookmarksToolbar: true, + + Homepage__URL: "https://www.mozilla.org", + Homepage__Locked: "true", + Homepage__Additional__0: "https://extra-homepage-1.example.com", + Homepage__Additional__1: "https://extra-homepage-2.example.com", + + WebsiteFilter__Block__0: "*://*.example.org/*", + WebsiteFilter__Block__1: "*://*.example.net/*", + WebsiteFilter__Exceptions__0: "*://*.example.org/*exception*", + + Permissions__Camera__Allow__0: "https://www.example.com", + + Permissions__Notifications__Allow__0: "https://www.example.com", + Permissions__Notifications__Allow__1: "https://www.example.org", + Permissions__Notifications__Block__0: "https://www.example.net", + + Permissions__Notifications__BlockNewRequests: true, + Permissions__Notifications__Locked: true, + + Bookmarks__0__Title: "Bookmark 1", + Bookmarks__0__URL: "https://bookmark1.example.com", + + Bookmarks__1__Title: "Bookmark 2", + Bookmarks__1__URL: "https://bookmark2.example.com", + Bookmarks__1__Folder: "Folder", + }; + + let expected = { + DisplayBookmarksToolbar: true, + + Homepage: { + URL: "https://www.mozilla.org", + Locked: "true", + Additional: [ + "https://extra-homepage-1.example.com", + "https://extra-homepage-2.example.com", + ], + }, + + WebsiteFilter: { + Block: ["*://*.example.org/*", "*://*.example.net/*"], + Exceptions: ["*://*.example.org/*exception*"], + }, + + Permissions: { + Camera: { + Allow: ["https://www.example.com"], + }, + + Notifications: { + Allow: ["https://www.example.com", "https://www.example.org"], + Block: ["https://www.example.net"], + BlockNewRequests: true, + Locked: true, + }, + }, + + Bookmarks: [ + { + Title: "Bookmark 1", + URL: "https://bookmark1.example.com", + }, + { + Title: "Bookmark 2", + URL: "https://bookmark2.example.com", + Folder: "Folder", + }, + ], + }; + + let unflattened = macOSPoliciesParser.unflatten(input); + + deepEqual(unflattened, expected, "Input was unflattened correctly."); +}); + +add_task(async function test_array_unflatten() { + let input = { + Foo__1: 1, + Foo__5: 5, + Foo__10: 10, + Foo__30: 30, + Foo__51: 51, // This one should not be included as the limit is 50 + }; + + let unflattened = macOSPoliciesParser.unflatten(input); + equal(unflattened.Foo.length, 31, "Array size is correct"); + + let expected = { + Foo: [, 1, , , , 5], // eslint-disable-line no-sparse-arrays + }; + expected.Foo[10] = 10; + expected.Foo[30] = 30; + + deepEqual(unflattened, expected, "Array was unflattened correctly."); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_permissions.js b/browser/components/enterprisepolicies/tests/xpcshell/test_permissions.js new file mode 100644 index 0000000000..f4440e53f5 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_permissions.js @@ -0,0 +1,355 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +function URI(str) { + return Services.io.newURI(str); +} + +add_task(async function test_setup_preexisting_permissions() { + // Pre-existing ALLOW permissions that should be overridden + // with DENY. + + // No ALLOW -> DENY override for popup and install permissions, + // because their policies only supports the Allow parameter. + + PermissionTestUtils.add( + "https://www.pre-existing-allow.com", + "camera", + Ci.nsIPermissionManager.ALLOW_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.pre-existing-allow.com", + "microphone", + Ci.nsIPermissionManager.ALLOW_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.pre-existing-allow.com", + "geo", + Ci.nsIPermissionManager.ALLOW_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.pre-existing-allow.com", + "desktop-notification", + Ci.nsIPermissionManager.ALLOW_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.pre-existing-allow.com", + "autoplay-media", + Ci.nsIPermissionManager.ALLOW_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.pre-existing-allow.com", + "xr", + Ci.nsIPermissionManager.ALLOW_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + + // Pre-existing DENY permissions that should be overridden + // with ALLOW. + + PermissionTestUtils.add( + "https://www.pre-existing-deny.com", + "camera", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.pre-existing-deny.com", + "microphone", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.pre-existing-deny.com", + "geo", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.pre-existing-deny.com", + "desktop-notification", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.pre-existing-deny.com", + "autoplay-media", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.pre-existing-deny.com", + "xr", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); +}); + +add_task(async function test_setup_activate_policies() { + await setupPolicyEngineWithJson({ + policies: { + Permissions: { + Camera: { + Allow: ["https://www.allow.com", "https://www.pre-existing-deny.com"], + Block: ["https://www.deny.com", "https://www.pre-existing-allow.com"], + }, + Microphone: { + Allow: ["https://www.allow.com", "https://www.pre-existing-deny.com"], + Block: ["https://www.deny.com", "https://www.pre-existing-allow.com"], + }, + Location: { + Allow: ["https://www.allow.com", "https://www.pre-existing-deny.com"], + Block: ["https://www.deny.com", "https://www.pre-existing-allow.com"], + }, + Notifications: { + Allow: ["https://www.allow.com", "https://www.pre-existing-deny.com"], + Block: ["https://www.deny.com", "https://www.pre-existing-allow.com"], + }, + Autoplay: { + Allow: ["https://www.allow.com", "https://www.pre-existing-deny.com"], + Block: ["https://www.deny.com", "https://www.pre-existing-allow.com"], + }, + VirtualReality: { + Allow: ["https://www.allow.com", "https://www.pre-existing-deny.com"], + Block: ["https://www.deny.com", "https://www.pre-existing-allow.com"], + }, + }, + }, + }); + equal( + Services.policies.status, + Ci.nsIEnterprisePolicies.ACTIVE, + "Engine is active" + ); +}); + +function checkPermission(url, expected, permissionName) { + let expectedValue = Ci.nsIPermissionManager[`${expected}_ACTION`]; + let uri = Services.io.newURI(`https://www.${url}`); + + equal( + PermissionTestUtils.testPermission(uri, permissionName), + expectedValue, + `Correct (${permissionName}=${expected}) for URL ${url}` + ); + + if (expected != "UNKNOWN") { + let permission = PermissionTestUtils.getPermissionObject( + uri, + permissionName, + true + ); + ok(permission, "Permission object exists"); + equal( + permission.expireType, + Ci.nsIPermissionManager.EXPIRE_POLICY, + "Permission expireType is correct" + ); + } +} + +function checkAllPermissionsForType(type, typeSupportsDeny = true) { + checkPermission("allow.com", "ALLOW", type); + checkPermission("unknown.com", "UNKNOWN", type); + checkPermission("pre-existing-deny.com", "ALLOW", type); + + if (typeSupportsDeny) { + checkPermission("deny.com", "DENY", type); + checkPermission("pre-existing-allow.com", "DENY", type); + } +} + +add_task(async function test_camera_policy() { + checkAllPermissionsForType("camera"); +}); + +add_task(async function test_microphone_policy() { + checkAllPermissionsForType("microphone"); +}); + +add_task(async function test_location_policy() { + checkAllPermissionsForType("geo"); +}); + +add_task(async function test_notifications_policy() { + checkAllPermissionsForType("desktop-notification"); +}); + +add_task(async function test_autoplay_policy() { + checkAllPermissionsForType("autoplay-media"); +}); + +add_task(async function test_xr_policy() { + checkAllPermissionsForType("xr"); +}); + +add_task(async function test_change_permission() { + // Checks that changing a permission will still retain the + // value set through the engine. + PermissionTestUtils.add( + "https://www.allow.com", + "camera", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.allow.com", + "microphone", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.allow.com", + "geo", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.allow.com", + "desktop-notification", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.allow.com", + "autoplay-media", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.allow.com", + "xr", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + + checkPermission("allow.com", "ALLOW", "camera"); + checkPermission("allow.com", "ALLOW", "microphone"); + checkPermission("allow.com", "ALLOW", "geo"); + checkPermission("allow.com", "ALLOW", "desktop-notification"); + checkPermission("allow.com", "ALLOW", "autoplay-media"); + checkPermission("allow.com", "ALLOW", "xr"); + + // Also change one un-managed permission to make sure it doesn't + // cause any problems to the policy engine or the permission manager. + PermissionTestUtils.add( + "https://www.unmanaged.com", + "camera", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.unmanaged.com", + "microphone", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.unmanaged.com", + "geo", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.unmanaged.com", + "desktop-notification", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.unmanaged.com", + "autoplay-media", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + PermissionTestUtils.add( + "https://www.unmanaged.com", + "xr", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); +}); + +add_task(async function test_setup_trackingprotection() { + await setupPolicyEngineWithJson({ + policies: { + EnableTrackingProtection: { + Exceptions: ["https://www.allow.com"], + }, + }, + }); + equal( + Services.policies.status, + Ci.nsIEnterprisePolicies.ACTIVE, + "Engine is active" + ); +}); + +add_task(async function test_trackingprotection() { + checkPermission("allow.com", "ALLOW", "trackingprotection"); +}); + +// This seems a little out of place, but it's really a cookie +// permission, not cookies per say. +add_task(async function test_cookie_allow_session() { + await setupPolicyEngineWithJson({ + policies: { + Cookies: { + AllowSession: ["https://allowsession.example.com"], + }, + }, + }); + equal( + PermissionTestUtils.testPermission( + URI("https://allowsession.example.com"), + "cookie" + ), + Ci.nsICookiePermission.ACCESS_SESSION + ); +}); + +// This again seems out of places, but AutoLaunchProtocolsFromOrigins +// is all permissions. +add_task(async function test_autolaunchprotocolsfromorigins() { + await setupPolicyEngineWithJson({ + policies: { + AutoLaunchProtocolsFromOrigins: [ + { + allowed_origins: ["https://allowsession.example.com"], + protocol: "test-protocol", + }, + ], + }, + }); + equal( + PermissionTestUtils.testPermission( + URI("https://allowsession.example.com"), + "open-protocol-handler^test-protocol" + ), + Ci.nsIPermissionManager.ALLOW_ACTION + ); +}); + +// This again seems out of places, but PasswordManagerExceptions +// is all permissions. +add_task(async function test_passwordmanagerexceptions() { + await setupPolicyEngineWithJson({ + policies: { + PasswordManagerExceptions: ["https://pwexception.example.com"], + }, + }); + equal( + PermissionTestUtils.testPermission( + URI("https://pwexception.example.com"), + "login-saving" + ), + Ci.nsIPermissionManager.DENY_ACTION + ); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_policy_search_engine.js b/browser/components/enterprisepolicies/tests/xpcshell/test_policy_search_engine.js new file mode 100644 index 0000000000..5c602442f2 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_policy_search_engine.js @@ -0,0 +1,490 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const { SearchTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/SearchTestUtils.sys.mjs" +); +const { TestUtils } = ChromeUtils.importESModule( + "resource://testing-common/TestUtils.sys.mjs" +); +var { AddonTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/AddonTestUtils.sys.mjs" +); + +Services.prefs.setBoolPref("browser.search.log", true); +SearchTestUtils.init(this); + +AddonTestUtils.init(this, false); +AddonTestUtils.createAppInfo( + "xpcshell@tests.mozilla.org", + "XPCShell", + "48", + "48" +); + +add_setup(async () => { + await AddonTestUtils.promiseStartupManager(); + await Services.search.init(); + console.log("done init"); +}); + +add_task(async function test_install_and_set_default() { + // Make sure we are starting in an expected state to avoid false positive + // test results. + Assert.notEqual( + (await Services.search.getDefault()).name, + "MozSearch", + "Default search engine should not be MozSearch when test starts" + ); + Assert.equal( + Services.search.getEngineByName("Foo"), + null, + 'Engine "Foo" should not be present when test starts' + ); + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "MozSearch", + URLTemplate: "http://example.com/?q={searchTerms}", + }, + ], + Default: "MozSearch", + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + // If this passes, it means that the new search engine was properly installed + // *and* was properly set as the default. + Assert.equal( + (await Services.search.getDefault()).name, + "MozSearch", + "Specified search engine should be the default" + ); + + // Clean up + await setupPolicyEngineWithJsonWithSearch({}); + EnterprisePolicyTesting.resetRunOnceState(); +}); + +add_task(async function test_install_and_set_default_private() { + // Make sure we are starting in an expected state to avoid false positive + // test results. + Assert.notEqual( + (await Services.search.getDefaultPrivate()).name, + "MozSearch", + "Default search engine should not be MozSearch when test starts" + ); + Assert.equal( + Services.search.getEngineByName("Foo"), + null, + 'Engine "Foo" should not be present when test starts' + ); + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "MozSearch", + URLTemplate: "http://example.com/?q={searchTerms}", + }, + ], + DefaultPrivate: "MozSearch", + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + // If this passes, it means that the new search engine was properly installed + // *and* was properly set as the default. + Assert.equal( + (await Services.search.getDefaultPrivate()).name, + "MozSearch", + "Specified search engine should be the default private engine" + ); + + // Clean up + await setupPolicyEngineWithJsonWithSearch({}); + EnterprisePolicyTesting.resetRunOnceState(); +}); + +// Same as the last test, but with "PreventInstalls" set to true to make sure +// it does not prevent search engines from being installed properly +add_task(async function test_install_and_set_default_prevent_installs() { + Assert.notEqual( + (await Services.search.getDefault()).name, + "MozSearch", + "Default search engine should not be MozSearch when test starts" + ); + Assert.equal( + Services.search.getEngineByName("Foo"), + null, + 'Engine "Foo" should not be present when test starts' + ); + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "MozSearch", + URLTemplate: "http://example.com/?q={searchTerms}", + }, + ], + Default: "MozSearch", + PreventInstalls: true, + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + Assert.equal( + (await Services.search.getDefault()).name, + "MozSearch", + "Specified search engine should be the default" + ); + + // Clean up + await setupPolicyEngineWithJsonWithSearch({}); + EnterprisePolicyTesting.resetRunOnceState(); +}); + +add_task(async function test_install_and_remove() { + let iconURL = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII="; + + Assert.equal( + Services.search.getEngineByName("Foo"), + null, + 'Engine "Foo" should not be present when test starts' + ); + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "Foo", + URLTemplate: "http://example.com/?q={searchTerms}", + IconURL: iconURL, + }, + ], + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + // If this passes, it means that the new search engine was properly installed + + let engine = Services.search.getEngineByName("Foo"); + Assert.notEqual(engine, null, "Specified search engine should be installed"); + + Assert.equal( + engine.wrappedJSObject.getIconURL(), + iconURL, + "Icon should be present" + ); + Assert.equal( + engine.wrappedJSObject.queryCharset, + "UTF-8", + "Should default to utf-8" + ); + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Remove: ["Foo"], + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + // If this passes, it means that the specified engine was properly removed + Assert.equal( + Services.search.getEngineByName("Foo"), + null, + "Specified search engine should not be installed" + ); + + await setupPolicyEngineWithJsonWithSearch({}); + EnterprisePolicyTesting.resetRunOnceState(); +}); + +add_task(async function test_install_post_method_engine() { + Assert.equal( + Services.search.getEngineByName("Post"), + null, + 'Engine "Post" should not be present when test starts' + ); + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "Post", + Method: "POST", + PostData: "q={searchTerms}&anotherParam=yes", + URLTemplate: "http://example.com/", + }, + ], + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + let engine = Services.search.getEngineByName("Post"); + Assert.notEqual(engine, null, "Specified search engine should be installed"); + + Assert.equal( + engine.wrappedJSObject._urls[0].method, + "POST", + "Method should be POST" + ); + + let submission = engine.getSubmission("term", "text/html"); + Assert.notEqual(submission.postData, null, "Post data should not be null"); + + let scriptableInputStream = Cc[ + "@mozilla.org/scriptableinputstream;1" + ].createInstance(Ci.nsIScriptableInputStream); + scriptableInputStream.init(submission.postData); + Assert.equal( + scriptableInputStream.read(scriptableInputStream.available()), + "q=term&anotherParam=yes", + "Post data should be present" + ); + + await setupPolicyEngineWithJsonWithSearch({}); + EnterprisePolicyTesting.resetRunOnceState(); +}); + +add_task(async function test_install_with_encoding() { + // Make sure we are starting in an expected state to avoid false positive + // test results. + Assert.equal( + Services.search.getEngineByName("Encoding"), + null, + 'Engine "Encoding" should not be present when test starts' + ); + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "Encoding", + Encoding: "windows-1252", + URLTemplate: "http://example.com/?q={searchTerms}", + }, + ], + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + let engine = Services.search.getEngineByName("Encoding"); + Assert.equal( + engine.wrappedJSObject.queryCharset, + "windows-1252", + "Should have correct encoding" + ); + + // Clean up + await setupPolicyEngineWithJsonWithSearch({}); + EnterprisePolicyTesting.resetRunOnceState(); +}); + +add_task(async function test_install_and_update() { + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "ToUpdate", + URLTemplate: "http://initial.example.com/?q={searchTerms}", + }, + ], + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + let engine = Services.search.getEngineByName("ToUpdate"); + Assert.notEqual(engine, null, "Specified search engine should be installed"); + + Assert.equal( + engine.getSubmission("test").uri.spec, + "http://initial.example.com/?q=test", + "Initial submission URL should be correct." + ); + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "ToUpdate", + URLTemplate: "http://update.example.com/?q={searchTerms}", + }, + ], + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + engine = Services.search.getEngineByName("ToUpdate"); + Assert.notEqual(engine, null, "Specified search engine should be installed"); + + Assert.equal( + engine.getSubmission("test").uri.spec, + "http://update.example.com/?q=test", + "Updated Submission URL should be correct." + ); + + // Clean up + await setupPolicyEngineWithJsonWithSearch({}); + EnterprisePolicyTesting.resetRunOnceState(); +}); + +add_task(async function test_install_with_suggest() { + // Make sure we are starting in an expected state to avoid false positive + // test results. + Assert.equal( + Services.search.getEngineByName("Suggest"), + null, + 'Engine "Suggest" should not be present when test starts' + ); + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "Suggest", + URLTemplate: "http://example.com/?q={searchTerms}", + SuggestURLTemplate: "http://suggest.example.com/?q={searchTerms}", + }, + ], + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + let engine = Services.search.getEngineByName("Suggest"); + + Assert.equal( + engine.getSubmission("test", "application/x-suggestions+json").uri.spec, + "http://suggest.example.com/?q=test", + "Updated Submission URL should be correct." + ); + + // Clean up + await setupPolicyEngineWithJsonWithSearch({}); + EnterprisePolicyTesting.resetRunOnceState(); +}); + +add_task(async function test_install_and_restart_keeps_settings() { + // Make sure we are starting in an expected state to avoid false positive + // test results. + Assert.equal( + Services.search.getEngineByName("Settings"), + null, + 'Engine "Settings" should not be present when test starts' + ); + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "Settings", + URLTemplate: "http://example.com/?q={searchTerms}", + }, + ], + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + let settingsWritten = SearchTestUtils.promiseSearchNotification( + "write-settings-to-disk-complete" + ); + let engine = Services.search.getEngineByName("Settings"); + engine.hidden = true; + engine.alias = "settings"; + await settingsWritten; + + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Add: [ + { + Name: "Settings", + URLTemplate: "http://example.com/?q={searchTerms}", + }, + ], + }, + }, + }); + + engine = Services.search.getEngineByName("Settings"); + + Assert.ok(engine.hidden, "Should have kept the engine hidden after restart"); + Assert.equal( + engine.alias, + "settings", + "Should have kept the engine alias after restart" + ); + + // Clean up + await setupPolicyEngineWithJsonWithSearch({}); + EnterprisePolicyTesting.resetRunOnceState(); +}); + +add_task(async function test_reset_default() { + await setupPolicyEngineWithJsonWithSearch({ + policies: { + SearchEngines: { + Remove: ["DuckDuckGo"], + }, + }, + }); + // Get in line, because the Search policy callbacks are async. + await TestUtils.waitForTick(); + + let engine = Services.search.getEngineByName("DuckDuckGo"); + + Assert.equal( + engine.hidden, + true, + "Application specified engine should be hidden." + ); + + await Services.search.restoreDefaultEngines(); + + engine = Services.search.getEngineByName("DuckDuckGo"); + Assert.equal( + engine.hidden, + false, + "Application specified engine should not be hidden" + ); + + EnterprisePolicyTesting.resetRunOnceState(); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_popups_cookies_addons.js b/browser/components/enterprisepolicies/tests/xpcshell/test_popups_cookies_addons.js new file mode 100644 index 0000000000..8da8d4b9e4 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_popups_cookies_addons.js @@ -0,0 +1,121 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_setup_preexisting_permissions() { + // Pre-existing ALLOW permissions that should be overriden + // with DENY. + + // No ALLOW -> DENY override for popup and install permissions, + // because their policies only supports the Allow parameter. + + PermissionTestUtils.add( + "https://www.pre-existing-allow.com", + "cookie", + Ci.nsIPermissionManager.ALLOW_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + + // Pre-existing DENY permissions that should be overriden + // with ALLOW. + PermissionTestUtils.add( + "https://www.pre-existing-deny.com", + "popup", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + + PermissionTestUtils.add( + "https://www.pre-existing-deny.com", + "install", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + + PermissionTestUtils.add( + "https://www.pre-existing-deny.com", + "cookie", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); +}); + +add_task(async function test_setup_activate_policies() { + await setupPolicyEngineWithJson("config_popups_cookies_addons.json"); + equal( + Services.policies.status, + Ci.nsIEnterprisePolicies.ACTIVE, + "Engine is active" + ); +}); + +function checkPermission(url, expected, permissionName) { + let expectedValue = Ci.nsIPermissionManager[`${expected}_ACTION`]; + let uri = Services.io.newURI(`https://www.${url}`); + + equal( + PermissionTestUtils.testPermission(uri, permissionName), + expectedValue, + `Correct (${permissionName}=${expected}) for URL ${url}` + ); + + if (expected != "UNKNOWN") { + let permission = PermissionTestUtils.getPermissionObject( + uri, + permissionName, + true + ); + ok(permission, "Permission object exists"); + equal( + permission.expireType, + Ci.nsIPermissionManager.EXPIRE_POLICY, + "Permission expireType is correct" + ); + } +} + +function checkAllPermissionsForType(type, typeSupportsDeny = true) { + checkPermission("allow.com", "ALLOW", type); + checkPermission("unknown.com", "UNKNOWN", type); + checkPermission("pre-existing-deny.com", "ALLOW", type); + + if (typeSupportsDeny) { + checkPermission("deny.com", "DENY", type); + checkPermission("pre-existing-allow.com", "DENY", type); + } +} + +add_task(async function test_popups_policy() { + checkAllPermissionsForType("popup", false); +}); + +add_task(async function test_webextensions_policy() { + checkAllPermissionsForType("install", false); +}); + +add_task(async function test_cookies_policy() { + checkAllPermissionsForType("cookie"); +}); + +add_task(async function test_change_permission() { + // Checks that changing a permission will still retain the + // value set through the engine. + PermissionTestUtils.add( + "https://www.allow.com", + "cookie", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); + + checkPermission("allow.com", "ALLOW", "cookie"); + + // Also change one un-managed permission to make sure it doesn't + // cause any problems to the policy engine or the permission manager. + PermissionTestUtils.add( + "https://www.unmanaged.com", + "cookie", + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION + ); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_preferences.js b/browser/components/enterprisepolicies/tests/xpcshell/test_preferences.js new file mode 100644 index 0000000000..eb13fe24ae --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_preferences.js @@ -0,0 +1,257 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const OLD_PREFERENCES_TESTS = [ + { + policies: { + Preferences: { + "network.IDN_show_punycode": true, + "accessibility.force_disabled": 1, + "security.default_personal_cert": "Select Automatically", + "geo.enabled": 1, + "extensions.getAddons.showPane": 0, + }, + }, + lockedPrefs: { + "network.IDN_show_punycode": true, + "accessibility.force_disabled": 1, + "security.default_personal_cert": "Select Automatically", + "geo.enabled": true, + "extensions.getAddons.showPane": false, + }, + }, +]; + +const NEW_PREFERENCES_TESTS = [ + { + policies: { + Preferences: { + "browser.policies.test.default.boolean": { + Value: true, + Status: "default", + }, + "browser.policies.test.default.string": { + Value: "string", + Status: "default", + }, + "browser.policies.test.default.number": { + Value: 11, + Status: "default", + }, + "browser.policies.test.locked.boolean": { + Value: true, + Status: "locked", + }, + "browser.policies.test.locked.string": { + Value: "string", + Status: "locked", + }, + "browser.policies.test.locked.number": { + Value: 11, + Status: "locked", + }, + "browser.policies.test.user.boolean": { + Value: true, + Status: "user", + }, + "browser.policies.test.user.string": { + Value: "string", + Status: "user", + }, + "browser.policies.test.user.number": { + Value: 11, + Status: "user", + }, + "browser.policies.test.default.number.implicit": { + Value: 0, + Status: "default", + }, + "browser.policies.test.default.number.explicit": { + Value: 0, + Status: "default", + Type: "number", + }, + }, + }, + defaultPrefs: { + "browser.policies.test.default.boolean": true, + "browser.policies.test.default.string": "string", + "browser.policies.test.default.number": 11, + "browser.policies.test.default.number.implicit": false, + "browser.policies.test.default.number.explicit": 0, + }, + lockedPrefs: { + "browser.policies.test.locked.boolean": true, + "browser.policies.test.locked.string": "string", + "browser.policies.test.locked.number": 11, + }, + userPrefs: { + "browser.policies.test.user.boolean": true, + "browser.policies.test.user.string": "string", + "browser.policies.test.user.number": 11, + }, + }, + { + policies: { + Preferences: { + "browser.policies.test.user.boolean": { + Status: "clear", + }, + "browser.policies.test.user.string": { + Status: "clear", + }, + "browser.policies.test.user.number": { + Status: "clear", + }, + }, + }, + + clearPrefs: { + "browser.policies.test.user.boolean": true, + "browser.policies.test.user.string": "string", + "browser.policies.test.user.number": 11, + }, + }, +]; + +const BAD_PREFERENCES_TESTS = [ + { + policies: { + Preferences: { + "not.a.valid.branch": { + Value: true, + Status: "default", + }, + "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer": + { + Value: true, + Status: "default", + }, + }, + }, + defaultPrefs: { + "not.a.valid.branch": true, + "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer": true, + }, + }, +]; + +add_task(async function test_old_preferences() { + for (let test of OLD_PREFERENCES_TESTS) { + await setupPolicyEngineWithJson({ + policies: test.policies, + }); + + info("Checking policy: " + Object.keys(test.policies)[0]); + + for (let [prefName, prefValue] of Object.entries(test.lockedPrefs || {})) { + checkLockedPref(prefName, prefValue); + } + } +}); + +add_task(async function test_new_preferences() { + for (let test of NEW_PREFERENCES_TESTS) { + await setupPolicyEngineWithJson({ + policies: test.policies, + }); + + info("Checking policy: " + Object.keys(test.policies)[0]); + + for (let [prefName, prefValue] of Object.entries(test.lockedPrefs || {})) { + checkLockedPref(prefName, prefValue); + } + + for (let [prefName, prefValue] of Object.entries(test.defaultPrefs || {})) { + checkDefaultPref(prefName, prefValue); + } + + for (let [prefName, prefValue] of Object.entries(test.userPrefs || {})) { + checkUserPref(prefName, prefValue); + } + + for (let [prefName, prefValue] of Object.entries(test.clearPrefs || {})) { + checkClearPref(prefName, prefValue); + } + } +}); + +add_task(async function test_bad_preferences() { + for (let test of BAD_PREFERENCES_TESTS) { + await setupPolicyEngineWithJson({ + policies: test.policies, + }); + + info("Checking policy: " + Object.keys(test.policies)[0]); + + for (let prefName of Object.entries(test.defaultPrefs || {})) { + checkUnsetPref(prefName); + } + } +}); + +add_task(async function test_user_default_preference() { + Services.prefs + .getDefaultBranch("") + .setBoolPref("browser.policies.test.override", true); + + await setupPolicyEngineWithJson({ + policies: { + Preferences: { + "browser.policies.test.override": { + Value: true, + Status: "user", + }, + }, + }, + }); + + checkUserPref("browser.policies.test.override", true); +}); + +add_task(async function test_security_preference() { + await setupPolicyEngineWithJson({ + policies: { + Preferences: { + "security.this.should.not.work": { + Value: true, + Status: "default", + }, + }, + }, + }); + + checkUnsetPref("security.this.should.not.work"); +}); + +add_task(async function test_JSON_preferences() { + await setupPolicyEngineWithJson({ + policies: { + Preferences: + '{"browser.policies.test.default.boolean.json": {"Value": true,"Status": "default"}}', + }, + }); + + checkDefaultPref("browser.policies.test.default.boolean.json", true); +}); + +add_task(async function test_bug_1666836() { + await setupPolicyEngineWithJson({ + policies: { + Preferences: { + "browser.tabs.warnOnClose": { + Value: 0, + Status: "default", + }, + }, + }, + }); + + equal( + Preferences.get("browser.tabs.warnOnClose"), + false, + `browser.tabs.warnOnClose should be false` + ); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_proxy.js b/browser/components/enterprisepolicies/tests/xpcshell/test_proxy.js new file mode 100644 index 0000000000..ef5ad1e178 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_proxy.js @@ -0,0 +1,122 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +add_task(async function test_proxy_modes_and_autoconfig() { + // Directly test the proxy Mode and AutoconfigURL parameters through + // the API instead of the policy engine, because the test harness + // uses these prefs, and changing them interfere with the harness. + + // Checks that every Mode value translates correctly to the expected pref value + let { ProxyPolicies, PROXY_TYPES_MAP } = ChromeUtils.importESModule( + "resource:///modules/policies/ProxyPolicies.sys.mjs" + ); + + for (let [mode, expectedValue] of PROXY_TYPES_MAP) { + ProxyPolicies.configureProxySettings({ Mode: mode }, (_, value) => { + equal(value, expectedValue, "Correct proxy mode"); + }); + } + + let autoconfigURL = new URL("data:text/plain,test"); + ProxyPolicies.configureProxySettings( + { AutoConfigURL: autoconfigURL }, + (_, value) => { + equal(value, autoconfigURL.href, "AutoconfigURL correctly set"); + } + ); +}); + +add_task(async function test_proxy_boolean_settings() { + // Tests that both false and true values are correctly set and locked + await setupPolicyEngineWithJson({ + policies: { + Proxy: { + UseProxyForDNS: false, + AutoLogin: false, + }, + }, + }); + + checkUnlockedPref("network.proxy.socks_remote_dns", false); + checkUnlockedPref("signon.autologin.proxy", false); + + await setupPolicyEngineWithJson({ + policies: { + Proxy: { + UseProxyForDNS: true, + AutoLogin: true, + }, + }, + }); + + checkUnlockedPref("network.proxy.socks_remote_dns", true); + checkUnlockedPref("signon.autologin.proxy", true); +}); + +add_task(async function test_proxy_socks_and_passthrough() { + await setupPolicyEngineWithJson({ + policies: { + Proxy: { + SOCKSVersion: 4, + Passthrough: "a, b, c", + }, + }, + }); + + checkUnlockedPref("network.proxy.socks_version", 4); + checkUnlockedPref("network.proxy.no_proxies_on", "a, b, c"); +}); + +add_task(async function test_proxy_addresses() { + function checkProxyPref(proxytype, address, port) { + checkUnlockedPref(`network.proxy.${proxytype}`, address); + checkUnlockedPref(`network.proxy.${proxytype}_port`, port); + } + + await setupPolicyEngineWithJson({ + policies: { + Proxy: { + HTTPProxy: "http.proxy.example.com:10", + SSLProxy: "ssl.proxy.example.com:30", + SOCKSProxy: "socks.proxy.example.com:40", + }, + }, + }); + + checkProxyPref("http", "http.proxy.example.com", 10); + checkProxyPref("ssl", "ssl.proxy.example.com", 30); + checkProxyPref("socks", "socks.proxy.example.com", 40); + + // Do the same, but now use the UseHTTPProxyForAllProtocols option + // and check that it takes effect. + await setupPolicyEngineWithJson({ + policies: { + Proxy: { + HTTPProxy: "http.proxy.example.com:10", + // FTP support was removed in bug 1574475 + // Setting an FTPProxy should result in a warning but should not fail + FTPProxy: "ftp.proxy.example.com:20", + SSLProxy: "ssl.proxy.example.com:30", + SOCKSProxy: "socks.proxy.example.com:40", + UseHTTPProxyForAllProtocols: true, + }, + }, + }); + + checkProxyPref("http", "http.proxy.example.com", 10); + checkProxyPref("ssl", "http.proxy.example.com", 10); + checkProxyPref("socks", "http.proxy.example.com", 10); + + // Make sure the FTPProxy setting did nothing + Assert.equal( + Preferences.has("network.proxy.ftp"), + false, + "network.proxy.ftp should not be set" + ); + Assert.equal( + Preferences.has("network.proxy.ftp_port"), + false, + "network.proxy.ftp_port should not be set" + ); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_requestedlocales.js b/browser/components/enterprisepolicies/tests/xpcshell/test_requestedlocales.js new file mode 100644 index 0000000000..5908b2d35c --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_requestedlocales.js @@ -0,0 +1,119 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +var { setTimeout } = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" +); + +const REQ_LOC_CHANGE_EVENT = "intl:requested-locales-changed"; + +function promiseLocaleChanged(requestedLocale) { + return new Promise(resolve => { + let localeObserver = { + observe(aSubject, aTopic, aData) { + switch (aTopic) { + case REQ_LOC_CHANGE_EVENT: + let reqLocs = Services.locale.requestedLocales; + equal(reqLocs[0], requestedLocale); + Services.obs.removeObserver(localeObserver, REQ_LOC_CHANGE_EVENT); + resolve(); + } + }, + }; + Services.obs.addObserver(localeObserver, REQ_LOC_CHANGE_EVENT); + }); +} + +function promiseLocaleNotChanged(requestedLocale) { + return new Promise(resolve => { + let localeObserver = { + observe(aSubject, aTopic, aData) { + switch (aTopic) { + case REQ_LOC_CHANGE_EVENT: + ok(false, "Locale should not change."); + Services.obs.removeObserver(localeObserver, REQ_LOC_CHANGE_EVENT); + resolve(); + } + }, + }; + Services.obs.addObserver(localeObserver, REQ_LOC_CHANGE_EVENT); + /* eslint-disable mozilla/no-arbitrary-setTimeout */ + setTimeout(function () { + Services.obs.removeObserver(localeObserver, REQ_LOC_CHANGE_EVENT); + resolve(); + }, 100); + }); +} + +add_task(async function test_requested_locale_array() { + let originalLocales = Services.locale.requestedLocales; + let localePromise = promiseLocaleChanged("de"); + await setupPolicyEngineWithJson({ + policies: { + RequestedLocales: ["de"], + }, + }); + await localePromise; + Services.locale.requestedLocales = originalLocales; +}); + +add_task(async function test_requested_locale_string() { + let originalLocales = Services.locale.requestedLocales; + let localePromise = promiseLocaleChanged("fr"); + await setupPolicyEngineWithJson({ + policies: { + RequestedLocales: "fr", + }, + }); + await localePromise; + Services.locale.requestedLocales = originalLocales; +}); + +add_task(async function test_system_locale_string() { + let originalLocales = Services.locale.requestedLocales; + + let localePromise = promiseLocaleChanged("und"); + Services.locale.requestedLocales = ["und"]; + await localePromise; + + let systemLocale = Cc["@mozilla.org/intl/ospreferences;1"].getService( + Ci.mozIOSPreferences + ).systemLocale; + localePromise = promiseLocaleChanged(systemLocale); + + await setupPolicyEngineWithJson({ + policies: { + RequestedLocales: "", + }, + }); + await localePromise; + Services.locale.requestedLocales = originalLocales; +}); + +add_task(async function test_user_requested_locale_change() { + let originalLocales = Services.locale.requestedLocales; + let localePromise = promiseLocaleChanged("fr"); + await setupPolicyEngineWithJson({ + policies: { + RequestedLocales: "fr", + }, + }); + await localePromise; + + // Simulate user change of locale + localePromise = promiseLocaleChanged("de"); + Services.locale.requestedLocales = ["de"]; + await localePromise; + + localePromise = promiseLocaleNotChanged("fr"); + await setupPolicyEngineWithJson({ + policies: { + RequestedLocales: "fr", + }, + }); + await localePromise; + + Services.locale.requestedLocales = originalLocales; +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_runOnce_helper.js b/browser/components/enterprisepolicies/tests/xpcshell/test_runOnce_helper.js new file mode 100644 index 0000000000..c8e73b3422 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_runOnce_helper.js @@ -0,0 +1,21 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +let { runOnce } = ChromeUtils.importESModule( + "resource:///modules/policies/Policies.sys.mjs" +); + +let runCount = 0; +function callback() { + runCount++; +} + +add_task(async function test_runonce_helper() { + runOnce("test_action", callback); + equal(runCount, 1, "Callback ran for the first time."); + + runOnce("test_action", callback); + equal(runCount, 1, "Callback didn't run again."); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_simple_pref_policies.js b/browser/components/enterprisepolicies/tests/xpcshell/test_simple_pref_policies.js new file mode 100644 index 0000000000..8ef8b831ef --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_simple_pref_policies.js @@ -0,0 +1,1055 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* + * Use this file to add tests to policies that are + * simple pref flips. + * + * It's best to make a test to actually test the feature + * instead of the pref flip, but if that feature is well + * covered by tests, including that its pref actually works, + * it's OK to have the policy test here just to ensure + * that the right pref values are set. + */ + +const POLICIES_TESTS = [ + /* + * Example: + * { + * // Policies to be set at once through the engine + * policies: { "DisableFoo": true, "ConfigureBar": 42 }, + * + * // Locked prefs to check + * lockedPrefs: { "feature.foo": false }, + * + * // Unlocked prefs to check + * unlockedPrefs: { "bar.baz": 42 } + * }, + */ + + // POLICY: DisableSecurityBypass + { + policies: { + DisableSecurityBypass: { + InvalidCertificate: true, + SafeBrowsing: true, + }, + }, + lockedPrefs: { + "security.certerror.hideAddException": true, + "browser.safebrowsing.allowOverride": false, + }, + }, + + // POLICY: DisableBuiltinPDFViewer + { + policies: { DisableBuiltinPDFViewer: true }, + lockedPrefs: { "pdfjs.disabled": true }, + }, + + // POLICY: DisableFormHistory + { + policies: { DisableFormHistory: true }, + lockedPrefs: { "browser.formfill.enable": false }, + }, + + // POLICY: EnableTrackingProtection + { + policies: { + EnableTrackingProtection: { + Value: true, + }, + }, + unlockedPrefs: { + "privacy.trackingprotection.enabled": true, + "privacy.trackingprotection.pbmode.enabled": true, + }, + }, + { + policies: { + EnableTrackingProtection: { + Value: false, + Locked: true, + }, + }, + lockedPrefs: { + "privacy.trackingprotection.enabled": false, + "privacy.trackingprotection.pbmode.enabled": false, + }, + }, + + { + policies: { + EnableTrackingProtection: { + Cryptomining: true, + Fingerprinting: true, + EmailTracking: true, + Locked: true, + }, + }, + lockedPrefs: { + "privacy.trackingprotection.cryptomining.enabled": true, + "privacy.trackingprotection.fingerprinting.enabled": true, + "privacy.trackingprotection.emailtracking.enabled": true, + "privacy.trackingprotection.emailtracking.pbmode.enabled": true, + }, + }, + + // POLICY: GoToIntranetSiteForSingleWordEntryInAddressBar + { + policies: { + GoToIntranetSiteForSingleWordEntryInAddressBar: true, + }, + lockedPrefs: { + "browser.fixup.dns_first_for_single_words": true, + }, + }, + + // POLICY: OverrideFirstRunPage + { + policies: { OverrideFirstRunPage: "https://www.example.com/" }, + lockedPrefs: { "startup.homepage_welcome_url": "https://www.example.com/" }, + }, + + // POLICY: Authentication + { + policies: { + Authentication: { + SPNEGO: ["a.com", "b.com"], + Delegated: ["a.com", "b.com"], + NTLM: ["a.com", "b.com"], + AllowNonFQDN: { + SPNEGO: true, + NTLM: true, + }, + AllowProxies: { + SPNEGO: false, + NTLM: false, + }, + PrivateBrowsing: true, + }, + }, + lockedPrefs: { + "network.negotiate-auth.trusted-uris": "a.com, b.com", + "network.negotiate-auth.delegation-uris": "a.com, b.com", + "network.automatic-ntlm-auth.trusted-uris": "a.com, b.com", + "network.automatic-ntlm-auth.allow-non-fqdn": true, + "network.negotiate-auth.allow-non-fqdn": true, + "network.automatic-ntlm-auth.allow-proxies": false, + "network.negotiate-auth.allow-proxies": false, + "network.auth.private-browsing-sso": true, + }, + }, + + // POLICY: Authentication (unlocked) + { + policies: { + Authentication: { + SPNEGO: ["a.com", "b.com"], + Delegated: ["a.com", "b.com"], + NTLM: ["a.com", "b.com"], + AllowNonFQDN: { + SPNEGO: true, + NTLM: true, + }, + AllowProxies: { + SPNEGO: false, + NTLM: false, + }, + PrivateBrowsing: true, + Locked: false, + }, + }, + unlockedPrefs: { + "network.negotiate-auth.trusted-uris": "a.com, b.com", + "network.negotiate-auth.delegation-uris": "a.com, b.com", + "network.automatic-ntlm-auth.trusted-uris": "a.com, b.com", + "network.automatic-ntlm-auth.allow-non-fqdn": true, + "network.negotiate-auth.allow-non-fqdn": true, + "network.automatic-ntlm-auth.allow-proxies": false, + "network.negotiate-auth.allow-proxies": false, + "network.auth.private-browsing-sso": true, + }, + }, + + // POLICY: Certificates (true) + { + policies: { + Certificates: { + ImportEnterpriseRoots: true, + }, + }, + lockedPrefs: { + "security.enterprise_roots.enabled": true, + }, + }, + + // POLICY: Certificates (false) + { + policies: { + Certificates: { + ImportEnterpriseRoots: false, + }, + }, + lockedPrefs: { + "security.enterprise_roots.enabled": false, + }, + }, + + // POLICY: InstallAddons.Default (block addon installs) + { + policies: { + InstallAddonsPermission: { + Default: false, + }, + }, + lockedPrefs: { + "xpinstall.enabled": false, + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons": false, + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features": false, + }, + }, + + // POLICY: SanitizeOnShutdown + { + policies: { + SanitizeOnShutdown: true, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": true, + "privacy.clearOnShutdown.cookies": true, + "privacy.clearOnShutdown.downloads": true, + "privacy.clearOnShutdown.formdata": true, + "privacy.clearOnShutdown.history": true, + "privacy.clearOnShutdown.sessions": true, + "privacy.clearOnShutdown.siteSettings": true, + "privacy.clearOnShutdown.offlineApps": true, + }, + }, + + { + policies: { + SanitizeOnShutdown: false, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": false, + "privacy.clearOnShutdown.cache": false, + "privacy.clearOnShutdown.cookies": false, + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": false, + "privacy.clearOnShutdown.siteSettings": false, + "privacy.clearOnShutdown.offlineApps": false, + }, + }, + + { + policies: { + SanitizeOnShutdown: { + Cache: true, + }, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": true, + "privacy.clearOnShutdown.cookies": false, + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": false, + }, + }, + + { + policies: { + SanitizeOnShutdown: { + Cookies: true, + }, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": false, + "privacy.clearOnShutdown.cookies": true, + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": false, + }, + }, + + { + policies: { + SanitizeOnShutdown: { + Downloads: true, + }, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": false, + "privacy.clearOnShutdown.cookies": false, + "privacy.clearOnShutdown.downloads": true, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": false, + }, + }, + + { + policies: { + SanitizeOnShutdown: { + FormData: true, + }, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": false, + "privacy.clearOnShutdown.cookies": false, + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": true, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": false, + }, + }, + + { + policies: { + SanitizeOnShutdown: { + History: true, + }, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": false, + "privacy.clearOnShutdown.cookies": false, + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": true, + "privacy.clearOnShutdown.sessions": false, + }, + }, + + { + policies: { + SanitizeOnShutdown: { + Sessions: true, + }, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": false, + "privacy.clearOnShutdown.cookies": false, + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": true, + }, + }, + + { + policies: { + SanitizeOnShutdown: { + SiteSettings: true, + }, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": false, + "privacy.clearOnShutdown.cookies": false, + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": false, + "privacy.clearOnShutdown.siteSettings": true, + }, + }, + + { + policies: { + SanitizeOnShutdown: { + OfflineApps: true, + }, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": false, + "privacy.clearOnShutdown.cookies": false, + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": false, + "privacy.clearOnShutdown.offlineApps": true, + }, + }, + + // POLICY: SanitizeOnShutdown using Locked + { + policies: { + SanitizeOnShutdown: { + Cache: true, + Locked: true, + }, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": true, + }, + unlockedPrefs: { + "privacy.clearOnShutdown.cookies": false, + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": false, + }, + }, + + { + policies: { + SanitizeOnShutdown: { + Cache: true, + Cookies: false, + Locked: true, + }, + }, + lockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": true, + "privacy.clearOnShutdown.cookies": false, + }, + unlockedPrefs: { + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": false, + }, + }, + + { + policies: { + SanitizeOnShutdown: { + Cache: true, + Locked: false, + }, + }, + unlockedPrefs: { + "privacy.sanitize.sanitizeOnShutdown": true, + "privacy.clearOnShutdown.cache": true, + "privacy.clearOnShutdown.cookies": false, + "privacy.clearOnShutdown.downloads": false, + "privacy.clearOnShutdown.formdata": false, + "privacy.clearOnShutdown.history": false, + "privacy.clearOnShutdown.sessions": false, + }, + }, + + // POLICY: DNSOverHTTPS Unlocked + { + policies: { + DNSOverHTTPS: { + Enabled: false, + ProviderURL: "https://example.com/provider", + ExcludedDomains: ["example.com", "example.org"], + }, + }, + unlockedPrefs: { + "network.trr.mode": 5, + "network.trr.uri": "https://example.com/provider", + "network.trr.excluded-domains": "example.com,example.org", + }, + }, + + // POLICY: DNSOverHTTPS Fallback off + { + policies: { + DNSOverHTTPS: { + Enabled: true, + Fallback: false, + }, + }, + unlockedPrefs: { + "network.trr.mode": 3, + }, + }, + + // POLICY: DNSOverHTTPS Locked + { + policies: { + DNSOverHTTPS: { + Enabled: true, + ProviderURL: "https://example.com/provider", + ExcludedDomains: ["example.com", "example.org"], + Locked: true, + }, + }, + lockedPrefs: { + "network.trr.mode": 2, + "network.trr.uri": "https://example.com/provider", + "network.trr.excluded-domains": "example.com,example.org", + }, + }, + + // POLICY: SSLVersionMin/SSLVersionMax (1) + { + policies: { + SSLVersionMin: "tls1", + SSLVersionMax: "tls1.1", + }, + lockedPrefs: { + "security.tls.version.min": 1, + "security.tls.version.max": 2, + }, + }, + + // POLICY: SSLVersionMin/SSLVersionMax (2) + { + policies: { + SSLVersionMin: "tls1.2", + SSLVersionMax: "tls1.3", + }, + lockedPrefs: { + "security.tls.version.min": 3, + "security.tls.version.max": 4, + }, + }, + + // POLICY: CaptivePortal + { + policies: { + CaptivePortal: false, + }, + lockedPrefs: { + "network.captive-portal-service.enabled": false, + }, + }, + + // POLICY: NetworkPrediction + { + policies: { + NetworkPrediction: false, + }, + lockedPrefs: { + "network.dns.disablePrefetch": true, + "network.dns.disablePrefetchFromHTTPS": true, + }, + }, + + // POLICY: ExtensionUpdate + { + policies: { + ExtensionUpdate: false, + }, + lockedPrefs: { + "extensions.update.enabled": false, + }, + }, + + // POLICY: DisableShield + { + policies: { + DisableFirefoxStudies: true, + }, + lockedPrefs: { + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons": false, + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features": false, + }, + }, + + // POLICY: NewTabPage + { + policies: { + NewTabPage: false, + }, + lockedPrefs: { + "browser.newtabpage.enabled": false, + }, + }, + + // POLICY: SearchSuggestEnabled + { + policies: { + SearchSuggestEnabled: false, + }, + lockedPrefs: { + "browser.urlbar.suggest.searches": false, + "browser.search.suggest.enabled": false, + }, + }, + + // POLICY: FirefoxHome + { + policies: { + FirefoxHome: { + Pocket: false, + Locked: true, + }, + }, + lockedPrefs: { + "browser.newtabpage.activity-stream.feeds.system.topstories": false, + }, + }, + + // POLICY: OfferToSaveLoginsDefault + { + policies: { + OfferToSaveLoginsDefault: false, + }, + unlockedPrefs: { + "signon.rememberSignons": false, + }, + }, + + // POLICY: RememberPasswords + { + policies: { OfferToSaveLogins: false }, + lockedPrefs: { "signon.rememberSignons": false }, + }, + { + policies: { OfferToSaveLogins: true }, + lockedPrefs: { "signon.rememberSignons": true }, + }, + + // POLICY: UserMessaging + { + policies: { + UserMessaging: { + WhatsNew: false, + SkipOnboarding: true, + Locked: true, + }, + }, + lockedPrefs: { + "browser.messaging-system.whatsNewPanel.enabled": false, + "browser.aboutwelcome.enabled": false, + }, + }, + + // POLICY: UserMessaging->SkipOnboarding false (bug 1697566) + { + policies: { + UserMessaging: { + SkipOnboarding: false, + Locked: false, + }, + }, + unlockedPrefs: { + "browser.aboutwelcome.enabled": true, + }, + }, + + { + policies: { + UserMessaging: { + ExtensionRecommendations: false, + Locked: false, + }, + }, + unlockedPrefs: { + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons": false, + }, + }, + + { + policies: { + UserMessaging: { + FeatureRecommendations: false, + Locked: false, + }, + }, + unlockedPrefs: { + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features": false, + }, + }, + + // POLICY: Permissions->Autoplay + { + policies: { + Permissions: { + Autoplay: { + Default: "block-audio-video", + }, + }, + }, + unlockedPrefs: { + "media.autoplay.default": 5, + }, + }, + + { + policies: { + Permissions: { + Autoplay: { + Default: "allow-audio-video", + Locked: true, + }, + }, + }, + lockedPrefs: { + "media.autoplay.default": 0, + }, + }, + + { + policies: { + Permissions: { + Autoplay: { + Default: "block-audio", + Locked: false, + }, + }, + }, + unlockedPrefs: { + "media.autoplay.default": 1, + }, + }, + + // POLICY: LegacySameSiteCookieBehaviorEnabled + + { + policies: { + LegacySameSiteCookieBehaviorEnabled: true, + }, + unlockedPrefs: { + "network.cookie.sameSite.laxByDefault": false, + }, + }, + + // POLICY: LegacySameSiteCookieBehaviorEnabledForDomainList + + { + policies: { + LegacySameSiteCookieBehaviorEnabledForDomainList: [ + "example.com", + "example.org", + ], + }, + unlockedPrefs: { + "network.cookie.sameSite.laxByDefault.disabledHosts": + "example.com,example.org", + }, + }, + + // POLICY: EncryptedMediaExtensions + + { + policies: { + EncryptedMediaExtensions: { + Enabled: false, + Locked: true, + }, + }, + lockedPrefs: { + "media.eme.enabled": false, + }, + }, + + // POLICY: PDFjs + + { + policies: { + PDFjs: { + Enabled: false, + }, + }, + lockedPrefs: { + "pdfjs.disabled": true, + }, + }, + + { + policies: { + PDFjs: { + Enabled: true, + EnablePermissions: true, + }, + }, + lockedPrefs: { + "pdfjs.disabled": false, + "pdfjs.enablePermissions": true, + }, + }, + + { + policies: { + PDFjs: { + Enabled: true, + EnablePermissions: false, + }, + }, + lockedPrefs: { + "pdfjs.disabled": false, + "pdfjs.enablePermissions": false, + }, + }, + + // POLICY: PictureInPicture + + { + policies: { + PictureInPicture: { + Enabled: false, + Locked: true, + }, + }, + lockedPrefs: { + "media.videocontrols.picture-in-picture.video-toggle.enabled": false, + }, + }, + + // POLICY: DisabledCiphers + { + policies: { + DisabledCiphers: { + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: false, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: false, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: false, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: false, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: false, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: false, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: false, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: false, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: false, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: false, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA: false, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA: false, + TLS_RSA_WITH_AES_128_GCM_SHA256: false, + TLS_RSA_WITH_AES_256_GCM_SHA384: false, + TLS_RSA_WITH_AES_128_CBC_SHA: false, + TLS_RSA_WITH_AES_256_CBC_SHA: false, + TLS_RSA_WITH_3DES_EDE_CBC_SHA: false, + }, + }, + lockedPrefs: { + "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256": true, + "security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256": true, + "security.ssl3.ecdhe_ecdsa_chacha20_poly1305_sha256": true, + "security.ssl3.ecdhe_rsa_chacha20_poly1305_sha256": true, + "security.ssl3.ecdhe_ecdsa_aes_256_gcm_sha384": true, + "security.ssl3.ecdhe_rsa_aes_256_gcm_sha384": true, + "security.ssl3.ecdhe_rsa_aes_128_sha": true, + "security.ssl3.ecdhe_ecdsa_aes_128_sha": true, + "security.ssl3.ecdhe_rsa_aes_256_sha": true, + "security.ssl3.ecdhe_ecdsa_aes_256_sha": true, + "security.ssl3.dhe_rsa_aes_128_sha": true, + "security.ssl3.dhe_rsa_aes_256_sha": true, + "security.ssl3.rsa_aes_128_gcm_sha256": true, + "security.ssl3.rsa_aes_256_gcm_sha384": true, + "security.ssl3.rsa_aes_128_sha": true, + "security.ssl3.rsa_aes_256_sha": true, + "security.ssl3.deprecated.rsa_des_ede3_sha": true, + }, + }, + + { + policies: { + DisabledCiphers: { + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: true, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: true, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: true, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: true, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: true, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: true, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: true, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: true, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA: true, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA: true, + TLS_RSA_WITH_AES_128_GCM_SHA256: true, + TLS_RSA_WITH_AES_256_GCM_SHA384: true, + TLS_RSA_WITH_AES_128_CBC_SHA: true, + TLS_RSA_WITH_AES_256_CBC_SHA: true, + TLS_RSA_WITH_3DES_EDE_CBC_SHA: true, + }, + }, + lockedPrefs: { + "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256": false, + "security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256": false, + "security.ssl3.ecdhe_ecdsa_chacha20_poly1305_sha256": false, + "security.ssl3.ecdhe_rsa_chacha20_poly1305_sha256": false, + "security.ssl3.ecdhe_ecdsa_aes_256_gcm_sha384": false, + "security.ssl3.ecdhe_rsa_aes_256_gcm_sha384": false, + "security.ssl3.ecdhe_rsa_aes_128_sha": false, + "security.ssl3.ecdhe_ecdsa_aes_128_sha": false, + "security.ssl3.ecdhe_rsa_aes_256_sha": false, + "security.ssl3.ecdhe_ecdsa_aes_256_sha": false, + "security.ssl3.dhe_rsa_aes_128_sha": false, + "security.ssl3.dhe_rsa_aes_256_sha": false, + "security.ssl3.rsa_aes_128_gcm_sha256": false, + "security.ssl3.rsa_aes_256_gcm_sha384": false, + "security.ssl3.rsa_aes_128_sha": false, + "security.ssl3.rsa_aes_256_sha": false, + "security.ssl3.deprecated.rsa_des_ede3_sha": false, + }, + }, + + { + policies: { + WindowsSSO: true, + }, + lockedPrefs: { + "network.http.windows-sso.enabled": true, + }, + }, + + { + policies: { + Cookies: { + Behavior: "accept", + BehaviorPrivateBrowsing: "reject-foreign", + Locked: true, + }, + }, + lockedPrefs: { + "network.cookie.cookieBehavior": 0, + "network.cookie.cookieBehavior.pbmode": 1, + }, + }, + + { + policies: { + Cookies: { + Behavior: "reject-foreign", + BehaviorPrivateBrowsing: "reject", + Locked: true, + }, + }, + lockedPrefs: { + "network.cookie.cookieBehavior": 1, + "network.cookie.cookieBehavior.pbmode": 2, + }, + }, + + { + policies: { + Cookies: { + Behavior: "reject", + BehaviorPrivateBrowsing: "limit-foreign", + Locked: true, + }, + }, + lockedPrefs: { + "network.cookie.cookieBehavior": 2, + "network.cookie.cookieBehavior.pbmode": 3, + }, + }, + + { + policies: { + Cookies: { + Behavior: "limit-foreign", + BehaviorPrivateBrowsing: "reject-tracker", + Locked: true, + }, + }, + lockedPrefs: { + "network.cookie.cookieBehavior": 3, + "network.cookie.cookieBehavior.pbmode": 4, + }, + }, + + { + policies: { + Cookies: { + Behavior: "reject-tracker", + BehaviorPrivateBrowsing: "reject-tracker-and-partition-foreign", + Locked: true, + }, + }, + lockedPrefs: { + "network.cookie.cookieBehavior": 4, + "network.cookie.cookieBehavior.pbmode": 5, + }, + }, + { + policies: { + Cookies: { + Behavior: "reject-tracker-and-partition-foreign", + BehaviorPrivateBrowsing: "accept", + Locked: true, + }, + }, + lockedPrefs: { + "network.cookie.cookieBehavior": 5, + "network.cookie.cookieBehavior.pbmode": 0, + }, + }, + + { + policies: { + UseSystemPrintDialog: true, + }, + lockedPrefs: { + "print.prefer_system_dialog": true, + }, + }, + + // Bug 1820195 + { + policies: { + Preferences: { + "pdfjs.cursorToolOnLoad": { + Value: 1, + Status: "default", + }, + "pdfjs.sidebarViewOnLoad": { + Value: 0, + Status: "default", + }, + }, + }, + unlockedPrefs: { + "pdfjs.cursorToolOnLoad": 1, + "pdfjs.sidebarViewOnLoad": 0, + }, + }, + + // Bug 1772503 + { + policies: { + DisableFirefoxStudies: true, + }, + lockedPrefs: { + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons": false, + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features": false, + }, + }, + { + policies: { + Preferences: { + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons": { + Value: true, + }, + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features": { + Value: true, + }, + }, + }, + lockedPrefs: { + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons": true, + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features": true, + }, + }, +]; + +add_task(async function test_policy_simple_prefs() { + for (let test of POLICIES_TESTS) { + await setupPolicyEngineWithJson({ + policies: test.policies, + }); + + info("Checking policy: " + Object.keys(test.policies)[0]); + + for (let [prefName, prefValue] of Object.entries(test.lockedPrefs || {})) { + checkLockedPref(prefName, prefValue); + } + + for (let [prefName, prefValue] of Object.entries( + test.unlockedPrefs || {} + )) { + checkUnlockedPref(prefName, prefValue); + } + } +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_sorted_alphabetically.js b/browser/components/enterprisepolicies/tests/xpcshell/test_sorted_alphabetically.js new file mode 100644 index 0000000000..0d246c850c --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_sorted_alphabetically.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +function checkArrayIsSorted(array, msg) { + let sorted = true; + let sortedArray = array.slice().sort(function (a, b) { + return a.localeCompare(b); + }); + + for (let i = 0; i < array.length; i++) { + if (array[i] != sortedArray[i]) { + sorted = false; + break; + } + } + ok(sorted, msg); +} + +add_task(async function test_policies_sorted() { + let { schema } = ChromeUtils.importESModule( + "resource:///modules/policies/schema.sys.mjs" + ); + let { Policies } = ChromeUtils.importESModule( + "resource:///modules/policies/Policies.sys.mjs" + ); + + checkArrayIsSorted( + Object.keys(schema.properties), + "policies-schema.json is alphabetically sorted." + ); + checkArrayIsSorted( + Object.keys(Policies), + "Policies.jsm is alphabetically sorted." + ); +}); + +add_task(async function check_naming_conventions() { + let { schema } = ChromeUtils.importESModule( + "resource:///modules/policies/schema.sys.mjs" + ); + equal( + Object.keys(schema.properties).some(key => key.includes("__")), + false, + "Can't use __ in a policy name as it's used as a delimiter" + ); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_telemetry.js b/browser/components/enterprisepolicies/tests/xpcshell/test_telemetry.js new file mode 100644 index 0000000000..537465ebd5 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/test_telemetry.js @@ -0,0 +1,102 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const { TelemetryTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/TelemetryTestUtils.sys.mjs" +); +const { AppConstants } = ChromeUtils.importESModule( + "resource://gre/modules/AppConstants.sys.mjs" +); + +add_task(async function test_telemetry_basic() { + await setupPolicyEngineWithJson({ + policies: { + DisableAboutSupport: true, + }, + }); + + TelemetryTestUtils.assertScalar( + TelemetryTestUtils.getProcessScalars("parent"), + "policies.is_enterprise", + true + ); +}); + +add_task(async function test_telemetry_just_roots() { + await setupPolicyEngineWithJson({ + policies: { + Certificates: { + ImportEnterpriseRoots: true, + }, + }, + }); + + TelemetryTestUtils.assertScalar( + TelemetryTestUtils.getProcessScalars("parent"), + "policies.is_enterprise", + AppConstants.IS_ESR + ); +}); + +add_task(async function test_telemetry_roots_plus_policy() { + await setupPolicyEngineWithJson({ + policies: { + DisableAboutSupport: true, + Certificates: { + ImportEnterpriseRoots: true, + }, + }, + }); + + TelemetryTestUtils.assertScalar( + TelemetryTestUtils.getProcessScalars("parent"), + "policies.is_enterprise", + true + ); +}); + +add_task(async function test_telemetry_esr() { + await setupPolicyEngineWithJson({}); + TelemetryTestUtils.assertScalar( + TelemetryTestUtils.getProcessScalars("parent"), + "policies.is_enterprise", + AppConstants.IS_ESR + ); +}); + +add_task(async function test_telemetry_esr_mac_eol() { + Services.prefs + .getDefaultBranch(null) + .setCharPref("distribution.id", "mozilla-mac-eol-esr115"); + await setupPolicyEngineWithJson({}); + TelemetryTestUtils.assertScalar( + TelemetryTestUtils.getProcessScalars("parent"), + "policies.is_enterprise", + false + ); +}); + +add_task(async function test_telemetry_esr_win_eol() { + Services.prefs + .getDefaultBranch(null) + .setCharPref("distribution.id", "mozilla-win-eol-esr115"); + await setupPolicyEngineWithJson({}); + TelemetryTestUtils.assertScalar( + TelemetryTestUtils.getProcessScalars("parent"), + "policies.is_enterprise", + false + ); +}); + +add_task(async function test_telemetry_esr_distro() { + Services.prefs + .getDefaultBranch(null) + .setCharPref("distribution.id", "any-other-distribution-id"); + await setupPolicyEngineWithJson({}); + TelemetryTestUtils.assertScalar( + TelemetryTestUtils.getProcessScalars("parent"), + "policies.is_enterprise", + AppConstants.IS_ESR + ); +}); diff --git a/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml b/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml new file mode 100644 index 0000000000..69dd3e5103 --- /dev/null +++ b/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml @@ -0,0 +1,55 @@ +[DEFAULT] +skip-if = ["os == 'android'"] # bug 1730213 +firefox-appdir = "browser" +head = "head.js" +support-files = ["policytest_v0.1.xpi"] + +["test_3rdparty.js"] + +["test_addon_update.js"] + +["test_appupdatepin.js"] + +["test_appupdateurl.js"] + +["test_bug1658259.js"] + +["test_cleanup.js"] + +["test_clear_blocked_cookies.js"] + +["test_containers.js"] + +["test_defaultbrowsercheck.js"] + +["test_empty_policy.js"] + +["test_exempt_domain_file_type_pairs_from_file_type_download_warnings.js"] + +["test_extensions.js"] + +["test_extensionsettings.js"] + +["test_macosparser_unflatten.js"] +run-if = ["os == 'mac'"] + +["test_permissions.js"] + +["test_policy_search_engine.js"] + +["test_popups_cookies_addons.js"] +support-files = ["config_popups_cookies_addons.json"] + +["test_preferences.js"] + +["test_proxy.js"] + +["test_requestedlocales.js"] + +["test_runOnce_helper.js"] + +["test_simple_pref_policies.js"] + +["test_sorted_alphabetically.js"] + +["test_telemetry.js"] |