diff --git a/.github/workflows/adhoc.yml b/.github/workflows/adhoc.yml
index 5a2e33c100..0b78830657 100644
--- a/.github/workflows/adhoc.yml
+++ b/.github/workflows/adhoc.yml
@@ -58,13 +58,13 @@ jobs:
echo "dsyms_path=${{ github.workspace }}/${{ env.dsyms_filename }}" >> $GITHUB_ENV
- name: Upload IPA artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ env.ipa_filename }}
path: ${{ env.ipa_path }}
- name: Upload dSYMs artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ env.dsyms_filename }}
path: ${{ env.dsyms_path }}
diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml
index 1696288b02..1f2f0608bf 100644
--- a/.github/workflows/alpha.yml
+++ b/.github/workflows/alpha.yml
@@ -58,7 +58,7 @@ jobs:
- name: Set cache key hash
run: |
- has_only_tags=$(jq '[ .object.pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
+ has_only_tags=$(jq '[ .pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
if [[ "$has_only_tags" == "true" ]]; then
echo "cache_key_hash=${{ hashFiles('DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}" >> $GITHUB_ENV
else
@@ -97,7 +97,7 @@ jobs:
echo "build_version=${build_version}" >> $GITHUB_ENV
- name: Upload dSYMs artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: DuckDuckGo-Alpha-dSYM-${{ env.app_version }}
path: ${{ env.dsyms_path }}
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 0ce6cf2ed4..8a6d1ba63b 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -43,6 +43,7 @@ jobs:
-target "DuckDuckGo" \
-scheme "DuckDuckGo" \
-destination "platform=iOS Simulator,name=iPhone 14,OS=16.4"
+ -skipPackagePluginValidation \
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/end-to-end.yml b/.github/workflows/end-to-end.yml
index de34f5fd98..2fcfe9b64e 100644
--- a/.github/workflows/end-to-end.yml
+++ b/.github/workflows/end-to-end.yml
@@ -17,7 +17,7 @@ jobs:
- name: Set cache key hash
run: |
- has_only_tags=$(jq '[ .object.pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
+ has_only_tags=$(jq '[ .pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
if [[ "$has_only_tags" == "true" ]]; then
echo "cache_key_hash=${{ hashFiles('DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}" >> $GITHUB_ENV
else
@@ -42,6 +42,7 @@ jobs:
-scheme "DuckDuckGo" \
-destination "platform=iOS Simulator,name=iPhone 14,OS=16.4" \
-derivedDataPath "DerivedData" \
+ -skipPackagePluginValidation \
| tee xcodebuild.log
- name: Release tests
@@ -78,7 +79,7 @@ jobs:
--data ' { "data": { "name": "GH Workflow Failure - 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
+ uses: actions/upload-artifact@v4
if: failure()
with:
name: BuildLogs
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index 5a67fdb265..e565805327 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -18,7 +18,7 @@ jobs:
- name: Set cache key hash
run: |
- has_only_tags=$(jq '[ .object.pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
+ has_only_tags=$(jq '[ .pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
if [[ "$has_only_tags" == "true" ]]; then
echo "cache_key_hash=${{ hashFiles('DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}" >> $GITHUB_ENV
else
@@ -46,11 +46,12 @@ jobs:
-scheme "AtbUITests" \
-destination "platform=iOS Simulator,name=iPhone 14,OS=16.4" \
-derivedDataPath "DerivedData" \
+ -skipPackagePluginValidation \
| tee xcodebuild.log \
| xcbeautify --report junit --report-path . --junit-report-filename unittests.xml
- name: Upload logs if workflow failed
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: failure()
with:
name: BuildLogs
@@ -87,6 +88,7 @@ jobs:
-scheme "FingerprintingUITests" \
-destination "platform=iOS Simulator,name=iPhone 14,OS=16.4" \
-derivedDataPath "DerivedData" \
+ -skipPackagePluginValidation \
| xcbeautify --report junit --report-path . --junit-report-filename unittests.xml
- name: Publish unit tests report
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index b8833eafaf..e145b145a3 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: SwiftLint
- uses: docker://norionomura/swiftlint:0.53.0
+ uses: docker://norionomura/swiftlint:0.54.0_swift-5.9.0
with:
args: swiftlint --reporter github-actions-logging --strict
@@ -53,7 +53,7 @@ jobs:
- name: Set cache key hash
run: |
- has_only_tags=$(jq '[ .object.pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
+ has_only_tags=$(jq '[ .pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
if [[ "$has_only_tags" == "true" ]]; then
echo "cache_key_hash=${{ hashFiles('DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}" >> $GITHUB_ENV
else
@@ -81,12 +81,13 @@ jobs:
-scheme "DuckDuckGo" \
-destination "platform=iOS Simulator,name=iPhone 15,OS=17.2" \
-derivedDataPath "DerivedData" \
+ -skipPackagePluginValidation \
DDG_SLOW_COMPILE_CHECK_THRESHOLD=250 \
| tee xcodebuild.log \
| xcbeautify --report junit --report-path . --junit-report-filename unittests.xml
- name: Upload logs if workflow failed
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: failure()
with:
name: BuildLogs
@@ -144,7 +145,7 @@ jobs:
- name: Set cache key hash
run: |
- has_only_tags=$(jq '[ .object.pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
+ has_only_tags=$(jq '[ .pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
if [[ "$has_only_tags" == "true" ]]; then
echo "cache_key_hash=${{ hashFiles('DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}" >> $GITHUB_ENV
else
@@ -183,6 +184,7 @@ jobs:
-destination "platform=iOS Simulator,name=iPhone 14" \
-derivedDataPath "DerivedData" \
-configuration "Release" \
+ -skipPackagePluginValidation \
| xcbeautify
create-asana-task:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 58f13d0b12..eed601f957 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -80,7 +80,7 @@ jobs:
- name: Upload dSYMs artifact
if: always()
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: DuckDuckGo-${{ steps.destination.outputs.destination }}-dSYM-${{ env.app_version }}
path: ${{ env.dsyms_path }}
diff --git a/.github/workflows/sync-end-to-end.yml b/.github/workflows/sync-end-to-end.yml
index 3dc49732fa..ebe4d1463e 100644
--- a/.github/workflows/sync-end-to-end.yml
+++ b/.github/workflows/sync-end-to-end.yml
@@ -5,9 +5,10 @@ on:
- cron: '0 5 * * *' # run at 5 AM UTC
jobs:
- sync-end-to-end-tests:
- name: Sync End to end Tests
+ build-for-sync-end-to-end-tests:
+ name: Build for Sync End To End Tests
runs-on: macos-13
+ timeout-minutes: 30
steps:
- name: Check out the code
@@ -17,7 +18,7 @@ jobs:
- name: Set cache key hash
run: |
- has_only_tags=$(jq '[ .object.pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
+ has_only_tags=$(jq '[ .pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved)
if [[ "$has_only_tags" == "true" ]]; then
echo "cache_key_hash=${{ hashFiles('DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}" >> $GITHUB_ENV
else
@@ -40,43 +41,80 @@ jobs:
run: |
set -o pipefail && xcodebuild \
-scheme "DuckDuckGo" \
- -destination "platform=iOS Simulator,name=iPhone 14,OS=16.4" \
+ -destination "platform=iOS Simulator,name=iPhone 14" \
-derivedDataPath "DerivedData" \
+ -skipPackagePluginValidation \
| tee xcodebuild.log
+
+ - name: Store Binary
+ uses: actions/upload-artifact@v4
+ with:
+ name: duckduckgo-ios-app
+ path: DerivedData/Build/Products/Debug-iphonesimulator/DuckDuckGo.app
+
+ - name: Upload logs when workflow failed
+ uses: actions/upload-artifact@v4
+ if: failure()
+ with:
+ name: BuildLogs
+ path: |
+ xcodebuild.log
+ DerivedData/Logs/Test/*.xcresult
+ retention-days: 7
+ sync-end-to-end-tests:
+ name: Sync End To End Tests
+ needs: build-for-sync-end-to-end-tests
+ runs-on: macos-13
+ timeout-minutes: 30
+ strategy:
+ matrix:
+ os-version: [15, 16, 17]
+ #max-parallel: 1 # Uncomment this line to run tests sequentially.
+ fail-fast: false
+
+ steps:
+ - name: Check out the code
+ uses: actions/checkout@v3 # Don't need submodules here as this is only for the tests folder
+
- name: Create test account for Sync and return the recovery code
uses: duckduckgo/sync_crypto/action@main
id: sync-recovery-code
with:
debug: true
- - name: Sync e2e tests
- uses: mobile-dev-inc/action-maestro-cloud@v1.6.0
+ - name: Retrieve Binary
+ uses: actions/download-artifact@v4
+ with:
+ name: duckduckgo-ios-app
+ path: DerivedData/Build/Products/Debug-iphonesimulator/DuckDuckGo.app
+
+ - name: Sync e2e tests
+ uses: mobile-dev-inc/action-maestro-cloud@v1.8.0
with:
api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }}
app-file: DerivedData/Build/Products/Debug-iphonesimulator/DuckDuckGo.app
+ ios-version: ${{ matrix.os-version }}
workspace: .maestro
include-tags: sync
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 }}" } }'
+ notify-failure:
+ name: Notify on failure
+ if: ${{ always() && contains(join(needs.*.result, ','), 'failure') }}
+ needs: [build-for-sync-end-to-end-tests, sync-end-to-end-tests]
+ runs-on: ubuntu-latest
- - 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
+ steps:
+ - name: Create Asana task when workflow failed
+ 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 }}" } }'
+
+
diff --git a/.maestro/shared/add_bookmarks_and_favorites.yaml b/.maestro/shared/add_bookmarks_and_favorites.yaml
new file mode 100644
index 0000000000..201a749e4f
--- /dev/null
+++ b/.maestro/shared/add_bookmarks_and_favorites.yaml
@@ -0,0 +1,21 @@
+appId: com.duckduckgo.mobile.ios
+---
+
+- tapOn:
+ id: searchEntry
+- inputText: www.duckduckgo.com
+- pressKey: Enter
+- runFlow:
+ when:
+ visible:
+ text: "Got It"
+ commands:
+ - tapOn: Got It
+- tapOn: Browsing Menu
+- tapOn: Add Favorite
+- tapOn:
+ id: searchEntry
+- inputText: www.spreadprivacy.com
+- pressKey: Enter
+- tapOn: Browsing Menu
+- tapOn: Add Bookmark
\ No newline at end of file
diff --git a/.maestro/shared/add_login_from_settings.yaml b/.maestro/shared/add_login_from_settings.yaml
new file mode 100644
index 0000000000..1f34c6df2b
--- /dev/null
+++ b/.maestro/shared/add_login_from_settings.yaml
@@ -0,0 +1,15 @@
+appId: com.duckduckgo.mobile.ios
+---
+
+- tapOn: Passwords
+- tapOn: Add 24
+- tapOn: Title
+- inputText: My Personal Website
+- tapOn: username@example.com
+- inputText: me@mypersonalwebsite.com
+- tapOn: example.com
+- inputText: mypersonalwebsite.com
+- tapOn: Save
+- tapOn: Passwords
+- tapOn: Settings
+- tapOn: Done
\ No newline at end of file
diff --git a/.maestro/shared/copy_recovery_code.yaml b/.maestro/shared/copy_recovery_code.yaml
new file mode 100644
index 0000000000..fa59861d27
--- /dev/null
+++ b/.maestro/shared/copy_recovery_code.yaml
@@ -0,0 +1,9 @@
+appId: com.duckduckgo.mobile.ios
+---
+# # - Put the code in the clipboard on Maestro Cloud
+# # - Prevent iOS from showing the Paste permission alert as Maestro can't handle it
+- tapOn: Sync Info
+- tapOn: Paste and Copy Recovery Code
+- inputText: ${CODE}
+- tapOn: Copy
+- tapOn: Debug
diff --git a/.maestro/shared/copy_recovery_code_from_settings.yaml b/.maestro/shared/copy_recovery_code_from_settings.yaml
new file mode 100644
index 0000000000..16ab4cfebf
--- /dev/null
+++ b/.maestro/shared/copy_recovery_code_from_settings.yaml
@@ -0,0 +1,16 @@
+# copy_recovery_code_from_settings.yaml
+
+appId: com.duckduckgo.mobile.ios
+---
+
+- scroll
+- scroll
+- scroll
+- assertVisible: Debug Menu
+- tapOn: Debug Menu
+- tapOn: Sync Info
+- tapOn: Paste and Copy Recovery Code
+- inputText: ${CODE}
+- tapOn: Copy
+- tapOn: Debug
+- tapOn: Settings
\ No newline at end of file
diff --git a/.maestro/shared/remove_local_bookmarks.yaml b/.maestro/shared/remove_local_bookmarks.yaml
new file mode 100644
index 0000000000..37a017b370
--- /dev/null
+++ b/.maestro/shared/remove_local_bookmarks.yaml
@@ -0,0 +1,12 @@
+appId: com.duckduckgo.mobile.ios
+---
+
+- tapOn: Bookmarks
+- tapOn: Edit
+- tapOn: Spread Privacy
+- scroll
+- scroll
+- tapOn: Delete
+- tapOn: Delete
+- tapOn: Done
+- tapOn: Done
\ No newline at end of file
diff --git a/.maestro/shared/remove_local_logins.yaml b/.maestro/shared/remove_local_logins.yaml
new file mode 100644
index 0000000000..e830ee3ec3
--- /dev/null
+++ b/.maestro/shared/remove_local_logins.yaml
@@ -0,0 +1,13 @@
+appId: com.duckduckgo.mobile.ios
+---
+
+- tapOn: Settings
+- tapOn: Passwords
+- tapOn: Passcode field
+- inputText: "0000"
+- pressKey: Enter
+- tapOn: My Personal Website
+- tapOn: Delete Password
+- tapOn: Delete Password
+- tapOn: Settings
+- tapOn: Done
\ No newline at end of file
diff --git a/.maestro/shared/set_internal_user.yaml b/.maestro/shared/set_internal_user_from_settings.yaml
similarity index 100%
rename from .maestro/shared/set_internal_user.yaml
rename to .maestro/shared/set_internal_user_from_settings.yaml
diff --git a/.maestro/shared/sync_create.yaml b/.maestro/shared/sync_create.yaml
index ec91e616c1..bcb1968ebe 100644
--- a/.maestro/shared/sync_create.yaml
+++ b/.maestro/shared/sync_create.yaml
@@ -12,3 +12,4 @@ appId: com.duckduckgo.mobile.ios
- tapOn: Next
- assertVisible: Your Data is Synced!
- tapOn: Done
+- assertVisible: Sync Enabled
diff --git a/.maestro/shared/sync_delete.yaml b/.maestro/shared/sync_delete.yaml
index 41e53148c4..472b859155 100644
--- a/.maestro/shared/sync_delete.yaml
+++ b/.maestro/shared/sync_delete.yaml
@@ -3,8 +3,7 @@ appId: com.duckduckgo.mobile.ios
- assertVisible: Sync & Backup
- scroll
-- tapOn:
- point: 50%,91% # TODO: Revisit after new setup flow has been implemented.
+- tapOn: Turn Off and Delete Server Data...
- assertVisible: Delete Server Data?
- tapOn: Delete Server Data
- assertVisible: Begin Syncing
\ No newline at end of file
diff --git a/.maestro/shared/sync_login.yaml b/.maestro/shared/sync_login.yaml
new file mode 100644
index 0000000000..e63fb885ef
--- /dev/null
+++ b/.maestro/shared/sync_login.yaml
@@ -0,0 +1,16 @@
+appId: com.duckduckgo.mobile.ios
+---
+
+- assertVisible: Begin Syncing
+- tapOn: Sync with Another Device
+- assertVisible: Scan QR Code
+- tapOn: Manually Enter Code
+- tapOn: Paste
+- assertVisible: Save Recovery Code
+- tapOn: Next
+- assertVisible: Your Data is Synced!
+- tapOn: Done
+- assertVisible: Sync Enabled
+- assertVisible:
+ id: "device"
+ index: 1
\ No newline at end of file
diff --git a/.maestro/shared/sync_logout.yaml b/.maestro/shared/sync_logout.yaml
new file mode 100644
index 0000000000..661af74b98
--- /dev/null
+++ b/.maestro/shared/sync_logout.yaml
@@ -0,0 +1,8 @@
+appId: com.duckduckgo.mobile.ios
+---
+
+- assertVisible: Sync & Backup
+- tapOn: Turn Off Sync & Backup...
+- assertVisible: Turn Off Sync?
+- tapOn: Remove
+- assertVisible: Begin Syncing
\ No newline at end of file
diff --git a/.maestro/shared/sync_recover_data.yaml b/.maestro/shared/sync_recover_data.yaml
new file mode 100644
index 0000000000..8c81e717c1
--- /dev/null
+++ b/.maestro/shared/sync_recover_data.yaml
@@ -0,0 +1,17 @@
+appId: com.duckduckgo.mobile.ios
+---
+
+- assertVisible: Sync & Backup
+- tapOn: Sync & Backup
+- assertVisible: Begin Syncing
+- tapOn: Recover Synced Data
+- assertVisible: Recover Synced Data
+- assertVisible: Get Started
+- tapOn: Get Started
+- tapOn: Enter Text Code Manually
+- tapOn: Paste
+- assertVisible: Save Recovery Code
+- tapOn: Next
+- assertVisible: Your Data is Synced!
+- tapOn: Done
+- assertVisible: Sync Enabled
\ No newline at end of file
diff --git a/.maestro/shared/sync_verify_bookmarks.yaml b/.maestro/shared/sync_verify_bookmarks.yaml
new file mode 100644
index 0000000000..295864854e
--- /dev/null
+++ b/.maestro/shared/sync_verify_bookmarks.yaml
@@ -0,0 +1,33 @@
+appId: com.duckduckgo.mobile.ios
+---
+
+- tapOn: Settings
+- tapOn: Done
+- tapOn: Bookmarks
+- runFlow:
+ when:
+ visible:
+ text: Download Missing Icons?
+ commands:
+ - tapOn: Not Now
+
+- assertVisible: Spread Privacy
+- assertVisible: Stack Overflow - Where Developers Learn, Share, & Build Careers
+- assertVisible: DuckDuckGo — Privacy, simplified.
+- assertVisible: DuckDuckGo · GitHub
+- assertVisible: "Wolfram|Alpha: Computational Intelligence"
+- assertVisible: news
+- assertVisible: code
+- assertVisible: sports
+- tapOn: news
+- assertVisible: Breaking News, Latest News and Videos | CNN
+- assertVisible: News, sport and opinion from the Guardian's global edition | The Guardian
+- tapOn: Bookmarks
+- tapOn: code
+- assertVisible: "GitHub - duckduckgo/Android: DuckDuckGo Android App"
+- assertVisible: "GitHub - duckduckgo/iOS: DuckDuckGo iOS Application"
+- tapOn: Bookmarks
+- tapOn: sports
+- assertVisible: NFL.com | Official Site of the National Football League
+- assertVisible: AS.com - Diario online deportivo. Fútbol, motor y mucho más
+- tapOn: Bookmarks
diff --git a/.maestro/shared/sync_verify_logins.yaml b/.maestro/shared/sync_verify_logins.yaml
new file mode 100644
index 0000000000..1fb1c8b334
--- /dev/null
+++ b/.maestro/shared/sync_verify_logins.yaml
@@ -0,0 +1,28 @@
+appId: com.duckduckgo.mobile.ios
+---
+
+- tapOn: Passwords
+- tapOn: Passcode field
+- inputText: "0000"
+- pressKey: Enter
+- assertVisible: Dax Login
+- tapOn: Dax Login
+- assertVisible: daxthetest
+- assertVisible: duckduckgo.com
+- tapOn: Passwords
+- assertVisible: Github
+- tapOn: Github
+- assertVisible: githubusername
+- assertVisible: github.com
+- tapOn: Passwords
+- assertVisible: StackOverflow
+- tapOn: StackOverflow
+- assertVisible: stacker
+- assertVisible: stackoverflow.com
+- tapOn: Passwords
+- assertVisible: My Personal Website
+- tapOn: My Personal Website
+- assertVisible: me@mypersonalwebsite.com
+- assertVisible: mypersonalwebsite.com
+- tapOn: Passwords
+- tapOn: Settings
diff --git a/.maestro/shared/sync_verify_unified_favorites.yaml b/.maestro/shared/sync_verify_unified_favorites.yaml
new file mode 100644
index 0000000000..e23b239ac8
--- /dev/null
+++ b/.maestro/shared/sync_verify_unified_favorites.yaml
@@ -0,0 +1,17 @@
+appId: com.duckduckgo.mobile.ios
+---
+
+- tapOn: Sync & Backup
+- scroll
+- assertVisible: Unify Favorites
+- tapOn:
+ rightOf:
+ id: "UnifiedFavoritesToggle"
+- tapOn: Settings
+- tapOn: Done
+- tapOn: Bookmarks
+- tapOn: Favorites
+- assertVisible: NFL.com | Official Site of the National Football League
+- assertVisible: DuckDuckGo · GitHub
+- assertVisible: Stack Overflow - Where Developers Learn, Share, & Build Careers
+- tapOn: Done
\ No newline at end of file
diff --git a/.maestro/sync_tests/01_create_account.yaml b/.maestro/sync_tests/01_create_account.yaml
index 37484bffb8..4cfb810980 100644
--- a/.maestro/sync_tests/01_create_account.yaml
+++ b/.maestro/sync_tests/01_create_account.yaml
@@ -4,8 +4,11 @@ tags:
---
+# Clear and launch
- clearState
- launchApp
+
+# Run onboarding Flow
- runFlow:
when:
visible:
@@ -13,9 +16,12 @@ tags:
index: 0
file: ../shared/onboarding.yaml
+# Set Internal User
- tapOn: Settings
- runFlow:
- file: ../shared/set_internal_user.yaml
+ file: ../shared/set_internal_user_from_settings.yaml
+
+# Create account
- runFlow:
file: ../shared/sync_create.yaml
diff --git a/.maestro/sync_tests/02_login_account.yaml b/.maestro/sync_tests/02_login_account.yaml
index de383e6e10..b2214cb476 100644
--- a/.maestro/sync_tests/02_login_account.yaml
+++ b/.maestro/sync_tests/02_login_account.yaml
@@ -4,9 +4,11 @@ tags:
---
-# Create an account
+# Clear and launch
- clearState
- launchApp
+
+# Run onboarding Flow
- runFlow:
when:
visible:
@@ -14,30 +16,24 @@ tags:
index: 0
file: ../shared/onboarding.yaml
+# Copy Recovery Code
- tapOn: Settings
- runFlow:
- file: ../shared/set_internal_user.yaml
-- runFlow:
- file: ../shared/sync_create.yaml
+ file: ../shared/copy_recovery_code_from_settings.yaml
+ env:
+ CODE: ${CODE}
-# Log Out
-- assertVisible: Sync & Backup
-- tapOn: Turn Off Sync & Backup...
-- assertVisible: Turn Off Sync?
-- tapOn: Remove
+# Set Internal User
+- runFlow:
+ file: ../shared/set_internal_user_from_settings.yaml
# Login
- assertVisible: Sync & Backup
-- tapOn: Sync with Another Device
-- assertVisible: Scan QR Code
-- tapOn: Manually Enter Code
-- tapOn: Paste
-- assertVisible: Save Recovery Code
-- tapOn: Next
-- assertVisible: Your Data is Synced!
-- tapOn: Done
+- tapOn: Sync & Backup
+- runFlow:
+ file: ../shared/sync_login.yaml
+- assertVisible: Sync & Backup
# Clean up
-- assertVisible: Sync & Backup
- runFlow:
- file: ../shared/sync_delete.yaml
+ file: ../shared/sync_logout.yaml
\ No newline at end of file
diff --git a/.maestro/sync_tests/03_recover_account.yaml b/.maestro/sync_tests/03_recover_account.yaml
index 4736be829c..99a542d74a 100644
--- a/.maestro/sync_tests/03_recover_account.yaml
+++ b/.maestro/sync_tests/03_recover_account.yaml
@@ -4,8 +4,11 @@ tags:
---
+# Clear and launch
- clearState
- launchApp
+
+# Run onboarding Flow
- runFlow:
when:
visible:
@@ -13,61 +16,23 @@ tags:
index: 0
file: ../shared/onboarding.yaml
-# This is a workaround to:
-# - Put the code in the clipboard on Maestro Cloud
-# - Prevent iOS from showing the Paste permission alert as Maestro can't handle it
-- tapOn:
- id: searchEntry
-- inputText: ${CODE}
+# Set Internal User
+- tapOn: Settings
+- runFlow:
+ file: ../shared/set_internal_user_from_settings.yaml
-- evalScript: ${output.counter = 0}
-- repeat:
- while:
- true: ${output.counter < 3}
- notVisible: Select All
- commands:
- - longPressOn:
- id: "searchEntry"
- - evalScript: ${output.counter = output.counter + 1}
+# Create account
+- runFlow:
+ file: ../shared/sync_create.yaml
-- tapOn: 'Select All'
-- tapOn: Cut
-- evalScript: ${output.counter = 0}
-- repeat:
- while:
- true: ${output.counter < 3}
- notVisible: Paste
- commands:
- - tapOn:
- id: "searchEntry"
- - evalScript: ${output.counter = output.counter + 1}
-- tapOn: Paste
-- tapOn: Cancel
+# Log Out
+- runFlow:
+ file: ../shared/sync_logout.yaml
-- tapOn: Close Tabs and Clear Data
-- tapOn: Close Tabs and Clear Data
+# Recover Data
- runFlow:
- when:
- visible:
- text: Cancel
- commands:
- - tapOn: Cancel
-#
+ file: ../shared/sync_recover_data.yaml
-# Recover Account test
-- tapOn: Settings
+# Clean up
- runFlow:
- file: ../shared/set_internal_user.yaml
-- assertVisible: Sync & Backup
-- tapOn: Sync & Backup
-- assertVisible: Begin Syncing
-- tapOn: Recover Synced Data
-- assertVisible: Recover Synced Data
-- assertVisible: Get Started
-- tapOn: Get Started
-- tapOn: Enter Text Code Manually
-- tapOn: Paste
-- assertVisible: Save Recovery Code
-- tapOn: Next
-- assertVisible: Your Data is Synced!
-- tapOn: Done
\ No newline at end of file
+ file: ../shared/sync_delete.yaml
diff --git a/.maestro/sync_tests/04_sync_data.yaml b/.maestro/sync_tests/04_sync_data.yaml
index 2d6ffeebe3..20605a75f8 100644
--- a/.maestro/sync_tests/04_sync_data.yaml
+++ b/.maestro/sync_tests/04_sync_data.yaml
@@ -4,8 +4,11 @@ tags:
---
+# Clear and launch
- clearState
- launchApp
+
+# Run onboarding Flow
- runFlow:
when:
visible:
@@ -14,181 +17,67 @@ tags:
file: ../shared/onboarding.yaml
# Add local favorite and bookmark
-- tapOn:
- id: searchEntry
-- inputText: www.duckduckgo.com
-- pressKey: Enter
- runFlow:
- when:
- visible:
- text: "Got It"
- commands:
- - tapOn: Got It
-- tapOn: Browsing Menu
-- tapOn: Add Favorite
-- tapOn:
- id: searchEntry
-- inputText: www.spreadprivacy.com
-- pressKey: Enter
-- tapOn: Browsing Menu
-- tapOn: Add Bookmark
+ file: ../shared/add_bookmarks_and_favorites.yaml
+- tapOn: Close Tabs and Clear Data
+- tapOn: Close Tabs and Clear Data
# Add local login
-- tapOn: Browsing Menu
- tapOn: Settings
-- tapOn: Logins
-- tapOn: Add 24
-- tapOn: Title
-- inputText: My Personal Website
-- tapOn: username@example.com
-- inputText: me@mypersonalwebsite.com
-- tapOn: example.com
-- inputText: mypersonalwebsite.com
-- tapOn: Save
-- tapOn: Logins
-- tapOn: Settings
-- tapOn: Done
-
-# Sync data
-# This is a workaround to:
-# - Put the code in the clipboard on Maestro Cloud
-# - Prevent iOS from showing the Paste permission alert as Maestro can't handle it
-- tapOn:
- id: searchEntry
-- inputText: ${CODE}
-
-- evalScript: ${output.counter = 0}
-- repeat:
- while:
- true: ${output.counter < 3}
- notVisible: Select All
- commands:
- - longPressOn:
- id: "searchEntry"
- - evalScript: ${output.counter = output.counter + 1}
-
-- tapOn: 'Select All'
-- tapOn: Cut
-- evalScript: ${output.counter = 0}
-- repeat:
- while:
- true: ${output.counter < 3}
- notVisible: Paste
- commands:
- - tapOn:
- id: "searchEntry"
- - evalScript: ${output.counter = output.counter + 1}
-- tapOn: Paste
-- tapOn: Cancel
-
-- tapOn: Close Tabs and Clear Data
-- tapOn: Close Tabs and Clear Data
- runFlow:
- when:
- visible:
- text: Cancel
- commands:
- - tapOn: Cancel
-#
+ file: ../shared/add_login_from_settings.yaml
+# Copy Recovery Code
- tapOn: Settings
- runFlow:
- file: ../shared/set_internal_user.yaml
+ file: ../shared/copy_recovery_code_from_settings.yaml
+ env:
+ CODE: ${CODE}
+
+# Set Internal User
+- runFlow:
+ file: ../shared/set_internal_user_from_settings.yaml
+
+# Login
- assertVisible: Sync & Backup
- tapOn: Sync & Backup
-- assertVisible: Begin Syncing
-- tapOn: Recover Synced Data
-- assertVisible: Recover Synced Data
-- assertVisible: Get Started
-- tapOn: Get Started
-- tapOn: Enter Text Code Manually
-- tapOn: Paste
-- assertVisible: Save Recovery Code
-- tapOn: Next
-- assertVisible: Your Data is Synced!
-- tapOn: Done
+- runFlow:
+ file: ../shared/sync_login.yaml
- assertVisible: Sync & Backup
+
+# Log Out
+- runFlow:
+ file: ../shared/sync_logout.yaml
- tapOn: Settings
-- assertVisible: Settings
- tapOn: Done
-# Verify bookmarks and favorites have been merged
-- tapOn: Bookmarks
-- runFlow:
- when:
- visible:
- text: Download Missing Icons?
- commands:
- - tapOn: Not Now
-
-- assertVisible: Spread Privacy
-- assertVisible: Stack Overflow - Where Developers Learn, Share, & Build Careers
-- assertVisible: DuckDuckGo — Privacy, simplified.
-- assertVisible: DuckDuckGo · GitHub
-- assertVisible: "Wolfram|Alpha: Computational Intelligence"
-- assertVisible: news
-- assertVisible: code
-- assertVisible: sports
-- tapOn: news
-- assertVisible: Breaking News, Latest News and Videos | CNN
-- assertVisible: News, sport and opinion from the Guardian's global edition | The Guardian
-- tapOn: Bookmarks
-- tapOn: code
-- assertVisible: "GitHub - duckduckgo/Android: DuckDuckGo Android App"
-- assertVisible: "GitHub - duckduckgo/iOS: DuckDuckGo iOS Application"
-- tapOn: Bookmarks
-- tapOn: sports
-- assertVisible: NFL.com | Official Site of the National Football League
-- assertVisible: AS.com - Diario online deportivo. Fútbol, motor y mucho más
-- tapOn: Bookmarks
-
-# Only expect local favorites when Share Favorites is off
-- tapOn: Favorites
-- assertVisible: DuckDuckGo — Privacy, simplified.
-
-# Enable Share Favorites and expect all favorites
-- tapOn: Done
+# Remove bookmarks that were added locally
+- runFlow:
+ file: ../shared/remove_local_bookmarks.yaml
+
+# Remove Login that were added locally
+- runFlow:
+ file: ../shared/remove_local_logins.yaml
+
+# Login
- tapOn: Settings
- tapOn: Sync & Backup
-- scroll
-- assertVisible: Unify Favorites
-- tapOn: "0"
-- tapOn: "0"
+- runFlow:
+ file: ../shared/sync_login.yaml
+
+# Verify bookmarks have been merged
- tapOn: Settings
+- runFlow:
+ file: ../shared/sync_verify_bookmarks.yaml
+
+# Verify favorites are unified
- tapOn: Done
-- tapOn: Bookmarks
-- tapOn: Favorites
-- assertVisible: NFL.com | Official Site of the National Football League
-- assertVisible: DuckDuckGo · GitHub
-- assertVisible: Stack Overflow - Where Developers Learn, Share, & Build Careers
-- tapOn: Done
+- tapOn: Settings
+- runFlow:
+ file: ../shared/sync_verify_unified_favorites.yaml
# Verify logins
- tapOn: Settings
-- tapOn: Logins
-- assertVisible: Unlock device to access saved Logins
-- tapOn: Passcode field
-- inputText: "0000"
-- pressKey: Enter
-- assertVisible: Dax Login
-- tapOn: Dax Login
-- assertVisible: daxthetest
-- assertVisible: duckduckgo.com
-- tapOn: Logins
-- assertVisible: Github
-- tapOn: Github
-- assertVisible: githubusername
-- assertVisible: github.com
-- tapOn: Logins
-- assertVisible: StackOverflow
-- tapOn: StackOverflow
-- assertVisible: stacker
-- assertVisible: stackoverflow.com
-- tapOn: Logins
-- assertVisible: My Personal Website
-- tapOn: My Personal Website
-- assertVisible: me@mypersonalwebsite.com
-- assertVisible: mypersonalwebsite.com
-- tapOn: Logins
-- tapOn: Settings
-- tapOn: Done
\ No newline at end of file
+- runFlow:
+ file: ../shared/sync_verify_logins.yaml
+
diff --git a/.maestro/sync_tests/05_delete_account.yaml b/.maestro/sync_tests/05_delete_account.yaml
new file mode 100644
index 0000000000..76947f05fd
--- /dev/null
+++ b/.maestro/sync_tests/05_delete_account.yaml
@@ -0,0 +1,39 @@
+appId: com.duckduckgo.mobile.ios
+tags:
+ - sync
+
+---
+
+# Clear and launch
+- clearState
+- launchApp
+
+# Run onboarding Flow
+- runFlow:
+ when:
+ visible:
+ text: "Let’s Do It!"
+ index: 0
+ file: ../shared/onboarding.yaml
+
+# Set Internal User
+- tapOn: Settings
+- runFlow:
+ file: ../shared/set_internal_user_from_settings.yaml
+
+# Create account
+- runFlow:
+ file: ../shared/sync_create.yaml
+
+# Remove account
+- runFlow:
+ file: ../shared/sync_delete.yaml
+
+# Try to login and check for error
+- assertVisible: Begin Syncing
+- tapOn: Sync with Another Device
+- assertVisible: Scan QR Code
+- tapOn: Manually Enter Code
+- tapOn: Paste
+- assertVisible: Sync Error
+- tapOn: OK
diff --git a/.swiftlint.yml b/.swiftlint.yml
index 9b5e726984..ae3959c57f 100644
--- a/.swiftlint.yml
+++ b/.swiftlint.yml
@@ -1,3 +1,5 @@
+allow_zero_lintable_files: true
+
disabled_rules:
- discarded_notification_center_observer
- notification_center_detachment
diff --git a/Configuration/Version.xcconfig b/Configuration/Version.xcconfig
index 3e6917b72b..8d65bcd73a 100644
--- a/Configuration/Version.xcconfig
+++ b/Configuration/Version.xcconfig
@@ -1 +1 @@
-MARKETING_VERSION = 7.99.0
+MARKETING_VERSION = 7.102.0
diff --git a/Core/AppPrivacyConfigurationDataProvider.swift b/Core/AppPrivacyConfigurationDataProvider.swift
index 81a313c2df..88beeca5eb 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 = "\"7c6169d648700908e0dfc5904d640c37\""
- public static let embeddedDataSHA = "e3cd448b68a22fe6c9563deeb4c7d2a62ae947bc655ff33b3fc030bba766672c"
+ public static let embeddedDataETag = "\"388dd0526e94f80473728c0bfbb48b39\""
+ public static let embeddedDataSHA = "f7b9ae8860ff84f33e602b40d0938776d2d9327115b4ddfe09fc0fa09b5e1ff1"
}
public var embeddedDataEtag: String {
diff --git a/Core/BookmarksModelsErrorHandling.swift b/Core/BookmarksModelsErrorHandling.swift
index 5d25ef7c80..b60ecdd4d8 100644
--- a/Core/BookmarksModelsErrorHandling.swift
+++ b/Core/BookmarksModelsErrorHandling.swift
@@ -57,10 +57,6 @@ public class BookmarksModelsErrorHandling: EventMapping {
case .missingParent(let object):
domainEvent = .missingParent(object)
- case .orphanedBookmarksPresent:
- if let syncService, syncService.authState == .inactive {
- domainEvent = .orphanedBookmarksPresent
- }
}
if let domainEvent {
diff --git a/Core/DailyPixel.swift b/Core/DailyPixel.swift
index eb583ee6af..af326479de 100644
--- a/Core/DailyPixel.swift
+++ b/Core/DailyPixel.swift
@@ -51,10 +51,14 @@ public final class DailyPixel {
/// Does not append any suffix unlike the alternative function below
public static func fire(pixel: Pixel.Event,
withAdditionalParameters params: [String: String] = [:],
+ includedParameters: [Pixel.QueryParameters] = [.atb, .appVersion],
onComplete: @escaping (Swift.Error?) -> Void = { _ in }) {
if !pixel.hasBeenFiredToday(dailyPixelStorage: storage) {
- Pixel.fire(pixel: pixel, withAdditionalParameters: params, onComplete: onComplete)
+ Pixel.fire(pixel: pixel,
+ withAdditionalParameters: params,
+ includedParameters: includedParameters,
+ onComplete: onComplete)
updatePixelLastFireDate(pixel: pixel)
} else {
onComplete(Error.alreadyFired)
diff --git a/Core/FeatureFlag.swift b/Core/FeatureFlag.swift
index 2f0819907d..06e6589641 100644
--- a/Core/FeatureFlag.swift
+++ b/Core/FeatureFlag.swift
@@ -39,8 +39,16 @@ public enum FeatureFlag: String {
extension FeatureFlag: FeatureFlagSourceProviding {
public var source: FeatureFlagSource {
switch self {
- case .debugMenu, .sync, .appTrackingProtection, .networkProtection, .networkProtectionWaitlistAccess, .networkProtectionWaitlistActive:
+ case .debugMenu, .appTrackingProtection:
return .internalOnly
+ case .sync:
+ return .remoteReleasable(.subfeature(SyncSubfeature.level0ShowSync))
+ case .networkProtection:
+ return .remoteReleasable(.feature(.networkProtection))
+ case .networkProtectionWaitlistAccess:
+ return .remoteReleasable(.subfeature(NetworkProtectionSubfeature.waitlist))
+ case .networkProtectionWaitlistActive:
+ return .remoteReleasable(.subfeature(NetworkProtectionSubfeature.waitlistBetaActive))
case .autofillCredentialInjecting:
return .remoteReleasable(.subfeature(AutofillSubfeature.credentialsAutofill))
case .autofillCredentialsSaving:
diff --git a/Core/Pixel.swift b/Core/Pixel.swift
index 229598fd36..b6d16d54cf 100644
--- a/Core/Pixel.swift
+++ b/Core/Pixel.swift
@@ -203,7 +203,7 @@ public class Pixel {
headers: headers)
let request = APIRequest(configuration: configuration, urlSession: .session(useMainThreadCallbackQueue: true))
request.fetch { _, error in
- os_log("Pixel fired %s %s", log: .generalLog, type: .debug, pixelName, "\(params)")
+ os_log("Pixel fired %{public}s %{public}s", log: .generalLog, type: .debug, pixelName, "\(params)")
onComplete(error)
}
}
diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift
index b5c54cf168..8d1ac89d99 100644
--- a/Core/PixelEvent.swift
+++ b/Core/PixelEvent.swift
@@ -21,6 +21,8 @@ import Foundation
import BrowserServicesKit
import Bookmarks
import Configuration
+import DDGSync
+import NetworkProtection
// swiftlint:disable file_length
extension Pixel {
@@ -313,9 +315,21 @@ extension Pixel {
// MARK: Network Protection
case networkProtectionActiveUser
+ case networkProtectionNewUser
+
+ case networkProtectionEnableAttemptConnecting
+ case networkProtectionEnableAttemptSuccess
+ case networkProtectionEnableAttemptFailure
+
+ case networkProtectionTunnelFailureDetected
+ case networkProtectionTunnelFailureRecovered
+
+ case networkProtectionLatency(quality: NetworkProtectionLatencyMonitor.ConnectionQuality)
+ case networkProtectionLatencyError
+
+ case networkProtectionEnabledOnSearch
case networkProtectionRekeyCompleted
- case networkProtectionLatency
case networkProtectionTunnelConfigurationNoServerRegistrationInfo
case networkProtectionTunnelConfigurationCouldNotSelectClosestServer
@@ -491,7 +505,6 @@ extension Pixel {
case indexOutOfRange(BookmarksModelError.ModelType)
case saveFailed(BookmarksModelError.ModelType)
case missingParent(BookmarksModelError.ObjectType)
- case orphanedBookmarksPresent
case bookmarksCouldNotLoadDatabase
case bookmarksCouldNotPrepareDatabase
@@ -503,6 +516,13 @@ extension Pixel {
case bookmarksMigrationCouldNotRemoveOldStore
case bookmarksMigrationCouldNotPrepareMultipleFavoriteFolders
+ case syncSignupDirect
+ case syncSignupConnect
+ case syncLogin
+ case syncDaily
+ case syncDuckAddressOverride
+ case syncSuccessRateDaily
+ case syncLocalTimestampResolutionTriggered(Feature)
case syncFailedToMigrate
case syncFailedToLoadAccount
case syncFailedToSetupEngine
@@ -841,8 +861,16 @@ extension Pixel.Event {
// MARK: Network Protection pixels
case .networkProtectionActiveUser: return "m_netp_daily_active_d"
+ case .networkProtectionNewUser: return "m_netp_daily_active_u"
+ case .networkProtectionEnableAttemptConnecting: return "m_netp_ev_enable_attempt"
+ case .networkProtectionEnableAttemptSuccess: return "m_netp_ev_enable_attempt_success"
+ case .networkProtectionEnableAttemptFailure: return "m_netp_ev_enable_attempt_failure"
+ case .networkProtectionTunnelFailureDetected: return "m_netp_ev_tunnel_failure"
+ case .networkProtectionTunnelFailureRecovered: return "m_netp_ev_tunnel_failure_recovered"
+ case .networkProtectionLatency(let quality): return "m_netp_ev_\(quality.rawValue)_latency"
+ case .networkProtectionLatencyError: return "m_netp_ev_latency_error_d"
case .networkProtectionRekeyCompleted: return "m_netp_rekey_completed"
- case .networkProtectionLatency: return "m_netp_latency"
+ case .networkProtectionEnabledOnSearch: return "m_netp_enabled_on_search"
case .networkProtectionTunnelConfigurationNoServerRegistrationInfo: return "m_netp_tunnel_config_error_no_server_registration_info"
case .networkProtectionTunnelConfigurationCouldNotSelectClosestServer: return "m_netp_tunnel_config_error_could_not_select_closest_server"
case .networkProtectionTunnelConfigurationCouldNotGetPeerPublicKey: return "m_netp_tunnel_config_error_could_not_get_peer_public_key"
@@ -1007,7 +1035,6 @@ extension Pixel.Event {
case .indexOutOfRange(let modelType): return "m_d_bookmarks_index_out_of_range_\(modelType.rawValue)"
case .saveFailed(let modelType): return "m_d_bookmarks_view_model_save_failed_\(modelType.rawValue)"
case .missingParent(let objectType): return "m_d_bookmark_model_missing_parent_\(objectType.rawValue)"
- case .orphanedBookmarksPresent: return "m_d_bookmarks_orphans_present"
case .bookmarksCouldNotLoadDatabase: return "m_d_bookmarks_could_not_load_database"
case .bookmarksCouldNotPrepareDatabase: return "m_d_bookmarks_could_not_prepare_database"
@@ -1020,6 +1047,13 @@ extension Pixel.Event {
case .bookmarksMigrationCouldNotRemoveOldStore: return "m_d_bookmarks_migration_could_not_remove_old_store"
case .bookmarksMigrationCouldNotPrepareMultipleFavoriteFolders: return "m_d_bookmarks_migration_could_not_prepare_multiple_favorite_folders"
+ case .syncSignupDirect: return "m_sync_signup_direct"
+ case .syncSignupConnect: return "m_sync_signup_connect"
+ case .syncLogin: return "m_sync_login"
+ case .syncDaily: return "m_sync_daily"
+ case .syncDuckAddressOverride: return "m_sync_duck_address_override"
+ case .syncSuccessRateDaily: return "m_sync_success_rate_daily"
+ case .syncLocalTimestampResolutionTriggered(let feature): return "m_sync_\(feature.name)_local_timestamp_resolution_triggered"
case .syncFailedToMigrate: return "m_d_sync_failed_to_migrate"
case .syncFailedToLoadAccount: return "m_d_sync_failed_to_load_account"
case .syncFailedToSetupEngine: return "m_d_sync_failed_to_setup_engine"
diff --git a/Core/PrintingUserScript.swift b/Core/PrintingUserScript.swift
index 64c458f727..4ee0c3c947 100644
--- a/Core/PrintingUserScript.swift
+++ b/Core/PrintingUserScript.swift
@@ -42,6 +42,7 @@ public class PrintingUserScript: NSObject, UserScript {
public var injectionTime: WKUserScriptInjectionTime = .atDocumentStart
public var forMainFrameOnly: Bool = false
public var messageNames: [String] = ["printHandler"]
+ public var requiresRunInPageContentWorld: Bool = true
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
delegate?.printingUserScriptDidRequestPrintController(self)
diff --git a/Core/SyncBookmarksAdapter.swift b/Core/SyncBookmarksAdapter.swift
index 6063cb766c..0d3a4acf2f 100644
--- a/Core/SyncBookmarksAdapter.swift
+++ b/Core/SyncBookmarksAdapter.swift
@@ -119,7 +119,11 @@ public final class SyncBookmarksAdapter {
}
}
- public func setUpProviderIfNeeded(database: CoreDataDatabase, metadataStore: SyncMetadataStore) {
+ public func setUpProviderIfNeeded(
+ database: CoreDataDatabase,
+ metadataStore: SyncMetadataStore,
+ metricsEventsHandler: EventMapping? = nil
+ ) {
guard provider == nil else {
return
}
@@ -129,6 +133,7 @@ public final class SyncBookmarksAdapter {
let provider = BookmarksProvider(
database: database,
metadataStore: metadataStore,
+ metricsEvents: metricsEventsHandler,
syncDidUpdateData: { [weak self] in
self?.syncDidCompleteSubject.send()
Self.isSyncBookmarksPaused = false
diff --git a/Core/SyncCredentialsAdapter.swift b/Core/SyncCredentialsAdapter.swift
index d98f7ba068..7d2acb7849 100644
--- a/Core/SyncCredentialsAdapter.swift
+++ b/Core/SyncCredentialsAdapter.swift
@@ -63,7 +63,11 @@ public final class SyncCredentialsAdapter {
}
}
- public func setUpProviderIfNeeded(secureVaultFactory: AutofillVaultFactory, metadataStore: SyncMetadataStore) {
+ public func setUpProviderIfNeeded(
+ secureVaultFactory: AutofillVaultFactory,
+ metadataStore: SyncMetadataStore,
+ metricsEventsHandler: EventMapping? = nil
+ ) {
guard provider == nil else {
return
}
@@ -73,6 +77,7 @@ public final class SyncCredentialsAdapter {
secureVaultFactory: secureVaultFactory,
secureVaultErrorReporter: secureVaultErrorReporter,
metadataStore: metadataStore,
+ metricsEvents: metricsEventsHandler,
syncDidUpdateData: { [weak self] in
self?.syncDidCompleteSubject.send()
Self.isSyncCredentialsPaused = false
diff --git a/Core/SyncDataProviders.swift b/Core/SyncDataProviders.swift
index a70b4acd4f..f655abc5ae 100644
--- a/Core/SyncDataProviders.swift
+++ b/Core/SyncDataProviders.swift
@@ -38,9 +38,21 @@ public class SyncDataProviders: DataProvidersSource {
return []
}
- bookmarksAdapter.setUpProviderIfNeeded(database: bookmarksDatabase, metadataStore: syncMetadata)
- credentialsAdapter.setUpProviderIfNeeded(secureVaultFactory: secureVaultFactory, metadataStore: syncMetadata)
- settingsAdapter.setUpProviderIfNeeded(metadataDatabase: syncMetadataDatabase, metadataStore: syncMetadata)
+ bookmarksAdapter.setUpProviderIfNeeded(
+ database: bookmarksDatabase,
+ metadataStore: syncMetadata,
+ metricsEventsHandler: metricsEventsHandler
+ )
+ credentialsAdapter.setUpProviderIfNeeded(
+ secureVaultFactory: secureVaultFactory,
+ metadataStore: syncMetadata,
+ metricsEventsHandler: metricsEventsHandler
+ )
+ settingsAdapter.setUpProviderIfNeeded(
+ metadataDatabase: syncMetadataDatabase,
+ metadataStore: syncMetadata,
+ metricsEventsHandler: metricsEventsHandler
+ )
let providers: [Any] = [
bookmarksAdapter.provider as Any,
@@ -122,6 +134,7 @@ public class SyncDataProviders: DataProvidersSource {
private var isDatabaseCleanersSetUp: Bool = false
private var syncMetadata: SyncMetadataStore?
private var syncAuthStateDidChangeCancellable: AnyCancellable?
+ private let metricsEventsHandler = SyncMetricsEventsHandler()
private let syncMetadataDatabase: CoreDataDatabase = SyncMetadataDatabase.make()
private let bookmarksDatabase: CoreDataDatabase
diff --git a/Core/SyncMetricsEventsHandler.swift b/Core/SyncMetricsEventsHandler.swift
new file mode 100644
index 0000000000..a9fb6f2a10
--- /dev/null
+++ b/Core/SyncMetricsEventsHandler.swift
@@ -0,0 +1,40 @@
+//
+// SyncMetricsEventsHandler.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 Common
+import SyncDataProviders
+import Foundation
+
+public class SyncMetricsEventsHandler: EventMapping {
+
+ public init() {
+ super.init { event, _, _, _ in
+ switch event {
+ case .overrideEmailProtectionSettings:
+ Pixel.fire(pixel: .syncDuckAddressOverride, includedParameters: [.appVersion])
+ case .localTimestampResolutionTriggered(let feature):
+ Pixel.fire(pixel: .syncLocalTimestampResolutionTriggered(feature), includedParameters: [.appVersion])
+ }
+ }
+ }
+
+ override init(mapping: @escaping EventMapping.Mapping) {
+ fatalError("Use init()")
+ }
+}
diff --git a/Core/SyncSettingsAdapter.swift b/Core/SyncSettingsAdapter.swift
index 9bfe132bb4..9b310a9291 100644
--- a/Core/SyncSettingsAdapter.swift
+++ b/Core/SyncSettingsAdapter.swift
@@ -38,7 +38,11 @@ public final class SyncSettingsAdapter {
public func updateDatabaseCleanupSchedule(shouldEnable: Bool) {
}
- public func setUpProviderIfNeeded(metadataDatabase: CoreDataDatabase, metadataStore: SyncMetadataStore) {
+ public func setUpProviderIfNeeded(
+ metadataDatabase: CoreDataDatabase,
+ metadataStore: SyncMetadataStore,
+ metricsEventsHandler: EventMapping? = nil
+ ) {
guard provider == nil else {
return
}
@@ -50,6 +54,7 @@ public final class SyncSettingsAdapter {
metadataDatabase: metadataDatabase,
metadataStore: metadataStore,
settingsHandlers: settingHandlers + [emailProtectionSyncHandler],
+ metricsEvents: metricsEventsHandler,
syncDidUpdateData: { [weak self] in
self?.syncDidCompleteSubject.send()
}
diff --git a/Core/UniquePixel.swift b/Core/UniquePixel.swift
new file mode 100644
index 0000000000..4be27a5e61
--- /dev/null
+++ b/Core/UniquePixel.swift
@@ -0,0 +1,84 @@
+//
+// UniquePixel.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
+
+/// A variant of pixel that is fired just once. Ever.
+///
+/// The 'fire' method mimics standard Pixel API.
+/// The 'onComplete' closure is always called - even when no pixel is fired.
+/// In those scenarios a 'UniquePixelError' is returned denoting the reason.
+///
+public final class UniquePixel {
+
+ public enum Error: Swift.Error {
+
+ case alreadyFired
+
+ }
+
+ private enum Constant {
+
+ static let uniquePixelStorageIdentifier = "com.duckduckgo.unique.pixel.storage"
+
+ }
+
+ public static let storage = UserDefaults(suiteName: Constant.uniquePixelStorageIdentifier)!
+
+ /// Sends a unique Pixel
+ /// This requires the pixel name to end with `_u`
+ public static func fire(pixel: Pixel.Event,
+ withAdditionalParameters params: [String: String] = [:],
+ onComplete: @escaping (Swift.Error?) -> Void = { _ in }) {
+ guard pixel.name.hasSuffix("_u") else {
+ assertionFailure("Unique pixel: must end with _u")
+ return
+ }
+
+ if !pixel.hasBeenFiredEver(uniquePixelStorage: storage) {
+ Pixel.fire(pixel: pixel, withAdditionalParameters: params, onComplete: onComplete)
+ storage.set(Date(), forKey: pixel.name)
+ } else {
+ onComplete(Error.alreadyFired)
+ }
+ }
+
+ public static func dateString(for date: Date?) -> String {
+ guard let date else { return "" }
+
+ let dateFormatter = DateFormatter()
+ dateFormatter.calendar = Calendar.current
+ dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
+ dateFormatter.dateFormat = "yyyy-MM-dd"
+
+ return dateFormatter.string(from: date)
+ }
+}
+
+extension Pixel.Event {
+
+ public func lastFireDate(uniquePixelStorage: UserDefaults) -> Date? {
+ uniquePixelStorage.object(forKey: name) as? Date
+ }
+
+ func hasBeenFiredEver(uniquePixelStorage: UserDefaults) -> Bool {
+ lastFireDate(uniquePixelStorage: uniquePixelStorage) != nil
+ }
+
+}
diff --git a/Core/ios-config.json b/Core/ios-config.json
index 092015bfeb..2afc6d62c5 100644
--- a/Core/ios-config.json
+++ b/Core/ios-config.json
@@ -1,6 +1,6 @@
{
"readme": "https://github.com/duckduckgo/privacy-configuration",
- "version": 1701253939396,
+ "version": 1703026028516,
"features": {
"adClickAttribution": {
"readme": "https://help.duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections/#3rd-party-tracker-loading-protection",
@@ -245,6 +245,9 @@
{
"domain": "metro.co.uk"
},
+ {
+ "domain": "youtube.com"
+ },
{
"domain": "earth.google.com"
},
@@ -264,7 +267,7 @@
]
},
"state": "enabled",
- "hash": "9ab9e1acdb6a8617c77109acc1e3943c"
+ "hash": "a1060783f1bf56f5cc661b994c9c9e56"
},
"autofill": {
"exceptions": [
@@ -1061,7 +1064,7 @@
},
"customUserAgent": {
"settings": {
- "defaultPolicy": "ddgFixed",
+ "defaultPolicy": "closest",
"ddgFixedSites": [],
"ddgDefaultSites": [
{
@@ -1070,131 +1073,7 @@
}
],
"closestUserAgent": {
- "versions": [
- "392",
- "390",
- "387",
- "385",
- "384",
- "381",
- "380",
- "378",
- "375",
- "373",
- "372",
- "369",
- "368",
- "366",
- "363",
- "362",
- "359",
- "357",
- "355",
- "354",
- "352",
- "350",
- "347",
- "346",
- "344",
- "342",
- "339",
- "337",
- "335",
- "333",
- "331",
- "329",
- "328",
- "326",
- "323",
- "321",
- "320",
- "318",
- "315",
- "313",
- "312",
- "309",
- "308",
- "306",
- "304",
- "302",
- "300",
- "298",
- "295",
- "293",
- "291",
- "289",
- "287",
- "285",
- "284",
- "281",
- "279",
- "278",
- "276",
- "274",
- "271",
- "269",
- "268",
- "266",
- "263",
- "262",
- "260",
- "257",
- "256",
- "254",
- "251",
- "249",
- "248",
- "245",
- "244",
- "241",
- "239",
- "238",
- "236",
- "234",
- "232",
- "230",
- "228",
- "226",
- "223",
- "222",
- "220",
- "218",
- "215",
- "213",
- "211",
- "209",
- "208",
- "205",
- "203",
- "202",
- "199",
- "197",
- "196",
- "194",
- "191",
- "190",
- "187",
- "185",
- "184",
- "182",
- "180",
- "178",
- "176",
- "173",
- "171",
- "169",
- "167",
- "165",
- "163",
- "161",
- "160",
- "157",
- "155",
- "154",
- "152",
- "150",
- "148"
- ]
+ "versions": []
},
"omitApplicationSites": [
{
@@ -1238,42 +1117,6 @@
},
{
"domain": "sundancecatalog.com"
- },
- {
- "domain": "cvs.com"
- },
- {
- "domain": "facebook.com"
- },
- {
- "domain": "finewineandgoodspirits.com"
- },
- {
- "domain": "formula1.com"
- },
- {
- "domain": "gigisplayhouse.org"
- },
- {
- "domain": "hulu.com"
- },
- {
- "domain": "instagram.com"
- },
- {
- "domain": "republicservices.com"
- },
- {
- "domain": "xfinity.com"
- },
- {
- "domain": "homedepot.ca"
- },
- {
- "domain": "unclaimedmoneyinfo.com"
- },
- {
- "domain": "timesmachine.nytimes.com"
}
],
"omitVersionSites": [
@@ -1296,7 +1139,20 @@
},
"exceptions": [],
"state": "enabled",
- "hash": "4c62237a3eeaf9cfec814fc3fb7af282"
+ "hash": "161a405c1f003e7d2c0df2a14d873389"
+ },
+ "dbp": {
+ "state": "disabled",
+ "features": {
+ "waitlist": {
+ "state": "disabled"
+ },
+ "waitlistBetaActive": {
+ "state": "disabled"
+ }
+ },
+ "exceptions": [],
+ "hash": "ba52a36920a4a76343fc3c44d98936f9"
},
"duckPlayer": {
"exceptions": [],
@@ -1453,6 +1309,10 @@
"selector": ".ad-unit",
"type": "hide-empty"
},
+ {
+ "selector": ".ad-unit-wrapper",
+ "type": "hide-empty"
+ },
{
"selector": ".column-ad",
"type": "hide-empty"
@@ -1541,6 +1401,10 @@
"selector": ".ad-banner-container",
"type": "hide-empty"
},
+ {
+ "selector": "#banner_ad",
+ "type": "hide-empty"
+ },
{
"selector": "[class*='bannerAd']",
"type": "hide-empty"
@@ -1629,6 +1493,10 @@
"selector": "[id*='advert-']",
"type": "hide-empty"
},
+ {
+ "selector": "[aria-label='advertisement']",
+ "type": "hide-empty"
+ },
{
"selector": ".ads__inline",
"type": "closest-empty"
@@ -1877,6 +1745,19 @@
"upgrade to flickr pro to hide these ads"
],
"domains": [
+ {
+ "domain": "10minutemail.com",
+ "rules": [
+ {
+ "selector": "#secondary_ads",
+ "type": "hide-empty"
+ },
+ {
+ "selector": "#vi-smartbanner",
+ "type": "hide"
+ }
+ ]
+ },
{
"domain": "3bmeteo.com",
"rules": [
@@ -1893,6 +1774,27 @@
}
]
},
+ {
+ "domain": "9gag.com",
+ "rules": [
+ {
+ "selector": ".billboard",
+ "type": "hide-empty"
+ },
+ {
+ "selector": ".inline-ad-container",
+ "type": "hide-empty"
+ },
+ {
+ "selector": ".salt-section",
+ "type": "hide-empty"
+ },
+ {
+ "selector": "#top-adhesion",
+ "type": "hide-empty"
+ }
+ ]
+ },
{
"domain": "abc.es",
"rules": [
@@ -2062,6 +1964,19 @@
}
]
},
+ {
+ "domain": "businessinsider.com",
+ "rules": [
+ {
+ "selector": ".in-post-sticky",
+ "type": "hide-empty"
+ },
+ {
+ "selector": ".subnav-ad-layout",
+ "type": "hide-empty"
+ }
+ ]
+ },
{
"domain": "carandclassic.com",
"rules": [
@@ -2192,6 +2107,49 @@
}
]
},
+ {
+ "domain": "dexerto.com",
+ "rules": [
+ {
+ "selector": "#leaderboard-top-adhesion",
+ "type": "closest-empty"
+ },
+ {
+ "selector": "[data-cy='Ad']",
+ "type": "closest-empty"
+ },
+ {
+ "selector": "[data-cy='VidazooPlayer']",
+ "type": "closest-empty"
+ }
+ ]
+ },
+ {
+ "domain": "dpreview.com",
+ "rules": [
+ {
+ "selector": ".ad-wrapper",
+ "type": "override"
+ }
+ ]
+ },
+ {
+ "domain": "drugs.com",
+ "rules": [
+ {
+ "selector": ".topbanner-wrap",
+ "type": "hide"
+ },
+ {
+ "selector": ".display-ad-wrapper",
+ "type": "hide-empty"
+ },
+ {
+ "selector": "[id*='ddc-sidebox-ad-stacked-wrap']",
+ "type": "hide-empty"
+ }
+ ]
+ },
{
"domain": "ebay.com",
"rules": [
@@ -2438,6 +2396,35 @@
}
]
},
+ {
+ "domain": "gbnews.com",
+ "rules": [
+ {
+ "selector": ".video-inbody",
+ "type": "hide-empty"
+ },
+ {
+ "selector": ".ad--billboard",
+ "type": "hide"
+ },
+ {
+ "selector": ".ad--placeholder",
+ "type": "hide"
+ },
+ {
+ "selector": ".stiky_sky",
+ "type": "hide"
+ },
+ {
+ "selector": "[position='sticky_banner']",
+ "type": "hide"
+ },
+ {
+ "selector": ".ad-inbody",
+ "type": "hide"
+ }
+ ]
+ },
{
"domain": "getpocket.com",
"rules": [
@@ -2540,6 +2527,23 @@
}
]
},
+ {
+ "domain": "healthline.com",
+ "rules": [
+ {
+ "selector": "[data-testid='header-leaderboard']",
+ "type": "hide-empty"
+ },
+ {
+ "selector": "[data-testid='sticky-inline-ad']",
+ "type": "closest-empty"
+ },
+ {
+ "selector": "[data-ad='true']",
+ "type": "closest-empty"
+ }
+ ]
+ },
{
"domain": "hindustantimes.com",
"rules": [
@@ -2637,6 +2641,10 @@
{
"selector": ".in-post-sticky",
"type": "hide-empty"
+ },
+ {
+ "selector": ".subnav-ad-layout",
+ "type": "hide-empty"
}
]
},
@@ -2948,11 +2956,14 @@
]
},
{
- "domain": "orange.fr",
+ "domain": "oceanofcompressed.xyz",
"rules": [
{
- "selector": ".tag-rm",
- "type": "hide-empty"
+ "type": "disable-default"
+ },
+ {
+ "selector": "#sticky-ads",
+ "type": "hide"
}
]
},
@@ -2969,6 +2980,15 @@
}
]
},
+ {
+ "domain": "orange.fr",
+ "rules": [
+ {
+ "selector": ".tag-rm",
+ "type": "hide-empty"
+ }
+ ]
+ },
{
"domain": "ouest-france.fr",
"rules": [
@@ -2991,6 +3011,35 @@
}
]
},
+ {
+ "domain": "pcgamesn.com",
+ "rules": [
+ {
+ "selector": ".static_mpu_wrap",
+ "type": "hide-empty"
+ },
+ {
+ "selector": "#nn_astro_wrapper",
+ "type": "hide-empty"
+ },
+ {
+ "selector": ".ad-nextpage",
+ "type": "hide"
+ },
+ {
+ "selector": ".legion_primiswrapper",
+ "type": "hide-empty"
+ },
+ {
+ "selector": ".nn_mobile_mpu_wrapper",
+ "type": "hide-empty"
+ },
+ {
+ "selector": ".nn-sticky",
+ "type": "hide-empty"
+ }
+ ]
+ },
{
"domain": "petapixel.com",
"rules": [
@@ -3630,6 +3679,10 @@
{
"selector": "[data-content='Advertisement']",
"type": "hide-empty"
+ },
+ {
+ "selector": "#YDC-Lead-Stack",
+ "type": "hide-empty"
}
]
},
@@ -3747,7 +3800,7 @@
]
},
"state": "enabled",
- "hash": "f7c00905a329790def09ac2296a0e1da"
+ "hash": "182ef21a9dcfd3a160468f851c4b1789"
},
"exceptionHandler": {
"exceptions": [
@@ -4461,6 +4514,25 @@
"state": "disabled",
"hash": "5e792dd491428702bc0104240fbce0ce"
},
+ "sync": {
+ "exceptions": [],
+ "state": "internal",
+ "features": {
+ "level0ShowSync": {
+ "state": "enabled"
+ },
+ "level1AllowDataSyncing": {
+ "state": "enabled"
+ },
+ "level2AllowSetupFlows": {
+ "state": "enabled"
+ },
+ "level3AllowCreateAccount": {
+ "state": "enabled"
+ }
+ },
+ "hash": "92673fe625ae2b888a4b0bfa9a974ce4"
+ },
"trackerAllowlist": {
"state": "enabled",
"settings": {
@@ -4495,6 +4567,16 @@
}
]
},
+ "a2z.com": {
+ "rules": [
+ {
+ "rule": "assets.brightspot.abebooks.a2z.com/",
+ "domains": [
+ ""
+ ]
+ }
+ ]
+ },
"acsbapp.com": {
"rules": [
{
@@ -4713,6 +4795,12 @@
"wxii12.com",
"wyff4.com"
]
+ },
+ {
+ "rule": "z-na.amazon-adsystem.com/widgets/onejs",
+ "domains": [
+ "oceanofcompressed.xyz"
+ ]
}
]
},
@@ -4741,7 +4829,17 @@
{
"rule": "analytics.analytics-egain.com/onetag/",
"domains": [
- "support.norton.com"
+ ""
+ ]
+ }
+ ]
+ },
+ "appboycdn.com": {
+ "rules": [
+ {
+ "rule": "js.appboycdn.com/web-sdk/3.1/appboy.min.js",
+ "domains": [
+ "edx.org"
]
}
]
@@ -5240,6 +5338,7 @@
"ah.nl",
"nytimes.com",
"rocketnews24.com",
+ "uwbadgers.com",
"wunderground.com",
"youmath.it"
]
@@ -5286,6 +5385,7 @@
"asics.com",
"brooklinen.com",
"carters.com",
+ "otterbox.com",
"seatosummit.com"
]
}
@@ -5345,6 +5445,16 @@
}
]
},
+ "egain.cloud": {
+ "rules": [
+ {
+ "rule": "egain.cloud/",
+ "domains": [
+ ""
+ ]
+ }
+ ]
+ },
"ensighten.com": {
"rules": [
{
@@ -5403,12 +5513,6 @@
},
"facebook.net": {
"rules": [
- {
- "rule": "connect.facebook.net/en_UK/sdk.js",
- "domains": [
- "globalcyclingnetwork.com"
- ]
- },
{
"rule": "connect.facebook.net/en_US/sdk.js",
"domains": [
@@ -5455,8 +5559,7 @@
{
"rule": "app.five9.com",
"domains": [
- "gmsdnv.com",
- "machiassavings.bank"
+ ""
]
}
]
@@ -5583,6 +5686,7 @@
"domains": [
"doterra.com",
"easyjet.com",
+ "edx.org",
"worlddutyfree.com"
]
},
@@ -5679,6 +5783,7 @@
{
"rule": "imasdk.googleapis.com/js/sdkloader/ima3.js",
"domains": [
+ "arkadium.com",
"bloomberg.com",
"gamak.tv",
"games.washingtonpost.com",
@@ -5688,6 +5793,12 @@
"rawstory.com",
"usatoday.com"
]
+ },
+ {
+ "rule": "storage.googleapis.com/code.snapengage.com/",
+ "domains": [
+ ""
+ ]
}
]
},
@@ -5706,6 +5817,9 @@
{
"rule": "pagead2.googlesyndication.com/pagead/js/adsbygoogle.js",
"domains": [
+ "air-journal.fr",
+ "arcadepunks.com",
+ "daotranslate.com",
"drakescans.com",
"duden.de",
"magicgameworld.com",
@@ -5745,7 +5859,8 @@
{
"rule": "googletagmanager.com/gtag/js",
"domains": [
- "abril.com.br"
+ "abril.com.br",
+ "cosmicbook.news"
]
}
]
@@ -5905,15 +6020,9 @@
"gorgias.chat": {
"rules": [
{
- "rule": "config.gorgias.chat",
+ "rule": "gorgias.chat",
"domains": [
- "help.athleticbrewing.com"
- ]
- },
- {
- "rule": "assets.gorgias.chat",
- "domains": [
- "help.athleticbrewing.com"
+ ""
]
}
]
@@ -5985,7 +6094,13 @@
{
"rule": "api.hubspot.com/livechat-public/v1/message/public",
"domains": [
- "pippintitle.com"
+ ""
+ ]
+ },
+ {
+ "rule": "js.hubspot.com/web-interactives-embed.js",
+ "domains": [
+ ""
]
},
{
@@ -6027,6 +6142,16 @@
}
]
},
+ "inmobi.com": {
+ "rules": [
+ {
+ "rule": "cmp.inmobi.com",
+ "domains": [
+ "express.co.uk"
+ ]
+ }
+ ]
+ },
"inq.com": {
"rules": [
{
@@ -6152,7 +6277,9 @@
"rule": "www.klaviyo.com/media/js/public/klaviyo_subscribe.js",
"domains": [
"fearofgod.com",
- "shopyalehome.com"
+ "restrap.com",
+ "shopyalehome.com",
+ "silhouetteu.com"
]
},
{
@@ -6282,6 +6409,26 @@
}
]
},
+ "media.net": {
+ "rules": [
+ {
+ "rule": "contextual.media.net/dmedianet.js",
+ "domains": [
+ "oceanofcompressed.xyz"
+ ]
+ }
+ ]
+ },
+ "mediavine.com": {
+ "rules": [
+ {
+ "rule": "scripts.mediavine.com/tags/cosmic-book-news.js",
+ "domains": [
+ "cosmicbook.news"
+ ]
+ }
+ ]
+ },
"medicare.gov": {
"rules": [
{
@@ -6424,6 +6571,16 @@
}
]
},
+ "onesignal.com": {
+ "rules": [
+ {
+ "rule": "cdn.onesignal.com/sdks/OneSignalSDK.js",
+ "domains": [
+ "cosmicbook.news"
+ ]
+ }
+ ]
+ },
"onlyfans.com": {
"rules": [
{
@@ -6679,17 +6836,6 @@
}
]
},
- "protection-widget.route.com": {
- "rules": [
- {
- "rule": "protection-widget.route.com/protect.core.js",
- "domains": [
- "littleunicorn.com",
- "olfactif.com"
- ]
- }
- ]
- },
"pubmatic.com": {
"rules": [
{
@@ -6731,7 +6877,8 @@
{
"rule": "secure.quantserve.com/quant.js",
"domains": [
- "aternos.org"
+ "aternos.org",
+ "oceanofcompressed.xyz"
]
}
]
@@ -6787,7 +6934,7 @@
{
"rule": "protection-widget.route.com/protect.core.js",
"domains": [
- "littleunicorn.com"
+ ""
]
}
]
@@ -6994,6 +7141,16 @@
}
]
},
+ "tfaforms.net": {
+ "rules": [
+ {
+ "rule": "tfaforms.net",
+ "domains": [
+ ""
+ ]
+ }
+ ]
+ },
"theplatform.com": {
"rules": [
{
@@ -7062,7 +7219,14 @@
"rule": "widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js",
"domains": [
"azurestandard.com",
- "domesticandgeneral.com"
+ "domesticandgeneral.com",
+ "www.hotpoint.co.uk"
+ ]
+ },
+ {
+ "rule": "widget.trustpilot.com/bootstrap/v5/tp.widget.sync.bootstrap.min.js",
+ "domains": [
+ "www.hotpoint.co.uk"
]
}
]
@@ -7171,6 +7335,16 @@
}
]
},
+ "visualwebsiteoptimizer.com": {
+ "rules": [
+ {
+ "rule": "dev.visualwebsiteoptimizer.com/j.php",
+ "domains": [
+ "searchhudforeclosures.com"
+ ]
+ }
+ ]
+ },
"voxmedia.com": {
"rules": [
{
@@ -7181,6 +7355,16 @@
}
]
},
+ "wovn.io": {
+ "rules": [
+ {
+ "rule": "j.wovn.io/1",
+ "domains": [
+ "tamashiiweb.com"
+ ]
+ }
+ ]
+ },
"wpadmngr.com": {
"rules": [
{
@@ -7379,7 +7563,7 @@
"domain": "sundancecatalog.com"
}
],
- "hash": "1ce506662b48fccc1bf37a3133fd3f1e"
+ "hash": "c1968268cb8a82bf532443edd17d9499"
},
"trackingCookies1p": {
"settings": {
diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj
index dd10712054..ee67435747 100644
--- a/DuckDuckGo.xcodeproj/project.pbxproj
+++ b/DuckDuckGo.xcodeproj/project.pbxproj
@@ -246,6 +246,7 @@
31DD208427395A5A008FB313 /* VoiceSearchHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DD208327395A5A008FB313 /* VoiceSearchHelper.swift */; };
31E69A63280F4CB600478327 /* DuckUI in Frameworks */ = {isa = PBXBuildFile; productRef = 31E69A62280F4CB600478327 /* DuckUI */; };
31EF52E1281B3BDC0034796E /* AutofillLoginListItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31EF52E0281B3BDC0034796E /* AutofillLoginListItemViewModel.swift */; };
+ 372A0FF02B2389590033BF7F /* SyncMetricsEventsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372A0FEF2B2389590033BF7F /* SyncMetricsEventsHandler.swift */; };
373608902ABB1E6C00629E7F /* FavoritesDisplayModeStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3736088F2ABB1E6C00629E7F /* FavoritesDisplayModeStorage.swift */; };
373608922ABB430D00629E7F /* FavoritesDisplayMode+UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373608912ABB430D00629E7F /* FavoritesDisplayMode+UserDefaults.swift */; };
373608932ABB432600629E7F /* FavoritesDisplayMode+UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373608912ABB430D00629E7F /* FavoritesDisplayMode+UserDefaults.swift */; };
@@ -693,6 +694,7 @@
B6BA95C528894A28004ABA20 /* BrowsingMenuViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B6BA95C428894A28004ABA20 /* BrowsingMenuViewController.storyboard */; };
B6BA95E828924730004ABA20 /* JSAlertController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B6BA95E728924730004ABA20 /* JSAlertController.storyboard */; };
B6CB93E5286445AB0090FEB4 /* Base64DownloadSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CB93E4286445AB0090FEB4 /* Base64DownloadSession.swift */; };
+ BDC234F72B27F51100D3C798 /* UniquePixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDC234F62B27F51100D3C798 /* UniquePixel.swift */; };
C10CB5F32A1A5BDF0048E503 /* AutofillViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10CB5F22A1A5BDF0048E503 /* AutofillViews.swift */; };
C111B26927F579EF006558B1 /* BookmarkOrFolderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C111B26827F579EF006558B1 /* BookmarkOrFolderTests.swift */; };
C12726EE2A5FF88C00215B02 /* EmailSignupPromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12726ED2A5FF88C00215B02 /* EmailSignupPromptView.swift */; };
@@ -1287,6 +1289,7 @@
31CC224828369B38001654A4 /* AutofillLoginSettingsListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginSettingsListViewController.swift; sourceTree = ""; };
31DD208327395A5A008FB313 /* VoiceSearchHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceSearchHelper.swift; sourceTree = ""; };
31EF52E0281B3BDC0034796E /* AutofillLoginListItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginListItemViewModel.swift; sourceTree = ""; };
+ 372A0FEF2B2389590033BF7F /* SyncMetricsEventsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncMetricsEventsHandler.swift; sourceTree = ""; };
3736088F2ABB1E6C00629E7F /* FavoritesDisplayModeStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesDisplayModeStorage.swift; sourceTree = ""; };
373608912ABB430D00629E7F /* FavoritesDisplayMode+UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FavoritesDisplayMode+UserDefaults.swift"; sourceTree = ""; };
37445F962A155F7C0029F789 /* SyncDataProviders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncDataProviders.swift; sourceTree = ""; };
@@ -2274,6 +2277,7 @@
B6BA95C428894A28004ABA20 /* BrowsingMenuViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = BrowsingMenuViewController.storyboard; sourceTree = ""; };
B6BA95E728924730004ABA20 /* JSAlertController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = JSAlertController.storyboard; sourceTree = ""; };
B6CB93E4286445AB0090FEB4 /* Base64DownloadSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Base64DownloadSession.swift; sourceTree = ""; };
+ BDC234F62B27F51100D3C798 /* UniquePixel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniquePixel.swift; sourceTree = ""; };
C10CB5F22A1A5BDF0048E503 /* AutofillViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillViews.swift; sourceTree = ""; };
C111B26827F579EF006558B1 /* BookmarkOrFolderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkOrFolderTests.swift; sourceTree = ""; };
C12726ED2A5FF88C00215B02 /* EmailSignupPromptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailSignupPromptView.swift; sourceTree = ""; };
@@ -3368,6 +3372,7 @@
37445F962A155F7C0029F789 /* SyncDataProviders.swift */,
37FD780E2A29E28B00B36DB1 /* SyncErrorHandler.swift */,
37CEFCAB2A673B90001EF741 /* CredentialsCleanupErrorHandling.swift */,
+ 372A0FEF2B2389590033BF7F /* SyncMetricsEventsHandler.swift */,
);
name = Sync;
sourceTree = "";
@@ -4589,6 +4594,7 @@
F1134EAE1F40AB2300B73467 /* Parser */,
F1134EA91F3E2BA700B73467 /* Store */,
CB2A7EF028410DF700885F67 /* PixelEvent.swift */,
+ BDC234F62B27F51100D3C798 /* UniquePixel.swift */,
853A717520F62FE800FE60BC /* Pixel.swift */,
1E05D1D729C46EDA00BF9A1F /* TimedPixel.swift */,
1E05D1D529C46EBB00BF9A1F /* DailyPixel.swift */,
@@ -5368,6 +5374,7 @@
buildRules = (
);
dependencies = (
+ B6080BB52B20B03800B418EF /* PBXTargetDependency */,
4B470EE7299C6DFB0086EBDC /* PBXTargetDependency */,
);
name = PacketTunnelProvider;
@@ -5389,6 +5396,7 @@
buildRules = (
);
dependencies = (
+ B6080BBD2B20B05000B418EF /* PBXTargetDependency */,
025CCFE82582601C001CD5BB /* PBXTargetDependency */,
);
name = FingerprintingUITests;
@@ -5408,6 +5416,7 @@
buildRules = (
);
dependencies = (
+ B6080BAF2B20B02800B418EF /* PBXTargetDependency */,
);
name = ShareExtension;
productName = ShareExtension;
@@ -5434,6 +5443,7 @@
buildRules = (
);
dependencies = (
+ B6080BAD2B20B02400B418EF /* PBXTargetDependency */,
F143C2EA1E4A4CD400CFDE3A /* PBXTargetDependency */,
8390447520BDCE10006461CD /* PBXTargetDependency */,
85482D932462DCD100EDEDD1 /* PBXTargetDependency */,
@@ -5466,6 +5476,7 @@
buildRules = (
);
dependencies = (
+ B6080BBB2B20B04D00B418EF /* PBXTargetDependency */,
84E341A81E2F7EFB00BDBA6F /* PBXTargetDependency */,
);
name = UnitTests;
@@ -5489,6 +5500,7 @@
buildRules = (
);
dependencies = (
+ B6080BB32B20B03400B418EF /* PBXTargetDependency */,
85DF714924F7FE6100C89288 /* PBXTargetDependency */,
);
name = WidgetsExtension;
@@ -5510,6 +5522,7 @@
buildRules = (
);
dependencies = (
+ B6080BB12B20B02B00B418EF /* PBXTargetDependency */,
);
name = OpenAction;
productName = OpenAction;
@@ -5527,6 +5540,7 @@
buildRules = (
);
dependencies = (
+ B6080BBF2B20B05300B418EF /* PBXTargetDependency */,
85D33FD125C97B6E002B91A6 /* PBXTargetDependency */,
);
name = IntegrationTests;
@@ -5549,6 +5563,7 @@
buildRules = (
);
dependencies = (
+ B6080BB92B20B04A00B418EF /* PBXTargetDependency */,
85F21DB3210F5E32002631A6 /* PBXTargetDependency */,
);
name = AtbUITests;
@@ -5570,6 +5585,7 @@
buildRules = (
);
dependencies = (
+ B6080BC12B20B05600B418EF /* PBXTargetDependency */,
9825F9CC293F2DE900F220F2 /* PBXTargetDependency */,
);
name = PerformanceTests;
@@ -5606,6 +5622,7 @@
buildRules = (
);
dependencies = (
+ B6080BB72B20B03B00B418EF /* PBXTargetDependency */,
);
name = Core;
packageProductDependencies = (
@@ -6122,7 +6139,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "# Conditionally embeds PacketTunnelProvider extension for Debug and Alpha builds.\n\n# Conditionally embeds the PacketTunnelProvider extension for debug builds.\\n# To be moved to the Embed App Extensions phase on release.\n\nif [ \"${CONFIGURATION}\" = \"Debug\" ] || [ \"${CONFIGURATION}\" = \"Alpha\" ]; then\n# Copy the extension \n rsync -r --copy-links \"${CONFIGURATION_BUILD_DIR}/PacketTunnelProvider.appex\" \"${CONFIGURATION_BUILD_DIR}/${PLUGINS_FOLDER_PATH}\"\nfi\n";
+ shellScript = "# Conditionally embeds PacketTunnelProvider extension for Debug and Alpha builds.\n\n# Conditionally embeds the PacketTunnelProvider extension for debug builds.\\n# To be moved to the Embed App Extensions phase on release.\n\nif [ \"${CONFIGURATION}\" = \"Debug\" ] || [ \"${CONFIGURATION}\" = \"Release\" ] || [ \"${CONFIGURATION}\" = \"Alpha\" ]; then\n# Copy the extension \n rsync -r --copy-links \"${CONFIGURATION_BUILD_DIR}/PacketTunnelProvider.appex\" \"${CONFIGURATION_BUILD_DIR}/${PLUGINS_FOLDER_PATH}\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */
@@ -6872,6 +6889,7 @@
37445F972A155F7C0029F789 /* SyncDataProviders.swift in Sources */,
EE9D68DE2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift in Sources */,
CB258D1F29A52B2500DEBA24 /* Configuration.swift in Sources */,
+ BDC234F72B27F51100D3C798 /* UniquePixel.swift in Sources */,
9847C00027A2DDBB00DB07AA /* AppPrivacyConfigurationDataProvider.swift in Sources */,
F143C3281E4A9A0E00CFDE3A /* StringExtension.swift in Sources */,
85449EFB23FDA0BC00512AAF /* UserDefaultsPropertyWrapper.swift in Sources */,
@@ -6896,6 +6914,7 @@
85D2187B24BF9F85004373D2 /* FaviconUserScript.swift in Sources */,
37FD780F2A29E28B00B36DB1 /* SyncErrorHandler.swift in Sources */,
85F21DC621145DD5002631A6 /* global.swift in Sources */,
+ 372A0FF02B2389590033BF7F /* SyncMetricsEventsHandler.swift in Sources */,
F41C2DA326C1925700F9A760 /* BookmarksAndFolders.xcdatamodeld in Sources */,
F4F6DFBA26EFF28A00ED7E12 /* BookmarkObjects.swift in Sources */,
EE7A92872AC6DE4700832A36 /* NetworkProtectionNotificationIdentifier.swift in Sources */,
@@ -6988,6 +7007,50 @@
target = 84E341911E2F7EFB00BDBA6F /* DuckDuckGo */;
targetProxy = 9825F9CD293F2DE900F220F2 /* PBXContainerItemProxy */;
};
+ B6080BAD2B20B02400B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BAC2B20B02400B418EF /* SwiftLintPlugin */;
+ };
+ B6080BAF2B20B02800B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BAE2B20B02800B418EF /* SwiftLintPlugin */;
+ };
+ B6080BB12B20B02B00B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BB02B20B02B00B418EF /* SwiftLintPlugin */;
+ };
+ B6080BB32B20B03400B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BB22B20B03400B418EF /* SwiftLintPlugin */;
+ };
+ B6080BB52B20B03800B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BB42B20B03800B418EF /* SwiftLintPlugin */;
+ };
+ B6080BB72B20B03B00B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BB62B20B03B00B418EF /* SwiftLintPlugin */;
+ };
+ B6080BB92B20B04A00B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BB82B20B04A00B418EF /* SwiftLintPlugin */;
+ };
+ B6080BBB2B20B04D00B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BBA2B20B04D00B418EF /* SwiftLintPlugin */;
+ };
+ B6080BBD2B20B05000B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BBC2B20B05000B418EF /* SwiftLintPlugin */;
+ };
+ B6080BBF2B20B05300B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BBE2B20B05300B418EF /* SwiftLintPlugin */;
+ };
+ B6080BC12B20B05600B418EF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ productRef = B6080BC02B20B05600B418EF /* SwiftLintPlugin */;
+ };
F143C2EA1E4A4CD400CFDE3A /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F143C2E31E4A4CD400CFDE3A /* Core */;
@@ -8104,6 +8167,7 @@
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "-ld_classic";
SDKROOT = iphoneos;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = NETWORK_PROTECTION;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
@@ -9160,7 +9224,7 @@
repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit";
requirement = {
kind = exactVersion;
- version = 92.0.1;
+ version = 97.0.0;
};
};
C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = {
@@ -9311,6 +9375,61 @@
package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
productName = Bookmarks;
};
+ B6080BAC2B20B02400B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
+ B6080BAE2B20B02800B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
+ B6080BB02B20B02B00B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
+ B6080BB22B20B03400B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
+ B6080BB42B20B03800B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
+ B6080BB62B20B03B00B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
+ B6080BB82B20B04A00B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
+ B6080BBA2B20B04D00B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
+ B6080BBC2B20B05000B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
+ B6080BBE2B20B05300B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
+ B6080BC02B20B05600B418EF /* SwiftLintPlugin */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
+ productName = "plugin:SwiftLintPlugin";
+ };
C14882EC27F211A000D59F0C /* SwiftSoup */ = {
isa = XCSwiftPackageProductDependency;
package = C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */;
diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 1e39e0adb6..5eb1e13d46 100644
--- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,178 +1,176 @@
{
- "object": {
- "pins": [
- {
- "package": "BloomFilter",
- "repositoryURL": "https://github.com/duckduckgo/bloom_cpp.git",
- "state": {
- "branch": null,
- "revision": "8076199456290b61b4544bf2f4caf296759906a0",
- "version": "3.0.0"
- }
- },
- {
- "package": "BrowserServicesKit",
- "repositoryURL": "https://github.com/DuckDuckGo/BrowserServicesKit",
- "state": {
- "branch": null,
- "revision": "fe577c508ad4ea163075ac8fab20673d0a7565f6",
- "version": "92.0.1"
- }
- },
- {
- "package": "CocoaAsyncSocket",
- "repositoryURL": "https://github.com/robbiehanson/CocoaAsyncSocket",
- "state": {
- "branch": null,
- "revision": "dbdc00669c1ced63b27c3c5f052ee4d28f10150c",
- "version": "7.6.5"
- }
- },
- {
- "package": "ContentScopeScripts",
- "repositoryURL": "https://github.com/duckduckgo/content-scope-scripts",
- "state": {
- "branch": null,
- "revision": "b7ad9843e70cede0c2ca9c4260d970f62cb28156",
- "version": "4.52.0"
- }
- },
- {
- "package": "DesignResourcesKit",
- "repositoryURL": "https://github.com/duckduckgo/DesignResourcesKit",
- "state": {
- "branch": null,
- "revision": "d7ea2561ec7624c224f52e1c9b349075ddf1c782",
- "version": "2.0.0"
- }
- },
- {
- "package": "Autofill",
- "repositoryURL": "https://github.com/duckduckgo/duckduckgo-autofill.git",
- "state": {
- "branch": null,
- "revision": "93677cc02cfe650ce7f417246afd0e8e972cd83e",
- "version": "10.0.0"
- }
- },
- {
- "package": "GRDB",
- "repositoryURL": "https://github.com/duckduckgo/GRDB.swift.git",
- "state": {
- "branch": null,
- "revision": "77d9a83191a74e319a5cfa27b0e3145d15607573",
- "version": "2.2.0"
- }
- },
- {
- "package": "FindInPageIOSJSSupport",
- "repositoryURL": "https://github.com/duckduckgo/ios-js-support",
- "state": {
- "branch": null,
- "revision": "6a6789ac8104a587316c58af75539753853b50d9",
- "version": "2.0.0"
- }
- },
- {
- "package": "Kingfisher",
- "repositoryURL": "https://github.com/onevcat/Kingfisher.git",
- "state": {
- "branch": null,
- "revision": "af4be924ad984cf4d16f4ae4df424e79a443d435",
- "version": "7.6.2"
- }
- },
- {
- "package": "Lottie",
- "repositoryURL": "https://github.com/duckduckgo/lottie-ios.git",
- "state": {
- "branch": null,
- "revision": "abf5510e261c85ffddd29de0bca9b72592ea2bdd",
- "version": "3.3.0"
- }
- },
- {
- "package": "OHHTTPStubs",
- "repositoryURL": "https://github.com/AliSoftware/OHHTTPStubs.git",
- "state": {
- "branch": null,
- "revision": "12f19662426d0434d6c330c6974d53e2eb10ecd9",
- "version": "9.1.0"
- }
- },
- {
- "package": "PrivacyDashboardResources",
- "repositoryURL": "https://github.com/duckduckgo/privacy-dashboard",
- "state": {
- "branch": null,
- "revision": "38336a574e13090764ba09a6b877d15ee514e371",
- "version": "3.1.1"
- }
- },
- {
- "package": "Punycode",
- "repositoryURL": "https://github.com/gumob/PunycodeSwift.git",
- "state": {
- "branch": null,
- "revision": "4356ec54e073741449640d3d50a1fd24fd1e1b8b",
- "version": "2.1.0"
- }
- },
- {
- "package": "swift-argument-parser",
- "repositoryURL": "https://github.com/apple/swift-argument-parser",
- "state": {
- "branch": null,
- "revision": "8f4d2753f0e4778c76d5f05ad16c74f707390531",
- "version": "1.2.3"
- }
- },
- {
- "package": "Swifter",
- "repositoryURL": "https://github.com/httpswift/swifter.git",
- "state": {
- "branch": null,
- "revision": "9483a5d459b45c3ffd059f7b55f9638e268632fd",
- "version": "1.5.0"
- }
- },
- {
- "package": "SwiftSoup",
- "repositoryURL": "https://github.com/scinfu/SwiftSoup",
- "state": {
- "branch": null,
- "revision": "41e7c263fb8c277e980ebcb9b0b5f6031d3d4886",
- "version": "2.4.2"
- }
- },
- {
- "package": "DDGSyncCrypto",
- "repositoryURL": "https://github.com/duckduckgo/sync_crypto",
- "state": {
- "branch": null,
- "revision": "2ab6ab6f0f96b259c14c2de3fc948935fc16ac78",
- "version": "0.2.0"
- }
- },
- {
- "package": "TrackerRadarKit",
- "repositoryURL": "https://github.com/duckduckgo/TrackerRadarKit",
- "state": {
- "branch": null,
- "revision": "a6b7ba151d9dc6684484f3785293875ec01cc1ff",
- "version": "1.2.2"
- }
- },
- {
- "package": "WireGuardKit",
- "repositoryURL": "https://github.com/duckduckgo/wireguard-apple",
- "state": {
- "branch": null,
- "revision": "2d8172c11478ab11b0f5ad49bdb4f93f4b3d5e0d",
- "version": "1.1.1"
- }
- }
- ]
- },
- "version": 1
+ "pins" : [
+ {
+ "identity" : "bloom_cpp",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/bloom_cpp.git",
+ "state" : {
+ "revision" : "8076199456290b61b4544bf2f4caf296759906a0",
+ "version" : "3.0.0"
+ }
+ },
+ {
+ "identity" : "browserserviceskit",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/DuckDuckGo/BrowserServicesKit",
+ "state" : {
+ "revision" : "d671accf1bf7097c4e7f5cd55cd1c6dfa005cf92",
+ "version" : "97.0.0"
+ }
+ },
+ {
+ "identity" : "cocoaasyncsocket",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/robbiehanson/CocoaAsyncSocket",
+ "state" : {
+ "revision" : "dbdc00669c1ced63b27c3c5f052ee4d28f10150c",
+ "version" : "7.6.5"
+ }
+ },
+ {
+ "identity" : "content-scope-scripts",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/content-scope-scripts",
+ "state" : {
+ "revision" : "b7ad9843e70cede0c2ca9c4260d970f62cb28156",
+ "version" : "4.52.0"
+ }
+ },
+ {
+ "identity" : "designresourceskit",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/DesignResourcesKit",
+ "state" : {
+ "revision" : "d7ea2561ec7624c224f52e1c9b349075ddf1c782",
+ "version" : "2.0.0"
+ }
+ },
+ {
+ "identity" : "duckduckgo-autofill",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/duckduckgo-autofill.git",
+ "state" : {
+ "revision" : "5597bc17709c8acf454ecaad4f4082007986242a",
+ "version" : "10.0.2"
+ }
+ },
+ {
+ "identity" : "grdb.swift",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/GRDB.swift.git",
+ "state" : {
+ "revision" : "77d9a83191a74e319a5cfa27b0e3145d15607573",
+ "version" : "2.2.0"
+ }
+ },
+ {
+ "identity" : "ios-js-support",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/ios-js-support",
+ "state" : {
+ "revision" : "6a6789ac8104a587316c58af75539753853b50d9",
+ "version" : "2.0.0"
+ }
+ },
+ {
+ "identity" : "kingfisher",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/onevcat/Kingfisher.git",
+ "state" : {
+ "revision" : "af4be924ad984cf4d16f4ae4df424e79a443d435",
+ "version" : "7.6.2"
+ }
+ },
+ {
+ "identity" : "lottie-ios",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/lottie-ios.git",
+ "state" : {
+ "revision" : "abf5510e261c85ffddd29de0bca9b72592ea2bdd",
+ "version" : "3.3.0"
+ }
+ },
+ {
+ "identity" : "ohhttpstubs",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/AliSoftware/OHHTTPStubs.git",
+ "state" : {
+ "revision" : "12f19662426d0434d6c330c6974d53e2eb10ecd9",
+ "version" : "9.1.0"
+ }
+ },
+ {
+ "identity" : "privacy-dashboard",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/privacy-dashboard",
+ "state" : {
+ "revision" : "38336a574e13090764ba09a6b877d15ee514e371",
+ "version" : "3.1.1"
+ }
+ },
+ {
+ "identity" : "punycodeswift",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/gumob/PunycodeSwift.git",
+ "state" : {
+ "revision" : "4356ec54e073741449640d3d50a1fd24fd1e1b8b",
+ "version" : "2.1.0"
+ }
+ },
+ {
+ "identity" : "swift-argument-parser",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-argument-parser",
+ "state" : {
+ "revision" : "c8ed701b513cf5177118a175d85fbbbcd707ab41",
+ "version" : "1.3.0"
+ }
+ },
+ {
+ "identity" : "swifter",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/httpswift/swifter.git",
+ "state" : {
+ "revision" : "9483a5d459b45c3ffd059f7b55f9638e268632fd",
+ "version" : "1.5.0"
+ }
+ },
+ {
+ "identity" : "swiftsoup",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/scinfu/SwiftSoup",
+ "state" : {
+ "revision" : "41e7c263fb8c277e980ebcb9b0b5f6031d3d4886",
+ "version" : "2.4.2"
+ }
+ },
+ {
+ "identity" : "sync_crypto",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/sync_crypto",
+ "state" : {
+ "revision" : "2ab6ab6f0f96b259c14c2de3fc948935fc16ac78",
+ "version" : "0.2.0"
+ }
+ },
+ {
+ "identity" : "trackerradarkit",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/TrackerRadarKit",
+ "state" : {
+ "revision" : "a6b7ba151d9dc6684484f3785293875ec01cc1ff",
+ "version" : "1.2.2"
+ }
+ },
+ {
+ "identity" : "wireguard-apple",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/duckduckgo/wireguard-apple",
+ "state" : {
+ "revision" : "2d8172c11478ab11b0f5ad49bdb4f93f4b3d5e0d",
+ "version" : "1.1.1"
+ }
+ }
+ ],
+ "version" : 2
}
diff --git a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo.xcscheme b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo.xcscheme
index e3730bb0c6..7c553f4089 100644
--- a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo.xcscheme
+++ b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo.xcscheme
@@ -95,8 +95,7 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
- allowLocationSimulation = "NO"
- showNonLocalizedStrings = "YES">
+ allowLocationSimulation = "NO">
Void in
+ task = AutocompleteRequest.session.dataTask(with: request) { [weak self] (data, _, error) in
guard let weakSelf = self else { return }
do {
let suggestions = try weakSelf.processResult(data: data, error: error)
diff --git a/DuckDuckGo/Base.lproj/Settings.storyboard b/DuckDuckGo/Base.lproj/Settings.storyboard
index e3d799493f..5f66405727 100644
--- a/DuckDuckGo/Base.lproj/Settings.storyboard
+++ b/DuckDuckGo/Base.lproj/Settings.storyboard
@@ -129,7 +129,7 @@
-