commit a5862a7e7064e721f95dad2a940bcb438f7fbc3f parent 133388e7c5fe390d411425a23743068d87eb816d Author: iulian moraru <imoraru@mozilla.com> Date: Wed, 3 Dec 2025 12:25:00 +0200 Revert "Bug 1999177 - Support cursor scroll in the composable toolbar r=android-reviewers,moyin" for causing linting failures on browser_ext_urlclassifier.js. This reverts commit ae35529fabc6a34d52d762358ce60907bdb9d0e1. Revert "Bug 1986320: apply code formatting via Lando" This reverts commit 768f3614fff260007f7de32a99bccd633e076523. Revert "Bug 1986320 - Implement an add-on block URL-Classifier feature - part 5 - Block top-level documents when loaded by add-ons, r=extension-reviewers,dimi,fluent-reviewers,robwu,bolsson,android-reviewers,android-l10n-reviewers,delphine,tcampbell" This reverts commit 5f2e690d2b8758ade8b2b4ce43fdd7e86a44f27d. Revert "Bug 1986320 - Implement an add-on block URL-Classifier feature - part 4 - Expose the URLClassifier addon feature to non-recommended addons only, r=zombie" This reverts commit 1e7b1753d4f32ed3f4ad7a523a41c455b672ce43. Revert "Bug 1986320 - Implement an add-on block URL-Classifier feature - part 3 - devtool support, r=devtools-reviewers,dimi,devtools-backward-compat-reviewers,bomsy" This reverts commit 928a253e9e58046a59d1a300a62f94f34da67a0b. Revert "Bug 1986320 - Implement an add-on block URL-Classifier feature - part 2 - telemetry, r=dimi,extension-reviewers,robwu" This reverts commit 2a13eb6ec3e803078f99cf8646a8df6ee0305704. Revert "Bug 1986320 - Implement an add-on block URL-Classifier feature - part 1, r=dimi,geckoview-reviewers,extension-reviewers,tcampbell,robwu" This reverts commit 1ef88130d9c3dc97cfee299c3069966e7d37f776. Diffstat:
50 files changed, 208 insertions(+), 1189 deletions(-)
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js @@ -1755,7 +1755,6 @@ pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true); pref("services.sync.prefs.sync.privacy.globalprivacycontrol.enabled", true); pref("services.sync.prefs.sync.privacy.sanitize.sanitizeOnShutdown", true); pref("services.sync.prefs.sync.privacy.trackingprotection.enabled", true); -pref("services.sync.prefs.sync.privacy.trackingprotection.harmfuladdon.enabled", true); pref("services.sync.prefs.sync.privacy.trackingprotection.cryptomining.enabled", true); pref("services.sync.prefs.sync.privacy.trackingprotection.fingerprinting.enabled", true); pref("services.sync.prefs.sync.privacy.trackingprotection.pbmode.enabled", true); @@ -2403,9 +2402,6 @@ pref("network.cookie.cookieBehavior", 5 /* BEHAVIOR_REJECT_TRACKER_AND_PARTITION // Enable Dynamic First-Party Isolation in the private browsing mode. pref("network.cookie.cookieBehavior.pbmode", 5 /* BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN */); -// Enable harmful addon URL blocking by default for all channels, only on desktop. -pref("privacy.trackingprotection.harmfuladdon.enabled", true); - // Enable fingerprinting blocking by default for all channels, only on desktop. pref("privacy.trackingprotection.fingerprinting.enabled", true); diff --git a/browser/base/content/blockedSite.js b/browser/base/content/blockedSite.js @@ -38,19 +38,6 @@ function getURL() { return url; } -function getAddonName() { - var url = document.documentURI; - var match = url.match(/&a=([^&]+)/); - - // match == null if not found; if so, return an empty string - // instead of what would turn out to be portions of the URI - if (!match) { - return ""; - } - - return decodeURIComponent(match[1]); -} - /** * Check whether this warning page is overridable or not, in which case * the "ignore the risk" suggestion in the error description @@ -85,7 +72,6 @@ function initPage() { deceptiveBlocked: "phishing", unwantedBlocked: "unwanted", harmfulBlocked: "harmful", - addonBlocked: "addon", }; const error = errorMap[getErrorCode()]; if (error === undefined) { @@ -122,25 +108,6 @@ function initPage() { innerDescNoOverride: "safeb-blocked-harmful-page-error-desc-no-override", learnMore: "safeb-blocked-harmful-page-learn-more", }, - addon: { - title: "safeb-blocked-addon-page-title", - shortDesc: "safeb-blocked-addon-page-short-desc", - innerDescOverride: [ - "safeb-blocked-addon-page-error-desc-override", - "safeb-blocked-addon-page-error-desc2-override", - "", - "safeb-blocked-addon-page-error-desc3-override", - "safeb-blocked-addon-page-error-desc4-override", - ], - innerDescNoOverride: [ - "safeb-blocked-addon-page-error-desc-override", - "safeb-blocked-addon-page-error-desc2-override", - "", - "safeb-blocked-addon-page-error-desc3-override", - "safeb-blocked-addon-page-error-desc4-override", - ], - learnMore: "safeb-blocked-addon-page-learn-more", - }, }; // Set page contents depending on type of blocked page @@ -159,35 +126,14 @@ function initPage() { } else { innerDescL10nID = messageIDs[error].innerDescOverride; } - if (error == "unwanted" || error == "harmful" || error == "addon") { + if (error == "unwanted" || error == "harmful") { document.getElementById("report_detection").remove(); } - const descArgs = { - sitename: getHostString(), - addonName: getAddonName(), - }; - // Add the inner description: - if (Array.isArray(innerDescL10nID)) { - const template = innerDesc.cloneNode(true); - - while (innerDesc.firstChild) { - innerDesc.firstChild.remove(); - } - - for (const id of innerDescL10nID) { - if (id === "") { - innerDesc.appendChild(document.createElement("br")); - } - - const node = template.cloneNode(true); - document.l10n.setAttributes(node, id, descArgs); - innerDesc.appendChild(node); - } - } else { - document.l10n.setAttributes(innerDesc, innerDescL10nID, descArgs); - } + document.l10n.setAttributes(innerDesc, innerDescL10nID, { + sitename: getHostString(), + }); // Add the learn more content: let learnMore = document.getElementById("learn_more"); diff --git a/browser/components/enterprisepolicies/Policies.sys.mjs b/browser/components/enterprisepolicies/Policies.sys.mjs @@ -1313,13 +1313,6 @@ export var Policies = { param.Locked ); } - if ("HarmfulAddon" in param) { - PoliciesUtils.setDefaultPref( - "privacy.trackingprotection.harmfuladdon.enabled", - param.HarmfulAddon, - param.Locked - ); - } if ("Fingerprinting" in param) { PoliciesUtils.setDefaultPref( "privacy.trackingprotection.fingerprinting.enabled", diff --git a/browser/locales/en-US/browser/safebrowsing/blockedSite.ftl b/browser/locales/en-US/browser/safebrowsing/blockedSite.ftl @@ -6,12 +6,10 @@ safeb-blocked-phishing-page-title = Deceptive site ahead safeb-blocked-malware-page-title = Visiting this website may harm your computer safeb-blocked-unwanted-page-title = The site ahead may contain harmful programs safeb-blocked-harmful-page-title = The site ahead may contain malware -safeb-blocked-addon-page-title = Site blocked for your safety safeb-blocked-phishing-page-short-desc = { -brand-short-name } blocked this page because it may trick you into doing something dangerous like installing software or revealing personal information like passwords or credit cards. safeb-blocked-malware-page-short-desc = { -brand-short-name } blocked this page because it might attempt to install malicious software that may steal or delete personal information on your computer. safeb-blocked-unwanted-page-short-desc = { -brand-short-name } blocked this page because it might try to trick you into installing programs that harm your browsing experience (for example, by changing your homepage or showing extra ads on sites you visit). safeb-blocked-harmful-page-short-desc = { -brand-short-name } blocked this page because it might try to install dangerous apps that steal or delete your information (for example, photos, passwords, messages and credit cards). -safeb-blocked-addon-page-short-desc = { -brand-short-name } blocked this page because one of your add-ons tried to open it. This site could be used to steal your info — like passwords or credit card numbers. # Variables: # $advisoryname (string) - Name of the advisory entity safeb-palm-advisory-desc = Advisory provided by <a data-l10n-name='advisory_provider'>{ $advisoryname }</a>. @@ -36,13 +34,3 @@ safeb-blocked-unwanted-page-learn-more = Learn more about harmful and unwanted s safeb-blocked-harmful-page-error-desc-override = <span data-l10n-name='sitename'>{ $sitename }</span> has been <a data-l10n-name='error_desc_link'>reported as containing a potentially harmful application</a>. You can <a data-l10n-name='ignore_warning_link'>ignore the risk</a> and go to this unsafe site. safeb-blocked-harmful-page-error-desc-no-override = <span data-l10n-name='sitename'>{ $sitename }</span> has been <a data-l10n-name='error_desc_link'>reported as containing a potentially harmful application</a>. safeb-blocked-harmful-page-learn-more = Learn more about { -brand-short-name }’s Phishing and Malware Protection at <a data-l10n-name='firefox_support'>support.mozilla.org</a>. - -## Variables: -## $addonName (string) - the name of the harmful add-on -## $sitename (string) - Domain name for the blocked page - -safeb-blocked-addon-page-error-desc-override = <strong>Why was this site blocked?</strong> -safeb-blocked-addon-page-error-desc2-override = <strong>{ $sitename }</strong> may be linked to deceptive and harmful activity. -safeb-blocked-addon-page-error-desc3-override = <strong>What can you do about it?</strong> -safeb-blocked-addon-page-error-desc4-override = To stop this from happening again, you can remove or disable <strong>{ $addonName }</strong> from about:addons. -safeb-blocked-addon-page-learn-more = <a data-l10n-name='firefox_support'>Learn more about { -brand-short-name }’s Phishing and Malware Protection</a>. diff --git a/browser/locales/en-US/chrome/overrides/appstrings.properties b/browser/locales/en-US/chrome/overrides/appstrings.properties @@ -38,7 +38,6 @@ malwareBlocked=The site at %S has been reported as an attack site and has been b harmfulBlocked=The site at %S has been reported as a potentially harmful site and has been blocked based on your security preferences. unwantedBlocked=The site at %S has been reported as serving unwanted software and has been blocked based on your security preferences. deceptiveBlocked=This web page at %S has been reported as a deceptive site and has been blocked based on your security preferences. -addonBlocked=Site blocked for your safety. cspBlocked=This page has a content security policy that prevents it from being loaded in this way. xfoBlocked=This page has an X-Frame-Options policy that prevents it from being loaded in this context. corruptedContentErrorv2=The site at %S has experienced a network protocol violation that cannot be repaired. diff --git a/devtools/client/locales/en-US/netmonitor.properties b/devtools/client/locales/en-US/netmonitor.properties @@ -262,11 +262,6 @@ networkMenu.blocked2=Blocked # %S is the extension name. networkMenu.blockedby=Blocked By %S -# LOCALIZATION NOTE (networkMenu.classifiedFor): This is a generic message for a -# URL that has been blocked by the URL-Classifier because loaded by an extension -# %S is the extension name. -networkMenu.addonBlocked=Harmful Add-on Blocked (%S) - # LOCALIZATION NOTE (networkMenu.blockedTooltip): This is a the text displayed # as a tooltip for the blocked icon in the request list networkMenu.blockedTooltip=Blocked diff --git a/devtools/client/netmonitor/src/components/request-list/RequestListColumnTransferredSize.js b/devtools/client/netmonitor/src/components/request-list/RequestListColumnTransferredSize.js @@ -30,7 +30,7 @@ const UPDATED_TRANSFERRED_PROPS = [ "isRacing", "fromServiceWorker", "blockedReason", - "extension", + "blockingExtension", ]; class RequestListColumnTransferredSize extends Component { @@ -51,7 +51,7 @@ class RequestListColumnTransferredSize extends Component { render() { const { blockedReason, - extension, + blockingExtension, fromCache, fromServiceWorker, status, @@ -61,7 +61,7 @@ class RequestListColumnTransferredSize extends Component { let text; if (blockedReason) { - text = getBlockedReasonString(blockedReason, extension); + text = getBlockedReasonString(blockedReason, blockingExtension); } else if (fromCache || status === "304") { text = SIZE_CACHED; } else if (fromServiceWorker) { diff --git a/devtools/client/netmonitor/src/components/request-list/RequestListItem.js b/devtools/client/netmonitor/src/components/request-list/RequestListItem.js @@ -174,7 +174,7 @@ const UPDATED_REQ_ITEM_PROPS = [ "isEventStream", "priority", "blockedReason", - "extension", + "blockingExtension", ]; const UPDATED_REQ_PROPS = [ diff --git a/devtools/client/netmonitor/src/constants.js b/devtools/client/netmonitor/src/constants.js @@ -238,7 +238,7 @@ const UPDATE_PROPS = [ "referrerPolicy", "priority", "blockedReason", - "extension", + "blockingExtension", "channelId", "waitingTime", "proxyHttpVersion", @@ -580,7 +580,6 @@ const BLOCKED_REASON_MESSAGES = { 2007: "Cryptomining", 2008: "Fingerprinting", 2009: "Socialtracking", - 2011: "Harmful Add-on Blocked", 3001: "Mixed Block", 4000: "CSP", 4001: "CSP No Data Protocol", diff --git a/devtools/client/netmonitor/src/utils/l10n.js b/devtools/client/netmonitor/src/utils/l10n.js @@ -16,34 +16,27 @@ const NET_STRINGS_URI = "devtools/client/locales/netmonitor.properties"; exports.L10N = new LocalizationHelper(NET_STRINGS_URI); -function getBlockedReasonString(blockedReason, extension) { - if (!blockedReason) { - return null; - } - - if (extension?.blocking) { - return exports.L10N.getFormatStr( - "networkMenu.addonBlocked", - extension.blocking - ); - } - - if (extension?.blocked) { +function getBlockedReasonString(blockedReason, blockingExtension) { + if (blockedReason && blockingExtension) { return exports.L10N.getFormatStr( "networkMenu.blockedby", - extension.blocked + blockingExtension ); } - // If we receive a platform error code, print it as-is - if (typeof blockedReason == "string" && blockedReason.startsWith("NS_")) { - return blockedReason; + if (blockedReason) { + // If we receive a platform error code, print it as-is + if (typeof blockedReason == "string" && blockedReason.startsWith("NS_")) { + return blockedReason; + } + + return ( + BLOCKED_REASON_MESSAGES[blockedReason] || + exports.L10N.getStr("networkMenu.blocked2") + ); } - return ( - BLOCKED_REASON_MESSAGES[blockedReason] || - exports.L10N.getStr("networkMenu.blocked2") - ); + return null; } exports.getBlockedReasonString = getBlockedReasonString; diff --git a/devtools/client/netmonitor/test/browser_net_block-extensions.js b/devtools/client/netmonitor/test/browser_net_block-extensions.js @@ -87,7 +87,7 @@ add_task(async function () { is( request.querySelector(".requests-list-transferred").innerText, - `Harmful Add-on Blocked (${extensionName})`, + `Blocked By ${extensionName}`, "The request shows the blocking extension name" ); diff --git a/devtools/client/webconsole/components/Output/message-types/NetworkEventMessage.js b/devtools/client/webconsole/components/Output/message-types/NetworkEventMessage.js @@ -89,7 +89,7 @@ function NetworkEventMessage({ isXHR, timeStamp, blockedReason, - extension, + blockingExtension, httpVersion, status, statusText, @@ -137,7 +137,7 @@ function NetworkEventMessage({ if (blockedReason) { statusInfo = dom.span( { className: "status-info" }, - getBlockedReasonString(blockedReason, extension) + getBlockedReasonString(blockedReason, blockingExtension) ); topLevelClasses.push("network-message-blocked"); } diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_stubs_network_event.js b/devtools/client/webconsole/test/browser/browser_webconsole_stubs_network_event.js @@ -196,7 +196,7 @@ function getOrderedResource(resource) { isThirdPartyTrackingResource: resource.isThirdPartyTrackingResource, referrerPolicy: resource.referrerPolicy, blockedReason: resource.blockedReason, - extension: resource.extension, + blockingExtension: resource.blockingExtension, channelId: resource.channelId, totalTime: resource.totalTime, securityState: resource.securityState, diff --git a/devtools/client/webconsole/test/node/fixtures/stubs/networkEvent.js b/devtools/client/webconsole/test/node/fixtures/stubs/networkEvent.js @@ -45,7 +45,6 @@ rawPackets.set(`GET request`, { "isThirdPartyTrackingResource": false, "referrerPolicy": "strict-origin-when-cross-origin", "blockedReason": 0, - "extension": {}, "totalTime": 2, "securityState": "secure", "isRacing": false @@ -78,7 +77,6 @@ rawPackets.set(`GET request update`, { "isThirdPartyTrackingResource": false, "referrerPolicy": "strict-origin-when-cross-origin", "blockedReason": 0, - "extension": {}, "totalTime": 3, "securityState": "secure", "isRacing": false @@ -118,7 +116,6 @@ rawPackets.set(`XHR GET request`, { "isThirdPartyTrackingResource": false, "referrerPolicy": "strict-origin-when-cross-origin", "blockedReason": 0, - "extension": {}, "totalTime": 1, "securityState": "insecure", "isRacing": false @@ -157,7 +154,6 @@ rawPackets.set(`XHR GET request update`, { "isThirdPartyTrackingResource": false, "referrerPolicy": "strict-origin-when-cross-origin", "blockedReason": 0, - "extension": {}, "totalTime": 1, "securityState": "insecure", "isRacing": false @@ -197,7 +193,6 @@ rawPackets.set(`XHR POST request`, { "isThirdPartyTrackingResource": false, "referrerPolicy": "strict-origin-when-cross-origin", "blockedReason": 0, - "extension": {}, "totalTime": 1, "securityState": "insecure", "isRacing": false @@ -236,7 +231,6 @@ rawPackets.set(`XHR POST request update`, { "isThirdPartyTrackingResource": false, "referrerPolicy": "strict-origin-when-cross-origin", "blockedReason": 0, - "extension": {}, "totalTime": 2, "securityState": "insecure", "isRacing": false diff --git a/devtools/server/actors/network-monitor/network-event-actor.js b/devtools/server/actors/network-monitor/network-event-actor.js @@ -63,7 +63,7 @@ function isFileChannel(channel) { * Object describing the network event or the configuration of the * network observer, and which cannot be easily inferred from the raw * channel. - * - extension: optional object with `blocking` or `blocked` extension IDs + * - blockingExtension: optional string * id of the blocking webextension if any * - blockedReason: optional number or string * - discardRequestBody: boolean @@ -223,7 +223,7 @@ class NetworkEventActor extends Actor { resourceId: this._channelId, resourceType: NETWORK_EVENT, blockedReason, - extension: networkEventOptions.extension, + blockingExtension: networkEventOptions.blockingExtension, browsingContextID, cause, // This is used specifically in the browser toolbox console to distinguish privileged @@ -658,7 +658,7 @@ class NetworkEventActor extends Actor { * * @param object */ - addResponseContentComplete({ blockedReason, extension }) { + addResponseContentComplete({ blockedReason, blockingExtension }) { // Ignore calls when this actor is already destroyed if (this.isDestroyed()) { return; @@ -668,7 +668,7 @@ class NetworkEventActor extends Actor { lazy.NetworkUtils.NETWORK_EVENT_TYPES.RESPONSE_CONTENT_COMPLETE, { blockedReason, - extension, + blockingExtension, } ); } @@ -679,9 +679,7 @@ class NetworkEventActor extends Actor { * @param object content * The response content. */ - addResponseContent(content, data) { - const { blockedReason, extension } = data || {}; - + addResponseContent(content) { // Ignore calls when this actor is already destroyed if (this.isDestroyed()) { return; @@ -694,8 +692,6 @@ class NetworkEventActor extends Actor { mimeType: content.mimeType, contentSize: content.size, transferredSize: content.transferredSize, - blockedReason, - extension, } ); } diff --git a/devtools/server/actors/resources/network-events.js b/devtools/server/actors/resources/network-events.js @@ -385,7 +385,7 @@ class NetworkEventWatcher { resourceUpdates.mimeType = updateResource.mimeType; break; case NETWORK_EVENT_TYPES.RESPONSE_CONTENT_COMPLETE: - resourceUpdates.extension = updateResource.extension; + resourceUpdates.blockingExtension = updateResource.blockingExtension; resourceUpdates.blockedReason = updateResource.blockedReason; break; case NETWORK_EVENT_TYPES.EVENT_TIMINGS: diff --git a/devtools/shared/network-observer/NetworkObserver.sys.mjs b/devtools/shared/network-observer/NetworkObserver.sys.mjs @@ -443,13 +443,11 @@ export class NetworkObserver { }); } else { // Handles any early blockings e.g by Web Extensions or by CORS - const { extension, blockedReason } = lazy.NetworkUtils.getBlockedReason( - channel, - httpActivity.fromCache - ); + const { blockingExtension, blockedReason } = + lazy.NetworkUtils.getBlockedReason(channel, httpActivity.fromCache); this.#createNetworkEvent(httpActivity, { blockedReason, - extension, + blockingExtension, }); } } @@ -931,7 +929,7 @@ export class NetworkObserver { */ #createNetworkEvent( httpActivity, - { timestamp, blockedReason, extension, inProgressRequest } = {} + { timestamp, blockedReason, blockingExtension, inProgressRequest } = {} ) { if ( blockedReason === undefined && @@ -947,7 +945,7 @@ export class NetworkObserver { { timestamp, blockedReason, - extension, + blockingExtension, discardRequestBody: !this.#saveRequestAndResponseBodies, discardResponseBody: !this.#saveRequestAndResponseBodies, }, diff --git a/devtools/shared/network-observer/NetworkResponseListener.sys.mjs b/devtools/shared/network-observer/NetworkResponseListener.sys.mjs @@ -636,14 +636,15 @@ export class NetworkResponseListener { #getResponseContentComplete() { // Check any errors or blocking scenarios which happen late in the cycle // e.g If a host is not found (NS_ERROR_UNKNOWN_HOST) or CORS blocking. - const { extension, blockedReason } = lazy.NetworkUtils.getBlockedReason( - this.#httpActivity.channel, - this.#httpActivity.fromCache - ); + const { blockingExtension, blockedReason } = + lazy.NetworkUtils.getBlockedReason( + this.#httpActivity.channel, + this.#httpActivity.fromCache + ); this.#httpActivity.owner.addResponseContentComplete({ blockedReason, - extension, + blockingExtension, discardResponseBody: this.#httpActivity.discardResponseBody, truncated: this.#truncated, }); diff --git a/devtools/shared/network-observer/NetworkUtils.sys.mjs b/devtools/shared/network-observer/NetworkUtils.sys.mjs @@ -614,8 +614,7 @@ function matchRequest(channel, filters) { } function getBlockedReason(channel, fromCache = false) { - let blockedReason; - const extension = {}; + let blockingExtension, blockedReason; const { status } = channel; try { @@ -623,27 +622,15 @@ function getBlockedReason(channel, fromCache = false) { const properties = request.QueryInterface(Ci.nsIPropertyBag); blockedReason = request.loadInfo.requestBlockingReason; - extension.blocking = properties.getProperty("cancelledByExtension"); + blockingExtension = properties.getProperty("cancelledByExtension"); // WebExtensionPolicy is not available for workers if (typeof WebExtensionPolicy !== "undefined") { - extension.blocking = WebExtensionPolicy.getByID(extension.blocking).name; + blockingExtension = WebExtensionPolicy.getByID(blockingExtension).name; } } catch (err) { // "cancelledByExtension" doesn't have to be available. } - - if ( - blockedReason === Ci.nsILoadInfo.BLOCKING_REASON_CLASSIFY_HARMFULADDON_URI - ) { - try { - const properties = channel.QueryInterface(Ci.nsIPropertyBag); - extension.blocked = properties.getProperty("blockedExtension"); - } catch (err) { - // "blockedExtension" doesn't have to be available. - } - } - // These are platform errors which are not exposed to the users, // usually the requests (with these errors) might be displayed with various // other status codes. @@ -679,7 +666,7 @@ function getBlockedReason(channel, fromCache = false) { blockedReason = ChromeUtils.getXPCOMErrorName(status); } - return { extension, blockedReason }; + return { blockingExtension, blockedReason }; } function getCharset(channel) { diff --git a/devtools/shared/specs/network-event.js b/devtools/shared/specs/network-event.js @@ -152,7 +152,7 @@ const networkEventSpec = generateActorSpec({ encoding: Option(1, "string"), transferredSize: Option(1, "number"), blockedReason: Option(1, "number"), - extension: Option(1, "json"), + blockingExtension: Option(1, "string"), }, "network-event-update:event-timings": { diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp @@ -3565,7 +3565,6 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, } else if (NS_ERROR_PHISHING_URI == aError || NS_ERROR_MALWARE_URI == aError || NS_ERROR_UNWANTED_URI == aError || - NS_ERROR_HARMFULADDON_URI == aError || NS_ERROR_HARMFUL_URI == aError) { nsAutoCString host; aURI->GetHost(host); @@ -3588,8 +3587,6 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, error = "unwantedBlocked"; } else if (NS_ERROR_HARMFUL_URI == aError) { error = "harmfulBlocked"; - } else if (NS_ERROR_HARMFULADDON_URI == aError) { - error = "addonBlocked"; } cssClass.AssignLiteral("blacklist"); @@ -3930,18 +3927,6 @@ nsresult nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL, errorPageUrl.AppendLiteral("&d="); errorPageUrl.AppendASCII(escapedDescription.get()); - nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aFailedChannel)); - if (props) { - nsAutoCString addonName; - props->GetPropertyAsACString(u"blockedExtension"_ns, addonName); - - nsCString escapedAddonName; - SAFE_ESCAPE(escapedAddonName, addonName, url_Path); - - errorPageUrl.AppendLiteral("&a="); - errorPageUrl.AppendASCII(escapedAddonName.get()); - } - nsCOMPtr<nsIURI> errorPageURI; nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl); NS_ENSURE_SUCCESS(rv, rv); @@ -6359,7 +6344,6 @@ nsresult nsDocShell::FilterStatusForErrorPage( aStatus == NS_ERROR_PROXY_AUTHENTICATION_FAILED || aStatus == NS_ERROR_PROXY_TOO_MANY_REQUESTS || aStatus == NS_ERROR_MALFORMED_URI || - aStatus == NS_ERROR_HARMFULADDON_URI || aStatus == NS_ERROR_BLOCKED_BY_POLICY || aStatus == NS_ERROR_DOM_COOP_FAILED || aStatus == NS_ERROR_DOM_COEP_FAILED || diff --git a/dom/chrome-webidl/WebExtensionPolicy.webidl b/dom/chrome-webidl/WebExtensionPolicy.webidl @@ -126,12 +126,6 @@ interface WebExtensionPolicy { attribute boolean ignoreQuarantine; /** - * True if this extension has recommended state. - */ - [Cached, Pure] - readonly attribute boolean hasRecommendedState; - - /** * True if both e10s and webextensions.remote are enabled. This must be * used instead of checking the remote pref directly since remote extensions * require both to be enabled. @@ -330,8 +324,6 @@ dictionary WebExtensionInit { boolean ignoreQuarantine = false; - boolean hasRecommendedState = false; - boolean temporarilyInstalled = false; required WebExtensionLocalizeCallback localizeCallback; diff --git a/dom/locales/en-US/chrome/appstrings.properties b/dom/locales/en-US/chrome/appstrings.properties @@ -31,7 +31,6 @@ malwareBlocked=The site at %S has been reported as an attack site and has been b harmfulBlocked=The site at %S has been reported as a potentially harmful site and has been blocked based on your security preferences. unwantedBlocked=The site at %S has been reported as serving unwanted software and has been blocked based on your security preferences. deceptiveBlocked=This web page at %S has been reported as a deceptive site and has been blocked based on your security preferences. -addonBlocked=Site blocked for your safety. cspBlocked=This page has a content security policy that prevents it from being loaded in this way. xfoBlocked=This page has an X-Frame-Options policy that prevents it from being loaded in this context. corruptedContentErrorv2=The site at %S has experienced a network protocol violation that cannot be repaired. diff --git a/js/xpconnect/src/xpc.msg b/js/xpconnect/src/xpc.msg @@ -259,7 +259,6 @@ XPC_MSG_DEF(NS_ERROR_FINGERPRINTING_URI , "The URI is fingerprinti XPC_MSG_DEF(NS_ERROR_CRYPTOMINING_URI , "The URI is cryptomining") XPC_MSG_DEF(NS_ERROR_SOCIALTRACKING_URI , "The URI is social tracking") XPC_MSG_DEF(NS_ERROR_EMAILTRACKING_URI , "The URI is email tracking") -XPC_MSG_DEF(NS_ERROR_HARMFULADDON_URI , "The URI is not available for add-ons") /* Profile manager error codes */ XPC_MSG_DEF(NS_ERROR_DATABASE_CHANGED , "Flushing the profiles to disk would have overwritten changes made elsewhere.") diff --git a/mobile/android/android-components/components/browser/errorpages/src/main/java/mozilla/components/browser/errorpages/ErrorPages.kt b/mobile/android/android-components/components/browser/errorpages/src/main/java/mozilla/components/browser/errorpages/ErrorPages.kt @@ -240,10 +240,6 @@ enum class ErrorType( R.string.mozac_browser_errorpages_safe_phishing_uri_title, R.string.mozac_browser_errorpages_safe_phishing_uri_message, ), - NS_ERROR_HARMFULADDON_URI( - R.string.mozac_browser_errorpages_harmful_addon_uri_title, - R.string.mozac_browser_errorpages_harmful_addon_uri_message, - ), ERROR_HTTPS_ONLY( R.string.mozac_browser_errorpages_httpsonly_title, R.string.mozac_browser_errorpages_httpsonly_message, diff --git a/mobile/android/android-components/components/browser/errorpages/src/main/res/values/strings.xml b/mobile/android/android-components/components/browser/errorpages/src/main/res/values/strings.xml @@ -300,13 +300,6 @@ <p>This web page at %1$s has been reported as a deceptive site and has been blocked based on your security preferences.</p> ]]></string> - <!-- The document title and heading of an error page. --> - <string name="mozac_browser_errorpages_harmful_addon_uri_title">Site blocked for your safety</string> - <!-- The %1$s will be replaced by the malicious website URL--> - <string name="mozac_browser_errorpages_harmful_addon_uri_message"><![CDATA[ - <p>This web page at %1$s has been blocked because one of your add-ons tried to open it. This site could be used to steal your info — like passwords or credit card numbers.</p> - ]]></string> - <!-- The title of the error page for websites that do not support HTTPS when HTTPS-Only is turned on --> <string name="mozac_browser_errorpages_httpsonly_title">Secure Site Not Available</string> <!-- The text of the error page for websites that do not support HTTPS when HTTPS-Only is turned on. %1$s will be replaced with the URL of the website. --> diff --git a/mobile/android/android-components/components/compose/browser-toolbar/src/main/java/mozilla/components/compose/browser/toolbar/ui/InlineAutocompleteTextField.kt b/mobile/android/android-components/components/compose/browser-toolbar/src/main/java/mozilla/components/compose/browser/toolbar/ui/InlineAutocompleteTextField.kt @@ -17,29 +17,19 @@ import androidx.compose.foundation.gestures.awaitEachGesture import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.foundation.text.input.InputTransformation -import androidx.compose.foundation.text.input.OutputTransformation -import androidx.compose.foundation.text.input.TextFieldBuffer -import androidx.compose.foundation.text.input.TextFieldLineLimits -import androidx.compose.foundation.text.input.TextFieldState -import androidx.compose.foundation.text.input.rememberTextFieldState -import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue -import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -62,18 +52,23 @@ import androidx.compose.ui.platform.PlatformTextInputMethodRequest import androidx.compose.ui.platform.TextToolbar import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.toClipEntry +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.OffsetMapping +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.input.TransformedText +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.sp import androidx.core.graphics.toColorInt import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import mozilla.components.compose.base.theme.AcornTheme import mozilla.components.compose.browser.toolbar.concept.BrowserToolbarTestTags.ADDRESSBAR_SEARCH_BOX @@ -111,27 +106,50 @@ internal fun InlineAutocompleteTextField( onUrlEdit: (BrowserToolbarQuery) -> Unit = {}, onUrlCommitted: (String) -> Unit = {}, ) { - val textFieldState = rememberTextFieldState( - initialText = query, - initialSelection = when { - showQueryAsPreselected -> TextRange(0, query.length) - else -> TextRange(query.length) - }, - ) - var useSuggestion by remember { mutableStateOf(true) } - // Properties referenced in long lived lambdas - val currentSuggestion by rememberUpdatedState(suggestion) - val currentUseSuggestion by rememberUpdatedState(useSuggestion) + var textFieldValue by remember { mutableStateOf(TextFieldValue("")) } + LaunchedEffect(query) { + if (query != textFieldValue.text) { + textFieldValue = TextFieldValue( + text = query, + selection = when (showQueryAsPreselected) { + true -> TextRange(0, query.length) + false -> TextRange(query.length) + }, + ) + } + } val focusRequester = remember { FocusRequester() } val keyboardController = LocalSoftwareKeyboardController.current + LaunchedEffect(Unit) { + focusRequester.requestFocus() + } + var useSuggestion by remember { mutableStateOf(true) } val suggestionTextColor = MaterialTheme.colorScheme.onSurface val highlightBackgroundColor = Color(TEXT_HIGHLIGHT_COLOR.toColorInt()) + val suggestionVisualTransformation = remember(useSuggestion, suggestion, textFieldValue) { + when (textFieldValue.text.isEmpty() || !useSuggestion) { + true -> VisualTransformation.None + false -> AutocompleteVisualTransformation( + userInput = textFieldValue, + suggestion = suggestion, + textColor = suggestionTextColor, + textBackground = highlightBackgroundColor, + ) + } + } + + val localView = LocalView.current + LaunchedEffect(suggestion) { + suggestion?.text?.let { + @Suppress("DEPRECATION") + localView.announceForAccessibility(it) + } + } var suggestionBounds by remember { mutableStateOf<Rect?>(null) } val deviceLayoutDirection = LocalLayoutDirection.current - val scrollState = rememberScrollState() val context = LocalContext.current val defaultTextToolbar = LocalTextToolbar.current @@ -140,32 +158,6 @@ internal fun InlineAutocompleteTextField( val pasteInterceptorToolbar = remember(defaultTextToolbar, clipboard) { PasteSanitizerTextToolbar(context, defaultTextToolbar, clipboard, coroutineScope) } - DisposableEffect(Unit) { - onDispose { pasteInterceptorToolbar.hide() } - } - - LaunchedEffect(Unit) { - focusRequester.requestFocus() - } - - LaunchedEffect(query) { - if (query != textFieldState.text.toString()) { - textFieldState.edit { - replace(0, length, query) - selection = TextRange(query.length) - } - } - } - - val localView = LocalView.current - LaunchedEffect(suggestion) { - if (useSuggestion) { - suggestion?.text?.let { - @Suppress("DEPRECATION") - localView.announceForAccessibility(it) - } - } - } // Always want the text to be entered left to right. CompositionLocalProvider( @@ -186,7 +178,38 @@ internal fun InlineAutocompleteTextField( }, ) { BasicTextField( - state = textFieldState, + value = textFieldValue, + onValueChange = { newValue -> + // Remove suggestion if cursor placement changed + val onlySelectionChanged = textFieldValue.text == newValue.text && + textFieldValue.composition == newValue.composition && + textFieldValue.annotatedString == newValue.annotatedString + if (onlySelectionChanged) { + useSuggestion = false + textFieldValue = newValue + return@BasicTextField + } + + // Remove suggestion if user pressed backspace and + // only delete query characters for the next backspace after the suggestion was removed. + val originalText = textFieldValue.text + val newText = newValue.text + val isBackspaceHidingSuggestion = originalText.length == newText.length + 1 && + originalText.startsWith(newText) && + (useSuggestion && suggestion?.text?.startsWith(originalText) == true) + if (isBackspaceHidingSuggestion) { + useSuggestion = false + } else { + useSuggestion = true + onUrlEdit( + BrowserToolbarQuery( + previous = originalText, + current = newText, + ), + ) + textFieldValue = newValue + } + }, modifier = modifier .testTag(ADDRESSBAR_SEARCH_BOX) .fillMaxWidth() @@ -204,66 +227,80 @@ internal fun InlineAutocompleteTextField( LayoutDirection.Rtl -> TextAlign.End }, ), - lineLimits = TextFieldLineLimits.SingleLine, - scrollState = scrollState, keyboardOptions = KeyboardOptions( showKeyboardOnFocus = true, keyboardType = KeyboardType.Uri, imeAction = ImeAction.Go, autoCorrectEnabled = !usePrivateModeQueries, ), - onKeyboardAction = { - keyboardController?.hide() - val currentText = textFieldState.text.toString() - val finalUrl = if (useSuggestion && suggestion?.text?.startsWith(currentText) == true) { - suggestion.text - } else { - currentText - } - onUrlCommitted(finalUrl) - }, - inputTransformation = remember(onUrlEdit) { - AutocompleteInputTransformation( - suggestion = { currentSuggestion }, - shouldUseSuggestion = { currentUseSuggestion }, - onSuggestionVisibilityChangeRequest = { useSuggestion = it }, - onUrlEdit = onUrlEdit, - ) - }, - outputTransformation = remember(suggestionTextColor) { - AutocompleteOutputTransformation( - suggestion = { currentSuggestion }, - shouldUseSuggestion = { currentUseSuggestion }, - textColor = suggestionTextColor, - textBackground = highlightBackgroundColor, - ) - }, - cursorBrush = SolidColor(MaterialTheme.colorScheme.primary), + keyboardActions = KeyboardActions( + onGo = { + keyboardController?.hide() + val currentSuggestion = suggestion?.text + onUrlCommitted( + when (useSuggestion && currentSuggestion?.startsWith(textFieldValue.text) == true) { + true -> currentSuggestion + else -> textFieldValue.text + }, + ) + }, + ), + singleLine = true, + visualTransformation = suggestionVisualTransformation, onTextLayout = { layoutResult -> - val currentInput = textFieldState.text + val currentInput = textFieldValue.text suggestionBounds = when (currentInput.isEmpty()) { true -> null false -> try { - layoutResult()?.getBoundingBox(currentInput.length - 1) + layoutResult.getBoundingBox(currentInput.length - 1) } catch (_: IllegalArgumentException) { null } } }, - decorator = { innerTextField -> - AutocompleteDecorator( - hint = hint, - suggestion = when { - useSuggestion -> currentSuggestion - else -> null + cursorBrush = SolidColor(MaterialTheme.colorScheme.primary), + decorationBox = { innerTextField -> + Box( + modifier = Modifier + .fillMaxWidth() + // Commit the suggestion when users tap on the outside of the typed in text. + .pointerInput(suggestion, suggestionBounds) { + awaitEachGesture { + val downEvent = awaitFirstDown(requireUnconsumed = false) + val bounds = suggestionBounds + val suggestion = suggestion?.text + if (bounds != null && suggestion != null && + bounds.right < downEvent.position.x + ) { + onUrlEdit( + BrowserToolbarQuery( + previous = textFieldValue.text, + current = suggestion, + ), + ) + textFieldValue = TextFieldValue( + text = suggestion, + selection = TextRange(suggestion.length), + ) + } + } + }, + contentAlignment = when (deviceLayoutDirection) { + LayoutDirection.Ltr -> Alignment.CenterStart + LayoutDirection.Rtl -> Alignment.CenterEnd }, - onSuggestionVisibilityChangeRequest = { useSuggestion = it }, - suggestionBounds = suggestionBounds, - textFieldState = textFieldState, - onUrlEdit = onUrlEdit, - deviceLayoutDirection = deviceLayoutDirection, - innerTextField = innerTextField, - ) + ) { + if (textFieldValue.text.isEmpty()) { + Text( + text = hint, + style = TextStyle( + fontSize = TEXT_SIZE.sp, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ), + ) + } + innerTextField() + } }, ) } @@ -282,146 +319,44 @@ data class BrowserToolbarQuery( ) /** - * Helper for removing the suggestion or delete from the user query when backspace is pressed. - */ -@OptIn(ExperimentalFoundationApi::class) -private class AutocompleteInputTransformation( - private val suggestion: () -> AutocompleteResult?, - private val shouldUseSuggestion: () -> Boolean, - private val onSuggestionVisibilityChangeRequest: (Boolean) -> Unit, - private val onUrlEdit: (BrowserToolbarQuery) -> Unit, -) : InputTransformation { - override fun TextFieldBuffer.transformInput() { - val originalText = originalText.toString() - val newText = asCharSequence().toString() - val suggestion = suggestion()?.text - - val isBackspace = originalText.length > newText.length && originalText.startsWith(newText) - val isSuggestionVisible = shouldUseSuggestion() && - suggestion?.startsWith(originalText) == true && suggestion.length > originalText.length - val isCursorAtQueryEnd = originalSelection.collapsed && originalSelection.end == originalText.length - - if (isBackspace) { - onSuggestionVisibilityChangeRequest(false) - - val isBackspaceHidingSuggestion = isCursorAtQueryEnd && isSuggestionVisible - if (isBackspaceHidingSuggestion) { - // Avoid deleting text, just hide the suggestion. - revertAllChanges() - } else { - // Actually delete text and hide the suggestion. - onUrlEdit(BrowserToolbarQuery(previous = originalText, current = newText)) - } - } else { - if (originalText != newText) { - onSuggestionVisibilityChangeRequest(true) - onUrlEdit(BrowserToolbarQuery(previous = originalText, current = newText)) - } - } - } -} - -/** * Helper for showing the autocomplete suggestion inline with user's input. */ -@OptIn(ExperimentalFoundationApi::class) -private class AutocompleteOutputTransformation( - private val suggestion: () -> AutocompleteResult?, - private val shouldUseSuggestion: () -> Boolean, +private class AutocompleteVisualTransformation( + private val userInput: TextFieldValue, + private val suggestion: AutocompleteResult?, private val textColor: Color, private val textBackground: Color, -) : OutputTransformation { - override fun TextFieldBuffer.transformOutput() { - val userInput = asCharSequence() - val suggestion = suggestion() - if (!shouldUseSuggestion() || - suggestion?.text?.isEmpty() == true || - suggestion?.text?.startsWith(userInput) == false - ) { return } +) : VisualTransformation { + + override fun filter(text: AnnotatedString): TransformedText { + if (suggestion?.text.isNullOrEmpty() || !suggestion.text.startsWith(userInput.text)) { + return TransformedText(AnnotatedString(userInput.text), OffsetMapping.Identity) + } - val suffix = suggestion?.text?.removePrefix(userInput) ?: return - if (suffix.isNotEmpty()) { - val originalLength = length - append(suffix) - addStyle( - SpanStyle( - color = textColor, - background = textBackground, + val transformed = buildAnnotatedString { + append(userInput.text) + append( + AnnotatedString( + suggestion.text.removePrefix(userInput.text), + spanStyle = SpanStyle( + color = textColor, + background = textBackground, + ), ), - originalLength, - length, ) } - } -} -/** - * Helper for handling the text shown to the user: - * - show the current query or hint if query is empty. - * - dismisses the suggestion if cursor is placed in query. - * - commits the suggestion if cursor is placed in the suggestion or after it. - */ -@Composable -@Suppress("LongParameterList") -private fun AutocompleteDecorator( - hint: String, - suggestion: AutocompleteResult?, - onSuggestionVisibilityChangeRequest: (Boolean) -> Unit, - suggestionBounds: Rect?, - textFieldState: TextFieldState, - onUrlEdit: (BrowserToolbarQuery) -> Unit, - deviceLayoutDirection: LayoutDirection, - innerTextField: @Composable () -> Unit, -) { - // Stop using the suggestion if cursor is moved manually away from the end. - LaunchedEffect(textFieldState) { - snapshotFlow { textFieldState.selection } - .collectLatest { - if (it.end != textFieldState.text.length) { - onSuggestionVisibilityChangeRequest(false) - } + val offsetMapping = object : OffsetMapping { + override fun originalToTransformed(offset: Int): Int { + return offset } - } - Box( - modifier = Modifier - .fillMaxWidth() - // Commit the suggestion when users tap on the outside of the typed in text. - .pointerInput(suggestion, suggestionBounds) { - awaitEachGesture { - val downEvent = awaitFirstDown(requireUnconsumed = false) - val suggestionText = suggestion?.text - if (suggestionBounds != null && suggestionText != null && - suggestionBounds.right < downEvent.position.x - ) { - onUrlEdit( - BrowserToolbarQuery( - previous = textFieldState.text.toString(), - current = suggestionText, - ), - ) - textFieldState.edit { - replace(0, length, suggestionText) - selection = TextRange(suggestionText.length) - } - } - } - }, - contentAlignment = when (deviceLayoutDirection) { - LayoutDirection.Ltr -> Alignment.CenterStart - LayoutDirection.Rtl -> Alignment.CenterEnd - }, - ) { - if (textFieldState.text.isEmpty()) { - Text( - text = hint, - style = LocalTextStyle.current.merge( - fontSize = TEXT_SIZE.sp, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ), - ) + override fun transformedToOriginal(offset: Int): Int { + return offset.coerceIn(0, userInput.text.length) + } } - innerTextField() + + return TransformedText(transformed, offsetMapping) } } diff --git a/mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/InlineAutocompleteTextFieldTest.kt b/mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/InlineAutocompleteTextFieldTest.kt @@ -111,34 +111,6 @@ class InlineAutocompleteTextFieldTest { } @Test - fun `GIVEN an autocomplete suggestion is shown WHEN tapping outside the query, THEN commit the autocomplete suggestion`() { - val onUrlEdit: (BrowserToolbarQuery) -> Unit = mock() - val suggestion = AutocompleteResult( - input = "w", - text = "wikipedia.org", - url = "https://wikipedia.org", - source = "test", - totalItems = 1, - ) - - composeTestRule.setContent { - InlineAutocompleteTextField( - query = "w", - hint = "", - suggestion = suggestion, - showQueryAsPreselected = false, - usePrivateModeQueries = false, - onUrlEdit = onUrlEdit, - ) - } - - // Tapping on the very right is to the outside of the current query. - composeTestRule.onNodeWithTag(ADDRESSBAR_SEARCH_BOX).performTouchInput { click(position = centerRight) } - - verify(onUrlEdit).invoke(BrowserToolbarQuery(previous = "w", current = "wikipedia.org")) - } - - @Test fun `GIVEN a query and suggestion are shown WHEN backspace is first pressed THEN only clear the suggestion`() { val onUrlEdit: (BrowserToolbarQuery) -> Unit = mock() val suggestion = AutocompleteResult( diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml @@ -16364,12 +16364,6 @@ value: true mirror: always -# Block harmful addon URLs. -- name: privacy.trackingprotection.harmfuladdon.enabled - type: bool - value: false - mirror: always - # Block 3rd party fingerprinting resources. - name: privacy.trackingprotection.fingerprinting.enabled type: bool diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js @@ -3311,8 +3311,6 @@ pref("urlclassifier.trackingAnnotationWhitelistTable", "moztest-trackwhite-simpl pref("urlclassifier.trackingTable", "moztest-track-simple,ads-track-digest256,social-track-digest256,analytics-track-digest256"); pref("urlclassifier.trackingWhitelistTable", "moztest-trackwhite-simple,mozstd-trackwhite-digest256,google-trackwhite-digest256"); -pref("urlclassifier.features.harmfuladdon.blocklistTables", "harmfuladdon-block-digest256"); -pref("urlclassifier.features.harmfuladdon.entitylistTables", "harmfuladdon-entitylist-digest256"); pref("urlclassifier.features.fingerprinting.blacklistTables", "base-fingerprinting-track-digest256"); pref("urlclassifier.features.fingerprinting.whitelistTables", "mozstd-trackwhite-digest256,google-trackwhite-digest256"); pref("urlclassifier.features.fingerprinting.annotate.blacklistTables", "base-fingerprinting-track-digest256"); @@ -3430,7 +3428,7 @@ pref("browser.safebrowsing.reportPhishURL", "https://%LOCALE%.phish-report.mozil // Mozilla Safe Browsing provider (for tracking protection and plugin blocking) pref("browser.safebrowsing.provider.mozilla.pver", "2.2"); -pref("browser.safebrowsing.provider.mozilla.lists", "base-track-digest256,mozstd-trackwhite-digest256,google-trackwhite-digest256,content-track-digest256,mozplugin-block-digest256,mozplugin2-block-digest256,ads-track-digest256,social-track-digest256,analytics-track-digest256,base-fingerprinting-track-digest256,content-fingerprinting-track-digest256,base-cryptomining-track-digest256,content-cryptomining-track-digest256,fanboyannoyance-ads-digest256,fanboysocial-ads-digest256,easylist-ads-digest256,easyprivacy-ads-digest256,adguard-ads-digest256,social-tracking-protection-digest256,social-tracking-protection-facebook-digest256,social-tracking-protection-linkedin-digest256,social-tracking-protection-twitter-digest256,base-email-track-digest256,content-email-track-digest256,consent-manager-track-digest256,anti-fraud-track-digest256,harmfuladdon-block-digest256,harmfuladdon-entitylist-digest256"); +pref("browser.safebrowsing.provider.mozilla.lists", "base-track-digest256,mozstd-trackwhite-digest256,google-trackwhite-digest256,content-track-digest256,mozplugin-block-digest256,mozplugin2-block-digest256,ads-track-digest256,social-track-digest256,analytics-track-digest256,base-fingerprinting-track-digest256,content-fingerprinting-track-digest256,base-cryptomining-track-digest256,content-cryptomining-track-digest256,fanboyannoyance-ads-digest256,fanboysocial-ads-digest256,easylist-ads-digest256,easyprivacy-ads-digest256,adguard-ads-digest256,social-tracking-protection-digest256,social-tracking-protection-facebook-digest256,social-tracking-protection-linkedin-digest256,social-tracking-protection-twitter-digest256,base-email-track-digest256,content-email-track-digest256,consent-manager-track-digest256,anti-fraud-track-digest256"); pref("browser.safebrowsing.provider.mozilla.updateURL", "moz-sbrs:://antitracking"); pref("browser.safebrowsing.provider.mozilla.gethashURL", "https://shavar.services.mozilla.com/gethash?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2"); // Set to a date in the past to force immediate download in new profiles. diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl @@ -1538,7 +1538,6 @@ interface nsILoadInfo : nsISupports const uint32_t BLOCKING_REASON_CLASSIFY_FINGERPRINTING_URI = 2008; const uint32_t BLOCKING_REASON_CLASSIFY_SOCIALTRACKING_URI = 2009; const uint32_t BLOCKING_REASON_CLASSIFY_EMAILTRACKING_URI = 2010; - const uint32_t BLOCKING_REASON_CLASSIFY_HARMFULADDON_URI = 2011; const uint32_t BLOCKING_REASON_MIXED_BLOCKED = 3001; // The general reason comes from nsCSPContext::permitsInternal(), // which is way too generic to distinguish an exact reason. diff --git a/netwerk/metrics.yaml b/netwerk/metrics.yaml @@ -3105,27 +3105,3 @@ network: - kershaw@mozilla.com expires: never telemetry_mirror: h#REL_PRELOAD_MISS_RATIO - - urlclassifier_addon_block: - type: event - description: > - A classified network request initiated by a WebExtension was blocked by the - addon-protection feature. - bugs: - - https://bugzilla.mozilla.org/show_bug.cgi?id=1986320 - data_reviews: - - https://bugzilla.mozilla.org/show_bug.cgi?id=1986320 - notification_emails: - - amarchesini@mozilla.com - - addons-dev-internal@mozilla.com - expires: never - extra_keys: - addon_id: - description: The add-on ID - type: string - etld: - description: The eTLD+1 of the request URL - type: string - table: - description: Classifier table name(s) that matched - type: string diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp @@ -1198,7 +1198,6 @@ void HttpChannelChild::DoOnStopRequest(nsIRequest* aRequest, aChannelStatus == NS_ERROR_UNWANTED_URI || aChannelStatus == NS_ERROR_BLOCKED_URI || aChannelStatus == NS_ERROR_HARMFUL_URI || - aChannelStatus == NS_ERROR_HARMFULADDON_URI || aChannelStatus == NS_ERROR_PHISHING_URI) { nsCString list, provider, fullhash; diff --git a/netwerk/url-classifier/UrlClassifierCommon.cpp b/netwerk/url-classifier/UrlClassifierCommon.cpp @@ -139,10 +139,6 @@ nsresult UrlClassifierCommon::SetBlockedContent(nsIChannel* channel, NS_ENSURE_ARG(!aList.IsEmpty()); switch (aErrorCode) { - case NS_ERROR_HARMFULADDON_URI: - NS_SetRequestBlockingReason( - channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_HARMFULADDON_URI); - break; case NS_ERROR_MALWARE_URI: NS_SetRequestBlockingReason( channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_MALWARE_URI); diff --git a/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp b/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp @@ -15,7 +15,6 @@ #include "UrlClassifierFeatureEmailTrackingProtection.h" #include "UrlClassifierFeatureFingerprintingAnnotation.h" #include "UrlClassifierFeatureFingerprintingProtection.h" -#include "UrlClassifierFeatureHarmfulAddonProtection.h" #include "UrlClassifierFeaturePhishingProtection.h" #include "UrlClassifierFeatureSocialTrackingAnnotation.h" #include "UrlClassifierFeatureSocialTrackingProtection.h" @@ -49,7 +48,6 @@ void UrlClassifierFeatureFactory::Shutdown() { UrlClassifierFeatureSocialTrackingProtection::MaybeShutdown(); UrlClassifierFeatureTrackingAnnotation::MaybeShutdown(); UrlClassifierFeatureTrackingProtection::MaybeShutdown(); - UrlClassifierFeatureHarmfulAddonProtection::MaybeShutdown(); } /* static */ @@ -116,12 +114,6 @@ void UrlClassifierFeatureFactory::GetFeaturesFromChannel( aFeatures.AppendElement(feature); } - // Addon Protection - feature = UrlClassifierFeatureHarmfulAddonProtection::MaybeCreate(aChannel); - if (feature) { - aFeatures.AppendElement(feature); - } - // Tracking Protection feature = UrlClassifierFeatureTrackingProtection::MaybeCreate(aChannel); if (feature) { @@ -253,12 +245,6 @@ UrlClassifierFeatureFactory::GetFeatureByName(const nsACString& aName) { return feature.forget(); } - // Addon Protection - feature = UrlClassifierFeatureHarmfulAddonProtection::GetIfNameMatches(aName); - if (feature) { - return feature.forget(); - } - return nullptr; } @@ -342,12 +328,6 @@ void UrlClassifierFeatureFactory::GetFeatureNames(nsTArray<nsCString>& aArray) { aArray.AppendElement(name); } - // Addon Protection - name.Assign(UrlClassifierFeatureHarmfulAddonProtection::Name()); - if (!name.IsEmpty()) { - aArray.AppendElement(name); - } - // PhishingProtection features { nsTArray<nsCString> features; diff --git a/netwerk/url-classifier/UrlClassifierFeatureHarmfulAddonProtection.cpp b/netwerk/url-classifier/UrlClassifierFeatureHarmfulAddonProtection.cpp @@ -1,317 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/. */ - -#include "UrlClassifierFeatureHarmfulAddonProtection.h" - -#include "mozilla/AntiTrackingUtils.h" -#include "mozilla/extensions/WebExtensionPolicy.h" -#include "mozilla/glean/NetwerkMetrics.h" -#include "mozilla/net/UrlClassifierCommon.h" -#include "ChannelClassifierService.h" -#include "mozilla/StaticPrefs_privacy.h" -#include "nsNetUtil.h" -#include "mozilla/StaticPtr.h" -#include "nsIChannel.h" -#include "nsIEffectiveTLDService.h" -#include "nsIHttpChannelInternal.h" -#include "nsIWebProgressListener.h" -#include "nsIWritablePropertyBag2.h" - -namespace mozilla { -namespace net { - -namespace { - -#define HARMFULADDON_FEATURE_NAME "harmfuladdon-protection" - -#define URLCLASSIFIER_HARMFULADDON_BLOCKLIST \ - "urlclassifier.features.harmfuladdon.blocklistTables" -#define URLCLASSIFIER_HARMFULADDON_BLOCKLIST_TEST_ENTRIES \ - "urlclassifier.features.harmfuladdon.blocklistHosts" -#define URLCLASSIFIER_HARMFULADDON_ENTITYLIST \ - "urlclassifier.features.harmfuladdon.entitylistTables" -#define URLCLASSIFIER_HARMFULADDON_ENTITYLIST_TEST_ENTRIES \ - "urlclassifier.features.harmfuladdon.entitylistHosts" -#define URLCLASSIFIER_HARMFULADDON_EXCEPTION_URLS \ - "urlclassifier.features.harmfuladdon.skipURLs" -#define TABLE_HARMFULADDON_BLOCKLIST_PREF "harmfuladdon-blocklist-pref" -#define TABLE_HARMFULADDON_ENTITYLIST_PREF "harmfuladdon-entitylist-pref" - -StaticRefPtr<UrlClassifierFeatureHarmfulAddonProtection> - gFeatureHarmfulAddonProtection; - -extensions::WebExtensionPolicy* GetAddonPolicy(nsIChannel* aChannel) { - nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); - - nsCOMPtr<nsIPrincipal> triggeringPrincipal; - if (NS_FAILED(loadInfo->GetTriggeringPrincipal( - getter_AddRefs(triggeringPrincipal)))) { - return nullptr; - } - - nsCOMPtr<nsIPrincipal> loadingPrincipal; - if (NS_FAILED( - loadInfo->GetLoadingPrincipal(getter_AddRefs(loadingPrincipal)))) { - return nullptr; - } - - extensions::WebExtensionPolicy* policy = nullptr; - - if (triggeringPrincipal) { - policy = BasePrincipal::Cast(triggeringPrincipal)->AddonPolicy(); - - if (!policy) { - policy = - BasePrincipal::Cast(triggeringPrincipal)->ContentScriptAddonPolicy(); - } - } - - if (!policy && loadingPrincipal) { - policy = BasePrincipal::Cast(loadingPrincipal)->AddonPolicy(); - - if (!policy) { - policy = - BasePrincipal::Cast(loadingPrincipal)->ContentScriptAddonPolicy(); - } - } - - return policy; -} - -bool GetAddonId(nsIChannel* aChannel, nsACString& aAddonID) { - extensions::WebExtensionPolicy* policy = GetAddonPolicy(aChannel); - if (!policy) { - return false; - } - - CopyUTF16toUTF8(nsDependentAtomString(policy->Id()), aAddonID); - return true; -} - -bool GetAddonName(nsIChannel* aChannel, nsACString& aAddonName) { - extensions::WebExtensionPolicy* policy = GetAddonPolicy(aChannel); - if (!policy) { - return false; - } - - CopyUTF16toUTF8(policy->Name(), aAddonName); - return true; -} - -bool GetETLD(nsIChannel* aChannel, nsACString& aETLD) { - nsCOMPtr<nsIURI> uri; - nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); - if (NS_WARN_IF(NS_FAILED(rv)) || !uri) { - return false; - } - - nsCOMPtr<nsIEffectiveTLDService> etld( - do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID)); - if (NS_WARN_IF(!etld)) { - return false; - } - - rv = etld->GetBaseDomain(uri, 0, aETLD); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - - return !aETLD.IsEmpty(); -} - -void RecordGleanAddonBlocked(nsIChannel* aChannel, - const nsACString& aTableStr) { - nsAutoCString etld; - if (!GetETLD(aChannel, etld)) { - return; - } - - nsAutoCString addonId; - if (!GetAddonId(aChannel, addonId)) { - return; - } - - glean::network::urlclassifier_addon_block.Record( - Some(glean::network::UrlclassifierAddonBlockExtra{ - mozilla::Some(addonId), mozilla::Some(etld), - mozilla::Some(nsCString(aTableStr))})); -} - -} // namespace - -UrlClassifierFeatureHarmfulAddonProtection:: - UrlClassifierFeatureHarmfulAddonProtection() - : UrlClassifierFeatureAntiTrackingBase( - nsLiteralCString(HARMFULADDON_FEATURE_NAME), - nsLiteralCString(URLCLASSIFIER_HARMFULADDON_BLOCKLIST), - nsLiteralCString(URLCLASSIFIER_HARMFULADDON_ENTITYLIST), - nsLiteralCString(URLCLASSIFIER_HARMFULADDON_BLOCKLIST_TEST_ENTRIES), - nsLiteralCString(URLCLASSIFIER_HARMFULADDON_ENTITYLIST_TEST_ENTRIES), - nsLiteralCString(TABLE_HARMFULADDON_BLOCKLIST_PREF), - nsLiteralCString(TABLE_HARMFULADDON_ENTITYLIST_PREF), - nsLiteralCString(URLCLASSIFIER_HARMFULADDON_EXCEPTION_URLS)) {} - -/* static */ const char* UrlClassifierFeatureHarmfulAddonProtection::Name() { - return HARMFULADDON_FEATURE_NAME; -} - -/* static */ -void UrlClassifierFeatureHarmfulAddonProtection::MaybeInitialize() { - UC_LOG_LEAK(("UrlClassifierFeatureHarmfulAddonProtection::MaybeInitialize")); - - if (!gFeatureHarmfulAddonProtection) { - gFeatureHarmfulAddonProtection = - new UrlClassifierFeatureHarmfulAddonProtection(); - gFeatureHarmfulAddonProtection->InitializePreferences(); - } -} - -/* static */ -void UrlClassifierFeatureHarmfulAddonProtection::MaybeShutdown() { - UC_LOG_LEAK(("UrlClassifierFeatureHarmfulAddonProtection::MaybeShutdown")); - - if (gFeatureHarmfulAddonProtection) { - gFeatureHarmfulAddonProtection->ShutdownPreferences(); - gFeatureHarmfulAddonProtection = nullptr; - } -} - -/* static */ -already_AddRefed<UrlClassifierFeatureHarmfulAddonProtection> -UrlClassifierFeatureHarmfulAddonProtection::MaybeCreate(nsIChannel* aChannel) { - MOZ_ASSERT(aChannel); - - UC_LOG_LEAK( - ("UrlClassifierFeatureHarmfulAddonProtection::MaybeCreate - channel %p", - aChannel)); - - if (!StaticPrefs::privacy_trackingprotection_harmfuladdon_enabled()) { - return nullptr; - } - - RefPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); - nsIPrincipal* triggeringPrincipal = loadInfo->TriggeringPrincipal(); - bool addonTriggeringPrincipal = - triggeringPrincipal && - triggeringPrincipal->GetIsAddonOrExpandedAddonPrincipal(); - - nsIPrincipal* loadingPrincipal = loadInfo->GetLoadingPrincipal(); - bool addonLoadingPrincipal = - loadingPrincipal && - loadingPrincipal->GetIsAddonOrExpandedAddonPrincipal(); - - if (!addonTriggeringPrincipal && !addonLoadingPrincipal) { - return nullptr; - } - - // Recommended add-ons are exempt. - extensions::WebExtensionPolicy* policy = GetAddonPolicy(aChannel); - if (policy && policy->HasRecommendedState()) { - return nullptr; - } - - MaybeInitialize(); - MOZ_ASSERT(gFeatureHarmfulAddonProtection); - - RefPtr<UrlClassifierFeatureHarmfulAddonProtection> self = - gFeatureHarmfulAddonProtection; - return self.forget(); -} - -/* static */ -already_AddRefed<nsIUrlClassifierFeature> -UrlClassifierFeatureHarmfulAddonProtection::GetIfNameMatches( - const nsACString& aName) { - if (!aName.EqualsLiteral(HARMFULADDON_FEATURE_NAME)) { - return nullptr; - } - - MaybeInitialize(); - MOZ_ASSERT(gFeatureHarmfulAddonProtection); - - RefPtr<UrlClassifierFeatureHarmfulAddonProtection> self = - gFeatureHarmfulAddonProtection; - return self.forget(); -} - -NS_IMETHODIMP -UrlClassifierFeatureHarmfulAddonProtection::ProcessChannel( - nsIChannel* aChannel, const nsTArray<nsCString>& aList, - const nsTArray<nsCString>& aHashes, bool* aShouldContinue) { - NS_ENSURE_ARG_POINTER(aChannel); - NS_ENSURE_ARG_POINTER(aShouldContinue); - - bool isAllowListed = UrlClassifierCommon::IsAllowListed(aChannel); - - // This is a blocking feature. - *aShouldContinue = isAllowListed; - - if (isAllowListed) { - return NS_OK; - } - - bool ShouldProcessByProtectionFeature = - UrlClassifierCommon::ShouldProcessWithProtectionFeature(aChannel); - - *aShouldContinue = !ShouldProcessByProtectionFeature; - - if (!ShouldProcessByProtectionFeature) { - return NS_OK; - } - - nsAutoCString list; - UrlClassifierCommon::TablesToString(aList, list); - - ChannelBlockDecision decision = - ChannelClassifierService::OnBeforeBlockChannel(aChannel, mName, list); - if (decision != ChannelBlockDecision::Blocked) { - *aShouldContinue = true; - return NS_OK; - } - - RecordGleanAddonBlocked(aChannel, list); - - nsAutoCString addonName; - if (GetAddonName(aChannel, addonName)) { - nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel)); - if (props) { - props->SetPropertyAsACString(u"blockedExtension"_ns, addonName); - } - } - - UrlClassifierCommon::SetBlockedContent(aChannel, NS_ERROR_HARMFULADDON_URI, - list, ""_ns, ""_ns); - - UC_LOG( - ("UrlClassifierFeatureHarmfulAddonProtection::ProcessChannel - " - "cancelling channel %p", - aChannel)); - - (void)aChannel->Cancel(NS_ERROR_HARMFULADDON_URI); - return NS_OK; -} - -NS_IMETHODIMP -UrlClassifierFeatureHarmfulAddonProtection::GetURIByListType( - nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType, - nsIUrlClassifierFeature::URIType* aURIType, nsIURI** aURI) { - NS_ENSURE_ARG_POINTER(aChannel); - NS_ENSURE_ARG_POINTER(aURIType); - NS_ENSURE_ARG_POINTER(aURI); - - if (aListType == nsIUrlClassifierFeature::blocklist) { - *aURIType = nsIUrlClassifierFeature::blocklistURI; - return aChannel->GetURI(aURI); - } - - MOZ_ASSERT(aListType == nsIUrlClassifierFeature::entitylist); - - *aURIType = nsIUrlClassifierFeature::pairwiseEntitylistURI; - return aChannel->GetURI(aURI); -} - -} // namespace net -} // namespace mozilla diff --git a/netwerk/url-classifier/UrlClassifierFeatureHarmfulAddonProtection.h b/netwerk/url-classifier/UrlClassifierFeatureHarmfulAddonProtection.h @@ -1,49 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/. */ - -#ifndef mozilla_net_UrlClassifierFeatureHarmfulAddonProtection_h -#define mozilla_net_UrlClassifierFeatureHarmfulAddonProtection_h - -#include "UrlClassifierFeatureBase.h" - -class nsIChannel; - -namespace mozilla { -namespace net { - -class UrlClassifierFeatureHarmfulAddonProtection final - : public UrlClassifierFeatureAntiTrackingBase { - public: - static const char* Name(); - - static void MaybeShutdown(); - - static already_AddRefed<UrlClassifierFeatureHarmfulAddonProtection> - MaybeCreate(nsIChannel* aChannel); - - static already_AddRefed<nsIUrlClassifierFeature> GetIfNameMatches( - const nsACString& aName); - - NS_IMETHOD ProcessChannel(nsIChannel* aChannel, - const nsTArray<nsCString>& aList, - const nsTArray<nsCString>& aHashes, - bool* aShouldContinue) override; - - NS_IMETHOD GetURIByListType(nsIChannel* aChannel, - nsIUrlClassifierFeature::listType aListType, - nsIUrlClassifierFeature::URIType* aURIType, - nsIURI** aURI) override; - - private: - UrlClassifierFeatureHarmfulAddonProtection(); - - static void MaybeInitialize(); -}; - -} // namespace net -} // namespace mozilla - -#endif // mozilla_net_UrlClassifierFeatureHarmfulAddonProtection_h diff --git a/netwerk/url-classifier/moz.build b/netwerk/url-classifier/moz.build @@ -47,7 +47,6 @@ UNIFIED_SOURCES += [ "UrlClassifierFeatureFactory.cpp", "UrlClassifierFeatureFingerprintingAnnotation.cpp", "UrlClassifierFeatureFingerprintingProtection.cpp", - "UrlClassifierFeatureHarmfulAddonProtection.cpp", "UrlClassifierFeaturePhishingProtection.cpp", "UrlClassifierFeatureResult.cpp", "UrlClassifierFeatureSocialTrackingAnnotation.cpp", diff --git a/toolkit/components/extensions/Extension.sys.mjs b/toolkit/components/extensions/Extension.sys.mjs @@ -3469,8 +3469,6 @@ export class Extension extends ExtensionData { !!addonData.recommendationState?.states?.length || lazy.QuarantinedDomains.isUserAllowedAddonId(this.id); - this.hasRecommendedState = !!addonData.recommendationState?.states?.length; - this.views = new Set(); this._backgroundPageFrameLoader = null; @@ -3801,7 +3799,6 @@ export class Extension extends ExtensionData { optionalPermissions: this.optionalPermissions, isPrivileged: this.isPrivileged, ignoreQuarantine: this.ignoreQuarantine, - hasRecommendedState: this.hasRecommendedState, temporarilyInstalled: this.temporarilyInstalled, }; } @@ -4076,7 +4073,6 @@ export class Extension extends ExtensionData { baseURL: this.resourceURL, isPrivileged: this.isPrivileged, ignoreQuarantine: this.ignoreQuarantine, - hasRecommendedState: this.hasRecommendedState, temporarilyInstalled: this.temporarilyInstalled, allowedOrigins: new MatchPatternSet([]), localizeCallback: () => "", @@ -4093,7 +4089,6 @@ export class Extension extends ExtensionData { baseURL: this.resourceURL, isPrivileged: this.isPrivileged, ignoreQuarantine: this.ignoreQuarantine, - hasRecommendedState: this.hasRecommendedState, }); sharedData.set("extensions/pending", pendingExtensions); diff --git a/toolkit/components/extensions/ExtensionProcessScript.sys.mjs b/toolkit/components/extensions/ExtensionProcessScript.sys.mjs @@ -145,7 +145,6 @@ ExtensionManager = { isPrivileged: extension.isPrivileged, ignoreQuarantine: extension.ignoreQuarantine, - hasRecommendedState: extension.hasRecommendedState, temporarilyInstalled: extension.temporarilyInstalled, permissions: extension.permissions, allowedOrigins: extension.allowedOrigins, diff --git a/toolkit/components/extensions/WebExtensionPolicy.cpp b/toolkit/components/extensions/WebExtensionPolicy.cpp @@ -197,7 +197,6 @@ WebExtensionPolicyCore::WebExtensionPolicyCore(GlobalObject& aGlobal, mTemporarilyInstalled(aInit.mTemporarilyInstalled), mBackgroundWorkerScript(aInit.mBackgroundWorkerScript), mIgnoreQuarantine(aInit.mIsPrivileged || aInit.mIgnoreQuarantine), - mHasRecommendedState(aInit.mHasRecommendedState), mPermissions(new AtomSet(aInit.mPermissions)) { // In practice this is not necessary, but in tests where the uuid // passed in is not lowercased various tests can fail. @@ -469,10 +468,6 @@ void WebExtensionPolicy::SetIgnoreQuarantine(bool aIgnore) { mCore->SetIgnoreQuarantine(aIgnore); } -void WebExtensionPolicy::SetHasRecommendedState(bool aHasRecommendedState) { - mCore->SetHasRecommendedState(aHasRecommendedState); -} - void WebExtensionPolicy::RegisterContentScript( WebExtensionContentScript& script, ErrorResult& aRv) { // Raise an "invalid argument" error if the script is not related to diff --git a/toolkit/components/extensions/WebExtensionPolicy.h b/toolkit/components/extensions/WebExtensionPolicy.h @@ -144,16 +144,6 @@ class WebExtensionPolicyCore final { bool QuarantinedFromDoc(const DocInfo& aDoc) const; bool QuarantinedFromURI(const URLInfo& aURI) const MOZ_EXCLUDES(mLock); - bool HasRecommendedState() const MOZ_EXCLUDES(mLock) { - AutoReadLock lock(mLock); - return mHasRecommendedState; - } - - void SetHasRecommendedState(bool aHasRecommendedState) MOZ_EXCLUDES(mLock) { - AutoWriteLock lock(mLock); - mHasRecommendedState = aHasRecommendedState; - } - bool PrivateBrowsingAllowed() const; // Try to get a reference to the cycle-collected main-thread-only @@ -204,7 +194,6 @@ class WebExtensionPolicyCore final { mutable RWLock mLock{"WebExtensionPolicyCore"}; bool mIgnoreQuarantine MOZ_GUARDED_BY(mLock); - bool mHasRecommendedState MOZ_GUARDED_BY(mLock); RefPtr<AtomSet> mPermissions MOZ_GUARDED_BY(mLock); RefPtr<MatchPatternSetCore> mHostPermissions MOZ_GUARDED_BY(mLock); }; @@ -326,9 +315,6 @@ class WebExtensionPolicy final : public nsISupports, public nsWrapperCache { bool IgnoreQuarantine() const { return mCore->IgnoreQuarantine(); } void SetIgnoreQuarantine(bool aIgnore); - bool HasRecommendedState() const { return mCore->HasRecommendedState(); } - void SetHasRecommendedState(bool aHasRecommendedState); - void GetContentScripts(ScriptArray& aScripts) const; const ScriptArray& ContentScripts() const { return mContentScripts; } diff --git a/toolkit/components/extensions/test/browser/browser.toml b/toolkit/components/extensions/test/browser/browser.toml @@ -104,8 +104,6 @@ support-files = ["!/toolkit/components/thumbnails/test/head.js"] ["browser_ext_trial_ml.js"] support-files = [ "!/toolkit/components/ml/tests/browser/head.js"] -["browser_ext_urlclassifier.js"] - ["browser_ext_webNavigation_eventpage.js"] ["browser_ext_webRequest_redirect_mozextension.js"] diff --git a/toolkit/components/extensions/test/browser/browser_ext_urlclassifier.js b/toolkit/components/extensions/test/browser/browser_ext_urlclassifier.js @@ -1,107 +0,0 @@ -/* 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" -); - -AddonTestUtils.initMochitest(this); - -const server = AddonTestUtils.createHttpServer({ - hosts: ["expected.example.org", "extra.example.org"], -}); -server.registerPathHandler("/", (req, res) => { - info(`Test HTTP server for domain "${req.host}" got ${req.method} request\n`); - res.setStatusLine(req.httpVersion, 200, "OK"); - res.write("OK"); -}); - -add_task(async function test_extension_tab_create() { - Services.fog.testResetFOG(); - - await SpecialPowers.pushPrefEnv({ - set: [ - [ - "urlclassifier.features.harmfuladdon.blocklistHosts", - "expected.example.org", - ], - ], - }); - const id = "ext-create-tab@mochitest"; - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - browser_specific_settings: { - gecko: { id }, - }, - host_permissions: [ - "*://expected.example.org/*", - "*://extra.example.org/*", - ], - }, - background() { - const { browser } = this; - let tab; - browser.test.onMessage.addListener(async (msg, ...args) => { - if (msg === "create-tab") { - tab = await browser.tabs.create({ - url: "about:blank", - active: true, - }); - } else if (msg === "load-tab") { - await browser.tabs.update(tab.id, { url: args[0] }); - } else { - browser.test.fail(`Got unexpected test message ${msg}`); - } - browser.test.sendMessage(`${msg}:done`); - }); - }, - }); - - await extension.startup(); - - extension.sendMessage("create-tab"); - await extension.awaitMessage("create-tab:done"); - - const aboutBlockedLoaded = BrowserTestUtils.waitForContentEvent( - gBrowser.selectedTab.linkedBrowser, - "AboutBlockedLoaded", - true, - undefined, - true - ); - - extension.sendMessage("load-tab", "http://expected.example.org"); - await extension.awaitMessage("load-tab:done"); - - info("Wait for custom Glean ping submit"); - const gleanEvents = Glean.network.urlclassifierAddonBlock - .testGetValue() - ?.map(evt => evt.extra); - Assert.deepEqual( - gleanEvents, - [ - { - addon_id: id, - table: "harmfuladdon-blocklist-pref", - etld: "example.org", - }, - ], - "Got the expected Glean events" - ); - - await aboutBlockedLoaded; - - Services.fog.testResetFOG(); - - extension.sendMessage("load-tab", "http://extra.example.org"); - await extension.awaitMessage("load-tab:done"); - - const newGleanEvents = Glean.network.urlclassifierAddonBlock.testGetValue(); - Assert.deepEqual(newGleanEvents, null, "No glean event received"); - - await extension.unload(); - BrowserTestUtils.removeTab(gBrowser.selectedTab); -}); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_urlclassifier.js b/toolkit/components/extensions/test/xpcshell/test_ext_urlclassifier.js @@ -1,139 +0,0 @@ -/* 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"; - -add_setup(async () => { - do_get_profile(); - Services.fog.initializeFOG(); - - Services.prefs.setCharPref( - "urlclassifier.features.harmfuladdon.blocklistHosts", - "example.org" - ); - Services.prefs.setCharPref( - "urlclassifier.features.harmfuladdon.entitylistHosts", - "" - ); - Services.prefs.setCharPref( - "urlclassifier.features.harmfuladdon.skipURLs", - "" - ); - - registerCleanupFunction(() => { - Services.prefs.clearUserPref( - "urlclassifier.features.harmfuladdon.blocklistHosts" - ); - Services.prefs.clearUserPref( - "urlclassifier.features.harmfuladdon.entitylistHosts" - ); - Services.prefs.clearUserPref( - "urlclassifier.features.harmfuladdon.skipURLs" - ); - }); -}); - -const server = AddonTestUtils.createHttpServer({ - hosts: ["example.com", "example.org"], -}); - -server.registerPathHandler("/dummy", (request, response) => { - response.setStatusLine(request.httpVersion, 200, "OK"); - response.setHeader("Content-Type", "text/html", false); - response.write("<!DOCTYPE html><html></html>"); -}); - -server.registerPathHandler("/contentScript", (request, response) => { - response.setStatusLine(request.httpVersion, 200, "OK"); - response.setHeader("Content-Type", "text/html", false); - response.write("<h1>Content Script</h1>"); -}); - -server.registerPathHandler("/backgroundScript", (request, response) => { - response.setStatusLine(request.httpVersion, 200, "OK"); - response.setHeader("Content-Type", "text/html", false); - response.write("<h1>Background Script</h1>"); -}); - -add_task( - { pref_set: [["privacy.trackingprotection.harmfuladdon.enabled", true]] }, - async function test_addon_blocked_by_url_classifier() { - await runTest("backgroundScript_failed", "contentScript_failed", true); - } -); - -add_task( - { pref_set: [["privacy.trackingprotection.harmfuladdon.enabled", false]] }, - async function test_addon_blocked_by_url_classifier() { - await runTest("backgroundScript_loaded", "contentScript_loaded", false); - } -); - -async function runTest(message1, message2, expectGleanEvent) { - Services.fog.testResetFOG(); - - const extension = ExtensionTestUtils.loadExtension({ - manifest: { - host_permissions: ["http://example.org/"], - - content_scripts: [ - { - matches: ["http://example.com/*"], - run_at: "document_end", - js: ["contentscript.js"], - }, - ], - }, - - background: async () => { - try { - await fetch("http://example.org/backgroundScript").then(r => r.text()); - browser.test.sendMessage("backgroundScript_loaded"); - } catch (e) { - browser.test.sendMessage("backgroundScript_failed"); - } - }, - - files: { - "contentscript.js": async () => { - try { - await fetch("http://example.org/contentScript").then(r => r.text()); - browser.test.sendMessage("contentScript_loaded"); - } catch (e) { - browser.test.sendMessage("contentScript_failed"); - } - }, - }, - }); - - await extension.startup(); - - const contentPage = await ExtensionTestUtils.loadContentPage( - "http://example.com/dummy" - ); - - await extension.awaitMessage(message1); - await extension.awaitMessage(message2); - - if (expectGleanEvent) { - const events = Glean.network.urlclassifierAddonBlock.testGetValue(); - Assert.greater(events.length, 1, "We have received glean events"); - - let glean = events[0]; - Assert.greater(glean.extra.addon_id.length, 0); - Assert.equal(glean.extra.table, "harmfuladdon-blocklist-pref"); - Assert.equal(glean.extra.etld, "example.org"); - - glean = events[1]; - Assert.greater(glean.extra.addon_id.length, 0); - Assert.equal(glean.extra.table, "harmfuladdon-blocklist-pref"); - Assert.equal(glean.extra.etld, "example.org"); - } else { - const events = Glean.network.urlclassifierAddonBlock.testGetValue(); - Assert.equal(events, undefined, "We haven't received glean events"); - } - - await contentPage.close(); - await extension.unload(); -} diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.toml b/toolkit/components/extensions/test/xpcshell/xpcshell.toml @@ -140,8 +140,6 @@ skip-if = [ ["test_ext_unknown_permissions.js"] -["test_ext_urlclassifier.js"] - ["test_ext_webRequest_handlerBehaviorChanged.js"] ["test_ext_webRequest_urlclassification.js"] diff --git a/toolkit/components/url-classifier/SafeBrowsing.sys.mjs b/toolkit/components/url-classifier/SafeBrowsing.sys.mjs @@ -314,25 +314,6 @@ const FEATURES = [ ); }, }, - { - name: "harmfuladdon-protection", - list: [ - "urlclassifier.features.harmfuladdon.blocklistTables", - "urlclassifier.features.harmfuladdon.entitylistTables", - ], - enabled() { - return Services.prefs.getBoolPref( - "privacy.trackingprotection.harmfuladdon.enabled", - false - ); - }, - update() { - return Services.prefs.getBoolPref( - "browser.safebrowsing.features.harmfuladdon.update", - this.enabled() - ); - }, - }, ]; export var SafeBrowsing = { diff --git a/toolkit/modules/RemotePageAccessManager.sys.mjs b/toolkit/modules/RemotePageAccessManager.sys.mjs @@ -213,7 +213,6 @@ export let RemotePageAccessManager = { "browser.contentblocking.report.proxy.enabled", "privacy.trackingprotection.cryptomining.enabled", "privacy.trackingprotection.fingerprinting.enabled", - "privacy.trackingprotection.harmfuladdon.enabled", "privacy.trackingprotection.enabled", "privacy.trackingprotection.socialtracking.enabled", "browser.contentblocking.report.show_mobile_app", diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_recommendations.js b/toolkit/mozapps/extensions/test/xpcshell/test_recommendations.js @@ -700,21 +700,6 @@ add_task( extensionLine.awaitStartup(), ]); - Assert.equal( - WebExtensionPolicy.getByID(extensionInvalidRecommended.id) - .hasRecommendedState, - false - ); - Assert.equal( - WebExtensionPolicy.getByID(extensionValidRecommended.id) - .hasRecommendedState, - true - ); - Assert.equal( - WebExtensionPolicy.getByID(extensionLine.id).hasRecommendedState, - true - ); - // Uninstall all test extensions. await Promise.all( Object.keys(recommendationStatesPerId).map(async addonId => { diff --git a/xpcom/base/ErrorList.py b/xpcom/base/ErrorList.py @@ -953,7 +953,6 @@ with modules["URILOADER"]: errors["NS_ERROR_SOCIALTRACKING_URI"] = FAILURE(43) errors["NS_ERROR_EMAILTRACKING_URI"] = FAILURE(44) errors["NS_ERROR_RESTRICTED_CONTENT"] = FAILURE(45) - errors["NS_ERROR_HARMFULADDON_URI"] = FAILURE(46) # Used when "Save Link As..." doesn't see the headers quickly enough to # choose a filename. See nsContextMenu.js. errors["NS_ERROR_SAVE_LINK_AS_TIMEOUT"] = FAILURE(32)