From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/browser/browser_webext_incognito.js | 593 +++++++++++++++++++++ 1 file changed, 593 insertions(+) create mode 100644 toolkit/mozapps/extensions/test/browser/browser_webext_incognito.js (limited to 'toolkit/mozapps/extensions/test/browser/browser_webext_incognito.js') diff --git a/toolkit/mozapps/extensions/test/browser/browser_webext_incognito.js b/toolkit/mozapps/extensions/test/browser/browser_webext_incognito.js new file mode 100644 index 0000000000..9180bbcf91 --- /dev/null +++ b/toolkit/mozapps/extensions/test/browser/browser_webext_incognito.js @@ -0,0 +1,593 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +const { AddonTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/AddonTestUtils.sys.mjs" +); +const { ExtensionPermissions } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionPermissions.sys.mjs" +); +const { Management } = ChromeUtils.importESModule( + "resource://gre/modules/Extension.sys.mjs" +); + +var gManagerWindow; + +AddonTestUtils.initMochitest(this); + +function get_test_items() { + var items = {}; + + for (let item of gManagerWindow.document.querySelectorAll("addon-card")) { + items[item.getAttribute("addon-id")] = item; + } + + return items; +} + +function getHtmlElem(selector) { + return gManagerWindow.document.querySelector(selector); +} + +function getPrivateBrowsingBadge(card) { + return card.querySelector(".addon-badge-private-browsing-allowed"); +} + +function getPreferencesButtonAtListView(card) { + return card.querySelector("panel-item[action='preferences']"); +} + +function getPreferencesButtonAtDetailsView() { + return getHtmlElem("panel-item[action='preferences']"); +} + +function isInlineOptionsVisible() { + // The following button is used to open the inline options browser. + return !getHtmlElem(".tab-button[name='preferences']").hidden; +} + +function getPrivateBrowsingValue() { + return getHtmlElem("input[type='radio'][name='private-browsing']:checked") + .value; +} + +async function setPrivateBrowsingValue(value, id) { + let changePromise = new Promise(resolve => { + const listener = (type, { extensionId, added, removed }) => { + if (extensionId == id) { + // Let's make sure we received the right message + let { permissions } = value == "0" ? removed : added; + ok(permissions.includes("internal:privateBrowsingAllowed")); + Management.off("change-permissions", listener); + resolve(); + } + }; + Management.on("change-permissions", listener); + }); + let radio = getHtmlElem( + `input[type="radio"][name="private-browsing"][value="${value}"]` + ); + // NOTE: not using EventUtils.synthesizeMouseAtCenter here because it + // does make this test to fail intermittently in some jobs (e.g. TV jobs) + radio.click(); + // Let's make sure we wait until the change has peristed in the database + return changePromise; +} + +// Check whether the private browsing inputs are visible in the details view. +function checkIsModifiable(expected) { + if (expected) { + is_element_visible( + getHtmlElem(".addon-detail-row-private-browsing"), + "Private browsing should be visible" + ); + } else { + is_element_hidden( + getHtmlElem(".addon-detail-row-private-browsing"), + "Private browsing should be hidden" + ); + } + checkHelpRow(".addon-detail-row-private-browsing", expected); +} + +// Check whether the details view shows that private browsing is forcibly disallowed. +function checkIsDisallowed(expected) { + if (expected) { + is_element_visible( + getHtmlElem(".addon-detail-row-private-browsing-disallowed"), + "Private browsing should be disallowed" + ); + } else { + is_element_hidden( + getHtmlElem(".addon-detail-row-private-browsing-disallowed"), + "Private browsing should not be disallowed" + ); + } + checkHelpRow(".addon-detail-row-private-browsing-disallowed", expected); +} + +// Check whether the details view shows that private browsing is forcibly allowed. +function checkIsRequired(expected) { + if (expected) { + is_element_visible( + getHtmlElem(".addon-detail-row-private-browsing-required"), + "Private browsing should be required" + ); + } else { + is_element_hidden( + getHtmlElem(".addon-detail-row-private-browsing-required"), + "Private browsing should not be required" + ); + } + checkHelpRow(".addon-detail-row-private-browsing-required", expected); +} + +function checkHelpRow(selector, expected) { + let helpRow = getHtmlElem(`${selector} + .addon-detail-help-row`); + if (expected) { + is_element_visible(helpRow, `Help row should be shown: ${selector}`); + is_element_visible(helpRow.querySelector("a"), "Expected learn more link"); + } else { + is_element_hidden(helpRow, `Help row should be hidden: ${selector}`); + } +} + +async function hasPrivateAllowed(id) { + let perms = await ExtensionPermissions.get(id); + return perms.permissions.includes("internal:privateBrowsingAllowed"); +} + +add_task(async function test_badge_and_toggle_incognito() { + let addons = new Map([ + [ + "@test-default", + { + useAddonManager: "temporary", + manifest: { + browser_specific_settings: { + gecko: { id: "@test-default" }, + }, + }, + }, + ], + [ + "@test-override", + { + useAddonManager: "temporary", + manifest: { + browser_specific_settings: { + gecko: { id: "@test-override" }, + }, + }, + incognitoOverride: "spanning", + }, + ], + [ + "@test-override-permanent", + { + useAddonManager: "permanent", + manifest: { + browser_specific_settings: { + gecko: { id: "@test-override-permanent" }, + }, + }, + incognitoOverride: "spanning", + }, + ], + [ + "@test-not-allowed", + { + useAddonManager: "temporary", + manifest: { + browser_specific_settings: { + gecko: { id: "@test-not-allowed" }, + }, + incognito: "not_allowed", + }, + }, + ], + ]); + let extensions = []; + for (let definition of addons.values()) { + let extension = ExtensionTestUtils.loadExtension(definition); + extensions.push(extension); + await extension.startup(); + } + + gManagerWindow = await open_manager("addons://list/extension"); + let items = get_test_items(); + for (let [id, definition] of addons.entries()) { + ok(items[id], `${id} listed`); + let badge = getPrivateBrowsingBadge(items[id]); + if (definition.incognitoOverride == "spanning") { + is_element_visible(badge, `private browsing badge is visible`); + } else { + is_element_hidden(badge, `private browsing badge is hidden`); + } + } + await close_manager(gManagerWindow); + + for (let [id, definition] of addons.entries()) { + gManagerWindow = await open_manager( + "addons://detail/" + encodeURIComponent(id) + ); + ok(true, `==== ${id} detail opened`); + if (definition.manifest.incognito == "not_allowed") { + checkIsModifiable(false); + ok(!(await hasPrivateAllowed(id)), "Private browsing permission not set"); + checkIsDisallowed(true); + } else { + // This assumes PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS, we test other options in a later test in this file. + checkIsModifiable(true); + if (definition.incognitoOverride == "spanning") { + is(getPrivateBrowsingValue(), "1", "Private browsing should be on"); + ok(await hasPrivateAllowed(id), "Private browsing permission set"); + await setPrivateBrowsingValue("0", id); + is(getPrivateBrowsingValue(), "0", "Private browsing should be off"); + ok( + !(await hasPrivateAllowed(id)), + "Private browsing permission removed" + ); + } else { + is(getPrivateBrowsingValue(), "0", "Private browsing should be off"); + ok( + !(await hasPrivateAllowed(id)), + "Private browsing permission not set" + ); + await setPrivateBrowsingValue("1", id); + is(getPrivateBrowsingValue(), "1", "Private browsing should be on"); + ok(await hasPrivateAllowed(id), "Private browsing permission set"); + } + } + await close_manager(gManagerWindow); + } + + for (let extension of extensions) { + await extension.unload(); + } +}); + +add_task(async function test_addon_preferences_button() { + let addons = new Map([ + [ + "test-inline-options@mozilla.com", + { + useAddonManager: "temporary", + manifest: { + name: "Extension with inline options", + browser_specific_settings: { + gecko: { id: "test-inline-options@mozilla.com" }, + }, + options_ui: { page: "options.html", open_in_tab: false }, + }, + }, + ], + [ + "test-newtab-options@mozilla.com", + { + useAddonManager: "temporary", + manifest: { + name: "Extension with options page in a new tab", + browser_specific_settings: { + gecko: { id: "test-newtab-options@mozilla.com" }, + }, + options_ui: { page: "options.html", open_in_tab: true }, + }, + }, + ], + [ + "test-not-allowed@mozilla.com", + { + useAddonManager: "temporary", + manifest: { + name: "Extension not allowed in PB windows", + incognito: "not_allowed", + browser_specific_settings: { + gecko: { id: "test-not-allowed@mozilla.com" }, + }, + options_ui: { page: "options.html", open_in_tab: true }, + }, + }, + ], + ]); + + async function runTest(openInPrivateWin) { + const win = await BrowserTestUtils.openNewBrowserWindow({ + private: openInPrivateWin, + }); + + gManagerWindow = await open_manager( + "addons://list/extension", + undefined, + undefined, + undefined, + win + ); + + const checkPrefsVisibility = (id, hasInlinePrefs, expectVisible) => { + if (!hasInlinePrefs) { + const detailsPrefBtn = getPreferencesButtonAtDetailsView(); + is( + !detailsPrefBtn.hidden, + expectVisible, + `The ${id} prefs button in the addon details has the expected visibility` + ); + } else { + is( + isInlineOptionsVisible(), + expectVisible, + `The ${id} inline prefs in the addon details has the expected visibility` + ); + } + }; + + const setAddonPrivateBrowsingAccess = async (id, allowPrivateBrowsing) => { + const cardUpdatedPromise = BrowserTestUtils.waitForEvent( + getHtmlElem("addon-card"), + "update" + ); + is( + getPrivateBrowsingValue(), + allowPrivateBrowsing ? "0" : "1", + `Private browsing should be initially ${ + allowPrivateBrowsing ? "off" : "on" + }` + ); + + // Get the DOM element we want to click on (to allow or disallow the + // addon on private browsing windows). + await setPrivateBrowsingValue(allowPrivateBrowsing ? "1" : "0", id); + + info(`Waiting for details view of ${id} to be reloaded`); + await cardUpdatedPromise; + + is( + getPrivateBrowsingValue(), + allowPrivateBrowsing ? "1" : "0", + `Private browsing should be initially ${ + allowPrivateBrowsing ? "on" : "off" + }` + ); + + is( + await hasPrivateAllowed(id), + allowPrivateBrowsing, + `Private browsing permission ${ + allowPrivateBrowsing ? "added" : "removed" + }` + ); + let badge = getPrivateBrowsingBadge(getHtmlElem("addon-card")); + is( + !badge.hidden, + allowPrivateBrowsing, + `Expected private browsing badge at ${id}` + ); + }; + + const extensions = []; + for (const definition of addons.values()) { + const extension = ExtensionTestUtils.loadExtension(definition); + extensions.push(extension); + await extension.startup(); + } + + const items = get_test_items(); + + for (const id of addons.keys()) { + // Check the preferences button in the addon list page. + is( + getPreferencesButtonAtListView(items[id]).hidden, + openInPrivateWin, + `The ${id} prefs button in the addon list has the expected visibility` + ); + } + + for (const [id, definition] of addons.entries()) { + // Check the preferences button or inline frame in the addon + // details page. + info(`Opening addon details for ${id}`); + const hasInlinePrefs = !definition.manifest.options_ui.open_in_tab; + const onceViewChanged = wait_for_view_load(gManagerWindow, null, true); + gManagerWindow.loadView(`addons://detail/${encodeURIComponent(id)}`); + await onceViewChanged; + + checkPrefsVisibility(id, hasInlinePrefs, !openInPrivateWin); + + // While testing in a private window, also check that the preferences + // are going to be visible when we toggle the PB access for the addon. + if (openInPrivateWin && definition.manifest.incognito !== "not_allowed") { + await setAddonPrivateBrowsingAccess(id, true); + checkPrefsVisibility(id, hasInlinePrefs, true); + + await setAddonPrivateBrowsingAccess(id, false); + checkPrefsVisibility(id, hasInlinePrefs, false); + } + } + + for (const extension of extensions) { + await extension.unload(); + } + + await close_manager(gManagerWindow); + await BrowserTestUtils.closeWindow(win); + } + + // run tests in private and non-private windows. + await runTest(true); + await runTest(false); +}); + +add_task(async function test_addon_postinstall_incognito_hidden_checkbox() { + await SpecialPowers.pushPrefEnv({ + set: [["extensions.langpacks.signatures.required", false]], + }); + + const TEST_ADDONS = [ + { + manifest: { + name: "Extension incognito default opt-in", + browser_specific_settings: { + gecko: { id: "ext-incognito-default-opt-in@mozilla.com" }, + }, + }, + }, + { + manifest: { + name: "Extension incognito not_allowed", + browser_specific_settings: { + gecko: { id: "ext-incognito-not-allowed@mozilla.com" }, + }, + incognito: "not_allowed", + }, + }, + { + manifest: { + name: "Static Theme", + browser_specific_settings: { + gecko: { id: "static-theme@mozilla.com" }, + }, + theme: { + colors: { + frame: "#FFFFFF", + tab_background_text: "#000", + }, + }, + }, + }, + { + manifest: { + name: "Dictionary", + browser_specific_settings: { gecko: { id: "dictionary@mozilla.com" } }, + dictionaries: { + und: "dictionaries/und.dic", + }, + }, + files: { + "dictionaries/und.dic": "", + "dictionaries/und.aff": "", + }, + }, + { + manifest: { + name: "Langpack", + browser_specific_settings: { gecko: { id: "langpack@mozilla.com" } }, + langpack_id: "und", + languages: { + und: { + chrome_resources: { + global: "chrome/und/locale/und/global", + }, + version: "20190326174300", + }, + }, + }, + }, + ]; + + for (let definition of TEST_ADDONS) { + let { id } = definition.manifest.browser_specific_settings.gecko; + info( + `Testing incognito checkbox visibility on ${id} post install notification` + ); + + const xpi = AddonTestUtils.createTempWebExtensionFile(definition); + let install = await AddonManager.getInstallForFile(xpi); + + await Promise.all([ + waitAppMenuNotificationShown("addon-installed", id, true), + install.install().then(() => { + Services.obs.notifyObservers( + { + addon: install.addon, + target: gBrowser.selectedBrowser, + }, + "webextension-install-notify" + ); + }), + ]); + + const { addon } = install; + const { permissions } = addon; + const canChangePBAccess = Boolean( + permissions & AddonManager.PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS + ); + + if (id === "ext-incognito-default-opt-in@mozilla.com") { + ok( + canChangePBAccess, + `${id} should have the PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS permission` + ); + } else { + ok( + !canChangePBAccess, + `${id} should not have the PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS permission` + ); + } + + // This tests the visibility of various private detail rows. + gManagerWindow = await open_manager( + "addons://detail/" + encodeURIComponent(id) + ); + info(`addon ${id} detail opened`); + if (addon.type === "extension") { + checkIsModifiable(canChangePBAccess); + let required = addon.incognito === "spanning"; + checkIsRequired(!canChangePBAccess && required); + checkIsDisallowed(!canChangePBAccess && !required); + } else { + checkIsModifiable(false); + checkIsRequired(false); + checkIsDisallowed(false); + } + await close_manager(gManagerWindow); + + await addon.uninstall(); + } + + // It is not possible to create a privileged add-on and install it, so just + // simulate an installed privileged add-on and check the UI. + await test_incognito_of_privileged_addons(); +}); + +// Checks that the private browsing flag of privileged add-ons cannot be modified. +async function test_incognito_of_privileged_addons() { + // In mochitests it is not possible to create and install a privileged add-on + // or a system add-on, so create a mock provider that simulates privileged + // add-ons (which lack the PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS permission). + let provider = new MockProvider(); + provider.createAddons([ + { + name: "default incognito", + id: "default-incognito@mock", + incognito: "spanning", // This is the default. + // Anything without the PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS permission. + permissions: 0, + }, + { + name: "not_allowed incognito", + id: "not-allowed-incognito@mock", + incognito: "not_allowed", + // Anything without the PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS permission. + permissions: 0, + }, + ]); + + gManagerWindow = await open_manager( + "addons://detail/default-incognito%40mock" + ); + checkIsModifiable(false); + checkIsRequired(true); + checkIsDisallowed(false); + await close_manager(gManagerWindow); + + gManagerWindow = await open_manager( + "addons://detail/not-allowed-incognito%40mock" + ); + checkIsModifiable(false); + checkIsRequired(false); + checkIsDisallowed(true); + await close_manager(gManagerWindow); + + provider.unregister(); +} -- cgit v1.2.3