/* 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/. */ /* globals startBackground, analytics, communication, catcher, log, browser, getStrings */ "use strict"; this.senderror = (function () { const exports = {}; // Do not show an error more than every ERROR_TIME_LIMIT milliseconds: const ERROR_TIME_LIMIT = 3000; const messages = { REQUEST_ERROR: { titleKey: "screenshots-request-error-title", infoKey: "screenshots-request-error-details", }, CONNECTION_ERROR: { titleKey: "screenshots-connection-error-title", infoKey: "screenshots-connection-error-details", }, LOGIN_ERROR: { titleKey: "screenshots-request-error-title", infoKey: "screenshots-login-error-details", }, LOGIN_CONNECTION_ERROR: { titleKey: "screenshots-connection-error-title", infoKey: "screenshots-connection-error-details", }, UNSHOOTABLE_PAGE: { titleKey: "screenshots-unshootable-page-error-title", infoKey: "screenshots-unshootable-page-error-details", }, EMPTY_SELECTION: { titleKey: "screenshots-empty-selection-error-title", }, PRIVATE_WINDOW: { titleKey: "screenshots-private-window-error-title", infoKey: "screenshots-private-window-error-details", }, generic: { titleKey: "screenshots-generic-error-title", infoKey: "screenshots-generic-error-details", showMessage: true, }, }; communication.register("reportError", (sender, error) => { catcher.unhandled(error); }); let lastErrorTime; exports.showError = async function (error) { if (lastErrorTime && Date.now() - lastErrorTime < ERROR_TIME_LIMIT) { return; } lastErrorTime = Date.now(); const id = crypto.randomUUID(); let popupMessage = error.popupMessage || "generic"; if (!messages[popupMessage]) { popupMessage = "generic"; } let item = messages[popupMessage]; if (!("title" in item)) { let keys = [{ id: item.titleKey }]; if ("infoKey" in item) { keys.push({ id: item.infoKey }); } [item.title, item.info] = await getStrings(keys); } let title = item.title; let message = item.info || ""; const showMessage = item.showMessage; if (error.message && showMessage) { if (message) { message += "\n" + error.message; } else { message = error.message; } } if (Date.now() - startBackground.startTime > 5 * 1000) { browser.notifications.create(id, { type: "basic", // FIXME: need iconUrl for an image, see #2239 title, message, }); } }; exports.reportError = function (e) { if (!analytics.isTelemetryEnabled()) { log.error("Telemetry disabled. Not sending critical error:", e); return; } const exception = new Error(e.message); exception.stack = e.multilineStack || e.stack || undefined; // To improve Sentry reporting & grouping, replace the // moz-extension://$uuid base URL with a generic resource:// URL. if (exception.stack) { exception.stack = exception.stack.replace( /moz-extension:\/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/g, "resource://screenshots-addon" ); } const rest = {}; for (const attr in e) { if ( ![ "name", "message", "stack", "multilineStack", "popupMessage", "version", "sentryPublicDSN", "help", "fromMakeError", ].includes(attr) ) { rest[attr] = e[attr]; } } rest.stack = exception.stack; }; catcher.registerHandler(errorObj => { if (!errorObj.noPopup) { exports.showError(errorObj); } if (!errorObj.noReport) { exports.reportError(errorObj); } }); return exports; })();