Skip to content

Conversation

@madblex
Copy link
Contributor

@madblex madblex commented Nov 6, 2025

Asana Task/Github Issue: https://app.asana.com/1/137249556945/project/1206054067224240/task/1211804981097440

Description

This PR builds a prototype for the WebInterferenceDetection system:

  • the service with the detection logic
  • the associated WebInterferenceDetection content feature prototype + example usages
  • working integration in the BrokerProtection content feature

Goals

  • Keep all interference detection logic in one place (services/web-interference-detection/) to avoid duplication across features while maintaining flexibility for future detector types.
  • All detectors use common utilities from detection-utils.js (selector checking, visibility detection, pattern matching) to maximise code reuse and consistency.
  • The service architecture intentionally avoids over-constraining detector implementations. We will revisit this based on what patterns emerge.
  • Unsure about this: Each interference type has an independent configuration with observeDOMChanges flag controlling whether continuous monitoring is enabled per-detector.

Caveats

Current implementation creates new observers for each detect() call when observeDOMChanges: true. Multiple detections may create redundant observers. Future iterations should consider observer pooling/reuse, debouncing detection calls, or centralised DOM observation.

Testing Steps

n/a

Checklist

Please tick all that apply:

  • I have tested this change locally
  • I have tested this change locally in all supported browsers
  • This change will be visible to users
  • I have added automated tests that cover this change
  • I have ensured the change is gated by config
  • This change was covered by a ship review
  • This change was covered by a tech design
  • Any dependent config has been merged

Note

Introduces a config-driven Web Interference Detection service (bot/fraud/YouTube ads) with messaging APIs, a new feature entry point, and BrokerProtection integration.

  • Services:
    • injected/src/services/web-interference-detection/: New detection service with detectors bot-detection, fraud-detection, youtube-ads-detection, shared utils (detection-utils, result-factory), default config, and type definitions.
    • detector-service.js: Orchestrates detections per request and optional continuous monitoring via callbacks.
  • Features:
    • features/web-interference-detection.js: New content feature enabling on-demand detection (detectInterference) and continuous monitoring (startInterferenceMonitoring), emitting interferenceDetected/interferenceChanged.
    • features/broker-protection.js: Integrates detection via createWebInterferenceService, adds detectInterference handler and emits interferenceDetected/interferenceDetectionError.
  • Utilities:
    • error-utils.js: Adds safeCall helper.
  • Config/Types:
    • default-config.js: Default interference configuration (bot, fraud, YouTube ads).
    • types/*.js: API and detection type definitions.

Written by Cursor Bugbot for commit 5e9d02f. This will update automatically on new commits. Configure here.

@madblex madblex requested review from a team as code owners November 6, 2025 16:42
@github-actions
Copy link

github-actions bot commented Nov 6, 2025

Temporary Branch Update

The temporary branch has been updated with the latest changes. Below are the details:

Please use the above install command to update to the latest version.

@netlify
Copy link

netlify bot commented Nov 6, 2025

Deploy Preview for content-scope-scripts failed.

Name Link
🔨 Latest commit 5e9d02f
🔍 Latest deploy log https://app.netlify.com/projects/content-scope-scripts/deploys/690ccfe85521e10008df863b

@github-actions
Copy link

github-actions bot commented Nov 6, 2025

[Beta] Generated file diff

Time updated: Thu, 06 Nov 2025 16:43:18 GMT

Android
    - android/autofillImport.js
  • android/brokerProtection.js

File has changed

Apple
    - apple/contentScopeIsolated.js

File has changed

Integration
    - integration/contentScope.js

File has changed

Windows
    - windows/contentScope.js

File has changed

if (!this.root) {
setTimeout(() => this.start(), 500);
return;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Memory Leak: Unstored Timeout Causes Repeated Retries

Memory leak: When findRoot() returns null, setTimeout schedules a retry but the timeout ID is not stored. If stop() is called before the root is found, the timeout will still fire and call start() again, potentially creating new intervals that can never be cleaned up. The timeout should be stored in a class property and cleared in the stop() method.

Fix in Cursor Fix in Web

const { status, selectors, textPatterns, textSources } = statusConfig;
const hasMatch = matchesSelectors(selectors) || matchesTextPatterns(document.body, textPatterns, textSources);
return hasMatch ? status : null;
})?.status || null
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Fragile find() callback returning non-boolean value

Incorrect find() callback logic: The callback returns hasMatch ? status : null where it should return a boolean. While this works by accident (returning a truthy string causes find() to stop), the logic is confusing and fragile. The callback should return hasMatch directly, making the code: statusSelectors.find((statusConfig) => { ... return hasMatch; })?.status || null.

Fix in Cursor Fix in Web


cleanup() {
this.activeDetections.forEach((detection) => detection.stop());
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Memory leak from uncleared detections array

The cleanup() method calls stop() on all activeDetections but doesn't clear the array afterward. This means the array retains references to stopped detections, preventing garbage collection and causing the array to grow unbounded across multiple detect() calls. Should add this.activeDetections = []; after the forEach.

Fix in Cursor Fix in Web

*/

/**
* @typedef {'cloudflare' | 'hcaptcha'} VendorName
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can all of these just be defined with the code that makes it rather than a 'types' file? Often these can just be exported js constants with lighterweight annotations or none.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be any of that, not holding any strong preference; jsdoc is pretty hard to read also 😅

* @param {string[]} [selectors]
* @returns {boolean}
*/
export function checkSelectors(selectors) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect a bunch of these already exist (either as part of features or already in utils). Ask AI if it can find any :).

querySelectors are usually faster just running once and concatting to find any of them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good shout!

* @returns {TypeDetectionResult}
*/
detect() {
const root = this.findRoot();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this whole class is generic enough to work for any ad detection, is that the case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It did cross my mind but then I'd have to "make it work" from the beginning for PIR as well, where we do not actually need this level of functionality, hence the 3rd goal in the description "The service architecture intentionally avoids over-constraining detector implementations. We will revisit this based on what patterns emerge."

Now that @jdorweiler is taking over and he will need the more complex detections, it may be wise to try make it generic enough and have a single detector or a single base detector that can be extended with minor custom stuff.

@@ -0,0 +1,165 @@
# Web Interference Detection Service

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering instead of minting a whole new services/ directory just having these as injected/src/features/web-interference-detection/ that broker-protection imports is good enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd be creating an artificial dependency between 2 features. TBH I don't know if we already have stuff like this in the code already, but theoretically, I don't think features should depend on each other. Happy to defer to you since you know this arch better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants