summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/content/abuse-reports.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /toolkit/mozapps/extensions/content/abuse-reports.js
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/mozapps/extensions/content/abuse-reports.js')
-rw-r--r--toolkit/mozapps/extensions/content/abuse-reports.js376
1 files changed, 376 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/content/abuse-reports.js b/toolkit/mozapps/extensions/content/abuse-reports.js
new file mode 100644
index 0000000000..c6461a071b
--- /dev/null
+++ b/toolkit/mozapps/extensions/content/abuse-reports.js
@@ -0,0 +1,376 @@
+/* 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/. */
+
+/* eslint max-len: ["error", 80] */
+/* import-globals-from aboutaddonsCommon.js */
+/* exported openAbuseReport */
+/* global windowRoot */
+
+/**
+ * This script is part of the HTML about:addons page and it provides some
+ * helpers used for the Abuse Reporting submission (and related message bars).
+ */
+
+const { AbuseReporter } = ChromeUtils.importESModule(
+ "resource://gre/modules/AbuseReporter.sys.mjs"
+);
+
+// Message Bars definitions.
+const ABUSE_REPORT_MESSAGE_BARS = {
+ // Idle message-bar (used while the submission is still ongoing).
+ submitting: {
+ actions: ["cancel"],
+ l10n: {
+ id: "abuse-report-messagebar-submitting2",
+ actionIds: {
+ cancel: "abuse-report-messagebar-action-cancel",
+ },
+ },
+ },
+ // Submitted report message-bar.
+ submitted: {
+ actions: ["remove", "keep"],
+ dismissable: true,
+ l10n: {
+ id: "abuse-report-messagebar-submitted2",
+ actionIdsPerAddonType: {
+ extension: {
+ remove: "abuse-report-messagebar-action-remove-extension",
+ keep: "abuse-report-messagebar-action-keep-extension",
+ },
+ sitepermission: {
+ remove: "abuse-report-messagebar-action-remove-sitepermission",
+ keep: "abuse-report-messagebar-action-keep-sitepermission",
+ },
+ theme: {
+ remove: "abuse-report-messagebar-action-remove-theme",
+ keep: "abuse-report-messagebar-action-keep-theme",
+ },
+ },
+ },
+ },
+ // Submitted report message-bar (with no remove actions).
+ "submitted-no-remove-action": {
+ dismissable: true,
+ l10n: { id: "abuse-report-messagebar-submitted-noremove2" },
+ },
+ // Submitted report and remove addon message-bar.
+ "submitted-and-removed": {
+ dismissable: true,
+ l10n: {
+ idsPerAddonType: {
+ extension: "abuse-report-messagebar-removed-extension2",
+ sitepermission: "abuse-report-messagebar-removed-sitepermission2",
+ theme: "abuse-report-messagebar-removed-theme2",
+ },
+ },
+ },
+ // The "aborted report" message bar is rendered as a generic informative one,
+ // because aborting a report is triggered by a user choice.
+ ERROR_ABORTED_SUBMIT: {
+ type: "info",
+ dismissable: true,
+ l10n: { id: "abuse-report-messagebar-aborted2" },
+ },
+ // Errors message bars.
+ ERROR_ADDON_NOTFOUND: {
+ type: "error",
+ dismissable: true,
+ l10n: { id: "abuse-report-messagebar-error2" },
+ },
+ ERROR_CLIENT: {
+ type: "error",
+ dismissable: true,
+ l10n: { id: "abuse-report-messagebar-error2" },
+ },
+ ERROR_NETWORK: {
+ actions: ["retry", "cancel"],
+ type: "error",
+ l10n: {
+ id: "abuse-report-messagebar-error2",
+ actionIds: {
+ retry: "abuse-report-messagebar-action-retry",
+ cancel: "abuse-report-messagebar-action-cancel",
+ },
+ },
+ },
+ ERROR_RECENT_SUBMIT: {
+ actions: ["retry", "cancel"],
+ type: "error",
+ l10n: {
+ id: "abuse-report-messagebar-error-recent-submit2",
+ actionIds: {
+ retry: "abuse-report-messagebar-action-retry",
+ cancel: "abuse-report-messagebar-action-cancel",
+ },
+ },
+ },
+ ERROR_SERVER: {
+ actions: ["retry", "cancel"],
+ type: "error",
+ l10n: {
+ id: "abuse-report-messagebar-error2",
+ actionIds: {
+ retry: "abuse-report-messagebar-action-retry",
+ cancel: "abuse-report-messagebar-action-cancel",
+ },
+ },
+ },
+ ERROR_UNKNOWN: {
+ actions: ["retry", "cancel"],
+ type: "error",
+ l10n: {
+ id: "abuse-report-messagebar-error2",
+ actionIds: {
+ retry: "abuse-report-messagebar-action-retry",
+ cancel: "abuse-report-messagebar-action-cancel",
+ },
+ },
+ },
+};
+
+async function openAbuseReport({ addonId, reportEntryPoint }) {
+ try {
+ const reportDialog = await AbuseReporter.openDialog(
+ addonId,
+ reportEntryPoint,
+ window.docShell.chromeEventHandler
+ );
+
+ // Warn the user before the about:addons tab while an
+ // abuse report dialog is still open, and close the
+ // report dialog if the user choose to close the related
+ // about:addons tab.
+ const beforeunloadListener = evt => evt.preventDefault();
+ const unloadListener = () => reportDialog.close();
+ const clearUnloadListeners = () => {
+ window.removeEventListener("beforeunload", beforeunloadListener);
+ window.removeEventListener("unload", unloadListener);
+ };
+ window.addEventListener("beforeunload", beforeunloadListener);
+ window.addEventListener("unload", unloadListener);
+
+ reportDialog.promiseReport
+ .then(
+ report => {
+ if (report) {
+ submitReport({ report });
+ }
+ },
+ err => {
+ Cu.reportError(
+ `Unexpected abuse report panel error: ${err} :: ${err.stack}`
+ );
+ reportDialog.close();
+ }
+ )
+ .then(clearUnloadListeners);
+ } catch (err) {
+ // Log the detailed error to the browser console.
+ Cu.reportError(err);
+ document.dispatchEvent(
+ new CustomEvent("abuse-report:create-error", {
+ detail: {
+ addonId,
+ addon: err.addon,
+ errorType: err.errorType,
+ },
+ })
+ );
+ }
+}
+
+// Unlike the openAbuseReport function, technically this method wouldn't need
+// to be async, but it is so that both the implementations will be providing
+// the same type signatures (returning a promise) to the callers, independently
+// from which abuse reporting feature is enabled.
+async function openAbuseReportAMOForm({ addonId, reportEntryPoint }) {
+ const amoUrl = AbuseReporter.getAMOFormURL({ addonId });
+ windowRoot.ownerGlobal.openTrustedLinkIn(amoUrl, "tab", {
+ // Make sure the newly open tab is going to be focused, independently
+ // from general user prefs.
+ forceForeground: true,
+ });
+}
+
+window.openAbuseReport = AbuseReporter.amoFormEnabled
+ ? openAbuseReportAMOForm
+ : openAbuseReport;
+
+// Helper function used to create abuse report message bars in the
+// HTML about:addons page.
+function createReportMessageBar(
+ definitionId,
+ { addonId, addonName, addonType },
+ { onclose, onaction } = {}
+) {
+ const barInfo = ABUSE_REPORT_MESSAGE_BARS[definitionId];
+ if (!barInfo) {
+ throw new Error(`message-bar definition not found: ${definitionId}`);
+ }
+ const { dismissable, actions, type, l10n } = barInfo;
+
+ // TODO(Bug 1789718): Remove after the deprecated XPIProvider-based
+ // implementation is also removed.
+ const mappingAddonType =
+ addonType === "sitepermission-deprecated" ? "sitepermission" : addonType;
+
+ const getMessageL10n = () => {
+ return l10n.idsPerAddonType
+ ? l10n.idsPerAddonType[mappingAddonType]
+ : l10n.id;
+ };
+ const getActionL10n = action => {
+ return l10n.actionIdsPerAddonType
+ ? l10n.actionIdsPerAddonType[mappingAddonType][action]
+ : l10n.actionIds[action];
+ };
+
+ const messagebar = document.createElement("moz-message-bar");
+
+ document.l10n.setAttributes(messagebar, getMessageL10n(), {
+ "addon-name": addonName || addonId,
+ });
+ messagebar.setAttribute("data-l10n-attrs", "message");
+
+ actions?.forEach(action => {
+ const buttonEl = document.createElement("button");
+ buttonEl.addEventListener("click", () => onaction && onaction(action));
+ document.l10n.setAttributes(buttonEl, getActionL10n(action));
+ buttonEl.setAttribute("slot", "actions");
+ messagebar.appendChild(buttonEl);
+ });
+
+ messagebar.setAttribute("type", type || "info");
+ messagebar.dismissable = dismissable;
+ messagebar.addEventListener("message-bar:close", onclose, { once: true });
+
+ document.getElementById("abuse-reports-messages").append(messagebar);
+
+ document.dispatchEvent(
+ new CustomEvent("abuse-report:new-message-bar", {
+ detail: { definitionId, messagebar },
+ })
+ );
+ return messagebar;
+}
+
+async function submitReport({ report }) {
+ const { addon } = report;
+ const addonId = addon.id;
+ const addonName = addon.name;
+ const addonType = addon.type;
+
+ // Ensure that the tab that originated the report dialog is selected
+ // when the user is submitting the report.
+ const { gBrowser } = window.windowRoot.ownerGlobal;
+ if (gBrowser && gBrowser.getTabForBrowser) {
+ let tab = gBrowser.getTabForBrowser(window.docShell.chromeEventHandler);
+ gBrowser.selectedTab = tab;
+ }
+
+ // Create a message bar while we are still submitting the report.
+ const mbSubmitting = createReportMessageBar(
+ "submitting",
+ { addonId, addonName, addonType },
+ {
+ onaction: action => {
+ if (action === "cancel") {
+ report.abort();
+ mbSubmitting.remove();
+ }
+ },
+ }
+ );
+
+ try {
+ await report.submit();
+ mbSubmitting.remove();
+
+ // Create a submitted message bar when the submission has been
+ // successful.
+ let barId;
+ if (
+ !(addon.permissions & AddonManager.PERM_CAN_UNINSTALL) &&
+ !isPending(addon, "uninstall")
+ ) {
+ // Do not offer remove action if the addon can't be uninstalled.
+ barId = "submitted-no-remove-action";
+ } else if (report.reportEntryPoint === "uninstall") {
+ // With reportEntryPoint "uninstall" a specific message bar
+ // is going to be used.
+ barId = "submitted-and-removed";
+ } else {
+ // All the other reportEntryPoint ("menu" and "toolbar_context_menu")
+ // use the same kind of message bar.
+ barId = "submitted";
+ }
+
+ const mbInfo = createReportMessageBar(
+ barId,
+ {
+ addonId,
+ addonName,
+ addonType,
+ },
+ {
+ onaction: action => {
+ mbInfo.remove();
+ // action "keep" doesn't require any further action,
+ // just handle "remove".
+ if (action === "remove") {
+ report.addon.uninstall(true);
+ }
+ },
+ }
+ );
+ } catch (err) {
+ // Log the complete error in the console.
+ console.error("Error submitting abuse report for", addonId, err);
+ mbSubmitting.remove();
+ // The report has a submission error, create a error message bar which
+ // may optionally allow the user to retry to submit the same report.
+ const barId =
+ err.errorType in ABUSE_REPORT_MESSAGE_BARS
+ ? err.errorType
+ : "ERROR_UNKNOWN";
+
+ const mbError = createReportMessageBar(
+ barId,
+ {
+ addonId,
+ addonName,
+ addonType,
+ },
+ {
+ onaction: action => {
+ mbError.remove();
+ switch (action) {
+ case "retry":
+ submitReport({ report });
+ break;
+ case "cancel":
+ report.abort();
+ break;
+ }
+ },
+ }
+ );
+ }
+}
+
+document.addEventListener("abuse-report:submit", ({ detail }) => {
+ submitReport(detail);
+});
+
+document.addEventListener("abuse-report:create-error", ({ detail }) => {
+ const { addonId, addon, errorType } = detail;
+ const barId =
+ errorType in ABUSE_REPORT_MESSAGE_BARS ? errorType : "ERROR_UNKNOWN";
+ createReportMessageBar(barId, {
+ addonId,
+ addonName: addon && addon.name,
+ addonType: addon && addon.type,
+ });
+});