diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 3d3ba3c8af..01ec4a7540 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -74,8 +74,9 @@ jobs: restore-keys: | ${{ runner.os }}-spm- + # Using Xcode 15 as the alpha build uses iOS 17 APIs - name: Select Xcode - run: sudo xcode-select -s /Applications/Xcode_$(<.xcode-version).app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_15.0.1.app/Contents/Developer - name: Prepare fastlane run: bundle install diff --git a/.github/workflows/sync-end-to-end.yml b/.github/workflows/sync-end-to-end.yml index df2a04df7c..3dc49732fa 100644 --- a/.github/workflows/sync-end-to-end.yml +++ b/.github/workflows/sync-end-to-end.yml @@ -60,4 +60,23 @@ jobs: env: | CODE=${{ steps.sync-recovery-code.outputs.recovery-code }} + - name: Create Asana task when workflow failed + if: ${{ failure() }} + run: | + curl -s "https://app.asana.com/api/1.0/tasks" \ + --header "Accept: application/json" \ + --header "Authorization: Bearer ${{ secrets.ASANA_ACCESS_TOKEN }}" \ + --header "Content-Type: application/json" \ + --data ' { "data": { "name": "GH Workflow Failure - Sync End to end tests", "workspace": "${{ vars.GH_ASANA_WORKSPACE_ID }}", "projects": [ "${{ vars.GH_ASANA_IOS_APP_PROJECT_ID }}" ], "notes" : "The end to end workflow has failed. See https://github.com/duckduckgo/iOS/actions/runs/${{ github.run_id }}" } }' + + - name: Upload logs when workflow failed + uses: actions/upload-artifact@v3 + if: failure() + with: + name: BuildLogs + path: | + xcodebuild.log + DerivedData/Logs/Test/*.xcresult + retention-days: 7 + diff --git a/.maestro/release_tests/emailprotection.yaml b/.maestro/release_tests/emailprotection.yaml index 67b41ef000..e4cc61fba4 100644 --- a/.maestro/release_tests/emailprotection.yaml +++ b/.maestro/release_tests/emailprotection.yaml @@ -17,7 +17,7 @@ tags: - scroll - scroll - assertVisible: Email Protection -- tapOn: Email Protection, Block email trackers and hide your address +- tapOn: Email Protection - assertVisible: id: searchEntry - assertVisible: https://duckduckgo.com/email/ diff --git a/.maestro/shared/sync_create.yaml b/.maestro/shared/sync_create.yaml index 8164466ac3..bc4bb338d0 100644 --- a/.maestro/shared/sync_create.yaml +++ b/.maestro/shared/sync_create.yaml @@ -1,12 +1,10 @@ appId: com.duckduckgo.mobile.ios --- -- assertVisible: Sync -- tapOn: Sync -- assertVisible: Sync -- tapOn: "0" -- assertVisible: Turn on Sync? -- tapOn: Turn on Sync -- tapOn: Sync Another Device -- tapOn: Show QR Code -- assertVisible: "Go to Settings > Sync in the DuckDuckGo App on a different device and scan this QR code to sync." \ No newline at end of file +- assertVisible: Sync & Back Up +- tapOn: Sync & Back Up +- assertVisible: Sync & Back Up +- tapOn: Start Sync & Back Up +- assertVisible: All Set! +- tapOn: Next +- assertVisible: Save Recovery Code? diff --git a/.maestro/shared/sync_delete.yaml b/.maestro/shared/sync_delete.yaml index a82919c953..54a78f3c15 100644 --- a/.maestro/shared/sync_delete.yaml +++ b/.maestro/shared/sync_delete.yaml @@ -1,7 +1,7 @@ appId: com.duckduckgo.mobile.ios --- -- assertVisible: Sync +- assertVisible: Sync & Back Up - scroll - tapOn: point: 50%,91% # TODO: Revisit after new setup flow has been implemented. diff --git a/.maestro/sync_tests/01_create_account.yaml b/.maestro/sync_tests/01_create_account.yaml index 6e39ee2fd4..5b48e6c829 100644 --- a/.maestro/sync_tests/01_create_account.yaml +++ b/.maestro/sync_tests/01_create_account.yaml @@ -21,9 +21,7 @@ tags: # Clean up -- tapOn: Back -- tapOn: Cancel - tapOn: Not Now -- assertVisible: Sync +- assertVisible: Sync & Back Up - runFlow: - file: ../shared/sync_delete.yaml \ No newline at end of file + file: ../shared/sync_delete.yaml diff --git a/.maestro/sync_tests/02_login_account.yaml b/.maestro/sync_tests/02_login_account.yaml index aef46f2912..99a69684fa 100644 --- a/.maestro/sync_tests/02_login_account.yaml +++ b/.maestro/sync_tests/02_login_account.yaml @@ -21,25 +21,22 @@ tags: file: ../shared/sync_create.yaml # Copy Sync Code and Log Out -- tapOn: Back -- tapOn: Cancel -- assertVisible: Save Recovery Key -- tapOn: Copy Key +- tapOn: Copy Code - tapOn: Not Now -- tapOn: "1" +- assertVisible: Sync & Back Up +- tapOn: Turn Off Sync & Back Up - assertVisible: Turn Off Sync? - tapOn: Remove # Login -- tapOn: "0" -- tapOn: Recover Your Synced Data -- tapOn: Manually Enter Code +- assertVisible: Sync & Back Up +- tapOn: Enter Text Code - tapOn: Paste - assertVisible: Device Synced! - tapOn: Next - tapOn: Not Now # Clean up -- assertVisible: Sync +- assertVisible: Sync & Back Up - runFlow: - file: ../shared/sync_delete.yaml \ No newline at end of file + file: ../shared/sync_delete.yaml diff --git a/.maestro/sync_tests/03_recover_account.yaml b/.maestro/sync_tests/03_recover_account.yaml index 265684b884..d20cbf3b3b 100644 --- a/.maestro/sync_tests/03_recover_account.yaml +++ b/.maestro/sync_tests/03_recover_account.yaml @@ -19,8 +19,12 @@ tags: - tapOn: id: searchEntry - inputText: ${CODE} -- longPressOn: - id: searchEntry +- repeat: + while: + notVisible: "Select All" + commands: + - tapOn: + id: searchEntry - tapOn: Select All - tapOn: Cut - tapOn: @@ -35,14 +39,11 @@ tags: - tapOn: Settings - runFlow: file: ../shared/set_internal_user.yaml -- assertVisible: Sync -- tapOn: Sync -- assertVisible: Sync -- tapOn: "0" -- assertVisible: Turn on Sync? -- tapOn: Recover Your Synced Data -- assertVisible: Scan QR Code -- tapOn: Manually Enter Code +- assertVisible: Sync & Back Up +- tapOn: Sync & Back Up +- assertVisible: Sync & Back up +- tapOn: Recover Your Data +- tapOn: Enter Text Code - tapOn: Paste - assertVisible: Device Synced! - tapOn: Next diff --git a/.maestro/sync_tests/04_sync_data.yaml b/.maestro/sync_tests/04_sync_data.yaml index 643cd1a431..329b22bb80 100644 --- a/.maestro/sync_tests/04_sync_data.yaml +++ b/.maestro/sync_tests/04_sync_data.yaml @@ -56,14 +56,12 @@ tags: - tapOn: id: searchEntry - inputText: ${CODE} -- longPressOn: - id: searchEntry -- runFlow: - when: - visible: - text: searchEntry +- repeat: + while: + notVisible: "Select All" commands: - - tapOn: searchEntry + - tapOn: + id: searchEntry - tapOn: Select All - tapOn: Cut - tapOn: @@ -86,14 +84,11 @@ tags: - tapOn: Settings - runFlow: file: ../shared/set_internal_user.yaml -- assertVisible: Sync -- tapOn: Sync -- assertVisible: Sync -- tapOn: "0" -- assertVisible: Turn on Sync? -- tapOn: Recover Your Synced Data -- assertVisible: Scan QR Code -- tapOn: Manually Enter Code +- assertVisible: Sync & Back Up +- tapOn: Sync & Back Up +- assertVisible: Sync & Back up +- tapOn: Recover Your Data +- tapOn: Enter Text Code - tapOn: Paste - assertVisible: Device Synced! - tapOn: Next diff --git a/Configuration/Version.xcconfig b/Configuration/Version.xcconfig index f16be59a1f..773b0e1646 100644 --- a/Configuration/Version.xcconfig +++ b/Configuration/Version.xcconfig @@ -1 +1 @@ -MARKETING_VERSION = 7.96.0 +MARKETING_VERSION = 7.97.0 diff --git a/Core/AppDeepLinkSchemes.swift b/Core/AppDeepLinkSchemes.swift index c88f697cbc..38fa976b99 100644 --- a/Core/AppDeepLinkSchemes.swift +++ b/Core/AppDeepLinkSchemes.swift @@ -31,6 +31,8 @@ public enum AppDeepLinkSchemes: String, CaseIterable { case addFavorite = "ddgAddFavorite" + case openVPN = "ddgOpenVPN" + public var url: URL { URL(string: rawValue + "://")! } diff --git a/Core/AppPrivacyConfigurationDataProvider.swift b/Core/AppPrivacyConfigurationDataProvider.swift index 3e07b81b83..4e4e1e6202 100644 --- a/Core/AppPrivacyConfigurationDataProvider.swift +++ b/Core/AppPrivacyConfigurationDataProvider.swift @@ -23,8 +23,8 @@ import BrowserServicesKit final public class AppPrivacyConfigurationDataProvider: EmbeddedDataProvider { public struct Constants { - public static let embeddedDataETag = "\"39c652b21aa330463726faf240e03445\"" - public static let embeddedDataSHA = "b19c28e816008ace47a9e3e58f74eef6558b5cbdcd7d79d098d7d2e56d686075" + public static let embeddedDataETag = "\"71b1b5499f333348df4f9bc52b74185f\"" + public static let embeddedDataSHA = "a5b30cf79e5efc40fec6fb28491a7484822041d927a6e2d8c9c7ccd3bd236c61" } public var embeddedDataEtag: String { diff --git a/Core/AppTrackerDataSetProvider.swift b/Core/AppTrackerDataSetProvider.swift index 625fe0a39b..c41f8ed1b5 100644 --- a/Core/AppTrackerDataSetProvider.swift +++ b/Core/AppTrackerDataSetProvider.swift @@ -23,8 +23,8 @@ import BrowserServicesKit final public class AppTrackerDataSetProvider: EmbeddedDataProvider { public struct Constants { - public static let embeddedDataETag = "\"3b73923ebfd4702c33aea682db0bac11\"" - public static let embeddedDataSHA = "16e1e52530db19badfefc9a07d76620f9c608c12dc144f67020da8a9a4ddb0fa" + public static let embeddedDataETag = "\"3a50d09fd78a893f1a284051d1f777de\"" + public static let embeddedDataSHA = "2c1995807a61fd9fa311baab01633411282759732f098765f5380bda5e92b9e2" } public var embeddedDataEtag: String { diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index a2005a22f2..37e48dcb73 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -203,7 +203,8 @@ extension Pixel { case autofillLoginsSaveLoginModalDisplayed case autofillLoginsSaveLoginModalConfirmed case autofillLoginsSaveLoginModalDismissed - + case autofillLoginsSaveLoginModalExcludeSiteConfirmed + case autofillLoginsSavePasswordModalDisplayed case autofillLoginsSavePasswordModalConfirmed case autofillLoginsSavePasswordModalDismissed @@ -238,6 +239,9 @@ extension Pixel { case autofillLoginsSettingsEnabled case autofillLoginsSettingsDisabled case autofillLoginsSettingsAddNewLoginErrorAttemptedToCreateDuplicate + case autofillLoginsSettingsResetExcludedDisplayed + case autofillLoginsSettingsResetExcludedConfirmed + case autofillLoginsSettingsResetExcludedDismissed case autofillLoginsPasswordGenerationPromptDisplayed case autofillLoginsPasswordGenerationPromptConfirmed @@ -312,6 +316,8 @@ extension Pixel { case networkProtectionClientFailedToEncodeRegisterKeyRequest case networkProtectionClientFailedToFetchRegisteredServers case networkProtectionClientFailedToParseRegisteredServersResponse + case networkProtectionClientFailedToFetchLocations + case networkProtectionClientFailedToParseLocationsResponse case networkProtectionClientFailedToEncodeRedeemRequest case networkProtectionClientInvalidInviteCode case networkProtectionClientFailedToRedeemInviteCode @@ -358,9 +364,6 @@ extension Pixel { case remoteMessageSecondaryActionClicked case remoteMessageSheet - // MARK: Return user measurement - case returnUser - // MARK: debug pixels case dbCrashDetected @@ -700,7 +703,8 @@ extension Pixel.Event { case .autofillLoginsSaveLoginModalDisplayed: return "m_autofill_logins_save_login_inline_displayed" case .autofillLoginsSaveLoginModalConfirmed: return "m_autofill_logins_save_login_inline_confirmed" case .autofillLoginsSaveLoginModalDismissed: return "m_autofill_logins_save_login_inline_dismissed" - + case .autofillLoginsSaveLoginModalExcludeSiteConfirmed: return "m_autofill_logins_save_login_exclude_site_confirmed" + case .autofillLoginsSavePasswordModalDisplayed: return "m_autofill_logins_save_password_inline_displayed" case .autofillLoginsSavePasswordModalConfirmed: return "m_autofill_logins_save_password_inline_confirmed" case .autofillLoginsSavePasswordModalDismissed: return "m_autofill_logins_save_password_inline_dismissed" @@ -742,6 +746,9 @@ extension Pixel.Event { case .autofillLoginsSettingsDisabled: return "m_autofill_logins_settings_disabled" case .autofillLoginsSettingsAddNewLoginErrorAttemptedToCreateDuplicate: return "m_autofill_logins_settings_add-new-login_error_attempted-to-create-duplicate" + case .autofillLoginsSettingsResetExcludedDisplayed: return "m_autofill_settings_reset_excluded_displayed" + case .autofillLoginsSettingsResetExcludedConfirmed: return "m_autofill_settings_reset_excluded_confirmed" + case .autofillLoginsSettingsResetExcludedDismissed: return "m_autofill_settings_reset_excluded_dismissed" case .autofillLoginsPasswordGenerationPromptDisplayed: return "m_autofill_logins_password_generation_prompt_displayed" case .autofillLoginsPasswordGenerationPromptConfirmed: return "m_autofill_logins_password_generation_prompt_confirmed" @@ -810,6 +817,9 @@ extension Pixel.Event { case .networkProtectionClientFailedToFetchRegisteredServers: return "m_netp_backend_api_error_failed_to_fetch_registered_servers" case .networkProtectionClientFailedToParseRegisteredServersResponse: return "m_netp_backend_api_error_parsing_device_registration_response_failed" + case .networkProtectionClientFailedToFetchLocations: return "m_netp_backend_api_error_failed_to_fetch_locations" + case .networkProtectionClientFailedToParseLocationsResponse: + return "m_netp_backend_api_error_parsing_locations_response_failed" case .networkProtectionClientFailedToEncodeRedeemRequest: return "m_netp_backend_api_error_encoding_redeem_request_body_failed" case .networkProtectionClientInvalidInviteCode: return "m_netp_backend_api_error_invalid_invite_code" case .networkProtectionClientFailedToRedeemInviteCode: return "m_netp_backend_api_error_failed_to_redeem_invite_code" @@ -998,7 +1008,6 @@ extension Pixel.Event { case .compilationFailed: return "m_d_compilation_failed" // MARK: - Return user measurement - case .returnUser: return "m_return_user" case .debugReturnUserAddATB: return "m_debug_return_user_add_atb" case .debugReturnUserReadATB: return "m_debug_return_user_read_atb" case .debugReturnUserUpdateATB: return "m_debug_return_user_update_atb" diff --git a/Core/ReturnUserMeasurement.swift b/Core/ReturnUserMeasurement.swift index 0dce183c42..f4a9507a08 100644 --- a/Core/ReturnUserMeasurement.swift +++ b/Core/ReturnUserMeasurement.swift @@ -45,9 +45,6 @@ class KeychainReturnUserMeasurement: ReturnUserMeasurement { } func installCompletedWithATB(_ atb: Atb) { - if let oldATB = readSecureATB() { - sendReturnUserMeasurement(oldATB, atb.version) - } writeSecureATB(atb.version) } @@ -88,34 +85,6 @@ class KeychainReturnUserMeasurement: ReturnUserMeasurement { } - private func readSecureATB() -> String? { - let query: [String: Any] = [ - kSecClass as String: kSecClassGenericPassword, - kSecAttrAccount as String: Self.SecureATBKeychainName, - kSecReturnData as String: kCFBooleanTrue!, - kSecMatchLimit as String: kSecMatchLimitOne - ] - - var dataTypeRef: AnyObject? - let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef) - if ![errSecSuccess, errSecItemNotFound].contains(status) { - fireDebugPixel(.debugReturnUserReadATB, errorCode: status) - } - - if let data = dataTypeRef as? Data { - return String(data: data, encoding: .utf8) - } - - return nil - } - - private func sendReturnUserMeasurement(_ oldATB: String, _ newATB: String) { - Pixel.fire(pixel: .returnUser, withAdditionalParameters: [ - PixelParameters.returnUserOldATB: oldATB, - PixelParameters.returnUserNewATB: newATB - ]) - } - private func fireDebugPixel(_ event: Pixel.Event, errorCode: OSStatus) { Pixel.fire(pixel: event, withAdditionalParameters: [ PixelParameters.returnUserErrorCode: "\(errorCode)" diff --git a/Core/UserDefaults+NetworkProtection.swift b/Core/UserDefaults+NetworkProtection.swift index fb9def1004..e137aa51c2 100644 --- a/Core/UserDefaults+NetworkProtection.swift +++ b/Core/UserDefaults+NetworkProtection.swift @@ -31,4 +31,10 @@ public extension UserDefaults { } } +public enum NetworkProtectionUserDefaultKeys { + + public static let lastSelectedServer = "com.duckduckgo.network-protection.last-selected-server" + +} + #endif diff --git a/Core/UserDefaultsPropertyWrapper.swift b/Core/UserDefaultsPropertyWrapper.swift index 78a4507ba0..47c17546f9 100644 --- a/Core/UserDefaultsPropertyWrapper.swift +++ b/Core/UserDefaultsPropertyWrapper.swift @@ -81,7 +81,7 @@ public struct UserDefaultsWrapper { case autofillCredentialsSavePromptShowAtLeastOnce = "com.duckduckgo.ios.autofillCredentialsSavePromptShowAtLeastOnce" case autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary = "com.duckduckgo.ios.autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary" - + case featureFlaggingDidVerifyInternalUser = "com.duckduckgo.app.featureFlaggingDidVerifyInternalUser" case voiceSearchEnabled = "com.duckduckgo.app.voiceSearchEnabled" diff --git a/Core/ios-config.json b/Core/ios-config.json index 530bbe5602..ce6aeae32a 100644 --- a/Core/ios-config.json +++ b/Core/ios-config.json @@ -1,6 +1,6 @@ { "readme": "https://github.com/duckduckgo/privacy-configuration", - "version": 1699039046694, + "version": 1699875322077, "features": { "adClickAttribution": { "readme": "https://help.duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections/#3rd-party-tracker-loading-protection", @@ -82,6 +82,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -107,7 +110,7 @@ ] }, "state": "enabled", - "hash": "5a2395ef011fb7be4acb7885024e63fe" + "hash": "5bfae22c5e0cb13c0a25ce80531827ff" }, "androidBrowserConfig": { "exceptions": [], @@ -247,6 +250,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -255,7 +261,7 @@ ] }, "state": "enabled", - "hash": "03b154384cddc4cecfd685959d658256" + "hash": "4719cb6c793d13a9ac81c329f4d206c8" }, "autofill": { "exceptions": [ @@ -298,12 +304,15 @@ }, { "percent": 10 + }, + { + "percent": 100 } ] } } }, - "hash": "968968437514e582ebd4789a22207b91" + "hash": "3d95a9b3c8112148eda0ad09b1002b53" }, "clickToLoad": { "exceptions": [ @@ -915,6 +924,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -932,7 +944,7 @@ } }, "state": "disabled", - "hash": "f57113e4f2e7dd0fb93f5f73f9ef4fdb" + "hash": "36e8971fa9bb204b78a5929a14a108dd" }, "clickToPlay": { "exceptions": [ @@ -944,6 +956,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -956,7 +971,7 @@ } }, "state": "disabled", - "hash": "6724dd4acc868b402c6d23193bc6ba56" + "hash": "4390af06f967ef97a827aeab0ac0d1ca" }, "contentBlocking": { "state": "enabled", @@ -976,9 +991,6 @@ { "domain": "ads.google.com" }, - { - "domain": "sundancecatalog.com" - }, { "domain": "earth.google.com" }, @@ -987,9 +999,12 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], - "hash": "aa730da73ce0d03c67fcac68f9196b97" + "hash": "71ad0f38f9ce2bbacae5ff7db05511ec" }, "cookie": { "settings": { @@ -1036,10 +1051,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "01ed94213fc52b4ef93d988070491c49" + "hash": "e41dbd0af3841636937030d91bc305b1" }, "customUserAgent": { "settings": { @@ -1218,12 +1236,18 @@ { "domain": "marvel.com" }, + { + "domain": "sundancecatalog.com" + }, { "domain": "cvs.com" }, { "domain": "facebook.com" }, + { + "domain": "finewineandgoodspirits.com" + }, { "domain": "formula1.com" }, @@ -1261,12 +1285,15 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ] }, "exceptions": [], "state": "enabled", - "hash": "232df10f29daf038ce889d28a9064a6b" + "hash": "b101ded240bc51fce0ece83191b2da62" }, "duckPlayer": { "exceptions": [], @@ -1339,60 +1366,6 @@ { "domain": "duckduckgo.com" }, - { - "domain": "bild.de" - }, - { - "domain": "derstandard.at" - }, - { - "domain": "foxnews.com" - }, - { - "domain": "kbb.com" - }, - { - "domain": "wiwo.de" - }, - { - "domain": "metro.co.uk" - }, - { - "domain": "blick.ch" - }, - { - "domain": "thechive.com" - }, - { - "domain": "bizjournals.com" - }, - { - "domain": "slate.com" - }, - { - "domain": "dailycaller.com" - }, - { - "domain": "dailymail.co.uk" - }, - { - "domain": "eltiempo.com" - }, - { - "domain": "dailyherald.com" - }, - { - "domain": "publico.es" - }, - { - "domain": "rawstory.com" - }, - { - "domain": "allgemeine-zeitung.de" - }, - { - "domain": "thehindu.com" - }, { "domain": "earth.google.com" }, @@ -1401,6 +1374,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -1610,6 +1586,10 @@ "selector": ".ad_container", "type": "closest-empty" }, + { + "selector": ".ad-container--leaderboard", + "type": "hide-empty" + }, { "selector": ".ads_container", "type": "hide-empty" @@ -1813,10 +1793,6 @@ { "selector": "#ez-content-blocker-container", "type": "hide" - }, - { - "selector": "#notify-adblock", - "type": "hide" } ], "styleTagExceptions": [ @@ -1863,6 +1839,7 @@ "advertisementhide ad", "advertisement - scroll to continue", "advertisement · scroll to continue", + "advertisement - story continues below", "advertising", "advertising\nskip ad", "advertising\nskip ad\nskip ad\nskip ad", @@ -1911,6 +1888,35 @@ } ] }, + { + "domain": "allgemeine-zeitung.de", + "rules": [ + { + "type": "disable-default" + }, + { + "selector": ".adSlot", + "type": "hide-empty" + }, + { + "selector": ".adBorder", + "type": "hide-empty" + }, + { + "selector": ".nativeAd", + "type": "closest-empty" + } + ] + }, + { + "domain": "androidpolice.com", + "rules": [ + { + "selector": "[class*='ad-zone']", + "type": "hide" + } + ] + }, { "domain": "apnews.com", "rules": [ @@ -1951,6 +1957,31 @@ } ] }, + { + "domain": "bild.de", + "rules": [ + { + "type": "disable-default" + }, + { + "selector": "[id^='mrec']", + "type": "hide-empty" + }, + { + "selector": "#superbanner", + "type": "hide-empty" + } + ] + }, + { + "domain": "bizjournals.com", + "rules": [ + { + "selector": ".adwrap", + "type": "closest-empty" + } + ] + }, { "domain": "bleacherreport.com", "rules": [ @@ -1969,6 +2000,15 @@ } ] }, + { + "domain": "blick.ch", + "rules": [ + { + "selector": "[id*='appnexus-placement-']", + "type": "hide-empty" + } + ] + }, { "domain": "bloomberg.com", "rules": [ @@ -2070,6 +2110,31 @@ } ] }, + { + "domain": "dailyherald.com", + "rules": [ + { + "selector": ".instoryAdBlock", + "type": "hide" + } + ] + }, + { + "domain": "dailymail.co.uk", + "rules": [ + { + "type": "disable-default" + }, + { + "selector": "[class*='dmg-ads']", + "type": "hide-empty" + }, + { + "selector": ".mol-ads-label-container", + "type": "closest-empty" + } + ] + }, { "domain": "dallasnews.com", "rules": [ @@ -2235,6 +2300,27 @@ } ] }, + { + "domain": "foodnetwork.co.uk", + "rules": [ + { + "selector": ".bg-bodyBg", + "type": "hide-empty" + }, + { + "selector": ".module--ad-module-primary", + "type": "hide-empty" + }, + { + "selector": "#mtf-1", + "type": "closest-empty" + }, + { + "selector": "#btf-1", + "type": "closest-empty" + } + ] + }, { "domain": "football365.com", "rules": [ @@ -2481,6 +2567,15 @@ } ] }, + { + "domain": "insider.com", + "rules": [ + { + "selector": ".in-post-sticky", + "type": "hide-empty" + } + ] + }, { "domain": "investing.com", "rules": [ @@ -2581,6 +2676,18 @@ } ] }, + { + "domain": "metro.co.uk", + "rules": [ + { + "type": "disable-default" + }, + { + "selector": ".ad-slot-container", + "type": "hide-empty" + } + ] + }, { "domain": "mirror.co.uk", "rules": [ @@ -2847,6 +2954,19 @@ } ] }, + { + "domain": "publico.es", + "rules": [ + { + "selector": ".pb-ads", + "type": "hide-empty" + }, + { + "selector": "#sc_intxt_container", + "type": "hide" + } + ] + }, { "domain": "qz.com", "rules": [ @@ -2856,6 +2976,35 @@ } ] }, + { + "domain": "rawstory.com", + "rules": [ + { + "selector": ".container_proper-ad-unit", + "type": "hide" + }, + { + "selector": ".controlled_via_ad_manager", + "type": "hide" + }, + { + "selector": ".mgid_3x2", + "type": "hide-empty" + }, + { + "selector": ".proper-ad-unit", + "type": "hide" + }, + { + "selector": "[id^='rc-widget-']", + "type": "hide-empty" + }, + { + "selector": "#story-top-ad", + "type": "hide" + } + ] + }, { "domain": "reddit.com", "rules": [ @@ -2983,6 +3132,10 @@ { "selector": ".slate-ad", "type": "hide-empty" + }, + { + "selector": ".top-ad", + "type": "hide" } ] }, @@ -3021,6 +3174,15 @@ } ] }, + { + "domain": "sportbible.com", + "rules": [ + { + "selector": "[class*='Advert']", + "type": "hide" + } + ] + }, { "domain": "target.com", "rules": [ @@ -3039,6 +3201,15 @@ } ] }, + { + "domain": "thegatewaypundit.com", + "rules": [ + { + "selector": ".code-block", + "type": "hide" + } + ] + }, { "domain": "thehour.com", "rules": [ @@ -3048,6 +3219,15 @@ } ] }, + { + "domain": "thehindu.com", + "rules": [ + { + "selector": "#articledivrec", + "type": "hide-empty" + } + ] + }, { "domain": "thetimes.co.uk", "rules": [ @@ -3183,6 +3363,10 @@ { "selector": "[class^='Ad__Container-']", "type": "hide" + }, + { + "selector": "#ac-lre-player", + "type": "hide-empty" } ] }, @@ -3212,6 +3396,15 @@ } ] }, + { + "domain": "westernjournal.com", + "rules": [ + { + "selector": ".sponsor", + "type": "hide-empty" + } + ] + }, { "domain": "washingtonpost.com", "rules": [ @@ -3247,6 +3440,14 @@ } ] }, + { + "domain": "wiwo.de", + "rules": [ + { + "type": "disable-default" + } + ] + }, { "domain": "wsj.com", "rules": [ @@ -3409,7 +3610,7 @@ ] }, "state": "enabled", - "hash": "903602d78d217518a48be612b2a08f3e" + "hash": "15184cba961aadf588965f6caf070306" }, "exceptionHandler": { "exceptions": [ @@ -3421,10 +3622,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "acf631a1f283d1ea71e5d3116f17a110" + "hash": "5e792dd491428702bc0104240fbce0ce" }, "fingerprintingAudio": { "state": "disabled", @@ -3440,9 +3644,12 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], - "hash": "aec17726775580a32c51d6ad0559c13f" + "hash": "f25a8f2709e865c2bd743828c7ee2f77" }, "fingerprintingBattery": { "exceptions": [ @@ -3457,10 +3664,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "enabled", - "hash": "f74e2255710593a76b5a80571da555a2" + "hash": "440f8d663d59430c93d66208655d9238" }, "fingerprintingCanvas": { "settings": { @@ -3559,10 +3769,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "55ba309065f40d78a5f0308411d6df97" + "hash": "ea4c565bae27996f0d651300d757594c" }, "fingerprintingHardware": { "settings": { @@ -3610,10 +3823,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "enabled", - "hash": "81bda64a0a893eebb721772fbd64126a" + "hash": "911cbc583f376d416ac75c57ecc577f1" }, "fingerprintingScreenSize": { "settings": { @@ -3661,10 +3877,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "enabled", - "hash": "4fa7c8746240605af7885a953dcbdfe9" + "hash": "0fb22f84b750e0d29bad55bd95d9ce2b" }, "fingerprintingTemporaryStorage": { "exceptions": [ @@ -3682,10 +3901,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "enabled", - "hash": "5e81950bd7e1cbf6489ed4fb7d5b57fb" + "hash": "568a23faa984c8e7eda002294ad8f82f" }, "googleRejected": { "exceptions": [ @@ -3697,10 +3919,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "acf631a1f283d1ea71e5d3116f17a110" + "hash": "5e792dd491428702bc0104240fbce0ce" }, "gpc": { "state": "enabled", @@ -3737,6 +3962,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -3748,7 +3976,7 @@ "privacy-test-pages.site" ] }, - "hash": "0a23d1c1dc75bb6664af7d81c6f80e77" + "hash": "083267b595694bd75cda73218f8811c2" }, "harmfulApis": { "settings": { @@ -3858,10 +4086,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "cd14e5f0c64cbe269b73cd40b8c89c42" + "hash": "44d3e707cba3ee0a3578f52dc2ce2aa4" }, "https": { "state": "enabled", @@ -3883,9 +4114,12 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], - "hash": "b055b164b3c3a9f20ad93e041be1810e" + "hash": "f772808ed34cc9ea8cbcbb7cdaf74429" }, "incontextSignup": { "exceptions": [], @@ -3923,6 +4157,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -3933,7 +4170,7 @@ ] }, "state": "enabled", - "hash": "9cbed3731aad3fb286c8245ba8ff87dd" + "hash": "698de7b963d7d7942c5c5d1e986bb1b1" }, "networkProtection": { "state": "disabled", @@ -3966,10 +4203,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "e2fe271add53f2e5dafb31b235d1fa54" + "hash": "841fa92b9728c9754f050662678f82c7" }, "privacyDashboard": { "exceptions": [], @@ -4012,10 +4252,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "6a035dc634a0eaff88ce00de3905a1bb" + "hash": "0d3df0f7c24ebde89d2dced4e2d34322" }, "requestFilterer": { "state": "disabled", @@ -4028,12 +4271,15 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { "windowInMs": 0 }, - "hash": "591960d057333a55489a557f5cd7d121" + "hash": "0fff8017d8ea4b5609b8f5c110be1401" }, "runtimeChecks": { "state": "disabled", @@ -4046,10 +4292,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": {}, - "hash": "158fe8be52fa1c0fabf08d8a12fd55b0" + "hash": "800a19533c728bbec7e31e466f898268" }, "serviceworkerInitiatedRequests": { "exceptions": [ @@ -4061,10 +4310,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "acf631a1f283d1ea71e5d3116f17a110" + "hash": "5e792dd491428702bc0104240fbce0ce" }, "trackerAllowlist": { "state": "enabled", @@ -4191,6 +4443,16 @@ } ] }, + "adserver.adtech.advertising.com": { + "rules": [ + { + "rule": "adserver.adtech.advertising.com/pubapi/3.0/1/54669.7/0/0/ADTECH;v=2;cmd=bid;cors=yes", + "domains": [ + "collider.com" + ] + } + ] + }, "adswizz.com": { "rules": [ { @@ -4198,6 +4460,12 @@ "domains": [ "tunein.com" ] + }, + { + "rule": "adswizz.com/adswizz/js/SynchroClient2.js", + "domains": [ + "tunein.com" + ] } ] }, @@ -4773,7 +5041,6 @@ "rule": "pubads.g.doubleclick.net/gampad/ads", "domains": [ "crunchyroll.com", - "fifa.com", "nhl.com", "rocketnews24.com", "viki.com" @@ -5001,6 +5268,7 @@ { "rule": "app.five9.com", "domains": [ + "gmsdnv.com", "machiassavings.bank" ] } @@ -5205,6 +5473,12 @@ "" ] }, + { + "rule": "www.google.com/url", + "domains": [ + "" + ] + }, { "rule": "www.google.com/maps/", "domains": [ @@ -5213,6 +5487,16 @@ } ] }, + "googleapis.com": { + "rules": [ + { + "rule": "imasdk.googleapis.com/js/sdkloader/ima3.js", + "domains": [ + "nfl.com" + ] + } + ] + }, "googleoptimize.com": { "rules": [ { @@ -5235,6 +5519,14 @@ "zefoy.com" ] }, + { + "rule": "pagead2.googlesyndication.com/pagead/show_ads.js", + "domains": [ + "luckylandslots.com", + "rocketnews24.com", + "zefoy.com" + ] + }, { "rule": "tpc.googlesyndication.com/pagead/js/loader21.html", "domains": [ @@ -5383,6 +5675,7 @@ "thecw38.com", "thecw46.com", "thecwtc.com", + "thenationaldesk.com", "turnto10.com", "univisionseattle.com", "upnorthlive.com", @@ -5483,6 +5776,12 @@ "domains": [ "pippintitle.com" ] + }, + { + "rule": "no-cache.hubspot.com/cta/default/", + "domains": [ + "" + ] } ] }, @@ -5588,6 +5887,16 @@ } ] }, + "jsdelivr.net": { + "rules": [ + { + "rule": "cdn.jsdelivr.net/npm/@fingerprintjs/fingerprintjs@3/dist/fp.js", + "domains": [ + "sbermarket.ru" + ] + } + ] + }, "kampyle.com": { "rules": [ { @@ -5638,6 +5947,7 @@ { "rule": "static.klaviyo.com/onsite/js/klaviyo.js", "domains": [ + "essentialpraxis.com", "kidsguide.com", "urbanebikes.com" ] @@ -6774,9 +7084,12 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], - "hash": "2ea09955d838b29daa5416586bb2f25a" + "hash": "65670bfba426ac832fe6bb2082c432c8" }, "trackingCookies1p": { "settings": { @@ -6794,10 +7107,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "057704f003231b68cde1faca12adec27" + "hash": "4dddf681372a2aea9788090b13db6e6f" }, "trackingCookies3p": { "settings": { @@ -6812,10 +7128,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "e2fe271add53f2e5dafb31b235d1fa54" + "hash": "841fa92b9728c9754f050662678f82c7" }, "trackingParameters": { "exceptions": [ @@ -6828,6 +7147,9 @@ { "domain": "marvel.com" }, + { + "domain": "sundancecatalog.com" + }, { "domain": "theverge.com" } @@ -6862,7 +7184,7 @@ ] }, "state": "enabled", - "hash": "2ca96907627936c8912983c971c5f1c9" + "hash": "f2437495da4898e8e048643ab38ef372" }, "userAgentRotation": { "settings": { @@ -6877,10 +7199,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "3893596da5fb3653a6adc10538f08a2e" + "hash": "f65d10dfdf6739feab99a08d42734747" }, "voiceSearch": { "exceptions": [], @@ -6897,6 +7222,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "enabled", @@ -6929,7 +7257,7 @@ } ] }, - "hash": "3702e5c5e88b46c494d8e4ef4e17a8da" + "hash": "4e94cff79e689ff320de22a57e242bdd" }, "windowsPermissionUsage": { "exceptions": [], diff --git a/Core/trackerData.json b/Core/trackerData.json index 18ddb15be4..84975e1a36 100644 --- a/Core/trackerData.json +++ b/Core/trackerData.json @@ -1,7 +1,7 @@ { "_builtWith": { - "tracker-radar": "29f80529aa526f0a0f8daadb1c8717d6dccdbb1a45f98477de48e8a8d213d386-4013b4e91930c643394cb31c6c745356f133b04f", - "tracker-surrogates": "d61691a2fdf9f4dc062a8d248fd1e78c20b5b892" + "tracker-radar": "ae2fbc01abd26abf1903208a5cabbaed6a96ab2aa13779d2125a98fc45fee2cd-4013b4e91930c643394cb31c6c745356f133b04f", + "tracker-surrogates": "abd6067fac9693cc5a43d48931b111ca08cb0d5a" }, "readme": "https://github.com/duckduckgo/tracker-blocklists", "trackers": { @@ -136,45 +136,14 @@ "Ad Motivated Tracking", "Advertising" ], - "default": "ignore", + "default": "block", "rules": [ { - "rule": "2mdn\\.net/dot\\.gif" - }, - { - "rule": "2mdn\\.net/10533936/1679336805544/" - }, - { - "rule": "2mdn\\.net/8762481/1679421215390" - }, - { - "rule": "2mdn\\.net/879366/" - }, - { - "rule": "2mdn\\.net/ads/" - }, - { - "rule": "2mdn\\.net/creatives/assets/" - }, - { - "rule": "2mdn\\.net/dfp/" - }, - { - "rule": "2mdn\\.net/dynamic/2/" - }, - { - "rule": "2mdn\\.net/sadbundle/" - }, - { - "rule": "2mdn\\.net/simgad/[0-9]+" - }, - { - "rule": "2mdn\\.net/videoplayback" + "rule": "2mdn\\.net/instream/html5/ima3\\.js", + "surrogate": "google-ima.js" }, { "rule": "2mdn\\.net/instream/video/client\\.js", - "fingerprinting": 1, - "cookies": 0, "exceptions": { "domains": [ "dailywire.com", @@ -822,7 +791,17 @@ "Social - Share", "Third-Party Analytics Marketing" ], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "static\\.addtoany\\.com/menu/page\\.js", + "exceptions": { + "domains": [ + "tiny.cc" + ] + } + } + ] }, "adelixir.com": { "domain": "adelixir.com", @@ -2519,9 +2498,16 @@ "foxbusiness.com", "foxnews.com", "fyi.tv", + "gamingbible.co.uk", + "gamingbible.com", "history.com", + "ladbible.com", "mylifetime.com", - "sueddeutsche.de" + "sportbible.com", + "sueddeutsche.de", + "tyla.com", + "unilad.co.uk", + "unilad.com" ] } } @@ -4474,14 +4460,7 @@ "fingerprinting": 2, "cookies": 0.000824, "categories": [], - "default": "ignore", - "rules": [ - { - "rule": "boldchat\\.com/aid/.*/vms\\.js", - "fingerprinting": 2, - "cookies": 0.000201 - } - ] + "default": "ignore" }, "booking.com": { "domain": "booking.com", @@ -7761,9 +7740,14 @@ "default": "ignore", "rules": [ { - "rule": "dbukjj6eu5tsf\\.cloudfront\\.net\\/assets\\.sidearmsports\\.com\\/common\\/js\\/20170825\\/video\\.js", + "rule": "dbukjj6eu5tsf\\.cloudfront\\.net/assets\\.sidearmsports\\.com/common/js/20170825/video\\.js", "fingerprinting": 3, - "cookies": 0 + "cookies": 0, + "exceptions": { + "domains": [ + "utsports.com" + ] + } } ] }, @@ -8257,6 +8241,14 @@ "sbs.com.au" ] } + }, + { + "rule": "g\\.doubleclick\\.net/pagead/ads", + "exceptions": { + "domains": [ + "fukuishimbun.co.jp" + ] + } } ] }, @@ -9825,11 +9817,6 @@ ], "default": "ignore", "rules": [ - { - "rule": "facebook\\.net/.*/all\\.js", - "fingerprinting": 1, - "cookies": 0.0000408 - }, { "rule": "facebook\\.net/.*/fbevents\\.js", "fingerprinting": 1, @@ -10814,14 +10801,7 @@ "fingerprinting": 1, "cookies": 0.0000408, "categories": [], - "default": "ignore", - "rules": [ - { - "rule": "geoip-js\\.com\\/js\\/apis\\/geoip2\\/v2\\.1\\/geoip2\\.js", - "fingerprinting": 1, - "cookies": 0.0000204 - } - ] + "default": "ignore" }, "getblue.io": { "domain": "getblue.io", @@ -11502,7 +11482,33 @@ "Ad Motivated Tracking", "Advertising" ], - "default": "block" + "default": "ignore", + "rules": [ + { + "rule": "googleadservices\\.com/gampad/cookie\\.js" + }, + { + "rule": "googleadservices\\.com/pagead/conversion\\.js" + }, + { + "rule": "googleadservices\\.com/gampad/google_service\\.js" + }, + { + "rule": "googleadservices\\.com/gampad/google_ads\\.js" + }, + { + "rule": "googleadservices\\.com/favicon\\.ico" + }, + { + "rule": "googleadservices\\.com/ga/phone" + }, + { + "rule": "googleadservices\\.com/ccm/conversion/845940546/" + }, + { + "rule": "googleadservices\\.com/pagead/conversion/" + } + ] }, "googlehosted.com": { "domain": "googlehosted.com", @@ -11619,9 +11625,28 @@ "rule": "googlesyndication\\.com/adsbygoogle\\.js", "surrogate": "adsbygoogle.js" }, + { + "rule": "pagead2\\.googlesyndication\\.com/pagead/js/adsbygoogle\\.js", + "surrogate": "adsbygoogle.js", + "exceptions": { + "domains": [ + "dronedj.com", + "fukuishimbun.co.jp", + "spaceexplored.com" + ] + } + }, { "rule": "googlesyndication\\.com/pagead/js/adsbygoogle\\.js", "surrogate": "adsbygoogle.js" + }, + { + "rule": "pagead2\\.googlesyndication\\.com/pagead/managed/js/adsense", + "exceptions": { + "domains": [ + "fukuishimbun.co.jp" + ] + } } ] }, @@ -11986,11 +12011,6 @@ "rule": "groovehq\\.com\\/api\\/shim\\/27299f7da6676b065f217a683a418325", "fingerprinting": 2, "cookies": 0 - }, - { - "rule": "groovehq\\.com\\/_next\\/static\\/chunks\\/9fd8c5e27f99fce506e2e5d3b010ddba7982b0f2\\.7fb5a86b2706698b7a7e\\.js", - "fingerprinting": 2, - "cookies": 0 } ] }, @@ -12908,14 +12928,6 @@ ] } }, - { - "rule": "hubspot\\.com/api/livechat-public/v1/", - "exceptions": { - "types": [ - "xmlhttprequest" - ] - } - }, { "rule": "hubspot\\.com/hubfs/", "exceptions": { @@ -13255,7 +13267,13 @@ "Content Delivery", "Embedded Content" ], - "default": "ignore" + "default": "ignore", + "rules": [ + { + "rule": "imasdk\\.googleapis\\.com/js/sdkloader/ima3\\.js", + "surrogate": "google-ima.js" + } + ] }, "imedia.cz": { "domain": "imedia.cz", @@ -14240,18 +14258,6 @@ } ] }, - "ipify.org": { - "domain": "ipify.org", - "owner": { - "name": "ipify.org", - "displayName": "ipify.org" - }, - "prevalence": 0.00555, - "fingerprinting": 1, - "cookies": 0.000116, - "categories": [], - "default": "block" - }, "iplsc.com": { "domain": "iplsc.com", "owner": { @@ -15484,25 +15490,7 @@ "Embedded Content", "Third-Party Analytics Marketing" ], - "default": "ignore", - "rules": [ - { - "rule": "lightboxcdn\\.com/vendor/.*/user\\.js", - "fingerprinting": 3, - "cookies": 0.0000749 - }, - { - "rule": "lightboxcdn\\.com\\/w37htfhcq2\\/vendor\\/721dac7b-a982-4a33-afe7-ffe31144fbdd\\/user\\.js", - "fingerprinting": 3, - "cookies": 0.0000136 - }, - { - "rule": "lightboxcdn\\.com\\/vendor\\/b90a8cf1-793b-4cc5-b282-f863e44f81fa\\/lightbox_inline\\.js", - "fingerprinting": 0, - "cookies": 0, - "comment": "pixel" - } - ] + "default": "ignore" }, "lijit.com": { "domain": "lijit.com", @@ -15653,7 +15641,60 @@ "Ad Motivated Tracking", "Advertising" ], - "default": "block" + "default": "ignore", + "rules": [ + { + "rule": "linksynergy\\.com/rcs" + }, + { + "rule": "linksynergy\\.com/jsp" + }, + { + "rule": "linksynergy\\.com/cs" + }, + { + "rule": "linksynergy\\.com/act\\.php" + }, + { + "rule": "linksynergy\\.com/t" + }, + { + "rule": "linksynergy\\.com/consent/v1/p" + }, + { + "rule": "linksynergy\\.com/imp" + }, + { + "rule": "linksynergy\\.com/consent/v3/p" + }, + { + "rule": "linksynergy\\.com/phoenix/phoenix-2\\.26\\.min\\.js" + }, + { + "rule": "linksynergy\\.com/privacy/ad_choices\\.png" + }, + { + "rule": "linksynergy\\.com/fs-bin/show" + }, + { + "rule": "linksynergy\\.com/cc" + }, + { + "rule": "linksynergy\\.com/js/" + }, + { + "rule": "linksynergy\\.com/wakeup/" + }, + { + "rule": "linksynergy\\.com/advertisers/owllab9118/" + }, + { + "rule": "linksynergy\\.com/pix/[0-9]+" + }, + { + "rule": "linksynergy\\.com/[0-9]+\\.ct\\.js" + } + ] }, "list-manage.com": { "domain": "list-manage.com", @@ -16454,7 +16495,8 @@ "Embedded Content", "Social - Share" ], - "default": "ignore" + "default": "ignore", + "rules": [] }, "mailchimp.com": { "domain": "mailchimp.com", @@ -18041,7 +18083,20 @@ "fingerprinting": 0, "cookies": 0.00373, "categories": [], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "hello\\.myfonts\\.net/count/", + "exceptions": { + "domains": [ + "condor.com" + ], + "types": [ + "stylesheet" + ] + } + } + ] }, "myregistry.com": { "domain": "myregistry.com", @@ -18105,7 +18160,30 @@ "fingerprinting": 2, "cookies": 0.00189, "categories": [], - "default": "block" + "default": "ignore", + "rules": [ + { + "rule": "nakanohito\\.jp/b3/bi\\.js" + }, + { + "rule": "nakanohito\\.jp/b3/" + }, + { + "rule": "nakanohito\\.jp/uhj2/uh\\.js" + }, + { + "rule": "nakanohito\\.jp/cm/inner\\.css" + }, + { + "rule": "nakanohito\\.jp/ua/uwa\\.js" + }, + { + "rule": "nakanohito\\.jp/ua/" + }, + { + "rule": "nakanohito\\.jp/chatbot_pc\\.css" + } + ] }, "nanorep.co": { "domain": "nanorep.co", @@ -18359,6 +18437,15 @@ ], "default": "block", "rules": [ + { + "rule": "js-agent\\.newrelic\\.com", + "exceptions": { + "domains": [ + "chaturbate.com", + "johnlewis.com" + ] + } + }, { "rule": "newrelic\\.com", "exceptions": { @@ -18712,11 +18799,7 @@ "rules": [ { "rule": "npttech\\.com/advertising\\.js", - "exceptions": { - "types": [ - "script" - ] - } + "surrogate": "noop.js" } ] }, @@ -18734,7 +18817,17 @@ "categories": [ "Analytics" ], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "nr-data\\.net", + "exceptions": { + "domains": [ + "chaturbate.com" + ] + } + } + ] }, "nrich.ai": { "domain": "nrich.ai", @@ -20377,7 +20470,39 @@ "Audience Measurement", "Third-Party Analytics Marketing" ], - "default": "block" + "default": "ignore", + "rules": [ + { + "rule": "parsely\\.com/plogger/" + }, + { + "rule": "parsely\\.com/videoplugins/brightcove/videojs-parsely-loader-v1-latest\\.min\\.js" + }, + { + "rule": "parsely\\.com/videoplugins/brightcove/videojs-parsely-v1-latest\\.min\\.js" + }, + { + "rule": "parsely\\.com/v2/profile" + }, + { + "rule": "parsely\\.com/px/" + }, + { + "rule": "parsely\\.com/v2/related" + }, + { + "rule": "parsely\\.com/v2/analytics/posts" + }, + { + "rule": "parsely\\.com/v2/similar" + }, + { + "rule": "parsely\\.com/keys/adweek\\.com/p\\.js" + }, + { + "rule": "parsely\\.com/v2/search" + } + ] }, "partplanes.com": { "domain": "partplanes.com", @@ -20592,7 +20717,17 @@ "fingerprinting": 2, "cookies": 0.00574, "categories": [], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "edge\\.permutive\\.app", + "exceptions": { + "domains": [ + "globaltv.com" + ] + } + } + ] }, "permutive.com": { "domain": "permutive.com", @@ -21133,11 +21268,6 @@ "categories": [], "default": "ignore", "rules": [ - { - "rule": "powr\\.io\\/powr\\.js", - "fingerprinting": 1, - "cookies": 0.00000681 - }, { "rule": "powr\\.io\\/popup\\/u\\/61af4f5f_1680291259", "fingerprinting": 1, @@ -21409,14 +21539,7 @@ "fingerprinting": 1, "cookies": 0.000197, "categories": [], - "default": "ignore", - "rules": [ - { - "rule": "providesupport\\.com\\/sjs\\/static\\.js", - "fingerprinting": 1, - "cookies": 0.000123 - } - ] + "default": "ignore" }, "pswec.com": { "domain": "pswec.com", @@ -23122,7 +23245,23 @@ "Ad Motivated Tracking", "Advertising" ], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "micro\\.rubiconproject\\.com/prebid/dynamic/.*\\.js", + "exceptions": { + "domains": [ + "gamingbible.co.uk", + "gamingbible.com", + "ladbible.com", + "sportbible.com", + "tyla.com", + "unilad.co.uk", + "unilad.com" + ] + } + } + ] }, "ruralrobin.com": { "domain": "ruralrobin.com", @@ -25973,7 +26112,7 @@ "cookies": 0.0000136 }, { - "rule": "storage\\.googleapis\\.com/code\\.snapengage\\.com/", + "rule": "storage\\.googleapis\\.com/code\\.snapengage\\.com/js/", "fingerprinting": 3, "cookies": 0.0000136 }, @@ -27133,7 +27272,60 @@ "fingerprinting": 1, "cookies": 0.0436, "categories": [], - "default": "block" + "default": "ignore", + "rules": [ + { + "rule": "tiktok\\.com/i18n/pixel/events\\.js" + }, + { + "rule": "tiktok\\.com/i18n/pixel/static/identify_d1af3\\.js" + }, + { + "rule": "tiktok\\.com/api/v2/pixel" + }, + { + "rule": "tiktok\\.com/i18n/pixel/sdk\\.js" + }, + { + "rule": "tiktok\\.com/api/v2/performance_interaction" + }, + { + "rule": "tiktok\\.com/i18n/pixel/config\\.js" + }, + { + "rule": "tiktok\\.com/i18n/pixel/disable_cookie" + }, + { + "rule": "tiktok\\.com/i18n/pixel/static/identify_821f6\\.js" + }, + { + "rule": "tiktok\\.com/v1/user/webid" + }, + { + "rule": "tiktok\\.com/service/2/abtest_config/" + }, + { + "rule": "tiktok\\.com/web/resource" + }, + { + "rule": "tiktok\\.com/v1/list" + }, + { + "rule": "tiktok\\.com/web/report" + }, + { + "rule": "tiktok\\.com/oembed" + }, + { + "rule": "tiktok\\.com/i18n/pixel/enable_cookie" + }, + { + "rule": "tiktok\\.com/i18n/pixel/static/identify_a7248\\.js" + }, + { + "rule": "tiktok\\.com/i18n/pixel/static/main\\..*\\.js" + } + ] }, "tinypass.com": { "domain": "tinypass.com", @@ -29123,7 +29315,18 @@ "categories": [ "Advertising" ], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "cdn\\.viglink\\.com/api/vglnk\\.js", + "exceptions": { + "domains": [ + "9to5mac.com", + "electrek.co" + ] + } + } + ] }, "visualwebsiteoptimizer.com": { "domain": "visualwebsiteoptimizer.com", @@ -29856,6 +30059,14 @@ "categories": [], "default": "ignore", "rules": [ + { + "rule": "universal\\.wgplayer\\.com/tag/", + "exceptions": { + "domains": [ + "yoho.games" + ] + } + }, { "rule": "wgplayer\\.com\\/tag\\/", "fingerprinting": 1, @@ -31264,21 +31475,6 @@ "categories": [], "default": "block" }, - "zopim.com": { - "domain": "zopim.com", - "owner": { - "name": "Zendesk, Inc.", - "displayName": "Zendesk", - "privacyPolicy": "https://www.zendesk.com/company/customers-partners/privacy-policy/" - }, - "prevalence": 0.0078, - "fingerprinting": 1, - "cookies": 0.00153, - "categories": [ - "Embedded Content" - ], - "default": "block" - }, "zprk.io": { "domain": "zprk.io", "owner": { @@ -42275,13 +42471,6 @@ "prevalence": 0.0926, "displayName": "iPerceptions" }, - "ipify.org": { - "domains": [ - "ipify.org" - ], - "prevalence": 0.0163, - "displayName": "ipify.org" - }, "Grupa Interia.pl Sp. z o.o. sp. k.": { "domains": [ "adretail.pl", @@ -51319,7 +51508,6 @@ "iocnt.net": "INFOnline GmbH", "iper2.com": "iPerceptions Inc.", "iperceptions.com": "iPerceptions Inc.", - "ipify.org": "ipify.org", "adretail.pl": "Grupa Interia.pl Sp. z o.o. sp. k.", "adsearch.pl": "Grupa Interia.pl Sp. z o.o. sp. k.", "bryk.pl": "Grupa Interia.pl Sp. z o.o. sp. k.", diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index aace48e673..41659805c7 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -267,6 +267,7 @@ 37FCAAC029930E26000E420A /* FailedAssertionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FCAABF29930E26000E420A /* FailedAssertionView.swift */; }; 37FD780F2A29E28B00B36DB1 /* SyncErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FD780E2A29E28B00B36DB1 /* SyncErrorHandler.swift */; }; 4B0295192537BC6700E00CEF /* ConfigurationDebugViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0295182537BC6700E00CEF /* ConfigurationDebugViewController.swift */; }; + 4B274F602AFEAECC003F0745 /* NetworkProtectionWidgetRefreshModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B274F5F2AFEAECC003F0745 /* NetworkProtectionWidgetRefreshModel.swift */; }; 4B2754EC29E8C7DF00394032 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 4B2754EB29E8C7DF00394032 /* Lottie */; }; 4B470ED6299C49800086EBDC /* AppTrackingProtectionDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B470ED5299C49800086EBDC /* AppTrackingProtectionDatabase.swift */; }; 4B470ED9299C4AED0086EBDC /* AppTrackingProtectionModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4B470ED7299C4AED0086EBDC /* AppTrackingProtectionModel.xcdatamodeld */; }; @@ -275,6 +276,8 @@ 4B470EE4299C6DFB0086EBDC /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F143C2E41E4A4CD400CFDE3A /* Core.framework */; }; 4B52648B25F9613B00CB4C24 /* trackerData.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B52648A25F9613B00CB4C24 /* trackerData.json */; }; 4B53648A26718D0E001AA041 /* EmailWaitlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B53648926718D0E001AA041 /* EmailWaitlist.swift */; }; + 4B5C462A2AF2A6E6002A4432 /* VPNIntents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5C46292AF2A6E6002A4432 /* VPNIntents.swift */; }; + 4B5C462B2AF2BDC4002A4432 /* VPNIntents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5C46292AF2A6E6002A4432 /* VPNIntents.swift */; }; 4B60AC97252EC07B00E8D219 /* fullscreenvideo.js in Resources */ = {isa = PBXBuildFile; fileRef = 4B60AC96252EC07B00E8D219 /* fullscreenvideo.js */; }; 4B60ACA1252EC0B100E8D219 /* FullScreenVideoUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B60ACA0252EC0B100E8D219 /* FullScreenVideoUserScript.swift */; }; 4B62C4BA25B930DD008912C6 /* AppConfigurationFetchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B62C4B925B930DD008912C6 /* AppConfigurationFetchTests.swift */; }; @@ -291,6 +294,8 @@ 4B83397329AFB8D2003F7EA9 /* AppTrackingProtectionFeedbackModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B83397229AFB8D2003F7EA9 /* AppTrackingProtectionFeedbackModel.swift */; }; 4B83397529AFBCE6003F7EA9 /* AppTrackingProtectionFeedbackModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B83397429AFBCE6003F7EA9 /* AppTrackingProtectionFeedbackModelTests.swift */; }; 4B948E2629DCCDB9002531FA /* Persistence in Frameworks */ = {isa = PBXBuildFile; productRef = 4B948E2529DCCDB9002531FA /* Persistence */; }; + 4BB7CBB02AF59C310014A35F /* VPNWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB7CBAF2AF59C310014A35F /* VPNWidget.swift */; }; + 4BBBBA872B02E85400D965DA /* DesignResourcesKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4BBBBA862B02E85400D965DA /* DesignResourcesKit */; }; 4BC21A2F27238B7500229F0E /* RunLoopExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC21A2C272388BD00229F0E /* RunLoopExtensionTests.swift */; }; 4BC6DD1C2A60E6AD001EC129 /* ReportBrokenSiteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC6DD1B2A60E6AD001EC129 /* ReportBrokenSiteView.swift */; }; 4BE2756827304F57006B20B0 /* URLRequestExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE27566272F878F006B20B0 /* URLRequestExtension.swift */; }; @@ -710,9 +715,12 @@ C1B7B52D2894469D0098FD6A /* DefaultVariantManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B7B52C2894469D0098FD6A /* DefaultVariantManager.swift */; }; C1B7B53028944E390098FD6A /* RemoteMessagingStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B7B52F28944E390098FD6A /* RemoteMessagingStoreTests.swift */; }; C1B7B53428944EFA0098FD6A /* CoreDataTestUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B7B53328944EFA0098FD6A /* CoreDataTestUtilities.swift */; }; + C1B924B72ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B924B62ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift */; }; C1BF0BA529B63D7200482B73 /* AutofillLoginPromptHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */; }; C1BF0BA929B63E2200482B73 /* AutofillLoginPromptViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */; }; C1CCCBA7283E101500CF3791 /* FaviconsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CCCBA6283E101500CF3791 /* FaviconsHelper.swift */; }; + C1CDA3162AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CDA3152AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift */; }; + C1CDA31E2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CDA31D2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift */; }; C1D21E2D293A5965006E5A05 /* AutofillLoginSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */; }; C1D21E2F293A599C006E5A05 /* AutofillLoginSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */; }; C1F341C52A6924000032057B /* EmailAddressPromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F341C42A6924000032057B /* EmailAddressPromptView.swift */; }; @@ -753,6 +761,8 @@ EE0153EB2A6FF970002A8B26 /* NetworkProtectionRootViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0153EA2A6FF970002A8B26 /* NetworkProtectionRootViewModelTests.swift */; }; EE0153ED2A6FF9E6002A8B26 /* NetworkProtectionRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0153EC2A6FF9E6002A8B26 /* NetworkProtectionRootView.swift */; }; EE0153EF2A70021E002A8B26 /* NetworkProtectionInviteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0153EE2A70021E002A8B26 /* NetworkProtectionInviteView.swift */; }; + EE01EB402AFBD0000096AAC9 /* NetworkProtectionVPNSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE01EB3F2AFBD0000096AAC9 /* NetworkProtectionVPNSettingsViewModel.swift */; }; + EE01EB432AFC1E0A0096AAC9 /* NetworkProtectionVPNLocationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE01EB422AFC1E0A0096AAC9 /* NetworkProtectionVPNLocationView.swift */; }; EE276BEA2A77F823009167B6 /* NetworkProtectionRootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE276BE92A77F823009167B6 /* NetworkProtectionRootViewController.swift */; }; EE3766DE2AC5945500AAB575 /* NetworkProtectionUNNotificationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE3766DD2AC5945500AAB575 /* NetworkProtectionUNNotificationPresenter.swift */; }; EE3B226B29DE0F110082298A /* MockInternalUserStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE3B226A29DE0F110082298A /* MockInternalUserStoring.swift */; }; @@ -1282,6 +1292,7 @@ 37FCAACB2993149A000E420A /* Waitlist */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Waitlist; sourceTree = ""; }; 37FD780E2A29E28B00B36DB1 /* SyncErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncErrorHandler.swift; sourceTree = ""; }; 4B0295182537BC6700E00CEF /* ConfigurationDebugViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationDebugViewController.swift; sourceTree = ""; }; + 4B274F5F2AFEAECC003F0745 /* NetworkProtectionWidgetRefreshModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionWidgetRefreshModel.swift; sourceTree = ""; }; 4B470ED5299C49800086EBDC /* AppTrackingProtectionDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTrackingProtectionDatabase.swift; sourceTree = ""; }; 4B470ED8299C4AED0086EBDC /* AppTrackingProtectionModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = AppTrackingProtectionModel.xcdatamodel; sourceTree = ""; }; 4B470EDA299C4FB20086EBDC /* AppTrackingProtectionListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTrackingProtectionListViewModel.swift; sourceTree = ""; }; @@ -1289,6 +1300,7 @@ 4B470EE2299C6DD10086EBDC /* AppTrackingProtectionStoringModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTrackingProtectionStoringModel.swift; sourceTree = ""; }; 4B52648A25F9613B00CB4C24 /* trackerData.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = trackerData.json; sourceTree = ""; }; 4B53648926718D0E001AA041 /* EmailWaitlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailWaitlist.swift; sourceTree = ""; }; + 4B5C46292AF2A6E6002A4432 /* VPNIntents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNIntents.swift; sourceTree = ""; }; 4B60AC96252EC07B00E8D219 /* fullscreenvideo.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = fullscreenvideo.js; sourceTree = ""; }; 4B60ACA0252EC0B100E8D219 /* FullScreenVideoUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenVideoUserScript.swift; sourceTree = ""; }; 4B62C4B925B930DD008912C6 /* AppConfigurationFetchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfigurationFetchTests.swift; sourceTree = ""; }; @@ -1303,6 +1315,7 @@ 4B83397029AC18C9003F7EA9 /* AppTrackingProtectionStoringModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTrackingProtectionStoringModelTests.swift; sourceTree = ""; }; 4B83397229AFB8D2003F7EA9 /* AppTrackingProtectionFeedbackModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTrackingProtectionFeedbackModel.swift; sourceTree = ""; }; 4B83397429AFBCE6003F7EA9 /* AppTrackingProtectionFeedbackModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTrackingProtectionFeedbackModelTests.swift; sourceTree = ""; }; + 4BB7CBAF2AF59C310014A35F /* VPNWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNWidget.swift; sourceTree = ""; }; 4BC21A2C272388BD00229F0E /* RunLoopExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunLoopExtensionTests.swift; sourceTree = ""; }; 4BC6DD1B2A60E6AD001EC129 /* ReportBrokenSiteView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportBrokenSiteView.swift; sourceTree = ""; }; 4BE27566272F878F006B20B0 /* URLRequestExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = URLRequestExtension.swift; path = ../DuckDuckGo/URLRequestExtension.swift; sourceTree = ""; }; @@ -2293,9 +2306,12 @@ C1B7B52C2894469D0098FD6A /* DefaultVariantManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultVariantManager.swift; sourceTree = ""; }; C1B7B52F28944E390098FD6A /* RemoteMessagingStoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMessagingStoreTests.swift; sourceTree = ""; }; C1B7B53328944EFA0098FD6A /* CoreDataTestUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataTestUtilities.swift; sourceTree = ""; }; + C1B924B62ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillNeverSavedTableViewCell.swift; sourceTree = ""; }; C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillLoginPromptHelper.swift; sourceTree = ""; }; C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillLoginPromptViewModelTests.swift; sourceTree = ""; }; C1CCCBA6283E101500CF3791 /* FaviconsHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconsHelper.swift; sourceTree = ""; }; + C1CDA3152AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillNeverPromptWebsitesManager.swift; sourceTree = ""; }; + C1CDA31D2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillNeverPromptWebsitesManagerTests.swift; sourceTree = ""; }; C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginSession.swift; sourceTree = ""; }; C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginSessionTests.swift; sourceTree = ""; }; C1F341C42A6924000032057B /* EmailAddressPromptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailAddressPromptView.swift; sourceTree = ""; }; @@ -2353,6 +2369,8 @@ EE0153EA2A6FF970002A8B26 /* NetworkProtectionRootViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRootViewModelTests.swift; sourceTree = ""; }; EE0153EC2A6FF9E6002A8B26 /* NetworkProtectionRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRootView.swift; sourceTree = ""; }; EE0153EE2A70021E002A8B26 /* NetworkProtectionInviteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionInviteView.swift; sourceTree = ""; }; + EE01EB3F2AFBD0000096AAC9 /* NetworkProtectionVPNSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNSettingsViewModel.swift; sourceTree = ""; }; + EE01EB422AFC1E0A0096AAC9 /* NetworkProtectionVPNLocationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNLocationView.swift; sourceTree = ""; }; EE276BE92A77F823009167B6 /* NetworkProtectionRootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRootViewController.swift; sourceTree = ""; }; EE3766DD2AC5945500AAB575 /* NetworkProtectionUNNotificationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionUNNotificationPresenter.swift; sourceTree = ""; }; EE3B226A29DE0F110082298A /* MockInternalUserStoring.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockInternalUserStoring.swift; sourceTree = ""; }; @@ -2586,6 +2604,7 @@ 8512EA5124ED30D20073EE19 /* SwiftUI.framework in Frameworks */, 85DF714624F7FE6100C89288 /* Core.framework in Frameworks */, 8512EA4F24ED30D20073EE19 /* WidgetKit.framework in Frameworks */, + 4BBBBA872B02E85400D965DA /* DesignResourcesKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3295,6 +3314,7 @@ 311BD1AE2836BB4200AEF6C1 /* AutofillItemsLockedView.swift */, 2DC3FBD62FBAF21E87610FA8 /* AutofillNoAuthAvailableView.swift */, C18ED4392AB6F77600BF3805 /* AutofillSettingsEnableFooterView.swift */, + C1B924B62ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift */, ); name = Table; sourceTree = ""; @@ -3379,6 +3399,14 @@ name = WindowsBrowser; sourceTree = ""; }; + 4B274F5E2AFEAEB3003F0745 /* Widget */ = { + isa = PBXGroup; + children = ( + 4B274F5F2AFEAECC003F0745 /* NetworkProtectionWidgetRefreshModel.swift */, + ); + name = Widget; + sourceTree = ""; + }; 4B470ED4299C484B0086EBDC /* AppTrackingProtection */ = { isa = PBXGroup; children = ( @@ -3394,6 +3422,14 @@ name = AppTrackingProtection; sourceTree = ""; }; + 4B5C46282AF2A6DB002A4432 /* Intents */ = { + isa = PBXGroup; + children = ( + 4B5C46292AF2A6E6002A4432 /* VPNIntents.swift */, + ); + name = Intents; + sourceTree = ""; + }; 4B6484F427FD1E390050A7A1 /* Waitlist */ = { isa = PBXGroup; children = ( @@ -3701,6 +3737,7 @@ 8512EA5324ED30D20073EE19 /* Widgets.swift */, 853273AF24FEFE4600E3C778 /* WidgetsExtension.entitlements */, 853273A924FEF24300E3C778 /* WidgetViews.swift */, + 4BB7CBAF2AF59C310014A35F /* VPNWidget.swift */, ); path = Widgets; sourceTree = ""; @@ -4415,6 +4452,14 @@ name = Root; sourceTree = ""; }; + EE01EB412AFC1DE10096AAC9 /* PreferredLocation */ = { + isa = PBXGroup; + children = ( + EE01EB422AFC1E0A0096AAC9 /* NetworkProtectionVPNLocationView.swift */, + ); + name = PreferredLocation; + sourceTree = ""; + }; EE3766DC2AC5940A00AAB575 /* NetworkProtection */ = { isa = PBXGroup; children = ( @@ -4473,6 +4518,7 @@ isa = PBXGroup; children = ( EE9D68D02AE00CF300B55EF4 /* NetworkProtectionVPNSettingsView.swift */, + EE01EB3F2AFBD0000096AAC9 /* NetworkProtectionVPNSettingsViewModel.swift */, ); name = VPNSettings; sourceTree = ""; @@ -4489,6 +4535,7 @@ EECD94B22A28B8580085C66E /* NetworkProtection */ = { isa = PBXGroup; children = ( + EE01EB412AFC1DE10096AAC9 /* PreferredLocation */, EE9D68D62AE1527F00B55EF4 /* VPNNotifications */, EE9D68CF2AE00CE000B55EF4 /* VPNSettings */, EE458D122ABB651500FC651A /* Debug */, @@ -4496,6 +4543,8 @@ EE0153DF2A6EABAF002A8B26 /* Helpers */, EEFD562D2A65B68B00DAEC48 /* Invite */, EECD94B32A28B96C0085C66E /* Status */, + 4B5C46282AF2A6DB002A4432 /* Intents */, + 4B274F5E2AFEAEB3003F0745 /* Widget */, EE8594982A44791C008A6D06 /* NetworkProtectionTunnelController.swift */, ); name = NetworkProtection; @@ -5218,6 +5267,7 @@ C1BF0BA629B63E0400482B73 /* AutofillLoginUI */, F40F843528C938370081AE75 /* AutofillLoginListViewModelTests.swift */, C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */, + C1CDA31D2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift */, ); name = Autofill; sourceTree = ""; @@ -5228,6 +5278,7 @@ D63657182A7BAE7C001AF19D /* EmailManagerRequestDelegate.swift */, F4147353283BF834004AA7A5 /* AutofillContentScopeFeatureToggles.swift */, C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */, + C1CDA3152AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift */, C13B32D12A0E750700A59236 /* AutofillSettingStatus.swift */, 319A370F28299A850079FBCE /* PasswordHider.swift */, 31C70B5428045E3500FB6AD1 /* SecureVaultErrorReporter.swift */, @@ -5417,6 +5468,9 @@ 85DF714924F7FE6100C89288 /* PBXTargetDependency */, ); name = WidgetsExtension; + packageProductDependencies = ( + 4BBBBA862B02E85400D965DA /* DesignResourcesKit */, + ); productName = WidgetsExtension; productReference = 8512EA4D24ED30D20073EE19 /* WidgetsExtension.appex */; productType = "com.apple.product-type.app-extension"; @@ -6161,6 +6215,7 @@ F1668BCE1E798081008CBA04 /* BookmarksViewController.swift in Sources */, 1E162610296C5C630004127F /* CustomDaxDialogViewModel.swift in Sources */, 8590CB69268A4E190089F6BF /* DebugEtagStorage.swift in Sources */, + C1CDA3162AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift in Sources */, F1CA3C371F045878005FADB3 /* PrivacyStore.swift in Sources */, 37FCAAC029930E26000E420A /* FailedAssertionView.swift in Sources */, F4E1936625AF722F001D2666 /* HighlightCutOutView.swift in Sources */, @@ -6208,6 +6263,7 @@ CB9B873C278C8FEA001F4906 /* WidgetEducationView.swift in Sources */, 85F200002215C17B006BB258 /* FindInPage.swift in Sources */, F1386BA41E6846C40062FC3C /* TabDelegate.swift in Sources */, + C1B924B72ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift in Sources */, 020108A929A7C1CD00644F9D /* AppTrackerImageCache.swift in Sources */, 3132FA2A27A0788F00DD7A12 /* QuickLookPreviewHelper.swift in Sources */, C1D21E2D293A5965006E5A05 /* AutofillLoginSession.swift in Sources */, @@ -6379,6 +6435,7 @@ 85C861E628FF1B5F00189466 /* HomeViewSectionRenderersExtension.swift in Sources */, F1D477C61F2126CC0031ED49 /* OmniBarState.swift in Sources */, 85F2FFCD2211F615006BB258 /* MainViewController+KeyCommands.swift in Sources */, + 4B274F602AFEAECC003F0745 /* NetworkProtectionWidgetRefreshModel.swift in Sources */, 0268FC132A449F04000EE6A2 /* OnboardingContainerView.swift in Sources */, 858650D9246B0D3C00C36F8A /* DaxOnboardingViewController.swift in Sources */, 312E5746283BB04A00C18FA0 /* AutofillEmptySearchView.swift in Sources */, @@ -6412,6 +6469,7 @@ F1D796F01E7B07610019D451 /* BookmarksViewControllerCells.swift in Sources */, 85058369219F424500ED4EDB /* UIColorExtension.swift in Sources */, 85058368219C49E000ED4EDB /* HomeViewSectionRenderers.swift in Sources */, + EE01EB432AFC1E0A0096AAC9 /* NetworkProtectionVPNLocationView.swift in Sources */, F456B3B525810BB900B79B90 /* FireButtonAnimationSettingsViewController.swift in Sources */, 9820EAF522613CD30089094D /* WebProgressWorker.swift in Sources */, B6CB93E5286445AB0090FEB4 /* Base64DownloadSession.swift in Sources */, @@ -6437,6 +6495,7 @@ 020108A729A6ABF600644F9D /* AppTPToggleView.swift in Sources */, 02A54A982A093126000C8FED /* AppTPHomeViewModel.swift in Sources */, F1617C191E573EA800DEDCAF /* TabSwitcherDelegate.swift in Sources */, + 4B5C462A2AF2A6E6002A4432 /* VPNIntents.swift in Sources */, 310742A62848CD780012660B /* BackForwardMenuHistoryItem.swift in Sources */, 858566FB252E55D6007501B8 /* ImageCacheDebugViewController.swift in Sources */, 0290472E29E99A2F0008FE3C /* GenericIconView.swift in Sources */, @@ -6481,6 +6540,7 @@ 31EF52E1281B3BDC0034796E /* AutofillLoginListItemViewModel.swift in Sources */, 1E4FAA6627D8DFC800ADC5B3 /* CompleteDownloadRowViewModel.swift in Sources */, 83004E862193E5ED00DA013C /* TabViewControllerBrowsingMenuExtension.swift in Sources */, + EE01EB402AFBD0000096AAC9 /* NetworkProtectionVPNSettingsViewModel.swift in Sources */, EE72CA852A862D000043B5B3 /* NetworkProtectionDebugViewController.swift in Sources */, C18ED43A2AB6F77600BF3805 /* AutofillSettingsEnableFooterView.swift in Sources */, CB84C7BD29A3EF530088A5B8 /* AppConfigurationURLProvider.swift in Sources */, @@ -6592,6 +6652,7 @@ C1D21E2F293A599C006E5A05 /* AutofillLoginSessionTests.swift in Sources */, 85D2187924BF6B8B004373D2 /* FaviconSourcesProviderTests.swift in Sources */, 1E8146AD28C8ABF000D1AF63 /* TrackerAnimationLogicTests.swift in Sources */, + C1CDA31E2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift in Sources */, B6AD9E3A28D456820019CDE9 /* PrivacyConfigurationManagerMock.swift in Sources */, F189AED71F18F6DE001EBAE1 /* TabTests.swift in Sources */, F13B4BFB1F18E3D900814661 /* TabsModelPersistenceExtensionTests.swift in Sources */, @@ -6667,6 +6728,8 @@ 853273B324FF114700E3C778 /* DeepLinks.swift in Sources */, 853273B424FFB36100E3C778 /* UIColorExtension.swift in Sources */, 853273AB24FEF27500E3C778 /* WidgetViews.swift in Sources */, + 4B5C462B2AF2BDC4002A4432 /* VPNIntents.swift in Sources */, + 4BB7CBB02AF59C310014A35F /* VPNWidget.swift in Sources */, 8512EA5424ED30D20073EE19 /* Widgets.swift in Sources */, 85DB12EB2A1FE2A4000A4A72 /* LockScreenWidgets.swift in Sources */, 8544C37C250B827300A0FE73 /* UserText.swift in Sources */, @@ -8499,7 +8562,7 @@ MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG NETWORK_PROTECTION"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG NETWORK_PROTECTION ALPHA"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2"; VALID_ARCHS = "$(ARCHS_STANDARD_64_BIT)"; @@ -9080,7 +9143,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 83.0.0; + version = 84.1.1; }; }; C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { @@ -9197,6 +9260,11 @@ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Persistence; }; + 4BBBBA862B02E85400D965DA /* DesignResourcesKit */ = { + isa = XCSwiftPackageProductDependency; + package = F42D541B29DCA40B004C4FF1 /* XCRemoteSwiftPackageReference "DesignResourcesKit" */; + productName = DesignResourcesKit; + }; 851481872A600EFC00ABC65F /* RemoteMessaging */ = { isa = XCSwiftPackageProductDependency; package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d9cc92bff7..a9e3205a3a 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/DuckDuckGo/BrowserServicesKit", "state": { "branch": null, - "revision": "f7e20cd37bbc0d25ae3c3f25ef52d319366613e7", - "version": "83.0.0" + "revision": "b97c451037f7a24aef6389be8252df301d2294cd", + "version": "84.1.1" } }, { @@ -51,8 +51,8 @@ "repositoryURL": "https://github.com/duckduckgo/duckduckgo-autofill.git", "state": { "branch": null, - "revision": "c8e895c8fd50dc76e8d8dc827a636ad77b7f46ff", - "version": "9.0.0" + "revision": "93677cc02cfe650ce7f417246afd0e8e972cd83e", + "version": "10.0.0" } }, { diff --git a/DuckDuckGo/AboutViewController.swift b/DuckDuckGo/AboutViewController.swift index 0c9d4a1328..765b17d10a 100644 --- a/DuckDuckGo/AboutViewController.swift +++ b/DuckDuckGo/AboutViewController.swift @@ -19,64 +19,64 @@ import UIKit import Core +import SwiftUI +import DesignResourcesKit -class AboutViewController: UIViewController { +class AboutViewController: UIHostingController { - @IBOutlet weak var headerText: UILabel! - @IBOutlet weak var descriptionText: UILabel! - @IBOutlet weak var logoImage: UIImageView! - @IBOutlet weak var moreButton: UIButton! - - override func viewDidLoad() { - super.viewDidLoad() - - applyTheme(ThemeManager.shared.currentTheme) + convenience init() { + self.init(rootView: AboutView()) } - @IBAction func onPrivacyLinkTapped(_ sender: UIButton) { - dismiss(animated: true) { - UIApplication.shared.open(URL.aboutLink, options: [:]) +} + +struct AboutView: View { + + var body: some View { + ScrollView { + VStack(spacing: 12) { + Image("Logo") + .resizable() + .frame(width: 96, height: 96) + .padding(.top) + + Image("TextDuckDuckGo") + + Text("Welcome to the Duck Side!") + .daxHeadline() + + Rectangle() + .frame(width: 80, height: 0.5) + .foregroundColor(Color(designSystemColor: .lines)) + .padding() + + Text(LocalizedStringKey(UserText.aboutText)) + .lineLimit(nil) + .multilineTextAlignment(.leading) + .foregroundColor(.primary) + .tintIfAvailable(Color(designSystemColor: .accent)) + .padding(.horizontal, 32) + .padding(.bottom) + + Spacer() + } + .frame(maxWidth: .infinity) } + .background(Rectangle() + .ignoresSafeArea() + .foregroundColor(Color(designSystemColor: .background))) } + } -extension AboutViewController: Themable { +private extension View { - func decorate(with theme: Theme) { - view.backgroundColor = theme.backgroundColor - - switch theme.currentImageSet { - case .light: - logoImage?.image = UIImage(named: "LogoDarkText") - case .dark: - logoImage?.image = UIImage(named: "LogoLightText") + @ViewBuilder func tintIfAvailable(_ color: Color) -> some View { + if #available(iOS 16.0, *) { + tint(color) + } else { + self } - - decorateDescription(with: theme) - - headerText.textColor = theme.aboutScreenTextColor - moreButton.setTitleColor(theme.aboutScreenButtonColor, for: .normal) } - - private func decorateDescription(with theme: Theme) { - if let attributedText = descriptionText.attributedText, - var font = attributedText.attribute(NSAttributedString.Key.font, at: 0, effectiveRange: nil) as? UIFont { - - let attributes: [NSAttributedString.Key: Any] - if traitCollection.horizontalSizeClass == .regular, - traitCollection.verticalSizeClass == .regular { - font = font.withSize(24.0) - attributes = [.foregroundColor: theme.aboutScreenTextColor, - .font: font] - } else { - attributes = [.foregroundColor: theme.aboutScreenTextColor, - .font: font] - } - let decoratedText = NSMutableAttributedString(string: UserText.settingsAboutText) - decoratedText.addAttributes(attributes, range: NSRange(location: 0, length: decoratedText.length)) - - descriptionText.attributedText = decoratedText - } - } } diff --git a/DuckDuckGo/AppDelegate+AppDeepLinks.swift b/DuckDuckGo/AppDelegate+AppDeepLinks.swift index 60788a6abc..ec8d49dbac 100644 --- a/DuckDuckGo/AppDelegate+AppDeepLinks.swift +++ b/DuckDuckGo/AppDelegate+AppDeepLinks.swift @@ -22,6 +22,7 @@ import Core extension AppDelegate { + // swiftlint:disable:next cyclomatic_complexity func handleAppDeepLink(_ app: UIApplication, _ mainViewController: MainViewController?, _ url: URL) -> Bool { guard let mainViewController else { return false } @@ -50,6 +51,11 @@ extension AppDelegate { case .newEmail: mainViewController.newEmailAddress() + case .openVPN: +#if NETWORK_PROTECTION + presentNetworkProtectionStatusSettingsModal() +#endif + default: guard app.applicationState == .active, let currentTab = mainViewController.currentTab else { diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index 9b3a32e512..3732a3fd5e 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -67,6 +67,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private var appTrackingProtectionDatabase: CoreDataDatabase = AppTrackingProtectionDatabase.make() #endif +#if NETWORK_PROTECTION + private let widgetRefreshModel = NetworkProtectionWidgetRefreshModel() +#endif + private var autoClear: AutoClear? private var showKeyboardIfSettingOn = true private var lastBackgroundDate: Date? @@ -278,6 +282,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { syncDataProviders: syncDataProviders, appSettings: AppDependencyProvider.shared.appSettings) #endif + main.loadViewIfNeeded() window = UIWindow(frame: UIScreen.main.bounds) @@ -316,6 +321,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { AppDependencyProvider.shared.appSettings.setAutofillIsNewInstallForOnByDefault() } +#if NETWORK_PROTECTION + widgetRefreshModel.beginObservingVPNStatus() +#endif + return true } @@ -411,6 +420,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { syncService.scheduler.notifyAppLifecycleEvent() fireFailedCompilationsPixelIfNeeded() refreshShortcuts() + +#if NETWORK_PROTECTION + widgetRefreshModel.refreshVPNWidget() +#endif } func applicationWillResignActive(_ application: UIApplication) { @@ -566,7 +579,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } NotificationCenter.default.post(name: AutofillLoginListAuthenticator.Notifications.invalidateContext, object: nil) - mainViewController?.clearNavigationStack() + + // The openVPN action handles the navigation stack on its own and does not need it to be cleared + if url != AppDeepLinkSchemes.openVPN.url { + mainViewController?.clearNavigationStack() + } + autoClear?.applicationWillMoveToForeground() showKeyboardIfSettingOn = false @@ -814,7 +832,7 @@ extension AppDelegate: UNUserNotificationCenterDelegate { } #if NETWORK_PROTECTION - private func presentNetworkProtectionStatusSettingsModal() { + func presentNetworkProtectionStatusSettingsModal() { if #available(iOS 15, *) { let networkProtectionRoot = NetworkProtectionRootViewController() presentSettings(with: networkProtectionRoot) diff --git a/DuckDuckGo/AppDependencyProvider.swift b/DuckDuckGo/AppDependencyProvider.swift index 3b42c75074..5f7854281c 100644 --- a/DuckDuckGo/AppDependencyProvider.swift +++ b/DuckDuckGo/AppDependencyProvider.swift @@ -34,6 +34,7 @@ protocol DependencyProvider { var voiceSearchHelper: VoiceSearchHelperProtocol { get } var downloadManager: DownloadManager { get } var autofillLoginSession: AutofillLoginSession { get } + var autofillNeverPromptWebsitesManager: AutofillNeverPromptWebsitesManager { get } var configurationManager: ConfigurationManager { get } } @@ -56,6 +57,7 @@ class AppDependencyProvider: DependencyProvider { let voiceSearchHelper: VoiceSearchHelperProtocol = VoiceSearchHelper() let downloadManager = DownloadManager() let autofillLoginSession = AutofillLoginSession() + lazy var autofillNeverPromptWebsitesManager = AutofillNeverPromptWebsitesManager() let configurationManager = ConfigurationManager() } diff --git a/DuckDuckGo/AppUserDefaults.swift b/DuckDuckGo/AppUserDefaults.swift index f06c8d7180..552e381a02 100644 --- a/DuckDuckGo/AppUserDefaults.swift +++ b/DuckDuckGo/AppUserDefaults.swift @@ -252,7 +252,7 @@ public class AppUserDefaults: AppSettings { userDefaults?.set(newValue, forKey: Keys.autofillCredentialsEnabled) } } - + @UserDefaultsWrapper(key: .autofillCredentialsSavePromptShowAtLeastOnce, defaultValue: false) var autofillCredentialsSavePromptShowAtLeastOnce: Bool diff --git a/DuckDuckGo/AutofillLoginListViewModel.swift b/DuckDuckGo/AutofillLoginListViewModel.swift index ae9642b488..2295c54873 100644 --- a/DuckDuckGo/AutofillLoginListViewModel.swift +++ b/DuckDuckGo/AutofillLoginListViewModel.swift @@ -45,6 +45,11 @@ internal enum AutofillLoginListSectionType: Comparable { static let miscSectionHeading = "#" } +internal enum EnableAutofillRows: Int, CaseIterable { + case toggleAutofill + case resetNeverPromptWebsites +} + final class AutofillLoginListViewModel: ObservableObject { enum ViewState { @@ -66,10 +71,12 @@ final class AutofillLoginListViewModel: ObservableObject { private let tld: TLD private var currentTabUrl: URL? private let secureVault: (any AutofillSecureVault)? + private let autofillNeverPromptWebsitesManager: AutofillNeverPromptWebsitesManager private var cachedDeletedCredentials: SecureVaultModels.WebsiteCredentials? private let autofillDomainNameUrlMatcher = AutofillDomainNameUrlMatcher() private let autofillDomainNameUrlSort = AutofillDomainNameUrlSort() + @Published private (set) var viewState: AutofillLoginListViewModel.ViewState = .authLocked @Published private(set) var sections = [AutofillLoginListSectionType]() { didSet { @@ -89,11 +96,13 @@ final class AutofillLoginListViewModel: ObservableObject { } } - init(appSettings: AppSettings, tld: TLD, secureVault: (any AutofillSecureVault)?, currentTabUrl: URL? = nil) { + init(appSettings: AppSettings, tld: TLD, secureVault: (any AutofillSecureVault)?, currentTabUrl: URL? = nil, autofillNeverPromptWebsitesManager: AutofillNeverPromptWebsitesManager = AppDependencyProvider.shared.autofillNeverPromptWebsitesManager) { self.appSettings = appSettings self.tld = tld self.secureVault = secureVault self.currentTabUrl = currentTabUrl + self.autofillNeverPromptWebsitesManager = autofillNeverPromptWebsitesManager + updateData() authenticationNotRequired = !hasAccountsSaved || AppDependencyProvider.shared.autofillLoginSession.isValidSession setupCancellables() @@ -153,7 +162,7 @@ final class AutofillLoginListViewModel: ObservableObject { func rowsInSection(_ section: Int) -> Int { switch self.sections[section] { case .enableAutofill: - return 1 + return autofillNeverPromptWebsitesManager.neverPromptWebsites.isEmpty ? 1 : 2 case .credentials(_, let items): return items.count } @@ -180,8 +189,11 @@ final class AutofillLoginListViewModel: ObservableObject { } self.sections = makeSections(with: filteredAccounts) } - - + + func resetNeverPromptWebsites() { + _ = autofillNeverPromptWebsitesManager.deleteAllNeverPromptWebsites() + } + // MARK: Private Methods private func fetchAccounts() -> [SecureVaultModels.WebsiteAccount] { diff --git a/DuckDuckGo/AutofillLoginPromptView.swift b/DuckDuckGo/AutofillLoginPromptView.swift index 0a75d988ee..4570c243f8 100644 --- a/DuckDuckGo/AutofillLoginPromptView.swift +++ b/DuckDuckGo/AutofillLoginPromptView.swift @@ -44,7 +44,7 @@ struct AutofillLoginPromptView: View { VStack { Spacer() .frame(height: Const.Size.topPadding) - AutofillViews.WebsiteWithFavicon(accountDomain: viewModel.domain) + AutofillViews.AppIconHeader() Spacer() .frame(height: Const.Size.headlineTopPadding) AutofillViews.Headline(title: viewModel.message) diff --git a/DuckDuckGo/AutofillLoginSettingsListViewController.swift b/DuckDuckGo/AutofillLoginSettingsListViewController.swift index 313cfb6b84..c206821c60 100644 --- a/DuckDuckGo/AutofillLoginSettingsListViewController.swift +++ b/DuckDuckGo/AutofillLoginSettingsListViewController.swift @@ -77,6 +77,7 @@ final class AutofillLoginSettingsListViewController: UIViewController { tableView.estimatedSectionFooterHeight = 40 tableView.registerCell(ofType: AutofillListItemTableViewCell.self) tableView.registerCell(ofType: EnableAutofillSettingsTableViewCell.self) + tableView.registerCell(ofType: AutofillNeverSavedTableViewCell.self) // Have to set tableHeaderView height otherwise tableView content will jump when adding / removing searchController due to tableView insetGrouped style tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 24)) return tableView @@ -217,7 +218,23 @@ final class AutofillLoginSettingsListViewController: UIViewController { navigationController?.pushViewController(detailsController, animated: animated) detailsViewController = detailsController } - + + private func presentNeverPromptResetPromptAtIndexPath(_ indexPath: IndexPath) { + let controller = UIAlertController(title: "", + message: UserText.autofillResetNeverSavedActionTitle, + preferredStyle: .actionSheet) + controller.addAction(UIAlertAction(title: UserText.autofillResetNeverSavedActionConfirmButton, style: .destructive) { [weak self] _ in + self?.viewModel.resetNeverPromptWebsites() + self?.tableView.reloadData() + Pixel.fire(pixel: .autofillLoginsSettingsResetExcludedConfirmed) + }) + controller.addAction(UIAlertAction(title: UserText.autofillResetNeverSavedActionCancelButton, style: .cancel) { _ in + Pixel.fire(pixel: .autofillLoginsSettingsResetExcludedDismissed) + }) + present(controller: controller, fromView: tableView.cellForRow(at: indexPath) ?? tableView) + Pixel.fire(pixel: .autofillLoginsSettingsResetExcludedDisplayed) + } + private func setupCancellables() { viewModel.$viewState .receive(on: DispatchQueue.main) @@ -470,6 +487,12 @@ final class AutofillLoginSettingsListViewController: UIViewController { cell.theme = ThemeManager.shared.currentTheme return cell } + + private func neverSavedCell(for tableView: UITableView, indexPath: IndexPath) -> AutofillNeverSavedTableViewCell { + let cell = tableView.dequeueCell(ofType: AutofillNeverSavedTableViewCell.self, for: indexPath) + cell.theme = ThemeManager.shared.currentTheme + return cell + } } // MARK: UITableViewDelegate @@ -489,11 +512,16 @@ extension AutofillLoginSettingsListViewController: UITableViewDelegate { tableView.deselectRow(at: indexPath, animated: true) switch viewModel.sections[indexPath.section] { + case .enableAutofill: + switch EnableAutofillRows(rawValue: indexPath.row) { + case .resetNeverPromptWebsites: + presentNeverPromptResetPromptAtIndexPath(indexPath) + default: + break + } case .credentials(_, let items): let item = items[indexPath.row] showAccountDetails(item.account) - default: - break } } @@ -556,7 +584,14 @@ extension AutofillLoginSettingsListViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { switch viewModel.sections[indexPath.section] { case .enableAutofill: - return enableAutofillCell(for: tableView, indexPath: indexPath) + switch EnableAutofillRows(rawValue: indexPath.row) { + case .toggleAutofill: + return enableAutofillCell(for: tableView, indexPath: indexPath) + case .resetNeverPromptWebsites: + return neverSavedCell(for: tableView, indexPath: indexPath) + default: + fatalError("No cell for row at index \(indexPath.row)") + } case .credentials(_, let items): return credentialCell(for: tableView, item: items[indexPath.row], indexPath: indexPath) } diff --git a/DuckDuckGo/AutofillNeverPromptWebsitesManager.swift b/DuckDuckGo/AutofillNeverPromptWebsitesManager.swift new file mode 100644 index 0000000000..1671e0b5fb --- /dev/null +++ b/DuckDuckGo/AutofillNeverPromptWebsitesManager.swift @@ -0,0 +1,84 @@ +// +// AutofillNeverPromptWebsitesManager.swift +// DuckDuckGo +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import BrowserServicesKit +import Core + +class AutofillNeverPromptWebsitesManager { + + public private(set) var neverPromptWebsites: [SecureVaultModels.NeverPromptWebsites] = [] + + private let secureVault: (any AutofillSecureVault)? + + public init(secureVault: (any AutofillSecureVault)? = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared)) { + self.secureVault = secureVault + + fetchNeverPromptWebsites() + } + + public func hasNeverPromptWebsitesFor(domain: String) -> Bool { + return neverPromptWebsites.contains { $0.domain == domain } + } + + public func saveNeverPromptWebsite(_ domain: String) throws -> Int64? { + guard let secureVault = secureVault else { + return nil + } + + do { + let id = try secureVault.storeNeverPromptWebsites(SecureVaultModels.NeverPromptWebsites(domain: domain)) + + fetchNeverPromptWebsites() + return id + } catch { + Pixel.fire(pixel: .secureVaultError, error: error) + throw error + } + } + + public func deleteAllNeverPromptWebsites() -> Bool { + guard let secureVault = secureVault else { + return false + } + + do { + try secureVault.deleteAllNeverPromptWebsites() + + fetchNeverPromptWebsites() + return true + } catch { + Pixel.fire(pixel: .secureVaultError, error: error) + return false + } + } + + private func fetchNeverPromptWebsites() { + guard let secureVault = secureVault else { + return + } + + do { + neverPromptWebsites = try secureVault.neverPromptWebsites() + } catch { + Pixel.fire(pixel: .secureVaultError, error: error) + neverPromptWebsites = [] + } + } +} diff --git a/DuckDuckGo/AutofillNeverSavedTableViewCell.swift b/DuckDuckGo/AutofillNeverSavedTableViewCell.swift new file mode 100644 index 0000000000..adfc4c5e53 --- /dev/null +++ b/DuckDuckGo/AutofillNeverSavedTableViewCell.swift @@ -0,0 +1,78 @@ +// +// AutofillNeverSavedTableViewCell.swift +// DuckDuckGo +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit +import DesignResourcesKit + +class AutofillNeverSavedTableViewCell: UITableViewCell { + + var theme: Theme? { + didSet { + updateTheme() + } + } + + private lazy var titleLabel: UILabel = { + let label = UILabel(frame: CGRect.zero) + label.font = .preferredFont(forTextStyle: .callout) + label.text = UserText.autofillNeverSavedSettings + label.numberOfLines = 0 + label.lineBreakMode = .byWordWrapping + return label + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setupSubviews() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupSubviews() { + installSubviews() + installConstraints() + } + + private func installSubviews() { + contentView.addSubview(titleLabel) + } + + private func installConstraints() { + titleLabel.translatesAutoresizingMaskIntoConstraints = false + let margins = contentView.layoutMarginsGuide + + NSLayoutConstraint.activate([ + titleLabel.topAnchor.constraint(equalTo: margins.topAnchor), + titleLabel.bottomAnchor.constraint(equalTo: margins.bottomAnchor), + titleLabel.leadingAnchor.constraint(equalTo: margins.leadingAnchor), + titleLabel.trailingAnchor.constraint(equalTo: margins.trailingAnchor) + ]) + } + + private func updateTheme() { + guard let theme = theme else { + return + } + + titleLabel.textColor = theme.autofillDefaultTitleTextColor + contentView.backgroundColor = UIColor(designSystemColor: .surface) + } +} diff --git a/DuckDuckGo/AutofillViews.swift b/DuckDuckGo/AutofillViews.swift index 8dab1a504d..aae551c98f 100644 --- a/DuckDuckGo/AutofillViews.swift +++ b/DuckDuckGo/AutofillViews.swift @@ -55,18 +55,10 @@ struct AutofillViews { } } - struct WebsiteWithFavicon: View { - let accountDomain: String - + struct AppIconHeader: View { var body: some View { - HStack { - FaviconView(viewModel: FaviconViewModel(domain: accountDomain)) - .scaledToFit() - .frame(width: Const.Size.logoImage, height: Const.Size.logoImage) - Text(accountDomain) - .daxFootnoteRegular() - .foregroundColor(Color(designSystemColor: .textSecondary)) - } + Image.appIcon + .scaledToFit() } } @@ -241,4 +233,5 @@ private enum Const { private extension Image { static let close = Image("Close-24") + static let appIcon = Image("WaitlistShareSheetLogo") } diff --git a/DuckDuckGo/Base.lproj/Settings.storyboard b/DuckDuckGo/Base.lproj/Settings.storyboard index 679524ecd2..1d4eb7fa61 100644 --- a/DuckDuckGo/Base.lproj/Settings.storyboard +++ b/DuckDuckGo/Base.lproj/Settings.storyboard @@ -117,9 +117,6 @@ - - - @@ -145,9 +142,6 @@ - - - @@ -540,7 +534,7 @@ - +