From 811f84b1f2c104dda05ee2887fbcd65550ea07c8 Mon Sep 17 00:00:00 2001 From: jdorweiler Date: Mon, 1 Dec 2025 15:49:11 -0700 Subject: [PATCH 1/5] extension messaging for detector' --- injected/entry-points/extension-mv3.js | 10 ++++++++++ injected/src/features.js | 2 +- injected/src/features/breakage-reporting.js | 3 ++- injected/src/sendmessage-transport.js | 18 ++++++++++++++++-- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/injected/entry-points/extension-mv3.js b/injected/entry-points/extension-mv3.js index 29f9f384b6..5c920614ba 100644 --- a/injected/entry-points/extension-mv3.js +++ b/injected/entry-points/extension-mv3.js @@ -3,6 +3,7 @@ */ import { load, init, update } from '../src/content-scope-features.js'; import { computeLimitedSiteObject } from '../src/utils.js'; +import { getSharedMessagingTransport } from '../src/sendmessage-transport.js'; const secret = (crypto.getRandomValues(new Uint32Array(1))[0] / 2 ** 32).toString().replace('0.', ''); @@ -34,6 +35,15 @@ window.addEventListener(secret, ({ detail: encodedMessage }) => { init(message.argumentsObject); } break; + default: + // Route messages with messageType to the messaging transport for subscriptions + if (message.messageType) { + const transport = getSharedMessagingTransport(); + if (transport?.onResponse) { + transport.onResponse(message); + } + } + break; } }); diff --git a/injected/src/features.js b/injected/src/features.js index 9075035dbc..e4a3489749 100644 --- a/injected/src/features.js +++ b/injected/src/features.js @@ -79,7 +79,7 @@ export const platformSupport = { 'pageContext', 'duckAiDataClearing', ], - firefox: ['cookie', ...baseFeatures, 'clickToLoad'], + firefox: ['cookie', ...baseFeatures, 'clickToLoad', 'webInterferenceDetection', 'breakageReporting'], chrome: ['cookie', ...baseFeatures, 'clickToLoad', 'webInterferenceDetection', 'breakageReporting'], 'chrome-mv3': ['cookie', ...baseFeatures, 'clickToLoad', 'webInterferenceDetection', 'breakageReporting'], integration: [...baseFeatures, ...otherFeatures], diff --git a/injected/src/features/breakage-reporting.js b/injected/src/features/breakage-reporting.js index 55cd074063..f271627604 100644 --- a/injected/src/features/breakage-reporting.js +++ b/injected/src/features/breakage-reporting.js @@ -17,7 +17,8 @@ export default class BreakageReporting extends ContentFeature { }; // Only run detectors if explicitly configured - const detectorSettings = this.getFeatureSetting('interferenceTypes', 'webInterferenceDetection'); + const interferenceTypes = this.getFeatureSetting('interferenceTypes'); + const detectorSettings = interferenceTypes?.webInterferenceDetection; if (detectorSettings) { result.detectorData = { botDetection: runBotDetection(detectorSettings.botDetection), diff --git a/injected/src/sendmessage-transport.js b/injected/src/sendmessage-transport.js index f9f5f6d45d..8fce8d6fde 100644 --- a/injected/src/sendmessage-transport.js +++ b/injected/src/sendmessage-transport.js @@ -6,12 +6,26 @@ import { TestTransportConfig } from '../../messaging/index.js'; * @typedef {import('@duckduckgo/messaging').MessagingTransport} MessagingTransport */ +/** @type {SendMessageMessagingTransport | null} */ +let sharedTransport = null; + /** * @deprecated - A temporary constructor for the extension to make the messaging config */ export function extensionConstructMessagingConfig() { - const messagingTransport = new SendMessageMessagingTransport(); - return new TestTransportConfig(messagingTransport); + // Use shared transport so all features receive messages via onResponse + if (!sharedTransport) { + sharedTransport = new SendMessageMessagingTransport(); + } + return new TestTransportConfig(sharedTransport); +} + +/** + * Get the shared messaging transport for routing messages from the background + * @returns {SendMessageMessagingTransport | null} + */ +export function getSharedMessagingTransport() { + return sharedTransport; } /** From 9f004fc7db79ab9d3c39e36c06c61dbe734e86e6 Mon Sep 17 00:00:00 2001 From: jdorweiler Date: Mon, 1 Dec 2025 15:54:17 -0700 Subject: [PATCH 2/5] comments --- injected/entry-points/extension-mv3.js | 3 ++- injected/src/sendmessage-transport.js | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/injected/entry-points/extension-mv3.js b/injected/entry-points/extension-mv3.js index 5c920614ba..4d06d6e693 100644 --- a/injected/entry-points/extension-mv3.js +++ b/injected/entry-points/extension-mv3.js @@ -36,7 +36,8 @@ window.addEventListener(secret, ({ detail: encodedMessage }) => { } break; default: - // Route messages with messageType to the messaging transport for subscriptions + // Messages with messageType are subscription responses from the extension. + // Route them to the shared transport so all subscribed features receive them. if (message.messageType) { const transport = getSharedMessagingTransport(); if (transport?.onResponse) { diff --git a/injected/src/sendmessage-transport.js b/injected/src/sendmessage-transport.js index 8fce8d6fde..bb7339f301 100644 --- a/injected/src/sendmessage-transport.js +++ b/injected/src/sendmessage-transport.js @@ -6,14 +6,17 @@ import { TestTransportConfig } from '../../messaging/index.js'; * @typedef {import('@duckduckgo/messaging').MessagingTransport} MessagingTransport */ -/** @type {SendMessageMessagingTransport | null} */ +/** + * Singleton transport shared across all features. Without this, each feature would + * have its own transport/queue and wouldn't receive messages meant for other features. + * @type {SendMessageMessagingTransport | null} + */ let sharedTransport = null; /** * @deprecated - A temporary constructor for the extension to make the messaging config */ export function extensionConstructMessagingConfig() { - // Use shared transport so all features receive messages via onResponse if (!sharedTransport) { sharedTransport = new SendMessageMessagingTransport(); } @@ -21,7 +24,7 @@ export function extensionConstructMessagingConfig() { } /** - * Get the shared messaging transport for routing messages from the background + * Used by entry-points to route incoming extension messages to onResponse(). * @returns {SendMessageMessagingTransport | null} */ export function getSharedMessagingTransport() { From 33c679dd4f7b7dc55a677ad254495c434f9ac58e Mon Sep 17 00:00:00 2001 From: jdorweiler Date: Tue, 2 Dec 2025 10:55:54 -0700 Subject: [PATCH 3/5] fix getfeaturesetting --- injected/src/features/breakage-reporting.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/injected/src/features/breakage-reporting.js b/injected/src/features/breakage-reporting.js index f271627604..590f8f56f0 100644 --- a/injected/src/features/breakage-reporting.js +++ b/injected/src/features/breakage-reporting.js @@ -17,8 +17,8 @@ export default class BreakageReporting extends ContentFeature { }; // Only run detectors if explicitly configured - const interferenceTypes = this.getFeatureSetting('interferenceTypes'); - const detectorSettings = interferenceTypes?.webInterferenceDetection; + // Fetch interferenceTypes from webInterferenceDetection feature settings + const detectorSettings = this.getFeatureSetting('interferenceTypes', 'webInterferenceDetection'); if (detectorSettings) { result.detectorData = { botDetection: runBotDetection(detectorSettings.botDetection), From d2d68a45b7e36c5511913c12703dddfcacf1d7d9 Mon Sep 17 00:00:00 2001 From: jdorweiler Date: Tue, 9 Dec 2025 15:49:46 -0700 Subject: [PATCH 4/5] create singleton in getter --- injected/src/sendmessage-transport.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/injected/src/sendmessage-transport.js b/injected/src/sendmessage-transport.js index bb7339f301..0475ac0480 100644 --- a/injected/src/sendmessage-transport.js +++ b/injected/src/sendmessage-transport.js @@ -17,17 +17,18 @@ let sharedTransport = null; * @deprecated - A temporary constructor for the extension to make the messaging config */ export function extensionConstructMessagingConfig() { - if (!sharedTransport) { - sharedTransport = new SendMessageMessagingTransport(); - } - return new TestTransportConfig(sharedTransport); + return new TestTransportConfig(getSharedMessagingTransport()); } /** * Used by entry-points to route incoming extension messages to onResponse(). - * @returns {SendMessageMessagingTransport | null} + * Ensures a singleton transport exists. + * @returns {SendMessageMessagingTransport} */ export function getSharedMessagingTransport() { + if (!sharedTransport) { + sharedTransport = new SendMessageMessagingTransport(); + } return sharedTransport; } From e7fe8b476fccbc5ca2a7d2f5ebea65f3b3879edb Mon Sep 17 00:00:00 2001 From: jdorweiler Date: Wed, 10 Dec 2025 11:57:27 -0700 Subject: [PATCH 5/5] drop default config --- injected/src/detectors/README.md | 1 - injected/src/detectors/default-config.js | 48 ------------------------ 2 files changed, 49 deletions(-) delete mode 100644 injected/src/detectors/default-config.js diff --git a/injected/src/detectors/README.md b/injected/src/detectors/README.md index 7482f20bb6..2111adb1df 100644 --- a/injected/src/detectors/README.md +++ b/injected/src/detectors/README.md @@ -20,7 +20,6 @@ detectors/ │ └── fraud-detection.js # fraud/phishing warning utility ├── utils/ │ └── detection-utils.js # DOM helpers (selectors, text matching, visibility) -└── default-config.js # fallback detector settings ``` ## How It Works diff --git a/injected/src/detectors/default-config.js b/injected/src/detectors/default-config.js deleted file mode 100644 index edde889a8e..0000000000 --- a/injected/src/detectors/default-config.js +++ /dev/null @@ -1,48 +0,0 @@ -export const DEFAULT_DETECTOR_SETTINGS = Object.freeze({ - botDetection: { - cloudflareTurnstile: { - state: 'enabled', - vendor: 'cloudflare', - selectors: ['.cf-turnstile', 'script[src*="challenges.cloudflare.com"]'], - windowProperties: ['turnstile'], - statusSelectors: [ - { - status: 'solved', - selectors: ['[data-state="success"]'], - }, - { - status: 'failed', - selectors: ['[data-state="error"]'], - }, - ], - }, - cloudflareChallengePage: { - state: 'enabled', - vendor: 'cloudflare', - selectors: ['#challenge-form', '.cf-browser-verification', '#cf-wrapper', 'script[src*="challenges.cloudflare.com"]'], - windowProperties: ['_cf_chl_opt', '__CF$cv$params', 'cfjsd'], - }, - hcaptcha: { - state: 'enabled', - vendor: 'hcaptcha', - selectors: ['.h-captcha', '[data-hcaptcha-widget-id]', 'script[src*="hcaptcha.com"]', 'script[src*="assets.hcaptcha.com"]'], - windowProperties: ['hcaptcha'], - }, - }, - fraudDetection: { - phishingWarning: { - state: 'enabled', - type: 'phishing', - selectors: ['.warning-banner', '#security-alert'], - textPatterns: ['suspicious.*activity', 'unusual.*login', 'verify.*account'], - textSources: ['innerText'], - }, - accountSuspension: { - state: 'enabled', - type: 'suspension', - selectors: ['.account-suspended', '#suspension-notice'], - textPatterns: ['account.*suspended', 'access.*restricted'], - textSources: ['innerText'], - }, - }, -});