From aca240d6dad3ed1e11c89022d307e34bc9d68376 Mon Sep 17 00:00:00 2001 From: Omar Alaaeldein Date: Wed, 12 Aug 2026 12:02:38 -0400 Subject: [PATCH 1/3] Migrate to Chrome Manifest V3 (hybrid DNR + scripting engine) --- background.js | 24 +++ claude.md | 179 +++++++++++++++++++ clearurls.js | 356 ++++++++++++++++++++++++------------- core_js/badgedHandler.js | 4 +- core_js/cleaning_tool.js | 20 +-- core_js/context_menu.js | 86 ++++----- core_js/eTagFilter.js | 125 ++++++------- core_js/google_link_fix.js | 119 +++++-------- core_js/historyListener.js | 73 ++++---- core_js/message_handler.js | 28 +-- core_js/storage.js | 109 ++++++++---- core_js/tools.js | 21 +-- core_js/watchdog.js | 31 ++-- core_js/yandex_link_fix.js | 105 +++++------ manifest.json | 61 +++---- 15 files changed, 818 insertions(+), 523 deletions(-) create mode 100644 background.js create mode 100644 claude.md diff --git a/background.js b/background.js new file mode 100644 index 00000000..e7e9544a --- /dev/null +++ b/background.js @@ -0,0 +1,24 @@ +/* + * ClearURLs - Manifest V3 Service Worker Entry Point + * Loads all background scripts via importScripts(). + */ +try { + importScripts( + 'browser-polyfill.js', + 'core_js/utils/Multimap.js', + 'core_js/utils/URLHashParams.js', + 'core_js/message_handler.js', + 'external_js/ip-range-check.js', + 'core_js/tools.js', + 'core_js/badgedHandler.js', + 'core_js/pureCleaning.js', + 'core_js/context_menu.js', + 'core_js/historyListener.js', + 'clearurls.js', + 'core_js/storage.js', + 'core_js/watchdog.js', + 'core_js/eTagFilter.js' + ); +} catch (e) { + console.error('[ClearURLs] Failed to load background scripts:', e); +} diff --git a/claude.md b/claude.md new file mode 100644 index 00000000..451171ff --- /dev/null +++ b/claude.md @@ -0,0 +1,179 @@ +# ClearURLs — Chrome Manifest V3 Migration Guide + +> **Status: ✅ Migration Complete** — All files have been migrated from MV2 to MV3. + +## Project Overview + +**ClearURLs** is a browser extension that removes tracking parameters and fields from URLs to protect user privacy. It intercepts web requests, strips tracking query parameters (like `utm_source`, `fbclid`, etc.), blocks known tracking domains, neutralizes ETag-based tracking, and fixes Google/Yandex search result link hijacking. + +--- + +## Architecture Overview + +``` +manifest.json — Extension manifest (MV3) +background.js — Service worker entry point (NEW - loads all scripts via importScripts) +browser-polyfill.js — webextension-polyfill (Firefox/Chrome compat layer) +clearurls.js — Core URL cleaning engine + declarativeNetRequest rule builder +core_js/ + storage.js — Storage abstraction, app bootstrap (genesis()) + tools.js — Utility functions (i18n, icons, badges, hashing) + message_handler.js — IPC: explicit dispatch map (no window dependency) + badgedHandler.js — Per-tab badge counter management + pureCleaning.js — Standalone URL cleaning (for context menu/tools) + context_menu.js — "Copy clean link" context menu (uses chrome.scripting) + historyListener.js — SPA history.replaceState URL cleaning (uses chrome.scripting) + watchdog.js — Periodic self-test (uses chrome.alarms) + eTagFilter.js — ETag header removal via declarativeNetRequest + popup.js — Popup UI controller + settings.js — Settings page controller + log.js — Log viewer controller + cleaning_tool.js — Manual URL cleaning tool controller (async bug fixed) + siteBlockedAlert.js — Blocked site warning page controller + google_link_fix.js — Content script: Google search link fix (MAIN world) + yandex_link_fix.js — Content script: Yandex search link fix (MAIN world) + write_version.js — Injects version string into HTML pages + utils/ + Multimap.js — Multimap data structure (pure JS) + URLHashParams.js — URL fragment parameter parser (pure JS) +``` + +--- + +## Changes Made (Summary) + +### manifest.json +- `browser_action` → `action` (removed `browser_style`) +- `background.scripts` → `background.service_worker: "background.js"` +- `content_security_policy` string → object format +- `` moved from `permissions` to `host_permissions` +- Removed `webRequest`, `webRequestBlocking` permissions +- Added `declarativeNetRequest`, `declarativeNetRequestFeedback`, `scripting`, `alarms` +- Added `"world": "MAIN"` to Google and Yandex content scripts +- Removed `browser_specific_settings` (Chrome-only build) +- Added `web_accessible_resources`, `minimum_chrome_version: "120"` +- Removed `include_globs` (incompatible with MAIN world) + +### background.js (NEW) +- Service worker entry point using `importScripts()` to load all background scripts + +### clearurls.js +- Removed `browser.webRequest.onBeforeRequest.addListener(..., ["blocking"])` +- Removed `clearUrl()`, `promise()`, `isDataURL()` (MV2 webRequest callbacks) +- Added `buildDeclarativeNetRequestRules()` — converts provider rules to DNR dynamic rules: + - Query parameter removal → `redirect` + `queryTransform.removeParams` + - Domain blocking → `block` rules + - URL redirections → `redirect` + `regexFilter`/`regexSubstitution` + - Raw rules → `redirect` + `regexFilter` + - Ping blocking → `block` for ping resource type +- Added `chrome.declarativeNetRequest.onRuleMatchedDebug` listener for statistics +- Updated all `getOrDefault()` calls to standalone function (no prototype pollution) +- Preserved `Provider` class and `removeFieldsFormURL` for pureCleaning/context menu + +### core_js/tools.js +- `browser.browserAction.*` → `browser.action.*` +- Removed Firefox-only `setBadgeTextColor` call +- `getBrowser()` rewritten (removed `InstallTrigger` check) +- `Object.prototype.getOrDefault` → standalone `getOrDefault(obj, key, default)` function + +### core_js/message_handler.js +- Replaced `window[request.function]` with explicit dispatch map (`messageHandlers`) +- Added `registerMessageHandler(name, fn)` for safe function registration + +### core_js/badgedHandler.js +- `browser.browserAction.setBadgeText` → `browser.action.setBadgeText` + +### core_js/context_menu.js +- `browser.tabs.executeScript` → `chrome.scripting.executeScript` with `func`+`args` +- Moved `onClicked` listener to top level for service worker compatibility +- Uses `navigator.clipboard.writeText()` with fallback + +### core_js/historyListener.js +- `browser.tabs.executeScript` → `chrome.scripting.executeScript` with `func`+`args` +- Moved `webNavigation.onHistoryStateUpdated` listener to top level +- Settings check moved inside listener callback + +### core_js/watchdog.js +- `setInterval(60000)` → `chrome.alarms.create("clearurls-watchdog", {periodInMinutes: 1})` +- Uses `chrome.alarms.onAlarm` listener + +### core_js/eTagFilter.js +- `browser.webRequest.onHeadersReceived` blocking → `chrome.declarativeNetRequest.updateDynamicRules` +- ETag headers are now removed (not replaced with random values) +- Uses reserved rule ID 99999 for the ETag rule +- `setupETagFilter()` called from genesis() after storage loads + +### core_js/storage.js +- `deferSaveOnDisk()` timeout reduced from 30s to 5s for service worker safety +- Added `ensureStorageLoaded()` for service worker re-initialization +- Added `storageInitialized` / `storageInitPromise` state tracking +- All message handlers registered via `registerMessageHandler()` at load time +- `genesis()` uses `ensureStorageLoaded()` instead of direct `browser.storage.local.get()` +- Calls `setupETagFilter()` after storage initialization + +### core_js/cleaning_tool.js +- Fixed async race condition bug (global `var i` in for loop with async callbacks) +- Replaced with `Promise.all()` + `map()` pattern +- Removed unnecessary global variables + +### core_js/google_link_fix.js +- Removed `