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 @@ -