diff --git a/.gitignore b/.gitignore index e2e5dee31f..6f27779f86 100755 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ public/css/*.* build/firefox build/chrome build/chrome-mv3 +build/safari build/test test/background.js integration-test/artifacts/ @@ -21,6 +22,7 @@ shared/content-scope-scripts/ unit-test/data/reference-tests/ shared/data/smarter_encryption.txt shared/data/bundled/smarter-encryption-rules.json +shared/data/bundled/tds.json /test-results/ /playwright-report/ /playwright/.cache/ diff --git a/Makefile b/Makefile index 906a9fe3a8..5290a42c80 100755 --- a/Makefile +++ b/Makefile @@ -28,8 +28,17 @@ MAKE = make -j4 $(type) browser=$(browser) type=$(type) watch: while true; do $(MAKE) -q || $(MAKE); sleep 1; done +safari: dev $(BUILD_DIR)/data/bundled/tds-rules.json + rm -rf browsers/safari/Shared\ \(Extension\)/Resources/* + cp -r $(BUILD_DIR)/ browsers/safari/safari-mv3/Shared\ \(Extension\)/Resources/ .PHONY: release dev +$(BUILD_DIR)/data/bundled/tds-rules.json: $(BUILD_DIR)/data/bundled/tds.json $(BUILD_DIR)/data/surrogates.txt + node scripts/buildSafariBlocklist.mjs $< $(SURROGATES_DIR) `dirname $@` + +$(BUILD_DIR)/data/bundled/tds.json: + curl https://staticcdn.duckduckgo.com/trackerblocking/v4/tds.json > $@ + ###--- Unit tests ---### unit-test: build/test/background.js build/test/ui.js build/test/shared-utils.js $(KARMA) start karma.conf.js @@ -137,14 +146,25 @@ SURROGATES_DIR = node_modules/@duckduckgo/tracker-surrogates/surrogates BUILD_FOLDERS = $(BUILD_DIR)/public/js/content-scripts $(BUILD_DIR)/public/css BROWSER_TYPE = $(browser) COPY_DIRS = $(BUILD_DIR)/manifest.json +# Specify the set of scripts for the extension background +BACKGROUND_JS = shared/js/background/background.js +CSS_SCRIPT = $(browser) +ifeq ($(type), dev) + BACKGROUND_JS := shared/js/background/debug.js $(BACKGROUND_JS) +endif +ifeq ($(browser), safari) + BACKGROUND_JS := shared/js/background/safari.js + BROWSER_TYPE := chrome + CSS_SCRIPT := chrome-mv3 +endif ifeq ($(browser),chrome-mv3) BROWSER_TYPE := chrome COPY_DIRS += $(BUILD_DIR)/managed-schema.json endif ## Copy tasks: Copying resources that don't need and compiling -$(BUILD_DIR)/manifest.json: browsers/$(browser)/* - cp -r browsers/$(browser)/* $(BUILD_DIR) +$(BUILD_DIR)/manifest.json: browsers/$(browser)/manifest.json + cp -r $< $@ build/chrome-mv3/$(type)/managed-schema.json: browsers/chrome/managed-schema.json cp $< $@ @@ -182,11 +202,6 @@ copy-autofill: $(BUILD_DIR)/public/js/content-scripts/autofill.js $(BUILD_DIR)/p copy: $(COPY_DIRS) $(BUILD_DIR)/_locales $(BUILD_DIR)/data $(BUILD_DIR)/dashboard $(BUILD_DIR)/web_accessible_resources $(BUILD_DIR)/data/surrogates.txt $(BUILD_DIR)/public/font copy-autofill ##--- Build targets ---# -# Specify the set of scripts for the extension background -BACKGROUND_JS = shared/js/background/background.js -ifeq ($(type), dev) - BACKGROUND_JS := shared/js/background/debug.js $(BACKGROUND_JS) -endif JS_BUNDLES = background.js base.js inject.js content-scripts/content-scope-messaging.js feedback.js options.js devtools-panel.js list-editor.js newtab.js js: $(addprefix $(BUILD_DIR)/public/js/, $(JS_BUNDLES)) @@ -196,7 +211,7 @@ $(BUILD_DIR)/public/js/background.js: $(SOURCE_FILES) $(BROWSERIFY) $(BACKGROUND_JS) -o $@ $(BUILD_DIR)/public/js/content-scripts/content-scope-messaging.js: shared/js/content-scripts/content-scope-messaging.js - cp $< $@ + $(BROWSERIFY) $< > $@ ## Extension UI/Devtools scripts $(BUILD_DIR)/public/js/base.js: $(SOURCE_FILES) @@ -222,7 +237,7 @@ $(BUILD_DIR)/public/js/newtab.js: $(SOURCE_FILES) shared/data/bundled/tracker-lookup.json: node scripts/bundleTrackers.mjs -$(BUILD_DIR)/public/js/inject.js: node_modules/@duckduckgo/content-scope-scripts/build/$(browser)/inject.js shared/data/bundled/tracker-lookup.json shared/data/bundled/extension-config.json +$(BUILD_DIR)/public/js/inject.js: node_modules/@duckduckgo/content-scope-scripts/build/$(CSS_SCRIPT)/inject.js shared/data/bundled/tracker-lookup.json shared/data/bundled/extension-config.json node scripts/bundleContentScopeScripts.mjs $@ $^ # SASS diff --git a/browsers/safari/manifest.json b/browsers/safari/manifest.json new file mode 100644 index 0000000000..f9a2f808da --- /dev/null +++ b/browsers/safari/manifest.json @@ -0,0 +1,86 @@ +{ + "name": "__MSG_appName__", + "description": "__MSG_appDesc__", + "default_locale": "en", + "version": "2023.2.17", + "icons": { + "16": "img/icon_16.png", + "48": "img/icon_48.png", + "128": "img/icon_128.png" + }, + "manifest_version": 3, + "action": { + "default_popup": "dashboard/html/browser.html", + "default_icon": "img/icon_browser_action.png" + }, + "options_page": "html/options.html", + "background": { + "service_worker": "public/js/background.js" + }, + "content_scripts": [ + { + "matches": [ + "" + ], + "match_about_blank": true, + "all_frames": true, + "css": [ + "public/css/noatb.css" + ], + "run_at": "document_start" + }, + { + "js": [ + "public/js/content-scripts/autofill.js" + ], + "css": [ + "public/css/autofill-host-styles.css" + ], + "matches": [ + "" + ], + "all_frames": true, + "run_at": "document_start" + } + ], + "permissions": [ + "activeTab", + "alarms", + "contextMenus", + "declarativeNetRequest", + "declarativeNetRequestFeedback", + "declarativeNetRequestWithHostAccess", + "scripting", + "storage", + "tabs", + "webNavigation", + "cookies" + ], + "host_permissions": [ + "https://*.duckduckgo.com/*", + "*://*/*" + ], + "web_accessible_resources": [ + { + "resources": [ + "/web_accessible_resources/*", + "/img/logo-small.svg", + "/public/css/autofill.css", + "/public/font/*", + "/html/tracker-stats.html" + ], + "matches": [ + "" + ] + } + ], + "declarative_net_request": { + "rule_resources": [ + { + "id": "tds2", + "enabled": true, + "path": "data/bundled/tds-rules.json" + } + ] + } +} diff --git a/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json b/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000000..eb87897008 --- /dev/null +++ b/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json b/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..532cd729c6 --- /dev/null +++ b/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,63 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/Contents.json b/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json b/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json new file mode 100644 index 0000000000..a19a549220 --- /dev/null +++ b/browsers/safari/safari-mv3/Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json @@ -0,0 +1,20 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/browsers/safari/safari-mv3/Shared (App)/Base.lproj/Main.html b/browsers/safari/safari-mv3/Shared (App)/Base.lproj/Main.html new file mode 100644 index 0000000000..9ec50ef236 --- /dev/null +++ b/browsers/safari/safari-mv3/Shared (App)/Base.lproj/Main.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + safari-mv3 Icon +

You can turn on safari-mv3’s Safari extension in Settings.

+

You can turn on safari-mv3’s extension in Safari Extensions preferences.

+

safari-mv3’s extension is currently on. You can turn it off in Safari Extensions preferences.

+

safari-mv3’s extension is currently off. You can turn it on in Safari Extensions preferences.

+ + + diff --git a/browsers/safari/safari-mv3/Shared (App)/Resources/Icon.png b/browsers/safari/safari-mv3/Shared (App)/Resources/Icon.png new file mode 100644 index 0000000000..423b491de9 Binary files /dev/null and b/browsers/safari/safari-mv3/Shared (App)/Resources/Icon.png differ diff --git a/browsers/safari/safari-mv3/Shared (App)/Resources/Script.js b/browsers/safari/safari-mv3/Shared (App)/Resources/Script.js new file mode 100644 index 0000000000..4f1174c945 --- /dev/null +++ b/browsers/safari/safari-mv3/Shared (App)/Resources/Script.js @@ -0,0 +1,24 @@ +function show(platform, enabled, useSettingsInsteadOfPreferences) { + document.body.classList.add(`platform-${platform}`); + + if (useSettingsInsteadOfPreferences) { + document.getElementsByClassName('platform-mac state-on')[0].innerText = "safari-mv3’s extension is currently on. You can turn it off in the Extensions section of Safari Settings."; + document.getElementsByClassName('platform-mac state-off')[0].innerText = "safari-mv3’s extension is currently off. You can turn it on in the Extensions section of Safari Settings."; + document.getElementsByClassName('platform-mac state-unknown')[0].innerText = "You can turn on safari-mv3’s extension in the Extensions section of Safari Settings."; + document.getElementsByClassName('platform-mac open-preferences')[0].innerText = "Quit and Open Safari Settings…"; + } + + if (typeof enabled === "boolean") { + document.body.classList.toggle(`state-on`, enabled); + document.body.classList.toggle(`state-off`, !enabled); + } else { + document.body.classList.remove(`state-on`); + document.body.classList.remove(`state-off`); + } +} + +function openPreferences() { + webkit.messageHandlers.controller.postMessage("open-preferences"); +} + +document.querySelector("button.open-preferences").addEventListener("click", openPreferences); diff --git a/browsers/safari/safari-mv3/Shared (App)/Resources/Style.css b/browsers/safari/safari-mv3/Shared (App)/Resources/Style.css new file mode 100644 index 0000000000..b6d06083df --- /dev/null +++ b/browsers/safari/safari-mv3/Shared (App)/Resources/Style.css @@ -0,0 +1,61 @@ +* { + -webkit-user-select: none; + -webkit-user-drag: none; + cursor: default; +} + +:root { + color-scheme: light dark; + + --spacing: 20px; +} + +html { + height: 100%; +} + +body { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + + gap: var(--spacing); + margin: 0 calc(var(--spacing) * 2); + height: 100%; + + font: -apple-system-short-body; + text-align: center; +} + +body:not(.platform-mac, .platform-ios) :is(.platform-mac, .platform-ios) { + display: none; +} + +body.platform-ios .platform-mac { + display: none; +} + +body.platform-mac .platform-ios { + display: none; +} + +body.platform-ios .platform-mac { + display: none; +} + +body:not(.state-on, .state-off) :is(.state-on, .state-off) { + display: none; +} + +body.state-on :is(.state-off, .state-unknown) { + display: none; +} + +body.state-off :is(.state-on, .state-unknown) { + display: none; +} + +button { + font-size: 1em; +} diff --git a/browsers/safari/safari-mv3/Shared (App)/ViewController.swift b/browsers/safari/safari-mv3/Shared (App)/ViewController.swift new file mode 100644 index 0000000000..e155fe325c --- /dev/null +++ b/browsers/safari/safari-mv3/Shared (App)/ViewController.swift @@ -0,0 +1,81 @@ +// +// ViewController.swift +// Shared (App) +// +// Created by Sam Macbeth on 07.03.23. +// + +import WebKit + +#if os(iOS) +import UIKit +typealias PlatformViewController = UIViewController +#elseif os(macOS) +import Cocoa +import SafariServices +typealias PlatformViewController = NSViewController +#endif + +let extensionBundleIdentifier = "com.duckduckgo.safari-mv3.Extension" + +class ViewController: PlatformViewController, WKNavigationDelegate, WKScriptMessageHandler { + + @IBOutlet var webView: WKWebView! + + override func viewDidLoad() { + super.viewDidLoad() + + self.webView.navigationDelegate = self + +#if os(iOS) + self.webView.scrollView.isScrollEnabled = false +#endif + + self.webView.configuration.userContentController.add(self, name: "controller") + + self.webView.loadFileURL(Bundle.main.url(forResource: "Main", withExtension: "html")!, allowingReadAccessTo: Bundle.main.resourceURL!) + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { +#if os(iOS) + webView.evaluateJavaScript("show('ios')") +#elseif os(macOS) + webView.evaluateJavaScript("show('mac')") + + SFSafariExtensionManager.getStateOfSafariExtension(withIdentifier: extensionBundleIdentifier) { (state, error) in + guard let state = state, error == nil else { + // Insert code to inform the user that something went wrong. + return + } + + DispatchQueue.main.async { + if #available(macOS 13, *) { + webView.evaluateJavaScript("show('mac', \(state.isEnabled), true)") + } else { + webView.evaluateJavaScript("show('mac', \(state.isEnabled), false)") + } + } + } +#endif + } + + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { +#if os(macOS) + if (message.body as! String != "open-preferences") { + return; + } + + SFSafariApplication.showPreferencesForExtension(withIdentifier: extensionBundleIdentifier) { error in + guard error == nil else { + // Insert code to inform the user that something went wrong. + return + } + + DispatchQueue.main.async { + NSApplication.shared.terminate(nil) + } + } +#endif + } + +} diff --git a/browsers/safari/safari-mv3/Shared (Extension)/SafariWebExtensionHandler.swift b/browsers/safari/safari-mv3/Shared (Extension)/SafariWebExtensionHandler.swift new file mode 100644 index 0000000000..90b559d962 --- /dev/null +++ b/browsers/safari/safari-mv3/Shared (Extension)/SafariWebExtensionHandler.swift @@ -0,0 +1,26 @@ +// +// SafariWebExtensionHandler.swift +// Shared (Extension) +// +// Created by Sam Macbeth on 07.03.23. +// + +import SafariServices +import os.log + +let SFExtensionMessageKey = "message" + +class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { + + func beginRequest(with context: NSExtensionContext) { + let item = context.inputItems[0] as! NSExtensionItem + let message = item.userInfo?[SFExtensionMessageKey] + os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", message as! CVarArg) + + let response = NSExtensionItem() + response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ] + + context.completeRequest(returningItems: [response], completionHandler: nil) + } + +} diff --git a/browsers/safari/safari-mv3/iOS (App)/AppDelegate.swift b/browsers/safari/safari-mv3/iOS (App)/AppDelegate.swift new file mode 100644 index 0000000000..6ab6bc556e --- /dev/null +++ b/browsers/safari/safari-mv3/iOS (App)/AppDelegate.swift @@ -0,0 +1,24 @@ +// +// AppDelegate.swift +// iOS (App) +// +// Created by Sam Macbeth on 07.03.23. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + +} diff --git a/browsers/safari/safari-mv3/iOS (App)/Base.lproj/LaunchScreen.storyboard b/browsers/safari/safari-mv3/iOS (App)/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..620a70cbaf --- /dev/null +++ b/browsers/safari/safari-mv3/iOS (App)/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/browsers/safari/safari-mv3/iOS (App)/Base.lproj/Main.storyboard b/browsers/safari/safari-mv3/iOS (App)/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..618dfce18f --- /dev/null +++ b/browsers/safari/safari-mv3/iOS (App)/Base.lproj/Main.storyboard @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/browsers/safari/safari-mv3/iOS (App)/Info.plist b/browsers/safari/safari-mv3/iOS (App)/Info.plist new file mode 100644 index 0000000000..dd3c9afdae --- /dev/null +++ b/browsers/safari/safari-mv3/iOS (App)/Info.plist @@ -0,0 +1,25 @@ + + + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/browsers/safari/safari-mv3/iOS (App)/SceneDelegate.swift b/browsers/safari/safari-mv3/iOS (App)/SceneDelegate.swift new file mode 100644 index 0000000000..b7965bef5d --- /dev/null +++ b/browsers/safari/safari-mv3/iOS (App)/SceneDelegate.swift @@ -0,0 +1,18 @@ +// +// SceneDelegate.swift +// iOS (App) +// +// Created by Sam Macbeth on 07.03.23. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + guard let _ = (scene as? UIWindowScene) else { return } + } + +} diff --git a/browsers/safari/safari-mv3/iOS (Extension)/Info.plist b/browsers/safari/safari-mv3/iOS (Extension)/Info.plist new file mode 100644 index 0000000000..9ee504dc51 --- /dev/null +++ b/browsers/safari/safari-mv3/iOS (Extension)/Info.plist @@ -0,0 +1,13 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.Safari.web-extension + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler + + + diff --git a/browsers/safari/safari-mv3/macOS (App)/AppDelegate.swift b/browsers/safari/safari-mv3/macOS (App)/AppDelegate.swift new file mode 100644 index 0000000000..876aa42c16 --- /dev/null +++ b/browsers/safari/safari-mv3/macOS (App)/AppDelegate.swift @@ -0,0 +1,21 @@ +// +// AppDelegate.swift +// macOS (App) +// +// Created by Sam Macbeth on 07.03.23. +// + +import Cocoa + +@main +class AppDelegate: NSObject, NSApplicationDelegate { + + func applicationDidFinishLaunching(_ notification: Notification) { + // Override point for customization after application launch. + } + + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + +} diff --git a/browsers/safari/safari-mv3/macOS (App)/Base.lproj/Main.storyboard b/browsers/safari/safari-mv3/macOS (App)/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..912f277fad --- /dev/null +++ b/browsers/safari/safari-mv3/macOS (App)/Base.lproj/Main.storyboard @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/browsers/safari/safari-mv3/macOS (App)/safari-mv3.entitlements b/browsers/safari/safari-mv3/macOS (App)/safari-mv3.entitlements new file mode 100644 index 0000000000..625af03d99 --- /dev/null +++ b/browsers/safari/safari-mv3/macOS (App)/safari-mv3.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + com.apple.security.network.client + + + diff --git a/browsers/safari/safari-mv3/macOS (Extension)/Info.plist b/browsers/safari/safari-mv3/macOS (Extension)/Info.plist new file mode 100644 index 0000000000..9ee504dc51 --- /dev/null +++ b/browsers/safari/safari-mv3/macOS (Extension)/Info.plist @@ -0,0 +1,13 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.Safari.web-extension + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler + + + diff --git a/browsers/safari/safari-mv3/macOS (Extension)/safari-mv3.entitlements b/browsers/safari/safari-mv3/macOS (Extension)/safari-mv3.entitlements new file mode 100644 index 0000000000..f2ef3ae026 --- /dev/null +++ b/browsers/safari/safari-mv3/macOS (Extension)/safari-mv3.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + + diff --git a/browsers/safari/safari-mv3/safari-mv3.xcodeproj/project.pbxproj b/browsers/safari/safari-mv3/safari-mv3.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..adfd49aa08 --- /dev/null +++ b/browsers/safari/safari-mv3/safari-mv3.xcodeproj/project.pbxproj @@ -0,0 +1,966 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + B30595CA29B743CD00D54F56 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30595C929B743CD00D54F56 /* AppDelegate.swift */; }; + B30595CC29B743CD00D54F56 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30595CB29B743CD00D54F56 /* SceneDelegate.swift */; }; + B30595CF29B743CD00D54F56 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B30595CD29B743CD00D54F56 /* LaunchScreen.storyboard */; }; + B30595D229B743CD00D54F56 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B30595D029B743CD00D54F56 /* Main.storyboard */; }; + B30595DB29B743CD00D54F56 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30595DA29B743CD00D54F56 /* AppDelegate.swift */; }; + B30595DE29B743CD00D54F56 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B30595DC29B743CD00D54F56 /* Main.storyboard */; }; + B30595E529B743CD00D54F56 /* safari-mv3 Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = B30595E429B743CD00D54F56 /* safari-mv3 Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + B30595EF29B743CD00D54F56 /* safari-mv3 Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = B30595EE29B743CD00D54F56 /* safari-mv3 Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + B30595F529B743CD00D54F56 /* Main.html in Resources */ = {isa = PBXBuildFile; fileRef = B30595B029B743CC00D54F56 /* Main.html */; }; + B30595F629B743CD00D54F56 /* Main.html in Resources */ = {isa = PBXBuildFile; fileRef = B30595B029B743CC00D54F56 /* Main.html */; }; + B30595F729B743CD00D54F56 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = B30595B229B743CC00D54F56 /* Icon.png */; }; + B30595F829B743CD00D54F56 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = B30595B229B743CC00D54F56 /* Icon.png */; }; + B30595F929B743CD00D54F56 /* Style.css in Resources */ = {isa = PBXBuildFile; fileRef = B30595B329B743CC00D54F56 /* Style.css */; }; + B30595FA29B743CD00D54F56 /* Style.css in Resources */ = {isa = PBXBuildFile; fileRef = B30595B329B743CC00D54F56 /* Style.css */; }; + B30595FB29B743CD00D54F56 /* Script.js in Resources */ = {isa = PBXBuildFile; fileRef = B30595B429B743CC00D54F56 /* Script.js */; }; + B30595FC29B743CD00D54F56 /* Script.js in Resources */ = {isa = PBXBuildFile; fileRef = B30595B429B743CC00D54F56 /* Script.js */; }; + B30595FD29B743CD00D54F56 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30595B529B743CC00D54F56 /* ViewController.swift */; }; + B30595FE29B743CD00D54F56 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30595B529B743CC00D54F56 /* ViewController.swift */; }; + B30595FF29B743CD00D54F56 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B30595B629B743CD00D54F56 /* Assets.xcassets */; }; + B305960029B743CD00D54F56 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B30595B629B743CD00D54F56 /* Assets.xcassets */; }; + B305960129B743CD00D54F56 /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30595B829B743CD00D54F56 /* SafariWebExtensionHandler.swift */; }; + B305960229B743CD00D54F56 /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30595B829B743CD00D54F56 /* SafariWebExtensionHandler.swift */; }; + B305962B29B743FC00D54F56 /* html in Resources */ = {isa = PBXBuildFile; fileRef = B305962329B743FB00D54F56 /* html */; }; + B305962C29B743FC00D54F56 /* html in Resources */ = {isa = PBXBuildFile; fileRef = B305962329B743FB00D54F56 /* html */; }; + B305962D29B743FC00D54F56 /* dashboard in Resources */ = {isa = PBXBuildFile; fileRef = B305962429B743FB00D54F56 /* dashboard */; }; + B305962E29B743FC00D54F56 /* dashboard in Resources */ = {isa = PBXBuildFile; fileRef = B305962429B743FB00D54F56 /* dashboard */; }; + B305962F29B743FC00D54F56 /* img in Resources */ = {isa = PBXBuildFile; fileRef = B305962529B743FC00D54F56 /* img */; }; + B305963029B743FC00D54F56 /* img in Resources */ = {isa = PBXBuildFile; fileRef = B305962529B743FC00D54F56 /* img */; }; + B305963129B743FC00D54F56 /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = B305962629B743FC00D54F56 /* manifest.json */; }; + B305963229B743FC00D54F56 /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = B305962629B743FC00D54F56 /* manifest.json */; }; + B305963329B743FC00D54F56 /* data in Resources */ = {isa = PBXBuildFile; fileRef = B305962729B743FC00D54F56 /* data */; }; + B305963429B743FC00D54F56 /* data in Resources */ = {isa = PBXBuildFile; fileRef = B305962729B743FC00D54F56 /* data */; }; + B305963529B743FC00D54F56 /* public in Resources */ = {isa = PBXBuildFile; fileRef = B305962829B743FC00D54F56 /* public */; }; + B305963629B743FC00D54F56 /* public in Resources */ = {isa = PBXBuildFile; fileRef = B305962829B743FC00D54F56 /* public */; }; + B305963729B743FC00D54F56 /* _locales in Resources */ = {isa = PBXBuildFile; fileRef = B305962929B743FC00D54F56 /* _locales */; }; + B305963829B743FC00D54F56 /* _locales in Resources */ = {isa = PBXBuildFile; fileRef = B305962929B743FC00D54F56 /* _locales */; }; + B305963929B743FC00D54F56 /* web_accessible_resources in Resources */ = {isa = PBXBuildFile; fileRef = B305962A29B743FC00D54F56 /* web_accessible_resources */; }; + B305963A29B743FC00D54F56 /* web_accessible_resources in Resources */ = {isa = PBXBuildFile; fileRef = B305962A29B743FC00D54F56 /* web_accessible_resources */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + B30595E629B743CD00D54F56 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B30595AA29B743CC00D54F56 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B30595E329B743CD00D54F56; + remoteInfo = "safari-mv3 Extension (iOS)"; + }; + B30595F029B743CD00D54F56 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B30595AA29B743CC00D54F56 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B30595ED29B743CD00D54F56; + remoteInfo = "safari-mv3 Extension (macOS)"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + B305961829B743CD00D54F56 /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + B30595E529B743CD00D54F56 /* safari-mv3 Extension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; + B305961F29B743CD00D54F56 /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + B30595EF29B743CD00D54F56 /* safari-mv3 Extension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + B30595B129B743CC00D54F56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = Base; path = ../Base.lproj/Main.html; sourceTree = ""; }; + B30595B229B743CC00D54F56 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; + B30595B329B743CC00D54F56 /* Style.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = Style.css; sourceTree = ""; }; + B30595B429B743CC00D54F56 /* Script.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = Script.js; sourceTree = ""; }; + B30595B529B743CC00D54F56 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + B30595B629B743CD00D54F56 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B30595B829B743CD00D54F56 /* SafariWebExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariWebExtensionHandler.swift; sourceTree = ""; }; + B30595C629B743CD00D54F56 /* safari-mv3.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "safari-mv3.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + B30595C929B743CD00D54F56 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + B30595CB29B743CD00D54F56 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + B30595CE29B743CD00D54F56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + B30595D129B743CD00D54F56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + B30595D329B743CD00D54F56 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B30595D829B743CD00D54F56 /* safari-mv3.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "safari-mv3.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + B30595DA29B743CD00D54F56 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + B30595DD29B743CD00D54F56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + B30595DF29B743CD00D54F56 /* safari-mv3.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "safari-mv3.entitlements"; sourceTree = ""; }; + B30595E429B743CD00D54F56 /* safari-mv3 Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "safari-mv3 Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + B30595E929B743CD00D54F56 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B30595EE29B743CD00D54F56 /* safari-mv3 Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "safari-mv3 Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + B30595F329B743CD00D54F56 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B30595F429B743CD00D54F56 /* safari-mv3.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "safari-mv3.entitlements"; sourceTree = ""; }; + B305962329B743FB00D54F56 /* html */ = {isa = PBXFileReference; lastKnownFileType = folder; path = html; sourceTree = ""; }; + B305962429B743FB00D54F56 /* dashboard */ = {isa = PBXFileReference; lastKnownFileType = folder; path = dashboard; sourceTree = ""; }; + B305962529B743FC00D54F56 /* img */ = {isa = PBXFileReference; lastKnownFileType = folder; path = img; sourceTree = ""; }; + B305962629B743FC00D54F56 /* manifest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = manifest.json; sourceTree = ""; }; + B305962729B743FC00D54F56 /* data */ = {isa = PBXFileReference; lastKnownFileType = folder; path = data; sourceTree = ""; }; + B305962829B743FC00D54F56 /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; }; + B305962929B743FC00D54F56 /* _locales */ = {isa = PBXFileReference; lastKnownFileType = folder; path = _locales; sourceTree = ""; }; + B305962A29B743FC00D54F56 /* web_accessible_resources */ = {isa = PBXFileReference; lastKnownFileType = folder; path = web_accessible_resources; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B30595C329B743CD00D54F56 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B30595D529B743CD00D54F56 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B30595E129B743CD00D54F56 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B30595EB29B743CD00D54F56 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B30595A929B743CC00D54F56 = { + isa = PBXGroup; + children = ( + B30595AE29B743CC00D54F56 /* Shared (App) */, + B30595B729B743CD00D54F56 /* Shared (Extension) */, + B30595C829B743CD00D54F56 /* iOS (App) */, + B30595D929B743CD00D54F56 /* macOS (App) */, + B30595E829B743CD00D54F56 /* iOS (Extension) */, + B30595F229B743CD00D54F56 /* macOS (Extension) */, + B30595C729B743CD00D54F56 /* Products */, + ); + sourceTree = ""; + }; + B30595AE29B743CC00D54F56 /* Shared (App) */ = { + isa = PBXGroup; + children = ( + B30595B529B743CC00D54F56 /* ViewController.swift */, + B30595B629B743CD00D54F56 /* Assets.xcassets */, + B30595AF29B743CC00D54F56 /* Resources */, + ); + path = "Shared (App)"; + sourceTree = ""; + }; + B30595AF29B743CC00D54F56 /* Resources */ = { + isa = PBXGroup; + children = ( + B30595B029B743CC00D54F56 /* Main.html */, + B30595B229B743CC00D54F56 /* Icon.png */, + B30595B329B743CC00D54F56 /* Style.css */, + B30595B429B743CC00D54F56 /* Script.js */, + ); + path = Resources; + sourceTree = ""; + }; + B30595B729B743CD00D54F56 /* Shared (Extension) */ = { + isa = PBXGroup; + children = ( + B30595B829B743CD00D54F56 /* SafariWebExtensionHandler.swift */, + B30595B929B743CD00D54F56 /* Resources */, + ); + path = "Shared (Extension)"; + sourceTree = ""; + }; + B30595B929B743CD00D54F56 /* Resources */ = { + isa = PBXGroup; + children = ( + B305962929B743FC00D54F56 /* _locales */, + B305962429B743FB00D54F56 /* dashboard */, + B305962729B743FC00D54F56 /* data */, + B305962329B743FB00D54F56 /* html */, + B305962529B743FC00D54F56 /* img */, + B305962629B743FC00D54F56 /* manifest.json */, + B305962829B743FC00D54F56 /* public */, + B305962A29B743FC00D54F56 /* web_accessible_resources */, + ); + path = Resources; + sourceTree = ""; + }; + B30595C729B743CD00D54F56 /* Products */ = { + isa = PBXGroup; + children = ( + B30595C629B743CD00D54F56 /* safari-mv3.app */, + B30595D829B743CD00D54F56 /* safari-mv3.app */, + B30595E429B743CD00D54F56 /* safari-mv3 Extension.appex */, + B30595EE29B743CD00D54F56 /* safari-mv3 Extension.appex */, + ); + name = Products; + sourceTree = ""; + }; + B30595C829B743CD00D54F56 /* iOS (App) */ = { + isa = PBXGroup; + children = ( + B30595C929B743CD00D54F56 /* AppDelegate.swift */, + B30595CB29B743CD00D54F56 /* SceneDelegate.swift */, + B30595CD29B743CD00D54F56 /* LaunchScreen.storyboard */, + B30595D029B743CD00D54F56 /* Main.storyboard */, + B30595D329B743CD00D54F56 /* Info.plist */, + ); + path = "iOS (App)"; + sourceTree = ""; + }; + B30595D929B743CD00D54F56 /* macOS (App) */ = { + isa = PBXGroup; + children = ( + B30595DA29B743CD00D54F56 /* AppDelegate.swift */, + B30595DC29B743CD00D54F56 /* Main.storyboard */, + B30595DF29B743CD00D54F56 /* safari-mv3.entitlements */, + ); + path = "macOS (App)"; + sourceTree = ""; + }; + B30595E829B743CD00D54F56 /* iOS (Extension) */ = { + isa = PBXGroup; + children = ( + B30595E929B743CD00D54F56 /* Info.plist */, + ); + path = "iOS (Extension)"; + sourceTree = ""; + }; + B30595F229B743CD00D54F56 /* macOS (Extension) */ = { + isa = PBXGroup; + children = ( + B30595F329B743CD00D54F56 /* Info.plist */, + B30595F429B743CD00D54F56 /* safari-mv3.entitlements */, + ); + path = "macOS (Extension)"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B30595C529B743CD00D54F56 /* safari-mv3 (iOS) */ = { + isa = PBXNativeTarget; + buildConfigurationList = B305961929B743CD00D54F56 /* Build configuration list for PBXNativeTarget "safari-mv3 (iOS)" */; + buildPhases = ( + B30595C229B743CD00D54F56 /* Sources */, + B30595C329B743CD00D54F56 /* Frameworks */, + B30595C429B743CD00D54F56 /* Resources */, + B305961829B743CD00D54F56 /* Embed Foundation Extensions */, + ); + buildRules = ( + ); + dependencies = ( + B30595E729B743CD00D54F56 /* PBXTargetDependency */, + ); + name = "safari-mv3 (iOS)"; + productName = "safari-mv3 (iOS)"; + productReference = B30595C629B743CD00D54F56 /* safari-mv3.app */; + productType = "com.apple.product-type.application"; + }; + B30595D729B743CD00D54F56 /* safari-mv3 (macOS) */ = { + isa = PBXNativeTarget; + buildConfigurationList = B305962029B743CD00D54F56 /* Build configuration list for PBXNativeTarget "safari-mv3 (macOS)" */; + buildPhases = ( + B30595D429B743CD00D54F56 /* Sources */, + B30595D529B743CD00D54F56 /* Frameworks */, + B30595D629B743CD00D54F56 /* Resources */, + B305961F29B743CD00D54F56 /* Embed Foundation Extensions */, + ); + buildRules = ( + ); + dependencies = ( + B30595F129B743CD00D54F56 /* PBXTargetDependency */, + ); + name = "safari-mv3 (macOS)"; + productName = "safari-mv3 (macOS)"; + productReference = B30595D829B743CD00D54F56 /* safari-mv3.app */; + productType = "com.apple.product-type.application"; + }; + B30595E329B743CD00D54F56 /* safari-mv3 Extension (iOS) */ = { + isa = PBXNativeTarget; + buildConfigurationList = B305961529B743CD00D54F56 /* Build configuration list for PBXNativeTarget "safari-mv3 Extension (iOS)" */; + buildPhases = ( + B30595E029B743CD00D54F56 /* Sources */, + B30595E129B743CD00D54F56 /* Frameworks */, + B30595E229B743CD00D54F56 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "safari-mv3 Extension (iOS)"; + productName = "safari-mv3 Extension (iOS)"; + productReference = B30595E429B743CD00D54F56 /* safari-mv3 Extension.appex */; + productType = "com.apple.product-type.app-extension"; + }; + B30595ED29B743CD00D54F56 /* safari-mv3 Extension (macOS) */ = { + isa = PBXNativeTarget; + buildConfigurationList = B305961C29B743CD00D54F56 /* Build configuration list for PBXNativeTarget "safari-mv3 Extension (macOS)" */; + buildPhases = ( + B30595EA29B743CD00D54F56 /* Sources */, + B30595EB29B743CD00D54F56 /* Frameworks */, + B30595EC29B743CD00D54F56 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "safari-mv3 Extension (macOS)"; + productName = "safari-mv3 Extension (macOS)"; + productReference = B30595EE29B743CD00D54F56 /* safari-mv3 Extension.appex */; + productType = "com.apple.product-type.app-extension"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B30595AA29B743CC00D54F56 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1420; + LastUpgradeCheck = 1420; + TargetAttributes = { + B30595C529B743CD00D54F56 = { + CreatedOnToolsVersion = 14.2; + }; + B30595D729B743CD00D54F56 = { + CreatedOnToolsVersion = 14.2; + }; + B30595E329B743CD00D54F56 = { + CreatedOnToolsVersion = 14.2; + }; + B30595ED29B743CD00D54F56 = { + CreatedOnToolsVersion = 14.2; + }; + }; + }; + buildConfigurationList = B30595AD29B743CC00D54F56 /* Build configuration list for PBXProject "safari-mv3" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B30595A929B743CC00D54F56; + productRefGroup = B30595C729B743CD00D54F56 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B30595C529B743CD00D54F56 /* safari-mv3 (iOS) */, + B30595D729B743CD00D54F56 /* safari-mv3 (macOS) */, + B30595E329B743CD00D54F56 /* safari-mv3 Extension (iOS) */, + B30595ED29B743CD00D54F56 /* safari-mv3 Extension (macOS) */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B30595C429B743CD00D54F56 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B30595F729B743CD00D54F56 /* Icon.png in Resources */, + B30595CF29B743CD00D54F56 /* LaunchScreen.storyboard in Resources */, + B30595F529B743CD00D54F56 /* Main.html in Resources */, + B30595FB29B743CD00D54F56 /* Script.js in Resources */, + B30595FF29B743CD00D54F56 /* Assets.xcassets in Resources */, + B30595D229B743CD00D54F56 /* Main.storyboard in Resources */, + B30595F929B743CD00D54F56 /* Style.css in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B30595D629B743CD00D54F56 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B30595F829B743CD00D54F56 /* Icon.png in Resources */, + B30595FA29B743CD00D54F56 /* Style.css in Resources */, + B30595DE29B743CD00D54F56 /* Main.storyboard in Resources */, + B30595FC29B743CD00D54F56 /* Script.js in Resources */, + B305960029B743CD00D54F56 /* Assets.xcassets in Resources */, + B30595F629B743CD00D54F56 /* Main.html in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B30595E229B743CD00D54F56 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B305963129B743FC00D54F56 /* manifest.json in Resources */, + B305962F29B743FC00D54F56 /* img in Resources */, + B305962B29B743FC00D54F56 /* html in Resources */, + B305963529B743FC00D54F56 /* public in Resources */, + B305962D29B743FC00D54F56 /* dashboard in Resources */, + B305963929B743FC00D54F56 /* web_accessible_resources in Resources */, + B305963729B743FC00D54F56 /* _locales in Resources */, + B305963329B743FC00D54F56 /* data in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B30595EC29B743CD00D54F56 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B305963229B743FC00D54F56 /* manifest.json in Resources */, + B305963029B743FC00D54F56 /* img in Resources */, + B305962C29B743FC00D54F56 /* html in Resources */, + B305963629B743FC00D54F56 /* public in Resources */, + B305962E29B743FC00D54F56 /* dashboard in Resources */, + B305963A29B743FC00D54F56 /* web_accessible_resources in Resources */, + B305963829B743FC00D54F56 /* _locales in Resources */, + B305963429B743FC00D54F56 /* data in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B30595C229B743CD00D54F56 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B30595FD29B743CD00D54F56 /* ViewController.swift in Sources */, + B30595CA29B743CD00D54F56 /* AppDelegate.swift in Sources */, + B30595CC29B743CD00D54F56 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B30595D429B743CD00D54F56 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B30595FE29B743CD00D54F56 /* ViewController.swift in Sources */, + B30595DB29B743CD00D54F56 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B30595E029B743CD00D54F56 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B305960129B743CD00D54F56 /* SafariWebExtensionHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B30595EA29B743CD00D54F56 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B305960229B743CD00D54F56 /* SafariWebExtensionHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + B30595E729B743CD00D54F56 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B30595E329B743CD00D54F56 /* safari-mv3 Extension (iOS) */; + targetProxy = B30595E629B743CD00D54F56 /* PBXContainerItemProxy */; + }; + B30595F129B743CD00D54F56 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B30595ED29B743CD00D54F56 /* safari-mv3 Extension (macOS) */; + targetProxy = B30595F029B743CD00D54F56 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + B30595B029B743CC00D54F56 /* Main.html */ = { + isa = PBXVariantGroup; + children = ( + B30595B129B743CC00D54F56 /* Base */, + ); + name = Main.html; + sourceTree = ""; + }; + B30595CD29B743CD00D54F56 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B30595CE29B743CD00D54F56 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + B30595D029B743CD00D54F56 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B30595D129B743CD00D54F56 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + B30595DC29B743CD00D54F56 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B30595DD29B743CD00D54F56 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + B305961329B743CD00D54F56 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + B305961429B743CD00D54F56 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + B305961629B743CD00D54F56 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = HKE973VLUW; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "iOS (Extension)/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "safari-mv3 Extension"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.duckduckgo.safari-mv3.Extension"; + PRODUCT_NAME = "safari-mv3 Extension"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + B305961729B743CD00D54F56 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = HKE973VLUW; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "iOS (Extension)/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "safari-mv3 Extension"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.duckduckgo.safari-mv3.Extension"; + PRODUCT_NAME = "safari-mv3 Extension"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B305961A29B743CD00D54F56 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = HKE973VLUW; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "iOS (App)/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "safari-mv3"; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + "-framework", + WebKit, + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.duckduckgo.safari-mv3"; + PRODUCT_NAME = "safari-mv3"; + SDKROOT = iphoneos; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + B305961B29B743CD00D54F56 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = HKE973VLUW; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "iOS (App)/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "safari-mv3"; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + "-framework", + WebKit, + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.duckduckgo.safari-mv3"; + PRODUCT_NAME = "safari-mv3"; + SDKROOT = iphoneos; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B305961D29B743CD00D54F56 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/safari-mv3.entitlements"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = HKE973VLUW; + ENABLE_HARDENED_RUNTIME = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "macOS (Extension)/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "safari-mv3 Extension"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.duckduckgo.safari-mv3.Extension"; + PRODUCT_NAME = "safari-mv3 Extension"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + B305961E29B743CD00D54F56 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/safari-mv3.entitlements"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = HKE973VLUW; + ENABLE_HARDENED_RUNTIME = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "macOS (Extension)/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "safari-mv3 Extension"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.duckduckgo.safari-mv3.Extension"; + PRODUCT_NAME = "safari-mv3 Extension"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + B305962129B743CD00D54F56 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "macOS (App)/safari-mv3.entitlements"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = HKE973VLUW; + ENABLE_HARDENED_RUNTIME = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = "safari-mv3"; + INFOPLIST_KEY_NSMainStoryboardFile = Main; + INFOPLIST_KEY_NSPrincipalClass = NSApplication; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + "-framework", + WebKit, + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.duckduckgo.safari-mv3"; + PRODUCT_NAME = "safari-mv3"; + SDKROOT = macosx; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + B305962229B743CD00D54F56 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "macOS (App)/safari-mv3.entitlements"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = HKE973VLUW; + ENABLE_HARDENED_RUNTIME = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = "safari-mv3"; + INFOPLIST_KEY_NSMainStoryboardFile = Main; + INFOPLIST_KEY_NSPrincipalClass = NSApplication; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + "-framework", + WebKit, + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.duckduckgo.safari-mv3"; + PRODUCT_NAME = "safari-mv3"; + SDKROOT = macosx; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B30595AD29B743CC00D54F56 /* Build configuration list for PBXProject "safari-mv3" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B305961329B743CD00D54F56 /* Debug */, + B305961429B743CD00D54F56 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B305961529B743CD00D54F56 /* Build configuration list for PBXNativeTarget "safari-mv3 Extension (iOS)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B305961629B743CD00D54F56 /* Debug */, + B305961729B743CD00D54F56 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B305961929B743CD00D54F56 /* Build configuration list for PBXNativeTarget "safari-mv3 (iOS)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B305961A29B743CD00D54F56 /* Debug */, + B305961B29B743CD00D54F56 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B305961C29B743CD00D54F56 /* Build configuration list for PBXNativeTarget "safari-mv3 Extension (macOS)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B305961D29B743CD00D54F56 /* Debug */, + B305961E29B743CD00D54F56 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B305962029B743CD00D54F56 /* Build configuration list for PBXNativeTarget "safari-mv3 (macOS)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B305962129B743CD00D54F56 /* Debug */, + B305962229B743CD00D54F56 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B30595AA29B743CC00D54F56 /* Project object */; +} diff --git a/browsers/safari/safari-mv3/safari-mv3.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/browsers/safari/safari-mv3/safari-mv3.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..919434a625 --- /dev/null +++ b/browsers/safari/safari-mv3/safari-mv3.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/browsers/safari/safari-mv3/safari-mv3.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/browsers/safari/safari-mv3/safari-mv3.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/browsers/safari/safari-mv3/safari-mv3.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/browsers/safari/safari-mv3/safari-mv3.xcodeproj/xcuserdata/sammacbeth.xcuserdatad/xcschemes/xcschememanagement.plist b/browsers/safari/safari-mv3/safari-mv3.xcodeproj/xcuserdata/sammacbeth.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000000..4ac96c9415 --- /dev/null +++ b/browsers/safari/safari-mv3/safari-mv3.xcodeproj/xcuserdata/sammacbeth.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,19 @@ + + + + + SchemeUserState + + safari-mv3 (iOS).xcscheme_^#shared#^_ + + orderHint + 0 + + safari-mv3 (macOS).xcscheme_^#shared#^_ + + orderHint + 1 + + + + diff --git a/scripts/buildSafariBlocklist.mjs b/scripts/buildSafariBlocklist.mjs new file mode 100644 index 0000000000..b566bee879 --- /dev/null +++ b/scripts/buildSafariBlocklist.mjs @@ -0,0 +1,21 @@ +import fs from 'fs/promises' +import path from 'path' +import { generateTdsRuleset } from '@duckduckgo/ddg2dnr/lib/tds.js' +import { convertDNRRuleset } from '../shared/js/background/safai-compat.mjs' + +(async () => { + const tdsPath = process.argv[2] + const surrogatesPath = process.argv[3] + const rulesPath = process.argv[4] + // Collect and merge surrogates from node_modules into web_accessible_resources + const availableSurrogates = await fs.readdir(surrogatesPath) + + // Fetch TDS, build ruleset, and convert to Safari compatible rules. + const tds = JSON.parse(await fs.readFile(tdsPath, { encoding: 'utf-8' })) + const { ruleset, allowingRulesByClickToLoadAction } = await generateTdsRuleset(tds, new Set(availableSurrogates), '/web_accessible_resources/', ({ regex }) => ({ isSupported: regex.indexOf('facebook') === 0 })) + const convertedRules = convertDNRRuleset(ruleset) + + // Write DNR blocklist to disk + await fs.writeFile(path.join(rulesPath, 'tds-rules.json'), JSON.stringify(convertedRules, undefined, 2)) + await fs.writeFile(path.join(rulesPath, 'ctl-allow-rules.json'), JSON.stringify(allowingRulesByClickToLoadAction, undefined, 2)) +})() diff --git a/shared/data/bundled/extension-config.json b/shared/data/bundled/extension-config.json index 4d56ecb145..0520598bcf 100644 --- a/shared/data/bundled/extension-config.json +++ b/shared/data/bundled/extension-config.json @@ -1,10 +1,10 @@ { "readme": "https://github.com/duckduckgo/privacy-configuration", - "version": 1677839118579, + "version": 1676546521995, "features": { "adClickAttribution": { "readme": "https://help.duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections/#3rd-party-tracker-loading-protection", - "state": "enabled", + "state": "disabled", "exceptions": [], "settings": { "linkFormats": [ @@ -94,7 +94,7 @@ "?amp" ] }, - "state": "enabled", + "state": "disabled", "hash": "8668c1396cf49ac18e2e057c48dac1a7" }, "autoconsent": { @@ -158,10 +158,6 @@ { "domain": "corporatefinanceinstitute.com", "reason": "CMP gets incorrectly handled / repeatedly opens tabs" - }, - { - "domain": "kicker.de", - "reason": "https://github.com/duckduckgo/autoconsent/issues/66" } ], "settings": { @@ -170,21 +166,17 @@ ] }, "state": "disabled", - "hash": "ffb4c255daefd46d2ae948b440ea2579" + "hash": "a097d7ccd20814348d1b3b89ef31e089" }, "autofill": { "exceptions": [ { "domain": "containerstore.com", "reason": "Generally poor UX - no username saved on signup, prompts for Duck address on 'forgot password'." - }, - { - "domain": "roll20.net", - "reason": "Performance issue for too many fields." } ], "state": "enabled", - "hash": "59c4bd9b8cee343c81da98bfe5d77928" + "hash": "cdb6aeccec0eb59ae554f3fd75d336cc" }, "clickToPlay": { "exceptions": [], @@ -197,7 +189,7 @@ "state": "enabled" } }, - "state": "enabled", + "state": "disabled", "hash": "2f0917addece756bfb107fc3fba535e9" }, "contentBlocking": { @@ -217,7 +209,7 @@ "reason": "Clicking 'Continue' after filling out details for account creation yields an error." } ], - "state": "enabled", + "state": "disabled", "minSupportedVersion": "2022.6.1", "settings": { "trackerCookie": "enabled", @@ -305,10 +297,6 @@ "domain": "tvlistings.zap2it.com", "reason": "main content hidden" }, - { - "domain": "mangaread.org", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/592" - }, { "domain": "manhwascan.net", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/592" @@ -340,10 +328,6 @@ "selector": "[class*='dfp-']", "type": "hide-empty" }, - { - "selector": "[id*='dfp-']", - "type": "hide-empty" - }, { "selector": "[id*='dfp_']", "type": "closest-empty" @@ -362,16 +346,12 @@ }, { "selector": "[id*='taboola-']", - "type": "hide" + "type": "closest-empty" }, { "selector": ".taboolaHeight", "type": "hide" }, - { - "selector": ".taboola-placeholder", - "type": "hide" - }, { "selector": ".adHolder", "type": "closest-empty" @@ -388,22 +368,10 @@ "selector": "[class*='ad_unit']", "type": "closest-empty" }, - { - "selector": ".column-ad", - "type": "hide-empty" - }, - { - "selector": ".wide-ad", - "type": "hide-empty" - }, { "selector": ".ad", "type": "hide-empty" }, - { - "selector": ".AD", - "type": "hide-empty" - }, { "selector": "[class*='ad-content']", "type": "hide-empty" @@ -412,10 +380,6 @@ "selector": "[class*='ad-slot_']", "type": "hide-empty" }, - { - "selector": "[class*='_ad-slot']", - "type": "hide-empty" - }, { "selector": ".ad-block", "type": "hide-empty" @@ -425,7 +389,7 @@ "type": "hide-empty" }, { - "selector": "[class^='adunit']", + "selector": ".adunitContainer", "type": "hide-empty" }, { @@ -448,10 +412,6 @@ "selector": ".leaderboard_wrapper", "type": "hide-empty" }, - { - "selector": ".banner-leaderboard", - "type": "hide-empty" - }, { "selector": ".ad-banner-container", "type": "hide-empty" @@ -464,10 +424,6 @@ "selector": ".banner-placeholder", "type": "hide-empty" }, - { - "selector": ".header-ads", - "type": "hide-empty" - }, { "selector": ".header-ad-slot", "type": "hide-empty" @@ -493,11 +449,7 @@ "type": "closest-empty" }, { - "selector": "[class^='ad-container']", - "type": "hide-empty" - }, - { - "selector": "[class*='-ad-container']", + "selector": ".ad-container", "type": "hide-empty" }, { @@ -520,14 +472,6 @@ "selector": "[id*='advert-']", "type": "hide-empty" }, - { - "selector": ".ads__inline", - "type": "closest-empty" - }, - { - "selector": ".ads__native", - "type": "closest-empty" - }, { "selector": ".ad-slot", "type": "closest-empty" @@ -576,10 +520,6 @@ "selector": ".bordeaux-slot", "type": "closest-empty" }, - { - "selector": ".bordeaux-anchored-container", - "type": "hide-empty" - }, { "selector": ".rightAd", "type": "hide-empty" @@ -605,7 +545,6 @@ "advertising\nskip ad\nskip ad\nskip ad", "ad feedback", "anzeige", - "close this ad", "sponsored", "sponsorisé", "story continues below advertisement", @@ -767,19 +706,6 @@ } ] }, - { - "domain": "express.co.uk", - "rules": [ - { - "selector": ".superbanner", - "type": "hide-empty" - }, - { - "selector": "#ad-vip-article", - "type": "hide-empty" - } - ] - }, { "domain": "fandom.com", "rules": [ @@ -824,36 +750,6 @@ } ] }, - { - "domain": "ghacks.net", - "rules": [ - { - "selector": ".box-banner", - "type": "hide-empty" - }, - { - "selector": "[id^='ghacks_ad_code']", - "type": "hide-empty" - } - ] - }, - { - "domain": "hindustantimes.com", - "rules": [ - { - "selector": ".desktopAd", - "type": "hide-empty" - }, - { - "selector": "[class^='adHeight']", - "type": "hide-empty" - }, - { - "selector": "[class^='adMinHeight']", - "type": "hide-empty" - } - ] - }, { "domain": "huffpost.com", "rules": [ @@ -946,19 +842,6 @@ } ] }, - { - "domain": "nasdaq.com", - "rules": [ - { - "selector": "[class^='ads__midpage']", - "type": "hide-empty" - }, - { - "selector": "[class^='ads__right-rail']", - "type": "hide-empty" - } - ] - }, { "domain": "nbcsports.com", "rules": [ @@ -972,15 +855,6 @@ } ] }, - { - "domain": "newsmax.com", - "rules": [ - { - "selector": ".DFPad", - "type": "hide-empty" - } - ] - }, { "domain": "nytimes.com", "rules": [ @@ -1018,15 +892,6 @@ } ] }, - { - "domain": "observador.pt", - "rules": [ - { - "selector": ".obs-ad-placeholder", - "type": "hide-empty" - } - ] - }, { "domain": "orange.fr", "rules": [ @@ -1063,45 +928,12 @@ } ] }, - { - "domain": "rumble.com", - "rules": [ - { - "selector": "[id^='rumble-ad']", - "type": "hide-empty" - } - ] - }, { "domain": "scmp.com", "rules": [ { "selector": "[class*='ad-slot-container']", "type": "hide-empty" - }, - { - "selector": ".top-ad", - "type": "hide-empty" - }, - { - "selector": ".advertisement--mobile", - "type": "hide-empty" - }, - { - "selector": ".bottom-ad", - "type": "hide-empty" - }, - { - "selector": ".article-list__inline-ad", - "type": "hide-empty" - }, - { - "selector": ".page-container__mobile-native-ad", - "type": "hide-empty" - }, - { - "selector": ".ad-area", - "type": "hide-empty" } ] }, @@ -1136,15 +968,6 @@ } ] }, - { - "domain": "target.com", - "rules": [ - { - "selector": "[class^='styles__PubAdWrapper']", - "type": "closest-empty" - } - ] - }, { "domain": "thingiverse.com", "rules": [ @@ -1172,15 +995,6 @@ } ] }, - { - "domain": "wunderground.com", - "rules": [ - { - "selector": ".pane-wu-fullscreenweather-ad-box-atf", - "type": "hide-empty" - } - ] - }, { "domain": "vice.com", "rules": [ @@ -1318,7 +1132,7 @@ "type": "closest-empty" }, { - "selector": "[class^='ad-container']", + "selector": ".ad-container", "type": "override" } ] @@ -1339,7 +1153,7 @@ "type": "closest-empty" }, { - "selector": "[class^='ad-container']", + "selector": ".ad-container", "type": "override" } ] @@ -1347,7 +1161,7 @@ ] }, "state": "enabled", - "hash": "636cbf0b3e45a59768a126ab9e73a9f0" + "hash": "d719a498422990f19674a5a450d300b4" }, "fingerprintingAudio": { "state": "disabled", @@ -1494,11 +1308,11 @@ }, "googleRejected": { "exceptions": [], - "state": "enabled", + "state": "disabled", "hash": "52857469413a66e8b0c7b00de5589162" }, "gpc": { - "state": "enabled", + "state": "disabled", "exceptions": [ { "domain": "allegiantair.com", @@ -1508,10 +1322,6 @@ "domain": "costco.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/644" }, - { - "domain": "duluthtrading.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/700" - }, { "domain": "web.whatsapp.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/620" @@ -1526,17 +1336,17 @@ "privacy-test-pages.glitch.me" ] }, - "hash": "470c77b05c99b8f0986cc40422a59c91" + "hash": "4d1b636f1a6bc56bdaf40e3d71ffd583" }, "https": { - "state": "enabled", + "state": "disabled", "exceptions": [], "hash": "697382e31649d84b01166f1dc6f790d6" }, "incontextSignup": { "exceptions": [], - "state": "disabled", - "hash": "728493ef7a1488e4781656d3f9db84aa" + "state": "enabled", + "hash": "52857469413a66e8b0c7b00de5589162" }, "navigatorInterface": { "exceptions": [], @@ -1558,7 +1368,7 @@ "reason": "https://github.com/duckduckgo/privacy-configuration/issues/647" } ], - "state": "enabled", + "state": "disabled", "hash": "118f6c323fac42ad0ab7ac4c7ac8a93d" }, "requestFilterer": { @@ -1569,33 +1379,6 @@ }, "hash": "9439c856372a09f0cfdc9e2e0fd086fd" }, - "runtimeChecks": { - "state": "disabled", - "exceptions": [], - "settings": { - "taintCheck": "enabled", - "matchAllDomains": "disabled", - "matchAllStackDomains": "enabled", - "overloadInstanceOf": "enabled", - "elementRemovalTimeout": 1000, - "domains": [ - { - "domain": "preactjs.com" - }, - { - "domain": "reactjs.org" - }, - { - "domain": "browserbench.org" - }, - { - "domain": "good.third-party.site" - } - ], - "stackDomains": [] - }, - "hash": "32be9e17c1e346de2f37bed896eb0231" - }, "serviceworkerInitiatedRequests": { "exceptions": [], "state": "enabled", @@ -1605,3481 +1388,14 @@ "state": "enabled", "settings": { "allowlistedTrackers": { - "3lift.com": { - "rules": [ - { - "rule": "tlx.3lift.com/header/auction", - "domains": [ - "aternos.org" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/328" - } - ] - }, - "4dex.io": { - "rules": [ - { - "rule": "mp.4dex.io/prebid", - "domains": [ - "aternos.org" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/328" - } - ] - }, - "a-mo.net": { - "rules": [ - { - "rule": "prebid.a-mo.net/a/c", - "domains": [ - "aternos.org" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/328" - } - ] - }, - "acsbapp.com": { - "rules": [ - { - "rule": "acsbapp.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/629" - } - ] - }, - "addthis.com": { - "rules": [ - { - "rule": "s7.addthis.com/js/300/addthis_widget.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/427" - }, - { - "rule": "s7.addthis.com/l10n/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/427" - }, - { - "rule": "s7.addthis.com/static/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/427" - } - ] - }, - "adform.net": { - "rules": [ - { - "rule": "adx.adform.net/adx/openrtb", - "domains": [ - "aternos.org" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/328" - }, - { - "rule": "c1.adform.net/serving/cookie/match", - "domains": [ - "dhl.de" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/340" - } - ] - }, - "ads-twitter.com": { - "rules": [ - { - "rule": "static.ads-twitter.com/uwt.js", - "domains": [ - "hentaihaven.xxx" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/452" - } - ] - }, - "adsafeprotected.com": { - "rules": [ - { - "rule": "static.adsafeprotected.com/favicon.ico", - "domains": [ - "tf1info.fr" - ], - "reason": "Adwall displays over video and prevents video from being played." - }, - { - "rule": "static.adsafeprotected.com/iasPET.1.js", - "domains": [ - "corriere.it" - ], - "reason": "Example URL: https://www.corriere.it/video-articoli/2022/07/13/missione-wwf-liberare-mare-plastica/9abb64de-029d-11ed-a0cc-ad3c68cacbae.shtml;,Clicking on the video to play causes a still frame to show and the video does not continue." - }, - { - "rule": "static.adsafeprotected.com/vans-adapter-google-ima.js", - "domains": [ - "nhl.com" - ], - "reason": "Videos show a spinner and never load." - } - ] - }, - "ahacdn.me": { - "rules": [ - { - "rule": "ahacdn.me", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/447" - } - ] - }, - "akadns.net": { - "rules": [ - { - "rule": "login.fidelity.com.febsec-fidelity.com.akadns.net", - "domains": [ - "fidelity.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/677" - } - ] - }, - "aldi-digital.co.uk": { - "rules": [ - { - "rule": "assets.aldi-digital.co.uk/assets/050b4966c22c430e5c9308903ebb87e1/dist/scripts/main.js", - "domains": [ - "aldi.co.uk" - ], - "reason": "Product lists don't render." - } - ] - }, - "alicdn.com": { + "bad.third-party.site": { "rules": [ - { - "rule": "aeis.alicdn.com/", - "domains": [ - "aliexpress.com", - "aliexpress.us" - ], - "reason": "CNAME ENTRY GENERATED FROM: alicdn.com.edgekey.net" - }, - { - "rule": "aeu.alicdn.com/", - "domains": [ - "aliexpress.com", - "aliexpress.us" - ], - "reason": "CNAME ENTRY GENERATED FROM: alicdn.com.edgekey.net" - }, - { - "rule": "assets.alicdn.com/", - "domains": [ - "aliexpress.com", - "aliexpress.us" - ], - "reason": "CNAME ENTRY GENERATED FROM: alicdn.com.edgekey.net" - }, - { - "rule": "is.alicdn.com/", - "domains": [ - "aliexpress.com", - "aliexpress.us" - ], - "reason": "CNAME ENTRY GENERATED FROM: alicdn.com.edgekey.net" - }, - { - "rule": "time-ak.alicdn.com/", - "domains": [ - "aliexpress.com", - "aliexpress.us" - ], - "reason": "CNAME ENTRY GENERATED FROM: alicdn.com.edgekey.net" - }, - { - "rule": "alicdn.com", - "domains": [ - "aliexpress.us" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/460" - } - ] - }, - "amazon-adsystem.com": { - "rules": [ - { - "rule": "c.amazon-adsystem.com/aax2/apstag.js", - "domains": [ - "corriere.it", - "eurogamer.net", - "seattletimes.com" - ], - "reason": "corriere.it - ,Example URL: https://www.corriere.it/video-articoli/2022/07/13/missione-wwf-liberare-mare-plastica/9abb64de-029d-11ed-a0cc-ad3c68cacbae.shtml;,Clicking on the video to play causes a still frame to show and the video does not continue.,eurogamer.net, seattletimes.com - An unskippable adwall appears which prevents interaction with the page." - } - ] - }, - "azure.net": { - "rules": [ - { - "rule": "amp.azure.net/libs/amp/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/504" - } - ] - }, - "azureedge.net": { - "rules": [ - { - "rule": "orderweb-cdn-endpoint-centralus.azureedge.net/js/chunk-vendors.js", - "domains": [ - "chipotle.com" - ], - "reason": "Site loads blank and cannot be interacted with." - } - ] - }, - "bc0a.com": { - "rules": [ - { - "rule": "marvel-b1-cdn.bc0a.com/f00000000269380/www.beretta.com/assets/", - "domains": [ - "beretta.com" - ], - "reason": "Example URL1: https://www.beretta.com/en-us/womens-clothing/caps-and-hats/;,Example URL2: https://www.beretta.com/en-us/mens-clothing/caps-and-hats/lp-trucker-hat/;,Various product and product-related images do not render - e.g., main product images on product pages, product images in product listings, etc." - } - ] - }, - "bing.com": { - "rules": [ - { - "rule": "r.bing.com/rp/", - "domains": [ - "" - ], - "reason": "See https://github.com/duckduckgo/privacy-configuration/issues/321.,These requests are associated with map/location functionality on websites." - }, - { - "rule": "th.bing.com/th", - "domains": [ - "drudgereport.com" - ], - "reason": "On the homepage (drudgereport.com), some images are fetched from bing.com.,When we block these requests, the images do not render, and the page appears to have blank boxes.,Note that requests can be of the form th.bing.com/th?id=... or th.bing.com/th/id/..., hence we unblock the common path here." - }, - { - "rule": "www.bing.com/api/maps/mapcontrol", - "domains": [ - "" - ], - "reason": "See https://github.com/duckduckgo/privacy-configuration/issues/321.,This request is associated with map/location functionality on websites." - }, - { - "rule": "www.bing.com/api/v6/Places/AutoSuggest", - "domains": [ - "" - ], - "reason": "See https://github.com/duckduckgo/privacy-configuration/issues/321.,This request is associated with map/location auto-suggest functionality on websites." - }, - { - "rule": "www.bing.com/maps/sdk/mapcontrol", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/321" - }, - { - "rule": "www.bing.com/maps/sdkrelease/mapcontrol", - "domains": [ - "" - ], - "reason": "See https://github.com/duckduckgo/privacy-configuration/issues/321.,This request is associated with map/location functionality on websites." - }, - { - "rule": "www.bing.com/rp/", - "domains": [ - "" - ], - "reason": "See https://github.com/duckduckgo/privacy-configuration/issues/321.,These requests are associated with map/location functionality on websites." - } - ] - }, - "captcha-delivery.com": { - "rules": [ - { - "rule": "captcha-delivery.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/501" - } - ] - }, - "casalemedia.com": { - "rules": [ - { - "rule": "htlb.casalemedia.com/cygnus", - "domains": [ - "aternos.org" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/328" - } - ] - }, - "cloudflare.com": { - "rules": [ - { - "rule": "cdnjs.cloudflare.com/ajax/libs/fingerprintjs2/1.8.6/fingerprint2.min.js", - "domains": [ - "winnipegfreepress.com" - ], - "reason": "Example URL: https://www.winnipegfreepress.com/local/city-will-try-to-fill-money-losing-ex-canada-post-office-576646662.html,Main text content on article does not load." - }, - { - "rule": "cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js", - "domains": [ - "2000mules.com" - ], - "reason": "Loading percentage hits 100% and the site does not proceed to display usual content." - }, - { - "rule": "challenges.cloudflare.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/641" - } - ] - }, - "cloudfront.net": { - "rules": [ - { - "rule": "d3oxtup47gylpj.cloudfront.net/theme/onlyfans/spa/chunk-vendors.js", - "domains": [ - "onlyfans.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/440" - } - ] - }, - "computerworld.com": { - "rules": [ - { - "rule": "cmpv2.computerworld.com/", - "domains": [ - "computerworld.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/344" - } - ] - }, - "cookiepro.com": { - "rules": [ - { - "rule": "cookie-cdn.cookiepro.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/466" - } - ] - }, - "cquotient.com": { - "rules": [ - { - "rule": "cdn.cquotient.com/js/v2/gretel.min.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/486" - }, - { - "rule": "e.cquotient.com/recs/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/486" - } - ] - }, - "criteo.com": { - "rules": [ - { - "rule": "bidder.criteo.com/cdb", - "domains": [ - "aternos.org" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/328" - } - ] - }, - "criteo.net": { - "rules": [ - { - "rule": "static.criteo.net/js/ld/publishertag.js", - "domains": [ - "wp.pl" - ], - "reason": "Adwall appears which reappears when dismissed. The adwall prevents interaction with the page." - }, - { - "rule": "static.criteo.net/js/ld/publishertag.prebid.js", - "domains": [ - "wp.pl" - ], - "reason": "Adwall appears which reappears when dismissed. The adwall prevents interaction with the page." - } - ] - }, - "cxense.com": { - "rules": [ - { - "rule": "api.cxense.com/public/widget/data", - "domains": [ - "wsj.com" - ], - "reason": "Opinion section article elements do not render. Note that Firefox Enhanced Tracking Protection may prevent mitigation from succeeding on Firefox." - } - ] - }, - "daumcdn.net": { - "rules": [ - { - "rule": "daumcdn.net", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/444" - } - ] - }, - "demdex.net": { - "rules": [ - { - "rule": "dpm.demdex.net/id", - "domains": [ - "dhl.de", - "homedepot.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/393" - } - ] - }, - "derstandard.de": { - "rules": [ - { - "rule": "spcmp.r53.derstandard.de/", - "domains": [ - "derstandard.de" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/344" - } - ] - }, - "doubleclick.net": { - "rules": [ - { - "rule": "securepubads.g.doubleclick.net/gampad/ads", - "domains": [ - "ah.nl" - ], - "reason": "'Bonus offer' elements do not render and are not clickable." - }, - { - "rule": "pubads.g.doubleclick.net/gampad/ads", - "domains": [ - "nhl.com", - "viki.com" - ], - "reason": "nhl.com - Videos show a spinner and never load.,viki.com - after a video has played for a few seconds an adwall pops up. Clicking 'I've turned off my adblocker' resets the video, then after a few seconds the adwall pops up again." - }, - { - "rule": "pubads.g.doubleclick.net/ssai/event/", - "domains": [ - "cbssports.com" - ], - "reason": "Live videos do not load or render." - }, - { - "rule": "securepubads.g.doubleclick.net/tag/js/gpt.js", - "domains": [ - "ah.nl", - "wunderground.com", - "youmath.it" - ], - "reason": "ah.nl - 'Bonus offer' elements do not render and are not clickable.,wunderground.com - Video element does not display.,youmath.it - Adwall displays which prevents page interaction and resets the page view when clicked." - }, - { - "rule": "securepubads.g.doubleclick.net/gpt/pubads_impl_", - "domains": [ - "ah.nl", - "wunderground.com" - ], - "reason": "ah.nl - 'Bonus offer' elements do not render and are not clickable.,wunderground.com - Video element does not display." - }, - { - "rule": "securepubads.g.doubleclick.net/pagead/ppub_config", - "domains": [ - "weather.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/415" - } - ] - }, - "dynamicyield.com": { - "rules": [ - { - "rule": "cdn.dynamicyield.com/api/", - "domains": [ - "brooklinen.com", - "seatosummit.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/535" - } - ] - }, - "edgekey.net": { - "rules": [ - { - "rule": "scene7.com.edgekey.net/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/356" - }, - { - "rule": "alicdn.com.edgekey.net/", - "domains": [ - "aliexpress.com", - "aliexpress.us" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/570" - }, - { - "rule": "nintendo.com.edgekey.net/account/js/common.js", - "domains": [ - "nintendo.com" - ], - "reason": "CNAME version of nintendo.com exception" - } - ] - }, - "ezoic.com": { - "rules": [ - { - "rule": "videosvc.ezoic.com/play", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/468" - }, - { - "rule": "video-streaming.ezoic.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/468" - } - ] - }, - "ezoic.net": { - "rules": [ - { - "rule": "g.ezoic.net", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/468" - } - ] - }, - "ezoiccdn.com": { - "rules": [ - { - "rule": "sf.ezoiccdn.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/468" - } - ] - }, - "facebook.net": { - "rules": [ - { - "rule": "connect.facebook.net/en_US/sdk.js", - "domains": [ - "bandsintown.com", - "nextdoor.co.uk", - "nextdoor.com" - ], - "reason": "bandsintown.com - Ticket page renders blank. With this exception the page redirects to ticketspice.com.,nextdoor.co.uk, nextdoor.com - Facebook login option appears greyed out and cannot be clicked." - }, - { - "rule": "connect.facebook.net/en_US/fbevents.js", - "domains": [ - "wp.pl" - ], - "reason": "Adwall appears which reappears when dismissed. The adwall prevents interaction with the page." - } - ] - }, - "fastly.net": { - "rules": [ - { - "rule": "mslc-prod-herokuapp-com.global.ssl.fastly.net/main.8736233213226195.js", - "domains": [ - "masslottery.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/332" - }, - { - "rule": "ticketmaster4.map.fastly.net/eps-d", - "domains": [ - "ticketmaster.ca", - "ticketmaster.com", - "ticketmaster.com.au", - "ticketmaster.com.mx" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/575" - }, - { - "rule": "target-opus.map.fastly.net/", - "domains": [ - "target.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/635" - } - ] - }, - "fox.com": { - "rules": [ - { - "rule": "fox.com", - "domains": [ - "adrise.tv", - "fncstatic.com", - "fox10phoenix.com", - "fox13news.com", - "fox26houston.com", - "fox29.com", - "fox2detroit.com", - "fox32chicago.com", - "fox35orlando.com", - "fox46charlotte.com", - "fox4news.com", - "fox5atlanta.com", - "fox5dc.com", - "fox5ny.com", - "fox7austin.com", - "fox9.com", - "foxbusiness.com", - "foxla.com", - "foxnews.com", - "foxsports.com", - "foxsportsasia.com", - "foxsportsgo.com", - "foxweather.com", - "ktvu.com", - "tubi.io", - "tubi.tv", - "tubi.video", - "tubitv.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/460" - } - ] - }, - "fwmrm.net": { - "rules": [ - { - "rule": "2a7e9.v.fwmrm.net/ad/g/1", - "domains": [ - "channel4.com" - ], - "reason": "Unskippable adblock warning when trying to play a video." - } - ] - }, - "geetest.com": { - "rules": [ - { - "rule": "api.geetest.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/462" - }, - { - "rule": "static.geetest.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/462" - } - ] - }, - "gemius.pl": { - "rules": [ - { - "rule": "gapl.hit.gemius.pl/gplayer.js", - "domains": [ - "tvp.pl" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/376" - }, - { - "rule": "pro.hit.gemius.pl/gstream.js", - "domains": [ - "tvp.pl" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/376" - }, - { - "rule": "wp.hit.gemius.pl/xgemius.js", - "domains": [ - "wp.pl" - ], - "reason": "Adwall appears which reappears when dismissed. The adwall prevents interaction with the page." - } - ] - }, - "getshogun.com": { - "rules": [ - { - "rule": "cdn.getshogun.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/450" - }, - { - "rule": "lib.getshogun.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/450" - } - ] - }, - "google-analytics.com": { - "rules": [ - { - "rule": "google-analytics.com/analytics.js", - "domains": [ - "doterra.com", - "easyjet.com" - ], - "reason": "doterra.com - For doterra.com/login/loading, the page shows a loading indicator and never redirects.,easyjet.com - Clicking 'Show Worldwide flights' after entering parameters for a worldwide flight in the flight viewing form does nothing." - }, - { - "rule": "www.google-analytics.com/plugins/ua/ecommerce.js", - "domains": [ - "doterra.com" - ], - "reason": "For doterra.com/login/loading, the page shows a loading indicator and never redirects." - } - ] - }, - "google.co.uk": { - "rules": [ - { - "rule": "maps.google.co.uk/maps", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/472" - } - ] - }, - "google.com": { - "rules": [ - { - "rule": "accounts.google.com/o/oauth2/iframerpc", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/489" - }, - { - "rule": "accounts.google.com/o/oauth2/iframe", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/489" - }, - { - "rule": "apis.google.com/js/platform.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/489" - }, - { - "rule": "apis.google.com/_/scs/abc-static/_/js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/489" - }, - { - "rule": "cse.google.com/cse.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/475" - }, - { - "rule": "cse.google.com/cse/element/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/475" - }, - { - "rule": "google.com/cse/cse.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/475" - }, - { - "rule": "www.google.com/cse/static/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/475" - }, - { - "rule": "www.google.com/maps/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/472" - } - ] - }, - "googlesyndication.com": { - "rules": [ - { - "rule": "pagead2.googlesyndication.com/pagead/js/adsbygoogle.js", - "domains": [ - "duden.de", - "magicgameworld.com", - "youmath.it" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/388" - }, - { - "rule": "tpc.googlesyndication.com/pagead/js/loader21.html", - "domains": [ - "laprensa.hn", - "rumble.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/388" - } - ] - }, - "googletagmanager.com": { - "rules": [ - { - "rule": "googletagmanager.com/gtm.js", - "domains": [ - "ah.nl", - "dailyherald.com", - "emirates.com", - "iltalehti.fi", - "kingarthurbaking.com", - "pickfu.com", - "rbcroyalbank.com" - ], - "reason": "ah.nl - 'Bonus offer' elements do not render and are not clickable.,dailyherald.com - Article images render as grey boxes.,emirates.com - After filling out login details and clicking to proceed, a loading spinners shows on the proceed button and the login does not progress.,iltalehti.fi - Article video renders as a blank box.,kingarthurbaking.com - https://github.com/duckduckgo/privacy-configuration/issues/348,pickfu.com - https://github.com/duckduckgo/privacy-configuration/issues/346,rbcroyalbank.com - Investments page renders blank." - } - ] - }, - "gstatic.com": { - "rules": [ - { - "rule": "maps.gstatic.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/472" - }, - { - "rule": "www.gstatic.com/_/mss/boq-identity/_/js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/489" - } - ] - }, - "iesnare.com": { - "rules": [ - { - "rule": "mpsnare.iesnare.com/snare.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/669" - } - ] - }, - "inq.com": { - "rules": [ - { - "rule": "inq.com/chatrouter", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/479" - }, - { - "rule": "inq.com/chatskins", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/479" - }, - { - "rule": "inq.com/tagserver/init", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/479" - }, - { - "rule": "inq.com/tagserver/launch", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/479" - }, - { - "rule": "inq.com/tagserver/postToServer", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/479" - } - ] - }, - "instagram.com": { - "rules": [ - { - "rule": "platform.instagram.com/en_US/embeds.js", - "domains": [ - "livejournal.com" - ], - "reason": "Instagram embeds as main article content render as grey boxes." - }, - { - "rule": "www.instagram.com/embed.js", - "domains": [ - "buzzfeed.com", - "livejournal.com" - ], - "reason": "Instagram embeds as main article content render as grey boxes." - } - ] - }, - "jimstatic.com": { - "rules": [ - { - "rule": "assets.jimstatic.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/496" - } - ] - }, - "klarnaservices.com": { - "rules": [ - { - "rule": "na-library.klarnaservices.com/lib.js", - "domains": [ - "brooksrunning.com", - "joann.com" - ], - "reason": "brooksrunning.com - When switching between product variants (e.g., different shoe colours) a loading spinner shows and the variant does not load.,joann.com - When switching between product variants (e.g., different shirt colours) the page shows an overlay and further interaction is prevented." - } - ] - }, - "klaviyo.com": { - "rules": [ - { - "rule": "www.klaviyo.com/media/js/public/klaviyo_subscribe.js", - "domains": [ - "fearofgod.com", - "shopyalehome.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/362" - }, - { - "rule": "klaviyo.com/", - "domains": [ - "kmail-lists.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/362" - } - ] - }, - "listrakbi.com": { - "rules": [ - { - "rule": "cdn.listrakbi.com/scripts/script.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/457" - } - ] - }, - "liveperson.net": { - "rules": [ - { - "rule": "liveperson.net", - "domains": [ - "virginmedia.com" - ], - "reason": "Chat button appears faded and cannot be interacted with." - } - ] - }, - "loggly.com": { - "rules": [ - { - "rule": "cloudfront.loggly.com/js/loggly.tracker-2.1.min.js", - "domains": [ - "rte.ie" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/681" - } - ] - }, - "lpsnmedia.net": { - "rules": [ - { - "rule": "lpsnmedia.net", - "domains": [ - "virginmedia.com" - ], - "reason": "Chat button appears faded and cannot be interacted with." - } - ] - }, - "ltwebstatic.com": { - "rules": [ - { - "rule": "sheinsz.ltwebstatic.com/she_dist/libs/geetest/fullpage.1.1.9.js", - "domains": [ - "shein.co.uk", - "shein.com" - ], - "reason": "When attempting to create an account (after filling out registration form and clicking 'Register'), there is an 'access timed out' warning, and account creation does not proceed." - } - ] - }, - "medicare.gov": { - "rules": [ - { - "rule": "frontend.medicare.gov/static/js/2.6c6651b4.chunk.js", - "domains": [ - "medicare.gov" - ], - "reason": "Navigation bar at top of site does not display, preventing easy access to e.g., site login.,Note that this CNAMEs to iservprod.medicare.gov.edgekey.net at time of mitiagtion." - } - ] - }, - "nextdoor.com": { - "rules": [ - { - "rule": "nextdoor.com", - "domains": [ - "nextdoor.co.uk" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/460" - } - ] - }, - "nintendo.com": { - "rules": [ - { - "rule": "cdn.accounts.nintendo.com/account/js/common.js", - "domains": [ - "nintendo.com" - ], - "reason": "Accounts page renders blank. Download buttons show loading stars and never finish loading. Pricing information doesn't load. Note that cdn.accounts.nintendo.com CNAMEs to star.accounts.nintendo.com.edgekey.net at the time of mitigation.; CNAME ENTRY GENERATED FROM: nintendo.com.edgekey.net" - }, - { - "rule": "api.ec.nintendo.com/account/js/common.js", - "domains": [ - "nintendo.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: nintendo.com.edgekey.net" - }, - { - "rule": "cdn.my.nintendo.com/account/js/common.js", - "domains": [ - "nintendo.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: nintendo.com.edgekey.net" - } - ] - }, - "nuance.com": { - "rules": [ - { - "rule": "nuance.com/media/launch", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/479" - }, - { - "rule": "nuance.com/media/sites", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/479" - } - ] - }, - "omnitagjs.com": { - "rules": [ - { - "rule": "hb-api.omnitagjs.com/hb-api/prebid/v1", - "domains": [ - "aternos.org" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/328" - } - ] - }, - "onlyfans.com": { - "rules": [ - { - "rule": "static.onlyfans.com", - "domains": [ - "onlyfans.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/440" - } - ] - }, - "openx.net": { - "rules": [ - { - "rule": "venatusmedia-d.openx.net/w/1.0/arj", - "domains": [ - "aternos.org" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/328" - } - ] - }, - "opta.net": { - "rules": [ - { - "rule": "secure.widget.cloud.opta.net/v3/v3.opta-widgets.js", - "domains": [ - "abc.net.au", - "emol.com" - ], - "reason": "abc.net.au - Error message displays in place of scoreboard (scoreboard does not show).,emol.com - Scoreboard does not render." - } - ] - }, - "osano.com": { - "rules": [ - { - "rule": "dsar.api.osano.com/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/529" - } - ] - }, - "pardot.com": { - "rules": [ - { - "rule": "go.pardot.com/", - "domains": [ - "klove.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/625" - } - ] - }, - "plotrabbit.com": { - "rules": [ - { - "rule": "plotrabbit.com", - "domains": [ - "cbssports.com" - ], - "reason": "Live videos do not load or render." - } - ] - }, - "primaryarms.com": { - "rules": [ - { - "rule": "images.primaryarms.com/f00000000191638/www.primaryarms.com/SSP%20Applications/NetSuite%20Inc.%20-%20SCA%20Mont%20Blanc/Development/img/", - "domains": [ - "primaryarms.com" - ], - "reason": "Product images on the main page don't render.,Note that this CNAMEs to marvel-b4-cdn.bc0a.com at time of mitigation." - }, - { - "rule": "images.primaryarms.com/f00000000191638/www.primaryarms.com/core/media/media.nl", - "domains": [ - "primaryarms.com" - ], - "reason": "Images in the large scrolling image banner on main page do not render.,Note that this CNAMEs to marvel-b4-cdn.bc0a.com at time of mitigation." - } - ] - }, - "privacy-center.org": { - "rules": [ - { - "rule": "sdk.privacy-center.org", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/339" - } - ] - }, - "privacy-mgmt.com": { - "rules": [ - { - "rule": "privacy-mgmt.com/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/344" - } - ] - }, - "privacymanager.io": { - "rules": [ - { - "rule": "cmp-consent-tool.privacymanager.io/latest/605.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "cmp-consent-tool.privacymanager.io/latest/650.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "cmp-consent-tool.privacymanager.io/latest/847.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "cmp-consent-tool.privacymanager.io/latest/assets/icons/.*.svg", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "cmp-consent-tool.privacymanager.io/latest/defaultTheme.css", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "cmp-consent-tool.privacymanager.io/latest/index.html", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "cmp-consent-tool.privacymanager.io/latest/main.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "cmp-consent-tool.privacymanager.io/latest/polyfills.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "cmp-consent-tool.privacymanager.io/latest/runtime.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "cmp-consent-tool.privacymanager.io/latest/vendor.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "gdpr.privacymanager.io/1/gdpr.bundle.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "gdpr.privacymanager.io/latest/gdpr.bundle.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "gdpr-wrapper.privacymanager.io/gdpr/.*/gdpr-liveramp.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "gdpr-wrapper.privacymanager.io/gdpr/.*/manager-logo.png", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - }, - { - "rule": "vendors.privacymanager.io/vendor-list.json", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/334" - } - ] - }, - "pubmatic.com": { - "rules": [ - { - "rule": "ads.pubmatic.com/AdServer/", - "domains": [ - "hindustantimes.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/388" - }, - { - "rule": "hbopenbid.pubmatic.com/translator", - "domains": [ - "aternos.org" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/328" - } - ] - }, - "quantserve.com": { - "rules": [ - { - "rule": "secure.quantserve.com/quant.js", - "domains": [ - "aternos.org" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/328" - } - ] - }, - "rncdn7.com": { - "rules": [ - { - "rule": "rncdn7.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/436" - } - ] - }, - "rumble.com": { - "rules": [ - { - "rule": "rumble.com/j/p/ui.r2.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/631" - } - ] - }, - "scene7.com": { - "rules": [ - { - "rule": "scene7.com/is/image/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/356" - }, - { - "rule": "scene7.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/356" - } - ] - }, - "searchspring.io": { - "rules": [ - { - "rule": "searchspring.io", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/435" - } - ] - }, - "segment.com": { - "rules": [ - { - "rule": "cdn.segment.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/484" - } - ] - }, - "shopeemobile.com": { - "rules": [ - { - "rule": "deo.shopeemobile.com/shopee", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/442" - } - ] - }, - "shortpixel.ai": { - "rules": [ - { - "rule": "cdn.shortpixel.ai/assets/js/bundles/spai-lib-bg", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/712" - } - ] - }, - "sky.com": { - "rules": [ - { - "rule": "accounts.sky.com/assets/sky_common.js", - "domains": [ - "sky.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/342" - } - ] - }, - "spiegel.de": { - "rules": [ - { - "rule": "sp-spiegel-de.spiegel.de/", - "domains": [ - "spiegel.de" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/344" - } - ] - }, - "spot.im": { - "rules": [ - { - "rule": "spot.im/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/622" - } - ] - }, - "strpst.com": { - "rules": [ - { - "rule": "strpst.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/438" - } - ] - }, - "theplatform.com": { - "rules": [ - { - "rule": "link.theplatform.com/s/", - "domains": [ - "nbcsports.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/512" - }, - { - "rule": "pdk.theplatform.com/pdk6/current/pdk/player.js", - "domains": [ - "eonline.com" - ], - "reason": "Videos don't play (blank box after clicking to play)." - }, - { - "rule": "pdk.theplatform.com/pdk6/next/pdk/player.js", - "domains": [ - "nbcsports.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/512" - } - ] - }, - "tiqcdn.com": { - "rules": [ - { - "rule": "tags.tiqcdn.com/utag/lgi/vm-uk/prod/utag.77.js", - "domains": [ - "virginmedia.com" - ], - "reason": "Chat button appears faded and cannot be interacted with." - } - ] - }, - "trustpilot.com": { - "rules": [ - { - "rule": "widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js", - "domains": [ - "domesticandgeneral.com" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/466" - } - ] - }, - "twitter.com": { - "rules": [ - { - "rule": "platform.twitter.com/embed/embed", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/717" - }, - { - "rule": "platform.twitter.com/widgets/tweet_button", - "domains": [ - "winnipegfreepress.com" - ], - "reason": "Tweet button does not render." - } - ] - }, - "usabilla.com": { - "rules": [ - { - "rule": "api.usabilla.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/482" - }, - { - "rule": "w.usabilla.com", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/482" - } - ] - }, - "usercentrics.eu": { - "rules": [ - { - "rule": "api.usercentrics.eu/settings", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/477" - }, - { - "rule": "api.usercentrics.eu/tcf", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/477" - }, - { - "rule": "api.usercentrics.eu/translations", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/477" - }, - { - "rule": "app.usercentrics.eu/browser", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/477" - }, - { - "rule": "app.usercentrics.eu/session/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/477" - }, - { - "rule": "graphql.usercentrics.eu/graphql", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/477" - }, - { - "rule": "privacy-proxy.usercentrics.eu/latest/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/477" - }, - { - "rule": "aggregator.service.usercentrics.eu/aggregate", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/477" - } - ] - }, - "yandex.ru": { - "rules": [ - { - "rule": "frontend.vh.yandex.ru/player/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/366" - }, - { - "rule": "strm.yandex.ru/get/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/366" - }, - { - "rule": "strm.yandex.ru/vh-special-converted/vod-content/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/366" - } - ] - }, - "yotpo.com": { - "rules": [ - { - "rule": "api.yotpo.com/products/.*/.*/bottomline", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/348" - }, - { - "rule": "api.yotpo.com/questions/send_confirmation_mail", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/348" - }, - { - "rule": "api.yotpo.com/v1/widget/reviews", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/348" - }, - { - "rule": "cdn-yotpo-images-production.yotpo.com/Product/.*/.*/square.jpg", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/348" - }, - { - "rule": "staticw2.yotpo.com/.*/widget.js", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/348" - }, - { - "rule": "staticw2.yotpo.com/.*/widget.css", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/348" - }, - { - "rule": "staticw2.yotpo.com/assets/yotpo-widget-font.woff", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/348" - }, - { - "rule": "staticw2.yotpo.com/batch/app_key/.*/domain_key/.*/widget/main_widget", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/348" - }, - { - "rule": "staticw2.yotpo.com/batch/", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/348" - }, - { - "rule": "api.yotpo.com/reviews/.*/vote", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/348" - } - ] - }, - "yottaa.com": { - "rules": [ - { - "rule": "cdn.yottaa.com/rapid.min.", - "domains": [ - "" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/492" - } - ] - }, - "zeustechnology.com": { - "rules": [ - { - "rule": "seattle-times.zeustechnology.com/main.js", - "domains": [ - "seattletimes.com" - ], - "reason": "An unskippable adwall appears which prevents interaction with the page." - } - ] - }, - "fidelity.com": { - "rules": [ - { - "rule": "login.fidelity.com", - "domains": [ - "fidelity.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: login.fidelity.com.febsec-fidelity.com.akadns.net" - } - ] - }, - "bareminerals.com": { - "rules": [ - { - "rule": "assets.bareminerals.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "biglots.com": { - "rules": [ - { - "rule": "assets.biglots.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "hpe.com": { - "rules": [ - { - "rule": "assets.ext.hpe.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "langhamhotels.com": { - "rules": [ - { - "rule": "assets.langhamhotels.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "lumen.com": { - "rules": [ - { - "rule": "assets.lumen.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "orvis.com": { - "rules": [ - { - "rule": "assets.orvis.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "spectrumenterprise.com": { - "rules": [ - { - "rule": "assets.spectrumenterprise.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "torrid.com": { - "rules": [ - { - "rule": "assets.torrid.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "microsoft.com": { - "rules": [ - { - "rule": "cdn-dynmedia-1.microsoft.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "hunterdouglas.com": { - "rules": [ - { - "rule": "content.hunterdouglas.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "ihg.com": { - "rules": [ - { - "rule": "digital.ihg.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "accenture.com": { - "rules": [ - { - "rule": "dynamicmedia.accenture.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "playstation.com": { - "rules": [ - { - "rule": "gmedia.playstation.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - }, - { - "rule": "media.direct.playstation.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "assaabloy.com": { - "rules": [ - { - "rule": "gw-assets.assaabloy.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "benq.com": { - "rules": [ - { - "rule": "image.benq.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "altrarunning.com": { - "rules": [ - { - "rule": "images.altrarunning.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "blackberry.com": { - "rules": [ - { - "rule": "images.blackberry.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "blue-tomato.com": { - "rules": [ - { - "rule": "images.blue-tomato.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "dxl.com": { - "rules": [ - { - "rule": "images.dxl.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "hugoboss.com": { - "rules": [ - { - "rule": "images.hugoboss.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "jansport.com": { - "rules": [ - { - "rule": "images.jansport.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "keurig.com": { - "rules": [ - { - "rule": "images.keurig.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "kwikset.com": { - "rules": [ - { - "rule": "images.kwikset.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "lee.com": { - "rules": [ - { - "rule": "images.lee.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "lennoxpros.com": { - "rules": [ - { - "rule": "images.lennoxpros.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "lululemon.com": { - "rules": [ - { - "rule": "images.lululemon.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "pfisterfaucets.com": { - "rules": [ - { - "rule": "images.pfisterfaucets.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "philips.com": { - "rules": [ - { - "rule": "images.philips.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - }, - { - "rule": "www.assets.lighting.philips.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "rosewoodhotels.com": { - "rules": [ - { - "rule": "images.rosewoodhotels.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "selfridges.com": { - "rules": [ - { - "rule": "images.selfridges.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "shaneco.com": { - "rules": [ - { - "rule": "images.shaneco.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "shophq.com": { - "rules": [ - { - "rule": "images.shophq.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "thenorthface.com": { - "rules": [ - { - "rule": "images.thenorthface.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "timberland.com": { - "rules": [ - { - "rule": "images.timberland.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "trex.com": { - "rules": [ - { - "rule": "images.trex.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "vans.com": { - "rules": [ - { - "rule": "images.vans.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "wacoal-america.com": { - "rules": [ - { - "rule": "images.wacoal-america.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "wegmans.com": { - "rules": [ - { - "rule": "images.wegmans.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "wrangler.com": { - "rules": [ - { - "rule": "images.wrangler.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "zgallerie.com": { - "rules": [ - { - "rule": "images.zgallerie.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "lakeshorelearning.com": { - "rules": [ - { - "rule": "img.lakeshorelearning.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "stryker.com": { - "rules": [ - { - "rule": "media-assets.stryker.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "castorama.fr": { - "rules": [ - { - "rule": "media.castorama.fr/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "chainreactioncycles.com": { - "rules": [ - { - "rule": "media.chainreactioncycles.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "guitarcenter.com": { - "rules": [ - { - "rule": "media.guitarcenter.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "kohlsimg.com": { - "rules": [ - { - "rule": "media.kohlsimg.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "musicarts.com": { - "rules": [ - { - "rule": "media.musicarts.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "musiciansfriend.com": { - "rules": [ - { - "rule": "media.musiciansfriend.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "schaefer-shop.de": { - "rules": [ - { - "rule": "media.schaefer-shop.de/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "screwfix.com": { - "rules": [ - { - "rule": "media.screwfix.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "screwfix.ie": { - "rules": [ - { - "rule": "media.screwfix.ie/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "sunbeltrentals.com": { - "rules": [ - { - "rule": "media.sunbeltrentals.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "tractorsupply.com": { - "rules": [ - { - "rule": "media.tractorsupply.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "bakerdist.com": { - "rules": [ - { - "rule": "resource.bakerdist.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "gemaire.com": { - "rules": [ - { - "rule": "resource.gemaire.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "bluegreenvacations.com": { - "rules": [ - { - "rule": "s7.bluegreenvacations.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "italia.it": { - "rules": [ - { - "rule": "tourismmedia.italia.it/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "signify.com": { - "rules": [ - { - "rule": "www.assets.signify.com/s7viewersdk/3.11/MixedMediaViewer/js/s7sdk/utils/Utils.js", - "domains": [ - "" - ], - "reason": "CNAME ENTRY GENERATED FROM: scene7.com.edgekey.net" - } - ] - }, - "aliexpress.com": { - "rules": [ - { - "rule": "login.aliexpress.com/", - "domains": [ - "aliexpress.com", - "aliexpress.us" - ], - "reason": "CNAME ENTRY GENERATED FROM: alicdn.com.edgekey.net" - } - ] - }, - "aliexpress.us": { - "rules": [ - { - "rule": "login.aliexpress.us/", - "domains": [ - "aliexpress.com", - "aliexpress.us" - ], - "reason": "CNAME ENTRY GENERATED FROM: alicdn.com.edgekey.net" - } - ] - }, - "ticketmaster.ca": { - "rules": [ - { - "rule": "epsf.ticketmaster.ca/eps-d", - "domains": [ - "ticketmaster.ca", - "ticketmaster.com", - "ticketmaster.com.au", - "ticketmaster.com.mx" - ], - "reason": "CNAME ENTRY GENERATED FROM: ticketmaster4.map.fastly.net" - } - ] - }, - "ticketmaster.com": { - "rules": [ - { - "rule": "epsf.ticketmaster.com/eps-d", - "domains": [ - "ticketmaster.ca", - "ticketmaster.com", - "ticketmaster.com.au", - "ticketmaster.com.mx" - ], - "reason": "CNAME ENTRY GENERATED FROM: ticketmaster4.map.fastly.net" - } - ] - }, - "livenationinternational.com": { - "rules": [ - { - "rule": "dynamicmedia.livenationinternational.com/eps-d", - "domains": [ - "ticketmaster.ca", - "ticketmaster.com", - "ticketmaster.com.au", - "ticketmaster.com.mx" - ], - "reason": "CNAME ENTRY GENERATED FROM: ticketmaster4.map.fastly.net" - }, - { - "rule": "staticmedia.livenationinternational.com/eps-d", - "domains": [ - "ticketmaster.ca", - "ticketmaster.com", - "ticketmaster.com.au", - "ticketmaster.com.mx" - ], - "reason": "CNAME ENTRY GENERATED FROM: ticketmaster4.map.fastly.net" - } - ] - }, - "target.com": { - "rules": [ - { - "rule": "api.target.com/", - "domains": [ - "target.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: target-opus.map.fastly.net" - }, - { - "rule": "carts.target.com/", - "domains": [ - "target.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: target-opus.map.fastly.net" - }, - { - "rule": "gsp.target.com/", - "domains": [ - "target.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: target-opus.map.fastly.net" - }, - { - "rule": "redoak.target.com/", - "domains": [ - "target.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: target-opus.map.fastly.net" - }, - { - "rule": "redsky.target.com/", - "domains": [ - "target.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: target-opus.map.fastly.net" - }, - { - "rule": "sapphire-api.target.com/", - "domains": [ - "target.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: target-opus.map.fastly.net" - }, - { - "rule": "taglocker.target.com/", - "domains": [ - "target.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: target-opus.map.fastly.net" - } - ] - }, - "targetimg1.com": { - "rules": [ - { - "rule": "assets.targetimg1.com/", - "domains": [ - "target.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: target-opus.map.fastly.net" - } - ] - }, - "bupa.com.au": { - "rules": [ - { - "rule": "lp-07.customermessaging.bupa.com.au", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: liveperson.net" - }, - { - "rule": "lp-01.customermessaging.bupa.com.au", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: lpsnmedia.net" - }, - { - "rule": "lpcdn.customermessaging.bupa.com.au", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: lpsnmedia.net" - } - ] - }, - "optus.com.au": { - "rules": [ - { - "rule": "lp-07.messaging.optus.com.au", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: liveperson.net" - }, - { - "rule": "lptag.messaging.optus.com.au", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: liveperson.net" - }, - { - "rule": "lp-01.messaging.optus.com.au", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: lpsnmedia.net" - }, - { - "rule": "lpcdn.messaging.optus.com.au", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: lpsnmedia.net" - } - ] - }, - "mbna.ca": { - "rules": [ - { - "rule": "chat.mbna.ca", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: lpsnmedia.net" - } - ] - }, - "singtel.com": { - "rules": [ - { - "rule": "chat.singtel.com", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: lpsnmedia.net" - } - ] - }, - "navyfederal.org": { - "rules": [ - { - "rule": "liveengage.navyfederal.org", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: lpsnmedia.net" - } - ] - }, - "citi.com": { - "rules": [ - { - "rule": "lpcdn.chat.online.citi.com", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: lpsnmedia.net" - } - ] - }, - "telstra.com.au": { - "rules": [ - { - "rule": "lpcdn.messaging.telstra.com.au", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: lpsnmedia.net" - } - ] - }, - "americanexpress.com": { - "rules": [ - { - "rule": "lpchat.americanexpress.com", - "domains": [ - "virginmedia.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: lpsnmedia.net" - } - ] - }, - "jumpcloud.com": { - "rules": [ - { - "rule": "cloud.jumpcloud.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "johnsoncontrols.com": { - "rules": [ - { - "rule": "connect.johnsoncontrols.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "claris.com": { - "rules": [ - { - "rule": "content.claris.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "nielsen.com": { - "rules": [ - { - "rule": "content.nielsen.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "ap.org": { - "rules": [ - { - "rule": "discover.ap.org/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "selinc.com": { - "rules": [ - { - "rule": "discover.selinc.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "discovery.org": { - "rules": [ - { - "rule": "dot.discovery.org/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "medbridgeeducation.com": { - "rules": [ - { - "rule": "enterprise.medbridgeeducation.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "baesystems.com": { - "rules": [ - { - "rule": "events.baesystems.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "freightos.com": { - "rules": [ - { - "rule": "get.freightos.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "adflegal.org": { - "rules": [ - { - "rule": "go.adflegal.org/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "advantech.com": { - "rules": [ - { - "rule": "go.advantech.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "adventure-life.com": { - "rules": [ - { - "rule": "go.adventure-life.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "brennancenter.org": { - "rules": [ - { - "rule": "go.brennancenter.org/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "cdata.com": { - "rules": [ - { - "rule": "go.cdata.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "herzing.edu": { - "rules": [ - { - "rule": "go.connect.herzing.edu/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "costar.com": { - "rules": [ - { - "rule": "go.costar.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "esri.com": { - "rules": [ - { - "rule": "go.esri.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "estes-express.com": { - "rules": [ - { - "rule": "go.estes-express.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "iocdf.org": { - "rules": [ - { - "rule": "go.iocdf.org/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "jinjibu.jp": { - "rules": [ - { - "rule": "go.jinjibu.jp/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "lifefitness.com": { - "rules": [ - { - "rule": "go.lifefitness.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "ofx.com": { - "rules": [ - { - "rule": "go.message.ofx.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "neilpatel.com": { - "rules": [ - { - "rule": "go.neilpatel.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "newport.com": { - "rules": [ - { - "rule": "go.newport.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "panasonic.biz": { - "rules": [ - { - "rule": "go.panasonic.biz/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "perkinscoie.com": { - "rules": [ - { - "rule": "go.perkinscoie.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "ripple.com": { - "rules": [ - { - "rule": "go.ripple.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "strongtie.com": { - "rules": [ - { - "rule": "go.strongtie.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "thirdspacelearning.com": { - "rules": [ - { - "rule": "go.thirdspacelearning.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "iata.org": { - "rules": [ - { - "rule": "go.updates.iata.org/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "uslawshield.com": { - "rules": [ - { - "rule": "go.uslawshield.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "lumbermenonline.com": { - "rules": [ - { - "rule": "go1.lumbermenonline.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "panasonic.jp": { - "rules": [ - { - "rule": "gohs.panasonic.jp/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "rescue.org": { - "rules": [ - { - "rule": "gorm.rescue.org/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "affirm.com": { - "rules": [ - { - "rule": "info.affirm.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "bldr.com": { - "rules": [ - { - "rule": "info.bldr.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "factsmgt.com": { - "rules": [ - { - "rule": "info.factsmgt.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "msci.com": { - "rules": [ - { - "rule": "info.msci.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "viewsonic.com": { - "rules": [ - { - "rule": "info.viewsonic.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "woolmark.com": { - "rules": [ - { - "rule": "info.woolmark.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "renasantbank.com": { - "rules": [ - { - "rule": "insights.renasantbank.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "caring.com": { - "rules": [ - { - "rule": "launch.caring.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "epson.com.au": { - "rules": [ - { - "rule": "marketing-sf.epson.com.au/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "globalsign.com": { - "rules": [ - { - "rule": "media.globalsign.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "tatlerasia.com": { - "rules": [ - { - "rule": "media2.tatlerasia.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "epson.co.in": { - "rules": [ - { - "rule": "mkt.pd.epson.co.in/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "tokyoweekender.com": { - "rules": [ - { - "rule": "mkt.tokyoweekender.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "northside.com": { - "rules": [ - { - "rule": "onechartmail.northside.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "doubleline.com": { - "rules": [ - { - "rule": "pardot.doubleline.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "epson.jp": { - "rules": [ - { - "rule": "pd.epson.jp/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "11880.com": { - "rules": [ - { - "rule": "pdt.11880.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "redlightguide.com": { - "rules": [ - { - "rule": "pdt.redlightguide.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "werkenntdenbesten.de": { - "rules": [ - { - "rule": "pdt.werkenntdenbesten.de/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "illumina.com": { - "rules": [ - { - "rule": "prdt.illumina.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "xserver.ne.jp": { - "rules": [ - { - "rule": "prm.xserver.ne.jp/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "brother.ca": { - "rules": [ - { - "rule": "resellersales.brother.ca/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "chemeurope.com": { - "rules": [ - { - "rule": "t.chemeurope.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "chemie.de": { - "rules": [ - { - "rule": "t.chemie.de/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "forgeglobal.com": { - "rules": [ - { - "rule": "ww2.forgeglobal.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "vonage.com": { - "rules": [ - { - "rule": "ww3.business.vonage.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "ntt.com": { - "rules": [ - { - "rule": "www.bizsol.ntt.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "shredit.com": { - "rules": [ - { - "rule": "www.email.shredit.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "ergotron.com": { - "rules": [ - { - "rule": "www2.ergotron.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "aruhi-corp.co.jp": { - "rules": [ - { - "rule": "www2.go.aruhi-corp.co.jp/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "sharecare.com": { - "rules": [ - { - "rule": "www2.sharecare.com/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "kidney.org": { - "rules": [ - { - "rule": "www3.kidney.org/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } - ] - }, - "sma.de": { - "rules": [ - { - "rule": "www3.sma.de/", - "domains": [ - "klove.com" - ], - "reason": "CNAME ENTRY GENERATED FROM: go.pardot.com" - } ] } } }, "exceptions": [], - "hash": "c6cded53b518a104bd5f4f8e7800f94d" + "hash": "47b616a5bd23e2bb09050ba7193f9ff2" }, "trackingCookies1p": { "settings": { @@ -5089,7 +1405,7 @@ } }, "exceptions": [], - "state": "enabled", + "state": "disabled", "hash": "66159bbb387e48b7d6295068e642fc99" }, "trackingCookies3p": { @@ -5097,7 +1413,7 @@ "excludedCookieDomains": [] }, "exceptions": [], - "state": "enabled", + "state": "disabled", "hash": "6859f9cb854d6be96600b5757600ee5b" }, "trackingParameters": { diff --git a/shared/data/constants.js b/shared/data/constants.js index 7bff53b0bb..7ac92f46a8 100644 --- a/shared/data/constants.js +++ b/shared/data/constants.js @@ -5,12 +5,13 @@ function getConfigFileName () { let browserName = browserInfo?.browser?.toLowerCase() || '' // clamp to known browsers - if (!['chrome', 'firefox', 'brave', 'edg'].includes(browserName)) { + if (!['chrome', 'firefox', 'brave', 'edg', 'safari'].includes(browserName)) { browserName = '' } else { browserName = '-' + browserName + (chrome?.runtime.getManifest().manifest_version === 3 ? 'mv3' : '') } - return `https://staticcdn.duckduckgo.com/trackerblocking/config/v2/extension${browserName}-config.json` + // return `https://staticcdn.duckduckgo.com/trackerblocking/config/v2/extension${browserName}-config.json` + return `https://pyrite-scarce-agenda.glitch.me/staticcdn/trackerblocking/config/v2/extension${browserName}-config.json` } module.exports = { @@ -99,7 +100,7 @@ module.exports = { }, { name: 'tds', - url: 'https://staticcdn.duckduckgo.com/trackerblocking/v4/tds.json', + url: '/data/bundled/tds.json', format: 'json', source: 'external', channels: { diff --git a/shared/js/background/atb.js b/shared/js/background/atb.js index 6a06f2882d..6988d1c8a0 100644 --- a/shared/js/background/atb.js +++ b/shared/js/background/atb.js @@ -237,10 +237,16 @@ const ATB = (() => { requestDomains: ['duckduckgo.com'], regexFilter: regExpAboutPage.source }) - + const browserName = parseUserAgentString() + if (browserName?.browser === 'Safari') { + delete atbRule.condition.requestDomains + } chrome.declarativeNetRequest.updateDynamicRules({ - removeRuleIds: [atbRule.id], - addRules: [atbRule] + removeRuleIds: [atbRule.id] + }).then(() => { + chrome.declarativeNetRequest.updateDynamicRules({ + addRules: [atbRule] + }) }) }, @@ -268,9 +274,4 @@ const ATB = (() => { } })() -settings.ready().then(async () => { - // set initial uninstall url - browserWrapper.setUninstallURL(await ATB.getSurveyURL()) -}) - module.exports = ATB diff --git a/shared/js/background/classes/tab.js b/shared/js/background/classes/tab.js index 309ff55380..cb5bbad3f5 100644 --- a/shared/js/background/classes/tab.js +++ b/shared/js/background/classes/tab.js @@ -41,6 +41,7 @@ class Tab { this.httpsRedirects = new HttpsRedirects() this.webResourceAccess = [] this.surrogates = {} + this.lastTrackerUpdate = Date.now() } /** diff --git a/shared/js/background/dnr-config-rulesets.js b/shared/js/background/dnr-config-rulesets.js index 418fc4dda2..da3a311881 100644 --- a/shared/js/background/dnr-config-rulesets.js +++ b/shared/js/background/dnr-config-rulesets.js @@ -1,9 +1,8 @@ import * as browserWrapper from './wrapper' import settings from './settings' -import tdsStorage from './storage/tds' +// import tdsStorage from './storage/tds' import trackers from './trackers' -import * as startup from './startup' -import { isFeatureEnabled } from './utils' +import { isFeatureEnabled, getBrowserName } from './utils' import { ensureServiceWorkerInitiatedRequestExceptions } from './dnr-service-worker-initiated' @@ -21,8 +20,10 @@ import { import { generateCombinedConfigBlocklistRuleset } from '@duckduckgo/ddg2dnr/lib/combined' +import { convertDNRRuleset } from './safai-compat.mjs' export const SETTING_PREFIX = 'declarative_net_request-' +const isRegexSupported = getBrowserName() !== 'safari' ? chrome.declarativeNetRequest.isRegexSupported : () => ({ isSupported: false }) // Allocate blocks of rule IDs for the different configurations. That way, the // rules associated with a configuration can be safely cleared without the risk @@ -108,6 +109,7 @@ async function configRulesNeedUpdate (configName, expectedState) { */ function minimalConfig ({ unprotectedTemporary, features }) { const result = { features: { }, unprotectedTemporary } + console.log('minimal config', features) for (const featureName of Object.keys(features)) { if (isFeatureEnabled(featureName)) { @@ -163,9 +165,10 @@ async function updateConfigRules ( } // Install the updated rules. - await chrome.declarativeNetRequest.updateDynamicRules({ - removeRuleIds, addRules: rules - }) + console.log('update rules', convertDNRRuleset(rules)) + await chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds }) + await chrome.declarativeNetRequest.updateDynamicRules({ addRules: convertDNRRuleset(rules) }) + console.log('dynmaic rules', await chrome.declarativeNetRequest.getDynamicRules()) // Then update the setting entry. const settingName = SETTING_PREFIX + configName @@ -203,14 +206,15 @@ export async function updateExtensionConfigRules (etag = null, configValue = nul } if (!configValue) { - await tdsStorage.ready('config') - configValue = tdsStorage.config + // await tdsStorage.ready('config') + // configValue = tdsStorage.config + return } if (!etag) { const settingName = SETTING_PREFIX + 'config' await settings.ready() - await tdsStorage.ready('config') + // await tdsStorage.ready('config') const settingValue = settings.getSetting(settingName) if (!settingValue?.etag) { // Should not be possible, but if the etag is unknown at this point @@ -230,7 +234,7 @@ export async function updateExtensionConfigRules (etag = null, configValue = nul } = await generateExtensionConfigurationRuleset( minimalConfig(configValue), denylistedDomains, - chrome.declarativeNetRequest.isRegexSupported, + isRegexSupported, ruleIdStart + 1 ) @@ -239,7 +243,7 @@ export async function updateExtensionConfigRules (etag = null, configValue = nul ) } -export async function updateCombinedConfigBlocklistRules () { +export async function updateCombinedConfigBlocklistRules (tdsStorage) { const extensionVersion = browserWrapper.getExtensionVersion() const denylistedDomains = await getDenylistedDomains() const tdsEtag = settings.getSetting('tds-etag') @@ -272,19 +276,22 @@ let ruleUpdateLock = Promise.resolve() * @param {object} configValue * @returns {Promise} */ -export async function onConfigUpdate (configName, etag, configValue) { +export async function onConfigUpdate (configName, etag, configValue, tdsStorage) { const extensionVersion = browserWrapper.getExtensionVersion() // Run an async lock on all blocklist updates so the latest update is always processed last ruleUpdateLock = ruleUpdateLock.then(async () => { // TDS (aka the block list). + console.log('onConfigUpdate', configName) if (configName === 'tds') { + console.log('skip tds') + return const [ruleIdStart] = ruleIdRangeByConfigName[configName] const latestState = { etag, extensionVersion } if (!(await configRulesNeedUpdate(configName, latestState))) { return } - await startup.ready() + // await startup.ready() // @ts-ignore: Once startup.ready() has finished, surrogateList will be // assigned. const supportedSurrogates = new Set(Object.keys(trackers.surrogateList)) @@ -295,7 +302,7 @@ export async function onConfigUpdate (configName, etag, configValue) { configValue, supportedSurrogates, '/web_accessible_resources/', - chrome.declarativeNetRequest.isRegexSupported, + isRegexSupported, ruleIdStart + 1 ) @@ -306,12 +313,17 @@ export async function onConfigUpdate (configName, etag, configValue) { await ensureServiceWorkerInitiatedRequestExceptions(configValue) } // combined rules (cookie blocking) - await updateCombinedConfigBlocklistRules() + await updateCombinedConfigBlocklistRules(tdsStorage) }) await ruleUpdateLock } -if (browserWrapper.getManifestVersion() === 3) { - tdsStorage.onUpdate('config', onConfigUpdate) - tdsStorage.onUpdate('tds', onConfigUpdate) +export function init (tdsStorage) { + if (browserWrapper.getManifestVersion() === 3) { + console.log('register dnr listeners') + // tdsStorage.onUpdate('config', onConfigUpdate) + // tdsStorage.onUpdate('tds', onConfigUpdate) + onConfigUpdate('config', 'a', tdsStorage.config, tdsStorage) + onConfigUpdate('tds', 'a', tdsStorage.tds, tdsStorage) + } } diff --git a/shared/js/background/dnr-user-allowlist.js b/shared/js/background/dnr-user-allowlist.js index 54d437f58b..c1ce735294 100644 --- a/shared/js/background/dnr-user-allowlist.js +++ b/shared/js/background/dnr-user-allowlist.js @@ -16,6 +16,7 @@ import { import { generateDNRRule } from '@duckduckgo/ddg2dnr/lib/utils' +import { convertDNRRuleset } from './safai-compat.mjs' /** * Normalize and validate the given untrusted domain (e.g. from user input). @@ -51,9 +52,11 @@ async function updateUserAllowlistRule (allowlistedDomains) { requestDomains: allowlistedDomains })) } + console.log('updateUserAllowlistRule', allowlistedDomains, addRules) + await chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds }) await chrome.declarativeNetRequest.updateDynamicRules({ - removeRuleIds, addRules + addRules: convertDNRRuleset(addRules) }) } diff --git a/shared/js/background/email-utils.js b/shared/js/background/email-utils.js index 4d28ca4bcb..01e8b98f38 100644 --- a/shared/js/background/email-utils.js +++ b/shared/js/background/email-utils.js @@ -53,31 +53,33 @@ export const fetchAlias = () => { const MENU_ITEM_ID = 'ddg-autofill-context-menu-item' // Create the contextual menu hidden by default -browser.contextMenus.create({ - id: MENU_ITEM_ID, - title: 'Generate Private Duck Address', - contexts: ['editable'], - documentUrlPatterns: ['https://*/*'], - visible: false -}, () => { - // It's fine if this context menu already exists, suppress that error. - // Note: Since webextension-polyfill does not wrap the contextMenus.create - // API, the old callback + runtime.lastError approach must be used. - const { lastError } = browser.runtime - if (lastError && lastError.message && - !lastError.message.startsWith('Cannot create item with duplicate id')) { - throw lastError - } -}) -browser.contextMenus.onClicked.addListener((info, tab) => { - const userData = getSetting('userData') - if (tab?.id && userData.nextAlias) { - browser.tabs.sendMessage(tab.id, { - type: 'contextualAutofill', - alias: userData.nextAlias - }) - } -}) +if (browser.contextMenus) { + browser.contextMenus.create({ + id: MENU_ITEM_ID, + title: 'Generate Private Duck Address', + contexts: ['editable'], + documentUrlPatterns: ['https://*/*'], + visible: false + }, () => { + // It's fine if this context menu already exists, suppress that error. + // Note: Since webextension-polyfill does not wrap the contextMenus.create + // API, the old callback + runtime.lastError approach must be used. + const { lastError } = browser.runtime + if (lastError && lastError.message && + !lastError.message.startsWith('Cannot create item with duplicate id')) { + throw lastError + } + }) + browser.contextMenus.onClicked.addListener((info, tab) => { + const userData = getSetting('userData') + if (tab?.id && userData.nextAlias) { + browser.tabs.sendMessage(tab.id, { + type: 'contextualAutofill', + alias: userData.nextAlias + }) + } + }) +} export const showContextMenuAction = () => browser.contextMenus.update(MENU_ITEM_ID, { visible: true }) diff --git a/shared/js/background/events.js b/shared/js/background/events.js index 6b750ab4ff..b7c18215f6 100644 --- a/shared/js/background/events.js +++ b/shared/js/background/events.js @@ -334,28 +334,6 @@ browser.webNavigation.onBeforeNavigate.addListener(details => { * TABS */ -const Companies = require('./companies') - -browser.tabs.onCreated.addListener((info) => { - if (info.id) { - tabManager.createOrUpdateTab(info.id, info) - } -}) - -browser.tabs.onUpdated.addListener((id, info) => { - // sync company data to storage when a tab finishes loading - if (info.status === 'complete') { - Companies.syncToStorage() - } - - tabManager.createOrUpdateTab(id, info) -}) - -browser.tabs.onRemoved.addListener((id, info) => { - // remove the tab object - tabManager.delete(id) -}) - // message popup to close when the active tab changes. browser.tabs.onActivated.addListener(() => { browserWrapper.notifyPopup({ closePopup: true }) diff --git a/shared/js/background/features/atb.js b/shared/js/background/features/atb.js new file mode 100644 index 0000000000..32111daf2e --- /dev/null +++ b/shared/js/background/features/atb.js @@ -0,0 +1,25 @@ +import ATB from '../atb' +import settings from '../settings' +import { getManifestVersion, setUninstallURL } from '../wrapper' + +async function init () { + await settings.ready() + setUninstallURL(await ATB.getSurveyURL()) +} + +async function onInstalled () { + await ATB.updateATBValues() + await ATB.openPostInstallPage() + onUpdated() +} + +async function onUpdated () { + if (getManifestVersion() === 3) { + // create ATB rule if there is a stored value in settings + ATB.setOrUpdateATBdnrRule(settings.getSetting('atb')) + } +} + +export default { + init, onInstalled, onUpdated +} diff --git a/shared/js/background/features/local-tds.js b/shared/js/background/features/local-tds.js new file mode 100644 index 0000000000..ee12ddebe8 --- /dev/null +++ b/shared/js/background/features/local-tds.js @@ -0,0 +1,74 @@ +import tdsStorage from '../storage/tds' +import trackers from '../trackers' +import { tdsLists } from '../../../data/constants' + +const bundledConfig = { + url: '/data/bundled/extension-config.json' +} +const configList = tdsLists.find(l => l.name === 'config') || bundledConfig + +class TDS { + constructor () { + this._loadPromise = Promise.all([this._loadTds(), this._loadConfig(), this._loadSurrogates()]) + tdsStorage.ready = this.ready.bind(this) + this._loadPromise.then(() => { + trackers.setLists([{ + name: 'surrogates', + data: this.surrogates + }, { + name: 'tds', + data: this.tds + }, { + name: 'config', + data: this.config + }]) + }) + } + + async _loadTds () { + this.tds = await (await fetch('/data/bundled/tds.json')).json() + // for compat with static imports, attach to tdsStorage singleton + tdsStorage.tds = this.tds + } + + async _loadConfig () { + let response + let remoteFailed = false + console.log('fetch', configList.url) + try { + response = await fetch(configList.url) + if (!response.ok) { + remoteFailed = true + } + } catch (e) { + remoteFailed = true + } + if (remoteFailed) { + console.warn('Config fetch error') + response = await fetch(bundledConfig.url) + } + if (response) { + this.config = await response.json() + tdsStorage.config = this.config + } + } + + async _loadSurrogates () { + this.surrogates = await (await fetch('/data/surrogates.txt')).text() + } + + ready () { + return this._loadPromise + } +} + +export default { + init: async () => { + const tds = new TDS() + await tds.ready() + return tds + }, + onInstalled: () => { + + } +} diff --git a/shared/js/background/features/remote-tds.js b/shared/js/background/features/remote-tds.js new file mode 100644 index 0000000000..3e743c4937 --- /dev/null +++ b/shared/js/background/features/remote-tds.js @@ -0,0 +1,17 @@ +import tdsStorage from '../storage/tds' +import trackers from '../trackers' + +export default { + init: async () => { + try { + const tdsLists = await tdsStorage.getLists(/* preferLocal= */true) + trackers.setLists(tdsLists) + } catch (e) { + console.warn('Error loading tds lists', e) + } + return tdsStorage + }, + onInstalled: () => { + tdsStorage.initOnInstall() + } +} diff --git a/shared/js/background/features/tab-tracking.js b/shared/js/background/features/tab-tracking.js new file mode 100644 index 0000000000..5748e087a8 --- /dev/null +++ b/shared/js/background/features/tab-tracking.js @@ -0,0 +1,82 @@ +import browser from 'webextension-polyfill' +import tabManager from '../tab-manager' +import Companies from '../companies' + +export default { + init: async () => { + const createdTargets = new Map() + // init from current open tabs + const savedTabs = await browser.tabs.query({ status: 'complete' }) + for (let i = 0; i < savedTabs.length; i++) { + const tab = savedTabs[i] + + if (tab.url) { + // On reinstall we wish to create the tab again + await tabManager.restoreOrCreate(tab) + } + } + if (browser.webNavigation.onCreatedNavigationTarget) { + browser.webNavigation.onCreatedNavigationTarget.addListener((details) => { + createdTargets.set(details.tabId, details.sourceTabId) + }) + } + browser.webNavigation.onBeforeNavigate.addListener((details) => { + console.log('navigation', details.tabId, details.frameId, details.url) + // ignore navigation on iframes + if (details.frameId !== 0) return + + const currentTab = tabManager.get({ tabId: details.tabId }) + const newTab = tabManager.create({ + tabId: details.tabId, + url: details.url + }) + + // persist the last URL the tab was trying to upgrade to HTTPS + if (currentTab && currentTab.httpsRedirects) { + newTab.httpsRedirects.persistMainFrameRedirect( + currentTab.httpsRedirects.getMainFrameRedirect() + ) + } + if (createdTargets.has(details.tabId)) { + const sourceTabId = createdTargets.get(details.tabId) + createdTargets.delete(details.tabId) + + const sourceTab = tabManager.get({ tabId: sourceTabId }) + if (sourceTab && sourceTab.adClick) { + createdTargets.set(details.tabId, sourceTabId) + if (sourceTab.adClick.shouldPropagateAdClickForNewTab(newTab)) { + newTab.adClick = sourceTab.adClick.propagate(newTab.id) + } + } + } + newTab.updateSite(details.url) + // devtools.postMessage(details.tabId, 'tabChange', devtools.serializeTab(newTab)) + }) + + browser.tabs.onCreated.addListener((info) => { + if (info.id) { + console.log('tabs.onCreated', info.id, info.url) + tabManager.createOrUpdateTab(info.id, info) + } + }) + + browser.tabs.onUpdated.addListener((id, info) => { + // sync company data to storage when a tab finishes loading + if (info.status === 'complete') { + Companies.syncToStorage() + } + if (info.url) { + console.log('tabs.onUpdated', id, info.url) + tabManager.createOrUpdateTab(id, info).updateSite(info.url) + } + }) + + browser.tabs.onRemoved.addListener((id, info) => { + // remove the tab object + tabManager.delete(id) + }) + + Companies.buildFromStorage() + return tabManager + } +} diff --git a/shared/js/background/message-handlers.js b/shared/js/background/message-handlers.js index ba770f3017..cdd237452a 100644 --- a/shared/js/background/message-handlers.js +++ b/shared/js/background/message-handlers.js @@ -115,6 +115,22 @@ async function getTab (tabId) { return tabManager.getOrRestoreTab(tabId) } +function processBlockedRequests(url, tabId, timeStamp) { + const tab = tabManager.get({ tabId }) + if (!tab || tab.lastTrackerUpdate >= timeStamp) { + return + } + const match = trackers.getTrackerData(url, tab.url || '', {}) + if (match) { + console.log('addTracker', tab.id, match.fullTrackerDomain, match.reason) + const baseDomain = utils.getBaseDomain(url) + tab.site.addTracker(match) + if (baseDomain) { + tab.addToTrackers(match, baseDomain, url) + } + tab.lastTrackerUpdate = timeStamp + } +} /** * This message is here to ensure the privacy dashboard can render * from a single call to the extension. @@ -124,6 +140,25 @@ async function getTab (tabId) { */ export async function getPrivacyDashboardData (options) { let { tabId } = options + console.log('getPrivacyDashboardData', browserName) + if (browserName === 'safari') { + const matched = await chrome.declarativeNetRequest.getMatchedRules() + console.log('matched', matched) + + try { + // After Safari 16.3 match data is stored in `rulesMatchedInfo` + if (matched.rulesMatchedInfo) { + matched.rulesMatchedInfo.forEach(({ request, tabId, timeStamp }) => { + processBlockedRequests(request.url, tabId, timeStamp) + }) + } else if (matched.forEach) { + // Safari 16.3 legacy match info format + matched.forEach(({ request }) => processBlockedRequests(request.url, request.tabId, request.timeStamp)) + } + } catch (e) { + console.warn(e) + } + } if (tabId === null) { const currentTab = await utils.getCurrentTab() if (!currentTab?.id) { diff --git a/shared/js/background/safai-compat.mjs b/shared/js/background/safai-compat.mjs new file mode 100644 index 0000000000..5678389034 --- /dev/null +++ b/shared/js/background/safai-compat.mjs @@ -0,0 +1,60 @@ + +function convertDnrRule (accumulator, rule) { + let { ruleset, nextId } = accumulator + if (rule.action.type === 'allowAllRequests') { + // fix for allowAllRequests + ruleset.push({ + id: nextId++, + priority: rule.priority, + action: { + type: 'allow' + }, + condition: { + domains: rule.condition.requestDomains.map(d => `*${d}`) + } + }) + return { ruleset, nextId } + } + if (rule.action.type === 'redirect' && rule.condition.urlFilter?.startsWith('||')) { + rule.condition.urlFilter = rule.condition.urlFilter.slice(2) + } + if (rule.condition.excludedInitiatorDomains) { + // subdomain matching prefix + rule.condition.excludedDomains = rule.condition.excludedInitiatorDomains.map(d => `*${d}`) + delete rule.condition.excludedInitiatorDomains + } + if (rule.condition.initiatorDomains) { + if (!rule.condition.initiatorDomains.includes('')) { + // subdomain matching prefix + rule.condition.domains = rule.condition.initiatorDomains.map(d => `*${d}`) + } + delete rule.condition.initiatorDomains + } + if (rule.condition.regexFilter) { + // this only happens for facebook rules, for which it's safe to drop the requestDomains part + delete rule.condition.requestDomains + } + if (rule.condition.requestDomains) { + for (const domain of rule.condition.requestDomains) { + const urlFilter = rule.condition.urlFilter || `||${domain}/` + if (rule.condition.urlFilter && !rule.condition.urlFilter.includes(domain)) { + // console.warn(`skip requestDomain ${domain} with filter ${rule.condition.urlFilter} (no-op rule)`) + continue + } + const ruleCopy = JSON.parse(JSON.stringify(rule)) + delete ruleCopy.condition.requestDomains + ruleCopy.condition.urlFilter = urlFilter + ruleCopy.id = nextId++ + ruleset.push(ruleCopy) + } + } else { + rule.id = nextId++ + ruleset.push(rule) + } + return { ruleset, nextId } +} + +export function convertDNRRuleset (ruleset) { + const conversionResult = ruleset.reduce(convertDnrRule, { ruleset: [], nextId: ruleset.length > 0 ? ruleset[0].id : 1 }) + return conversionResult.ruleset +} diff --git a/shared/js/background/safari.js b/shared/js/background/safari.js new file mode 100644 index 0000000000..5d782a9a21 --- /dev/null +++ b/shared/js/background/safari.js @@ -0,0 +1,45 @@ +import { startup } from './startup-mv3' +import * as settings from './settings' + +async function registerContentScripts () { + chrome.webNavigation.onCommitted.addListener(async ({ tabId, frameId }) => { + // 1-script-injection-isolated-world + await chrome.scripting.executeScript({ + target: { + tabId, + frameIds: [frameId] + }, + world: 'ISOLATED', + files: ['public/js/content-scripts/content-scope-messaging.js'], + injectImmediately: true + }) + // 2-script-injection-main-world + await chrome.scripting.executeScript({ + target: { + tabId, + frameIds: [frameId] + }, + world: 'MAIN', + files: ['public/js/inject.js'], + injectImmediately: true + }) + }) +} + +async function setupCTLAllowingRules () { + const allowingRulesByClickToLoadAction = await (await fetch('/data/bundled/ctl-allow-rules.json')).json() + settings.updateSetting('allowingDnrRulesByClickToLoadRuleAction', allowingRulesByClickToLoadAction) +} + +(async () => { + globalThis.dbg = await startup() + await registerContentScripts() + await setupCTLAllowingRules() +})() + +// show rule counter badge +if (chrome.declarativeNetRequest.setExtensionActionOptions) { + chrome.declarativeNetRequest.setExtensionActionOptions({ + displayActionCountAsBadgeText: true + }) +} diff --git a/shared/js/background/startup-mv3.js b/shared/js/background/startup-mv3.js new file mode 100644 index 0000000000..eeb5fdaa11 --- /dev/null +++ b/shared/js/background/startup-mv3.js @@ -0,0 +1,68 @@ +import browser from 'webextension-polyfill' +import experiment from './experiments' +import * as settings from './settings' +import * as dnrSessionId from './dnr-session-rule-id' +import * as messageHandlers from './message-handlers' + +import remoteTds from './features/local-tds' +import tabTracking from './features/tab-tracking' +import atb from './features/atb' +import * as email from './email-utils' + +import * as dnr from './dnr-config-rulesets' + +browser.runtime.onInstalled.addListener(async (details) => { + remoteTds.onInstalled() + if (details.reason.match(/install/)) { + await settings.ready() + settings.updateSetting('showWelcomeBanner', true) + atb.onInstalled() + } else if (details.reason.match(/update/)) { + atb.onUpdated() + } +}) + +browser.runtime.onMessage.addListener((req, sender) => { + const legacyMessageTypes = [ + 'addUserData', + 'getUserData', + 'removeUserData', + 'getEmailProtectionCapabilities', + 'getAddresses', + 'refreshAlias', + 'debuggerMessage' + ] + for (const legacyMessageType of legacyMessageTypes) { + if (legacyMessageType in req) { + req.messageType = legacyMessageType + req.options = req[legacyMessageType] + } + } + if (req.registeredTempAutofillContentScript) { + req.messageType = 'registeredContentScript' + } + if (req.messageType && req.messageType in messageHandlers) { + return Promise.resolve(messageHandlers[req.messageType](req.options, sender, req)) + } +}) + +export async function startup () { + // Run these init steps in parallel on the first tick + const [, tabManager,,] = await Promise.all([ + dnrSessionId.setSessionRuleOffsetFromStorage(), + tabTracking.init(), + settings.ready(), + experiment.setActiveExperiment(), + email.fetchAlias() + ]) + // tds init runs after settings + const tds = await remoteTds.init() + dnr.init(tds) + return { + settings, + tds, + tabManager, + dnr, + email + } +} diff --git a/shared/js/background/startup.js b/shared/js/background/startup.js index b8a5ba563f..8a8d3a1954 100644 --- a/shared/js/background/startup.js +++ b/shared/js/background/startup.js @@ -1,14 +1,12 @@ -import browser from 'webextension-polyfill' import { NewTabTrackerStats } from './newtab-tracker-stats' import { TrackerStats } from './classes/tracker-stats' +import * as tabTracking from './features/tab-tracking' const utils = require('./utils') const browserWrapper = require('./wrapper') -const Companies = require('./companies') const experiment = require('./experiments') const https = require('./https') const httpsStorage = require('./storage/https') const settings = require('./settings') -const tabManager = require('./tab-manager') const tdsStorage = require('./storage/tds') const trackers = require('./trackers') const dnrSessionId = require('./dnr-session-rule-id') @@ -40,8 +38,6 @@ export async function onStartup () { console.warn('Error loading tds lists', e) } - Companies.buildFromStorage() - /** * in Chrome only, try to initiate the `NewTabTrackerStats` feature */ @@ -68,15 +64,7 @@ export async function onStartup () { showContextMenuAction() } - const savedTabs = await browser.tabs.query({ status: 'complete' }) - for (let i = 0; i < savedTabs.length; i++) { - const tab = savedTabs[i] - - if (tab.url) { - // On reinstall we wish to create the tab again - await tabManager.restoreOrCreate(tab) - } - } + await tabTracking.init() if (resolveReadyPromise) { resolveReadyPromise() diff --git a/shared/js/background/storage/tds.js b/shared/js/background/storage/tds.js index a993b80527..b75bb1bd30 100644 --- a/shared/js/background/storage/tds.js +++ b/shared/js/background/storage/tds.js @@ -88,7 +88,11 @@ class TDSStorage { const listeners = this._onUpdatedListeners.get(configName) if (listeners) { for (const listener of listeners.slice()) { - await listener(configName, etag, configValue) + try { + await listener(configName, etag, configValue) + } catch (e) { + console.error(e) + } } } resolve(null) diff --git a/shared/js/background/url-utils.js b/shared/js/background/url-utils.js new file mode 100644 index 0000000000..6c4f21a14d --- /dev/null +++ b/shared/js/background/url-utils.js @@ -0,0 +1,71 @@ +import * as tldts from 'tldts' + +// Removes information from a URL, such as path, user information, and optionally sub domains +// @ts-ignore +export function extractLimitedDomainFromURL (url, { keepSubdomains } = {}) { + if (!url) return undefined + try { + const parsedURL = new URL(url) + const tld = tldts.parse(url) + if (!parsedURL || !tld) return '' + // tld.domain is null if this is an IP or the domain does not use a known TLD (e.g. localhost) + // in that case use the hostname (no truncation) + let finalURL = tld.domain || tld.hostname + if (keepSubdomains) { + finalURL = tld.hostname + } else if (tld.subdomain && tld.subdomain.toLowerCase() === 'www') { + // This is a special case where if a domain requires 'www' to work + // we keep it, even if we wouldn't normally keep subdomains. + // note that even mutliple subdomains like www.something.domain.com has + // subdomain of www.something, and wouldn't trigger this case. + finalURL = 'www.' + tld.domain + } + const port = parsedURL.port ? `:${parsedURL.port}` : '' + + return `${parsedURL.protocol}//${finalURL}${port}/` + } catch (e) { + // tried to parse invalid URL, such as an extension URL. In this case, don't modify anything + return undefined + } +} + +export function extractTopSubdomainFromHost (host) { + if (typeof host !== 'string') return false + const rgx = /\./g + // @ts-ignore + if (host.match(rgx) && host.match(rgx).length > 1) { + return host.split('.')[0] + } + return false +} + +/** + * @param {string} urlString + * @returns {string | null} etld plus one of the URL + */ +export function getBaseDomain (urlString) { + const parsedUrl = tldts.parse(urlString, { allowPrivateDomains: true }) + if (parsedUrl.hostname === 'localhost' || parsedUrl.hostname?.endsWith('.localhost') || parsedUrl.isIp) { + return parsedUrl.hostname + } + return parsedUrl.domain +} + +export function extractHostFromURL (url, shouldKeepWWW) { + if (!url) return '' + + // Tweak the URL for Firefox about:* pages to ensure that they are parsed + // correctly. For example, 'about:example' becomes 'about://example'. + if (url.startsWith('about:') && url[6] !== '/') { + url = 'about://' + url.substr(6) + } + + const urlObj = tldts.parse(url) + let hostname = urlObj.hostname || '' + + if (!shouldKeepWWW) { + hostname = hostname.replace(/^www\./, '') + } + + return hostname +} \ No newline at end of file diff --git a/shared/js/background/utils.js b/shared/js/background/utils.js index 529e612f4b..e8cf958c57 100644 --- a/shared/js/background/utils.js +++ b/shared/js/background/utils.js @@ -5,8 +5,17 @@ import settings from './settings' import * as tldts from 'tldts' import parseUserAgentString from '../shared-utils/parse-user-agent-string' import sha1 from '../shared-utils/sha1' +import { extractLimitedDomainFromURL, extractTopSubdomainFromHost, extractHostFromURL, getBaseDomain } from './url-utils' const browserInfo = parseUserAgentString() +export { + extractHostFromURL, + extractLimitedDomainFromURL, + extractTopSubdomainFromHost, + getBaseDomain +} + + /** * Produce a random float, matches the output of Math.random() but much more cryptographically psudo-random. * @returns {number} @@ -47,76 +56,6 @@ export async function sendAllTabsMessage (message, details) { } } -/** - * @param {string} urlString - * @returns {string | null} etld plus one of the URL - */ -export function getBaseDomain (urlString) { - const parsedUrl = tldts.parse(urlString, { allowPrivateDomains: true }) - if (parsedUrl.hostname === 'localhost' || parsedUrl.hostname?.endsWith('.localhost') || parsedUrl.isIp) { - return parsedUrl.hostname - } - return parsedUrl.domain -} - -export function extractHostFromURL (url, shouldKeepWWW) { - if (!url) return '' - - // Tweak the URL for Firefox about:* pages to ensure that they are parsed - // correctly. For example, 'about:example' becomes 'about://example'. - if (url.startsWith('about:') && url[6] !== '/') { - url = 'about://' + url.substr(6) - } - - const urlObj = tldts.parse(url) - let hostname = urlObj.hostname || '' - - if (!shouldKeepWWW) { - hostname = hostname.replace(/^www\./, '') - } - - return hostname -} - -// Removes information from a URL, such as path, user information, and optionally sub domains -// @ts-ignore -export function extractLimitedDomainFromURL (url, { keepSubdomains } = {}) { - if (!url) return undefined - try { - const parsedURL = new URL(url) - const tld = tldts.parse(url) - if (!parsedURL || !tld) return '' - // tld.domain is null if this is an IP or the domain does not use a known TLD (e.g. localhost) - // in that case use the hostname (no truncation) - let finalURL = tld.domain || tld.hostname - if (keepSubdomains) { - finalURL = tld.hostname - } else if (tld.subdomain && tld.subdomain.toLowerCase() === 'www') { - // This is a special case where if a domain requires 'www' to work - // we keep it, even if we wouldn't normally keep subdomains. - // note that even mutliple subdomains like www.something.domain.com has - // subdomain of www.something, and wouldn't trigger this case. - finalURL = 'www.' + tld.domain - } - const port = parsedURL.port ? `:${parsedURL.port}` : '' - - return `${parsedURL.protocol}//${finalURL}${port}/` - } catch (e) { - // tried to parse invalid URL, such as an extension URL. In this case, don't modify anything - return undefined - } -} - -export function extractTopSubdomainFromHost (host) { - if (typeof host !== 'string') return false - const rgx = /\./g - // @ts-ignore - if (host.match(rgx) && host.match(rgx).length > 1) { - return host.split('.')[0] - } - return false -} - // pull off subdomains and look for parent companies export function findParent (url) { const parts = extractHostFromURL(url).split('.') diff --git a/shared/js/background/wrapper.js b/shared/js/background/wrapper.js index a48647d1da..c361e81c10 100644 --- a/shared/js/background/wrapper.js +++ b/shared/js/background/wrapper.js @@ -41,6 +41,9 @@ export async function getFromStorage (key, cb) { // @ts-ignore export async function getFromManagedStorage (keys, cb) { + if (!browser.storage.managed) { + return {} + } try { return await browser.storage.managed.get(keys) } catch (e) { diff --git a/shared/js/shared-utils/parse-user-agent-string.js b/shared/js/shared-utils/parse-user-agent-string.js index 93d1db1f8b..88a7b51fe8 100644 --- a/shared/js/shared-utils/parse-user-agent-string.js +++ b/shared/js/shared-utils/parse-user-agent-string.js @@ -7,7 +7,7 @@ module.exports = (uaString) => { let version try { - let parsedUaParts = uaString.match(/(Firefox|Chrome|Edg)\/([0-9]+)/) + let parsedUaParts = uaString.match(/(Firefox|Chrome|Edg|Safari)\/([0-9]+)/) const isEdge = /(Edge?)\/([0-9]+)/ const isOpera = /(OPR)\/([0-9]+)/ // Above regex matches on Chrome first, so check if this is really Edge