diff --git a/.github/actions/install-certs-and-profiles/action.yml b/.github/actions/install-certs-and-profiles/action.yml index 466c511d2a..5ac06a2a0d 100644 --- a/.github/actions/install-certs-and-profiles/action.yml +++ b/.github/actions/install-certs-and-profiles/action.yml @@ -16,6 +16,12 @@ inputs: RELEASE_PROVISION_PROFILE_BASE64: required: true type: string + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: + required: true + type: string + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: + required: true + type: string NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64: required: true type: string @@ -55,6 +61,8 @@ runs: KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db REVIEW_PP_PATH=$RUNNER_TEMP/review_pp.provisionprofile RELEASE_PP_PATH=$RUNNER_TEMP/release_pp.provisionprofile + DBP_AGENT_RELEASE_PP_PATH=$RUNNER_TEMP/dbp_agent_release_pp.provisionprofile + DBP_AGENT_REVIEW_PP_PATH=$RUNNER_TEMP/dbp_agent_review_pp.provisionprofile NETP_SYSEX_RELEASE_PP_PATH=$RUNNER_TEMP/netp_sysex_release_pp.provisionprofile NETP_SYSEX_REVIEW_PP_PATH=$RUNNER_TEMP/netp_sysex_review_pp.provisionprofile NETP_AGENT_RELEASE_PP_PATH=$RUNNER_TEMP/netp_agent_release_pp.provisionprofile @@ -66,6 +74,8 @@ runs: echo -n "${{ inputs.BUILD_CERTIFICATE_BASE64 }}" | base64 --decode -o $CERTIFICATE_PATH echo -n "${{ inputs.REVIEW_PROVISION_PROFILE_BASE64 }}" | base64 --decode -o $REVIEW_PP_PATH echo -n "${{ inputs.RELEASE_PROVISION_PROFILE_BASE64 }}" | base64 --decode -o $RELEASE_PP_PATH + echo -n "${{ inputs.DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }}" | base64 --decode -o $DBP_AGENT_RELEASE_PP_PATH + echo -n "${{ inputs.DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64 }}" | base64 --decode -o $DBP_AGENT_REVIEW_PP_PATH echo -n "${{ inputs.NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64 }}" | base64 --decode -o $NETP_SYSEX_RELEASE_PP_PATH echo -n "${{ inputs.NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64 }}" | base64 --decode -o $NETP_SYSEX_REVIEW_PP_PATH echo -n "${{ inputs.NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }}" | base64 --decode -o $NETP_AGENT_RELEASE_PP_PATH @@ -86,6 +96,8 @@ runs: mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles cp $REVIEW_PP_PATH \ $RELEASE_PP_PATH \ + $DBP_AGENT_RELEASE_PP_PATH \ + $DBP_AGENT_REVIEW_PP_PATH \ $NETP_SYSEX_RELEASE_PP_PATH \ $NETP_SYSEX_REVIEW_PP_PATH \ $NETP_AGENT_RELEASE_PP_PATH \ diff --git a/.github/workflows/build_notarized.yml b/.github/workflows/build_notarized.yml index 5ddbc2388d..ab6f244032 100644 --- a/.github/workflows/build_notarized.yml +++ b/.github/workflows/build_notarized.yml @@ -49,6 +49,10 @@ on: required: true RELEASE_PROVISION_PROFILE_BASE64: required: true + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: + required: true + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: + required: true NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2: required: true NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2: @@ -115,6 +119,8 @@ jobs: KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.REVIEW_PROVISION_PROFILE_BASE64 }} RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64 }} NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2 }} NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2 }} NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2 }} diff --git a/.github/workflows/create_variants.yml b/.github/workflows/create_variants.yml index 758627690d..700bf6b2b4 100644 --- a/.github/workflows/create_variants.yml +++ b/.github/workflows/create_variants.yml @@ -70,6 +70,8 @@ jobs: KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.REVIEW_PROVISION_PROFILE_BASE64 }} RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64 }} NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2 }} NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2 }} NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2 }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 75e1cc8cd1..ca8a3a4038 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -236,6 +236,8 @@ jobs: KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.REVIEW_PROVISION_PROFILE_BASE64 }} RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64 }} NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2 }} NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2 }} NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2 }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 41b5fffa3c..b819a8745c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,6 +23,8 @@ jobs: KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.REVIEW_PROVISION_PROFILE_BASE64 }} RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64 }} NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2 }} NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2 }} NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2 }} diff --git a/Configuration/App/DBP/DuckDuckGoDBPAgent.xcconfig b/Configuration/App/DBP/DuckDuckGoDBPAgent.xcconfig new file mode 100644 index 0000000000..dde2b17232 --- /dev/null +++ b/Configuration/App/DBP/DuckDuckGoDBPAgent.xcconfig @@ -0,0 +1,65 @@ +// 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. +// + +#include "../AppTargetsBase.xcconfig" +#include "../../NetworkProtectionDeveloperID.xcconfig" + +// Override AppTargetsBase.xcconfig until we resolve bundle IDs. +PRODUCT_BUNDLE_IDENTIFIER[sdk=*] = $(DBP_AGENT_BUNDLE_ID) +PRODUCT_BUNDLE_IDENTIFIER[config=Debug][sdk=*] = $(DBP_AGENT_BUNDLE_ID) +PRODUCT_BUNDLE_IDENTIFIER[config=CI][sdk=*] = $(DBP_AGENT_BUNDLE_ID) +PRODUCT_BUNDLE_IDENTIFIER[config=Review][sdk=*] = $(DBP_AGENT_BUNDLE_ID) + +INFOPLIST_FILE = DuckDuckGoDBPBackgroundAgent/Info.plist +GENERATE_INFOPLIST_FILE = YES +INFOPLIST_KEY_LSUIElement = YES +INFOPLIST_KEY_NSPrincipalClass = Application + +// Just make sure to override anything set by the AppTargetBase.xcconfig +//CODE_SIGN_STYLE[config=Debug][sdk=*] = Manual +//CODE_SIGN_STYLE[config=Release][sdk=*] = Manual + +CODE_SIGN_ENTITLEMENTS[config=Review][sdk=macosx*] = DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements +CODE_SIGN_ENTITLEMENTS[config=CI][sdk=macosx*] = DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements +CODE_SIGN_ENTITLEMENTS[config=Debug][sdk=macosx*] = DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements +CODE_SIGN_ENTITLEMENTS[config=Release][sdk=macosx*] = DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements + +CODE_SIGN_IDENTITY[sdk=macosx*] = Developer ID Application +CODE_SIGN_IDENTITY[config=Debug][sdk=macosx*] = Apple Development +CODE_SIGN_IDENTITY[config=CI][sdk=macosx*] = + +PRODUCT_NAME = $(DBP_AGENT_PRODUCT_NAME) + +PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = +PROVISIONING_PROFILE_SPECIFIER[config=Review][sdk=macosx*] = macOS DBP Agent - Review +PROVISIONING_PROFILE_SPECIFIER[config=Release][sdk=macosx*] = macOS DBP Agent - Release + +FEATURE_FLAGS = FEEDBACK DBP NETWORK_PROTECTION + +GCC_PREPROCESSOR_DEFINITIONS[arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 +GCC_PREPROCESSOR_DEFINITIONS[config=CI][arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 DEBUG=1 CI=1 $(inherited) +GCC_PREPROCESSOR_DEFINITIONS[config=Debug][arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 DEBUG=1 $(inherited) +GCC_PREPROCESSOR_DEFINITIONS[config=Review][arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 REVIEW=1 $(inherited) + +SWIFT_ACTIVE_COMPILATION_CONDITIONS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION $(FEATURE_FLAGS) +SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION DEBUG CI $(FEATURE_FLAGS) +SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION DEBUG $(FEATURE_FLAGS) +SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION REVIEW $(FEATURE_FLAGS) + +SWIFT_OBJC_BRIDGING_HEADER = +SKIP_INSTALL = YES +ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = + +#include? "../../../LocalOverrides.xcconfig" diff --git a/Configuration/App/DBP/DuckDuckGoDBPAgentAppStore.xcconfig b/Configuration/App/DBP/DuckDuckGoDBPAgentAppStore.xcconfig new file mode 100644 index 0000000000..a953696765 --- /dev/null +++ b/Configuration/App/DBP/DuckDuckGoDBPAgentAppStore.xcconfig @@ -0,0 +1,65 @@ +// 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. +// + +#include "../AppTargetsBase.xcconfig" +#include "../../AppStore.xcconfig" + +// Override AppTargetsBase.xcconfig until we resolve bundle IDs. +PRODUCT_BUNDLE_IDENTIFIER[sdk=*] = $(DBP_AGENT_BUNDLE_ID) +PRODUCT_BUNDLE_IDENTIFIER[config=Debug][sdk=*] = $(DBP_AGENT_BUNDLE_ID) +PRODUCT_BUNDLE_IDENTIFIER[config=CI][sdk=*] = $(DBP_AGENT_BUNDLE_ID) +PRODUCT_BUNDLE_IDENTIFIER[config=Review][sdk=*] = $(DBP_AGENT_BUNDLE_ID) + +INFOPLIST_FILE = DuckDuckGoDBPBackgroundAgent/Info.plist +GENERATE_INFOPLIST_FILE = YES +INFOPLIST_KEY_LSUIElement = YES +INFOPLIST_KEY_NSPrincipalClass = Application + +// Just make sure to override anything set by the AppTargetBase.xcconfig +//CODE_SIGN_STYLE[config=Debug][sdk=*] = Manual +//CODE_SIGN_STYLE[config=Release][sdk=*] = Manual + +CODE_SIGN_ENTITLEMENTS[config=Review][sdk=macosx*] = DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements +CODE_SIGN_ENTITLEMENTS[config=CI][sdk=macosx*] = DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements +CODE_SIGN_ENTITLEMENTS[config=Debug][sdk=macosx*] = DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements +CODE_SIGN_ENTITLEMENTS[config=Release][sdk=macosx*] = DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements + +CODE_SIGN_IDENTITY[sdk=macosx*] = Developer ID Application +CODE_SIGN_IDENTITY[config=Debug][sdk=macosx*] = Apple Development +CODE_SIGN_IDENTITY[config=CI][sdk=macosx*] = + +PRODUCT_NAME = $(DBP_AGENT_PRODUCT_NAME) + +PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = +PROVISIONING_PROFILE_SPECIFIER[config=Review][sdk=macosx*] = macOS DBP Agent - Review +PROVISIONING_PROFILE_SPECIFIER[config=Release][sdk=macosx*] = macOS DBP Agent - Release + +FEATURE_FLAGS = FEEDBACK DBP NETWORK_PROTECTION + +GCC_PREPROCESSOR_DEFINITIONS[arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 +GCC_PREPROCESSOR_DEFINITIONS[config=CI][arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 DEBUG=1 CI=1 $(inherited) +GCC_PREPROCESSOR_DEFINITIONS[config=Debug][arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 DEBUG=1 $(inherited) +GCC_PREPROCESSOR_DEFINITIONS[config=Review][arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 REVIEW=1 $(inherited) + +SWIFT_ACTIVE_COMPILATION_CONDITIONS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION $(FEATURE_FLAGS) +SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION DEBUG CI $(FEATURE_FLAGS) +SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION DEBUG $(FEATURE_FLAGS) +SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION REVIEW $(FEATURE_FLAGS) + +SWIFT_OBJC_BRIDGING_HEADER = +SKIP_INSTALL = YES +ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = + +#include? "../../../LocalOverrides.xcconfig" diff --git a/Configuration/App/DuckDuckGoDBP.xcconfig b/Configuration/App/DuckDuckGoDBP.xcconfig index 3d324a49a7..45484fdfc5 100644 --- a/Configuration/App/DuckDuckGoDBP.xcconfig +++ b/Configuration/App/DuckDuckGoDBP.xcconfig @@ -27,6 +27,13 @@ FEATURE_FLAGS = FEEDBACK DBP NETWORK_PROTECTION PRODUCT_BUNDLE_IDENTIFIER = $(MAIN_BUNDLE_IDENTIFIER) +DBP_BACKGROUND_AGENT_BUNDLE_ID[sdk=*] = com.duckduckgo.macos.DBP.backgroundAgent +DBP_BACKGROUND_AGENT_BUNDLE_ID[config=Debug][sdk=*] = com.duckduckgo.macos.DBP.backgroundAgent.debug +DBP_BACKGROUND_AGENT_BUNDLE_ID[config=CI][sdk=*] = com.duckduckgo.macos.DBP.backgroundAgent.debug +DBP_BACKGROUND_AGENT_BUNDLE_ID[config=Review][sdk=*] = com.duckduckgo.macos.DBP.backgroundAgent.review + +DBP_BACKGROUND_AGENT_PRODUCT_NAME = DuckDuckGoDBPBackgroundAgent + PRODUCT_NAME_PREFIX = DuckDuckGoDBP CODE_SIGN_STYLE[sdk=*] = Automatic diff --git a/Configuration/NetworkProtectionDeveloperID.xcconfig b/Configuration/NetworkProtectionDeveloperID.xcconfig index f236ca2992..5c52341718 100644 --- a/Configuration/NetworkProtectionDeveloperID.xcconfig +++ b/Configuration/NetworkProtectionDeveloperID.xcconfig @@ -33,6 +33,7 @@ SYSEX_BUNDLE_ID[config=Review][sdk=*] = $(SYSEX_BUNDLE_ID_BASE).review SYSEX_BUNDLE_ID[config=Release][sdk=*] = $(SYSEX_BUNDLE_ID_BASE) DISTRIBUTED_NOTIFICATIONS_PREFIX_BASE = $(SYSEX_BUNDLE_ID_BASE) + DISTRIBUTED_NOTIFICATIONS_PREFIX[config=CI][sdk=*] = $(DISTRIBUTED_NOTIFICATIONS_PREFIX_BASE).ci DISTRIBUTED_NOTIFICATIONS_PREFIX[config=Review][sdk=*] = $(DISTRIBUTED_NOTIFICATIONS_PREFIX_BASE).review DISTRIBUTED_NOTIFICATIONS_PREFIX[config=Debug][sdk=*] = $(DISTRIBUTED_NOTIFICATIONS_PREFIX_BASE).debug @@ -54,13 +55,18 @@ NOTIFICATIONS_AGENT_BUNDLE_ID[sdk=*] = $(DEVELOPMENT_TEAM).com.duckduckgo.macos. NOTIFICATIONS_AGENT_BUNDLE_ID[config=Debug][sdk=*] = $(DEVELOPMENT_TEAM).com.duckduckgo.macos.browser.network-protection.notifications.debug NOTIFICATIONS_AGENT_BUNDLE_ID[config=CI][sdk=*] = $(DEVELOPMENT_TEAM).com.duckduckgo.macos.browser.network-protection.notifications.debug NOTIFICATIONS_AGENT_BUNDLE_ID[config=Review][sdk=*] = $(DEVELOPMENT_TEAM).com.duckduckgo.macos.browser.network-protection.notifications.review +NOTIFICATIONS_AGENT_PRODUCT_NAME = DuckDuckGo Notifications AGENT_BUNDLE_ID_BASE[sdk=*] = com.duckduckgo.macos.vpn +DBP_AGENT_BUNDLE_ID[sdk=*] = com.duckduckgo.macos.DBP.backgroundAgent +DBP_AGENT_BUNDLE_ID[config=Debug][sdk=*] = com.duckduckgo.macos.DBP.backgroundAgent.debug +DBP_AGENT_BUNDLE_ID[config=CI][sdk=*] = com.duckduckgo.macos.DBP.backgroundAgent.debug +DBP_AGENT_BUNDLE_ID[config=Review][sdk=*] = com.duckduckgo.macos.DBP.backgroundAgent.review +DBP_AGENT_PRODUCT_NAME = DuckDuckGoDBPBackgroundAgent + AGENT_BUNDLE_ID[sdk=*] = $(AGENT_BUNDLE_ID_BASE) AGENT_BUNDLE_ID[config=Debug][sdk=*] = $(AGENT_BUNDLE_ID_BASE).debug AGENT_BUNDLE_ID[config=CI][sdk=*] = $(AGENT_BUNDLE_ID_BASE).debug AGENT_BUNDLE_ID[config=Review][sdk=*] = $(AGENT_BUNDLE_ID_BASE).review - AGENT_PRODUCT_NAME = DuckDuckGo VPN -NOTIFICATIONS_AGENT_PRODUCT_NAME = DuckDuckGo Notifications diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 73f8e63823..064a98607e 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -2817,7 +2817,6 @@ 4BF0E50A2AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */; }; 4BF0E50B2AD2552200FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */; }; 4BF0E50C2AD2552300FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */; }; - 4BF0E50E2AD2555D00FFEC9E /* (null) in Frameworks */ = {isa = PBXBuildFile; }; 4BF0E5122AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5112AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift */; }; 4BF0E5132AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5112AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift */; }; 4BF0E5142AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5112AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift */; }; @@ -2868,8 +2867,6 @@ 7B2DDCFA2A93B25F0039D884 /* KeychainType+ClientDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */; }; 7B2DDCFB2A93B25F0039D884 /* KeychainType+ClientDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */; }; 7B2E52252A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2E52242A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift */; }; - 7B31FD882AD124620086AA24 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; - 7B31FD8A2AD124680086AA24 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; 7B31FD8C2AD125620086AA24 /* NetworkProtectionIPC in Frameworks */ = {isa = PBXBuildFile; productRef = 7B31FD8B2AD125620086AA24 /* NetworkProtectionIPC */; }; 7B31FD8E2AD125760086AA24 /* NetworkProtectionIPC in Frameworks */ = {isa = PBXBuildFile; productRef = 7B31FD8D2AD125760086AA24 /* NetworkProtectionIPC */; }; 7B31FD902AD1257B0086AA24 /* NetworkProtectionIPC in Frameworks */ = {isa = PBXBuildFile; productRef = 7B31FD8F2AD1257B0086AA24 /* NetworkProtectionIPC */; }; @@ -2879,7 +2876,11 @@ 7B430EA12A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */; }; 7B430EA22A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */; }; 7B4CE8E726F02135009134B1 /* TabBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4CE8E626F02134009134B1 /* TabBarTests.swift */; }; + 7B5DD69A2AE51FFA001DE99C /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B5DD6992AE51FFA001DE99C /* PixelKit */; }; 7B5F9A752AE2BE4E002AEBC0 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B5F9A742AE2BE4E002AEBC0 /* PixelKit */; }; + 7B6D98672ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift */; }; + 7B74F2482ADEB03900147283 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B74F2472ADEB03900147283 /* PixelKit */; }; + 7B8C083C2AE1268E00F4C67F /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B8C083B2AE1268E00F4C67F /* PixelKit */; }; 7B934C412A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B934C402A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift */; }; 7B96D0DC2ADFDB8E007E02C8 /* DataBrokerProtectionPixelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B96D0DB2ADFDB8E007E02C8 /* DataBrokerProtectionPixelTests.swift */; }; 7BA4727D26F01BC400EAA165 /* CoreDataTestUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292C42667104B00AD2C21 /* CoreDataTestUtilities.swift */; }; @@ -2920,9 +2921,12 @@ 7BAF9E4C2A8A3CCA002D3B6E /* UserDefaults+NetworkProtectionShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B934C402A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift */; }; 7BAF9E4D2A8A3CCB002D3B6E /* UserDefaults+NetworkProtectionShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B934C402A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift */; }; 7BB108592A43375D000AB95F /* PFMoveApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BB108582A43375D000AB95F /* PFMoveApplication.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 7BB369E92ACB39A500B4FFEB /* DuckDuckGoDBPBackgroundAgent.app in Embed Login Items */ = {isa = PBXBuildFile; fileRef = 9D9AE8D12AAA39A70026E7DC /* DuckDuckGoDBPBackgroundAgent.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 7BBD44282AD730A400D0A064 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7BBD44272AD730A400D0A064 /* PixelKit */; }; 7BBD45B12A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */; }; 7BBD45B22A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */; }; + 7BD01C152AD820310088B32E /* XPCHelper in Frameworks */ = {isa = PBXBuildFile; productRef = 7BD01C142AD820310088B32E /* XPCHelper */; }; + 7BD01C192AD8319C0088B32E /* IPCServiceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD01C182AD8319C0088B32E /* IPCServiceManager.swift */; }; 7BD1688E2AD4A4C400D24876 /* NetworkExtensionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD1688D2AD4A4C400D24876 /* NetworkExtensionController.swift */; }; 7BD3AF5D2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */; }; 7BE146072A6A83C700C313B8 /* NetworkProtectionDebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BE146062A6A83C700C313B8 /* NetworkProtectionDebugMenu.swift */; }; @@ -2933,7 +2937,6 @@ 7BEEA5162AD1236E00A9E72B /* NetworkProtectionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 7BEEA5152AD1236E00A9E72B /* NetworkProtectionUI */; }; 7BF1A9D82AE054D300FCA683 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7BF1A9D72AE054D300FCA683 /* Info.plist */; }; 7BF1A9DC2AE0551C00FCA683 /* DBPUnitTests.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 7BF1A9DB2AE0551C00FCA683 /* DBPUnitTests.xcconfig */; }; - 7BF7705F2AD6C999001C9182 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7BF7705E2AD6C999001C9182 /* PixelKit */; }; 7BFCB74E2ADE7E1A00DA3EA7 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7BFCB74D2ADE7E1A00DA3EA7 /* PixelKit */; }; 7BFCB7502ADE7E2300DA3EA7 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7BFCB74F2ADE7E2300DA3EA7 /* PixelKit */; }; 7BFE95522A9DF1CE0081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95512A9DF1CE0081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift */; }; @@ -3061,12 +3064,28 @@ 98A50964294B691800D10880 /* Persistence in Frameworks */ = {isa = PBXBuildFile; productRef = 98A50963294B691800D10880 /* Persistence */; }; 98A95D88299A2DF900B9B81A /* BookmarkMigrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A95D87299A2DF900B9B81A /* BookmarkMigrationTests.swift */; }; 98EB5D1027516A4800681FE6 /* AppPrivacyConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98EB5D0F27516A4800681FE6 /* AppPrivacyConfigurationTests.swift */; }; + 9D6983F92AC773C3002C02FC /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9D6983F82AC773C3002C02FC /* PixelKit */; }; + 9D6983FB2AC773C8002C02FC /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9D6983FA2AC773C8002C02FC /* PixelKit */; }; + 9D8FA00C2AC5BDCE005DD0D0 /* LoginItem+DataBrokerProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D8FA00B2AC5BDCE005DD0D0 /* LoginItem+DataBrokerProtection.swift */; }; 9D9AE8692AA76CDC0026E7DC /* LoginItem+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE8682AA76CDC0026E7DC /* LoginItem+NetworkProtection.swift */; }; 9D9AE86B2AA76CF90026E7DC /* LoginItemsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE86A2AA76CF90026E7DC /* LoginItemsManager.swift */; }; 9D9AE86C2AA76D1B0026E7DC /* LoginItemsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE86A2AA76CF90026E7DC /* LoginItemsManager.swift */; }; 9D9AE86D2AA76D1C0026E7DC /* LoginItemsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE86A2AA76CF90026E7DC /* LoginItemsManager.swift */; }; 9D9AE86E2AA76D1F0026E7DC /* LoginItem+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE8682AA76CDC0026E7DC /* LoginItem+NetworkProtection.swift */; }; 9D9AE86F2AA76D210026E7DC /* LoginItem+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE8682AA76CDC0026E7DC /* LoginItem+NetworkProtection.swift */; }; + 9D9AE8F92AAA3AD00026E7DC /* DataBrokerProtection in Frameworks */ = {isa = PBXBuildFile; productRef = 9D9AE8F82AAA3AD00026E7DC /* DataBrokerProtection */; }; + 9D9AE8FB2AAA3AD90026E7DC /* DataBrokerProtection in Frameworks */ = {isa = PBXBuildFile; productRef = 9D9AE8FA2AAA3AD90026E7DC /* DataBrokerProtection */; }; + 9D9AE91D2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9152AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift */; }; + 9D9AE91E2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9152AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift */; }; + 9D9AE91F2AAA3B450026E7DC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9D9AE9162AAA3B450026E7DC /* Assets.xcassets */; }; + 9D9AE9202AAA3B450026E7DC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9D9AE9162AAA3B450026E7DC /* Assets.xcassets */; }; + 9D9AE9212AAA3B450026E7DC /* UserText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9172AAA3B450026E7DC /* UserText.swift */; }; + 9D9AE9222AAA3B450026E7DC /* UserText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9172AAA3B450026E7DC /* UserText.swift */; }; + 9D9AE9292AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift */; }; + 9D9AE92A2AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift */; }; + 9D9AE92C2AAB84FF0026E7DC /* DBPMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */; }; + 9D9AE92D2AAB84FF0026E7DC /* DBPMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */; }; + 9D9AE9312AAB8A9E0026E7DC /* BrowserServicesKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9D9AE9302AAB8A9E0026E7DC /* BrowserServicesKit */; }; 9DB6E7242AA0DC5800A17F3C /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = 9DB6E7232AA0DC5800A17F3C /* LoginItems */; }; 9DB6E7262AA0DC6600A17F3C /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = 9DB6E7252AA0DC6600A17F3C /* LoginItems */; }; 9DC70B1A2AA1FA5B005A844B /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = 9DC70B192AA1FA5B005A844B /* LoginItems */; }; @@ -3739,6 +3758,7 @@ dstPath = Contents/Library/LoginItems; dstSubfolderSpec = 1; files = ( + 7BB369E92ACB39A500B4FFEB /* DuckDuckGoDBPBackgroundAgent.app in Embed Login Items */, 3192A2612A4C4CFF0084EA89 /* DuckDuckGo VPN.app in Embed Login Items */, 3192A2622A4C4CFF0084EA89 /* DuckDuckGo Notifications.app in Embed Login Items */, ); @@ -4278,6 +4298,9 @@ 7B4CE8E626F02134009134B1 /* TabBarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarTests.swift; sourceTree = ""; }; 7B5291882A1697680022E406 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 7B5291892A169BC90022E406 /* NetworkProtectionDeveloperID.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetworkProtectionDeveloperID.xcconfig; sourceTree = ""; }; + 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionLoginItemScheduler.swift; sourceTree = ""; }; + 7B6EC5E42AE2D8AF004FE6DF /* DuckDuckGoDBPAgentAppStore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DuckDuckGoDBPAgentAppStore.xcconfig; sourceTree = ""; }; + 7B6EC5E52AE2D8AF004FE6DF /* DuckDuckGoDBPAgent.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DuckDuckGoDBPAgent.xcconfig; sourceTree = ""; }; 7B76E6852AD5D77600186A84 /* XPCHelper */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = XPCHelper; sourceTree = ""; }; 7B934C3D2A866CFF00FC8F9C /* NetworkProtectionOnboardingMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionOnboardingMenu.swift; sourceTree = ""; }; 7B934C402A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserDefaults+NetworkProtectionShared.swift"; sourceTree = ""; }; @@ -4301,6 +4324,7 @@ 7BB108572A43375D000AB95F /* PFMoveApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFMoveApplication.h; sourceTree = ""; }; 7BB108582A43375D000AB95F /* PFMoveApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFMoveApplication.m; sourceTree = ""; }; 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionDebugUtilities.swift; sourceTree = ""; }; + 7BD01C182AD8319C0088B32E /* IPCServiceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPCServiceManager.swift; sourceTree = ""; }; 7BD1688D2AD4A4C400D24876 /* NetworkExtensionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkExtensionController.swift; sourceTree = ""; }; 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeychainType+ClientDefault.swift"; sourceTree = ""; }; 7BD8679A2A9E9E000063B9F7 /* NetworkProtectionFeatureVisibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionFeatureVisibility.swift; sourceTree = ""; }; @@ -4414,8 +4438,20 @@ 987799FF29999B64005D8EB6 /* Bookmark 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Bookmark 3.xcdatamodel"; sourceTree = ""; }; 98A95D87299A2DF900B9B81A /* BookmarkMigrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkMigrationTests.swift; sourceTree = ""; }; 98EB5D0F27516A4800681FE6 /* AppPrivacyConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPrivacyConfigurationTests.swift; sourceTree = ""; }; + 9D8FA00B2AC5BDCE005DD0D0 /* LoginItem+DataBrokerProtection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LoginItem+DataBrokerProtection.swift"; sourceTree = ""; }; 9D9AE8682AA76CDC0026E7DC /* LoginItem+NetworkProtection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LoginItem+NetworkProtection.swift"; sourceTree = ""; }; 9D9AE86A2AA76CF90026E7DC /* LoginItemsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginItemsManager.swift; sourceTree = ""; }; + 9D9AE8D12AAA39A70026E7DC /* DuckDuckGoDBPBackgroundAgent.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DuckDuckGoDBPBackgroundAgent.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 9D9AE8F22AAA39D30026E7DC /* .app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = .app; sourceTree = BUILT_PRODUCTS_DIR; }; + 9D9AE9142AAA3B450026E7DC /* Info-AppStore.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-AppStore.plist"; sourceTree = ""; }; + 9D9AE9152AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DuckDuckGoDBPBackgroundAgentAppDelegate.swift; sourceTree = ""; }; + 9D9AE9162AAA3B450026E7DC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 9D9AE9172AAA3B450026E7DC /* UserText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserText.swift; sourceTree = ""; }; + 9D9AE9182AAA3B450026E7DC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9D9AE9192AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppStore.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = DuckDuckGoDBPBackgroundAgentAppStore.entitlements; sourceTree = ""; }; + 9D9AE91A2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgent.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = DuckDuckGoDBPBackgroundAgent.entitlements; sourceTree = ""; }; + 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionBackgroundManager.swift; sourceTree = ""; }; + 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBPMocks.swift; sourceTree = ""; }; 9DB6E7222AA0DA7A00A17F3C /* LoginItems */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = LoginItems; sourceTree = ""; }; AA0877B726D5160D00B05660 /* SafariVersionReaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariVersionReaderTests.swift; sourceTree = ""; }; AA0877B926D5161D00B05660 /* WebKitVersionProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebKitVersionProviderTests.swift; sourceTree = ""; }; @@ -4898,9 +4934,11 @@ 9DB6E7262AA0DC6600A17F3C /* LoginItems in Frameworks */, 3192A2132A4C4CFF0084EA89 /* PrivacyDashboard in Frameworks */, 3192A2142A4C4CFF0084EA89 /* SyncDataProviders in Frameworks */, + 7B74F2482ADEB03900147283 /* PixelKit in Frameworks */, 3192A2152A4C4CFF0084EA89 /* SyncUI in Frameworks */, 3192A2162A4C4CFF0084EA89 /* NetworkProtectionUI in Frameworks */, 3192A2172A4C4CFF0084EA89 /* Common in Frameworks */, + 7BD01C152AD820310088B32E /* XPCHelper in Frameworks */, 3192A2182A4C4CFF0084EA89 /* Persistence in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4976,7 +5014,6 @@ 7BEEA5162AD1236E00A9E72B /* NetworkProtectionUI in Frameworks */, 7BFCB74E2ADE7E1A00DA3EA7 /* PixelKit in Frameworks */, EE7295ED2A545C0A008C0991 /* NetworkProtection in Frameworks */, - 7B31FD882AD124620086AA24 /* (null) in Frameworks */, 7BEC182F2AD5D8DC00D30536 /* SystemExtensionManager in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4990,7 +5027,6 @@ 7BEEA5142AD1236300A9E72B /* NetworkProtectionIPC in Frameworks */, EE7295EF2A545C12008C0991 /* NetworkProtection in Frameworks */, 4B2D067F2A1334D700DE1F49 /* NetworkProtectionUI in Frameworks */, - 7B31FD8A2AD124680086AA24 /* (null) in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5038,6 +5074,7 @@ 4B957BE42AC7AE700062CA31 /* DDGSync in Frameworks */, 4B957BE52AC7AE700062CA31 /* OpenSSL in Frameworks */, 4B957BE62AC7AE700062CA31 /* PrivacyDashboard in Frameworks */, + 7B8C083C2AE1268E00F4C67F /* PixelKit in Frameworks */, 4B957BE72AC7AE700062CA31 /* SyncDataProviders in Frameworks */, 4B957BE82AC7AE700062CA31 /* SyncUI in Frameworks */, 4B957BE92AC7AE700062CA31 /* NetworkProtectionUI in Frameworks */, @@ -5061,6 +5098,25 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 9D9AE8C62AAA39A70026E7DC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9D6983F92AC773C3002C02FC /* PixelKit in Frameworks */, + 9D9AE8F92AAA3AD00026E7DC /* DataBrokerProtection in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9D9AE8E72AAA39D30026E7DC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9D6983FB2AC773C8002C02FC /* PixelKit in Frameworks */, + 9D9AE9312AAB8A9E0026E7DC /* BrowserServicesKit in Frameworks */, + 9D9AE8FB2AAA3AD90026E7DC /* DataBrokerProtection in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; AA585D7B248FD31100E9A3E2 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -5071,6 +5127,7 @@ 9807F645278CA16F00E1547B /* BrowserServicesKit in Frameworks */, 1EC88CA12AC1DD63003A4471 /* Account in Frameworks */, 987799ED299998B1005D8EB6 /* Bookmarks in Frameworks */, + 7B5DD69A2AE51FFA001DE99C /* PixelKit in Frameworks */, 1E950E3F2912A10D0051A99B /* ContentBlocking in Frameworks */, 378F44E429B4BDE900899924 /* SwiftUIExtensions in Frameworks */, 1E950E432912A10D0051A99B /* UserScript in Frameworks */, @@ -5079,13 +5136,11 @@ 1E3ED4FD2AC1E0290075F60F /* Purchase in Frameworks */, 4B2AAAF529E70DEA0026AFC0 /* Lottie in Frameworks */, AA06B6B72672AF8100F541C5 /* Sparkle in Frameworks */, - 7BF7705F2AD6C999001C9182 /* PixelKit in Frameworks */, B6B77BE8297973D4001E68A1 /* Navigation in Frameworks */, 3739326729AE4B42009346AE /* DDGSync in Frameworks */, 7BA59C9B2AE18B49009A97B1 /* SystemExtensionManager in Frameworks */, 371D00E129D8509400EC8598 /* OpenSSL in Frameworks */, 1E950E412912A10D0051A99B /* PrivacyDashboard in Frameworks */, - 4BF0E50E2AD2555D00FFEC9E /* (null) in Frameworks */, 37DF000529F9C056002B7D3E /* SyncDataProviders in Frameworks */, 37BA812D29B3CD690053F1A3 /* SyncUI in Frameworks */, 4B4D60B12A0C83B900BCD287 /* NetworkProtectionUI in Frameworks */, @@ -5297,6 +5352,8 @@ children = ( 3192EC872A4DCF21001E97A5 /* DBPHomeViewController.swift */, 3139A1512AA4B3C000969C7D /* DataBrokerProtectionManager.swift */, + 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift */, + 9D8FA00B2AC5BDCE005DD0D0 /* LoginItem+DataBrokerProtection.swift */, ); path = DBP; sourceTree = ""; @@ -5433,6 +5490,7 @@ 4B957C432AC7AF190062CA31 /* DuckDuckGoPrivacyPro.xcconfig */, 378E2799296F6FDE00FCADA2 /* ManualAppStoreRelease.xcconfig */, 3192A2712A4CBD3A0084EA89 /* DuckDuckGoDBP.xcconfig */, + 7B6EC5E32AE2D88C004FE6DF /* DBP */, 4B18E3222A1D31E4005D0AAA /* NetworkProtection */, ); path = App; @@ -6436,6 +6494,15 @@ path = UITests; sourceTree = ""; }; + 7B6EC5E32AE2D88C004FE6DF /* DBP */ = { + isa = PBXGroup; + children = ( + 7B6EC5E52AE2D8AF004FE6DF /* DuckDuckGoDBPAgent.xcconfig */, + 7B6EC5E42AE2D8AF004FE6DF /* DuckDuckGoDBPAgentAppStore.xcconfig */, + ); + path = DBP; + sourceTree = ""; + }; 7B96D0D02ADFDA7F007E02C8 /* DuckDuckGoDBPTests */ = { isa = PBXGroup; children = ( @@ -6830,6 +6897,23 @@ path = LoginItems; sourceTree = ""; }; + 9D9AE9132AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgent */ = { + isa = PBXGroup; + children = ( + 9D9AE9152AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift */, + 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift */, + 7BD01C182AD8319C0088B32E /* IPCServiceManager.swift */, + 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */, + 9D9AE9172AAA3B450026E7DC /* UserText.swift */, + 9D9AE9162AAA3B450026E7DC /* Assets.xcassets */, + 9D9AE91A2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgent.entitlements */, + 9D9AE9192AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppStore.entitlements */, + 9D9AE9182AAA3B450026E7DC /* Info.plist */, + 9D9AE9142AAA3B450026E7DC /* Info-AppStore.plist */, + ); + path = DuckDuckGoDBPBackgroundAgent; + sourceTree = ""; + }; AA0877B626D515EE00B05660 /* UserAgent */ = { isa = PBXGroup; children = ( @@ -6944,6 +7028,7 @@ 7B96D0D02ADFDA7F007E02C8 /* DuckDuckGoDBPTests */, 4B5F14F72A148B230060320F /* NetworkProtectionAppExtension */, 4B25375C2A11BE7500610219 /* NetworkProtectionSystemExtension */, + 9D9AE9132AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgent */, 7BA7CC0D2AD11DC80042E5CE /* DuckDuckGoVPN */, AA585D7F248FD31100E9A3E2 /* Products */, 85AE2FF024A33A2D002D507F /* Frameworks */, @@ -6967,6 +7052,8 @@ 4B2D06392A11CFBB00DE1F49 /* DuckDuckGo VPN.app */, 4B2D06692A13318400DE1F49 /* DuckDuckGo VPN App Store.app */, 3192A26E2A4C4CFF0084EA89 /* DuckDuckGoDBP.app */, + 9D9AE8D12AAA39A70026E7DC /* DuckDuckGoDBPBackgroundAgent.app */, + 9D9AE8F22AAA39D30026E7DC /* .app */, 4B957C412AC7AE700062CA31 /* DuckDuckGo Privacy Pro.app */, 7B96D0CF2ADFDA7E007E02C8 /* DuckDuckGoDBPTests.xctest */, ); @@ -8527,6 +8614,7 @@ 31929F952A4C4CFF0084EA89 /* NetworkProtectionUI */, 31A93F502A5D8AF0008BB88D /* DataBrokerProtection */, 9DB6E7252AA0DC6600A17F3C /* LoginItems */, + 7B74F2472ADEB03900147283 /* PixelKit */, 7B31FD8D2AD125760086AA24 /* NetworkProtectionIPC */, ); productName = DuckDuckGo; @@ -8801,6 +8889,7 @@ 4B9579402AC7AE700062CA31 /* Subscription */, 4B9579412AC7AE700062CA31 /* Account */, 4B9579422AC7AE700062CA31 /* Purchase */, + 7B8C083B2AE1268E00F4C67F /* PixelKit */, 7B31FD8F2AD1257B0086AA24 /* NetworkProtectionIPC */, ); productName = DuckDuckGo; @@ -8847,6 +8936,50 @@ productReference = 7B96D0CF2ADFDA7E007E02C8 /* DuckDuckGoDBPTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 9D9AE8B22AAA39A70026E7DC /* DuckDuckGoDBPBackgroundAgent */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9D9AE8CC2AAA39A70026E7DC /* Build configuration list for PBXNativeTarget "DuckDuckGoDBPBackgroundAgent" */; + buildPhases = ( + 9D9AE8B62AAA39A70026E7DC /* Sources */, + 9D9AE8C62AAA39A70026E7DC /* Frameworks */, + 9D9AE8C92AAA39A70026E7DC /* Resources */, + 7BB34F502AD98394005691AE /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DuckDuckGoDBPBackgroundAgent; + packageProductDependencies = ( + 9D9AE8F82AAA3AD00026E7DC /* DataBrokerProtection */, + 9D6983F82AC773C3002C02FC /* PixelKit */, + ); + productName = DuckDuckGoAgent; + productReference = 9D9AE8D12AAA39A70026E7DC /* DuckDuckGoDBPBackgroundAgent.app */; + productType = "com.apple.product-type.application"; + }; + 9D9AE8D32AAA39D30026E7DC /* DuckDuckGoDBPBackgroundAgentAppStore */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9D9AE8ED2AAA39D30026E7DC /* Build configuration list for PBXNativeTarget "DuckDuckGoDBPBackgroundAgentAppStore" */; + buildPhases = ( + 9D9AE8D72AAA39D30026E7DC /* Sources */, + 9D9AE8E72AAA39D30026E7DC /* Frameworks */, + 9D9AE8EA2AAA39D30026E7DC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DuckDuckGoDBPBackgroundAgentAppStore; + packageProductDependencies = ( + 9D9AE8FA2AAA3AD90026E7DC /* DataBrokerProtection */, + 9D9AE9302AAB8A9E0026E7DC /* BrowserServicesKit */, + 9D6983FA2AC773C8002C02FC /* PixelKit */, + ); + productName = DuckDuckGoAgent; + productReference = 9D9AE8F22AAA39D30026E7DC /* .app */; + productType = "com.apple.product-type.application"; + }; AA585D7D248FD31100E9A3E2 /* DuckDuckGo Privacy Browser */ = { isa = PBXNativeTarget; buildConfigurationList = AA585DA4248FD31500E9A3E2 /* Build configuration list for PBXNativeTarget "DuckDuckGo Privacy Browser" */; @@ -8889,8 +9022,8 @@ 1EC88CA02AC1DD63003A4471 /* Account */, 1E3ED4FC2AC1E0290075F60F /* Purchase */, 7B31FD8B2AD125620086AA24 /* NetworkProtectionIPC */, - 7BF7705E2AD6C999001C9182 /* PixelKit */, 7BA59C9A2AE18B49009A97B1 /* SystemExtensionManager */, + 7B5DD6992AE51FFA001DE99C /* PixelKit */, ); productName = DuckDuckGo; productReference = AA585D7E248FD31100E9A3E2 /* DuckDuckGo.app */; @@ -9031,6 +9164,8 @@ 4B2D06682A13318400DE1F49 /* DuckDuckGoVPNAppStore */, 31929F7B2A4C4CFF0084EA89 /* DuckDuckGo DBP */, 7B96D0CE2ADFDA7E007E02C8 /* DuckDuckGoDBPTests */, + 9D9AE8B22AAA39A70026E7DC /* DuckDuckGoDBPBackgroundAgent */, + 9D9AE8D32AAA39D30026E7DC /* DuckDuckGoDBPBackgroundAgentAppStore */, 4B9579252AC7AE700062CA31 /* DuckDuckGo Privacy Pro */, ); }; @@ -9331,6 +9466,22 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 9D9AE8C92AAA39A70026E7DC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9D9AE91F2AAA3B450026E7DC /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9D9AE8EA2AAA39D30026E7DC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9D9AE9202AAA3B450026E7DC /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; AA585D7C248FD31100E9A3E2 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -9707,6 +9858,24 @@ shellPath = /bin/sh; shellScript = "if [[ -z \"${SYSEX_BUNDLE_ID}\" ]]; then\n echo \"Required build settings are not defined, please check xcconfig files\"\n exit 1\nfi\n\n\necho \"ditto ${BUILT_PRODUCTS_DIR}/${SYSEX_BUNDLE_ID}.systemextension $BUILT_PRODUCTS_DIR/${CONTENTS_FOLDER_PATH}/Library/SystemExtensions/${SYSEX_BUNDLE_ID}.systemextension\"\n\nditto \"${BUILT_PRODUCTS_DIR}/${SYSEX_BUNDLE_ID}.systemextension\" \"$BUILT_PRODUCTS_DIR/${CONTENTS_FOLDER_PATH}/Library/SystemExtensions/${SYSEX_BUNDLE_ID}.systemextension\" || exit 1\n"; }; + 7BB34F502AD98394005691AE /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# We had issues where the Swift Package resources were not being added to the Agent Apps,\n# so we're manually coping them here.\n# It seems to be a known issue: https://forums.swift.org/t/swift-packages-resource-bundle-not-present-in-xcarchive-when-framework-using-said-package-is-archived/50084/2\ncp -RL \"${BUILT_PRODUCTS_DIR}\"/ContentScopeScripts_ContentScopeScripts.bundle \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\n"; + }; AA8EDF2824925E940071C2E8 /* Swift Lint */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -9845,6 +10014,7 @@ 31929FBA2A4C4CFF0084EA89 /* BWEncryptionOutput.m in Sources */, 37745AFB2A9E05260068533A /* SyncSettingsAdapter.swift in Sources */, 31929FBC2A4C4CFF0084EA89 /* PermissionState.swift in Sources */, + 9D8FA00C2AC5BDCE005DD0D0 /* LoginItem+DataBrokerProtection.swift in Sources */, 31929FBD2A4C4CFF0084EA89 /* FeedbackPresenter.swift in Sources */, 31929FBE2A4C4CFF0084EA89 /* NavigationProtectionTabExtension.swift in Sources */, 31929FBF2A4C4CFF0084EA89 /* UserAgent.swift in Sources */, @@ -10458,6 +10628,7 @@ 3192A1F02A4C4CFF0084EA89 /* FireproofDomains.swift in Sources */, 3192A1F12A4C4CFF0084EA89 /* Database.swift in Sources */, 3192A1F22A4C4CFF0084EA89 /* HorizontallyCenteredLayout.swift in Sources */, + 7B6D98672ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift in Sources */, 3192A1F32A4C4CFF0084EA89 /* BookmarksOutlineView.swift in Sources */, 3192A1F42A4C4CFF0084EA89 /* CountryList.swift in Sources */, 3192A1F52A4C4CFF0084EA89 /* PreferencesSection.swift in Sources */, @@ -12245,6 +12416,29 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 9D9AE8B62AAA39A70026E7DC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9D9AE92C2AAB84FF0026E7DC /* DBPMocks.swift in Sources */, + 9D9AE9292AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */, + 9D9AE91D2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift in Sources */, + 9D9AE9212AAA3B450026E7DC /* UserText.swift in Sources */, + 7BD01C192AD8319C0088B32E /* IPCServiceManager.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9D9AE8D72AAA39D30026E7DC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9D9AE92D2AAB84FF0026E7DC /* DBPMocks.swift in Sources */, + 9D9AE92A2AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */, + 9D9AE91E2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift in Sources */, + 9D9AE9222AAA3B450026E7DC /* UserText.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; AA585D7A248FD31100E9A3E2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -13644,6 +13838,62 @@ }; name = Review; }; + 9D9AE8CD2AAA39A70026E7DC /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7B6EC5E52AE2D8AF004FE6DF /* DuckDuckGoDBPAgent.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + 9D9AE8CE2AAA39A70026E7DC /* CI */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7B6EC5E52AE2D8AF004FE6DF /* DuckDuckGoDBPAgent.xcconfig */; + buildSettings = { + }; + name = CI; + }; + 9D9AE8CF2AAA39A70026E7DC /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7B6EC5E52AE2D8AF004FE6DF /* DuckDuckGoDBPAgent.xcconfig */; + buildSettings = { + }; + name = Release; + }; + 9D9AE8D02AAA39A70026E7DC /* Review */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7B6EC5E52AE2D8AF004FE6DF /* DuckDuckGoDBPAgent.xcconfig */; + buildSettings = { + }; + name = Review; + }; + 9D9AE8EE2AAA39D30026E7DC /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7B6EC5E42AE2D8AF004FE6DF /* DuckDuckGoDBPAgentAppStore.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + 9D9AE8EF2AAA39D30026E7DC /* CI */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7B6EC5E42AE2D8AF004FE6DF /* DuckDuckGoDBPAgentAppStore.xcconfig */; + buildSettings = { + }; + name = CI; + }; + 9D9AE8F02AAA39D30026E7DC /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7B6EC5E42AE2D8AF004FE6DF /* DuckDuckGoDBPAgentAppStore.xcconfig */; + buildSettings = { + }; + name = Release; + }; + 9D9AE8F12AAA39D30026E7DC /* Review */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7B6EC5E42AE2D8AF004FE6DF /* DuckDuckGoDBPAgentAppStore.xcconfig */; + buildSettings = { + }; + name = Review; + }; AA585DA2248FD31500E9A3E2 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 37717E66296B5A20002FAEDF /* Global.xcconfig */; @@ -13895,6 +14145,28 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 9D9AE8CC2AAA39A70026E7DC /* Build configuration list for PBXNativeTarget "DuckDuckGoDBPBackgroundAgent" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9D9AE8CD2AAA39A70026E7DC /* Debug */, + 9D9AE8CE2AAA39A70026E7DC /* CI */, + 9D9AE8CF2AAA39A70026E7DC /* Release */, + 9D9AE8D02AAA39A70026E7DC /* Review */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9D9AE8ED2AAA39D30026E7DC /* Build configuration list for PBXNativeTarget "DuckDuckGoDBPBackgroundAgentAppStore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9D9AE8EE2AAA39D30026E7DC /* Debug */, + 9D9AE8EF2AAA39D30026E7DC /* CI */, + 9D9AE8F02AAA39D30026E7DC /* Release */, + 9D9AE8F12AAA39D30026E7DC /* Review */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; AA585D79248FD31100E9A3E2 /* Build configuration list for PBXProject "DuckDuckGo" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -14067,7 +14339,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 82.0.1; + version = 82.0.2; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { @@ -14492,10 +14764,22 @@ isa = XCSwiftPackageProductDependency; productName = NetworkProtectionIPC; }; + 7B5DD6992AE51FFA001DE99C /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + productName = PixelKit; + }; 7B5F9A742AE2BE4E002AEBC0 /* PixelKit */ = { isa = XCSwiftPackageProductDependency; productName = PixelKit; }; + 7B74F2472ADEB03900147283 /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + productName = PixelKit; + }; + 7B8C083B2AE1268E00F4C67F /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + productName = PixelKit; + }; 7BA59C9A2AE18B49009A97B1 /* SystemExtensionManager */ = { isa = XCSwiftPackageProductDependency; productName = SystemExtensionManager; @@ -14514,6 +14798,10 @@ isa = XCSwiftPackageProductDependency; productName = PixelKit; }; + 7BD01C142AD820310088B32E /* XPCHelper */ = { + isa = XCSwiftPackageProductDependency; + productName = XPCHelper; + }; 7BEC182E2AD5D8DC00D30536 /* SystemExtensionManager */ = { isa = XCSwiftPackageProductDependency; productName = SystemExtensionManager; @@ -14530,10 +14818,6 @@ isa = XCSwiftPackageProductDependency; productName = NetworkProtectionUI; }; - 7BF7705E2AD6C999001C9182 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 7BFCB74D2ADE7E1A00DA3EA7 /* PixelKit */ = { isa = XCSwiftPackageProductDependency; productName = PixelKit; @@ -14562,6 +14846,27 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Persistence; }; + 9D6983F82AC773C3002C02FC /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + productName = PixelKit; + }; + 9D6983FA2AC773C8002C02FC /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + productName = PixelKit; + }; + 9D9AE8F82AAA3AD00026E7DC /* DataBrokerProtection */ = { + isa = XCSwiftPackageProductDependency; + productName = DataBrokerProtection; + }; + 9D9AE8FA2AAA3AD90026E7DC /* DataBrokerProtection */ = { + isa = XCSwiftPackageProductDependency; + productName = DataBrokerProtection; + }; + 9D9AE9302AAB8A9E0026E7DC /* BrowserServicesKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = BrowserServicesKit; + }; 9DB6E7232AA0DC5800A17F3C /* LoginItems */ = { isa = XCSwiftPackageProductDependency; productName = LoginItems; diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8d7fa61073..613c121608 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "8f7a94a70812862203955b3d2bbb909420fa55dd", - "version" : "82.0.1" + "revision" : "8768193257dd1f461218ed2a8d7893156bde4bda", + "version" : "82.0.2" } }, { @@ -129,7 +129,7 @@ { "identity" : "trackerradarkit", "kind" : "remoteSourceControl", - "location" : "https://github.com/duckduckgo/TrackerRadarKit", + "location" : "https://github.com/duckduckgo/TrackerRadarKit.git", "state" : { "revision" : "4684440d03304e7638a2c8086895367e90987463", "version" : "1.2.1" diff --git a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser App Store.xcscheme b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser App Store.xcscheme index ccb95daa64..70c4322cf6 100644 --- a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser App Store.xcscheme +++ b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser App Store.xcscheme @@ -153,6 +153,16 @@ ReferencedContainer = "container:LocalPackages/SyncUI"> + + + + + + + + #import "WKWebView+Private.h" diff --git a/DuckDuckGo/Common/Extensions/BundleExtension.swift b/DuckDuckGo/Common/Extensions/BundleExtension.swift index 8a5dd88545..b39ef00b67 100644 --- a/DuckDuckGo/Common/Extensions/BundleExtension.swift +++ b/DuckDuckGo/Common/Extensions/BundleExtension.swift @@ -34,6 +34,11 @@ extension Bundle { static let notificationsAgentProductName = "NOTIFICATIONS_AGENT_PRODUCT_NAME" #endif static let appGroup = "NETP_APP_GROUP" + +#if DBP + static let dbpBackgroundAgentBundleId = "DBP_BACKGROUND_AGENT_BUNDLE_ID" + static let dbpBackgroundAgentProductName = "DBP_BACKGROUND_AGENT_PRODUCT_NAME" +#endif } var versionNumber: String? { @@ -74,6 +79,22 @@ extension Bundle { } #endif +#if DBP + var dbpBackgroundAgentBundleId: String { + guard let bundleID = object(forInfoDictionaryKey: Keys.dbpBackgroundAgentBundleId) as? String else { + fatalError("Info.plist is missing \(Keys.dbpBackgroundAgentBundleId)") + } + return bundleID + } + + var dbpBackgroundAgentURL: URL { + guard let productName = object(forInfoDictionaryKey: Keys.dbpBackgroundAgentProductName) as? String else { + fatalError("Info.plist is missing \(Keys.dbpBackgroundAgentProductName)") + } + return loginItemsURL.appendingPathComponent(productName + ".app") + } +#endif + var appGroupName: String { guard let appGroup = object(forInfoDictionaryKey: Keys.appGroup) as? String else { fatalError("Info.plist is missing \(Keys.appGroup)") diff --git a/DuckDuckGo/Common/Logging/Logging.swift b/DuckDuckGo/Common/Logging/Logging.swift index ce03218754..d29dd5a1af 100644 --- a/DuckDuckGo/Common/Logging/Logging.swift +++ b/DuckDuckGo/Common/Logging/Logging.swift @@ -42,6 +42,7 @@ extension OSLog { case duckPlayer = "Duck Player" case sync = "Sync" case networkProtection = "Network Protection" + case dbp = "dbp" } enum AllCategories { @@ -69,6 +70,7 @@ extension OSLog { @OSLogWrapper(.duckPlayer) static var duckPlayer @OSLogWrapper(.sync) static var sync @OSLogWrapper(.networkProtection) static var networkProtection + @OSLogWrapper(.dbp) static var dbp // Debug->Logging categories will only be enabled for one day @UserDefaultsWrapper(key: .loggingEnabledDate, defaultValue: .distantPast) diff --git a/DuckDuckGo/ContentBlocker/Mocks/ContentBlockingMock.swift b/DuckDuckGo/ContentBlocker/Mocks/ContentBlockingMock.swift index 524491ceba..6da3d7024c 100644 --- a/DuckDuckGo/ContentBlocker/Mocks/ContentBlockingMock.swift +++ b/DuckDuckGo/ContentBlocker/Mocks/ContentBlockingMock.swift @@ -16,6 +16,7 @@ // limitations under the License. // +import BloomFilterWrapper import BrowserServicesKit import Combine import Common diff --git a/DuckDuckGo/DBP/DBPHomeViewController.swift b/DuckDuckGo/DBP/DBPHomeViewController.swift index 51d76c289e..2749c6bb0c 100644 --- a/DuckDuckGo/DBP/DBPHomeViewController.swift +++ b/DuckDuckGo/DBP/DBPHomeViewController.swift @@ -49,13 +49,14 @@ final class DBPHomeViewController: NSViewController { sessionKey: sessionKey, featureToggles: features) - return DataBrokerProtectionViewController(scheduler: dataBrokerProtectionManager.scheduler, - dataManager: dataBrokerProtectionManager.dataManager, - privacyConfig: privacyConfigurationManager, - prefs: prefs, - openURLHandler: { url in - WindowControllersManager.shared.show(url: url, newTab: true) - }) + return DataBrokerProtectionViewController( + scheduler: dataBrokerProtectionManager.scheduler, + dataManager: dataBrokerProtectionManager.dataManager, + privacyConfig: privacyConfigurationManager, + prefs: prefs, + openURLHandler: { url in + WindowControllersManager.shared.show(url: url, newTab: true) + }) }() init(dataBrokerProtectionManager: DataBrokerProtectionManager) { diff --git a/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift new file mode 100644 index 0000000000..1883f61c38 --- /dev/null +++ b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift @@ -0,0 +1,78 @@ +// +// DataBrokerProtectionLoginItemScheduler.swift +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import DataBrokerProtection + +/// A scheduler that launches a login item and the communicates with it through an IPC scheduler. +/// +final class DataBrokerProtectionLoginItemScheduler { + private let ipcScheduler: DataBrokerProtectionIPCScheduler + private let loginItemsManager: LoginItemsManager + + init(ipcScheduler: DataBrokerProtectionIPCScheduler, loginItemsManager: LoginItemsManager = .init()) { + self.ipcScheduler = ipcScheduler + self.loginItemsManager = loginItemsManager + } + + // MARK: - Login Item Management + + func disableLoginItem() { + loginItemsManager.disableLoginItems([.dbpBackgroundAgent]) + } + + func enableLoginItem() { + loginItemsManager.enableLoginItems([.dbpBackgroundAgent], log: .dbp) + } +} + +extension DataBrokerProtectionLoginItemScheduler: DataBrokerProtectionScheduler { + var status: DataBrokerProtection.DataBrokerProtectionSchedulerStatus { + ipcScheduler.status + } + + var statusPublisher: Published.Publisher { + ipcScheduler.statusPublisher + } + + func scanAllBrokers(showWebView: Bool, completion: ((Error?) -> Void)?) { + enableLoginItem() + ipcScheduler.scanAllBrokers(showWebView: showWebView, completion: completion) + } + + func startScheduler(showWebView: Bool) { + enableLoginItem() + ipcScheduler.startScheduler(showWebView: showWebView) + } + + func stopScheduler() { + ipcScheduler.stopScheduler() + } + + func optOutAllBrokers(showWebView: Bool, completion: ((Error?) -> Void)?) { + ipcScheduler.optOutAllBrokers(showWebView: showWebView, completion: completion) + } + + func runAllOperations(showWebView: Bool) { + ipcScheduler.runAllOperations(showWebView: showWebView) + } + + func runQueuedOperations(showWebView: Bool, completion: ((Error?) -> Void)?) { + ipcScheduler.runQueuedOperations(showWebView: showWebView, completion: completion) + } +} diff --git a/DuckDuckGo/DBP/DataBrokerProtectionManager.swift b/DuckDuckGo/DBP/DataBrokerProtectionManager.swift index eddab96f38..7b732c83fb 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionManager.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionManager.swift @@ -19,6 +19,8 @@ import Foundation import BrowserServicesKit import DataBrokerProtection +import LoginItems +import Common public final class DataBrokerProtectionManager { @@ -30,33 +32,16 @@ public final class DataBrokerProtectionManager { private let fakeBrokerFlag: DataBrokerDebugFlag = DataBrokerDebugFlagFakeBroker() lazy var dataManager: DataBrokerProtectionDataManager = { - DataBrokerProtectionDataManager(fakeBrokerFlag: fakeBrokerFlag) + let dataManager = DataBrokerProtectionDataManager(fakeBrokerFlag: fakeBrokerFlag) + dataManager.delegate = self + return dataManager }() - lazy var scheduler: DataBrokerProtectionScheduler = { - let privacyConfigurationManager = PrivacyFeatures.contentBlocking.privacyConfigurationManager - let features = ContentScopeFeatureToggles(emailProtection: false, - emailProtectionIncontextSignup: false, - credentialsAutofill: false, - identitiesAutofill: false, - creditCardsAutofill: false, - credentialsSaving: false, - passwordGeneration: false, - inlineIconCredentials: false, - thirdPartyCredentialsProvider: false) + lazy var scheduler: DataBrokerProtectionLoginItemScheduler = { + let ipcClient = DataBrokerProtectionIPCClient(machServiceName: Bundle.main.dbpBackgroundAgentBundleId) + let ipcScheduler = DataBrokerProtectionIPCScheduler(ipcClient: ipcClient) - let privacySettings = PrivacySecurityPreferences.shared - let sessionKey = UUID().uuidString - let prefs = ContentScopeProperties.init(gpcEnabled: privacySettings.gpcEnabled, - sessionKey: sessionKey, - featureToggles: features) - - return DefaultDataBrokerProtectionScheduler(privacyConfigManager: privacyConfigurationManager, - contentScopeProperties: prefs, - dataManager: dataManager, - notificationCenter: NotificationCenter.default, - pixelHandler: DataBrokerProtectionPixelsHandler(), - redeemUseCase: redeemUseCase) + return DataBrokerProtectionLoginItemScheduler(ipcScheduler: ipcScheduler) }() private init() { @@ -68,15 +53,14 @@ public final class DataBrokerProtectionManager { public func shouldAskForInviteCode() -> Bool { redeemUseCase.shouldAskForInviteCode() } +} - public func runOperationsAndStartSchedulerIfPossible() { - guard !redeemUseCase.shouldAskForInviteCode() && !DataBrokerDebugFlagBlockScheduler().isFlagOn() else { return } +extension DataBrokerProtectionManager: DataBrokerProtectionDataManagerDelegate { + public func dataBrokerProtectionDataManagerDidUpdateData() { + scheduler.startScheduler() + } - // If there's no saved profile we don't need to start the scheduler - if dataManager.fetchProfile() != nil { - scheduler.runQueuedOperations(showWebView: false) { [weak self] in - self?.scheduler.startScheduler() - } - } + public func dataBrokerProtectionDataManagerDidDeleteData() { + scheduler.stopScheduler() } } diff --git a/DuckDuckGo/DBP/LoginItem+DataBrokerProtection.swift b/DuckDuckGo/DBP/LoginItem+DataBrokerProtection.swift new file mode 100644 index 0000000000..3f16d2c144 --- /dev/null +++ b/DuckDuckGo/DBP/LoginItem+DataBrokerProtection.swift @@ -0,0 +1,29 @@ +// +// LoginItem.swift +// +// 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 LoginItems + +#if DBP + +extension LoginItem { + + static let dbpBackgroundAgent = LoginItem(bundleId: Bundle.main.dbpBackgroundAgentBundleId, log: .dbp) + +} + +#endif diff --git a/DuckDuckGo/Info.plist b/DuckDuckGo/Info.plist index 25cc319f62..f0c286ac27 100644 --- a/DuckDuckGo/Info.plist +++ b/DuckDuckGo/Info.plist @@ -118,5 +118,9 @@ $(NETP_APP_GROUP) DISTRIBUTED_NOTIFICATIONS_PREFIX $(DISTRIBUTED_NOTIFICATIONS_PREFIX) + DBP_BACKGROUND_AGENT_BUNDLE_ID + $(DBP_BACKGROUND_AGENT_BUNDLE_ID) + DBP_BACKGROUND_AGENT_PRODUCT_NAME + $(DBP_BACKGROUND_AGENT_PRODUCT_NAME) diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-128.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-128.png new file mode 100644 index 0000000000..3f2f513a7f Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-128.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-128@2x.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-128@2x.png new file mode 100644 index 0000000000..dd84c8e074 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-128@2x.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-16.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-16.png new file mode 100644 index 0000000000..f6e54cd988 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-16.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-16@2x.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-16@2x.png new file mode 100644 index 0000000000..14216dc846 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-16@2x.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-256.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-256.png new file mode 100644 index 0000000000..7218a9fa5f Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-256.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-256@2x.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-256@2x.png new file mode 100644 index 0000000000..6e188b43f9 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-256@2x.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-32.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-32.png new file mode 100644 index 0000000000..f838f8afab Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-32.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-32@2x.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-32@2x.png new file mode 100644 index 0000000000..0ea26aee99 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-32@2x.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-512.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-512.png new file mode 100644 index 0000000000..fada4804f9 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-512.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-512@2x.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-512@2x.png new file mode 100644 index 0000000000..c46ef0627a Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Browser-512@2x.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Contents.json b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..b35079cf73 --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "filename" : "Browser-16.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "filename" : "Browser-16@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "filename" : "Browser-32.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "filename" : "Browser-32@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "filename" : "Browser-128.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "filename" : "Browser-128@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "filename" : "Browser-256.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "filename" : "Browser-256@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "filename" : "Browser-512.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "filename" : "Browser-512@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Contents.json b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Contents.json b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Contents.json new file mode 100644 index 0000000000..b7c3f3b420 --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "filename" : "Debug Icon-16.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "filename" : "Debug Icon-32.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "filename" : "Debug Icon-33.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "filename" : "Debug Icon-64.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "filename" : "Debug Icon-128.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "filename" : "Debug Icon-256.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "filename" : "Debug Icon-257.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "filename" : "Debug Icon-512.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "filename" : "Debug Icon-513.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "filename" : "Debug Icon-1024.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-1024.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-1024.png new file mode 100644 index 0000000000..0065673ca9 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-1024.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-128.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-128.png new file mode 100644 index 0000000000..65199d8947 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-128.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-16.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-16.png new file mode 100644 index 0000000000..c9de1d6f0d Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-16.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-256.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-256.png new file mode 100644 index 0000000000..59a2c03f0b Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-256.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-257.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-257.png new file mode 100644 index 0000000000..59a2c03f0b Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-257.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-32.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-32.png new file mode 100644 index 0000000000..2d3e7c150c Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-32.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-33.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-33.png new file mode 100644 index 0000000000..2d3e7c150c Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-33.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-512.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-512.png new file mode 100644 index 0000000000..6d2c73df15 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-512.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-513.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-513.png new file mode 100644 index 0000000000..6d2c73df15 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-513.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-64.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-64.png new file mode 100644 index 0000000000..86af44ed7d Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Debug.appiconset/Debug Icon-64.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-1024.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-1024.png new file mode 100644 index 0000000000..af338b9d99 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-1024.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-128.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-128.png new file mode 100644 index 0000000000..44bdb5c446 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-128.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-16.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-16.png new file mode 100644 index 0000000000..a1ddd0a139 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-16.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-256.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-256.png new file mode 100644 index 0000000000..5aca48ab5c Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-256.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-257.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-257.png new file mode 100644 index 0000000000..5aca48ab5c Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-257.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-32.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-32.png new file mode 100644 index 0000000000..e0ec14d405 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-32.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-33.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-33.png new file mode 100644 index 0000000000..e0ec14d405 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-33.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-512.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-512.png new file mode 100644 index 0000000000..6f75bf22df Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-512.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-513.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-513.png new file mode 100644 index 0000000000..6f75bf22df Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-513.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-64.png b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-64.png new file mode 100644 index 0000000000..6a99fa89a2 Binary files /dev/null and b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Beta Icon-64.png differ diff --git a/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Contents.json b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Contents.json new file mode 100644 index 0000000000..64fbbd3659 --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/Assets.xcassets/Icon - Review.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "filename" : "Beta Icon-16.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "filename" : "Beta Icon-32.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "filename" : "Beta Icon-33.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "filename" : "Beta Icon-64.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "filename" : "Beta Icon-128.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "filename" : "Beta Icon-256.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "filename" : "Beta Icon-257.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "filename" : "Beta Icon-512.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "filename" : "Beta Icon-513.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "filename" : "Beta Icon-1024.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DuckDuckGoDBPBackgroundAgent/DBPMocks.swift b/DuckDuckGoDBPBackgroundAgent/DBPMocks.swift new file mode 100644 index 0000000000..87b6e010a6 --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/DBPMocks.swift @@ -0,0 +1,90 @@ +// +// DBPMocks.swift +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import BrowserServicesKit +import Combine + +/* + This mock is a hack for now + We ideally should refactor the privacy config out of the main app + Into a local package, so that it can be be used here + */ +final class PrivacyConfigurationManagingMock: PrivacyConfigurationManaging { + + var data: Data { + let configString = """ + { + "readme": "https://github.com/duckduckgo/privacy-configuration", + "version": 1693838894358, + "features": { + "brokerProtection": { + "state": "enabled", + "exceptions": [], + "settings": {} + } + }, + "unprotectedTemporary": [] + } + """ + let data = configString.data(using: .utf8) + return data! + } + + var currentConfig: Data { + data + } + + var updatesPublisher: AnyPublisher = .init(Just(())) + + var privacyConfig: BrowserServicesKit.PrivacyConfiguration { + guard let privacyConfigurationData = try? PrivacyConfigurationData(data: data) else { + fatalError("Could not retrieve privacy configuration data") + } + let privacyConfig = privacyConfiguration(withData: privacyConfigurationData) + return privacyConfig + } + + func reload(etag: String?, data: Data?) -> PrivacyConfigurationManager.ReloadResult { + .downloaded + } +} + +func privacyConfiguration(withData data: PrivacyConfigurationData) -> PrivacyConfiguration { + let domain = MockDomainsProtectionStore() + return AppPrivacyConfiguration(data: data, + identifier: UUID().uuidString, + localProtection: domain, + internalUserDecider: DefaultInternalUserDecider(store: InternalUserDeciderStoreMock())) +} + +final class MockDomainsProtectionStore: DomainsProtectionStore { + var unprotectedDomains = Set() + + func disableProtection(forDomain domain: String) { + unprotectedDomains.insert(domain) + } + + func enableProtection(forDomain domain: String) { + unprotectedDomains.remove(domain) + } +} + +final class InternalUserDeciderStoreMock: InternalUserStoring { + var isInternalUser: Bool = false +} diff --git a/DuckDuckGoDBPBackgroundAgent/DataBrokerProtectionBackgroundManager.swift b/DuckDuckGoDBPBackgroundAgent/DataBrokerProtectionBackgroundManager.swift new file mode 100644 index 0000000000..36135d8277 --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/DataBrokerProtectionBackgroundManager.swift @@ -0,0 +1,84 @@ +// +// DataBrokerProtectionManager.swift +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import Common +import BrowserServicesKit +import DataBrokerProtection +import PixelKit + +public final class DataBrokerProtectionBackgroundManager { + + static let shared = DataBrokerProtectionBackgroundManager() + + private let authenticationRepository: AuthenticationRepository = UserDefaultsAuthenticationData() + private let authenticationService: DataBrokerProtectionAuthenticationService = AuthenticationService() + private let redeemUseCase: DataBrokerProtectionRedeemUseCase + private let fakeBrokerFlag: DataBrokerDebugFlag = DataBrokerDebugFlagFakeBroker() + + private lazy var ipcServiceManager = IPCServiceManager(scheduler: scheduler) + + lazy var dataManager: DataBrokerProtectionDataManager = { + DataBrokerProtectionDataManager(fakeBrokerFlag: fakeBrokerFlag) + }() + + lazy var scheduler: DataBrokerProtectionScheduler = { + let privacyConfigurationManager = PrivacyConfigurationManagingMock() // Forgive me, for I have sinned + let features = ContentScopeFeatureToggles(emailProtection: false, + emailProtectionIncontextSignup: false, + credentialsAutofill: false, + identitiesAutofill: false, + creditCardsAutofill: false, + credentialsSaving: false, + passwordGeneration: false, + inlineIconCredentials: false, + thirdPartyCredentialsProvider: false) + + let sessionKey = UUID().uuidString + let prefs = ContentScopeProperties.init(gpcEnabled: false, + sessionKey: sessionKey, + featureToggles: features) + + return DefaultDataBrokerProtectionScheduler(privacyConfigManager: privacyConfigurationManager, + contentScopeProperties: prefs, + dataManager: dataManager, + notificationCenter: NotificationCenter.default, + pixelHandler: DataBrokerProtectionPixelsHandler(), + redeemUseCase: redeemUseCase) + }() + + private init() { + self.redeemUseCase = RedeemUseCase(authenticationService: authenticationService, + authenticationRepository: authenticationRepository) + _ = ipcServiceManager + } + + public func runOperationsAndStartSchedulerIfPossible() { + + // If there's no saved profile we don't need to start the scheduler + if dataManager.fetchProfile() != nil { + scheduler.runQueuedOperations(showWebView: false) { [weak self] error in + guard error == nil else { + return + } + + self?.scheduler.startScheduler() + } + } + } +} diff --git a/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements b/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements new file mode 100644 index 0000000000..4a2f05c88c --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgent.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.application-groups + + $(NETP_APP_GROUP) + + keychain-access-groups + + $(NETP_APP_GROUP) + + + diff --git a/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift b/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift new file mode 100644 index 0000000000..28d8fc0d6d --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift @@ -0,0 +1,57 @@ +// +// DuckDuckGoAgentAppDelegate.swift +// +// 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 Cocoa +import Combine +import Common +import ServiceManagement +import DataBrokerProtection +import BrowserServicesKit + +@objc(Application) +final class DuckDuckGoDBPBackgroundAgentApplication: NSApplication { + private let _delegate = DuckDuckGoDBPBackgroundAgentAppDelegate() + + override init() { + os_log(.error, log: .dbpBackgroundAgent, "🟢 DBP background Agent starting: %{public}d", NSRunningApplication.current.processIdentifier) + + // prevent agent from running twice + if let anotherInstance = NSRunningApplication.runningApplications(withBundleIdentifier: Bundle.main.bundleIdentifier!).first(where: { $0 != .current }) { + os_log(.error, log: .dbpBackgroundAgent, "🔴 Stopping: another instance is running: %{public}d.", anotherInstance.processIdentifier) + exit(0) + } + + super.init() + self.delegate = _delegate + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +@main +final class DuckDuckGoDBPBackgroundAgentAppDelegate: NSObject, NSApplicationDelegate { + + func applicationDidFinishLaunching(_ aNotification: Notification) { + os_log("DuckDuckGoAgent started", log: .dbpBackgroundAgent, type: .info) + + let manager = DataBrokerProtectionBackgroundManager.shared + manager.runOperationsAndStartSchedulerIfPossible() + } +} diff --git a/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppStore.entitlements b/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppStore.entitlements new file mode 100644 index 0000000000..b2fd453927 --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppStore.entitlements @@ -0,0 +1,21 @@ + + + + + com.apple.security.network.server + + com.apple.security.network.client + + com.apple.security.app-sandbox + + keychain-access-groups + + $(NETP_APP_GROUP) + + com.apple.security.application-groups + + $(TeamIdentifierPrefix)com.duckduckgo.macos.browser.network-protection + $(NETP_APP_GROUP) + + + diff --git a/DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift b/DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift new file mode 100644 index 0000000000..5b352ec325 --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift @@ -0,0 +1,83 @@ +// +// IPCServiceManager.swift +// +// 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 Combine +import Foundation +import DataBrokerProtection + +/// Manages the IPC service for the Agent app +/// +/// This class will handle all interactions between IPC requests and the classes those requests +/// demand interaction with. +/// +final class IPCServiceManager { + private let ipcServer: DataBrokerProtectionIPCServer + private let scheduler: DataBrokerProtectionScheduler + private var cancellables = Set() + + init(ipcServer: DataBrokerProtectionIPCServer = .init(machServiceName: Bundle.main.bundleIdentifier!), + scheduler: DataBrokerProtectionScheduler) { + + self.ipcServer = ipcServer + self.scheduler = scheduler + + ipcServer.serverDelegate = self + ipcServer.activate() + } + + private func subscribeToSchedulerStatusChanges() { + scheduler.statusPublisher + .subscribe(on: DispatchQueue.main) + .sink { [weak self] status in + self?.ipcServer.schedulerStatusChanges(status) + } + .store(in: &cancellables) + } +} + +extension IPCServiceManager: IPCServerInterface { + + func register() { + // When a new client registers, send the last known status + ipcServer.schedulerStatusChanges(scheduler.status) + } + + func startScheduler(showWebView: Bool) { + scheduler.startScheduler(showWebView: showWebView) + } + + func stopScheduler() { + scheduler.stopScheduler() + } + + func optOutAllBrokers(showWebView: Bool, completion: @escaping ((Error?) -> Void)) { + scheduler.optOutAllBrokers(showWebView: showWebView, completion: completion) + } + + func scanAllBrokers(showWebView: Bool, completion: @escaping ((Error?) -> Void)) { + scheduler.scanAllBrokers(showWebView: showWebView, completion: completion) + } + + func runQueuedOperations(showWebView: Bool, completion: @escaping ((Error?) -> Void)) { + scheduler.runQueuedOperations(showWebView: showWebView, completion: completion) + } + + func runAllOperations(showWebView: Bool) { + scheduler.runAllOperations(showWebView: showWebView) + } +} diff --git a/DuckDuckGoDBPBackgroundAgent/Info-AppStore.plist b/DuckDuckGoDBPBackgroundAgent/Info-AppStore.plist new file mode 100644 index 0000000000..b6f094baff --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/Info-AppStore.plist @@ -0,0 +1,10 @@ + + + + + NETP_APP_GROUP + $(NETP_APP_GROUP) + LSApplicationCategoryType + public.app-category.productivity + + diff --git a/DuckDuckGoDBPBackgroundAgent/Info.plist b/DuckDuckGoDBPBackgroundAgent/Info.plist new file mode 100644 index 0000000000..b6f094baff --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/Info.plist @@ -0,0 +1,10 @@ + + + + + NETP_APP_GROUP + $(NETP_APP_GROUP) + LSApplicationCategoryType + public.app-category.productivity + + diff --git a/DuckDuckGoDBPBackgroundAgent/UserText.swift b/DuckDuckGoDBPBackgroundAgent/UserText.swift new file mode 100644 index 0000000000..227f211608 --- /dev/null +++ b/DuckDuckGoDBPBackgroundAgent/UserText.swift @@ -0,0 +1,26 @@ +// +// UserText.swift +// +// 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 + +final class UserText { + // MARK: - Status Menu + + static let networkProtectionStatusMenuShareFeedback = NSLocalizedString("network.protection.status.menu.share.feedback", value: "Share Feedback...", comment: "The status menu 'Share Feedback' menu item") + static let networkProtectionStatusMenuOpenDuckDuckGo = NSLocalizedString("network.protection.status.menu.open.duckduckgo", value: "Open DuckDuckGo...", comment: "The status menu 'Open DuckDuckGo' menu item") +} diff --git a/LocalPackages/Account/Package.swift b/LocalPackages/Account/Package.swift index a994db0f39..f6355d4554 100644 --- a/LocalPackages/Account/Package.swift +++ b/LocalPackages/Account/Package.swift @@ -12,7 +12,7 @@ let package = Package( targets: ["Account"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.0.2"), .package(path: "../Purchase") ], targets: [ diff --git a/LocalPackages/BuildToolPlugins/Plugins/InputFilesChecker/InputFilesChecker.swift b/LocalPackages/BuildToolPlugins/Plugins/InputFilesChecker/InputFilesChecker.swift index 465cc664ac..e44a865b5d 100644 --- a/LocalPackages/BuildToolPlugins/Plugins/InputFilesChecker/InputFilesChecker.swift +++ b/LocalPackages/BuildToolPlugins/Plugins/InputFilesChecker/InputFilesChecker.swift @@ -52,7 +52,10 @@ let extraInputFiles: [TargetName: Set] = [ "DuckDuckGo DBP": nonSandboxedExtraInputFiles.union([ .init("DBPHomeViewController.swift", .source), - .init("DataBrokerProtectionManager.swift", .source) + .init("DataBrokerProtectionManager.swift", .source), + .init("DataBrokerProtectionLoginItemScheduler.swift", .source), + .init("LoginItem+DataBrokerProtection.swift", .source), + .init("DuckDuckGoDBPBackgroundAgent.app", .unknown), ]), "DuckDuckGo Privacy Pro": nonSandboxedExtraInputFiles, diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 2131c4f397..a1b92613a0 100644 --- a/LocalPackages/DataBrokerProtection/Package.swift +++ b/LocalPackages/DataBrokerProtection/Package.swift @@ -29,9 +29,10 @@ let package = Package( targets: ["DataBrokerProtection"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.0.2"), .package(path: "../PixelKit"), - .package(path: "../SwiftUIExtensions") + .package(path: "../SwiftUIExtensions"), + .package(path: "../XPCHelper") ], targets: [ .target( @@ -39,7 +40,8 @@ let package = Package( dependencies: [ .product(name: "BrowserServicesKit", package: "BrowserServicesKit"), .product(name: "PixelKit", package: "PixelKit"), - .product(name: "SwiftUIExtensions", package: "SwiftUIExtensions") + .product(name: "SwiftUIExtensions", package: "SwiftUIExtensions"), + .byName(name: "XPCHelper") ], resources: [.process("Resources")] ), diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Bundle/BundleExtension.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Bundle/BundleExtension.swift new file mode 100644 index 0000000000..33aa55dfed --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Bundle/BundleExtension.swift @@ -0,0 +1,33 @@ +// +// BundleExtension.swift +// +// 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 + +extension Bundle { + + struct Keys { + static let appGroup = "NETP_APP_GROUP" + } + + var appGroupName: String { + guard let appGroup = object(forInfoDictionaryKey: Keys.appGroup) as? String else { + fatalError("Info.plist is missing \(Keys.appGroup)") + } + return appGroup + } +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDataManager.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDataManager.swift index eee5f834f9..784935fa05 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDataManager.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDataManager.swift @@ -42,6 +42,7 @@ extension DataBrokerProtectionDataManaging { public protocol DataBrokerProtectionDataManagerDelegate: AnyObject { func dataBrokerProtectionDataManagerDidUpdateData() + func dataBrokerProtectionDataManagerDidDeleteData() } public class DataBrokerProtectionDataManager: DataBrokerProtectionDataManaging { @@ -53,6 +54,7 @@ public class DataBrokerProtectionDataManager: DataBrokerProtectionDataManaging { required public init(fakeBrokerFlag: DataBrokerDebugFlag = DataBrokerDebugFlagFakeBroker()) { self.database = DataBrokerProtectionDatabase(fakeBrokerFlag: fakeBrokerFlag) + cache.delegate = self } @@ -97,10 +99,14 @@ extension DataBrokerProtectionDataManager: InMemoryDataCacheDelegate { public func flushCache(profile: DataBrokerProtectionProfile?) async { guard let profile = profile else { return } await saveProfile(profile) + + delegate?.dataBrokerProtectionDataManagerDidUpdateData() } public func removeAllData() { database.deleteProfileData() + + delegate?.dataBrokerProtectionDataManagerDidDeleteData() } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift new file mode 100644 index 0000000000..0d36ca6eb3 --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift @@ -0,0 +1,141 @@ +// +// DataBrokerProtectionIPCClient.swift +// +// 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 Combine +import Foundation +import XPCHelper + +/// This protocol describes the server-side IPC interface for controlling the tunnel +/// +public protocol IPCClientInterface: AnyObject { + func schedulerStatusChanges(_ status: DataBrokerProtectionSchedulerStatus) +} + +/// This is the XPC interface with parameters that can be packed properly +@objc +protocol XPCClientInterface { + func schedulerStatusChanged(_ payload: Data) +} + +public final class DataBrokerProtectionIPCClient { + + // MARK: - XPC Communication + + let xpc: XPCClient + + // MARK: - Scheduler Status + + @Published + private(set) public var schedulerStatus: DataBrokerProtectionSchedulerStatus = .idle + + public var schedulerStatusPublisher: Published.Publisher { + $schedulerStatus + } + + // MARK: - Initializers + + public init(machServiceName: String) { + let clientInterface = NSXPCInterface(with: XPCClientInterface.self) + let serverInterface = NSXPCInterface(with: XPCServerInterface.self) + + xpc = XPCClient( + machServiceName: machServiceName, + clientInterface: clientInterface, + serverInterface: serverInterface) + + xpc.delegate = self + } +} + +// MARK: - Outgoing communication to the server + +extension DataBrokerProtectionIPCClient: IPCServerInterface { + + public func register() { + xpc.execute(call: { server in + server.register() + }, xpcReplyErrorHandler: { _ in + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! + }) + } + + public func startScheduler(showWebView: Bool) { + xpc.execute(call: { server in + server.startScheduler(showWebView: showWebView) + }, xpcReplyErrorHandler: { _ in + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! + }) + } + + public func stopScheduler() { + xpc.execute(call: { server in + server.stopScheduler() + }, xpcReplyErrorHandler: { _ in + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! + }) + } + + public func optOutAllBrokers(showWebView: Bool, completion: @escaping ((Error?) -> Void)) { + xpc.execute(call: { server in + server.optOutAllBrokers(showWebView: showWebView, completion: completion) + }, xpcReplyErrorHandler: { error in + completion(error) + }) + } + + public func scanAllBrokers(showWebView: Bool, completion: @escaping ((Error?) -> Void)) { + xpc.execute(call: { server in + server.scanAllBrokers(showWebView: showWebView, completion: completion) + }, xpcReplyErrorHandler: { error in + completion(error) + }) + } + + public func runQueuedOperations(showWebView: Bool, completion: @escaping ((Error?) -> Void)) { + xpc.execute(call: { server in + server.runQueuedOperations(showWebView: showWebView, completion: completion) + }, xpcReplyErrorHandler: { error in + completion(error) + }) + } + + public func runAllOperations(showWebView: Bool) { + xpc.execute(call: { server in + server.runAllOperations(showWebView: showWebView) + }, xpcReplyErrorHandler: { _ in + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! + }) + } +} + +// MARK: - Incoming communication from the server + +extension DataBrokerProtectionIPCClient: XPCClientInterface { + func schedulerStatusChanged(_ payload: Data) { + guard let status = try? JSONDecoder().decode(DataBrokerProtectionSchedulerStatus.self, from: payload) else { + + return + } + + schedulerStatus = status + } +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCScheduler.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCScheduler.swift new file mode 100644 index 0000000000..b69402626d --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCScheduler.swift @@ -0,0 +1,67 @@ +// +// DataBrokerProtectionIPCScheduler.swift +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import Combine +import Common + +/// A scheduler that works through IPC to request the scheduling to a different process +/// +public final class DataBrokerProtectionIPCScheduler: DataBrokerProtectionScheduler { + + private let ipcClient: DataBrokerProtectionIPCClient + + public init(ipcClient: DataBrokerProtectionIPCClient) { + self.ipcClient = ipcClient + } + + public var status: DataBrokerProtectionSchedulerStatus { + ipcClient.schedulerStatus + } + + public var statusPublisher: Published.Publisher { + ipcClient.schedulerStatusPublisher + } + + public func startScheduler(showWebView: Bool) { + ipcClient.startScheduler(showWebView: showWebView) + } + + public func stopScheduler() { + ipcClient.stopScheduler() + } + + public func optOutAllBrokers(showWebView: Bool, completion: ((Error?) -> Void)?) { + let completion = completion ?? { _ in } + ipcClient.optOutAllBrokers(showWebView: showWebView, completion: completion) + } + + public func scanAllBrokers(showWebView: Bool, completion: ((Error?) -> Void)?) { + let completion = completion ?? { _ in } + ipcClient.scanAllBrokers(showWebView: showWebView, completion: completion) + } + + public func runQueuedOperations(showWebView: Bool, completion: ((Error?) -> Void)?) { + let completion = completion ?? { _ in } + ipcClient.runQueuedOperations(showWebView: showWebView, completion: completion) + } + + public func runAllOperations(showWebView: Bool) { + ipcClient.runAllOperations(showWebView: showWebView) + } +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift new file mode 100644 index 0000000000..b0527a88e0 --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift @@ -0,0 +1,149 @@ +// +// TunnelControllerIPCServer.swift +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import XPCHelper + +/// This protocol describes the server-side IPC interface for controlling the tunnel +/// +public protocol IPCServerInterface: AnyObject { + /// Registers a connection with the server. + /// + /// This is the point where the server will start sending status updates to the client. + /// + func register() + + // MARK: - Scheduler + + /// Start the scheduler + /// + func startScheduler(showWebView: Bool) + + /// Stop the scheduler + /// + func stopScheduler() + + func optOutAllBrokers(showWebView: Bool, completion: @escaping ((Error?) -> Void)) + func scanAllBrokers(showWebView: Bool, completion: @escaping ((Error?) -> Void)) + func runQueuedOperations(showWebView: Bool, completion: @escaping ((Error?) -> Void)) + func runAllOperations(showWebView: Bool) +} + +/// This protocol describes the server-side XPC interface. +/// +/// The object that implements this interface takes care of unpacking any encoded data and forwarding +/// calls to the IPC interface when appropriate. +/// +@objc +protocol XPCServerInterface { + /// Registers a connection with the server. + /// + /// This is the point where the server will start sending status updates to the client. + /// + func register() + + // MARK: - Scheduler + + /// Start the scheduler + /// + func startScheduler(showWebView: Bool) + + /// Stop the scheduler + /// + func stopScheduler() + + func optOutAllBrokers(showWebView: Bool, completion: @escaping ((Error?) -> Void)) + func scanAllBrokers(showWebView: Bool, completion: @escaping ((Error?) -> Void)) + func runQueuedOperations(showWebView: Bool, completion: @escaping ((Error?) -> Void)) + func runAllOperations(showWebView: Bool) +} + +public final class DataBrokerProtectionIPCServer { + let xpc: XPCServer + + /// The delegate. + /// + public weak var serverDelegate: IPCServerInterface? + + public init(machServiceName: String) { + let clientInterface = NSXPCInterface(with: XPCClientInterface.self) + let serverInterface = NSXPCInterface(with: XPCServerInterface.self) + + xpc = XPCServer( + machServiceName: machServiceName, + clientInterface: clientInterface, + serverInterface: serverInterface) + + xpc.delegate = self + } + + public func activate() { + xpc.activate() + } +} + +// MARK: - Outgoing communication to the clients + +extension DataBrokerProtectionIPCServer: IPCClientInterface { + + public func schedulerStatusChanges(_ status: DataBrokerProtectionSchedulerStatus) { + let payload: Data + + do { + payload = try JSONEncoder().encode(status) + } catch { + return + } + + xpc.forEachClient { client in + client.schedulerStatusChanged(payload) + } + } +} + +// MARK: - Incoming communication from a client + +extension DataBrokerProtectionIPCServer: XPCServerInterface { + func register() { + serverDelegate?.register() + } + + func startScheduler(showWebView: Bool) { + serverDelegate?.startScheduler(showWebView: showWebView) + } + + func stopScheduler() { + serverDelegate?.stopScheduler() + } + + func optOutAllBrokers(showWebView: Bool, completion: @escaping ((Error?) -> Void)) { + serverDelegate?.optOutAllBrokers(showWebView: showWebView, completion: completion) + } + + func scanAllBrokers(showWebView: Bool, completion: @escaping ((Error?) -> Void)) { + serverDelegate?.scanAllBrokers(showWebView: showWebView, completion: completion) + } + + func runQueuedOperations(showWebView: Bool, completion: @escaping ((Error?) -> Void)) { + serverDelegate?.runQueuedOperations(showWebView: showWebView, completion: completion) + } + + func runAllOperations(showWebView: Bool) { + serverDelegate?.runAllOperations(showWebView: showWebView) + } +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Pixels/DataBrokerProtectionPixels.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Pixels/DataBrokerProtectionPixels.swift index 9e19a6f408..6e9a30759f 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Pixels/DataBrokerProtectionPixels.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Pixels/DataBrokerProtectionPixels.swift @@ -155,6 +155,7 @@ public enum DataBrokerProtectionPixels: Equatable { } extension DataBrokerProtectionPixels: PixelKitEvent { + public var name: String { switch self { case .parentChildMatches: return "dbp_macos_parent-child-broker-matches" @@ -227,3 +228,34 @@ extension DataBrokerProtectionPixels: PixelKitEvent { } } } + +public class DataBrokerProtectionPixelsHandler: EventMapping { + + public init() { + super.init { event, _, _, _ in + switch event { + case .error(let error, _): + PixelKit.fire(DebugEvent(event, error: error)) + case .parentChildMatches, + .optOutStart, + .optOutEmailGenerate, + .optOutCaptchaParse, + .optOutCaptchaSend, + .optOutCaptchaSolve, + .optOutSubmit, + .optOutEmailReceive, + .optOutEmailConfirm, + .optOutValidate, + .optOutFinish, + .optOutSubmitSuccess, + .optOutSuccess, + .optOutFailure: + PixelKit.fire(event) + } + } + } + + override init(mapping: @escaping EventMapping.Mapping) { + fatalError("Use init()") + } +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionNoOpScheduler.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionNoOpScheduler.swift new file mode 100644 index 0000000000..23e564a2c7 --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionNoOpScheduler.swift @@ -0,0 +1,41 @@ +// +// SwiftUIPreviewHelper.swift +// +// 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 + +/// Convenience class for SwiftUI previews. +/// +/// Do not use this for any production code. +/// +final class DataBrokerProtectionNoOpScheduler: DataBrokerProtectionScheduler { + + private(set) public var status: DataBrokerProtectionSchedulerStatus = .idle + + private var internalStatusPublisher: Published = .init(initialValue: .idle) + + public var statusPublisher: Published.Publisher { + internalStatusPublisher.projectedValue + } + + func startScheduler(showWebView: Bool) { } + func stopScheduler() { } + func optOutAllBrokers(showWebView: Bool, completion: ((Error?) -> Void)?) { } + func runQueuedOperations(showWebView: Bool, completion: ((Error?) -> Void)?) { } + func scanAllBrokers(showWebView: Bool, completion: ((Error?) -> Void)?) { } + func runAllOperations(showWebView: Bool) { } +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift index ba701bcbd2..b1468e0c19 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift @@ -21,22 +21,23 @@ import Common import BrowserServicesKit import Combine -public enum DataBrokerProtectionSchedulerStatus { +public enum DataBrokerProtectionSchedulerStatus: Codable { case stopped case idle case running } public protocol DataBrokerProtectionScheduler { - var statusPublisher: Published.Publisher { get } + var status: DataBrokerProtectionSchedulerStatus { get } + var statusPublisher: Published.Publisher { get } func startScheduler(showWebView: Bool) func stopScheduler() - func optOutAllBrokers(showWebView: Bool, completion: (() -> Void)?) - func scanAllBrokers(showWebView: Bool, completion: (() -> Void)?) - func runQueuedOperations(showWebView: Bool, completion: (() -> Void)?) + func optOutAllBrokers(showWebView: Bool, completion: ((Error?) -> Void)?) + func scanAllBrokers(showWebView: Bool, completion: ((Error?) -> Void)?) + func runQueuedOperations(showWebView: Bool, completion: ((Error?) -> Void)?) func runAllOperations(showWebView: Bool) } @@ -73,9 +74,13 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch private let emailService: EmailServiceProtocol private let captchaService: CaptchaServiceProtocol + /// Ensures that only one scheduler operation is executed at the same time. + /// + private let schedulerDispatchQueue = DispatchQueue(label: "schedulerDispatchQueue", qos: .default) + @Published public var status: DataBrokerProtectionSchedulerStatus = .stopped - public var statusPublisher: Published.Publisher { $status} + public var statusPublisher: Published.Publisher { $status } private lazy var dataBrokerProcessor: DataBrokerProtectionProcessor = { @@ -98,7 +103,6 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch pixelHandler: EventMapping, redeemUseCase: DataBrokerProtectionRedeemUseCase ) { - activity = NSBackgroundActivityScheduler(identifier: schedulerIdentifier) activity.repeats = true activity.interval = SchedulerCycle.interval @@ -149,22 +153,26 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch self.dataBrokerProcessor.runAllOperations(showWebView: showWebView) } - public func runQueuedOperations(showWebView: Bool = false, completion: (() -> Void)? = nil) { + public func runQueuedOperations(showWebView: Bool = false, completion: ((Error?) -> Void)? = nil) { os_log("Running queued operations...", log: .dataBrokerProtection) dataBrokerProcessor.runQueuedOperations(showWebView: showWebView, - completion: completion) + completion: { completion?(nil) }) } - public func scanAllBrokers(showWebView: Bool = false, completion: (() -> Void)? = nil) { + public func scanAllBrokers(showWebView: Bool = false, completion: ((Error?) -> Void)? = nil) { + stopScheduler() + os_log("Scanning all brokers...", log: .dataBrokerProtection) - self.dataBrokerProcessor.runAllScanOperations(showWebView: showWebView, - completion: completion) + dataBrokerProcessor.runAllScanOperations(showWebView: showWebView) { [weak self] in + self?.startScheduler(showWebView: showWebView) + completion?(nil) + } } - public func optOutAllBrokers(showWebView: Bool = false, completion: (() -> Void)?) { + public func optOutAllBrokers(showWebView: Bool = false, completion: ((Error?) -> Void)?) { os_log("Opting out all brokers...", log: .dataBrokerProtection) self.dataBrokerProcessor.runAllOptOutOperations(showWebView: showWebView, - completion: completion) + completion: { completion?(nil) }) } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionDatabaseProvider.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionDatabaseProvider.swift index 742c187ea5..71dc3219cd 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionDatabaseProvider.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionDatabaseProvider.swift @@ -79,11 +79,11 @@ protocol DataBrokerProtectionDatabaseProvider: SecureStorageDatabaseProvider { final class DefaultDataBrokerProtectionDatabaseProvider: GRDBSecureStorageDatabaseProvider, DataBrokerProtectionDatabaseProvider { public static func defaultDatabaseURL() -> URL { - return DefaultDataBrokerProtectionDatabaseProvider.databaseFilePath(directoryName: "DBP", fileName: "Vault.db") + return DefaultDataBrokerProtectionDatabaseProvider.databaseFilePath(directoryName: "DBP", fileName: "Vault.db", appGroupIdentifier: Bundle.main.appGroupName) } public init(file: URL = DefaultDataBrokerProtectionDatabaseProvider.defaultDatabaseURL(), key: Data) throws { - try super.init(file: file, key: key, writerType: .queue) { migrator in + try super.init(file: file, key: key, writerType: .pool) { migrator in migrator.registerMigration("v1", migrate: Self.migrateV1(database:)) migrator.registerMigration("v2", migrate: Self.migrateV2(database:)) migrator.registerMigration("v3", migrate: Self.migrateV3(database:)) diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionKeyStoreProvider.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionKeyStoreProvider.swift index 3f0ef57874..b9e39fc1a7 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionKeyStoreProvider.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionKeyStoreProvider.swift @@ -53,8 +53,9 @@ final class DataBrokerProtectionKeyStoreProvider: SecureStorageKeyStoreProvider func attributesForEntry(named: String, serviceName: String) -> [String: Any] { return [ kSecClass: kSecClassGenericPassword, - kSecUseDataProtectionKeychain: false, + kSecUseDataProtectionKeychain: true, kSecAttrSynchronizable: false, + kSecAttrAccessGroup: Bundle.main.appGroupName, kSecAttrAccount: named ] as [String: Any] } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/ContainerView/ContainerViewModel.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/ContainerView/ContainerViewModel.swift index f0725d61df..9479f9bd24 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/ContainerView/ContainerViewModel.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/ContainerView/ContainerViewModel.swift @@ -27,9 +27,8 @@ final class ContainerViewModel: ObservableObject { private let scheduler: DataBrokerProtectionScheduler private let dataManager: DataBrokerProtectionDataManaging - private var cancellables = Set() - @Published var schedulerStatus = "" + @Published var scanResults: ScanResult? @Published var showWebView = false @Published var useFakeBroker = false @Published var preventSchedulerStart = false @@ -40,41 +39,6 @@ final class ContainerViewModel: ObservableObject { self.dataManager = dataManager restoreFakeBrokerStatus() - setupCancellable() - } - - private func setupCancellable() { - scheduler.statusPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] status in - - switch status { - case .idle: - self?.schedulerStatus = "🟠 Idle" - case .running: - self?.schedulerStatus = "🟢 Running" - case .stopped: - self?.schedulerStatus = "🔴 Stopped" - } - }.store(in: &cancellables) - - $useFakeBroker - .receive(on: DispatchQueue.main) - .sink { value in - DataBrokerDebugFlagFakeBroker().setFlag(value) - }.store(in: &cancellables) - - $preventSchedulerStart - .receive(on: DispatchQueue.main) - .sink { value in - DataBrokerDebugFlagBlockScheduler().setFlag(value) - }.store(in: &cancellables) - - $showWebView - .receive(on: DispatchQueue.main) - .sink { value in - DataBrokerDebugFlagShowWebView().setFlag(value) - }.store(in: &cancellables) } private func restoreFakeBrokerStatus() { @@ -84,9 +48,12 @@ final class ContainerViewModel: ObservableObject { } func runQueuedOperationsAndStartScheduler() { - scheduler.runQueuedOperations(showWebView: showWebView) { [weak self] in - guard let self = self else { return } - self.scheduler.startScheduler(showWebView: self.showWebView) + scheduler.runQueuedOperations(showWebView: showWebView) { [scheduler] error in + guard error == nil else { + return + } + + scheduler.startScheduler(showWebView: self.showWebView) } } @@ -99,11 +66,7 @@ final class ContainerViewModel: ObservableObject { } func forceRunOptOuts() { - scheduler.optOutAllBrokers(showWebView: showWebView, completion: {}) - } - - func stopAllOperations() { - scheduler.stopScheduler() + scheduler.optOutAllBrokers(showWebView: showWebView, completion: nil) } func cleanData() { @@ -124,10 +87,8 @@ final class ContainerViewModel: ObservableObject { } private func scanAndUpdateUI(completion: @escaping (ScanResult) -> Void) { - scheduler.stopScheduler() - - scheduler.scanAllBrokers(showWebView: showWebView) { [weak self] in - guard let self = self else { return } + scheduler.scanAllBrokers(showWebView: self.showWebView) { [weak self] error in + guard error == nil, let self = self else { return } DispatchQueue.main.async { let hasResults = self.dataManager.hasMatches() diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/ContainerView/DataBrokerProtectionContainerView.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/ContainerView/DataBrokerProtectionContainerView.swift index 2f5c370467..6d033651d8 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/ContainerView/DataBrokerProtectionContainerView.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/ContainerView/DataBrokerProtectionContainerView.swift @@ -104,8 +104,6 @@ struct DataBrokerProtectionContainerView: View { @ViewBuilder private func debugUI() -> some View { VStack(alignment: .leading) { - Text("Scheduler status: \(containerViewModel.schedulerStatus)") - Toggle("Use Fake Broker", isOn: $containerViewModel.useFakeBroker) Toggle("Display WebViews", isOn: $containerViewModel.showWebView) @@ -164,7 +162,6 @@ struct DataBrokerProtectionContainerView: View { shouldShowDebugUI.toggle() }, editProfileClicked: { - containerViewModel.stopAllOperations() navigationViewModel.updateNavigation(.createProfile) }) .frame(height: 300) @@ -190,7 +187,7 @@ struct DataBrokerProtectionContainerView_Previews: PreviewProvider { let navigationViewModel = ContainerNavigationViewModel(dataManager: dataManager) let profileViewModel = ProfileViewModel(dataManager: dataManager) let resultsViewModel = ResultsViewModel(dataManager: dataManager) - let containerViewModel = ContainerViewModel(scheduler: PreviewScheduler(), dataManager: dataManager) + let containerViewModel = ContainerViewModel(scheduler: DataBrokerProtectionNoOpScheduler(), dataManager: dataManager) DataBrokerProtectionContainerView(containerViewModel: containerViewModel, navigationViewModel: navigationViewModel, diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/DataBrokerProtectionViewController.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/DataBrokerProtectionViewController.swift index b27e400acb..3de3da7b69 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/DataBrokerProtectionViewController.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/DataBrokerProtectionViewController.swift @@ -67,7 +67,6 @@ final public class DataBrokerProtectionViewController: NSViewController { webView?.load(URL(string: Constants.dbpUiUrl)!) } - } extension DataBrokerProtectionViewController: WKUIDelegate { diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/SwiftUIPreviewHelper.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/SwiftUIPreviewHelper.swift index 46f0a81046..ab560bf0f3 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/SwiftUIPreviewHelper.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/SwiftUIPreviewHelper.swift @@ -18,21 +18,6 @@ import Foundation -final class PreviewScheduler: DataBrokerProtectionScheduler { - @Published public var status: DataBrokerProtectionSchedulerStatus = .stopped - public var statusPublisher: Published.Publisher { $status} - - internal init() { - self.status = .idle - } - func startScheduler(showWebView: Bool) { } - func stopScheduler() { } - func optOutAllBrokers(showWebView: Bool, completion: (() -> Void)?) { } - func runQueuedOperations(showWebView: Bool, completion: (() -> Void)?) { } - func scanAllBrokers(showWebView: Bool, completion: (() -> Void)?) { } - func runAllOperations(showWebView: Bool) { } -} - final class PreviewDataManager: DataBrokerProtectionDataManaging { var delegate: DataBrokerProtectionDataManagerDelegate? diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Utils/Logging.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Utils/Logging.swift index 0152520aa1..7216eaa79b 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Utils/Logging.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Utils/Logging.swift @@ -34,6 +34,12 @@ struct Logging { fileprivate static let errorsLoggingEnabled = true fileprivate static let error: OSLog = OSLog(subsystem: subsystem, category: "Data Broker Protection Errors") + + fileprivate static let backgroundAgentLoggingEnabled = true + fileprivate static let backgroundAgent: OSLog = OSLog(subsystem: subsystem, category: "Data Broker Protection Background Agent") + + fileprivate static let backgroundAgentMemoryManagementLoggingEnabled = true + fileprivate static let backgroundAgentMemoryManagement: OSLog = OSLog(subsystem: subsystem, category: "Data Broker Protection Background Agent Memory Management") } extension OSLog { @@ -53,4 +59,12 @@ extension OSLog { public static var error: OSLog { Logging.errorsLoggingEnabled ? Logging.error : .disabled } + + public static var dbpBackgroundAgent: OSLog { + Logging.backgroundAgentLoggingEnabled ? Logging.backgroundAgent : .disabled + } + + public static var dbpBackgroundAgentMemoryManagement: OSLog { + Logging.backgroundAgentMemoryManagementLoggingEnabled ? Logging.backgroundAgentMemoryManagement : .disabled + } } diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index d8949c19a8..d92b60d263 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.0.2"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions") ], diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionIPC/TunnelControllerIPCClient.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionIPC/TunnelControllerIPCClient.swift index 8143bc7ca9..7479b0e8cf 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionIPC/TunnelControllerIPCClient.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionIPC/TunnelControllerIPCClient.swift @@ -69,19 +69,41 @@ public final class TunnelControllerIPCClient { extension TunnelControllerIPCClient: IPCServerInterface { public func register() { - try? xpc.server().register() + xpc.execute(call: { server in + server.register() + }, xpcReplyErrorHandler: { _ in + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! + }) } public func start() { - try? xpc.server().start() + xpc.execute(call: { server in + server.start() + }, xpcReplyErrorHandler: { _ in + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! + }) } public func stop() { - try? xpc.server().stop() + xpc.execute(call: { server in + server.stop() + }, xpcReplyErrorHandler: { _ in + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! + }) } public func resetAll(uninstallSystemExtension: Bool) async { - try? await xpc.server().resetAll(uninstallSystemExtension: uninstallSystemExtension) + xpc.execute(call: { server in + Task { + await server.resetAll(uninstallSystemExtension: uninstallSystemExtension) + } + }, xpcReplyErrorHandler: { _ in + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! + }) } public func debugCommand(_ command: DebugCommand) async { @@ -89,7 +111,14 @@ extension TunnelControllerIPCClient: IPCServerInterface { return } - try? await xpc.server().debugCommand(payload) + xpc.execute(call: { server in + Task { + await server.debugCommand(payload) + } + }, xpcReplyErrorHandler: { _ in + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! + }) } } diff --git a/LocalPackages/PixelKit/Package.swift b/LocalPackages/PixelKit/Package.swift index a12cae821d..0670c3b292 100644 --- a/LocalPackages/PixelKit/Package.swift +++ b/LocalPackages/PixelKit/Package.swift @@ -26,7 +26,10 @@ let package = Package( dependencies: []), .testTarget( name: "PixelKitTests", - dependencies: ["PixelKit", "PixelKitTestingUtilities"]), + dependencies: ["PixelKit", "PixelKitTestingUtilities"], + swiftSettings: [ + .define("DEBUG", .when(configuration: .debug)) + ]), .target( name: "PixelKitTestingUtilities", dependencies: ["PixelKit"]) diff --git a/LocalPackages/PixelKit/Sources/PixelKit/PixelKit.swift b/LocalPackages/PixelKit/Sources/PixelKit/PixelKit.swift index 8eeff1bec2..652096636b 100644 --- a/LocalPackages/PixelKit/Sources/PixelKit/PixelKit.swift +++ b/LocalPackages/PixelKit/Sources/PixelKit/PixelKit.swift @@ -161,7 +161,7 @@ public final class PixelKit { } public func fire(_ event: Event, - frequency: Frequency, + frequency: Frequency = .standard, withHeaders headers: [String: String]? = nil, withAdditionalParameters params: [String: String]? = nil, allowedQueryReservedCharacters: CharacterSet? = nil, @@ -199,7 +199,7 @@ public final class PixelKit { } public static func fire(_ event: Event, - frequency: Frequency, + frequency: Frequency = .standard, withHeaders headers: [String: String] = [:], withAdditionalParameters parameters: [String: String]? = nil, allowedQueryReservedCharacters: CharacterSet? = nil, diff --git a/LocalPackages/PixelKit/Sources/PixelKit/PixelKitEvent.swift b/LocalPackages/PixelKit/Sources/PixelKit/PixelKitEvent.swift index 3b4fea332e..8ae297cac9 100644 --- a/LocalPackages/PixelKit/Sources/PixelKit/PixelKitEvent.swift +++ b/LocalPackages/PixelKit/Sources/PixelKit/PixelKitEvent.swift @@ -41,6 +41,11 @@ public final class DebugEvent: PixelKitEvent { self.error = error } + public init(_ event: PixelKitEvent, error: Error? = nil) { + self.eventType = .custom(event) + self.error = error + } + public var name: String { switch eventType { case .assertionFailure: diff --git a/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift b/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift index cf00a8228b..db24a9277b 100644 --- a/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift +++ b/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift @@ -52,7 +52,7 @@ final class PixelKitTests: XCTestCase { } } - var frequency: PixelKitEventFrequency { + var frequency: PixelKit.Frequency { switch self { case .testEvent, .testEventWithoutParameters: return .standard @@ -111,7 +111,11 @@ final class PixelKitTests: XCTestCase { XCTAssertEqual(firedHeaders[PixelKit.Header.moreInfo], "See \(PixelKit.duckDuckGoMorePrivacyInfo)") XCTAssertEqual(parameters[PixelKit.Parameters.appVersion], appVersion) +#if DEBUG XCTAssertEqual(parameters[PixelKit.Parameters.test], PixelKit.Values.test) +#else + XCTAssertNil(parameters[PixelKit.Parameters.test]) +#endif } // Run test @@ -153,11 +157,15 @@ final class PixelKitTests: XCTestCase { XCTAssertEqual(firedHeaders[PixelKit.Header.moreInfo], expectedMoreInfoString) XCTAssertEqual(parameters[PixelKit.Parameters.appVersion], appVersion) +#if DEBUG XCTAssertEqual(parameters[PixelKit.Parameters.test], PixelKit.Values.test) +#else + XCTAssertNil(parameters[PixelKit.Parameters.test]) +#endif } // Run test - pixelKit.fire(event) + pixelKit.fire(event, frequency: .dailyOnly) // Wait for expectations to be fulfilled wait(for: [fireCallbackCalled], timeout: 0.5) @@ -197,12 +205,16 @@ final class PixelKitTests: XCTestCase { XCTAssertEqual(firedHeaders[PixelKit.Header.moreInfo], expectedMoreInfoString) XCTAssertEqual(parameters[PixelKit.Parameters.appVersion], appVersion) +#if DEBUG XCTAssertEqual(parameters[PixelKit.Parameters.test], PixelKit.Values.test) +#else + XCTAssertNil(parameters[PixelKit.Parameters.test]) +#endif } // Run test - pixelKit.fire(event) - pixelKit.fire(event) + pixelKit.fire(event, frequency: .dailyOnly) + pixelKit.fire(event, frequency: .dailyOnly) // Wait for expectations to be fulfilled wait(for: [fireCallbackCalled], timeout: 0.5) diff --git a/LocalPackages/XPCHelper/Sources/XPCHelper/XPCClient.swift b/LocalPackages/XPCHelper/Sources/XPCHelper/XPCClient.swift index dfd46b090d..c263fe2e09 100644 --- a/LocalPackages/XPCHelper/Sources/XPCHelper/XPCClient.swift +++ b/LocalPackages/XPCHelper/Sources/XPCHelper/XPCClient.swift @@ -97,11 +97,35 @@ public final class XPCClient ServerInterface { - guard let server = connection.remoteObjectProxy as? ServerInterface else { - throw ConnectionError.noRemoteObjectProxy + /// This is quite obscure, but XPC services with a completion block don't execute their completion block + /// if the XPC endpoint isn't running. The error handler block below detects errors while waiting for a reply. + /// + /// Refs: + /// https://developer.apple.com/forums/thread/713429?answerId=725930022#725930022 + /// + /// + /// + public func server(xpcReplyErrorHandler: @escaping (Error) -> Void) -> ServerInterface? { + connection.remoteObjectProxyWithErrorHandler({ error in + xpcReplyErrorHandler(error) + }) as? ServerInterface + } + + public func execute(call: (ServerInterface) -> Void, xpcReplyErrorHandler: @escaping (Error) -> Void) { + guard let serverInterface = connection.remoteObjectProxyWithErrorHandler({ error in + // This will be called if there's an error while waiting for an XPC response. + // Ref: https://developer.apple.com/documentation/foundation/nsxpcproxycreating/1415611-remoteobjectproxywitherrorhandle + // + // Since when there's an error while waiting for a response a completion callback will not be called, this + // allows us to call the completion callback ourselves. + xpcReplyErrorHandler(error) + }) as? ServerInterface else { + // This won't collide with the error handling above, as if this error happens there won't be any XPC + // request to begin with. + xpcReplyErrorHandler(ConnectionError.noRemoteObjectProxy) + return } - return server + call(serverInterface) } } diff --git a/scripts/assets/ExportOptions.plist b/scripts/assets/ExportOptions.plist index ac199e54dd..2c9c93bf58 100644 --- a/scripts/assets/ExportOptions.plist +++ b/scripts/assets/ExportOptions.plist @@ -18,6 +18,10 @@ Sandbox MacOS Browser Release com.duckduckgo.mobile.ios.review Sandbox MacOS Browser Product Review + com.duckduckgo.macos.DBP.backgroundAgent + macOS DBP Agent - Release + com.duckduckgo.macos.DBP.backgroundAgent.review + macOS DBP Agent - Review com.duckduckgo.macos.vpn.network-extension macOS NetP VPN SysEx - Release (XPC) com.duckduckgo.macos.vpn.network-extension.review