From ee8143b7c6ce4c7127f067be0451868cd620aae2 Mon Sep 17 00:00:00 2001 From: Blake Niemyjski Date: Wed, 22 Feb 2023 21:06:05 -0600 Subject: [PATCH 1/2] Fixes #70: Ignore errors created from browser extensions --- example/browser/index.html | 1 + example/browser/index.js | 9 ++++ .../browser/src/BrowserExceptionlessClient.ts | 2 + packages/browser/src/index.ts | 1 + .../BrowserIgnoreExtensionErrorsPlugin.ts | 20 ++++++++ ...BrowserIgnoreExtensionErrorsPlugin.test.ts | 50 +++++++++++++++++++ 6 files changed, 83 insertions(+) create mode 100644 packages/browser/src/plugins/BrowserIgnoreExtensionErrorsPlugin.ts create mode 100644 packages/browser/test/plugins/BrowserIgnoreExtensionErrorsPlugin.test.ts diff --git a/example/browser/index.html b/example/browser/index.html index 83c80388..d69681d5 100644 --- a/example/browser/index.html +++ b/example/browser/index.html @@ -15,6 +15,7 @@

Error Submission

+

Log Submission

diff --git a/example/browser/index.js b/example/browser/index.js index b772df3b..73a66904 100644 --- a/example/browser/index.js +++ b/example/browser/index.js @@ -53,6 +53,15 @@ document.addEventListener("DOMContentLoaded", () => { await builder.submit(); }); + document + .querySelector("#throw-browser-extension-error") + .addEventListener("click", () => { + const error = new Error("A Browser Extension Error"); + error.stack = "at () in chrome-extension://bmagokdooijbeehmkpknfglimnifench/firebug-lite.js:line 9716:col 29" + + throw error; + }); + document .querySelector("#throw-custom-error") .addEventListener("click", () => { diff --git a/packages/browser/src/BrowserExceptionlessClient.ts b/packages/browser/src/BrowserExceptionlessClient.ts index e9199b74..d959882f 100644 --- a/packages/browser/src/BrowserExceptionlessClient.ts +++ b/packages/browser/src/BrowserExceptionlessClient.ts @@ -2,6 +2,7 @@ import { Configuration, ExceptionlessClient, SimpleErrorPlugin } from "@exceptio import { BrowserErrorPlugin } from "./plugins/BrowserErrorPlugin.js"; import { BrowserGlobalHandlerPlugin } from "./plugins/BrowserGlobalHandlerPlugin.js"; +import { BrowserIgnoreExtensionErrorsPlugin } from "./plugins/BrowserIgnoreExtensionErrorsPlugin.js"; import { BrowserLifeCyclePlugin } from "./plugins/BrowserLifeCyclePlugin.js"; import { BrowserModuleInfoPlugin } from "./plugins/BrowserModuleInfoPlugin.js"; import { BrowserRequestInfoPlugin } from "./plugins/BrowserRequestInfoPlugin.js"; @@ -13,6 +14,7 @@ export class BrowserExceptionlessClient extends ExceptionlessClient { config.useLocalStorage(); config.addPlugin(new BrowserGlobalHandlerPlugin()); + config.addPlugin(new BrowserIgnoreExtensionErrorsPlugin()); config.addPlugin(new BrowserLifeCyclePlugin()); config.addPlugin(new BrowserModuleInfoPlugin()); config.addPlugin(new BrowserRequestInfoPlugin()); diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index ae31746a..d9e11b46 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -1,5 +1,6 @@ export { BrowserErrorPlugin } from "./plugins/BrowserErrorPlugin.js" export { BrowserGlobalHandlerPlugin } from "./plugins/BrowserGlobalHandlerPlugin.js"; +export { BrowserIgnoreExtensionErrorsPlugin } from "./plugins/BrowserIgnoreExtensionErrorsPlugin.js"; export { BrowserLifeCyclePlugin } from "./plugins/BrowserLifeCyclePlugin.js"; export { BrowserModuleInfoPlugin } from "./plugins/BrowserModuleInfoPlugin.js"; export { BrowserRequestInfoPlugin } from "./plugins/BrowserRequestInfoPlugin.js"; diff --git a/packages/browser/src/plugins/BrowserIgnoreExtensionErrorsPlugin.ts b/packages/browser/src/plugins/BrowserIgnoreExtensionErrorsPlugin.ts new file mode 100644 index 00000000..c11a4c68 --- /dev/null +++ b/packages/browser/src/plugins/BrowserIgnoreExtensionErrorsPlugin.ts @@ -0,0 +1,20 @@ +import { + EventPluginContext, + IEventPlugin +} from "@exceptionless/core"; + +export class BrowserIgnoreExtensionErrorsPlugin implements IEventPlugin { + public priority = 15; + public name = "BrowserIgnoreExtensionErrorsPlugin"; + + public async run(context: EventPluginContext): Promise { + const exception = context.eventContext.getException(); + if (exception?.stack && exception.stack.includes("-extension://")) { + // Handles all extensions like chrome-extension://, moz-extension://, ms-browser-extension://, safari-extension:// + context.log.info("Ignoring event with error stack containing browser extension"); + context.cancelled = true; + } + + return Promise.resolve(); + } +} diff --git a/packages/browser/test/plugins/BrowserIgnoreExtensionErrorsPlugin.test.ts b/packages/browser/test/plugins/BrowserIgnoreExtensionErrorsPlugin.test.ts new file mode 100644 index 00000000..ba366b38 --- /dev/null +++ b/packages/browser/test/plugins/BrowserIgnoreExtensionErrorsPlugin.test.ts @@ -0,0 +1,50 @@ +import { describe, test } from "@jest/globals"; +import { expect } from "expect"; + +import { + EventContext, + EventPluginContext, + ExceptionlessClient +} from "@exceptionless/core"; + +import { BrowserIgnoreExtensionErrorsPlugin } from "../../src/plugins/BrowserIgnoreExtensionErrorsPlugin.js"; + +describe("BrowserIgnoreExtensionErrorsPlugin", () => { + let client: ExceptionlessClient; + let plugin: BrowserIgnoreExtensionErrorsPlugin; + + beforeEach(() => { + client = new ExceptionlessClient(); + plugin = new BrowserIgnoreExtensionErrorsPlugin(); + }); + + const run = async (stackTrace?: string | undefined): Promise => { + const error = new Error("Test"); + if (stackTrace) { + error.stack = stackTrace; + } + + const eventContext = new EventContext(); + eventContext.setException(error); + + const context = new EventPluginContext(client, { type: "error" }, eventContext); + + await plugin.run(context); + return context; + } + + test("should not cancel empty stack trace", async () => { + const context = await run(); + expect(context.cancelled).toBe(false); + }); + + test("should not cancel normal stack trace", async () => { + const context = await run("at t() in https://test/Content/js/Exceptionless/exceptionless.min.js:line 1:col 260"); + expect(context.cancelled).toBe(false); + }); + + test("should cancel browser extension stack trace", async () => { + const context = await run("at Object.initialize() in chrome-extension://bmagokdooijbeehmkpknfglimnifench/firebug-lite.js:line 6289:col 29"); + expect(context.cancelled).toBe(true); + }); +}); From 8612119cef65d6bdeb9fc308bc020274e60a6c8c Mon Sep 17 00:00:00 2001 From: Blake Niemyjski Date: Wed, 22 Feb 2023 21:08:45 -0600 Subject: [PATCH 2/2] Fixed lint error --- packages/browser/src/plugins/BrowserGlobalHandlerPlugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser/src/plugins/BrowserGlobalHandlerPlugin.ts b/packages/browser/src/plugins/BrowserGlobalHandlerPlugin.ts index be9d06ab..cbb2d44c 100644 --- a/packages/browser/src/plugins/BrowserGlobalHandlerPlugin.ts +++ b/packages/browser/src/plugins/BrowserGlobalHandlerPlugin.ts @@ -46,7 +46,7 @@ export class BrowserGlobalHandlerPlugin implements IEventPlugin { void this._client?.submitNotFound(settings.url); } else if (xhr.status !== 401) { // TODO: Handle async - void this._client?.createUnhandledException(toError(error) as Error, "JQuery.ajaxError") + void this._client?.createUnhandledException(toError(error), "JQuery.ajaxError") .setSource(settings.url) .setProperty("status", xhr.status) .setProperty("request", settings.data)