597 lines
18 KiB
JavaScript
597 lines
18 KiB
JavaScript
/* -*- 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);
|
|
|
|
const notificationId = definition.manifest.theme
|
|
? "theme-installed"
|
|
: "addon-installed";
|
|
|
|
await Promise.all([
|
|
waitAppMenuNotificationShown(notificationId, 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();
|
|
}
|