Backed out 2 changesets (bug 1959534, bug 1955990) for causing mochitests failures in browser_parsable_css.js. CLOSED TREE

Backed out changeset 079c38a59719 (bug 1959534)
Backed out changeset e14907364ca3 (bug 1955990)
This commit is contained in:
Stanca Serban
2025-04-16 19:58:33 +03:00
parent a243afdc60
commit 1f2023fad0
10 changed files with 80 additions and 905 deletions

View File

@@ -412,18 +412,27 @@ export var ExtensionsUI = {
shouldShowTechnicalAndInteractionCheckbox &&
!!strings.dataCollectionPermissions?.collectsTechnicalAndInteractionData;
// Retrieve the permissions only once when we need them for one or both
// checkboxes.
let permissions;
if (showIncognitoCheckbox || showTechnicalAndInteractionCheckbox) {
permissions = await lazy.ExtensionPermissions.get(addon.id);
}
const incognitoPermissionName = "internal:privateBrowsingAllowed";
let grantPrivateBrowsingAllowed = false;
if (showIncognitoCheckbox) {
let { permissions } = await lazy.ExtensionPermissions.get(addon.id);
grantPrivateBrowsingAllowed = permissions.includes(
grantPrivateBrowsingAllowed = permissions.permissions.includes(
incognitoPermissionName
);
}
const technicalAndInteractionDataName = "technicalAndInteraction";
// This is an opt-out setting.
let grantTechnicalAndInteractionDataCollection = true;
let grantTechnicalAndInteractionDataCollection = false;
if (showTechnicalAndInteractionCheckbox) {
grantTechnicalAndInteractionDataCollection =
permissions.data_collection.includes(technicalAndInteractionDataName);
}
// Wait for any pending prompts to complete before showing the next one.
let pending;

View File

@@ -29,10 +29,8 @@ html|*.addon-webext-perm-list {
/* Required data collection permission shouldn't have a list style. */
&.webext-perm-granted:not(.webext-data-collection-perm-granted) {
list-style-position: inside;
list-style-type: disc;
/* Align the list with the rest of the page, and use `list-style-position:
* outside` to keep long string correctly wrapped. */
margin-inline-start: 1em;
}
/* Add some space between the list of permissions and the data collection

View File

@@ -2647,36 +2647,36 @@ export class ExtensionData {
* Wether to include the full domains set in the returned
* results. Defaults to false.
*
* @typedef {object} PermissionStrings
* @property {Array<string>} msgs an array of localized strings describing
* required permissions
* @property {Record<string, string>} optionalPermissions a map of permission
* name to localized strings describing the permission
* @property {Record<string, string>} optionalOrigins a map of a host
* permission to localized strings describing the host permission, where
* appropriate. Currently only all url style permissions are included
* @property {string} text a localized string
* @property {string} listIntro a localized string that should be displayed
* before the list of permissions
* @property {{ msg?: string, collectsTechnicalAndInteractionData?: boolean }} dataCollectionPermissions
* an object containing information about data permissions to be displayed.
* It contains a message string, and whether the extension collects technical
* and interaction data, which needs to be handled differently
* @property {Record<string, string>} optionalDataCollectionPermissions a map
* of data collection permission names to localized strings
* @property {{ domainsSet: Set, msgIdIndex: number }=} fullDomainsList an
* object with a Set of the full domains list (with the property name
* "domainsSet") and the index of the corresponding message string (with the
* property name "msgIdIndex"). This property is expected to be set only if
* "options.fullDomainsList" is passed as true and the extension doesn't
* include allUrls origin permissions
* @returns {object} An object with properties containing localized strings
* for various elements of a permission dialog. The "header"
* property on this object is the notification header text
* and it has the string "<>" as a placeholder for the
* addon name.
*
* @returns {PermissionStrings} An object with properties containing
* localized strings for various elements of a
* permission dialog. The "header" property on
* this object is the notification header text
* and it has the string "<>" as a placeholder
* for the addon name.
* "object.msgs" is an array of localized strings
* describing required permissions
*
* "object.optionalPermissions" is a map of permission name
* to localized strings describing the permission.
*
* "object.optionalOrigins" is a map of a host permission
* to localized strings describing the host permission,
* where appropriate. Currently only all url style
* permissions are included.
*
* "object.fullDomainsList" is an object with a Set of the
* full domains list (with the property name "domainsSet")
* and the index of the corresponding message string (with
* the property name "msgIdIndex"). This property is
* expected to be set only if "options.fullDomainsList" is
* passed as true and the extension doesn't include
* allUrls origin permissions.
*
* "object.dataCollectionPermissions" is an object
* containing information about data permissions to be
* displayed. It contains a message string, and whether the
* extension collects technical and interaction data, which
* needs to be handled differently.
*/
static formatPermissionStrings(
{
@@ -2704,7 +2704,6 @@ export class ExtensionData {
text: "",
listIntro: "",
dataCollectionPermissions: {},
optionalDataCollectionPermissions: {},
};
// To keep the label & accesskey in sync for localizations,
@@ -2941,16 +2940,6 @@ export class ExtensionData {
result.optionalOrigins[ooKeys[i]] = res[i];
}
}
if (
lazy.dataCollectionPermissionsEnabled &&
optionalPermissions.data_collection?.length
) {
result.optionalDataCollectionPermissions =
this._formatOptionalDataCollectionPermissions(
optionalPermissions.data_collection
);
}
}
const hasDataCollectionOnly =
@@ -3104,34 +3093,6 @@ export class ExtensionData {
return dataCollectionPermissions;
}
/**
* @param {Array<string>} permissions A list of optional data collection
* permissions.
*
* @returns {Record<string, string>} A map of permission names to localized
* strings representing the optional data collection permissions.
*/
static _formatOptionalDataCollectionPermissions(permissions) {
const optionalDataCollectionPermissions = {};
const odcKeys = [];
const odcL10nIds = [];
for (let permission of permissions) {
const l10nId = lazy.permissionToL10nId(permission, /* short */ false);
odcKeys.push(permission);
odcL10nIds.push(l10nId);
}
if (odcKeys.length) {
const res = lazy.PERMISSION_L10N.formatValuesSync(odcL10nIds);
for (let i = 0; i < res.length; ++i) {
optionalDataCollectionPermissions[odcKeys[i]] = res[i];
}
}
return optionalDataCollectionPermissions;
}
}
const PROXIED_EVENTS = new Set([

View File

@@ -71,11 +71,3 @@ webext-perms-description-data-long-personallyIdentifyingInfo = Share personally
webext-perms-description-data-long-technicalAndInteraction = Share technical and interaction data with extension developer
webext-perms-description-data-long-websiteActivity = Share website activity with extension developer
webext-perms-description-data-long-websiteContent = Share website content with extension developer
## Headings for the Permissions tab in `about:addons`
addon-permissions-required-data-collection = Required data collection:
addon-permissions-optional-data-collection = Optional data collection:
# Name of the Permissions tab in `about:addons` when the data collection feature is enabled.
permissions-data-addon-button = Permissions and data

View File

@@ -692,15 +692,23 @@ addon-permissions-list > .addon-detail-row {
background-repeat: no-repeat;
word-break: break-all;
.addon-permissions-required &.permission-checked {
list-style-type: disc;
/* Align the list with the rest of the page, and use `list-style-position:
* outside` to keep long string correctly wrapped. */
margin-inline-start: 1em;
.addon-permissions-required & {
--checkmark-width: var(--size-item-small);
--checkmark-height: var(--size-item-small);
padding-inline-start: calc(var(--checkmark-width) + var(--space-small));
background-position: 0 center;
background-size: var(--checkmark-width) var(--checkmark-height);
/* using a list-style-image prevents aligning the image */
background-image: url("chrome://global/skin/icons/check.svg");
-moz-context-properties: fill;
fill: var(--green-60);
&:dir(rtl) {
background-position-x: right 0;
}
}
.addon-permissions-optional &,
.addon-data-collection-permissions-optional & {
.addon-permissions-optional & {
padding-inline-start: 0;
moz-toggle > moz-message-bar {
@@ -714,6 +722,11 @@ addon-permissions-list > .addon-detail-row {
.permission-header {
font-size: 1em;
/* Increase margin between the required and optional permissions lists. */
.addon-permissions-optional > & {
margin-top: var(--space-xlarge);
}
}
.tab-group {

View File

@@ -31,10 +31,6 @@
<link rel="localization" href="branding/brand.ftl" />
<link rel="localization" href="toolkit/about/aboutAddons.ftl" />
<link rel="localization" href="toolkit/global/extensionPermissions.ftl" />
<link
rel="localization"
href="locales-preview/dataCollectionPermissions.ftl"
/>
<link rel="localization" href="locales-preview/localModelManagement.ftl" />
<!-- Defer scripts so all the templates are loaded by the time they run. -->
@@ -325,7 +321,6 @@
</template>
<template name="addon-permissions-list">
<!-- Permissions -->
<div class="addon-permissions-required" hidden>
<h2
class="permission-header"
@@ -340,29 +335,11 @@
></h2>
<ul class="addon-permissions-list"></ul>
</div>
<!-- Data collection -->
<div class="addon-data-collection-permissions-required" hidden>
<h2
class="permission-header"
data-l10n-id="addon-permissions-required-data-collection"
></h2>
<ul class="addon-permissions-list"></ul>
</div>
<div class="addon-data-collection-permissions-optional" hidden>
<h2
class="permission-header"
data-l10n-id="addon-permissions-optional-data-collection"
></h2>
<ul class="addon-permissions-list"></ul>
</div>
<div
class="addon-detail-row addon-permissions-empty"
data-l10n-id="addon-permissions-empty2"
hidden
></div>
<div class="addon-detail-row">
<a
is="moz-support-link"

View File

@@ -43,12 +43,6 @@ XPCOMUtils.defineLazyPreferenceGetter(
"extensions.htmlaboutaddons.recommendations.enabled",
false
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"DATA_COLLECTION_PERMISSIONS_ENABLED",
"extensions.dataCollectionPermissions.enabled",
false
);
const PLUGIN_ICON_URL = "chrome://global/skin/icons/plugin.svg";
const EXTENSION_ICON_URL =
@@ -1924,7 +1918,7 @@ class AddonPermissionsList extends HTMLElement {
}
async render() {
let empty = { origins: [], permissions: [], data_collection: [] };
let empty = { origins: [], permissions: [] };
let requiredPerms = { ...(this.addon.userPermissions ?? empty) };
let optionalPerms = { ...(this.addon.optionalPermissions ?? empty) };
let grantedPerms = await ExtensionPermissions.get(this.addon.id);
@@ -1950,7 +1944,6 @@ class AddonPermissionsList extends HTMLElement {
let optionalEntries = [
...Object.entries(permissions.optionalPermissions),
...Object.entries(permissions.optionalOrigins),
...Object.entries(permissions.optionalDataCollectionPermissions),
];
this.textContent = "";
@@ -1960,7 +1953,8 @@ class AddonPermissionsList extends HTMLElement {
let section = frag.querySelector(".addon-permissions-required");
section.hidden = false;
let list = section.querySelector(".addon-permissions-list");
for (const msg of permissions.msgs) {
for (let msg of permissions.msgs) {
let item = document.createElement("li");
item.classList.add("permission-info", "permission-checked");
item.appendChild(document.createTextNode(msg));
@@ -1968,39 +1962,17 @@ class AddonPermissionsList extends HTMLElement {
}
}
if (permissions.dataCollectionPermissions?.msg) {
let section = frag.querySelector(
".addon-data-collection-permissions-required"
);
section.hidden = false;
let list = section.querySelector(".addon-permissions-list");
let item = document.createElement("li");
item.classList.add("permission-info", "permission-checked");
item.appendChild(
document.createTextNode(permissions.dataCollectionPermissions.msg)
);
list.appendChild(item);
}
if (optionalEntries.length) {
let section = frag.querySelector(".addon-permissions-optional");
section.hidden = false;
let list = section.querySelector(".addon-permissions-list");
let dataCollectionSection = frag.querySelector(
".addon-data-collection-permissions-optional"
);
let dataCollectionList = dataCollectionSection.querySelector(
".addon-permissions-list"
);
for (let id = 0; id < optionalEntries.length; id++) {
let [perm, msg] = optionalEntries[id];
let type = "permission";
if (permissions.optionalOrigins[perm]) {
type = "origin";
} else if (permissions.optionalDataCollectionPermissions[perm]) {
type = "data_collection";
}
let item = document.createElement("li");
item.classList.add("permission-info");
@@ -2012,8 +1984,7 @@ class AddonPermissionsList extends HTMLElement {
let checked =
grantedPerms.permissions.includes(perm) ||
grantedPerms.origins.includes(perm) ||
grantedPerms.data_collection.includes(perm);
grantedPerms.origins.includes(perm);
// If this is one of the "all sites" permissions
if (Extension.isAllSitesPermission(perm)) {
@@ -2023,6 +1994,7 @@ class AddonPermissionsList extends HTMLElement {
}
toggle.pressed = checked;
item.classList.toggle("permission-checked", checked);
toggle.setAttribute("permission-key", perm);
toggle.setAttribute("action", "toggle-permission");
@@ -2035,22 +2007,10 @@ class AddonPermissionsList extends HTMLElement {
toggle.append(mb);
}
item.appendChild(toggle);
if (type === "data_collection") {
dataCollectionSection.hidden = false;
dataCollectionList.appendChild(item);
} else {
section.hidden = false;
list.appendChild(item);
}
list.appendChild(item);
}
}
if (
!permissions.msgs.length &&
!optionalEntries.length &&
!permissions.dataCollectionPermissions?.msg
) {
if (!permissions.msgs.length && !optionalEntries.length) {
let row = frag.querySelector(".addon-permissions-empty");
row.hidden = false;
}
@@ -2217,12 +2177,6 @@ class AddonDetails extends HTMLElement {
});
}
// Override the deck button string when the feature is enabled, which isn't
// the case by default for now.
if (DATA_COLLECTION_PERMISSIONS_ENABLED) {
permsBtn.setAttribute("data-l10n-id", "permissions-data-addon-button");
}
// Hide the tab group if "details" is the only visible button.
let tabGroupButtons = this.tabGroup.querySelectorAll(".tab-button");
this.tabGroup.hidden = Array.from(tabGroupButtons).every(button => {
@@ -2528,8 +2482,6 @@ class AddonCard extends HTMLElement {
perms.permissions = [permission];
} else if (type === "origin") {
perms.origins = [permission];
} else if (type === "data_collection") {
perms.data_collection = [permission];
} else {
throw new Error("unknown permission type changed");
}
@@ -3094,6 +3046,7 @@ class AddonCard extends HTMLElement {
let target = document.querySelector(`[permission-key="${permission}"]`);
let checked = !data.removed;
if (target) {
target.closest("li").classList.toggle("permission-checked", checked);
target.pressed = checked;
}
}
@@ -3101,6 +3054,7 @@ class AddonCard extends HTMLElement {
// special-case for finding the all-sites target by attribute.
let target = document.querySelector("[permission-all-sites]");
let checked = await AddonCard.optionalAllSitesGranted(this.addon.id);
target.closest("li").classList.toggle("permission-checked", checked);
target.pressed = checked;
}
}

View File

@@ -14,20 +14,6 @@ const { PERMISSION_L10N, PERMISSION_L10N_ID_OVERRIDES } =
AddonTestUtils.initMochitest(this);
const assertVisibleSections = async (permsSection, expectedHeaders) => {
let headers = Array.from(permsSection.querySelectorAll(".permission-header"))
// Filter out hidden sections.
.filter(el => !el.parentNode.hidden)
.map(el => el.textContent);
Assert.deepEqual(
headers,
await Promise.all(
expectedHeaders.map(id => permsSection.ownerDocument.l10n.formatValue(id))
),
"Got expected headers"
);
};
async function background() {
browser.permissions.onAdded.addListener(perms => {
if (localStorage.getItem("listening")) {
@@ -252,9 +238,6 @@ async function runTest(options) {
card = getAddonCard(win, addonId);
let { deck, tabGroup } = card.details;
// Make sure the card is fully localized.
await win.document.l10n.translateFragment(card);
let permsBtn = tabGroup.querySelector('[name="permissions"]');
let permsShown = BrowserTestUtils.waitForEvent(deck, "view-changed");
permsBtn.click();
@@ -292,18 +275,6 @@ async function runTest(options) {
"There's a message when no permissions are shown"
);
}
// Check visible sections, making sure we don't show any unwanted one (e.g.
// data collection sections when it is turned off).
let expectedHeaders = [];
if (permissions.length) {
expectedHeaders.push("addon-permissions-required");
}
if (optional_permissions.length) {
expectedHeaders.push("addon-permissions-optional");
}
await assertVisibleSections(permsSection, expectedHeaders);
if (permissions.length) {
for (let name of permissions) {
// Check the permission-info class to make sure it's for a permission.
@@ -389,7 +360,7 @@ async function runTest(options) {
change = extension.awaitMessage("permission-removed");
}
let permissions = { permissions: [], origins: [], data_collection: [] };
let permissions = { permissions: [], origins: [] };
if (type == "origin") {
permissions.origins = [permission];
} else {
@@ -425,7 +396,7 @@ async function runTest(options) {
let change = waitForPermissionChange(otherId);
let perms = await ExtensionPermissions.get(otherId);
let existing = type == "origin" ? perms.origins : perms.permissions;
let permissions = { permissions: [], origins: [], data_collection: [] };
let permissions = { permissions: [], origins: [] };
if (type == "origin") {
permissions.origins = [permission];
} else {
@@ -1008,521 +979,3 @@ webext-perms-description-test-tabs = Custom description for the tabs permission
mockCleanup();
});
add_task(async function test_data_collection() {
await SpecialPowers.pushPrefEnv({
set: [["extensions.dataCollectionPermissions.enabled", true]],
});
const TEST_CASES = [
{
title: "no permissions",
data_collection_permissions: {},
async verifyUI(card) {
let permsSection = card.querySelector("addon-permissions-list");
await assertVisibleSections(permsSection, []);
let permission_rows = permsSection.querySelectorAll(".permission-info");
is(permission_rows.length, 0, "Expected 0 permission row");
let empty_row = permsSection.querySelector(".addon-permissions-empty");
ok(!empty_row.hidden, "Expected empty row to be visible");
},
},
{
title: "required data collection",
data_collection_permissions: {
required: ["healthInfo", "locationInfo"],
},
async verifyUI(card) {
let permsSection = card.querySelector("addon-permissions-list");
await assertVisibleSections(permsSection, [
"addon-permissions-required-data-collection",
]);
let permission_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-required .permission-info"
);
is(permission_rows.length, 1, "Expected 1 permission row");
is(
permission_rows[0].textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-data-some",
{
permissions: "health information, location",
}
),
"Expected localized permission string"
);
let empty_row = permsSection.querySelector(".addon-permissions-empty");
ok(empty_row.hidden, "Expected empty row to be hidden");
},
},
{
title: "explicit no data collection",
data_collection_permissions: {
required: ["none"],
},
async verifyUI(card) {
let permsSection = card.querySelector("addon-permissions-list");
await assertVisibleSections(permsSection, [
"addon-permissions-required-data-collection",
]);
let permission_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-required .permission-info"
);
is(permission_rows.length, 1, "Expected 1 permission row");
is(
permission_rows[0].textContent,
PERMISSION_L10N.formatValueSync("webext-perms-description-data-none"),
"Expected localized permission string"
);
let empty_row = permsSection.querySelector(".addon-permissions-empty");
ok(empty_row.hidden, "Expected empty row to be hidden");
},
},
{
title: "optional data collection",
data_collection_permissions: {
optional: ["technicalAndInteraction"],
},
async verifyUI(card) {
let permsSection = card.querySelector("addon-permissions-list");
await assertVisibleSections(permsSection, [
"addon-permissions-optional-data-collection",
]);
let permission_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-optional .permission-info"
);
is(permission_rows.length, 1, "Expected 1 permission row");
let toggle = permission_rows[0].querySelector("moz-toggle");
ok(toggle, "Expected a toggle element");
is(
toggle.labelEl.textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-data-long-technicalAndInteraction"
),
"Expected localized permission string"
);
let empty_row = permsSection.querySelector(".addon-permissions-empty");
ok(empty_row.hidden, "Expected empty row to be hidden");
},
},
{
title: "required and optional data collection",
data_collection_permissions: {
required: ["locationInfo"],
optional: ["technicalAndInteraction"],
},
async verifyUI(card) {
let permsSection = card.querySelector("addon-permissions-list");
await assertVisibleSections(permsSection, [
"addon-permissions-required-data-collection",
"addon-permissions-optional-data-collection",
]);
// required data collection
let required_data_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-required .permission-info"
);
is(required_data_rows.length, 1, "Expected 1 permission row");
is(
required_data_rows[0].textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-data-some",
{
permissions: "location",
}
),
"Expected localized permission string"
);
// optional data collection
let optional_data_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-optional .permission-info"
);
is(optional_data_rows.length, 1, "Expected 1 permission row");
let toggle = optional_data_rows[0].querySelector("moz-toggle");
ok(toggle, "Expected a toggle element");
is(
toggle.labelEl.textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-data-long-technicalAndInteraction"
),
"Expected localized permission string"
);
// empty
let empty_row = permsSection.querySelector(".addon-permissions-empty");
ok(empty_row.hidden, "Expected empty row to be hidden");
},
},
{
title: "required permissions, and data collection",
permissions: ["bookmarks"],
data_collection_permissions: {
required: ["none"],
optional: ["locationInfo", "technicalAndInteraction"],
},
async verifyUI(card) {
let permsSection = card.querySelector("addon-permissions-list");
await assertVisibleSections(permsSection, [
"addon-permissions-required",
"addon-permissions-required-data-collection",
"addon-permissions-optional-data-collection",
]);
// required permissions
let required_rows = permsSection.querySelectorAll(
".addon-permissions-required .permission-info"
);
is(required_rows.length, 1, "Expected 1 permission row");
is(
required_rows[0].textContent,
PERMISSION_L10N.formatValueSync("webext-perms-description-bookmarks"),
"Expected localized permission string"
);
// required data collection
let required_data_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-required .permission-info"
);
is(required_data_rows.length, 1, "Expected 1 permission row");
is(
required_data_rows[0].textContent,
PERMISSION_L10N.formatValueSync("webext-perms-description-data-none"),
"Expected localized permission string"
);
// optional data collection
let optional_data_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-optional .permission-info"
);
is(optional_data_rows.length, 2, "Expected 2 permission rows");
let toggle = optional_data_rows[0].querySelector("moz-toggle");
is(
toggle.labelEl.textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-data-long-locationInfo"
),
"Expected localized permission string"
);
toggle = optional_data_rows[1].querySelector("moz-toggle");
is(
toggle.labelEl.textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-data-long-technicalAndInteraction"
),
"Expected localized permission string"
);
},
},
{
title: "required permissions and required data collection",
permissions: ["bookmarks"],
data_collection_permissions: {
required: ["bookmarksInfo"],
},
async verifyUI(card) {
let permsSection = card.querySelector("addon-permissions-list");
await assertVisibleSections(permsSection, [
"addon-permissions-required",
"addon-permissions-required-data-collection",
]);
// required permissions
let required_rows = permsSection.querySelectorAll(
".addon-permissions-required .permission-info"
);
is(required_rows.length, 1, "Expected 1 permission row");
is(
required_rows[0].textContent,
PERMISSION_L10N.formatValueSync("webext-perms-description-bookmarks"),
"Expected localized permission string"
);
// required data collection
let required_data_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-required .permission-info"
);
is(required_data_rows.length, 1, "Expected 1 permission row");
is(
required_data_rows[0].textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-data-some",
{
permissions: "bookmarks",
}
),
"Expected localized permission string"
);
},
},
{
title: "required and optional permissions, and data collection",
permissions: ["bookmarks"],
optional_permissions: ["browsingData"],
data_collection_permissions: {
required: ["websiteActivity"],
optional: ["locationInfo", "technicalAndInteraction"],
},
async verifyUI(card) {
let permsSection = card.querySelector("addon-permissions-list");
await assertVisibleSections(permsSection, [
"addon-permissions-required",
"addon-permissions-optional",
"addon-permissions-required-data-collection",
"addon-permissions-optional-data-collection",
]);
// required permissions
let required_rows = permsSection.querySelectorAll(
".addon-permissions-required .permission-info"
);
is(required_rows.length, 1, "Expected 1 permission row");
is(
required_rows[0].textContent,
PERMISSION_L10N.formatValueSync("webext-perms-description-bookmarks"),
"Expected localized permission string"
);
// optional permissions
let optional_rows = permsSection.querySelectorAll(
".addon-permissions-optional .permission-info"
);
is(optional_rows.length, 1, "Expected 1 permission row");
let toggle = optional_rows[0].querySelector("moz-toggle");
is(
toggle.labelEl.textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-browsingData"
),
"Expected localized permission string"
);
// required data collection
let required_data_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-required .permission-info"
);
is(required_data_rows.length, 1, "Expected 1 permission row");
is(
required_data_rows[0].textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-data-some",
{
permissions: "website activity",
}
),
"Expected localized permission string"
);
// optional data collection
let optional_data_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-optional .permission-info"
);
is(optional_data_rows.length, 2, "Expected 2 permission rows");
toggle = optional_data_rows[0].querySelector("moz-toggle");
is(
toggle.labelEl.textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-data-long-locationInfo"
),
"Expected localized permission string"
);
toggle = optional_data_rows[1].querySelector("moz-toggle");
is(
toggle.labelEl.textContent,
PERMISSION_L10N.formatValueSync(
"webext-perms-description-data-long-technicalAndInteraction"
),
"Expected localized permission string"
);
},
async togglePerms(card, extension) {
let permsSection = card.querySelector("addon-permissions-list");
let optional_data_rows = permsSection.querySelectorAll(
".addon-data-collection-permissions-optional .permission-info"
);
let locationToggle = optional_data_rows[0].querySelector("moz-toggle");
let added = extension.awaitMessage("permission-added");
locationToggle.click();
let perms = await added;
Assert.deepEqual(
perms,
{
permissions: [],
origins: [],
data_collection: ["locationInfo"],
},
"Expected added permissions"
);
let removed = extension.awaitMessage("permission-removed");
locationToggle.click();
perms = await removed;
Assert.deepEqual(
perms,
{
permissions: [],
origins: [],
data_collection: ["locationInfo"],
},
"Expected removed permissions"
);
},
},
];
for (const {
title,
permissions,
optional_permissions,
data_collection_permissions,
verifyUI,
togglePerms,
} of TEST_CASES) {
info(title);
const id = `@${title.toLowerCase().replaceAll(/[^\w]+/g, "-")}`;
const extension = ExtensionTestUtils.loadExtension({
manifest: {
// Use the id as name so that we can more easily debug failures when
// that happens.
name: id,
permissions,
optional_permissions,
browser_specific_settings: {
gecko: {
id,
data_collection_permissions,
},
},
},
background,
useAddonManager: "permanent",
});
await extension.startup();
extension.sendMessage("init");
await extension.awaitMessage("ready");
let view = await loadInitialView("extension");
let addon = await AddonManager.getAddonByID(id);
let card = getAddonCard(view, addon.id);
let permsSection = card.querySelector("addon-permissions-list");
if (!permsSection) {
ok(!card.hasAttribute("expanded"), "The list card is not expanded");
let loaded = waitForViewLoad(view);
card.querySelector('[action="expand"]').click();
await loaded;
}
card = getAddonCard(view, addon.id);
let { tabGroup } = card.details;
let permsBtn = tabGroup.querySelector('[name="permissions"]');
is(
permsBtn.textContent,
PERMISSION_L10N.formatValueSync("permissions-data-addon-button"),
"Expected permissions and data tab"
);
await verifyUI(card);
if (togglePerms) {
await togglePerms(card, extension);
}
await closeView(view);
await extension.unload();
}
await SpecialPowers.popPrefEnv();
});
add_task(async function test_data_collection_and_disabled_extension() {
await SpecialPowers.pushPrefEnv({
set: [["extensions.dataCollectionPermissions.enabled", true]],
});
const extensionId = "@some-id";
const extension = ExtensionTestUtils.loadExtension({
manifest: {
browser_specific_settings: {
gecko: {
id: extensionId,
data_collection_permissions: {
optional: ["locationInfo", "healthInfo"],
},
},
},
},
useAddonManager: "permanent",
});
await extension.startup();
let addon = await AddonManager.getAddonByID(extensionId);
await addon.disable();
ok(addon.userDisabled, "addon is disabled");
let view = await loadInitialView("extension");
let card = getAddonCard(view, addon.id);
let permsSection = card.querySelector("addon-permissions-list");
if (!permsSection) {
ok(!card.hasAttribute("expanded"), "The list card is not expanded");
let loaded = waitForViewLoad(view);
card.querySelector('[action="expand"]').click();
await loaded;
}
card = getAddonCard(view, addon.id);
let optional_data_rows = card
.querySelector("addon-permissions-list")
.querySelectorAll(
".addon-data-collection-permissions-optional .permission-info"
);
let locationToggle = optional_data_rows[0].querySelector("moz-toggle");
let permissionChangePromise = waitForPermissionChange(extensionId);
locationToggle.click();
let perms = await permissionChangePromise;
Assert.deepEqual(
perms.added,
{
permissions: [],
origins: [],
data_collection: ["locationInfo"],
},
"Expected permission added"
);
permissionChangePromise = waitForPermissionChange(extensionId);
locationToggle.click();
perms = await permissionChangePromise;
Assert.deepEqual(
perms.removed,
{
permissions: [],
origins: [],
data_collection: ["locationInfo"],
},
"Expected permission removed"
);
// Now re-enable the add-on.
await addon.enable();
ok(!addon.userDisabled, "Expected add-on to no longer be disabled");
await closeView(view);
await extension.unload();
await SpecialPowers.popPrefEnv();
});

View File

@@ -6,7 +6,6 @@ const { AddonTestUtils } = ChromeUtils.importESModule(
ChromeUtils.defineESModuleGetters(this, {
PERMISSION_L10N: "resource://gre/modules/ExtensionPermissionMessages.sys.mjs",
ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.sys.mjs",
});
AddonTestUtils.initMochitest(this);
@@ -592,80 +591,3 @@ add_task(async function test_pending_update_with_no_prompted_permission() {
await SpecialPowers.popPrefEnv();
});
add_task(
async function test_pending_update_does_not_grant_technicalAndInteraction() {
await SpecialPowers.pushPrefEnv({
set: [["extensions.dataCollectionPermissions.enabled", true]],
});
const id = "@test-id";
const { extension } = createTestExtension({
id,
oldManifest: {
browser_specific_settings: {
gecko: {
id,
data_collection_permissions: {},
},
},
},
newManifest: {
permissions: ["bookmarks"],
browser_specific_settings: {
gecko: {
id,
data_collection_permissions: {
optional: ["technicalAndInteraction"],
},
},
},
},
});
await extension.startup();
await extension.awaitMessage("bgpage-ready");
const win = await loadInitialView("extension");
const dialogPromise = promisePopupNotificationShown(
"addon-webext-permissions"
);
win.checkForUpdates();
const popupContentEl = await dialogPromise;
// Confirm the update, and proceed.
const waitForManagementUpdate = new Promise(resolve => {
const { Management } = ChromeUtils.importESModule(
"resource://gre/modules/Extension.sys.mjs"
);
Management.once("update", resolve);
});
popupContentEl.button.click();
await promiseUpdateAvailable(extension);
await completePostponedUpdate({ id, win });
// Ensure that the bootstrap scope update method has been executed
// successfully and emitted the update Management event.
info("Wait for the Management update to be emitted");
await waitForManagementUpdate;
// This test verifies that we don't accidentally grant the
// "technicalAndInteraction" data collection permission on update because
// that's controlled by the `showTechnicalAndInteractionCheckbox` value in
// `ExtensionUI.showPermissionsPrompt()`.
const perms = await ExtensionPermissions.get(id);
Assert.deepEqual(
perms,
{
permissions: [],
origins: [],
data_collection: [],
},
"Expected no stored permission"
);
await closeView(win);
await extension.unload();
await SpecialPowers.popPrefEnv();
}
);

View File

@@ -14,7 +14,6 @@ const DEFAULT_THEME_ID = "default-theme@mozilla.org";
ChromeUtils.defineESModuleGetters(this, {
PERMISSION_L10N: "resource://gre/modules/ExtensionPermissionMessages.sys.mjs",
ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.sys.mjs",
});
AddonTestUtils.initMochitest(this);
@@ -850,11 +849,12 @@ add_task(async function testInstallDialogShowsDataCollectionPermissions() {
2,
"Expected two permission entries in the list"
);
let checkbox = popupContentEl.permsListEl.querySelector(
"li.webext-data-collection-perm-optional > checkbox"
Assert.ok(
popupContentEl.permsListEl.querySelector(
"li.webext-data-collection-perm-optional > checkbox"
),
"Expected technical and interaction checkbox"
);
Assert.ok(checkbox, "Expected technical and interaction checkbox");
Assert.ok(checkbox.checked, "Expected checkbox to be checked");
Assert.equal(
popupContentEl.permsListEl.firstChild.textContent,
PERMISSION_L10N.formatValueSync(
@@ -1101,107 +1101,3 @@ add_task(async function testInstallDialogShowsDataCollectionPermissions() {
await SpecialPowers.popPrefEnv();
});
add_task(async function testTechnicalAndInteractionData() {
await SpecialPowers.pushPrefEnv({
set: [["extensions.dataCollectionPermissions.enabled", true]],
});
const extensionId = "@test-id";
const extension = AddonTestUtils.createTempWebExtensionFile({
manifest: {
version: "1.0",
browser_specific_settings: {
gecko: {
id: extensionId,
data_collection_permissions: {
optional: ["technicalAndInteraction"],
},
},
},
},
});
let perms = await ExtensionPermissions.get(extensionId);
Assert.deepEqual(
perms,
{ permissions: [], origins: [], data_collection: [] },
"Expected no permissions"
);
await BrowserTestUtils.withNewTab("about:blank", async () => {
const dialogPromise = promisePopupNotificationShown(
"addon-webext-permissions"
);
gURLBar.value = extension.path;
gURLBar.focus();
EventUtils.synthesizeKey("KEY_Enter");
const popupContentEl = await dialogPromise;
// Install the add-on.
let notificationPromise = acceptAppMenuNotificationWhenShown(
"addon-installed",
extensionId
);
popupContentEl.button.click();
await notificationPromise;
perms = await ExtensionPermissions.get(extensionId);
Assert.deepEqual(
perms,
{
permissions: [],
origins: [],
data_collection: ["technicalAndInteraction"],
},
"Expected data collection permission"
);
const addon = await AddonManager.getAddonByID(extensionId);
Assert.ok(addon, "Expected add-on");
await addon.uninstall();
});
// Repeat but uncheck the checkbox this time.
await BrowserTestUtils.withNewTab("about:blank", async () => {
const dialogPromise = promisePopupNotificationShown(
"addon-webext-permissions"
);
gURLBar.value = extension.path;
gURLBar.focus();
EventUtils.synthesizeKey("KEY_Enter");
const popupContentEl = await dialogPromise;
const checkboxEl = popupContentEl.permsListEl.querySelector(
"li.webext-data-collection-perm-optional > checkbox"
);
checkboxEl.click();
// Install the add-on.
let notificationPromise = acceptAppMenuNotificationWhenShown(
"addon-installed",
extensionId
);
popupContentEl.button.click();
await notificationPromise;
perms = await ExtensionPermissions.get(extensionId);
Assert.deepEqual(
perms,
{
permissions: [],
origins: [],
data_collection: [],
},
"Expected no data collection permission"
);
const addon = await AddonManager.getAddonByID(extensionId);
Assert.ok(addon, "Expected add-on");
await addon.uninstall();
});
await SpecialPowers.popPrefEnv();
});