summaryrefslogtreecommitdiffstats
path: root/browser/extensions/report-site-issue/experimentalAPIs
diff options
context:
space:
mode:
Diffstat (limited to 'browser/extensions/report-site-issue/experimentalAPIs')
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/aboutConfigPrefs.js39
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/aboutConfigPrefs.json35
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/actors/tabExtrasActor.jsm163
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/browserInfo.js197
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/browserInfo.json64
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/helpMenu.js38
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/helpMenu.json28
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/l10n.js55
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/l10n.json21
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/tabExtras.js99
-rw-r--r--browser/extensions/report-site-issue/experimentalAPIs/tabExtras.json21
11 files changed, 760 insertions, 0 deletions
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/aboutConfigPrefs.js b/browser/extensions/report-site-issue/experimentalAPIs/aboutConfigPrefs.js
new file mode 100644
index 0000000000..0e8b6346c4
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/aboutConfigPrefs.js
@@ -0,0 +1,39 @@
+/* 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, ExtensionCommon, Services */
+
+this.aboutConfigPrefs = class extends ExtensionAPI {
+ getAPI(context) {
+ const EventManager = ExtensionCommon.EventManager;
+ const extensionIDBase = context.extension.id.split("@")[0];
+ const endpointPrefName = `extensions.${extensionIDBase}.newIssueEndpoint`;
+
+ return {
+ aboutConfigPrefs: {
+ onEndpointPrefChange: new EventManager({
+ context,
+ name: "aboutConfigPrefs.onEndpointPrefChange",
+ register: fire => {
+ const callback = () => {
+ fire.async().catch(() => {}); // ignore Message Manager disconnects
+ };
+ Services.prefs.addObserver(endpointPrefName, callback);
+ return () => {
+ Services.prefs.removeObserver(endpointPrefName, callback);
+ };
+ },
+ }).api(),
+ async getEndpointPref() {
+ return Services.prefs.getStringPref(endpointPrefName, undefined);
+ },
+ async setEndpointPref(value) {
+ Services.prefs.setStringPref(endpointPrefName, value);
+ },
+ },
+ };
+ }
+};
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/aboutConfigPrefs.json b/browser/extensions/report-site-issue/experimentalAPIs/aboutConfigPrefs.json
new file mode 100644
index 0000000000..1fd313e392
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/aboutConfigPrefs.json
@@ -0,0 +1,35 @@
+[
+ {
+ "namespace": "aboutConfigPrefs",
+ "description": "experimental API extension to allow access to about:config preferences",
+ "events": [
+ {
+ "name": "onEndpointPrefChange",
+ "type": "function",
+ "parameters": []
+ }
+ ],
+ "functions": [
+ {
+ "name": "getEndpointPref",
+ "type": "function",
+ "description": "Get the endpoint preference's value",
+ "parameters": [],
+ "async": true
+ },
+ {
+ "name": "setEndpointPref",
+ "type": "function",
+ "description": "Set the endpoint preference's value",
+ "parameters": [
+ {
+ "name": "value",
+ "type": "string",
+ "description": "The new value"
+ }
+ ],
+ "async": true
+ }
+ ]
+ }
+]
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/actors/tabExtrasActor.jsm b/browser/extensions/report-site-issue/experimentalAPIs/actors/tabExtrasActor.jsm
new file mode 100644
index 0000000000..52bc6c56c6
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/actors/tabExtrasActor.jsm
@@ -0,0 +1,163 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* 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";
+
+var EXPORTED_SYMBOLS = ["ReportSiteIssueHelperChild"];
+
+const PREVIEW_MAX_ITEMS = 10;
+const LOG_LEVELS = ["debug", "info", "warn", "error"];
+
+function getPreview(value) {
+ switch (typeof value) {
+ case "symbol":
+ return value.toString();
+
+ case "function":
+ return "function ()";
+
+ case "object":
+ if (value === null) {
+ return null;
+ }
+
+ if (Array.isArray(value)) {
+ return `(${value.length})[...]`;
+ }
+
+ return "{...}";
+
+ case "undefined":
+ return "undefined";
+
+ default:
+ try {
+ structuredClone(value);
+ } catch (_) {
+ return `${value}` || "?";
+ }
+
+ return value;
+ }
+}
+
+function getArrayPreview(arr) {
+ const preview = [];
+ let count = 0;
+ for (const value of arr) {
+ if (++count > PREVIEW_MAX_ITEMS) {
+ break;
+ }
+ preview.push(getPreview(value));
+ }
+
+ return preview;
+}
+
+function getObjectPreview(obj) {
+ const preview = {};
+ let count = 0;
+ for (const key of Object.keys(obj)) {
+ if (++count > PREVIEW_MAX_ITEMS) {
+ break;
+ }
+ preview[key] = getPreview(obj[key]);
+ }
+
+ return preview;
+}
+
+function getArgs(value) {
+ if (typeof value === "object" && value !== null) {
+ if (Array.isArray(value)) {
+ return getArrayPreview(value);
+ }
+
+ return getObjectPreview(value);
+ }
+
+ return getPreview(value);
+}
+
+class ReportSiteIssueHelperChild extends JSWindowActorChild {
+ _getConsoleMessages(windowId) {
+ const ConsoleAPIStorage = Cc[
+ "@mozilla.org/consoleAPI-storage;1"
+ ].getService(Ci.nsIConsoleAPIStorage);
+ let messages = ConsoleAPIStorage.getEvents(windowId);
+ return messages.map(evt => {
+ const { columnNumber, filename, level, lineNumber, timeStamp } = evt;
+ const args = evt.arguments.map(getArgs);
+
+ const message = {
+ level,
+ log: args,
+ uri: filename,
+ pos: `${lineNumber}:${columnNumber}`,
+ };
+
+ return { timeStamp, message };
+ });
+ }
+
+ _getScriptErrors(windowId, includePrivate) {
+ const messages = Services.console.getMessageArray();
+ return messages
+ .filter(message => {
+ if (message instanceof Ci.nsIScriptError) {
+ if (!includePrivate && message.isFromPrivateWindow) {
+ return false;
+ }
+
+ if (windowId && windowId !== message.innerWindowID) {
+ return false;
+ }
+
+ return true;
+ }
+
+ // If this is not an nsIScriptError and we need to do window-based
+ // filtering we skip this message.
+ return false;
+ })
+ .map(error => {
+ const {
+ timeStamp,
+ errorMessage,
+ sourceName,
+ lineNumber,
+ columnNumber,
+ logLevel,
+ } = error;
+ const message = {
+ level: LOG_LEVELS[logLevel],
+ log: [errorMessage],
+ uri: sourceName,
+ pos: `${lineNumber}:${columnNumber}`,
+ };
+ return { timeStamp, message };
+ });
+ }
+
+ _getLoggedMessages(includePrivate = false) {
+ const windowId = this.contentWindow.windowGlobalChild.innerWindowId;
+ return this._getConsoleMessages(windowId).concat(
+ this._getScriptErrors(windowId, includePrivate)
+ );
+ }
+
+ receiveMessage(msg) {
+ switch (msg.name) {
+ case "GetLog":
+ return this._getLoggedMessages();
+ case "GetBlockingStatus":
+ const { docShell } = this;
+ return {
+ hasTrackingContentBlocked: docShell.hasTrackingContentBlocked,
+ };
+ }
+ return null;
+ }
+}
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/browserInfo.js b/browser/extensions/report-site-issue/experimentalAPIs/browserInfo.js
new file mode 100644
index 0000000000..ce4466f1cf
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/browserInfo.js
@@ -0,0 +1,197 @@
+/* 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 AppConstants, ExtensionAPI, Services */
+
+function isTelemetryEnabled() {
+ return Services.prefs.getBoolPref(
+ "datareporting.healthreport.uploadEnabled",
+ false
+ );
+}
+
+function getSysinfoProperty(propertyName, defaultValue) {
+ try {
+ return Services.sysinfo.getProperty(propertyName);
+ } catch (e) {}
+
+ return defaultValue;
+}
+
+function getUserAgent() {
+ const { userAgent } = Cc[
+ "@mozilla.org/network/protocol;1?name=http"
+ ].getService(Ci.nsIHttpProtocolHandler);
+ return userAgent;
+}
+
+function getGfxData() {
+ const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
+ const data = {};
+
+ try {
+ const {
+ compositor,
+ hwCompositing,
+ openglCompositing,
+ wrCompositor,
+ wrSoftware,
+ } = gfxInfo.getFeatures();
+
+ data.features = {
+ compositor,
+ hwCompositing,
+ openglCompositing,
+ wrCompositor,
+ wrSoftware,
+ };
+ } catch (e) {}
+
+ try {
+ if (AppConstants.platform !== "android") {
+ data.monitors = gfxInfo.getMonitors();
+ }
+ } catch (e) {}
+
+ return data;
+}
+
+function limitStringToLength(str, maxLength) {
+ if (typeof str !== "string") {
+ return null;
+ }
+ return str.substring(0, maxLength);
+}
+
+function getSecurityAppData() {
+ const maxStringLength = 256;
+
+ const keys = [
+ ["registeredAntiVirus", "antivirus"],
+ ["registeredAntiSpyware", "antispyware"],
+ ["registeredFirewall", "firewall"],
+ ];
+
+ let result = {};
+
+ for (let [inKey, outKey] of keys) {
+ let prop = getSysinfoProperty(inKey, null);
+ if (prop) {
+ prop = limitStringToLength(prop, maxStringLength).split(";");
+ }
+
+ result[outKey] = prop;
+ }
+
+ return result;
+}
+
+function getAdditionalPrefs() {
+ const prefs = {};
+ for (const [name, dflt] of Object.entries({
+ "browser.opaqueResponseBlocking": false,
+ "extensions.InstallTrigger.enabled": false,
+ "gfx.canvas.accelerated.force-enabled": false,
+ "gfx.webrender.compositor.force-enabled": false,
+ "privacy.resistFingerprinting": false,
+ })) {
+ prefs[name] = Services.prefs.getBoolPref(name, dflt);
+ }
+ const cookieBehavior = "network.cookie.cookieBehavior";
+ prefs[cookieBehavior] = Services.prefs.getIntPref(cookieBehavior);
+
+ return prefs;
+}
+
+function getMemoryMB() {
+ let memoryMB = getSysinfoProperty("memsize", null);
+ if (memoryMB) {
+ memoryMB = Math.round(memoryMB / 1024 / 1024);
+ }
+
+ return memoryMB;
+}
+
+this.browserInfo = class extends ExtensionAPI {
+ getAPI(context) {
+ return {
+ browserInfo: {
+ async getGraphicsPrefs() {
+ const prefs = {};
+ for (const [name, dflt] of Object.entries({
+ "layers.acceleration.force-enabled": false,
+ "gfx.webrender.all": false,
+ "gfx.webrender.blob-images": true,
+ "gfx.webrender.enabled": false,
+ "image.mem.shared": true,
+ })) {
+ prefs[name] = Services.prefs.getBoolPref(name, dflt);
+ }
+ return prefs;
+ },
+ async getAppVersion() {
+ return AppConstants.MOZ_APP_VERSION;
+ },
+ async getBlockList() {
+ const trackingTable = Services.prefs.getCharPref(
+ "urlclassifier.trackingTable"
+ );
+ // If content-track-digest256 is in the tracking table,
+ // the user has enabled the strict list.
+ return trackingTable.includes("content") ? "strict" : "basic";
+ },
+ async getBuildID() {
+ return Services.appinfo.appBuildID;
+ },
+ async getUpdateChannel() {
+ return AppConstants.MOZ_UPDATE_CHANNEL;
+ },
+ async getPlatform() {
+ return AppConstants.platform;
+ },
+ async hasTouchScreen() {
+ const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(
+ Ci.nsIGfxInfo
+ );
+ return gfxInfo.getInfo().ApzTouchInput == 1;
+ },
+ async getAdditionalData() {
+ const blockList = await this.getBlockList();
+ const userAgent = getUserAgent();
+ const gfxData = getGfxData();
+ const prefs = getAdditionalPrefs();
+ const memoryMb = getMemoryMB();
+
+ const data = {
+ applicationName: Services.appinfo.name,
+ version: Services.appinfo.version,
+ updateChannel: AppConstants.MOZ_UPDATE_CHANNEL,
+ osArchitecture: getSysinfoProperty("arch", null),
+ osName: getSysinfoProperty("name", null),
+ osVersion: getSysinfoProperty("version", null),
+ fissionEnabled: Services.appinfo.fissionAutostart,
+ userAgent,
+ gfxData,
+ blockList,
+ prefs,
+ memoryMb,
+ };
+
+ if (AppConstants.isPlatformAndVersionAtLeast("win", "6.2")) {
+ data.sec = getSecurityAppData();
+ }
+
+ if (AppConstants.platform === "android") {
+ data.device = getSysinfoProperty("device", null);
+ data.isTablet = getSysinfoProperty("tablet", false);
+ }
+
+ return data;
+ },
+ },
+ };
+ }
+};
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/browserInfo.json b/browser/extensions/report-site-issue/experimentalAPIs/browserInfo.json
new file mode 100644
index 0000000000..c12f2ceb2e
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/browserInfo.json
@@ -0,0 +1,64 @@
+[
+ {
+ "namespace": "browserInfo",
+ "description": "experimental API extensions to get browser info not exposed via web APIs",
+ "functions": [
+ {
+ "name": "getAppVersion",
+ "type": "function",
+ "description": "Gets the app version",
+ "parameters": [],
+ "async": true
+ },
+ {
+ "name": "getBlockList",
+ "type": "function",
+ "description": "Gets the current blocklist",
+ "parameters": [],
+ "async": true
+ },
+ {
+ "name": "getBuildID",
+ "type": "function",
+ "description": "Gets the build ID",
+ "parameters": [],
+ "async": true
+ },
+ {
+ "name": "getGraphicsPrefs",
+ "type": "function",
+ "description": "Gets interesting about:config prefs for graphics",
+ "parameters": [],
+ "async": true
+ },
+ {
+ "name": "getPlatform",
+ "type": "function",
+ "description": "Gets the platform",
+ "parameters": [],
+ "async": true
+ },
+ {
+ "name": "getUpdateChannel",
+ "type": "function",
+ "description": "Gets the update channel",
+ "parameters": [],
+ "async": true
+ },
+ {
+ "name": "hasTouchScreen",
+ "type": "function",
+ "description": "Gets whether a touchscreen is present",
+ "parameters": [],
+ "async": true
+ },
+ {
+ "name": "getAdditionalData",
+ "type": "function",
+ "description": "Gets additional info for the new reporter experiment",
+ "parameters": [],
+ "async": true
+ }
+ ]
+ }
+]
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/helpMenu.js b/browser/extensions/report-site-issue/experimentalAPIs/helpMenu.js
new file mode 100644
index 0000000000..804f4b08d5
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/helpMenu.js
@@ -0,0 +1,38 @@
+/* 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, ExtensionCommon, Services */
+
+const TOPIC = "report-site-issue";
+
+this.helpMenu = class extends ExtensionAPI {
+ getAPI(context) {
+ const { tabManager } = context.extension;
+ let EventManager = ExtensionCommon.EventManager;
+
+ return {
+ helpMenu: {
+ onHelpMenuCommand: new EventManager({
+ context,
+ name: "helpMenu",
+ register: fire => {
+ let observer = (subject, topic, data) => {
+ let nativeTab = subject.wrappedJSObject;
+ let tab = tabManager.convert(nativeTab);
+ fire.async(tab);
+ };
+
+ Services.obs.addObserver(observer, TOPIC);
+
+ return () => {
+ Services.obs.removeObserver(observer, TOPIC);
+ };
+ },
+ }).api(),
+ },
+ };
+ }
+};
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/helpMenu.json b/browser/extensions/report-site-issue/experimentalAPIs/helpMenu.json
new file mode 100644
index 0000000000..e7c3a8c405
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/helpMenu.json
@@ -0,0 +1,28 @@
+[
+ {
+ "namespace": "helpMenu",
+ "events": [
+ {
+ "name": "onHelpMenuCommand",
+ "type": "function",
+ "async": "callback",
+ "description": "Fired when the command event for the Report Site Issue menuitem in Help is fired.",
+ "parameters": [
+ {
+ "type": "function",
+ "name": "callback",
+ "optional": true,
+ "parameters": [
+ {
+ "name": "tab",
+ "$ref": "tabs.Tab",
+ "optional": true,
+ "description": "Details about the selected tab in the window where the menuitem command fired."
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+]
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/l10n.js b/browser/extensions/report-site-issue/experimentalAPIs/l10n.js
new file mode 100644
index 0000000000..1c91e7a04d
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/l10n.js
@@ -0,0 +1,55 @@
+/* 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 */
+
+XPCOMUtils.defineLazyGetter(this, "l10nStrings", function () {
+ return Services.strings.createBundle(
+ "chrome://report-site-issue/locale/webcompat.properties"
+ );
+});
+
+let l10nManifest;
+
+this.l10n = class extends ExtensionAPI {
+ onShutdown(isAppShutdown) {
+ if (!isAppShutdown && l10nManifest) {
+ Components.manager.removeBootstrappedManifestLocation(l10nManifest);
+ }
+ }
+ getAPI(context) {
+ // Until we move to Fluent (bug 1446164), we're stuck with
+ // chrome.manifest for handling localization since its what the
+ // build system can handle for localized repacks.
+ if (context.extension.rootURI instanceof Ci.nsIJARURI) {
+ l10nManifest = context.extension.rootURI.JARFile.QueryInterface(
+ Ci.nsIFileURL
+ ).file;
+ } else if (context.extension.rootURI instanceof Ci.nsIFileURL) {
+ l10nManifest = context.extension.rootURI.file;
+ }
+
+ if (l10nManifest) {
+ Components.manager.addBootstrappedManifestLocation(l10nManifest);
+ } else {
+ console.error(
+ "Cannot find webcompat reporter chrome.manifest for registering translated strings"
+ );
+ }
+
+ return {
+ l10n: {
+ getMessage(name) {
+ try {
+ return Promise.resolve(l10nStrings.GetStringFromName(name));
+ } catch (e) {
+ return Promise.reject(e);
+ }
+ },
+ },
+ };
+ }
+};
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/l10n.json b/browser/extensions/report-site-issue/experimentalAPIs/l10n.json
new file mode 100644
index 0000000000..60942e726c
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/l10n.json
@@ -0,0 +1,21 @@
+[
+ {
+ "namespace": "l10n",
+ "description": "A stop-gap L10N API only meant to be used until a Fluent-based API is added in bug 1425104",
+ "functions": [
+ {
+ "name": "getMessage",
+ "type": "function",
+ "description": "Gets the message with the given name",
+ "parameters": [
+ {
+ "name": "name",
+ "type": "string",
+ "description": "The name of the message"
+ }
+ ],
+ "async": true
+ }
+ ]
+ }
+]
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/tabExtras.js b/browser/extensions/report-site-issue/experimentalAPIs/tabExtras.js
new file mode 100644
index 0000000000..12ccd91e05
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/tabExtras.js
@@ -0,0 +1,99 @@
+/* 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, XPCOMUtils, Services */
+
+XPCOMUtils.defineLazyServiceGetter(
+ this,
+ "resProto",
+ "@mozilla.org/network/protocol;1?name=resource",
+ "nsISubstitutingProtocolHandler"
+);
+
+this.tabExtras = class extends ExtensionAPI {
+ constructor(extension) {
+ super(extension);
+ this._registerActorModule();
+ }
+
+ getAPI(context) {
+ const { tabManager } = context.extension;
+ return {
+ tabExtras: {
+ async getWebcompatInfo(tabId) {
+ const {
+ browser: { browsingContext },
+ incognito,
+ } = tabManager.get(tabId);
+ const actors = gatherActors("ReportSiteIssueHelper", browsingContext);
+ const promises = actors.map(actor => actor.sendQuery("GetLog"));
+ const logs = await Promise.all(promises);
+ const info = await actors[0].sendQuery("GetBlockingStatus");
+ info.hasMixedActiveContentBlocked = !!(
+ browsingContext.secureBrowserUI.state &
+ Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT
+ );
+ info.hasMixedDisplayContentBlocked = !!(
+ browsingContext.secureBrowserUI.state &
+ Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_DISPLAY_CONTENT
+ );
+ info.isPB = incognito;
+ info.log = logs
+ .flat()
+ .sort((a, b) => a.timeStamp - b.timeStamp)
+ .map(m => m.message);
+ return info;
+ },
+ },
+ };
+ }
+
+ onShutdown(isAppShutdown) {
+ this._unregisterActorModule();
+ }
+
+ _registerActorModule() {
+ resProto.setSubstitution(
+ "report-site-issue",
+ Services.io.newURI(
+ "experimentalAPIs/actors/",
+ null,
+ this.extension.rootURI
+ )
+ );
+ ChromeUtils.registerWindowActor("ReportSiteIssueHelper", {
+ child: {
+ moduleURI: "resource://report-site-issue/tabExtrasActor.jsm",
+ },
+ allFrames: true,
+ });
+ }
+
+ _unregisterActorModule() {
+ ChromeUtils.unregisterWindowActor("ReportSiteIssueHelper");
+ resProto.setSubstitution("report-site-issue", null);
+ }
+};
+
+function getActorForBrowsingContext(name, browsingContext) {
+ const windowGlobal = browsingContext.currentWindowGlobal;
+ return windowGlobal ? windowGlobal.getActor(name) : null;
+}
+
+function gatherActors(name, browsingContext) {
+ const list = [];
+
+ const actor = getActorForBrowsingContext(name, browsingContext);
+ if (actor) {
+ list.push(actor);
+ }
+
+ for (const child of browsingContext.children) {
+ list.push(...gatherActors(name, child));
+ }
+
+ return list;
+}
diff --git a/browser/extensions/report-site-issue/experimentalAPIs/tabExtras.json b/browser/extensions/report-site-issue/experimentalAPIs/tabExtras.json
new file mode 100644
index 0000000000..7769049798
--- /dev/null
+++ b/browser/extensions/report-site-issue/experimentalAPIs/tabExtras.json
@@ -0,0 +1,21 @@
+[
+ {
+ "namespace": "tabExtras",
+ "description": "experimental tab API extensions",
+ "functions": [
+ {
+ "name": "getWebcompatInfo",
+ "type": "function",
+ "description": "Gets the content blocking status and script log for a given tab",
+ "parameters": [
+ {
+ "type": "integer",
+ "name": "tabId",
+ "minimum": 0
+ }
+ ],
+ "async": true
+ }
+ ]
+ }
+]