зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1853013 - Merge in scripting API and es module webcompat addon updates; r=denschub,webcompat-reviewers,ksenia
Differential Revision: https://phabricator.services.mozilla.com/D188119
This commit is contained in:
Родитель
6dcd9db55e
Коммит
4f0043ae3b
|
@ -2,21 +2,14 @@
|
|||
* 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";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["AboutCompat"];
|
||||
|
||||
const Services =
|
||||
globalThis.Services ||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm").Services;
|
||||
|
||||
const addonID = "webcompat@mozilla.org";
|
||||
const addonPageRelativeURL = "/about-compat/aboutCompat.html";
|
||||
|
||||
function AboutCompat() {
|
||||
export function AboutCompat() {
|
||||
this.chromeURL =
|
||||
WebExtensionPolicy.getByID(addonID).getURL(addonPageRelativeURL);
|
||||
}
|
||||
|
||||
AboutCompat.prototype = {
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIAboutModule"]),
|
||||
getURIFlags() {
|
|
@ -4,11 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/* global ExtensionAPI, XPCOMUtils */
|
||||
|
||||
const Services =
|
||||
globalThis.Services ||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm").Services;
|
||||
/* global ExtensionAPI, XPCOMUtils, Services */
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
|
|
|
@ -19,8 +19,8 @@ if (!Cm.isCIDRegistered(classID)) {
|
|||
);
|
||||
|
||||
const factory = ComponentUtils.generateSingletonFactory(function () {
|
||||
const { AboutCompat } = ChromeUtils.import(
|
||||
"resource://webcompat/AboutCompat.jsm"
|
||||
const { AboutCompat } = ChromeUtils.importESModule(
|
||||
"resource://webcompat/AboutCompat.sys.mjs"
|
||||
);
|
||||
return new AboutCompat();
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ Classes = [
|
|||
{
|
||||
'cid': '{97bf9550-2a7b-11e9-b56e-0800200c9a66}',
|
||||
'contract_ids': ['@mozilla.org/network/protocol/about;1?what=compat'],
|
||||
'jsm': 'resource://webcompat/AboutCompat.jsm',
|
||||
'esModule': 'resource://webcompat/AboutCompat.sys.mjs',
|
||||
'constructor': 'AboutCompat',
|
||||
},
|
||||
]
|
||||
|
|
|
@ -589,7 +589,6 @@ const AVAILABLE_SHIMS = [
|
|||
],
|
||||
contentScripts: [
|
||||
{
|
||||
cookieStoreId: "firefox-private",
|
||||
js: "firebase.js",
|
||||
runAt: "document_start",
|
||||
matches: [
|
||||
|
|
|
@ -486,7 +486,7 @@ const AVAILABLE_UA_OVERRIDES = [
|
|||
domain: "granbluefantasy.jp",
|
||||
bug: "1722954",
|
||||
config: {
|
||||
matches: ["*://*.granbluefantasy.jp/*"],
|
||||
matches: ["*://*.granbluefantasy.jp/*", "*://*.gbf.game.mbga.jp/*"],
|
||||
uaTransformer: originalUA => {
|
||||
return originalUA + " iPhone OS 12_0 like Mac OS X";
|
||||
},
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/* global ExtensionAPI, ExtensionCommon, Services, XPCOMUtils */
|
||||
/* global ExtensionAPI, ExtensionCommon, Services */
|
||||
|
||||
this.aboutConfigPrefs = class extends ExtensionAPI {
|
||||
getAPI(context) {
|
||||
|
|
|
@ -49,6 +49,28 @@
|
|||
],
|
||||
"async": true
|
||||
},
|
||||
{
|
||||
"name": "getBoolPrefSync",
|
||||
"type": "function",
|
||||
"description": "Get a webcompat preference's boolean value synchronously",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string",
|
||||
"description": "The preference name"
|
||||
},
|
||||
{
|
||||
"name": "defaultValue",
|
||||
"type": "boolean",
|
||||
"optional": true,
|
||||
"description": "Default value to return if the pref is not set (defaults to false if omitted)"
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"type": "boolean",
|
||||
"description": "returns the value of a boolean pref."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "setPref",
|
||||
"type": "function",
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* 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";
|
||||
|
||||
/* global ExtensionAPI, Services, XPCOMUtils */
|
||||
|
||||
this.aboutConfigPrefs = class extends ExtensionAPI {
|
||||
getAPI(context) {
|
||||
const extensionIDBase = context.extension.id.split("@")[0];
|
||||
const extensionPrefNameBase = `extensions.${extensionIDBase}.`;
|
||||
|
||||
return {
|
||||
aboutConfigPrefs: {
|
||||
getBoolPrefSync(prefName, defaultValue = false) {
|
||||
try {
|
||||
return Services.prefs.getBoolPref(
|
||||
`${extensionPrefNameBase}${prefName}`,
|
||||
defaultValue
|
||||
);
|
||||
} catch (_) {
|
||||
return defaultValue;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
|
@ -13,8 +13,25 @@ class Injections {
|
|||
this._injectionsEnabled = true;
|
||||
|
||||
this._availableInjections = availableInjections;
|
||||
this._activeInjections = new Map();
|
||||
this._activeInjections = new Set();
|
||||
// Only used if this.shouldUseScriptingAPI is false and we are falling back
|
||||
// to use the contentScripts API.
|
||||
this._activeInjectionHandles = new Map();
|
||||
this._customFunctions = customFunctions;
|
||||
|
||||
this.shouldUseScriptingAPI =
|
||||
browser.aboutConfigPrefs.getBoolPrefSync("useScriptingAPI");
|
||||
// Debug log emit only on nightly (similarly to the debug
|
||||
// helper used in shims.js for similar purpose).
|
||||
browser.appConstants.getReleaseBranch().then(releaseBranch => {
|
||||
if (releaseBranch !== "release_or_beta") {
|
||||
console.debug(
|
||||
`WebCompat Injections will be injected using ${
|
||||
this.shouldUseScriptingAPI ? "scripting" : "contentScripts"
|
||||
} API`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bindAboutCompatBroker(broker) {
|
||||
|
@ -48,6 +65,33 @@ class Injections {
|
|||
return this._injectionsEnabled;
|
||||
}
|
||||
|
||||
async getPromiseRegisteredScriptIds(scriptIds) {
|
||||
let registeredScriptIds = [];
|
||||
|
||||
// Try to avoid re-registering scripts already registered
|
||||
// (e.g. if the webcompat background page is restarted
|
||||
// after an extension process crash, after having registered
|
||||
// the content scripts already once), but do not prevent
|
||||
// to try registering them again if the getRegisteredContentScripts
|
||||
// method returns an unexpected rejection.
|
||||
try {
|
||||
const registeredScripts =
|
||||
await browser.scripting.getRegisteredContentScripts({
|
||||
// By default only look for script ids that belongs to Injections
|
||||
// (and ignore the ones that may belong to Shims).
|
||||
ids: scriptIds ?? this._availableInjections.map(inj => inj.id),
|
||||
});
|
||||
registeredScriptIds = registeredScripts.map(script => script.id);
|
||||
} catch (ex) {
|
||||
console.error(
|
||||
"Retrieve WebCompat GoFaster registered content scripts failed: ",
|
||||
ex
|
||||
);
|
||||
}
|
||||
|
||||
return registeredScriptIds;
|
||||
}
|
||||
|
||||
async registerContentScripts() {
|
||||
const platformInfo = await browser.runtime.getPlatformInfo();
|
||||
const platformMatches = [
|
||||
|
@ -55,10 +99,15 @@ class Injections {
|
|||
platformInfo.os,
|
||||
platformInfo.os == "android" ? "android" : "desktop",
|
||||
];
|
||||
|
||||
let registeredScriptIds = this.shouldUseScriptingAPI
|
||||
? await this.getPromiseRegisteredScriptIds()
|
||||
: [];
|
||||
|
||||
for (const injection of this._availableInjections) {
|
||||
if (platformMatches.includes(injection.platform)) {
|
||||
injection.availableOnPlatform = true;
|
||||
await this.enableInjection(injection);
|
||||
await this.enableInjection(injection, registeredScriptIds);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,17 +119,42 @@ class Injections {
|
|||
});
|
||||
}
|
||||
|
||||
assignContentScriptDefaults(contentScripts) {
|
||||
buildContentScriptRegistrations(contentScripts) {
|
||||
let finalConfig = Object.assign({}, contentScripts);
|
||||
|
||||
if (!finalConfig.runAt) {
|
||||
finalConfig.runAt = "document_start";
|
||||
}
|
||||
|
||||
if (this.shouldUseScriptingAPI) {
|
||||
// Don't persist the content scripts across browser restarts
|
||||
// (at least not yet, we would need to apply some more changes
|
||||
// to adjust webcompat for accounting for the scripts to be
|
||||
// already registered).
|
||||
//
|
||||
// NOTE: scripting API has been introduced in Gecko 102,
|
||||
// prior to Gecko 105 persistAcrossSessions option was required
|
||||
// and only accepted false persistAcrossSessions, after Gecko 105
|
||||
// is optional and defaults to true.
|
||||
|
||||
finalConfig.persistAcrossSessions = false;
|
||||
|
||||
// Convert js/css from contentScripts.register API method
|
||||
// format to scripting.registerContentScripts API method
|
||||
// format.
|
||||
if (Array.isArray(finalConfig.js)) {
|
||||
finalConfig.js = finalConfig.js.map(e => e.file);
|
||||
}
|
||||
|
||||
if (Array.isArray(finalConfig.css)) {
|
||||
finalConfig.css = finalConfig.css.map(e => e.file);
|
||||
}
|
||||
}
|
||||
|
||||
return finalConfig;
|
||||
}
|
||||
|
||||
async enableInjection(injection) {
|
||||
async enableInjection(injection, registeredScriptIds) {
|
||||
if (injection.active) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -89,7 +163,7 @@ class Injections {
|
|||
return this.enableCustomInjection(injection);
|
||||
}
|
||||
|
||||
return this.enableContentScripts(injection);
|
||||
return this.enableContentScripts(injection, registeredScriptIds);
|
||||
}
|
||||
|
||||
enableCustomInjection(injection) {
|
||||
|
@ -103,16 +177,40 @@ class Injections {
|
|||
}
|
||||
}
|
||||
|
||||
async enableContentScripts(injection) {
|
||||
async enableContentScripts(injection, registeredScriptIds) {
|
||||
let injectProps;
|
||||
try {
|
||||
const handle = await browser.contentScripts.register(
|
||||
this.assignContentScriptDefaults(injection.contentScripts)
|
||||
);
|
||||
this._activeInjections.set(injection, handle);
|
||||
const { id } = injection;
|
||||
if (this.shouldUseScriptingAPI) {
|
||||
// enableContentScripts receives a registeredScriptIds already
|
||||
// pre-computed once from registerContentScripts to register all
|
||||
// the injection, whereas it does not expect to receive one when
|
||||
// it is called from the AboutCompatBroker to re-enable one specific
|
||||
// injection.
|
||||
let activeScriptIds = Array.isArray(registeredScriptIds)
|
||||
? registeredScriptIds
|
||||
: await this.getPromiseRegisteredScriptIds([id]);
|
||||
injectProps = this.buildContentScriptRegistrations(
|
||||
injection.contentScripts
|
||||
);
|
||||
injectProps.id = id;
|
||||
if (!activeScriptIds.includes(id)) {
|
||||
await browser.scripting.registerContentScripts([injectProps]);
|
||||
}
|
||||
this._activeInjections.add(id);
|
||||
} else {
|
||||
const handle = await browser.contentScripts.register(
|
||||
this.buildContentScriptRegistrations(injection.contentScripts)
|
||||
);
|
||||
this._activeInjections.add(id);
|
||||
this._activeInjectionHandles.set(id, handle);
|
||||
}
|
||||
|
||||
injection.active = true;
|
||||
} catch (ex) {
|
||||
console.error(
|
||||
"Registering WebCompat GoFaster content scripts failed: ",
|
||||
{ injection, injectProps },
|
||||
ex
|
||||
);
|
||||
}
|
||||
|
@ -155,9 +253,18 @@ class Injections {
|
|||
}
|
||||
|
||||
async disableContentScripts(injection) {
|
||||
const contentScript = this._activeInjections.get(injection);
|
||||
await contentScript.unregister();
|
||||
this._activeInjections.delete(injection);
|
||||
if (this._activeInjections.has(injection.id)) {
|
||||
if (this.shouldUseScriptingAPI) {
|
||||
await browser.scripting.unregisterContentScripts({
|
||||
ids: [injection.id],
|
||||
});
|
||||
} else {
|
||||
const handle = this._activeInjectionHandles.get(injection.id);
|
||||
await handle.unregister();
|
||||
this._activeInjectionHandles.delete(injection.id);
|
||||
}
|
||||
this._activeInjections.delete(injection);
|
||||
}
|
||||
injection.active = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,13 @@ class Shim {
|
|||
this.runFirst = opts.runFirst;
|
||||
this.unblocksOnOptIn = unblocksOnOptIn;
|
||||
this.requestStorageAccessForRedirect = opts.requestStorageAccessForRedirect;
|
||||
this.shouldUseScriptingAPI =
|
||||
browser.aboutConfigPrefs.getBoolPrefSync("useScriptingAPI");
|
||||
debug(
|
||||
`WebCompat Shim ${this.id} will be injected using ${
|
||||
this.shouldUseScriptingAPI ? "scripting" : "contentScripts"
|
||||
} API`
|
||||
);
|
||||
|
||||
this._hostOptIns = new Set();
|
||||
|
||||
|
@ -76,14 +83,26 @@ class Shim {
|
|||
|
||||
this.redirectsRequests = !!this.file && matches?.length;
|
||||
|
||||
// NOTE: _contentScriptRegistrations is an array of string ids when
|
||||
// shouldUseScriptingAPI is true and an array of script handles returned
|
||||
// by contentScripts.register otherwise.
|
||||
this._contentScriptRegistrations = [];
|
||||
|
||||
this.contentScripts = contentScripts || [];
|
||||
for (const script of this.contentScripts) {
|
||||
if (typeof script.css === "string") {
|
||||
script.css = [{ file: `/shims/${script.css}` }];
|
||||
script.css = [
|
||||
this.shouldUseScriptingAPI
|
||||
? `/shims/${script.css}`
|
||||
: { file: `/shims/${script.css}` },
|
||||
];
|
||||
}
|
||||
if (typeof script.js === "string") {
|
||||
script.js = [{ file: `/shims/${script.js}` }];
|
||||
script.js = [
|
||||
this.shouldUseScriptingAPI
|
||||
? `/shims/${script.js}`
|
||||
: { file: `/shims/${script.js}` },
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,10 +263,52 @@ class Shim {
|
|||
!this._contentScriptRegistrations.length
|
||||
) {
|
||||
const matches = [];
|
||||
let idx = 0;
|
||||
for (const options of this.contentScripts) {
|
||||
matches.push(options.matches);
|
||||
const reg = await browser.contentScripts.register(options);
|
||||
this._contentScriptRegistrations.push(reg);
|
||||
if (this.shouldUseScriptingAPI) {
|
||||
// Some shims includes more than one script (e.g. Blogger one contains
|
||||
// a content script to be run on document_start and one to be run
|
||||
// on document_end.
|
||||
options.id = `shim-${this.id}-${idx++}`;
|
||||
options.persistAcrossSessions = false;
|
||||
// Having to call getRegisteredContentScripts each time we are going to
|
||||
// register a Shim content script is suboptimal, but avoiding that
|
||||
// may require a bit more changes (e.g. rework both Injections, Shim and Shims
|
||||
// classes to more easily register all content scripts with a single
|
||||
// call to the scripting API methods when the background script page is loading
|
||||
// and one per injection or shim being enabled from the AboutCompatBroker).
|
||||
// In the short term we call getRegisteredContentScripts and restrict it to
|
||||
// the script id we are about to register.
|
||||
let isAlreadyRegistered = false;
|
||||
try {
|
||||
const registeredScripts =
|
||||
await browser.scripting.getRegisteredContentScripts({
|
||||
ids: [options.id],
|
||||
});
|
||||
isAlreadyRegistered = !!registeredScripts.length;
|
||||
} catch (ex) {
|
||||
console.error(
|
||||
"Retrieve WebCompat GoFaster registered content scripts failed: ",
|
||||
ex
|
||||
);
|
||||
}
|
||||
try {
|
||||
if (!isAlreadyRegistered) {
|
||||
await browser.scripting.registerContentScripts([options]);
|
||||
}
|
||||
this._contentScriptRegistrations.push(options.id);
|
||||
} catch (ex) {
|
||||
console.error(
|
||||
"Registering WebCompat Shim content scripts failed: ",
|
||||
options,
|
||||
ex
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const reg = await browser.contentScripts.register(options);
|
||||
this._contentScriptRegistrations.push(reg);
|
||||
}
|
||||
}
|
||||
const urls = Array.from(new Set(matches.flat()));
|
||||
debug("Enabling content scripts for these URLs:", urls);
|
||||
|
@ -255,8 +316,13 @@ class Shim {
|
|||
}
|
||||
|
||||
async _unregisterContentScripts() {
|
||||
for (const registration of this._contentScriptRegistrations) {
|
||||
registration.unregister();
|
||||
if (this.shouldUseScriptingAPI) {
|
||||
const ids = this._contentScriptRegistrations;
|
||||
await browser.scripting.unregisterContentScripts({ ids });
|
||||
} else {
|
||||
for (const registration of this._contentScriptRegistrations) {
|
||||
registration.unregister();
|
||||
}
|
||||
}
|
||||
this._contentScriptRegistrations = [];
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"manifest_version": 2,
|
||||
"name": "Web Compatibility Interventions",
|
||||
"description": "Urgent post-release fixes for web compatibility.",
|
||||
"version": "118.1.0",
|
||||
"version": "118.3.0",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "webcompat@mozilla.org",
|
||||
|
@ -17,6 +17,11 @@
|
|||
"scopes": ["addon_parent"],
|
||||
"script": "experiment-apis/aboutConfigPrefs.js",
|
||||
"paths": [["aboutConfigPrefs"]]
|
||||
},
|
||||
"child": {
|
||||
"scopes": ["addon_child"],
|
||||
"script": "experiment-apis/aboutConfigPrefsChild.js",
|
||||
"paths": [["aboutConfigPrefs"]]
|
||||
}
|
||||
},
|
||||
"appConstants": {
|
||||
|
@ -65,6 +70,7 @@
|
|||
|
||||
"permissions": [
|
||||
"mozillaAddons",
|
||||
"scripting",
|
||||
"tabs",
|
||||
"webNavigation",
|
||||
"webRequest",
|
||||
|
|
|
@ -16,7 +16,7 @@ FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["about-compat"] += [
|
|||
"about-compat/aboutCompat.css",
|
||||
"about-compat/aboutCompat.html",
|
||||
"about-compat/aboutCompat.js",
|
||||
"about-compat/AboutCompat.jsm",
|
||||
"about-compat/AboutCompat.sys.mjs",
|
||||
"about-compat/aboutPage.js",
|
||||
"about-compat/aboutPage.json",
|
||||
"about-compat/aboutPageProcessScript.js",
|
||||
|
@ -31,6 +31,7 @@ FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["data"] += [
|
|||
FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["experiment-apis"] += [
|
||||
"experiment-apis/aboutConfigPrefs.js",
|
||||
"experiment-apis/aboutConfigPrefs.json",
|
||||
"experiment-apis/aboutConfigPrefsChild.js",
|
||||
"experiment-apis/appConstants.js",
|
||||
"experiment-apis/appConstants.json",
|
||||
"experiment-apis/matchPatterns.js",
|
||||
|
|
|
@ -4010,3 +4010,8 @@ pref("dom.sitepermsaddon-provider.separatedBlocklistedDomains", "shopee.co.th,sh
|
|||
|
||||
// Log level for logger in URLQueryStrippingListService
|
||||
pref("privacy.query_stripping.listService.logLevel", "Error");
|
||||
|
||||
// Signal to the webcompat site intervention add-on to use the MV3
|
||||
// scripting.registerContentScripts API instead of the older MV2
|
||||
// contentScripts.register API.
|
||||
pref("extensions.webcompat.useScriptingAPI", true);
|
||||
|
|
Загрузка…
Ссылка в новой задаче