diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 82841761e4..98daa3292d 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -134,7 +134,6 @@ 1DFAB5232A8983E100A0F7F6 /* SetExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DFAB51F2A89830D00A0F7F6 /* SetExtensionTests.swift */; }; 1E0C72062ABC63BD00802009 /* SubscriptionPagesUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0C72052ABC63BD00802009 /* SubscriptionPagesUserScript.swift */; }; 1E0C72072ABC63BD00802009 /* SubscriptionPagesUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0C72052ABC63BD00802009 /* SubscriptionPagesUserScript.swift */; }; - 1E46E1A02BD029BD0007273A /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = 1E46E19F2BD029BD0007273A /* Subscription */; }; 1E559BB12BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E559BB02BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift */; }; 1E559BB22BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E559BB02BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift */; }; 1E7E2E9029029A2A00C01B54 /* ContentBlockingRulesUpdateObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7E2E8F29029A2A00C01B54 /* ContentBlockingRulesUpdateObserver.swift */; }; @@ -611,7 +610,7 @@ 3706FC71293F65D500E42796 /* NSColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F41D174025CB131900472416 /* NSColorExtension.swift */; }; 3706FC73293F65D500E42796 /* AddressBarButtonsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4F525D6BF2C007F5990 /* AddressBarButtonsViewController.swift */; }; 3706FC77293F65D500E42796 /* PageObserverUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 853014D525E671A000FB8205 /* PageObserverUserScript.swift */; }; - 3706FC78293F65D500E42796 /* SecureVaultErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B642738127B65BAC0005DFD1 /* SecureVaultErrorReporter.swift */; }; + 3706FC78293F65D500E42796 /* SecureVaultReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B642738127B65BAC0005DFD1 /* SecureVaultReporter.swift */; }; 3706FC79293F65D500E42796 /* NSImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B139AFC26B60BD800894F82 /* NSImageExtensions.swift */; }; 3706FC7B293F65D500E42796 /* PasswordManagementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85625995269C953C00EE44BC /* PasswordManagementViewController.swift */; }; 3706FC7C293F65D500E42796 /* ImportedBookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CFA26FE191E001E4761 /* ImportedBookmarks.swift */; }; @@ -947,7 +946,6 @@ 373A1AB228451ED400586521 /* BookmarksHTMLImporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A1AB128451ED400586521 /* BookmarksHTMLImporterTests.swift */; }; 373D9B4829EEAC1B00381FDD /* SyncMetadataDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373D9B4729EEAC1B00381FDD /* SyncMetadataDatabase.swift */; }; 373D9B4929EEAC1B00381FDD /* SyncMetadataDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373D9B4729EEAC1B00381FDD /* SyncMetadataDatabase.swift */; }; - 373FB4B12B4D6C42004C88D6 /* PreferencesViews in Frameworks */ = {isa = PBXBuildFile; productRef = 373FB4B02B4D6C42004C88D6 /* PreferencesViews */; }; 373FB4B32B4D6C4B004C88D6 /* PreferencesViews in Frameworks */ = {isa = PBXBuildFile; productRef = 373FB4B22B4D6C4B004C88D6 /* PreferencesViews */; }; 37445F992A1566420029F789 /* SyncDataProviders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37445F982A1566420029F789 /* SyncDataProviders.swift */; }; 37445F9A2A1566420029F789 /* SyncDataProviders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37445F982A1566420029F789 /* SyncDataProviders.swift */; }; @@ -1028,8 +1026,6 @@ 37CD54D027F2FDD100F1F7B9 /* DefaultBrowserPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54C827F2FDD100F1F7B9 /* DefaultBrowserPreferences.swift */; }; 37CEFCA92A6737A2001EF741 /* CredentialsCleanupErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CEFCA82A6737A2001EF741 /* CredentialsCleanupErrorHandling.swift */; }; 37CEFCAA2A6737A2001EF741 /* CredentialsCleanupErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CEFCA82A6737A2001EF741 /* CredentialsCleanupErrorHandling.swift */; }; - 37CF91592BB416A500BADCAE /* Crashes in Frameworks */ = {isa = PBXBuildFile; productRef = 37CF91582BB416A500BADCAE /* Crashes */; }; - 37CF915B2BB416AC00BADCAE /* Crashes in Frameworks */ = {isa = PBXBuildFile; productRef = 37CF915A2BB416AC00BADCAE /* Crashes */; }; 37D2377A287EB8CA00BCE03B /* TabIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D23779287EB8CA00BCE03B /* TabIndex.swift */; }; 37D2377C287EBDA300BCE03B /* TabIndexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D2377B287EBDA300BCE03B /* TabIndexTests.swift */; }; 37D23780287EFEE200BCE03B /* PinnedTabsManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D2377F287EFEE200BCE03B /* PinnedTabsManagerTests.swift */; }; @@ -1080,7 +1076,6 @@ 4B1E6EF227AB5E5D00F51793 /* PasswordManagementItemList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E6EF027AB5E5D00F51793 /* PasswordManagementItemList.swift */; }; 4B25375B2A11BE7300610219 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B4D603E2A0B290200BCD287 /* NetworkExtension.framework */; }; 4B2537722A11BF8B00610219 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B25376F2A11BF8B00610219 /* main.swift */; }; - 4B2537772A11BFE100610219 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4B2537762A11BFE100610219 /* PixelKit */; }; 4B25377A2A11C01700610219 /* UserText+NetworkProtectionExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D607C2A0B29FA00BCD287 /* UserText+NetworkProtectionExtensions.swift */; }; 4B29759728281F0900187C4E /* FirefoxEncryptionKeyReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B29759628281F0900187C4E /* FirefoxEncryptionKeyReader.swift */; }; 4B2975992828285900187C4E /* FirefoxKeyReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2975982828285900187C4E /* FirefoxKeyReaderTests.swift */; }; @@ -1143,7 +1138,6 @@ 4B4BEC482A11B61F001D9AC5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4B4BEC342A11B509001D9AC5 /* Assets.xcassets */; }; 4B4D603F2A0B290200BCD287 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B4D603E2A0B290200BCD287 /* NetworkExtension.framework */; }; 4B4D60892A0B2A1C00BCD287 /* NetworkProtectionUNNotificationsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60762A0B29FA00BCD287 /* NetworkProtectionUNNotificationsPresenter.swift */; }; - 4B4D60982A0B2A5C00BCD287 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4B4D60972A0B2A5C00BCD287 /* PixelKit */; }; 4B4D609F2A0B2C7300BCD287 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85799C1725DEBB3F0007EC87 /* Logging.swift */; }; 4B4D60A02A0B2D5B00BCD287 /* Bundle+VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605E2A0B29FA00BCD287 /* Bundle+VPN.swift */; }; 4B4D60A12A0B2D6100BCD287 /* NetworkProtectionOptionKeyExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605F2A0B29FA00BCD287 /* NetworkProtectionOptionKeyExtension.swift */; }; @@ -1210,8 +1204,6 @@ 4B7534CC2A1FD7EA00158A99 /* NetworkProtectionInviteDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606C2A0B29FA00BCD287 /* NetworkProtectionInviteDialog.swift */; }; 4B7A57CF279A4EF300B1C70E /* ChromiumPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7A57CE279A4EF300B1C70E /* ChromiumPreferences.swift */; }; 4B7A60A1273E0BE400BBDFEB /* WKWebsiteDataStoreExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7A60A0273E0BE400BBDFEB /* WKWebsiteDataStoreExtension.swift */; }; - 4B81AD352B29512B00706C96 /* PixelKitTestingUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = 4B81AD342B29512B00706C96 /* PixelKitTestingUtilities */; }; - 4B81AD372B29513100706C96 /* PixelKitTestingUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = 4B81AD362B29513100706C96 /* PixelKitTestingUtilities */; }; 4B85A48028821CC500FC4C39 /* NSPasteboardItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B85A47F28821CC500FC4C39 /* NSPasteboardItemExtension.swift */; }; 4B8A4DFF27C83B29005F40E8 /* SaveIdentityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8A4DFE27C83B29005F40E8 /* SaveIdentityViewController.swift */; }; 4B8A4E0127C8447E005F40E8 /* SaveIdentityPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8A4E0027C8447E005F40E8 /* SaveIdentityPopover.swift */; }; @@ -1483,8 +1475,6 @@ 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 */; }; 7B624F172BA25C1F00A6C544 /* NetworkProtectionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 7B624F162BA25C1F00A6C544 /* NetworkProtectionUI */; }; 7B7DFB202B7E736B009EA1A3 /* MacPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */; }; 7B7DFB222B7E7473009EA1A3 /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 7B7DFB212B7E7473009EA1A3 /* Networking */; }; @@ -1499,7 +1489,6 @@ 7B97CD5E2B7E0BEA004FEF43 /* OptionalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B637273C26CCF0C200C8CB02 /* OptionalExtension.swift */; }; 7B97CD5F2B7E0BF7004FEF43 /* NSApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5C8F622591021700748EB7 /* NSApplicationExtension.swift */; }; 7B97CD602B7E0C2E004FEF43 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85799C1725DEBB3F0007EC87 /* Logging.swift */; }; - 7B97CD622B7E0C4B004FEF43 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B97CD612B7E0C4B004FEF43 /* PixelKit */; }; 7BA076BB2B65D61400D7FB72 /* NetworkProtectionProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 7BA076BA2B65D61400D7FB72 /* NetworkProtectionProxy */; }; 7BA4727D26F01BC400EAA165 /* CoreDataTestUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292C42667104B00AD2C21 /* CoreDataTestUtilities.swift */; }; 7BA59C9B2AE18B49009A97B1 /* SystemExtensionManager in Frameworks */ = {isa = PBXBuildFile; productRef = 7BA59C9A2AE18B49009A97B1 /* SystemExtensionManager */; }; @@ -1538,10 +1527,6 @@ 7BBD45B12A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */; }; 7BBD45B22A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */; }; 7BBE2B7B2B61663C00697445 /* NetworkProtectionProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 7BBE2B7A2B61663C00697445 /* NetworkProtectionProxy */; }; - 7BBE650D2BC67BA0008F4EE9 /* NetworkProtectionIPCTunnelControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBE650C2BC67BA0008F4EE9 /* NetworkProtectionIPCTunnelControllerTests.swift */; }; - 7BBE650E2BC67BA0008F4EE9 /* NetworkProtectionIPCTunnelControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBE650C2BC67BA0008F4EE9 /* NetworkProtectionIPCTunnelControllerTests.swift */; }; - 7BBE65102BC67EED008F4EE9 /* NetworkProtectionTestingSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBE650F2BC67EED008F4EE9 /* NetworkProtectionTestingSupport.swift */; }; - 7BBE65112BC67EED008F4EE9 /* NetworkProtectionTestingSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBE650F2BC67EED008F4EE9 /* NetworkProtectionTestingSupport.swift */; }; 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 */; }; @@ -1557,8 +1542,6 @@ 7BEEA5122AD1235B00A9E72B /* NetworkProtectionIPC in Frameworks */ = {isa = PBXBuildFile; productRef = 7BEEA5112AD1235B00A9E72B /* NetworkProtectionIPC */; }; 7BEEA5142AD1236300A9E72B /* NetworkProtectionIPC in Frameworks */ = {isa = PBXBuildFile; productRef = 7BEEA5132AD1236300A9E72B /* NetworkProtectionIPC */; }; 7BEEA5162AD1236E00A9E72B /* NetworkProtectionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 7BEEA5152AD1236E00A9E72B /* NetworkProtectionUI */; }; - 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 */; }; 7BFE95542A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */; }; 7BFE95552A9DF2990081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */; }; @@ -1683,8 +1666,6 @@ 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 */; }; 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 */; }; @@ -1701,7 +1682,6 @@ 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 */; }; - 9DB6E7242AA0DC5800A17F3C /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = 9DB6E7232AA0DC5800A17F3C /* LoginItems */; }; 9DC70B1A2AA1FA5B005A844B /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = 9DC70B192AA1FA5B005A844B /* LoginItems */; }; 9DEF97E12B06C4EE00764F03 /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 9DEF97E02B06C4EE00764F03 /* Networking */; }; 9F0A2CF82B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0A2CF72B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift */; }; @@ -2058,7 +2038,7 @@ B63ED0E026AFE32F00A9DAD1 /* GeolocationProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63ED0DF26AFE32F00A9DAD1 /* GeolocationProviderMock.swift */; }; B63ED0E326B3E7FA00A9DAD1 /* CLLocationManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63ED0E226B3E7FA00A9DAD1 /* CLLocationManagerMock.swift */; }; B63ED0E526BB8FB900A9DAD1 /* SharingMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63ED0E426BB8FB900A9DAD1 /* SharingMenu.swift */; }; - B642738227B65BAC0005DFD1 /* SecureVaultErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B642738127B65BAC0005DFD1 /* SecureVaultErrorReporter.swift */; }; + B642738227B65BAC0005DFD1 /* SecureVaultReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B642738127B65BAC0005DFD1 /* SecureVaultReporter.swift */; }; B643BF1427ABF772000BACEC /* NSWorkspaceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B643BF1327ABF772000BACEC /* NSWorkspaceExtension.swift */; }; B644B43D29D56829003FA9AB /* SearchNonexistentDomainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B644B43929D565DB003FA9AB /* SearchNonexistentDomainTests.swift */; }; B644B43E29D5682B003FA9AB /* SearchNonexistentDomainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B644B43929D565DB003FA9AB /* SearchNonexistentDomainTests.swift */; }; @@ -2526,6 +2506,9 @@ EEDE50122BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDE50102BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift */; }; EEF12E6F2A2111880023E6BF /* MacPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */; }; EEF53E182950CED5002D78F4 /* JSAlertViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */; }; + F116A7C32BD1924B00F3FCF7 /* PixelKitTestingUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = F116A7C22BD1924B00F3FCF7 /* PixelKitTestingUtilities */; }; + F116A7C72BD1925500F3FCF7 /* PixelKitTestingUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = F116A7C62BD1925500F3FCF7 /* PixelKitTestingUtilities */; }; + F116A7C92BD1929000F3FCF7 /* PixelKitTestingUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = F116A7C82BD1929000F3FCF7 /* PixelKitTestingUtilities */; }; F188267C2BBEB3AA00D9AC4F /* GeneralPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F188267B2BBEB3AA00D9AC4F /* GeneralPixel.swift */; }; F188267D2BBEB3AA00D9AC4F /* GeneralPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F188267B2BBEB3AA00D9AC4F /* GeneralPixel.swift */; }; F18826802BBEB58100D9AC4F /* PrivacyProPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F188267F2BBEB58100D9AC4F /* PrivacyProPixel.swift */; }; @@ -2538,6 +2521,14 @@ F18826912BC0105800D9AC4F /* PixelDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44012616B28300DD1EC2 /* PixelDataStore.swift */; }; F18826922BC0105900D9AC4F /* PixelDataRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68C92C32750EF76002AC6B0 /* PixelDataRecord.swift */; }; F18826932BC0105900D9AC4F /* PixelDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44012616B28300DD1EC2 /* PixelDataStore.swift */; }; + F198C7122BD18A28000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C7112BD18A28000BF24D /* PixelKit */; }; + F198C7142BD18A30000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C7132BD18A30000BF24D /* PixelKit */; }; + F198C7162BD18A44000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C7152BD18A44000BF24D /* PixelKit */; }; + F198C7182BD18A4C000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C7172BD18A4C000BF24D /* PixelKit */; }; + F198C71A2BD18A5B000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C7192BD18A5B000BF24D /* PixelKit */; }; + F198C71C2BD18A61000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C71B2BD18A61000BF24D /* PixelKit */; }; + F198C71E2BD18D88000BF24D /* SwiftLintTool in Frameworks */ = {isa = PBXBuildFile; productRef = F198C71D2BD18D88000BF24D /* SwiftLintTool */; }; + F198C7202BD18D92000BF24D /* SwiftLintTool in Frameworks */ = {isa = PBXBuildFile; productRef = F198C71F2BD18D92000BF24D /* SwiftLintTool */; }; F1B33DF22BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */; }; F1B33DF32BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */; }; F1B33DF62BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF52BAD970E001128B3 /* SubscriptionErrorReporter.swift */; }; @@ -2546,6 +2537,10 @@ F1D43AEF2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */; }; F1D43AF32B98E47800BAB743 /* BareBonesBrowserKit in Frameworks */ = {isa = PBXBuildFile; productRef = F1D43AF22B98E47800BAB743 /* BareBonesBrowserKit */; }; F1D43AF52B98E48900BAB743 /* BareBonesBrowserKit in Frameworks */ = {isa = PBXBuildFile; productRef = F1D43AF42B98E48900BAB743 /* BareBonesBrowserKit */; }; + F1DF95E32BD1807C0045E591 /* Crashes in Frameworks */ = {isa = PBXBuildFile; productRef = 08D4923DC968236E22E373E2 /* Crashes */; }; + F1DF95E42BD1807C0045E591 /* Crashes in Frameworks */ = {isa = PBXBuildFile; productRef = 537FC71EA5115A983FAF3170 /* Crashes */; }; + F1DF95E52BD1807C0045E591 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = DC3F73D49B2D44464AFEFCD8 /* Subscription */; }; + F1DF95E72BD188B60045E591 /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = F1DF95E62BD188B60045E591 /* LoginItems */; }; F41D174125CB131900472416 /* NSColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F41D174025CB131900472416 /* NSColorExtension.swift */; }; F44C130225C2DA0400426E3E /* NSAppearanceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F44C130125C2DA0400426E3E /* NSAppearanceExtension.swift */; }; F4A6198C283CFFBB007F2080 /* ContentScopeFeatureFlagging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4A6198B283CFFBB007F2080 /* ContentScopeFeatureFlagging.swift */; }; @@ -3182,7 +3177,6 @@ 4BD57C032AC112DF00B580EE /* NetworkProtectionRemoteMessagingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRemoteMessagingTests.swift; sourceTree = ""; }; 4BDFA4AD27BF19E500648192 /* ToggleableScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleableScrollView.swift; sourceTree = ""; }; 4BE0DF0426781961006337B7 /* NSStoryboardExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSStoryboardExtension.swift; sourceTree = ""; }; - 4BE15DB12A0B0DD500898243 /* PixelKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = PixelKit; sourceTree = ""; }; 4BE344ED2B2376DF003FC223 /* VPNFeedbackFormViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNFeedbackFormViewModelTests.swift; sourceTree = ""; }; 4BE4005227CF3DC3007D3161 /* SavePaymentMethodPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavePaymentMethodPopover.swift; sourceTree = ""; }; 4BE4005427CF3F19007D3161 /* SavePaymentMethodViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavePaymentMethodViewController.swift; sourceTree = ""; }; @@ -3279,8 +3273,6 @@ 7BB108582A43375D000AB95F /* PFMoveApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFMoveApplication.m; sourceTree = ""; }; 7BBA7CE52BAB03C1007579A3 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift"; sourceTree = ""; }; 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionDebugUtilities.swift; sourceTree = ""; }; - 7BBE650C2BC67BA0008F4EE9 /* NetworkProtectionIPCTunnelControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionIPCTunnelControllerTests.swift; sourceTree = ""; }; - 7BBE650F2BC67EED008F4EE9 /* NetworkProtectionTestingSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionTestingSupport.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 = ""; }; @@ -3687,7 +3679,7 @@ B63ED0DF26AFE32F00A9DAD1 /* GeolocationProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeolocationProviderMock.swift; sourceTree = ""; }; B63ED0E226B3E7FA00A9DAD1 /* CLLocationManagerMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLLocationManagerMock.swift; sourceTree = ""; }; B63ED0E426BB8FB900A9DAD1 /* SharingMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingMenu.swift; sourceTree = ""; }; - B642738127B65BAC0005DFD1 /* SecureVaultErrorReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureVaultErrorReporter.swift; sourceTree = ""; }; + B642738127B65BAC0005DFD1 /* SecureVaultReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureVaultReporter.swift; sourceTree = ""; }; B643BF1327ABF772000BACEC /* NSWorkspaceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSWorkspaceExtension.swift; sourceTree = ""; }; B644B43929D565DB003FA9AB /* SearchNonexistentDomainTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchNonexistentDomainTests.swift; sourceTree = ""; }; B645D8F529FA95440024461F /* WKProcessPoolExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKProcessPoolExtension.swift; sourceTree = ""; }; @@ -3999,8 +3991,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F1DF95E42BD1807C0045E591 /* Crashes in Frameworks */, 373FB4B32B4D6C4B004C88D6 /* PreferencesViews in Frameworks */, - 7B5F9A752AE2BE4E002AEBC0 /* PixelKit in Frameworks */, 4BF97AD32B43C43F00EB4240 /* NetworkProtectionUI in Frameworks */, 7B1459572B7D43E500047F2C /* NetworkProtectionProxy in Frameworks */, B6F7128229F6820A00594A45 /* QuickLookUI.framework in Frameworks */, @@ -4009,10 +4001,12 @@ 37A5E2F0298AA1B20047046B /* Persistence in Frameworks */, 9DC70B1A2AA1FA5B005A844B /* LoginItems in Frameworks */, 37269EFD2B332FAC005E8E46 /* Common in Frameworks */, + F198C7142BD18A30000BF24D /* PixelKit in Frameworks */, F1D43AF52B98E48900BAB743 /* BareBonesBrowserKit in Frameworks */, 378F44E629B4BDEE00899924 /* SwiftUIExtensions in Frameworks */, 3706FCA7293F65D500E42796 /* BrowserServicesKit in Frameworks */, 3129788A2B64131200B67619 /* DataBrokerProtection in Frameworks */, + F198C7202BD18D92000BF24D /* SwiftLintTool in Frameworks */, 4BCBE4582BA7E17800FC75A1 /* SubscriptionUI in Frameworks */, 3706FCA9293F65D500E42796 /* ContentBlocking in Frameworks */, 85D44B882BA08D30001B4AB5 /* Suggestions in Frameworks */, @@ -4022,7 +4016,6 @@ B6EC37FF29B8D915001ACE79 /* Configuration in Frameworks */, 372217822B33380700B8E9C2 /* TestUtils in Frameworks */, 3706FCAA293F65D500E42796 /* UserScript in Frameworks */, - 37CF915B2BB416AC00BADCAE /* Crashes in Frameworks */, 3706FCAB293F65D500E42796 /* TrackerRadarKit in Frameworks */, 85E2BBD02B8F534A00DBEC7A /* History in Frameworks */, 4BF97AD52B43C43F00EB4240 /* NetworkProtection in Frameworks */, @@ -4038,9 +4031,9 @@ buildActionMask = 2147483647; files = ( 3706FE88293F661700E42796 /* OHHTTPStubs in Frameworks */, + F116A7C72BD1925500F3FCF7 /* PixelKitTestingUtilities in Frameworks */, B65CD8CF2B316E0200A595BB /* SnapshotTesting in Frameworks */, 3706FE89293F661700E42796 /* OHHTTPStubsSwift in Frameworks */, - 4B81AD372B29513100706C96 /* PixelKitTestingUtilities in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4063,6 +4056,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F116A7C92BD1929000F3FCF7 /* PixelKitTestingUtilities in Frameworks */, B65CD8CD2B316DFC00A595BB /* SnapshotTesting in Frameworks */, B6AE39F329374AEC00C37AA4 /* OHHTTPStubs in Frameworks */, B6AE39F529374AEC00C37AA4 /* OHHTTPStubsSwift in Frameworks */, @@ -4075,8 +4069,8 @@ files = ( 37269F012B332FC8005E8E46 /* Common in Frameworks */, EE7295E92A545BC4008C0991 /* NetworkProtection in Frameworks */, - 4B2537772A11BFE100610219 /* PixelKit in Frameworks */, 7B37C7A52BAA32A50062546A /* Subscription in Frameworks */, + F198C7182BD18A4C000BF24D /* PixelKit in Frameworks */, 7BBE2B7B2B61663C00697445 /* NetworkProtectionProxy in Frameworks */, 4B2D062C2A11C0E100DE1F49 /* Networking in Frameworks */, 4B25375B2A11BE7300610219 /* NetworkExtension.framework in Frameworks */, @@ -4087,13 +4081,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F198C71A2BD18A5B000BF24D /* PixelKit in Frameworks */, 4B41EDAB2B1544B2001EEDF4 /* LoginItems in Frameworks */, 7B00997D2B6508B700FE7C31 /* NetworkProtectionProxy in Frameworks */, 7BEEA5122AD1235B00A9E72B /* NetworkProtectionIPC in Frameworks */, 7BA7CC5F2AD1210C0042E5CE /* Networking in Frameworks */, 7BEEA5162AD1236E00A9E72B /* NetworkProtectionUI in Frameworks */, BDADBDC92BD2BC2200421B9B /* Lottie in Frameworks */, - 7BFCB74E2ADE7E1A00DA3EA7 /* PixelKit in Frameworks */, EE7295ED2A545C0A008C0991 /* NetworkProtection in Frameworks */, EE2F9C5B2B90F2FF00D45FC9 /* Subscription in Frameworks */, 7BEC182F2AD5D8DC00D30536 /* SystemExtensionManager in Frameworks */, @@ -4104,9 +4098,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7BFCB7502ADE7E2300DA3EA7 /* PixelKit in Frameworks */, 4BCBE45C2BA7E18500FC75A1 /* Subscription in Frameworks */, 7BA7CC612AD1211C0042E5CE /* Networking in Frameworks */, + F198C71C2BD18A61000BF24D /* PixelKit in Frameworks */, 7BEEA5142AD1236300A9E72B /* NetworkProtectionIPC in Frameworks */, BDADBDCB2BD2BC2800421B9B /* Lottie in Frameworks */, 7B00997F2B6508C200FE7C31 /* NetworkProtectionProxy in Frameworks */, @@ -4129,10 +4123,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F1DF95E52BD1807C0045E591 /* Subscription in Frameworks */, 37269EFF2B332FBB005E8E46 /* Common in Frameworks */, EE7295E72A545BBB008C0991 /* NetworkProtection in Frameworks */, - 4B4D60982A0B2A5C00BCD287 /* PixelKit in Frameworks */, - 1E46E1A02BD029BD0007273A /* Subscription in Frameworks */, + F198C7162BD18A44000BF24D /* PixelKit in Frameworks */, 4B4D60AF2A0C837F00BCD287 /* Networking in Frameworks */, 7B25856E2BA2F2ED00D49F79 /* NetworkProtectionUI in Frameworks */, 4B4D603F2A0B290200BCD287 /* NetworkExtension.framework in Frameworks */, @@ -4161,7 +4155,6 @@ files = ( 7BDA36E62B7E037100AD5388 /* NetworkExtension.framework in Frameworks */, 7B97CD592B7E0B57004FEF43 /* NetworkProtectionProxy in Frameworks */, - 7B97CD622B7E0C4B004FEF43 /* PixelKit in Frameworks */, 7B7DFB222B7E7473009EA1A3 /* Networking in Frameworks */, 7B97CD5B2B7E0B85004FEF43 /* Common in Frameworks */, ); @@ -4172,7 +4165,6 @@ buildActionMask = 2147483647; files = ( 9DEF97E12B06C4EE00764F03 /* Networking in Frameworks */, - 9D6983F92AC773C3002C02FC /* PixelKit in Frameworks */, 9D9AE8F92AAA3AD00026E7DC /* DataBrokerProtection in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4181,7 +4173,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9D6983FB2AC773C8002C02FC /* PixelKit in Frameworks */, 315A023F2B6421AE00BFA577 /* Networking in Frameworks */, 9D9AE8FB2AAA3AD90026E7DC /* DataBrokerProtection in Frameworks */, ); @@ -4191,16 +4182,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 37CF91592BB416A500BADCAE /* Crashes in Frameworks */, - 373FB4B12B4D6C42004C88D6 /* PreferencesViews in Frameworks */, + F1DF95E32BD1807C0045E591 /* Crashes in Frameworks */, 85E2BBCE2B8F534000DBEC7A /* History in Frameworks */, 1EA7B8D32B7E078C000330A4 /* SubscriptionUI in Frameworks */, B6F7128129F681EB00594A45 /* QuickLookUI.framework in Frameworks */, - 9DB6E7242AA0DC5800A17F3C /* LoginItems in Frameworks */, EE7295E32A545B9A008C0991 /* NetworkProtection in Frameworks */, 9807F645278CA16F00E1547B /* BrowserServicesKit in Frameworks */, 987799ED299998B1005D8EB6 /* Bookmarks in Frameworks */, - 7B5DD69A2AE51FFA001DE99C /* PixelKit in Frameworks */, 1E950E3F2912A10D0051A99B /* ContentBlocking in Frameworks */, 31A3A4E32B0C115F0021063C /* DataBrokerProtection in Frameworks */, 378F44E429B4BDE900899924 /* SwiftUIExtensions in Frameworks */, @@ -4210,8 +4198,10 @@ 7B31FD8C2AD125620086AA24 /* NetworkProtectionIPC in Frameworks */, 37269EFB2B332F9E005E8E46 /* Common in Frameworks */, AA06B6B72672AF8100F541C5 /* Sparkle in Frameworks */, + F198C71E2BD18D88000BF24D /* SwiftLintTool in Frameworks */, 1EA7B8D52B7E078C000330A4 /* Subscription in Frameworks */, B6B77BE8297973D4001E68A1 /* Navigation in Frameworks */, + F198C7122BD18A28000BF24D /* PixelKit in Frameworks */, 3739326729AE4B42009346AE /* DDGSync in Frameworks */, 7BA59C9B2AE18B49009A97B1 /* SystemExtensionManager in Frameworks */, 371D00E129D8509400EC8598 /* OpenSSL in Frameworks */, @@ -4220,6 +4210,7 @@ 85D44B862BA08D29001B4AB5 /* Suggestions in Frameworks */, 37DF000529F9C056002B7D3E /* SyncDataProviders in Frameworks */, 37BA812D29B3CD690053F1A3 /* SyncUI in Frameworks */, + F1DF95E72BD188B60045E591 /* LoginItems in Frameworks */, 372217802B3337FE00B8E9C2 /* TestUtils in Frameworks */, 7BA076BB2B65D61400D7FB72 /* NetworkProtectionProxy in Frameworks */, 4B4D60B12A0C83B900BCD287 /* NetworkProtectionUI in Frameworks */, @@ -4232,9 +4223,9 @@ buildActionMask = 2147483647; files = ( B6DA44172616C13800DD1EC2 /* OHHTTPStubs in Frameworks */, + F116A7C32BD1924B00F3FCF7 /* PixelKitTestingUtilities in Frameworks */, B65CD8CB2B316DF100A595BB /* SnapshotTesting in Frameworks */, B6DA44192616C13800DD1EC2 /* OHHTTPStubsSwift in Frameworks */, - 4B81AD352B29512B00706C96 /* PixelKitTestingUtilities in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4665,7 +4656,6 @@ 3192A2702A4C4E330084EA89 /* DataBrokerProtection */, 9DB6E7222AA0DA7A00A17F3C /* LoginItems */, 7B25FE322AD12C990012AFAB /* NetworkProtectionMac */, - 4BE15DB12A0B0DD500898243 /* PixelKit */, 378F44E229B4B7B600899924 /* SwiftUIExtensions */, 37BA812B29B3CB8A0053F1A3 /* SyncUI */, 1E862A882A9FC01200F84D4B /* SubscriptionUI */, @@ -5589,13 +5579,11 @@ isa = PBXGroup; children = ( BDA7648F2BC4E56200D0400C /* Mocks */, - 7BBE65122BC67EF6008F4EE9 /* Support */, 4BCF15E62ABB98A20083F6DF /* Resources */, 4BCF15E42ABB98990083F6DF /* NetworkProtectionRemoteMessageTests.swift */, 4BD57C032AC112DF00B580EE /* NetworkProtectionRemoteMessagingTests.swift */, 7B09CBA72BA4BE7000CF245B /* NetworkProtectionPixelEventTests.swift */, BDA7648C2BC4E4EF00D0400C /* DefaultVPNLocationFormatterTests.swift */, - 7BBE650C2BC67BA0008F4EE9 /* NetworkProtectionIPCTunnelControllerTests.swift */, ); path = NetworkProtection; sourceTree = ""; @@ -5802,14 +5790,6 @@ path = LetsMove1.25; sourceTree = ""; }; - 7BBE65122BC67EF6008F4EE9 /* Support */ = { - isa = PBXGroup; - children = ( - 7BBE650F2BC67EED008F4EE9 /* NetworkProtectionTestingSupport.swift */, - ); - path = Support; - sourceTree = ""; - }; 7BDA36E72B7E037200AD5388 /* VPNProxyExtension */ = { isa = PBXGroup; children = ( @@ -5974,7 +5954,7 @@ 85CC1D7826A05E790062F04E /* Model */, 85CC1D7F26A05F6C0062F04E /* Services */, 85CC1D7926A05E820062F04E /* View */, - B642738127B65BAC0005DFD1 /* SecureVaultErrorReporter.swift */, + B642738127B65BAC0005DFD1 /* SecureVaultReporter.swift */, ); path = SecureVault; sourceTree = ""; @@ -6370,7 +6350,6 @@ 565E46DE2B2725DD0013AC2A /* SyncE2EUITests */, AA585D7F248FD31100E9A3E2 /* Products */, 85AE2FF024A33A2D002D507F /* Frameworks */, - EE0629702B90EE3500D868B4 /* Recovered References */, ); sourceTree = ""; }; @@ -7097,10 +7076,10 @@ 4B9292CD2667123700AD2C21 /* BookmarkManagementDetailViewController.swift */, 4B9292C72667123700AD2C21 /* BookmarkManagementSidebarViewController.swift */, 4B9292C82667123700AD2C21 /* BookmarkManagementSplitViewController.swift */, + 4B9292C92667123700AD2C21 /* BookmarkTableRowView.swift */, 4B92928726670D1600AD2C21 /* BookmarkOutlineCellView.swift */, 4B92928526670D1600AD2C21 /* BookmarksOutlineView.swift */, 4B92928926670D1700AD2C21 /* BookmarkTableCellView.swift */, - 4B9292C92667123700AD2C21 /* BookmarkTableRowView.swift */, 4B9292C62667123700AD2C21 /* BrowserTabSelectionDelegate.swift */, 4B92928626670D1600AD2C21 /* OutlineSeparatorViewCell.swift */, 4B0511B3262CAA5A00F6079C /* RoundedSelectionRowView.swift */, @@ -7995,13 +7974,6 @@ path = fonts; sourceTree = ""; }; - EE0629702B90EE3500D868B4 /* Recovered References */ = { - isa = PBXGroup; - children = ( - ); - name = "Recovered References"; - sourceTree = ""; - }; EEA3EEAF2B24EB5100E8333A /* VPNLocation */ = { isa = PBXGroup; children = ( @@ -8074,16 +8046,15 @@ CBCCF59F2996681700C02DFE /* Assert Xcode version */, 378E2798296F6D1D00FCADA2 /* Validate PRODUCT_NAME */, 3706FA79293F65D500E42796 /* Check Embedded Config URLs */, - B6E6BA192BA2D8BE008AA7E1 /* Run swiftlint */, 3706FA7A293F65D500E42796 /* Sources */, 3706FCA6293F65D500E42796 /* Frameworks */, 3706FCB1293F65D500E42796 /* Resources */, 4BBA2D272B6AC09D00F6A470 /* Embed Login Items */, + 6A8856B31B2BC5078B61ED81 /* Run swiftlint */, ); buildRules = ( ); dependencies = ( - B637D1BD2BC6AE6200C7DCA7 /* PBXTargetDependency */, 4BBA2D2B2B6AD01E00F6A470 /* PBXTargetDependency */, 4BBA2D292B6ACD4D00F6A470 /* PBXTargetDependency */, 4B5F14FE2A1529230060320F /* PBXTargetDependency */, @@ -8104,7 +8075,6 @@ B6EC37FE29B8D915001ACE79 /* Configuration */, 37DF000629F9C061002B7D3E /* SyncDataProviders */, 9DC70B192AA1FA5B005A844B /* LoginItems */, - 7B5F9A742AE2BE4E002AEBC0 /* PixelKit */, 37269EFC2B332FAC005E8E46 /* Common */, 372217812B33380700B8E9C2 /* TestUtils */, 4BF97AD02B43C43F00EB4240 /* NetworkProtectionIPC */, @@ -8118,8 +8088,10 @@ 4BCBE4572BA7E17800FC75A1 /* SubscriptionUI */, 85D44B872BA08D30001B4AB5 /* Suggestions */, 4BCBE4592BA7E17800FC75A1 /* Subscription */, - 37CF915A2BB416AC00BADCAE /* Crashes */, 9FF521472BAA909C00B9819B /* Lottie */, + 537FC71EA5115A983FAF3170 /* Crashes */, + F198C7132BD18A30000BF24D /* PixelKit */, + F198C71F2BD18D92000BF24D /* SwiftLintTool */, ); productName = DuckDuckGo; productReference = 3706FD05293F65D500E42796 /* DuckDuckGo App Store.app */; @@ -8143,8 +8115,8 @@ packageProductDependencies = ( 3706FDD6293F661700E42796 /* OHHTTPStubs */, 3706FDD8293F661700E42796 /* OHHTTPStubsSwift */, - 4B81AD362B29513100706C96 /* PixelKitTestingUtilities */, B65CD8CE2B316E0200A595BB /* SnapshotTesting */, + F116A7C62BD1925500F3FCF7 /* PixelKitTestingUtilities */, ); productName = DuckDuckGoTests; productReference = 3706FE99293F661700E42796 /* Unit Tests App Store.xctest */; @@ -8186,8 +8158,6 @@ 376113D62B29CD6800E794BB /* PBXTargetDependency */, ); name = "SyncE2EUITests App Store"; - packageProductDependencies = ( - ); productName = DuckDuckGoSyncUITests; productReference = 376113D42B29CD5B00E794BB /* SyncE2EUITests App Store.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; @@ -8211,6 +8181,7 @@ B6AE39F229374AEC00C37AA4 /* OHHTTPStubs */, B6AE39F429374AEC00C37AA4 /* OHHTTPStubsSwift */, B65CD8CC2B316DFC00A595BB /* SnapshotTesting */, + F116A7C82BD1929000F3FCF7 /* PixelKitTestingUtilities */, ); productName = "Integration Tests"; productReference = 4B1AD89D25FC27E200261379 /* Integration Tests.xctest */; @@ -8231,12 +8202,12 @@ ); name = NetworkProtectionSystemExtension; packageProductDependencies = ( - 4B2537762A11BFE100610219 /* PixelKit */, 4B2D062B2A11C0E100DE1F49 /* Networking */, EE7295E82A545BC4008C0991 /* NetworkProtection */, 37269F002B332FC8005E8E46 /* Common */, 7BBE2B7A2B61663C00697445 /* NetworkProtectionProxy */, 7B37C7A42BAA32A50062546A /* Subscription */, + F198C7172BD18A4C000BF24D /* PixelKit */, ); productName = NetworkProtectionSystemExtension; productReference = 4B25375A2A11BE7300610219 /* com.duckduckgo.macos.vpn.network-extension.debug.systemextension */; @@ -8264,10 +8235,10 @@ 7BEEA5112AD1235B00A9E72B /* NetworkProtectionIPC */, 7BEEA5152AD1236E00A9E72B /* NetworkProtectionUI */, 7BEC182E2AD5D8DC00D30536 /* SystemExtensionManager */, - 7BFCB74D2ADE7E1A00DA3EA7 /* PixelKit */, 4B41EDAA2B1544B2001EEDF4 /* LoginItems */, 7B00997C2B6508B700FE7C31 /* NetworkProtectionProxy */, EE2F9C5A2B90F2FF00D45FC9 /* Subscription */, + F198C7192BD18A5B000BF24D /* PixelKit */, BDADBDC82BD2BC2200421B9B /* Lottie */, ); productName = DuckDuckGoAgent; @@ -8297,10 +8268,10 @@ EE7295EE2A545C12008C0991 /* NetworkProtection */, 7BA7CC602AD1211C0042E5CE /* Networking */, 7BEEA5132AD1236300A9E72B /* NetworkProtectionIPC */, - 7BFCB74F2ADE7E2300DA3EA7 /* PixelKit */, 7B00997E2B6508C200FE7C31 /* NetworkProtectionProxy */, 4BA7C4DC2B3F64E500AFE511 /* LoginItems */, 4BCBE45B2BA7E18500FC75A1 /* Subscription */, + F198C71B2BD18A61000BF24D /* PixelKit */, BDADBDCA2BD2BC2800421B9B /* Lottie */, ); productName = DuckDuckGoAgentAppStore; @@ -8344,12 +8315,12 @@ ); name = NetworkProtectionAppExtension; packageProductDependencies = ( - 4B4D60972A0B2A5C00BCD287 /* PixelKit */, 4B4D60AE2A0C837F00BCD287 /* Networking */, EE7295E62A545BBB008C0991 /* NetworkProtection */, 37269EFE2B332FBB005E8E46 /* Common */, 7B25856D2BA2F2ED00D49F79 /* NetworkProtectionUI */, - 1E46E19F2BD029BD0007273A /* Subscription */, + DC3F73D49B2D44464AFEFCD8 /* Subscription */, + F198C7152BD18A44000BF24D /* PixelKit */, ); productName = NetworkProtectionAppExtension; productReference = 4B4D603D2A0B290200BCD287 /* NetworkProtectionAppExtension.appex */; @@ -8368,8 +8339,6 @@ dependencies = ( ); name = SyncE2EUITests; - packageProductDependencies = ( - ); productName = DuckDuckGoSyncUITests; productReference = 565E46DD2B2725DC0013AC2A /* SyncE2EUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; @@ -8412,7 +8381,6 @@ packageProductDependencies = ( 7B97CD582B7E0B57004FEF43 /* NetworkProtectionProxy */, 7B97CD5A2B7E0B85004FEF43 /* Common */, - 7B97CD612B7E0C4B004FEF43 /* PixelKit */, 7B7DFB212B7E7473009EA1A3 /* Networking */, ); productName = VPNProxyExtension; @@ -8435,7 +8403,6 @@ name = DuckDuckGoDBPBackgroundAgent; packageProductDependencies = ( 9D9AE8F82AAA3AD00026E7DC /* DataBrokerProtection */, - 9D6983F82AC773C3002C02FC /* PixelKit */, 9DEF97E02B06C4EE00764F03 /* Networking */, ); productName = DuckDuckGoAgent; @@ -8458,7 +8425,6 @@ name = DuckDuckGoDBPBackgroundAgentAppStore; packageProductDependencies = ( 9D9AE8FA2AAA3AD90026E7DC /* DataBrokerProtection */, - 9D6983FA2AC773C8002C02FC /* PixelKit */, 315A023E2B6421AE00BFA577 /* Networking */, ); productName = DuckDuckGoAgent; @@ -8471,17 +8437,16 @@ buildPhases = ( CBCCF59E299667B700C02DFE /* Assert Xcode version */, 3705272528992C8A000C06A2 /* Check Embedded Config URLs */, - B6409DC52BC7BD1F00D66F9E /* Run swiftlint */, AA585D7A248FD31100E9A3E2 /* Sources */, AA585D7B248FD31100E9A3E2 /* Frameworks */, AA585D7C248FD31100E9A3E2 /* Resources */, B6F2C8722A7A4C7D000498CF /* Make /Applications symlink, remove app on Clean build */, 4B2D065D2A11D2AE00DE1F49 /* Embed Login Items */, + 28003FDBDB96625F1630CFF2 /* Run swiftlint */, ); buildRules = ( ); dependencies = ( - B637D1BB2BC6AE5600C7DCA7 /* PBXTargetDependency */, 7B4627742B9AF2C8004ACE0B /* PBXTargetDependency */, 4B5F14FC2A15291D0060320F /* PBXTargetDependency */, 31C6E9AD2B0C07BA0086DC30 /* PBXTargetDependency */, @@ -8504,22 +8469,22 @@ 37DF000429F9C056002B7D3E /* SyncDataProviders */, 4B4D60B02A0C83B900BCD287 /* NetworkProtectionUI */, EE7295E22A545B9A008C0991 /* NetworkProtection */, - 9DB6E7232AA0DC5800A17F3C /* LoginItems */, 7B31FD8B2AD125620086AA24 /* NetworkProtectionIPC */, 7BA59C9A2AE18B49009A97B1 /* SystemExtensionManager */, - 7B5DD6992AE51FFA001DE99C /* PixelKit */, 31A3A4E22B0C115F0021063C /* DataBrokerProtection */, 37269EFA2B332F9E005E8E46 /* Common */, 3722177F2B3337FE00B8E9C2 /* TestUtils */, - 373FB4B02B4D6C42004C88D6 /* PreferencesViews */, 7BA076BA2B65D61400D7FB72 /* NetworkProtectionProxy */, 85E2BBCD2B8F534000DBEC7A /* History */, 1EA7B8D22B7E078C000330A4 /* SubscriptionUI */, 1EA7B8D42B7E078C000330A4 /* Subscription */, F1D43AF22B98E47800BAB743 /* BareBonesBrowserKit */, 85D44B852BA08D29001B4AB5 /* Suggestions */, - 37CF91582BB416A500BADCAE /* Crashes */, 9FF521452BAA908500B9819B /* Lottie */, + 08D4923DC968236E22E373E2 /* Crashes */, + F1DF95E62BD188B60045E591 /* LoginItems */, + F198C7112BD18A28000BF24D /* PixelKit */, + F198C71D2BD18D88000BF24D /* SwiftLintTool */, ); productName = DuckDuckGo; productReference = AA585D7E248FD31100E9A3E2 /* DuckDuckGo.app */; @@ -8543,8 +8508,8 @@ packageProductDependencies = ( B6DA44162616C13800DD1EC2 /* OHHTTPStubs */, B6DA44182616C13800DD1EC2 /* OHHTTPStubsSwift */, - 4B81AD342B29512B00706C96 /* PixelKitTestingUtilities */, B65CD8CA2B316DF100A595BB /* SnapshotTesting */, + F116A7C22BD1924B00F3FCF7 /* PixelKitTestingUtilities */, ); productName = DuckDuckGoTests; productReference = AA585D90248FD31400E9A3E2 /* Unit Tests.xctest */; @@ -8987,6 +8952,25 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 28003FDBDB96625F1630CFF2 /* Run swiftlint */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Run swiftlint"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ \"$CONFIGURATION\" != \"Debug\" ] || [ \"$ENABLE_PREVIEWS\" = \"YES\" ]; then exit 0; fi\n${BUILT_PRODUCTS_DIR}/SwiftLintTool\n"; + }; 3121F62B2B64266A002F706A /* Copy Swift Package resources */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -9119,7 +9103,7 @@ shellPath = /bin/sh; shellScript = "# Embeds login items for the App Store build.\n\n# Skip login item embedding for release builds until they're ready to go live.\nif [ \"${CONFIGURATION}\" = \"Release\" ]; then\n VPN_AGENT_NAME=\"${AGENT_RELEASE_PRODUCT_NAME}\"\n PIR_AGENT_NAME=\"${DBP_BACKGROUND_AGENT_RELEASE_PRODUCT_NAME}\"\nelse\n VPN_AGENT_NAME=\"${AGENT_PRODUCT_NAME}\"\n PIR_AGENT_NAME=\"${DBP_BACKGROUND_AGENT_PRODUCT_NAME}\"\nfi\n\nVPN_AGENT_ORIGIN=$(readlink -f \"${CONFIGURATION_BUILD_DIR}/${VPN_AGENT_NAME}.app\")\nPIR_AGENT_ORIGIN=$(readlink -f \"${CONFIGURATION_BUILD_DIR}/${PIR_AGENT_NAME}.app\")\nAGENT_DESTINATION=\"${CONFIGURATION_BUILD_DIR}/${CONTENTS_FOLDER_PATH}/Library/LoginItems\"\n \n# Make sure that Library/LoginItems exists before copying\nmkdir -p \"$AGENT_DESTINATION\"\n \necho \"Copying VPN agent from $VPN_AGENT_ORIGIN to $AGENT_DESTINATION\"\nrsync -r --links \"$VPN_AGENT_ORIGIN\" \"$AGENT_DESTINATION\"\n \necho \"Copying Personal Information Removal agent from $PIR_AGENT_ORIGIN to $AGENT_DESTINATION\"\nrsync -r --links \"$PIR_AGENT_ORIGIN\" \"$AGENT_DESTINATION\"\n"; }; - 7B31FD922AD126C40086AA24 /* Embed System Network Extension */ = { + 6A8856B31B2BC5078B61ED81 /* Run swiftlint */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9129,16 +9113,16 @@ ); inputPaths = ( ); - name = "Embed System Network Extension"; + name = "Run swiftlint"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; 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"; + shellScript = "if [ \"$CONFIGURATION\" != \"Debug\" ] || [ \"$ENABLE_PREVIEWS\" = \"YES\" ]; then exit 0; fi\n${BUILT_PRODUCTS_DIR}/SwiftLintTool\n"; }; - 7B557F2A2B8CA2A400099746 /* Embed Debug-only Network Extensions */ = { + 7B31FD922AD126C40086AA24 /* Embed System Network Extension */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9148,16 +9132,16 @@ ); inputPaths = ( ); - name = "Embed Debug-only Network Extensions"; + name = "Embed System Network Extension"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Support for embedding debug-only extensions (https://stackoverflow.com/a/76948057/712306)\nfunction embedExtensions() {\n for extension in $1\n do\n rsync -r --copy-links \"${CONFIGURATION_BUILD_DIR}/${extension}.appex\" \"${CONFIGURATION_BUILD_DIR}/${PLUGINS_FOLDER_PATH}\"\n done\n}\n\ndebug_extensions=(\"VPNProxyExtension\")\n\nif [ \"${CONFIGURATION}\" != \"Release\" ]\nthen\n embedExtensions $debug_extensions\nfi\n"; + 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 /* Copy Swift Package resources */ = { + 7B557F2A2B8CA2A400099746 /* Embed Debug-only Network Extensions */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9167,16 +9151,16 @@ ); inputPaths = ( ); - name = "Copy Swift Package resources"; + name = "Embed Debug-only Network Extensions"; 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}/\"\ncp -RL \"${BUILT_PRODUCTS_DIR}\"/DataBrokerProtection_DataBrokerProtection.bundle \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\n"; + shellScript = "# Support for embedding debug-only extensions (https://stackoverflow.com/a/76948057/712306)\nfunction embedExtensions() {\n for extension in $1\n do\n rsync -r --copy-links \"${CONFIGURATION_BUILD_DIR}/${extension}.appex\" \"${CONFIGURATION_BUILD_DIR}/${PLUGINS_FOLDER_PATH}\"\n done\n}\n\ndebug_extensions=(\"VPNProxyExtension\")\n\nif [ \"${CONFIGURATION}\" != \"Release\" ]\nthen\n embedExtensions $debug_extensions\nfi\n"; }; - B6409DC52BC7BD1F00D66F9E /* Run swiftlint */ = { + 7BB34F502AD98394005691AE /* Copy Swift Package resources */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9186,14 +9170,14 @@ ); inputPaths = ( ); - name = "Run swiftlint"; + name = "Copy Swift Package resources"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ \"$CONFIGURATION\" != \"Debug\" ] || [ \"$ENABLE_PREVIEWS\" = \"YES\" ]; then exit 0; fi\n${BUILT_PRODUCTS_DIR}/SwiftLintTool\n"; + 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}/\"\ncp -RL \"${BUILT_PRODUCTS_DIR}\"/DataBrokerProtection_DataBrokerProtection.bundle \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\n"; }; B6AEB5532BA3029B00781A09 /* Cleanup entitlements */ = { isa = PBXShellScriptBuildPhase; @@ -9233,25 +9217,6 @@ shellPath = /bin/sh; shellScript = "FRAMEWORKS_DIR=\"${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nDYLIB_TARGET_PATH=\"${FRAMEWORKS_DIR}/libswift_Concurrency.dylib\"\n\nif [ ! -e \"${DYLIB_TARGET_PATH}\" ]; then\n\n DYLIB_PATH=$(find \"${TOOLCHAIN_DIR}/usr/lib\" -path \"*/${HOST_PLATFORM}/libswift_Concurrency.dylib\")\n echo \"copy ${DYLIB_PATH} to ${DYLIB_TARGET_PATH}\"\n\n mkdir -p \"${FRAMEWORKS_DIR}\"\n cp \"${DYLIB_PATH}\" \"${DYLIB_TARGET_PATH}\" || exit 1\n\nelse\n echo \"${DYLIB_TARGET_PATH} exists 👌\"\nfi\n"; }; - B6E6BA192BA2D8BE008AA7E1 /* Run swiftlint */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Run swiftlint"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if [ \"$CONFIGURATION\" != \"Debug\" ] || [ \"$ENABLE_PREVIEWS\" = \"YES\" ]; then exit 0; fi\n${BUILT_PRODUCTS_DIR}/SwiftLintTool\n"; - }; B6F2C8722A7A4C7D000498CF /* Make /Applications symlink, remove app on Clean build */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -10022,7 +9987,7 @@ C1372EF52BBC5BAD003F8793 /* SecureTextField.swift in Sources */, 3706FC77293F65D500E42796 /* PageObserverUserScript.swift in Sources */, 4BF0E5132AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, - 3706FC78293F65D500E42796 /* SecureVaultErrorReporter.swift in Sources */, + 3706FC78293F65D500E42796 /* SecureVaultReporter.swift in Sources */, 3706FC79293F65D500E42796 /* NSImageExtensions.swift in Sources */, 3706FEBD293F6EFF00E42796 /* BWCommand.swift in Sources */, 3706FC7B293F65D500E42796 /* PasswordManagementViewController.swift in Sources */, @@ -10211,10 +10176,8 @@ B630E80129C887ED00363609 /* NSErrorAdditionalInfo.swift in Sources */, 3706FE31293F661700E42796 /* TabCollectionViewModelDelegateMock.swift in Sources */, 3706FE32293F661700E42796 /* BookmarksHTMLReaderTests.swift in Sources */, - 7BBE650E2BC67BA0008F4EE9 /* NetworkProtectionIPCTunnelControllerTests.swift in Sources */, 3706FE33293F661700E42796 /* FireTests.swift in Sources */, B60C6F8229B1B4AD007BFAA8 /* TestRunHelper.swift in Sources */, - 7BBE65112BC67EED008F4EE9 /* NetworkProtectionTestingSupport.swift in Sources */, 567DA94029E8045D008AC5EE /* MockEmailStorage.swift in Sources */, 317295D32AF058D3002C3206 /* MockWaitlistTermsAndConditionsActionHandler.swift in Sources */, 3706FE34293F661700E42796 /* PermissionStoreTests.swift in Sources */, @@ -11342,7 +11305,7 @@ 1D2DC0072901679C008083A1 /* BWError.swift in Sources */, 853014D625E671A000FB8205 /* PageObserverUserScript.swift in Sources */, B677FC4F2B06376B0099EB04 /* ReportFeedbackView.swift in Sources */, - B642738227B65BAC0005DFD1 /* SecureVaultErrorReporter.swift in Sources */, + B642738227B65BAC0005DFD1 /* SecureVaultReporter.swift in Sources */, 4B139AFD26B60BD800894F82 /* NSImageExtensions.swift in Sources */, B62B48392ADE46FC000DECE5 /* Application.swift in Sources */, 4B9DB02C2A983B24000927DB /* WaitlistKeychainStorage.swift in Sources */, @@ -11579,7 +11542,6 @@ 1D3B1AC22936B816006F4388 /* BWMessageIdGeneratorTests.swift in Sources */, B6C2C9F62760B659005B7F0A /* TestDataModel.xcdatamodeld in Sources */, 1DA6D1022A1FFA3700540406 /* HTTPCookieTests.swift in Sources */, - 7BBE65102BC67EED008F4EE9 /* NetworkProtectionTestingSupport.swift in Sources */, 1D9FDEC02B9B5FEA0040B78C /* AccessibilityPreferencesTests.swift in Sources */, B68172AE269EB43F006D1092 /* GeolocationServiceTests.swift in Sources */, B6AE74342609AFCE005B9B1A /* ProgressEstimationTests.swift in Sources */, @@ -11659,7 +11621,6 @@ 37CD54B927F1F8AC00F1F7B9 /* AppearancePreferencesTests.swift in Sources */, EEF53E182950CED5002D78F4 /* JSAlertViewModelTests.swift in Sources */, 376C4DB928A1A48A00CC0F5B /* FirePopoverViewModelTests.swift in Sources */, - 7BBE650D2BC67BA0008F4EE9 /* NetworkProtectionIPCTunnelControllerTests.swift in Sources */, AAEC74B62642CC6A00C2EFBC /* HistoryStoringMock.swift in Sources */, AA652CB125DD825B009059CC /* LocalBookmarkStoreTests.swift in Sources */, B630794226731F5400DCEE41 /* WKDownloadMock.swift in Sources */, @@ -11775,14 +11736,6 @@ target = 4B2537592A11BE7300610219 /* NetworkProtectionSystemExtension */; targetProxy = 7BEC18302AD5DA3300D30536 /* PBXContainerItemProxy */; }; - B637D1BB2BC6AE5600C7DCA7 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B637D1BA2BC6AE5600C7DCA7 /* SwiftLintTool */; - }; - B637D1BD2BC6AE6200C7DCA7 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B637D1BC2BC6AE6200C7DCA7 /* SwiftLintTool */; - }; B6AEB5552BA3042300781A09 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = B6E6B9F22BA1FD90008AA7E1 /* sandbox-test-tool */; @@ -12642,7 +12595,7 @@ version = 3.1.4000; }; }; - 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { + 3FFD51CF7C19ACBDB9687474 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { @@ -12650,6 +12603,22 @@ version = 138.0.0; }; }; + 4311906792B7676CE9535D76 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; + requirement = { + kind = revision; + revision = c06709ba8a586f6a40190bacaaaaa96b2d55e540; + }; + }; + 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; + requirement = { + kind = exactVersion; + version = 139.0.0; + }; + }; 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/airbnb/lottie-spm.git"; @@ -12706,13 +12675,21 @@ version = 0.1.0; }; }; + FAE06B199CA1F209B55B34E9 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; + requirement = { + kind = exactVersion; + version = 137.0.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 1E46E19F2BD029BD0007273A /* Subscription */ = { + 08D4923DC968236E22E373E2 /* Crashes */ = { isa = XCSwiftPackageProductDependency; - package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Subscription; + package = FAE06B199CA1F209B55B34E9 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Crashes; }; 1E950E3E2912A10D0051A99B /* ContentBlocking */ = { isa = XCSwiftPackageProductDependency; @@ -12835,10 +12812,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = DDGSync; }; - 373FB4B02B4D6C42004C88D6 /* PreferencesViews */ = { - isa = XCSwiftPackageProductDependency; - productName = PreferencesViews; - }; 373FB4B22B4D6C4B004C88D6 /* PreferencesViews */ = { isa = XCSwiftPackageProductDependency; productName = PreferencesViews; @@ -12864,16 +12837,6 @@ isa = XCSwiftPackageProductDependency; productName = SyncUI; }; - 37CF91582BB416A500BADCAE /* Crashes */ = { - isa = XCSwiftPackageProductDependency; - package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Crashes; - }; - 37CF915A2BB416AC00BADCAE /* Crashes */ = { - isa = XCSwiftPackageProductDependency; - package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Crashes; - }; 37DF000429F9C056002B7D3E /* SyncDataProviders */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -12889,10 +12852,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Navigation; }; - 4B2537762A11BFE100610219 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 4B2D062B2A11C0E100DE1F49 /* Networking */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -12914,10 +12873,6 @@ isa = XCSwiftPackageProductDependency; productName = NetworkProtection; }; - 4B4D60972A0B2A5C00BCD287 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 4B4D60AE2A0C837F00BCD287 /* Networking */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -12935,14 +12890,6 @@ isa = XCSwiftPackageProductDependency; productName = "plugin:InputFilesChecker"; }; - 4B81AD342B29512B00706C96 /* PixelKitTestingUtilities */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKitTestingUtilities; - }; - 4B81AD362B29513100706C96 /* PixelKitTestingUtilities */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKitTestingUtilities; - }; 4BA7C4DC2B3F64E500AFE511 /* LoginItems */ = { isa = XCSwiftPackageProductDependency; productName = LoginItems; @@ -12974,6 +12921,11 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = NetworkProtection; }; + 537FC71EA5115A983FAF3170 /* Crashes */ = { + isa = XCSwiftPackageProductDependency; + package = 4311906792B7676CE9535D76 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Crashes; + }; 7B00997C2B6508B700FE7C31 /* NetworkProtectionProxy */ = { isa = XCSwiftPackageProductDependency; productName = NetworkProtectionProxy; @@ -12999,14 +12951,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Subscription; }; - 7B5DD6992AE51FFA001DE99C /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; - 7B5F9A742AE2BE4E002AEBC0 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 7B624F162BA25C1F00A6C544 /* NetworkProtectionUI */ = { isa = XCSwiftPackageProductDependency; productName = NetworkProtectionUI; @@ -13025,10 +12969,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Common; }; - 7B97CD612B7E0C4B004FEF43 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 7BA076BA2B65D61400D7FB72 /* NetworkProtectionProxy */ = { isa = XCSwiftPackageProductDependency; productName = NetworkProtectionProxy; @@ -13067,14 +13007,6 @@ isa = XCSwiftPackageProductDependency; productName = NetworkProtectionUI; }; - 7BFCB74D2ADE7E1A00DA3EA7 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; - 7BFCB74F2ADE7E2300DA3EA7 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 85D44B852BA08D29001B4AB5 /* Suggestions */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -13115,14 +13047,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Persistence; }; - 9D6983F82AC773C3002C02FC /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; - 9D6983FA2AC773C8002C02FC /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 9D9AE8F82AAA3AD00026E7DC /* DataBrokerProtection */ = { isa = XCSwiftPackageProductDependency; productName = DataBrokerProtection; @@ -13131,10 +13055,6 @@ isa = XCSwiftPackageProductDependency; productName = DataBrokerProtection; }; - 9DB6E7232AA0DC5800A17F3C /* LoginItems */ = { - isa = XCSwiftPackageProductDependency; - productName = LoginItems; - }; 9DC70B192AA1FA5B005A844B /* LoginItems */ = { isa = XCSwiftPackageProductDependency; productName = LoginItems; @@ -13159,16 +13079,6 @@ package = AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */; productName = Sparkle; }; - B637D1BA2BC6AE5600C7DCA7 /* SwiftLintTool */ = { - isa = XCSwiftPackageProductDependency; - package = B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */; - productName = SwiftLintTool; - }; - B637D1BC2BC6AE6200C7DCA7 /* SwiftLintTool */ = { - isa = XCSwiftPackageProductDependency; - package = B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */; - productName = SwiftLintTool; - }; B65CD8CA2B316DF100A595BB /* SnapshotTesting */ = { isa = XCSwiftPackageProductDependency; package = B65CD8C92B316DF100A595BB /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */; @@ -13254,6 +13164,11 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Configuration; }; + DC3F73D49B2D44464AFEFCD8 /* Subscription */ = { + isa = XCSwiftPackageProductDependency; + package = 3FFD51CF7C19ACBDB9687474 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Subscription; + }; EE02D41F2BB460C000DBE6B3 /* BrowserServicesKit */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -13289,6 +13204,61 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = NetworkProtection; }; + F116A7C22BD1924B00F3FCF7 /* PixelKitTestingUtilities */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKitTestingUtilities; + }; + F116A7C62BD1925500F3FCF7 /* PixelKitTestingUtilities */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKitTestingUtilities; + }; + F116A7C82BD1929000F3FCF7 /* PixelKitTestingUtilities */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKitTestingUtilities; + }; + F198C7112BD18A28000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C7132BD18A30000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C7152BD18A44000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C7172BD18A4C000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C7192BD18A5B000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C71B2BD18A61000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C71D2BD18D88000BF24D /* SwiftLintTool */ = { + isa = XCSwiftPackageProductDependency; + package = B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */; + productName = SwiftLintTool; + }; + F198C71F2BD18D92000BF24D /* SwiftLintTool */ = { + isa = XCSwiftPackageProductDependency; + package = B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */; + productName = SwiftLintTool; + }; F1D43AF22B98E47800BAB743 /* BareBonesBrowserKit */ = { isa = XCSwiftPackageProductDependency; package = F1D43AF12B98E47800BAB743 /* XCRemoteSwiftPackageReference "BareBonesBrowser" */; @@ -13299,6 +13269,10 @@ package = F1D43AF12B98E47800BAB743 /* XCRemoteSwiftPackageReference "BareBonesBrowser" */; productName = BareBonesBrowserKit; }; + F1DF95E62BD188B60045E591 /* LoginItems */ = { + isa = XCSwiftPackageProductDependency; + productName = LoginItems; + }; /* End XCSwiftPackageProductDependency section */ /* Begin XCVersionGroup section */ diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 462a0cc553..3696fa870b 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "b8f0e5db431c63943b509d522c157f870ef03ae0", - "version" : "138.0.0" + "revision" : "1c2e84e6cd4543e9104aff753e48b146eeb36007", + "version" : "139.0.0" } }, { @@ -120,7 +120,7 @@ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-argument-parser", + "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { "revision" : "46989693916f56d1186bd59ac15124caef896560", "version" : "1.3.1" @@ -138,7 +138,7 @@ { "identity" : "swift-syntax", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax.git", + "location" : "https://github.com/apple/swift-syntax", "state" : { "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", "version" : "509.1.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 86fd422c11..e343e06df9 100644 --- a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser App Store.xcscheme +++ b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser App Store.xcscheme @@ -157,16 +157,6 @@ ReferencedContainer = "container:LocalPackages/SyncUI"> - - - - - - - - - - - - - - - - AutofillActionExecutor? { - guard let secureVault = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared), + guard let secureVault = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared), let syncService = NSApp.delegateTyped.syncService else { return nil } return AutofillDeleteAllPasswordsExecutor(userAuthenticator: DeviceAuthenticator.shared, diff --git a/DuckDuckGo/Autofill/ContentOverlayViewController.swift b/DuckDuckGo/Autofill/ContentOverlayViewController.swift index 9e325ef8b0..5bfdf2ca85 100644 --- a/DuckDuckGo/Autofill/ContentOverlayViewController.swift +++ b/DuckDuckGo/Autofill/ContentOverlayViewController.swift @@ -309,8 +309,8 @@ extension ContentOverlayViewController: SecureVaultManagerDelegate { } } - public func secureVaultInitFailed(_ error: SecureStorageError) { - SecureVaultErrorReporter.shared.secureVaultInitFailed(error) + public func secureVaultError(_ error: SecureStorageError) { + SecureVaultReporter.shared.secureVaultError(error) } public func secureVaultManager(_: BrowserServicesKit.SecureVaultManager, didReceivePixel pixel: AutofillUserScript.JSPixel) { diff --git a/DuckDuckGo/Common/Localizables/UserText.swift b/DuckDuckGo/Common/Localizables/UserText.swift index 9cb9493ebf..d7de7c47bf 100644 --- a/DuckDuckGo/Common/Localizables/UserText.swift +++ b/DuckDuckGo/Common/Localizables/UserText.swift @@ -212,6 +212,7 @@ struct UserText { static let addFolder = NSLocalizedString("menu.add.folder", value: "Add Folder…", comment: "Menu item to add a folder") static let tabHomeTitle = NSLocalizedString("tab.home.title", value: "New Tab", comment: "Tab home title") + static let tabUntitledTitle = NSLocalizedString("tab.empty.title", value: "Untitled", comment: "Title for an empty tab without a title") static let tabPreferencesTitle = NSLocalizedString("tab.preferences.title", value: "Settings", comment: "Tab preferences title") static let tabBookmarksTitle = NSLocalizedString("tab.bookmarks.title", value: "Bookmarks", comment: "Tab bookmarks title") static let tabOnboardingTitle = NSLocalizedString("tab.onboarding.title", value: "Welcome", comment: "Tab onboarding title") diff --git a/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift b/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift index bf1a08a800..48a458f3cf 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift @@ -48,6 +48,7 @@ final class DataBrokerProtectionDebugMenu: NSMenu { private let customURLLabelMenuItem = NSMenuItem(title: "") private let environmentMenu = NSMenu() + private let statusMenuIconMenu = NSMenuItem(title: "Show Status Menu Icon", action: #selector(DataBrokerProtectionDebugMenu.toggleShowStatusMenuItem)) private let webUISettings = DataBrokerProtectionWebUIURLSettings(.dbp) private let settings = DataBrokerProtectionSettings(defaults: .dbp) @@ -147,6 +148,8 @@ final class DataBrokerProtectionDebugMenu: NSMenu { NSMenuItem.separator() + statusMenuIconMenu.targetting(self) + NSMenuItem(title: "Show DB Browser", action: #selector(DataBrokerProtectionDebugMenu.showDatabaseBrowser)) .targetting(self) NSMenuItem(title: "Force Profile Removal", action: #selector(DataBrokerProtectionDebugMenu.showForceOptOutWindow)) @@ -172,6 +175,7 @@ final class DataBrokerProtectionDebugMenu: NSMenu { updateWaitlistItems() updateWebUIMenuItemsState() updateEnvironmentMenu() + updateShowStatusMenuIconMenu() } // MARK: - Menu functions @@ -223,7 +227,7 @@ final class DataBrokerProtectionDebugMenu: NSMenu { os_log("Running scan operations...", log: .dataBrokerProtection) let showWebView = sender.representedObject as? Bool ?? false - DataBrokerProtectionManager.shared.scheduler.scanAllBrokers(showWebView: showWebView) { errors in + DataBrokerProtectionManager.shared.scheduler.startManualScan(showWebView: showWebView) { errors in if let errors = errors { if let oneTimeError = errors.oneTimeError { os_log("scan operations finished, error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) @@ -366,6 +370,10 @@ final class DataBrokerProtectionDebugMenu: NSMenu { } } + @objc private func toggleShowStatusMenuItem() { + settings.showInMenuBar.toggle() + } + @objc func setSelectedEnvironment(_ menuItem: NSMenuItem) { let title = menuItem.title let selectedEnvironment: DataBrokerProtectionSettings.SelectedEnvironment @@ -448,6 +456,10 @@ final class DataBrokerProtectionDebugMenu: NSMenu { environmentMenu.items.first?.state = selectedEnvironment == .production ? .on: .off environmentMenu.items.last?.state = selectedEnvironment == .staging ? .on: .off } + + private func updateShowStatusMenuIconMenu() { + statusMenuIconMenu.state = settings.showInMenuBar ? .on : .off + } } extension DataBrokerProtectionDebugMenu: NSWindowDelegate { diff --git a/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift index 8cd8416bc4..cc0d841ee8 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift @@ -55,10 +55,10 @@ extension DataBrokerProtectionLoginItemScheduler: DataBrokerProtectionScheduler ipcScheduler.statusPublisher } - func scanAllBrokers(showWebView: Bool, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { + func startManualScan(showWebView: Bool, + completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { enableLoginItem() - ipcScheduler.scanAllBrokers(showWebView: showWebView, completion: completion) + ipcScheduler.startManualScan(showWebView: showWebView, completion: completion) } func startScheduler(showWebView: Bool) { diff --git a/DuckDuckGo/DataImport/Logins/SecureVault/SecureVaultLoginImporter.swift b/DuckDuckGo/DataImport/Logins/SecureVault/SecureVaultLoginImporter.swift index 17acb874e0..193806cef0 100644 --- a/DuckDuckGo/DataImport/Logins/SecureVault/SecureVaultLoginImporter.swift +++ b/DuckDuckGo/DataImport/Logins/SecureVault/SecureVaultLoginImporter.swift @@ -23,7 +23,7 @@ import SecureStorage final class SecureVaultLoginImporter: LoginImporter { func importLogins(_ logins: [ImportedLoginCredential], progressCallback: @escaping (Int) throws -> Void) throws -> DataImport.DataTypeSummary { - let vault = try AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared) + let vault = try AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared) var successful: [String] = [] var duplicates: [String] = [] diff --git a/DuckDuckGo/Fire/Model/Fire.swift b/DuckDuckGo/Fire/Model/Fire.swift index 29c2ca70f0..4766d8b6e6 100644 --- a/DuckDuckGo/Fire/Model/Fire.swift +++ b/DuckDuckGo/Fire/Model/Fire.swift @@ -385,7 +385,7 @@ final class Fire { // MARK: - Favicons private func autofillDomains() -> Set { - guard let vault = try? secureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared), + guard let vault = try? secureVaultFactory.makeVault(reporter: SecureVaultReporter.shared), let accounts = try? vault.accounts() else { return [] } diff --git a/DuckDuckGo/HomePage/Model/DataImportStatusProviding.swift b/DuckDuckGo/HomePage/Model/DataImportStatusProviding.swift index 4d65b77c05..17efd1a64d 100644 --- a/DuckDuckGo/HomePage/Model/DataImportStatusProviding.swift +++ b/DuckDuckGo/HomePage/Model/DataImportStatusProviding.swift @@ -31,7 +31,7 @@ final class BookmarksAndPasswordsImportStatusProvider: DataImportStatusProviding let secureVault: (any AutofillSecureVault)? let bookmarkManager: BookmarkManager - init(secureVault: (any AutofillSecureVault)? = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared), + init(secureVault: (any AutofillSecureVault)? = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared), bookmarkManager: BookmarkManager = LocalBookmarkManager.shared) { self.secureVault = secureVault self.bookmarkManager = bookmarkManager diff --git a/DuckDuckGo/Localizable.xcstrings b/DuckDuckGo/Localizable.xcstrings index ef1f610c2e..993f125ffd 100644 --- a/DuckDuckGo/Localizable.xcstrings +++ b/DuckDuckGo/Localizable.xcstrings @@ -20060,6 +20060,7 @@ }, "Hide" : { "comment" : "Main Menu > View > Home Button > None item\n Preferences > Home Button > None item", + "extractionState" : "extracted_with_value", "localizations" : { "de" : { "stringUnit" : { @@ -48009,6 +48010,7 @@ }, "Show left of the back button" : { "comment" : "Preferences > Home Button > left position item", + "extractionState" : "extracted_with_value", "localizations" : { "de" : { "stringUnit" : { @@ -48062,6 +48064,7 @@ }, "Show Left of the Back Button" : { "comment" : "Main Menu > View > Home Button > left position item", + "extractionState" : "extracted_with_value", "localizations" : { "de" : { "stringUnit" : { @@ -48327,6 +48330,7 @@ }, "Show right of the reload button" : { "comment" : "Preferences > Home Button > right position item", + "extractionState" : "extracted_with_value", "localizations" : { "de" : { "stringUnit" : { @@ -48380,6 +48384,7 @@ }, "Show Right of the Reload Button" : { "comment" : "Main Menu > View > Home Button > right position item", + "extractionState" : "extracted_with_value", "localizations" : { "de" : { "stringUnit" : { @@ -49868,6 +49873,66 @@ } } }, + "tab.empty.title" : { + "comment" : "Title for an empty tab without a title", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ohne Titel" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Untitled" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin título" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sans titre" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ohne Titel" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Naamloos" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bez tytułu" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem título" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Без названия" + } + } + } + }, "tab.error.title" : { "comment" : "Tab error title", "extractionState" : "extracted_with_value", @@ -53180,4 +53245,4 @@ } }, "version" : "1.0" -} \ No newline at end of file +} diff --git a/DuckDuckGo/Menus/MainMenuActions.swift b/DuckDuckGo/Menus/MainMenuActions.swift index 5be8c2344c..59729584ac 100644 --- a/DuckDuckGo/Menus/MainMenuActions.swift +++ b/DuckDuckGo/Menus/MainMenuActions.swift @@ -215,7 +215,7 @@ extension AppDelegate { savePanel.beginSheetModal(for: window) { response in guard response == .OK, let selectedURL = savePanel.url else { return } - let vault = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared) + let vault = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared) let exporter = CSVLoginExporter(secureVault: vault!) do { try exporter.exportVaultLogins(to: selectedURL) @@ -670,7 +670,7 @@ extension MainViewController { } @objc func resetSecureVaultData(_ sender: Any?) { - let vault = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared) + let vault = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared) let accounts = (try? vault?.accounts()) ?? [] for accountID in accounts.compactMap(\.id) { @@ -1042,7 +1042,7 @@ extension AppDelegate: NSMenuItemValidation { } private var areTherePasswords: Bool { - let vault = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared) + let vault = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared) guard let vault else { return false } diff --git a/DuckDuckGo/SecureVault/Model/AutofillNeverPromptWebsitesManager.swift b/DuckDuckGo/SecureVault/Model/AutofillNeverPromptWebsitesManager.swift index 015f0606f3..0e69ffd6dc 100644 --- a/DuckDuckGo/SecureVault/Model/AutofillNeverPromptWebsitesManager.swift +++ b/DuckDuckGo/SecureVault/Model/AutofillNeverPromptWebsitesManager.swift @@ -28,7 +28,7 @@ final class AutofillNeverPromptWebsitesManager { private let secureVault: (any AutofillSecureVault)? - public init(secureVault: (any AutofillSecureVault)? = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared)) { + public init(secureVault: (any AutofillSecureVault)? = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared)) { self.secureVault = secureVault fetchNeverPromptWebsites() diff --git a/DuckDuckGo/SecureVault/SecureVaultReporter.swift b/DuckDuckGo/SecureVault/SecureVaultReporter.swift new file mode 100644 index 0000000000..af50ce3e84 --- /dev/null +++ b/DuckDuckGo/SecureVault/SecureVaultReporter.swift @@ -0,0 +1,65 @@ +// +// SecureVaultReporter.swift +// +// Copyright © 2022 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Common +import Foundation +import BrowserServicesKit +import PixelKit +import SecureStorage + +final class SecureVaultKeyStoreEventMapper: EventMapping { + public init() { + super.init { event, _, _, _ in + switch event { + case .l1KeyMigration: + PixelKit.fire(DebugEvent(GeneralPixel.secureVaultKeystoreEventL1KeyMigration)) + case .l2KeyMigration: + PixelKit.fire(DebugEvent(GeneralPixel.secureVaultKeystoreEventL2KeyMigration)) + case .l2KeyPasswordMigration: + PixelKit.fire(DebugEvent(GeneralPixel.secureVaultKeystoreEventL2KeyPasswordMigration)) + } + } + } + + override init(mapping: @escaping EventMapping.Mapping) { + fatalError("Use init()") + } +} + +final class SecureVaultReporter: SecureVaultReporting { + static let shared = SecureVaultReporter() + private var keyStoreMapper: SecureVaultKeyStoreEventMapper + private init(keyStoreMapper: SecureVaultKeyStoreEventMapper = SecureVaultKeyStoreEventMapper()) { + self.keyStoreMapper = keyStoreMapper + } + + func secureVaultError(_ error: SecureStorageError) { + guard NSApp.runType.requiresEnvironment else { return } + + switch error { + case .initFailed, .failedToOpenDatabase: + PixelKit.fire(DebugEvent(GeneralPixel.secureVaultInitError(error: error))) + default: + PixelKit.fire(DebugEvent(GeneralPixel.secureVaultError(error: error))) + } + } + + func secureVaultKeyStoreEvent(_ event: SecureStorageKeyStoreEvent) { + keyStoreMapper.fire(event) + } +} diff --git a/DuckDuckGo/SecureVault/View/PasswordManagementViewController.swift b/DuckDuckGo/SecureVault/View/PasswordManagementViewController.swift index b5fd2cf4fc..f18a2478de 100644 --- a/DuckDuckGo/SecureVault/View/PasswordManagementViewController.swift +++ b/DuckDuckGo/SecureVault/View/PasswordManagementViewController.swift @@ -153,7 +153,7 @@ final class PasswordManagementViewController: NSViewController { } var secureVault: (any AutofillSecureVault)? { - try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared) + try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared) } private let passwordManagerCoordinator: PasswordManagerCoordinating = PasswordManagerCoordinator.shared @@ -1074,7 +1074,7 @@ extension PasswordManagementViewController: NSMenuItemValidation { } private var haveDuckDuckGoPasswords: Bool { - guard let vault = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared) else { return false } + guard let vault = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared) else { return false } let accounts = (try? vault.accounts()) ?? [] return !accounts.isEmpty } diff --git a/DuckDuckGo/SecureVault/View/SaveCredentialsViewController.swift b/DuckDuckGo/SecureVault/View/SaveCredentialsViewController.swift index fa4da02ff7..02a5595240 100644 --- a/DuckDuckGo/SecureVault/View/SaveCredentialsViewController.swift +++ b/DuckDuckGo/SecureVault/View/SaveCredentialsViewController.swift @@ -222,7 +222,7 @@ final class SaveCredentialsViewController: NSViewController { } } } else { - _ = try AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared).storeWebsiteCredentials(credentials) + _ = try AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared).storeWebsiteCredentials(credentials) NSApp.delegateTyped.syncService?.scheduler.notifyDataChanged() os_log(.debug, log: OSLog.sync, "Requesting sync if enabled") } diff --git a/DuckDuckGo/SecureVault/View/SaveIdentityViewController.swift b/DuckDuckGo/SecureVault/View/SaveIdentityViewController.swift index 88006e5096..61ce88b628 100644 --- a/DuckDuckGo/SecureVault/View/SaveIdentityViewController.swift +++ b/DuckDuckGo/SecureVault/View/SaveIdentityViewController.swift @@ -71,7 +71,7 @@ final class SaveIdentityViewController: NSViewController { identity.title = UserText.pmDefaultIdentityAutofillTitle do { - try AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared).storeIdentity(identity) + try AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared).storeIdentity(identity) PixelKit.fire(GeneralPixel.autofillItemSaved(kind: .identity)) } catch { os_log("%s:%s: failed to store identity %s", type: .error, className, #function, error.localizedDescription) diff --git a/DuckDuckGo/SecureVault/View/SavePaymentMethodViewController.swift b/DuckDuckGo/SecureVault/View/SavePaymentMethodViewController.swift index 68275eeb5e..31c9d6a3b3 100644 --- a/DuckDuckGo/SecureVault/View/SavePaymentMethodViewController.swift +++ b/DuckDuckGo/SecureVault/View/SavePaymentMethodViewController.swift @@ -92,7 +92,7 @@ final class SavePaymentMethodViewController: NSViewController { paymentMethod.title = CreditCardValidation.type(for: paymentMethod.cardNumber).displayName do { - try AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared).storeCreditCard(paymentMethod) + try AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared).storeCreditCard(paymentMethod) } catch { os_log("%s:%s: failed to store payment method %s", type: .error, className, #function, error.localizedDescription) PixelKit.fire(DebugEvent(GeneralPixel.secureVaultError(error: error))) diff --git a/DuckDuckGo/Statistics/GeneralPixel.swift b/DuckDuckGo/Statistics/GeneralPixel.swift index 285a3bbdee..708d25fbe4 100644 --- a/DuckDuckGo/Statistics/GeneralPixel.swift +++ b/DuckDuckGo/Statistics/GeneralPixel.swift @@ -311,6 +311,10 @@ enum GeneralPixel: PixelKitEventV2 { // Tracks installation without tracking retention. case installationAttribution + case secureVaultKeystoreEventL1KeyMigration + case secureVaultKeystoreEventL2KeyMigration + case secureVaultKeystoreEventL2KeyPasswordMigration + var name: String { switch self { @@ -764,6 +768,10 @@ enum GeneralPixel: PixelKitEventV2 { // Installation Attribution case .installationAttribution: return "m_mac_install" + + case .secureVaultKeystoreEventL1KeyMigration: return "m_mac_secure_vault_keystore_event_l1-key-migration" + case .secureVaultKeystoreEventL2KeyMigration: return "m_mac_secure_vault_keystore_event_l2-key-migration" + case .secureVaultKeystoreEventL2KeyPasswordMigration: return "m_mac_secure_vault_keystore_event_l2-key-password-migration" } } diff --git a/DuckDuckGo/Sync/SyncCredentialsAdapter.swift b/DuckDuckGo/Sync/SyncCredentialsAdapter.swift index 571fa21afb..c9f495901e 100644 --- a/DuckDuckGo/Sync/SyncCredentialsAdapter.swift +++ b/DuckDuckGo/Sync/SyncCredentialsAdapter.swift @@ -44,7 +44,7 @@ final class SyncCredentialsAdapter { syncDidCompletePublisher = syncDidCompleteSubject.eraseToAnyPublisher() databaseCleaner = CredentialsDatabaseCleaner( secureVaultFactory: secureVaultFactory, - secureVaultErrorReporter: SecureVaultErrorReporter.shared, + secureVaultErrorReporter: SecureVaultReporter.shared, errorEvents: CredentialsCleanupErrorHandling(), log: .passwordManager ) @@ -71,7 +71,7 @@ final class SyncCredentialsAdapter { do { let provider = try CredentialsProvider( secureVaultFactory: secureVaultFactory, - secureVaultErrorReporter: SecureVaultErrorReporter.shared, + secureVaultErrorReporter: SecureVaultReporter.shared, metadataStore: metadataStore, metricsEvents: metricsEventsHandler, log: OSLog.sync, diff --git a/DuckDuckGo/Tab/TabExtensions/AutofillTabExtension.swift b/DuckDuckGo/Tab/TabExtensions/AutofillTabExtension.swift index 867702bd7e..328b447ea3 100644 --- a/DuckDuckGo/Tab/TabExtensions/AutofillTabExtension.swift +++ b/DuckDuckGo/Tab/TabExtensions/AutofillTabExtension.swift @@ -163,8 +163,8 @@ extension AutofillTabExtension: SecureVaultManagerDelegate { } } - func secureVaultInitFailed(_ error: SecureStorageError) { - SecureVaultErrorReporter.shared.secureVaultInitFailed(error) + func secureVaultError(_ error: SecureStorageError) { + SecureVaultReporter.shared.secureVaultError(error) } public func secureVaultManager(_: BrowserServicesKit.SecureVaultManager, didReceivePixel pixel: AutofillUserScript.JSPixel) { diff --git a/DuckDuckGo/Tab/ViewModel/TabViewModel.swift b/DuckDuckGo/Tab/ViewModel/TabViewModel.swift index 1db6697d20..42ac6fcd45 100644 --- a/DuckDuckGo/Tab/ViewModel/TabViewModel.swift +++ b/DuckDuckGo/Tab/ViewModel/TabViewModel.swift @@ -290,7 +290,7 @@ final class TabViewModel { } private func updateTitle() { // swiftlint:disable:this cyclomatic_complexity - let title: String + var title: String switch tab.content { // keep an old tab title for web page terminated page, display "Failed to open page" for loading errors case _ where isShowingErrorPage && (tab.error?.code != .webContentProcessTerminated || tab.title == nil): @@ -324,6 +324,9 @@ final class TabViewModel { title = addressBarString } } + if title.isEmpty { + title = UserText.tabUntitledTitle + } if self.title != title { self.title = title } diff --git a/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift b/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift index 5e3bf42951..0a3e777138 100644 --- a/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift +++ b/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift @@ -72,15 +72,43 @@ final class DuckDuckGoDBPBackgroundAgentApplication: NSApplication { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + } @main final class DuckDuckGoDBPBackgroundAgentAppDelegate: NSObject, NSApplicationDelegate { + private let settings = DataBrokerProtectionSettings() + private var cancellables = Set() + private var statusBarMenu: StatusBarMenu? + @MainActor func applicationDidFinishLaunching(_ aNotification: Notification) { os_log("DuckDuckGoAgent started", log: .dbpBackgroundAgent, type: .info) let manager = DataBrokerProtectionBackgroundManager.shared manager.runOperationsAndStartSchedulerIfPossible() + + setupStatusBarMenu() + } + + @MainActor + private func setupStatusBarMenu() { + statusBarMenu = StatusBarMenu() + + if settings.showInMenuBar { + statusBarMenu?.show() + } else { + statusBarMenu?.hide() + } + + settings.showInMenuBarPublisher.sink { [weak self] showInMenuBar in + Task { @MainActor in + if showInMenuBar { + self?.statusBarMenu?.show() + } else { + self?.statusBarMenu?.hide() + } + } + }.store(in: &cancellables) } } diff --git a/DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift b/DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift index 01acff18bc..33a1fc1d77 100644 --- a/DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift +++ b/DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift @@ -84,10 +84,10 @@ extension IPCServiceManager: IPCServerInterface { } } - func scanAllBrokers(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { + func startManualScan(showWebView: Bool, + completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { pixelHandler.fire(.ipcServerScanAllBrokersReceivedByAgent) - scheduler.scanAllBrokers(showWebView: showWebView) { errors in + scheduler.startManualScan(showWebView: showWebView) { errors in if let error = errors?.oneTimeError { switch error { case DataBrokerProtectionSchedulerError.operationsInterrupted: diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 51d8ee4755..f82dfc3ce0 100644 --- a/LocalPackages/DataBrokerProtection/Package.swift +++ b/LocalPackages/DataBrokerProtection/Package.swift @@ -29,8 +29,7 @@ let package = Package( targets: ["DataBrokerProtection"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "138.0.0"), - .package(path: "../PixelKit"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "139.0.0"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), ], @@ -39,9 +38,9 @@ let package = Package( name: "DataBrokerProtection", dependencies: [ .product(name: "BrowserServicesKit", package: "BrowserServicesKit"), - .product(name: "PixelKit", package: "PixelKit"), .product(name: "SwiftUIExtensions", package: "SwiftUIExtensions"), .byName(name: "XPCHelper"), + .product(name: "PixelKit", package: "BrowserServicesKit"), ], resources: [.process("Resources")], swiftSettings: [ diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDatabase.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDatabase.swift index b32a2e42a1..bab6bce44f 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDatabase.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDatabase.swift @@ -55,12 +55,12 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { private let fakeBrokerFlag: DataBrokerDebugFlag private let pixelHandler: EventMapping private let vault: (any DataBrokerProtectionSecureVault)? - private let secureVaultErrorReporter: SecureVaultErrorReporting? + private let secureVaultErrorReporter: SecureVaultReporting? init(fakeBrokerFlag: DataBrokerDebugFlag = DataBrokerDebugFlagFakeBroker(), pixelHandler: EventMapping, vault: (any DataBrokerProtectionSecureVault)? = nil, - secureVaultErrorReporter: SecureVaultErrorReporting? = DataBrokerProtectionSecureVaultErrorReporter.shared) { + secureVaultErrorReporter: SecureVaultReporting? = DataBrokerProtectionSecureVaultErrorReporter.shared) { self.fakeBrokerFlag = fakeBrokerFlag self.pixelHandler = pixelHandler self.vault = vault @@ -69,7 +69,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func save(_ profile: DataBrokerProtectionProfile) async throws { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) if try vault.fetchProfile(with: Self.profileId) != nil { try await updateProfile(profile, vault: vault) @@ -85,7 +85,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { public func fetchProfile() throws -> DataBrokerProtectionProfile? { do { - let vault = try DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) return try vault.fetchProfile(with: Self.profileId) } catch { os_log("Database error: fetchProfile, error: %{public}@", log: .error, error.localizedDescription) @@ -96,7 +96,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { public func deleteProfileData() throws { do { - let vault = try DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) try vault.deleteProfileData() } catch { os_log("Database error: deleteProfileData, error: %{public}@", log: .error, error.localizedDescription) @@ -107,7 +107,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func fetchChildBrokers(for parentBroker: String) throws -> [DataBroker] { do { - let vault = try DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) return try vault.fetchChildBrokers(for: parentBroker) } catch { os_log("Database error: fetchChildBrokers, error: %{public}@", log: .error, error.localizedDescription) @@ -118,7 +118,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func save(_ extractedProfile: ExtractedProfile, brokerId: Int64, profileQueryId: Int64) throws -> Int64 { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) return try vault.save(extractedProfile: extractedProfile, brokerId: brokerId, profileQueryId: profileQueryId) } catch { @@ -130,7 +130,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func brokerProfileQueryData(for brokerId: Int64, and profileQueryId: Int64) throws -> BrokerProfileQueryData? { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) guard let broker = try vault.fetchBroker(with: brokerId), let profileQuery = try vault.fetchProfileQuery(with: profileQueryId), let scanOperation = try vault.fetchScan(brokerId: brokerId, profileQueryId: profileQueryId) else { @@ -157,7 +157,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func fetchExtractedProfiles(for brokerId: Int64) throws -> [ExtractedProfile] { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) return try vault.fetchExtractedProfiles(for: brokerId) } catch { os_log("Database error: fetchExtractedProfiles, error: %{public}@", log: .error, error.localizedDescription) @@ -168,7 +168,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func updatePreferredRunDate(_ date: Date?, brokerId: Int64, profileQueryId: Int64) throws { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) try vault.updatePreferredRunDate(date, brokerId: brokerId, profileQueryId: profileQueryId) } catch { os_log("Database error: updatePreferredRunDate without extractedProfileID, error: %{public}@", log: .error, error.localizedDescription) @@ -179,7 +179,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func updatePreferredRunDate(_ date: Date?, brokerId: Int64, profileQueryId: Int64, extractedProfileId: Int64) throws { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) try vault.updatePreferredRunDate( date, @@ -195,7 +195,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func updateLastRunDate(_ date: Date?, brokerId: Int64, profileQueryId: Int64) throws { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) try vault.updateLastRunDate(date, brokerId: brokerId, profileQueryId: profileQueryId) } catch { os_log("Database error: updateLastRunDate without extractedProfileID, error: %{public}@", log: .error, error.localizedDescription) @@ -206,7 +206,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func updateLastRunDate(_ date: Date?, brokerId: Int64, profileQueryId: Int64, extractedProfileId: Int64) throws { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) try vault.updateLastRunDate( date, @@ -223,7 +223,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func updateRemovedDate(_ date: Date?, on extractedProfileId: Int64) throws { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) try vault.updateRemovedDate(for: extractedProfileId, with: date) } catch { os_log("Database error: updateRemovedDate, error: %{public}@", log: .error, error.localizedDescription) @@ -234,7 +234,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func add(_ historyEvent: HistoryEvent) throws { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) if let extractedProfileId = historyEvent.extractedProfileId { try vault.save(historyEvent: historyEvent, brokerId: historyEvent.brokerId, profileQueryId: historyEvent.profileQueryId, extractedProfileId: extractedProfileId) @@ -250,7 +250,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func fetchAllBrokerProfileQueryData() throws -> [BrokerProfileQueryData] { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) let brokers = try vault.fetchAllBrokers() let profileQueries = try vault.fetchAllProfileQueries(for: Self.profileId) var brokerProfileQueryDataList = [BrokerProfileQueryData]() @@ -283,7 +283,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func saveOptOutOperation(optOut: OptOutOperationData, extractedProfile: ExtractedProfile) throws { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) try vault.save(brokerId: optOut.brokerId, profileQueryId: optOut.profileQueryId, @@ -299,7 +299,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func fetchLastEvent(brokerId: Int64, profileQueryId: Int64) throws -> HistoryEvent? { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) let events = try vault.fetchEvents(brokerId: brokerId, profileQueryId: profileQueryId) return events.max(by: { $0.date < $1.date }) @@ -312,7 +312,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func hasMatches() throws -> Bool { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) return try vault.hasMatches() } catch { os_log("Database error: hasMatches, error: %{public}@", log: .error, error.localizedDescription) @@ -323,7 +323,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func fetchScanHistoryEvents(brokerId: Int64, profileQueryId: Int64) throws -> [HistoryEvent] { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: nil) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: nil) guard let scan = try vault.fetchScan(brokerId: brokerId, profileQueryId: profileQueryId) else { return [HistoryEvent]() } @@ -338,7 +338,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func fetchOptOutHistoryEvents(brokerId: Int64, profileQueryId: Int64, extractedProfileId: Int64) throws -> [HistoryEvent] { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: nil) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: nil) guard let optOut = try vault.fetchOptOut(brokerId: brokerId, profileQueryId: profileQueryId, extractedProfileId: extractedProfileId) else { return [HistoryEvent]() } @@ -353,7 +353,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func fetchAttemptInformation(for extractedProfileId: Int64) throws -> AttemptInformation? { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) return try vault.fetchAttemptInformation(for: extractedProfileId) } catch { os_log("Database error: fetchAttemptInformation, error: %{public}@", log: .error, error.localizedDescription) @@ -364,7 +364,7 @@ final class DataBrokerProtectionDatabase: DataBrokerProtectionRepository { func addAttempt(extractedProfileId: Int64, attemptUUID: UUID, dataBroker: String, lastStageDate: Date, startTime: Date) throws { do { - let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: secureVaultErrorReporter) + let vault = try self.vault ?? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: secureVaultErrorReporter) try vault.save(extractedProfileId: extractedProfileId, attemptUUID: attemptUUID, dataBroker: dataBroker, diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionSecureVaultErrorReporter.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionSecureVaultErrorReporter.swift index 21cb003862..86421908fd 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionSecureVaultErrorReporter.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionSecureVaultErrorReporter.swift @@ -22,7 +22,7 @@ import SecureStorage import PixelKit import Common -final class DataBrokerProtectionSecureVaultErrorReporter: SecureVaultErrorReporting { +final class DataBrokerProtectionSecureVaultErrorReporter: SecureVaultReporting { static let shared = DataBrokerProtectionSecureVaultErrorReporter(pixelHandler: DataBrokerProtectionPixelsHandler()) let pixelHandler: EventMapping @@ -30,7 +30,7 @@ final class DataBrokerProtectionSecureVaultErrorReporter: SecureVaultErrorReport self.pixelHandler = pixelHandler } - func secureVaultInitFailed(_ error: SecureStorageError) { + func secureVaultError(_ error: SecureStorageError) { switch error { case .initFailed, .failedToOpenDatabase: pixelHandler.fire(.secureVaultInitError(error: error)) diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift index 7525572fd5..f7b809ac9f 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift @@ -136,8 +136,8 @@ extension DataBrokerProtectionIPCClient: IPCServerInterface { }) } - public func scanAllBrokers(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { + public func startManualScan(showWebView: Bool, + completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { self.pixelHandler.fire(.ipcServerScanAllBrokersCalledByApp) guard loginItemStatusChecker.doesHaveNecessaryPermissions() else { @@ -155,7 +155,7 @@ extension DataBrokerProtectionIPCClient: IPCServerInterface { } xpc.execute(call: { server in - server.scanAllBrokers(showWebView: showWebView) { errors in + server.startManualScan(showWebView: showWebView) { errors in if let error = errors?.oneTimeError { let nsError = error as NSError let interruptedError = DataBrokerProtectionSchedulerError.operationsInterrupted as NSError diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCScheduler.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCScheduler.swift index cfb11f5187..0763404514 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCScheduler.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCScheduler.swift @@ -51,10 +51,10 @@ public final class DataBrokerProtectionIPCScheduler: DataBrokerProtectionSchedul ipcClient.optOutAllBrokers(showWebView: showWebView, completion: completion) } - public func scanAllBrokers(showWebView: Bool, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { + public func startManualScan(showWebView: Bool, + completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { let completion = completion ?? { _ in } - ipcClient.scanAllBrokers(showWebView: showWebView, completion: completion) + ipcClient.startManualScan(showWebView: showWebView, completion: completion) } public func runQueuedOperations(showWebView: Bool, diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift index 9027e1d275..dce168b8fe 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift @@ -94,8 +94,8 @@ public protocol IPCServerInterface: AnyObject { func optOutAllBrokers(showWebView: Bool, completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) - func scanAllBrokers(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) + func startManualScan(showWebView: Bool, + completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) func runQueuedOperations(showWebView: Bool, completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) func runAllOperations(showWebView: Bool) @@ -135,8 +135,8 @@ protocol XPCServerInterface { func optOutAllBrokers(showWebView: Bool, completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) - func scanAllBrokers(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) + func startManualScan(showWebView: Bool, + completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) func runQueuedOperations(showWebView: Bool, completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) func runAllOperations(showWebView: Bool) @@ -213,9 +213,9 @@ extension DataBrokerProtectionIPCServer: XPCServerInterface { serverDelegate?.optOutAllBrokers(showWebView: showWebView, completion: completion) } - func scanAllBrokers(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { - serverDelegate?.scanAllBrokers(showWebView: showWebView, completion: completion) + func startManualScan(showWebView: Bool, + completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { + serverDelegate?.startManualScan(showWebView: showWebView, completion: completion) } func runQueuedOperations(showWebView: Bool, diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/DBPUIViewModel.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/DBPUIViewModel.swift index 3ca4eeb399..df3cf6fd82 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/DBPUIViewModel.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/DBPUIViewModel.swift @@ -75,7 +75,7 @@ final class DBPUIViewModel { extension DBPUIViewModel: DBPUIScanOps { func startScan() -> Bool { - scheduler.scanAllBrokers() + scheduler.startManualScan() return true } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerProtectionBrokerUpdater.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerProtectionBrokerUpdater.swift index 79020cde0b..9128f87178 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerProtectionBrokerUpdater.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerProtectionBrokerUpdater.swift @@ -118,7 +118,7 @@ public struct DataBrokerProtectionBrokerUpdater { } public static func provide() -> DataBrokerProtectionBrokerUpdater? { - if let vault = try? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: nil) { + if let vault = try? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: nil) { return DataBrokerProtectionBrokerUpdater(vault: vault) } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/advancedbackgroundchecks.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/advancedbackgroundchecks.com.json index e14795a195..d514b04052 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/advancedbackgroundchecks.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/advancedbackgroundchecks.com.json @@ -1,7 +1,7 @@ { "name": "AdvancedBackgroundChecks", "url": "advancedbackgroundchecks.com", - "version": "0.1.6", + "version": "0.1.7", "parent": "peoplefinders.com", "addedDatetime": 1678060800000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "7967f064-e3c5-442d-8380-99cf752fb8df", + "id": "070b6417-8ccd-4111-b5ae-7ae470b0399a", "url": "https://www.advancedbackgroundchecks.com/names/${firstName}-${lastName}_${city}-${state}_age_${age}" }, { "actionType": "extract", - "id": "6f6bb616-a4cb-4231-9abb-522722208f95", + "id": "d760163d-4a1f-476a-bc3e-4f3ccedc29f1", "selector": ".card-block", "profile": { "name": { @@ -24,7 +24,7 @@ "beforeText": "Age" }, "alternativeNamesList": { - "selector": "(.//p[@class='card-text max-lines-1'])[1]", + "selector": ".//p[contains(@class, 'card-text') and strong[contains(text(), 'AKA')]]", "afterText": "AKA:", "separator": "," }, @@ -40,7 +40,7 @@ "selector": "(.//p[@class='card-text'])[1]" }, "relativesList": { - "selector": "(.//p[@class='card-text max-lines-1'])[2]", + "selector": ".//p[contains(@class, 'card-text') and strong[contains(text(), 'Related to')]]", "afterText": "Related to:", "separator": "," }, diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionNoOpScheduler.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionNoOpScheduler.swift index 222377923b..cb3057b937 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionNoOpScheduler.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionNoOpScheduler.swift @@ -36,7 +36,7 @@ final class DataBrokerProtectionNoOpScheduler: DataBrokerProtectionScheduler { func stopScheduler() { } func optOutAllBrokers(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { } func runQueuedOperations(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { } - func scanAllBrokers(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { } + func startManualScan(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { } func runAllOperations(showWebView: Bool) { } func getDebugMetadata(completion: (DBPBackgroundAgentMetadata?) -> Void) { } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionProcessor.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionProcessor.swift index 0ba21a21f7..4e0cf5ac7d 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionProcessor.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionProcessor.swift @@ -25,7 +25,7 @@ protocol OperationRunnerProvider { } private enum DataBrokerProtectionProcessorFunction { - case runAllScanOperations(pendingCompletion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) + case startManualScans(pendingCompletion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) case runAllOptOutOperations(pendingCompletion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) case runQueuedOperations(pendingCompletion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) case runAllOperations(pendingCompletion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) @@ -64,16 +64,17 @@ final class DataBrokerProtectionProcessor { } // MARK: - Public functions - func runAllScanOperations(showWebView: Bool = false, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)? = nil) { + func startManualScans(showWebView: Bool = false, + completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)? = nil) { interruptCurrentlyRunningFunction() - currentlyRunningOperationsForFunction = .runAllScanOperations(pendingCompletion: completion) + currentlyRunningOperationsForFunction = .startManualScans(pendingCompletion: completion) runOperations(operationType: .scan, priorityDate: nil, - showWebView: showWebView) { errors in + showWebView: showWebView) { [weak self] errors in os_log("Scans done", log: .dataBrokerProtection) + self?.currentlyRunningOperationsForFunction = nil completion?(errors) - self.calculateMisMatches() + self?.calculateMisMatches() } } @@ -88,8 +89,9 @@ final class DataBrokerProtectionProcessor { currentlyRunningOperationsForFunction = .runAllOptOutOperations(pendingCompletion: completion) runOperations(operationType: .optOut, priorityDate: nil, - showWebView: showWebView) { errors in + showWebView: showWebView) { [weak self] errors in os_log("Optouts done", log: .dataBrokerProtection) + self?.currentlyRunningOperationsForFunction = nil completion?(errors) } } @@ -100,8 +102,9 @@ final class DataBrokerProtectionProcessor { currentlyRunningOperationsForFunction = .runQueuedOperations(pendingCompletion: completion) runOperations(operationType: .all, priorityDate: Date(), - showWebView: showWebView) { errors in + showWebView: showWebView) { [weak self] errors in os_log("Queued operations done", log: .dataBrokerProtection) + self?.currentlyRunningOperationsForFunction = nil completion?(errors) } } @@ -112,8 +115,9 @@ final class DataBrokerProtectionProcessor { currentlyRunningOperationsForFunction = .runAllOperations(pendingCompletion: completion) runOperations(operationType: .all, priorityDate: nil, - showWebView: showWebView) { errors in + showWebView: showWebView) { [weak self] errors in os_log("Queued operations done", log: .dataBrokerProtection) + self?.currentlyRunningOperationsForFunction = nil completion?(errors) } } @@ -129,7 +133,7 @@ final class DataBrokerProtectionProcessor { completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { // Before running new operations we check if there is any updates to the broker files. - if let vault = try? DataBrokerProtectionSecureVaultFactory.makeVault(errorReporter: nil) { + if let vault = try? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: nil) { let brokerUpdater = DataBrokerProtectionBrokerUpdater(vault: vault, pixelHandler: pixelHandler) brokerUpdater.checkForUpdatesInBrokerJSONFiles() } @@ -202,7 +206,7 @@ final class DataBrokerProtectionProcessor { operationQueue.cancelAllOperations() switch currentlyRunningOperationsForFunction { - case .runAllScanOperations(let pendingCompletion), + case .startManualScans(let pendingCompletion), .runAllOptOutOperations(let pendingCompletion), .runQueuedOperations(let pendingCompletion), .runAllOperations(let pendingCompletion): diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift index d5f9083d07..e7a15bd1bb 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift @@ -80,7 +80,7 @@ public protocol DataBrokerProtectionScheduler { func stopScheduler() func optOutAllBrokers(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) - func scanAllBrokers(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) + func startManualScan(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) func runQueuedOperations(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) func runAllOperations(showWebView: Bool) @@ -98,8 +98,8 @@ extension DataBrokerProtectionScheduler { runAllOperations(showWebView: false) } - public func scanAllBrokers() { - scanAllBrokers(showWebView: false, completion: nil) + public func startManualScan() { + startManualScan(showWebView: false, completion: nil) } } @@ -249,19 +249,21 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch } - public func scanAllBrokers(showWebView: Bool = false, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)? = nil) { + public func startManualScan(showWebView: Bool = false, + completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)? = nil) { stopScheduler() userNotificationService.requestNotificationPermission() os_log("Scanning all brokers...", log: .dataBrokerProtection) - dataBrokerProcessor.runAllScanOperations(showWebView: showWebView) { [weak self] errors in + dataBrokerProcessor.startManualScans(showWebView: showWebView) { [weak self] errors in guard let self = self else { return } self.startScheduler(showWebView: showWebView) - self.userNotificationService.sendFirstScanCompletedNotification() + if errors?.oneTimeError == nil { + self.userNotificationService.sendFirstScanCompletedNotification() + } if let hasMatches = try? self.dataManager.hasMatches(), hasMatches { @@ -272,15 +274,15 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch if let oneTimeError = errors.oneTimeError { switch oneTimeError { case DataBrokerProtectionSchedulerError.operationsInterrupted: - os_log("Interrupted during DefaultDataBrokerProtectionScheduler.scanAllBrokers in dataBrokerProcessor.runAllScanOperations(), error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) + os_log("Interrupted during DefaultDataBrokerProtectionScheduler.startManualScan in dataBrokerProcessor.runAllScanOperations(), error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) default: - os_log("Error during DefaultDataBrokerProtectionScheduler.scanAllBrokers in dataBrokerProcessor.runAllScanOperations(), error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) - self.pixelHandler.fire(.generalError(error: oneTimeError, functionOccurredIn: "DefaultDataBrokerProtectionScheduler.scanAllBrokers")) + os_log("Error during DefaultDataBrokerProtectionScheduler.startManualScan in dataBrokerProcessor.runAllScanOperations(), error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) + self.pixelHandler.fire(.generalError(error: oneTimeError, functionOccurredIn: "DefaultDataBrokerProtectionScheduler.startManualScan")) } } if let operationErrors = errors.operationErrors, operationErrors.count != 0 { - os_log("Operation error(s) during DefaultDataBrokerProtectionScheduler.scanAllBrokers in dataBrokerProcessor.runAllScanOperations(), count: %{public}d", log: .dataBrokerProtection, operationErrors.count) + os_log("Operation error(s) during DefaultDataBrokerProtectionScheduler.startManualScan in dataBrokerProcessor.runAllScanOperations(), count: %{public}d", log: .dataBrokerProtection, operationErrors.count) } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarMenu.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarMenu.swift new file mode 100644 index 0000000000..369a42ee56 --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarMenu.swift @@ -0,0 +1,71 @@ +// +// StatusBarMenu.swift +// +// Copyright © 2024 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 AppKit + +public final class StatusBarMenu: NSObject { + private let statusItem: NSStatusItem + private let popover: StatusBarPopover + + public override init() { + statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) + popover = StatusBarPopover() + popover.behavior = .transient + super.init() + + setupStatusItem() + } + + @objc + private func statusBarButtonTapped() { + togglePopover() + } + + private func setupStatusItem() { + statusItem.button?.target = self + statusItem.button?.image = NSImage(systemSymbolName: NSImage.Name("person.crop.circle.badge.minus"), accessibilityDescription: nil) + statusItem.button?.action = #selector(statusBarButtonTapped) + statusItem.button?.sendAction(on: [.leftMouseUp]) + } + + // MARK: - Popover + + private func togglePopover() { + if popover.isShown { + popover.close() + } else { + guard let button = statusItem.button else { + return + } + + popover.show(relativeTo: button.bounds, of: button, preferredEdge: .maxY) + popover.contentViewController?.view.window?.makeKey() + } + } + + // MARK: - Showing & Hiding the menu + + public func show() { + statusItem.isVisible = true + } + + public func hide() { + statusItem.isVisible = false + } +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarMenuDebugInfoViewModel.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarMenuDebugInfoViewModel.swift new file mode 100644 index 0000000000..9f3c15478c --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarMenuDebugInfoViewModel.swift @@ -0,0 +1,37 @@ +// +// StatusBarMenuDebugInfoViewModel.swift +// +// Copyright © 2024 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 + +public final class StatusBarMenuDebugInfoViewModel: ObservableObject { + + var bundlePath: String + var version: String + + public init(bundle: Bundle = .main) { + bundlePath = bundle.bundlePath + + // swiftlint:disable:next force_cast + let shortVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String + + // swiftlint:disable:next force_cast + let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String + + version = shortVersion + " (build: " + buildNumber + ")" + } +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarPopover.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarPopover.swift new file mode 100644 index 0000000000..84cc931d30 --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarPopover.swift @@ -0,0 +1,43 @@ +// +// StatusBarPopover.swift +// +// Copyright © 2024 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 AppKit +import SwiftUI + +public final class StatusBarPopover: NSPopover { + + public required override init() { + super.init() + + self.animates = false + self.behavior = .transient + + setupContentController() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupContentController() { + let controller = NSHostingController(rootView: StatusBarPopoverView(viewModel: StatusBarMenuDebugInfoViewModel())) + contentViewController = controller + controller.view.frame = CGRect(origin: .zero, size: controller.view.intrinsicContentSize) + } +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarPopoverView.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarPopoverView.swift new file mode 100644 index 0000000000..2e9199dc21 --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/StatusItem/StatusBarPopoverView.swift @@ -0,0 +1,64 @@ +// +// StatusBarPopoverView.swift +// +// Copyright © 2024 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 SwiftUI +import Combine + +struct StatusBarPopoverView: View { + let viewModel: StatusBarMenuDebugInfoViewModel + + var body: some View { + VStack(alignment: .center, spacing: 10) { + HStack { + Text("Personal Information Removal") + .font(.headline) + .foregroundColor(.primary) + Spacer() + } + + informationRow(title: "Version", details: viewModel.version) + informationRow(title: "Bundle Path", details: viewModel.bundlePath) + } + .padding() + .frame(width: 350, height: 200) + } + + private func informationRow(title: String, details: String) -> some View { + VStack(spacing: 2) { + HStack { + Text(title) + .font(.headline) + .foregroundColor(.primary) + Spacer() + } + HStack { + + Text(details) + .font(.body) + .foregroundColor(.secondary) + .makeSelectable() + .lineLimit(nil) + Spacer() + } + } + } +} + +#Preview { + StatusBarPopoverView(viewModel: StatusBarMenuDebugInfoViewModel()) +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionSecureVault.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionSecureVault.swift index aa0e13a95e..c854055aab 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionSecureVault.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionSecureVault.swift @@ -26,7 +26,7 @@ typealias DataBrokerProtectionVaultFactory = SecureVaultFactory( makeCryptoProvider: { return DataBrokerProtectionCryptoProvider() - }, makeKeyStoreProvider: { + }, makeKeyStoreProvider: { _ in return DataBrokerProtectionKeyStoreProvider() }, makeDatabaseProvider: { key in return try DefaultDataBrokerProtectionDatabaseProvider(key: key) diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Utils/DataBrokerProtectionSettings.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Utils/DataBrokerProtectionSettings.swift index 1d731fd0f4..78203fa40f 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Utils/DataBrokerProtectionSettings.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Utils/DataBrokerProtectionSettings.swift @@ -17,6 +17,7 @@ // import Foundation +import Combine public final class DataBrokerProtectionSettings { private let defaults: UserDefaults @@ -45,6 +46,8 @@ public final class DataBrokerProtectionSettings { self.init(defaults: .dbp) } + // MARK: - Environment + public var selectedEnvironment: SelectedEnvironment { get { defaults.dataBrokerProtectionSelectedEnvironment @@ -54,6 +57,22 @@ public final class DataBrokerProtectionSettings { defaults.dataBrokerProtectionSelectedEnvironment = newValue } } + + // MARK: - Show in Menu Bar + + public var showInMenuBarPublisher: AnyPublisher { + defaults.networkProtectionSettingShowInMenuBarPublisher + } + + public var showInMenuBar: Bool { + get { + defaults.dataBrokerProtectionShowMenuBarIcon + } + + set { + defaults.dataBrokerProtectionShowMenuBarIcon = newValue + } + } } extension UserDefaults { @@ -61,6 +80,13 @@ extension UserDefaults { "dataBrokerProtectionSelectedEnvironmentRawValue" } + static let showMenuBarIconDefaultValue = false + private var showMenuBarIconKey: String { + "dataBrokerProtectionShowMenuBarIcon" + } + + // MARK: - Environment + @objc dynamic var dataBrokerProtectionSelectedEnvironmentRawValue: String { get { @@ -81,4 +107,25 @@ extension UserDefaults { dataBrokerProtectionSelectedEnvironmentRawValue = newValue.rawValue } } + + // MARK: - Show in Menu Bar + + @objc + dynamic var dataBrokerProtectionShowMenuBarIcon: Bool { + get { + value(forKey: showMenuBarIconKey) as? Bool ?? Self.showMenuBarIconDefaultValue + } + + set { + guard newValue != dataBrokerProtectionShowMenuBarIcon else { + return + } + + set(newValue, forKey: showMenuBarIconKey) + } + } + + var networkProtectionSettingShowInMenuBarPublisher: AnyPublisher { + publisher(for: \.dataBrokerProtectionShowMenuBarIcon).eraseToAnyPublisher() + } } diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index ad131b9869..baaeee8336 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,12 +31,11 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "138.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "139.0.0"), .package(url: "https://github.com/airbnb/lottie-spm", exact: "4.4.1"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), - .package(path: "../PixelKit"), ], targets: [ // MARK: - NetworkProtectionIPC @@ -46,6 +45,7 @@ let package = Package( dependencies: [ .product(name: "NetworkProtection", package: "BrowserServicesKit"), .product(name: "XPCHelper", package: "XPCHelper"), + .product(name: "PixelKit", package: "BrowserServicesKit"), ], swiftSettings: [ .define("DEBUG", .when(configuration: .debug)) @@ -58,7 +58,7 @@ let package = Package( name: "NetworkProtectionProxy", dependencies: [ .product(name: "NetworkProtection", package: "BrowserServicesKit"), - .product(name: "PixelKit", package: "PixelKit"), + .product(name: "PixelKit", package: "BrowserServicesKit"), ], swiftSettings: [ .define("DEBUG", .when(configuration: .debug)) @@ -71,9 +71,9 @@ let package = Package( name: "NetworkProtectionUI", dependencies: [ .product(name: "NetworkProtection", package: "BrowserServicesKit"), + .product(name: "PixelKit", package: "BrowserServicesKit"), .product(name: "SwiftUIExtensions", package: "SwiftUIExtensions"), .product(name: "LoginItems", package: "LoginItems"), - .product(name: "PixelKit", package: "PixelKit"), .product(name: "Lottie", package: "lottie-spm") ], resources: [ @@ -90,7 +90,7 @@ let package = Package( "NetworkProtectionUI", .product(name: "NetworkProtectionTestUtils", package: "BrowserServicesKit"), .product(name: "LoginItems", package: "LoginItems"), - .product(name: "PixelKitTestingUtilities", package: "PixelKit"), + .product(name: "PixelKitTestingUtilities", package: "BrowserServicesKit"), ] ), ] diff --git a/LocalPackages/PixelKit/.gitignore b/LocalPackages/PixelKit/.gitignore deleted file mode 100644 index 3b29812086..0000000000 --- a/LocalPackages/PixelKit/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -.DS_Store -/.build -/Packages -/*.xcodeproj -xcuserdata/ -DerivedData/ -.swiftpm/config/registries.json -.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata -.netrc diff --git a/LocalPackages/PixelKit/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/LocalPackages/PixelKit/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/LocalPackages/PixelKit/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/LocalPackages/PixelKit/Package.swift b/LocalPackages/PixelKit/Package.swift deleted file mode 100644 index f6ca4e0701..0000000000 --- a/LocalPackages/PixelKit/Package.swift +++ /dev/null @@ -1,50 +0,0 @@ -// swift-tools-version: 5.7 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "PixelKit", - platforms: [ - .macOS("11.4") - ], - products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. - .library( - name: "PixelKit", - targets: ["PixelKit"] - ), - .library( - name: "PixelKitTestingUtilities", - targets: ["PixelKitTestingUtilities"] - ) - ], - dependencies: [ - ], - targets: [ - .target( - name: "PixelKit", - dependencies: [ - ], - swiftSettings: [ - .define("DEBUG", .when(configuration: .debug)), - ] - ), - .testTarget( - name: "PixelKitTests", - dependencies: [ - "PixelKit", - "PixelKitTestingUtilities", - ], - swiftSettings: [ - .define("DEBUG", .when(configuration: .debug)) - ] - ), - .target( - name: "PixelKitTestingUtilities", - dependencies: [ - "PixelKit", - ] - ) - ] -) diff --git a/LocalPackages/PixelKit/README.md b/LocalPackages/PixelKit/README.md deleted file mode 100644 index 9d5094a7d8..0000000000 --- a/LocalPackages/PixelKit/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# PixelKit - -This package is meant to provide basic support for firing pixel across different targets. - -This package was designed to not really know specific pixels. Those can be defined -individually by each target importing this package, or through more specialized -shared packages. - -This design decision is meant to make PixelKit lean and to make it possible to use it -for future apps we may decide to make, without it having to carry over all of the business -domain logic for any single app. diff --git a/LocalPackages/PixelKit/Sources/PixelKit/Extensions/String+StaticString.swift b/LocalPackages/PixelKit/Sources/PixelKit/Extensions/String+StaticString.swift deleted file mode 100644 index 19f9b8b692..0000000000 --- a/LocalPackages/PixelKit/Sources/PixelKit/Extensions/String+StaticString.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// String+StaticString.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 String { - init(_ staticString: StaticString) { - self = staticString.withUTF8Buffer { - String(decoding: $0, as: UTF8.self) - } - } -} diff --git a/LocalPackages/PixelKit/Sources/PixelKit/Extensions/URL+PixelKit.swift b/LocalPackages/PixelKit/Sources/PixelKit/Extensions/URL+PixelKit.swift deleted file mode 100644 index 98bb77c2c4..0000000000 --- a/LocalPackages/PixelKit/Sources/PixelKit/Extensions/URL+PixelKit.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// URL+PixelKit.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 URL { - - static let pixelBase = ProcessInfo.processInfo.environment["PIXEL_BASE_URL", default: "https://improving.duckduckgo.com"] - - public static func pixelUrl(forPixelNamed pixelName: String) -> URL { - let urlString = "\(Self.pixelBase)/t/\(pixelName)" - return URL(string: urlString)! - } - -} diff --git a/LocalPackages/PixelKit/Sources/PixelKit/PixelKit+Parameters.swift b/LocalPackages/PixelKit/Sources/PixelKit/PixelKit+Parameters.swift deleted file mode 100644 index b692271709..0000000000 --- a/LocalPackages/PixelKit/Sources/PixelKit/PixelKit+Parameters.swift +++ /dev/null @@ -1,137 +0,0 @@ -// -// PixelKit+Parameters.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 - -public extension PixelKit { - - enum Parameters: Hashable { - public static let duration = "duration" - public static let test = "test" - public static let appVersion = "appVersion" - public static let pixelSource = "pixelSource" - public static let osMajorVersion = "osMajorVersion" - - public static let errorCode = "e" - public static let errorDomain = "d" - public static let errorCount = "c" - public static let errorSource = "error_source" - public static let sourceBrowserVersion = "source_browser_version" - public static let underlyingErrorCode = "ue" - public static let underlyingErrorDomain = "ud" - public static let underlyingErrorSQLiteCode = "sqlrc" - public static let underlyingErrorSQLiteExtendedCode = "sqlerc" - - public static let keychainFieldName = "fieldName" - public static let keychainErrorCode = "keychain_error_code" - - public static let emailCohort = "cohort" - public static let emailLastUsed = "duck_address_last_used" - - public static let assertionMessage = "message" - public static let assertionFile = "file" - public static let assertionLine = "line" - - public static let function = "function" - public static let line = "line" - - public static let latency = "latency" - public static let server = "server" - public static let networkType = "net_type" - - // Pixel experiments - public static let experimentCohort = "cohort" - - // Dashboard - public static let dashboardTriggerOrigin = "trigger_origin" - - // VPN - public static let vpnBreakageCategory = "breakageCategory" - public static let vpnBreakageDescription = "breakageDescription" - public static let vpnBreakageMetadata = "breakageMetadata" - - public static let reason = "reason" - - public static let vpnCohort = "cohort" - } - - enum Values { - public static let test = "1" - } - -} - -public protocol ErrorWithPixelParameters { - - var errorParameters: [String: String] { get } - -} - -public extension Error { - - var pixelParameters: [String: String] { - var params = [String: String]() - - if let errorWithUserInfo = self as? ErrorWithPixelParameters { - params = errorWithUserInfo.errorParameters - } - - let nsError = self as NSError - - params[PixelKit.Parameters.errorCode] = "\(nsError.code)" - params[PixelKit.Parameters.errorDomain] = nsError.domain - - let underlyingErrorParameters = self.underlyingErrorParameters(for: nsError) - params.merge(underlyingErrorParameters) { first, _ in - return first - } - - if let sqlErrorCode = nsError.userInfo["SQLiteResultCode"] as? NSNumber { - params[PixelKit.Parameters.underlyingErrorSQLiteCode] = "\(sqlErrorCode.intValue)" - } - - if let sqlExtendedErrorCode = nsError.userInfo["SQLiteExtendedResultCode"] as? NSNumber { - params[PixelKit.Parameters.underlyingErrorSQLiteExtendedCode] = "\(sqlExtendedErrorCode.intValue)" - } - - return params - } - - /// Recursive call to add underlying error information - /// - func underlyingErrorParameters(for nsError: NSError, level: Int = 0) -> [String: String] { - if let underlyingError = nsError.userInfo[NSUnderlyingErrorKey] as? NSError { - let errorCodeParameterName = PixelKit.Parameters.underlyingErrorCode + (level == 0 ? "" : String(level + 1)) - let errorDomainParameterName = PixelKit.Parameters.underlyingErrorDomain + (level == 0 ? "" : String(level + 1)) - - let currentUnderlyingErrorParameters = [ - errorCodeParameterName: "\(underlyingError.code)", - errorDomainParameterName: underlyingError.domain - ] - - // Check if the underlying error has an underlying error of its own - let additionalParameters = underlyingErrorParameters(for: underlyingError, level: level + 1) - - return currentUnderlyingErrorParameters.merging(additionalParameters) { first, _ in - return first // Doesn't really matter as there should be no conflict of parameters - } - } - - return [:] - } -} diff --git a/LocalPackages/PixelKit/Sources/PixelKit/PixelKit.swift b/LocalPackages/PixelKit/Sources/PixelKit/PixelKit.swift deleted file mode 100644 index d647b28835..0000000000 --- a/LocalPackages/PixelKit/Sources/PixelKit/PixelKit.swift +++ /dev/null @@ -1,476 +0,0 @@ -// -// PixelKit.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 os.log // swiftlint:disable:this enforce_os_log_wrapper - -public final class PixelKit { - /// `true` if a request is fired, `false` otherwise - public typealias CompletionBlock = (Bool, Error?) -> Void - - /// The frequency with which a pixel is sent to our endpoint. - public enum Frequency { - /// The default frequency for pixels. This fires pixels with the event names as-is. - case standard - - /// [Legacy] Used in Pixel.fire(...) as .unique but without the `_u` requirement in the name - case legacyInitial - - /// Sent only once ever. The timestamp for this pixel is stored. - /// Note: This is the only pixel that MUST end with `_u`, Name for pixels of this type must end with if it doesn't an assertion is fired. - case unique - - /// [Legacy] Used in Pixel.fire(...) as .daily but without the `_d` automatically added to the name - case legacyDaily - - /// Sent once per day. The last timestamp for this pixel is stored and compared to the current date. Pixels of this type will have `_d` appended to their name. - case daily - - /// Sent once per day with a `_d` suffix, in addition to every time it is called with a `_c` suffix. - /// This means a pixel will get sent twice the first time it is called per-day, and subsequent calls that day will only send the `_c` variant. - /// This is useful in situations where pixels receive spikes in volume, as the daily pixel can be used to determine how many users are actually affected. - case dailyAndCount - - fileprivate var description: String { - switch self { - case .standard: - "Standard" - case .legacyInitial: - "Legacy Initial" - case .unique: - "Unique" - case .legacyDaily: - "Legacy Daily" - case .daily: - "Daily" - case .dailyAndCount: - "Daily and Count" - } - } - } - - public enum Header { - public static let acceptEncoding = "Accept-Encoding" - public static let acceptLanguage = "Accept-Language" - public static let userAgent = "User-Agent" - public static let ifNoneMatch = "If-None-Match" - public static let moreInfo = "X-DuckDuckGo-MoreInfo" - public static let client = "X-DuckDuckGo-Client" - } - - public enum Source: String { - case macStore = "browser-appstore" - case macDMG = "browser-dmg" - case iOS = "phone" - case iPadOS = "tablet" - } - - /// A closure typealias to request sending pixels through the network. - public typealias FireRequest = ( - _ pixelName: String, - _ headers: [String: String], - _ parameters: [String: String], - _ allowedQueryReservedCharacters: CharacterSet?, - _ callBackOnMainThread: Bool, - _ onComplete: @escaping CompletionBlock) -> Void - - public typealias Event = PixelKitEvent - public static let duckDuckGoMorePrivacyInfo = URL(string: "https://help.duckduckgo.com/duckduckgo-help-pages/privacy/atb/")! - private let defaults: UserDefaults - - private let logger = Logger(subsystem: "com.duckduckgo.PixelKit", category: "PixelKit") - - private static let defaultDailyPixelCalendar: Calendar = { - var calendar = Calendar.current - calendar.timeZone = TimeZone(secondsFromGMT: 0)! - return calendar - }() - - private static let weeksToCoalesceCohort = 6 - - private let dateGenerator: () -> Date - - public private(set) static var shared: PixelKit? - - private let appVersion: String - private let defaultHeaders: [String: String] - private let fireRequest: FireRequest - - /// Sets up PixelKit for the entire app. - /// - /// - Parameters: - /// - `dryRun`: if `true`, simulate requests and "send" them at an accelerated rate (once every 2 minutes instead of once a day) - /// - `source`: if set, adds a `pixelSource` parameter to the pixel call; this can be used to specify which target is sending the pixel - /// - `fireRequest`: this is not triggered when `dryRun` is `true` - public static func setUp(dryRun: Bool = false, - appVersion: String, - source: String? = nil, - defaultHeaders: [String: String], - dailyPixelCalendar: Calendar? = nil, - dateGenerator: @escaping () -> Date = Date.init, - defaults: UserDefaults, - fireRequest: @escaping FireRequest) { - shared = PixelKit(dryRun: dryRun, - appVersion: appVersion, - source: source, - defaultHeaders: defaultHeaders, - dailyPixelCalendar: dailyPixelCalendar, - dateGenerator: dateGenerator, - defaults: defaults, - fireRequest: fireRequest) - } - - public static func tearDown() { - shared = nil - } - - private var dryRun: Bool - private let source: String? - private let pixelCalendar: Calendar - - public init(dryRun: Bool, - appVersion: String, - source: String? = nil, - defaultHeaders: [String: String], - dailyPixelCalendar: Calendar? = nil, - dateGenerator: @escaping () -> Date = Date.init, - defaults: UserDefaults, - fireRequest: @escaping FireRequest) { - - self.dryRun = dryRun - self.appVersion = appVersion - self.source = source - self.defaultHeaders = defaultHeaders - self.pixelCalendar = dailyPixelCalendar ?? Self.defaultDailyPixelCalendar - self.dateGenerator = dateGenerator - self.defaults = defaults - self.fireRequest = fireRequest - logger.debug("👾 PixelKit initialised: dryRun: \(self.dryRun, privacy: .public) appVersion: \(self.appVersion, privacy: .public) source: \(self.source ?? "-", privacy: .public) defaultHeaders: \(self.defaultHeaders, privacy: .public) pixelCalendar: \(self.pixelCalendar, privacy: .public)") - } - - // swiftlint:disable:next function_body_length cyclomatic_complexity - private func fire(pixelNamed pixelName: String, - frequency: Frequency, - withHeaders headers: [String: String]?, - withAdditionalParameters params: [String: String]?, - withError error: Error?, - allowedQueryReservedCharacters: CharacterSet?, - includeAppVersionParameter: Bool, - onComplete: @escaping CompletionBlock) { - - var newParams = params ?? [:] - if includeAppVersionParameter { newParams[Parameters.appVersion] = appVersion } - if let source { newParams[Parameters.pixelSource] = source } - if let error { newParams.appendErrorPixelParams(error: error) } - - #if DEBUG - newParams[Parameters.test] = Values.test - #endif - - var headers = headers ?? defaultHeaders - headers[Header.moreInfo] = "See " + Self.duckDuckGoMorePrivacyInfo.absoluteString - headers[Header.client] = "macOS" - - switch frequency { - case .standard: - reportErrorIf(pixel: pixelName, endsWith: "_u") - reportErrorIf(pixel: pixelName, endsWith: "_d") - fireRequestWrapper(pixelName, headers, newParams, allowedQueryReservedCharacters, true, frequency, onComplete) - case .legacyInitial: - reportErrorIf(pixel: pixelName, endsWith: "_u") - reportErrorIf(pixel: pixelName, endsWith: "_d") - if !pixelHasBeenFiredEver(pixelName) { - fireRequestWrapper(pixelName, headers, newParams, allowedQueryReservedCharacters, true, frequency, onComplete) - updatePixelLastFireDate(pixelName: pixelName) - } else { - printDebugInfo(pixelName: pixelName, frequency: frequency, parameters: newParams, skipped: true) - } - case .unique: - reportErrorIf(pixel: pixelName, endsWith: "_d") - guard pixelName.hasSuffix("_u") else { - assertionFailure("Unique pixel: must end with _u") - return - } - if !pixelHasBeenFiredEver(pixelName) { - fireRequestWrapper(pixelName, headers, newParams, allowedQueryReservedCharacters, true, frequency, onComplete) - updatePixelLastFireDate(pixelName: pixelName) - } else { - printDebugInfo(pixelName: pixelName, frequency: frequency, parameters: newParams, skipped: true) - } - case .legacyDaily: - reportErrorIf(pixel: pixelName, endsWith: "_u") - reportErrorIf(pixel: pixelName, endsWith: "_d") - if !pixelHasBeenFiredToday(pixelName) { - fireRequestWrapper(pixelName, headers, newParams, allowedQueryReservedCharacters, true, frequency, onComplete) - updatePixelLastFireDate(pixelName: pixelName) - } else { - printDebugInfo(pixelName: pixelName, frequency: frequency, parameters: newParams, skipped: true) - } - case .daily: - reportErrorIf(pixel: pixelName, endsWith: "_u") - reportErrorIf(pixel: pixelName, endsWith: "_d") // Because is added automatically - if !pixelHasBeenFiredToday(pixelName) { - fireRequestWrapper(pixelName + "_d", headers, newParams, allowedQueryReservedCharacters, true, frequency, onComplete) - updatePixelLastFireDate(pixelName: pixelName) - } else { - printDebugInfo(pixelName: pixelName + "_d", frequency: frequency, parameters: newParams, skipped: true) - } - case .dailyAndCount: - reportErrorIf(pixel: pixelName, endsWith: "_u") - reportErrorIf(pixel: pixelName, endsWith: "_d") // Because is added automatically - reportErrorIf(pixel: pixelName, endsWith: "_c") // Because is added automatically - if !pixelHasBeenFiredToday(pixelName) { - fireRequestWrapper(pixelName + "_d", headers, newParams, allowedQueryReservedCharacters, true, frequency, onComplete) - updatePixelLastFireDate(pixelName: pixelName) - } else { - printDebugInfo(pixelName: pixelName + "_d", frequency: frequency, parameters: newParams, skipped: true) - } - - fireRequestWrapper(pixelName + "_c", headers, newParams, allowedQueryReservedCharacters, true, frequency, onComplete) - } - } - - /// If the pixel name ends with the forbiddenString then an error is logged or an assertion failure is fired in debug - func reportErrorIf(pixel: String, endsWith forbiddenString: String) { - if pixel.hasSuffix(forbiddenString) { - logger.error("Pixel \(pixel, privacy: .public) must not end with \(forbiddenString, privacy: .public)") - assertionFailure("Pixel \(pixel) must not end with \(forbiddenString)") - } - } - - private func printDebugInfo(pixelName: String, frequency: Frequency, parameters: [String: String], skipped: Bool = false) { - let params = parameters.filter { key, _ in !["test"].contains(key) } - logger.debug("👾[\(frequency.description, privacy: .public)-\(skipped ? "Skipped" : "Fired", privacy: .public)] \(pixelName, privacy: .public) \(params, privacy: .public)") - } - - private func fireRequestWrapper( - _ pixelName: String, - _ headers: [String: String], - _ parameters: [String: String], - _ allowedQueryReservedCharacters: CharacterSet?, - _ callBackOnMainThread: Bool, - _ frequency: Frequency, - _ onComplete: @escaping CompletionBlock) { - printDebugInfo(pixelName: pixelName, frequency: frequency, parameters: parameters, skipped: false) - guard !dryRun else { - // simulate server response time for Dry Run mode - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - onComplete(true, nil) - } - return - } - fireRequest(pixelName, headers, parameters, allowedQueryReservedCharacters, callBackOnMainThread, onComplete) - } - - private func prefixedName(for event: Event) -> String { - if event.name.hasPrefix("m_mac_") { - return event.name - } - - if let debugEvent = event as? DebugEvent { - return "m_mac_debug_\(debugEvent.name)" - } else { - return "m_mac_\(event.name)" - } - } - - public func fire(_ event: Event, - frequency: Frequency = .standard, - withHeaders headers: [String: String]? = nil, - withAdditionalParameters params: [String: String]? = nil, - withError error: Error? = nil, - allowedQueryReservedCharacters: CharacterSet? = nil, - includeAppVersionParameter: Bool = true, - onComplete: @escaping CompletionBlock = { _, _ in }) { - - let pixelName = prefixedName(for: event) - - if !dryRun { - if frequency == .daily, pixelHasBeenFiredToday(pixelName) { - onComplete(false, nil) - return - } else if frequency == .unique, pixelHasBeenFiredEver(pixelName) { - onComplete(false, nil) - return - } - } - - let newParams: [String: String]? - switch (event.parameters, params) { - case (.some(let parameters), .none): - newParams = parameters - case (.none, .some(let parameters)): - newParams = parameters - case (.some(let params1), .some(let params2)): - newParams = params1.merging(params2) { $1 } - case (.none, .none): - newParams = nil - } - - let newError: Error? - - if let event = event as? PixelKitEventV2, - let error = event.error { - - // For v2 events we only consider the error specified in the event - // and purposedly ignore the parameter in this call. - // This is to encourage moving the error over to the protocol error - // instead of still relying on the parameter of this call. - newError = error - } else { - newError = error - } - - fire(pixelNamed: pixelName, - frequency: frequency, - withHeaders: headers, - withAdditionalParameters: newParams, - withError: newError, - allowedQueryReservedCharacters: allowedQueryReservedCharacters, - includeAppVersionParameter: includeAppVersionParameter, - onComplete: onComplete) - } - - public static func fire(_ event: Event, - frequency: Frequency = .standard, - withHeaders headers: [String: String] = [:], - withAdditionalParameters parameters: [String: String]? = nil, - withError error: Error? = nil, - allowedQueryReservedCharacters: CharacterSet? = nil, - includeAppVersionParameter: Bool = true, - onComplete: @escaping CompletionBlock = { _, _ in }) { - - Self.shared?.fire(event, - frequency: frequency, - withHeaders: headers, - withAdditionalParameters: parameters, - withError: error, - allowedQueryReservedCharacters: allowedQueryReservedCharacters, - includeAppVersionParameter: includeAppVersionParameter, - onComplete: onComplete) - } - - private func cohort(from cohortLocalDate: Date?, dateGenerator: () -> Date = Date.init) -> String? { - guard let cohortLocalDate, - let baseDate = pixelCalendar.date(from: .init(year: 2023, month: 1, day: 1)), - let weeksSinceCohortAssigned = pixelCalendar.dateComponents([.weekOfYear], from: cohortLocalDate, to: dateGenerator()).weekOfYear, - let assignedCohort = pixelCalendar.dateComponents([.weekOfYear], from: baseDate, to: cohortLocalDate).weekOfYear else { - return nil - } - - if weeksSinceCohortAssigned > Self.weeksToCoalesceCohort { - return "" - } else { - return "week-" + String(assignedCohort + 1) - } - } - - public static func cohort(from cohortLocalDate: Date?, dateGenerator: () -> Date = Date.init) -> String { - Self.shared?.cohort(from: cohortLocalDate, dateGenerator: dateGenerator) ?? "" - } - - public static func pixelLastFireDate(event: Event) -> Date? { - Self.shared?.pixelLastFireDate(event: event) - } - - public func pixelLastFireDate(pixelName: String) -> Date? { - var date = defaults.object(forKey: userDefaultsKeyName(forPixelName: pixelName)) as? Date - if date == nil { - date = defaults.object(forKey: legacyUserDefaultsKeyName(forPixelName: pixelName)) as? Date - } - return date - } - - public func pixelLastFireDate(event: Event) -> Date? { - pixelLastFireDate(pixelName: prefixedName(for: event)) - } - - private func updatePixelLastFireDate(pixelName: String) { - defaults.set(dateGenerator(), forKey: userDefaultsKeyName(forPixelName: pixelName)) - } - - private func pixelHasBeenFiredToday(_ name: String) -> Bool { - guard !dryRun else { - if let lastFireDate = pixelLastFireDate(pixelName: name), - let twoMinsAgo = pixelCalendar.date(byAdding: .minute, value: -2, to: dateGenerator()) { - return lastFireDate >= twoMinsAgo - } - - return false - } - - if let lastFireDate = pixelLastFireDate(pixelName: name) { - return pixelCalendar.isDate(dateGenerator(), inSameDayAs: lastFireDate) - } - - return false - } - - private func pixelHasBeenFiredEver(_ name: String) -> Bool { - pixelLastFireDate(pixelName: name) != nil - } - - public func clearFrequencyHistoryFor(pixel: PixelKitEventV2) { - guard let name = Self.shared?.userDefaultsKeyName(forPixelName: pixel.name) else { - return - } - self.defaults.removeObject(forKey: name) - } - - public func clearFrequencyHistoryForAllPixels() { - for (key, _) in self.defaults.dictionaryRepresentation() { - if key.hasPrefix(Self.storageKeyPrefixLegacy) || key.hasPrefix(Self.storageKeyPrefix) { - self.defaults.removeObject(forKey: key) - self.logger.debug("🚮 Removing from storage \(key, privacy: .public)") - } - } - } - - static let storageKeyPrefixLegacy = "com.duckduckgo.network-protection.pixel." - static let storageKeyPrefix = "com.duckduckgo.network-protection.pixel." - - /// Initially PixelKit was configured only for serving netP so these very specific keys were used, now PixelKit serves the entire app so we need to move away from them. - /// NOTE: I would remove this 6 months after release - private func legacyUserDefaultsKeyName(forPixelName pixelName: String) -> String { - dryRun - ? "\(Self.storageKeyPrefixLegacy)\(pixelName).dry-run" - : "\(Self.storageKeyPrefixLegacy)\(pixelName)" - } - - private func userDefaultsKeyName(forPixelName pixelName: String) -> String { - return "\(Self.storageKeyPrefix)\(pixelName)\( dryRun ? ".dry-run" : "" )" - } -} - -extension Dictionary where Key == String, Value == String { - - mutating func appendErrorPixelParams(error: Error) { - self.merge(error.pixelParameters) { _, second in - return second - } - } -} - -internal extension PixelKit { - - /// [USE ONLY FOR TESTS] Sets the shared PixelKit.shared singleton - /// - Parameter pixelkit: A custom instance of PixelKit - static func setSharedForTesting(pixelKit: PixelKit) { - Self.shared = pixelKit - } -} diff --git a/LocalPackages/PixelKit/Sources/PixelKit/PixelKitEvent.swift b/LocalPackages/PixelKit/Sources/PixelKit/PixelKitEvent.swift deleted file mode 100644 index ca352f3347..0000000000 --- a/LocalPackages/PixelKit/Sources/PixelKit/PixelKitEvent.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// PixelKitEvent.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 - -/// An event that can be fired using PixelKit. -/// -public protocol PixelKitEvent { - var name: String { get } - var parameters: [String: String]? { get } -} - -/// Implementation of ``PixelKitEvent`` with specific logic for debug events. -/// -public final class DebugEvent: PixelKitEvent { - public enum EventType { - case assertionFailure(message: String, file: StaticString, line: UInt) - case custom(_ event: PixelKitEvent) - } - - public let eventType: EventType - public let error: Error? - - public init(eventType: EventType, error: Error? = nil) { - self.eventType = eventType - 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: - return "assertion_failure" - case .custom(let event): - return event.name - } - } - - public var parameters: [String: String]? { - var params: [String: String] - - if case let .custom(event) = eventType, - let eventParams = event.parameters { - params = eventParams - } else { - params = [String: String]() - } - - if let errorWithUserInfo = error as? ErrorWithPixelParameters { - params = errorWithUserInfo.errorParameters - } - - if case let .assertionFailure(message, file, line) = eventType { - params[PixelKit.Parameters.assertionMessage] = message - params[PixelKit.Parameters.assertionFile] = String(file) - params[PixelKit.Parameters.assertionLine] = String(line) - } - - if let error = error { - let nsError = error as NSError - - params[PixelKit.Parameters.errorCode] = "\(nsError.code)" - params[PixelKit.Parameters.errorDomain] = nsError.domain - - if let underlyingError = nsError.userInfo["NSUnderlyingError"] as? NSError { - params[PixelKit.Parameters.underlyingErrorCode] = "\(underlyingError.code)" - params[PixelKit.Parameters.underlyingErrorDomain] = underlyingError.domain - } - - if let sqlErrorCode = nsError.userInfo["SQLiteResultCode"] as? NSNumber { - params[PixelKit.Parameters.underlyingErrorSQLiteCode] = "\(sqlErrorCode.intValue)" - } - - if let sqlExtendedErrorCode = nsError.userInfo["SQLiteExtendedResultCode"] as? NSNumber { - params[PixelKit.Parameters.underlyingErrorSQLiteExtendedCode] = "\(sqlExtendedErrorCode.intValue)" - } - } - - return params - } -} diff --git a/LocalPackages/PixelKit/Sources/PixelKit/PixelKitEventV2.swift b/LocalPackages/PixelKit/Sources/PixelKit/PixelKitEventV2.swift deleted file mode 100644 index dc641454c9..0000000000 --- a/LocalPackages/PixelKit/Sources/PixelKit/PixelKitEventV2.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// PixelKitEventV2.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 - -/// New version of this protocol that allows us to maintain backwards-compatibility with PixelKitEvent -/// -/// This new implementation seeks to unify the handling of standard pixel parameters inside PixelKit. -/// The starting example of how this can be useful is error parameter handling - this protocol allows -/// the implementer to specify an error without having to know about its parameterisation. -/// -/// The reason this wasn't done directly in `PixelKitEvent` is to reduce the risk of breaking existing -/// pixels, and to allow us to migrate towards this incrementally. -/// -public protocol PixelKitEventV2: PixelKitEvent { - var error: Error? { get } -} - -/// Protocol to support mocking pixel firing. -/// -/// We're adding support for `PixelKitEventV2` events strategically because adding support for earlier pixels -/// would be more complicated and time consuming. The idea of V2 events is that fire calls should not include a lot -/// of parameters. Parameters should be provided by the `PixelKitEventV2` protocol (extending it if necessary) -/// and the call to `fire` should process those properties to serialize in the requests. -/// -public protocol PixelFiring { - func fire(_ event: PixelKitEventV2) - - func fire(_ event: PixelKitEventV2, - frequency: PixelKit.Frequency) -} - -extension PixelKit: PixelFiring { - public func fire(_ event: PixelKitEventV2) { - fire(event, frequency: .standard) - } - - public func fire(_ event: PixelKitEventV2, - frequency: PixelKit.Frequency) { - - fire(event, frequency: frequency, onComplete: { _, _ in }) - } -} diff --git a/LocalPackages/PixelKit/Sources/PixelKitTestingUtilities/PixelFireExpectations.swift b/LocalPackages/PixelKit/Sources/PixelKitTestingUtilities/PixelFireExpectations.swift deleted file mode 100644 index 1a1d8c2f64..0000000000 --- a/LocalPackages/PixelKit/Sources/PixelKitTestingUtilities/PixelFireExpectations.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// PixelFireExpectations.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 PixelKit - -/// Structure containing information about a pixel fire event. -/// -/// This is useful for test validation for libraries that rely on PixelKit, to make sure the pixels contain -/// all of the fields they are supposed to contain.. -/// -public struct PixelFireExpectations { - let pixelName: String - var error: Error? - var underlyingErrors: [Error] - var customFields: [String: String]? - - /// Convenience initializer for cleaner semantics - /// - public static func expect(pixelName: String, error: Error? = nil, underlyingErrors: [Error] = [], customFields: [String: String]? = nil) -> PixelFireExpectations { - - .init(pixelName: pixelName, error: error, underlyingErrors: underlyingErrors, customFields: customFields) - } - - public init(pixelName: String, error: Error? = nil, underlyingErrors: [Error] = [], customFields: [String: String]? = nil) { - self.pixelName = pixelName - self.error = error - self.underlyingErrors = underlyingErrors - self.customFields = customFields - } - - public var parameters: [String: String] { - var parameters = customFields ?? [String: String]() - - if let nsError = error as? NSError { - parameters[PixelKit.Parameters.errorCode] = String(nsError.code) - parameters[PixelKit.Parameters.errorDomain] = nsError.domain - } - - for (index, error) in underlyingErrors.enumerated() { - let errorCodeParameterName = PixelKit.Parameters.underlyingErrorCode + (index == 0 ? "" : String(index + 1)) - let errorDomainParameterName = PixelKit.Parameters.underlyingErrorDomain + (index == 0 ? "" : String(index + 1)) - let nsError = error as NSError - - parameters[errorCodeParameterName] = String(nsError.code) - parameters[errorDomainParameterName] = nsError.domain - } - - return parameters - } -} diff --git a/LocalPackages/PixelKit/Sources/PixelKitTestingUtilities/ValidatePixel.swift b/LocalPackages/PixelKit/Sources/PixelKitTestingUtilities/ValidatePixel.swift deleted file mode 100644 index 00547deb5b..0000000000 --- a/LocalPackages/PixelKit/Sources/PixelKitTestingUtilities/ValidatePixel.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// ValidatePixel.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 PixelKit -import XCTest - -public final class PixelRequestValidator { - public init() {} - - public func validateBasicPixelParams( - expectedAppVersion: String, - expectedUserAgent: String, - requestParameters parameters: [String: String], - requestHeaders headers: [String: String]) { - - XCTAssertEqual(parameters[PixelKit.Parameters.test], "1") - XCTAssertEqual(parameters[PixelKit.Parameters.appVersion], expectedAppVersion) - - XCTAssertEqual(headers[PixelKit.Header.userAgent], expectedUserAgent) - XCTAssertEqual(headers[PixelKit.Header.acceptEncoding], "gzip;q=1.0, compress;q=0.5") - XCTAssertNotNil(headers[PixelKit.Header.acceptLanguage]) - XCTAssertNotNil(headers[PixelKit.Header.moreInfo], PixelKit.duckDuckGoMorePrivacyInfo.absoluteString) - } - - public func validateDebugPixelParams( - expectedError: Error?, - requestParameters parameters: [String: String]) { - - if let error = expectedError as? NSError { - XCTAssertEqual(parameters[PixelKit.Parameters.errorCode], "\(error.code)") - XCTAssertEqual(parameters[PixelKit.Parameters.errorDomain], error.domain) - } - } -} diff --git a/LocalPackages/PixelKit/Sources/PixelKitTestingUtilities/XCTestCase+PixelKit.swift b/LocalPackages/PixelKit/Sources/PixelKitTestingUtilities/XCTestCase+PixelKit.swift deleted file mode 100644 index 81232cd4bb..0000000000 --- a/LocalPackages/PixelKit/Sources/PixelKitTestingUtilities/XCTestCase+PixelKit.swift +++ /dev/null @@ -1,169 +0,0 @@ -// -// XCTestCase+PixelKit.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 -@testable import PixelKit -import XCTest - -public extension XCTestCase { - - // MARK: - Parameters - - /// List of standard pixel parameters. - /// This is useful to support filtering these parameters out if needed. - private static var standardPixelParameters = [ - PixelKit.Parameters.appVersion, - PixelKit.Parameters.pixelSource, - PixelKit.Parameters.test - ] - - /// List of errror pixel parameters - private static var errorPixelParameters = [ - PixelKit.Parameters.errorCode, - PixelKit.Parameters.errorDomain - ] - - /// List of underlying error pixel parameters - private static var underlyingErrorPixelParameters = [ - PixelKit.Parameters.underlyingErrorCode, - PixelKit.Parameters.underlyingErrorDomain - ] - - /// Filter out the standard parameters. - private static func filterStandardPixelParameters(from parameters: [String: String]) -> [String: String] { - parameters.filter { element in - !standardPixelParameters.contains(element.key) - } - } - - static var pixelPlatformPrefix: String { -#if os(macOS) - return "m_mac_" -#elseif os(iOS) - return "m_" -#endif - } - - /// These parameters are known to be expected just based on the event definition. - /// - /// They're not a complete list of parameters for the event, as the fire call may contain extra information - /// that results in additional parameters. Ideally we want most (if not all) that information to eventually - /// make part of the pixel definition. - func knownExpectedParameters(for event: PixelKitEventV2) -> [String: String] { - var expectedParameters = [String: String]() - - if let error = event.error { - let nsError = error as NSError - expectedParameters[PixelKit.Parameters.errorCode] = "\(nsError.code)" - expectedParameters[PixelKit.Parameters.errorDomain] = nsError.domain - - if let underlyingError = nsError.userInfo[NSUnderlyingErrorKey] as? NSError { - expectedParameters[PixelKit.Parameters.underlyingErrorCode] = "\(underlyingError.code)" - expectedParameters[PixelKit.Parameters.underlyingErrorDomain] = underlyingError.domain - } - } - - return expectedParameters - } - - // MARK: - Misc Convenience - - private var userDefaults: UserDefaults { - UserDefaults(suiteName: "testing_\(UUID().uuidString)")! - } - - // MARK: - Pixel Firing Expectations - - func fire(_ event: PixelKitEventV2, frequency: PixelKit.Frequency, and expectations: PixelFireExpectations, file: StaticString, line: UInt) { - verifyThat(event, frequency: frequency, meets: expectations, file: file, line: line) - } - - /// Provides some snapshot of a fired pixel so that external libraries can validate all the expected info is included. - /// - /// This method also checks that there is internal consistency in the expected fields. - func verifyThat(_ event: PixelKitEventV2, - frequency: PixelKit.Frequency, - meets expectations: PixelFireExpectations, - file: StaticString, - line: UInt) { - let expectedPixelNames: [String] = expectedPixelNames(originalName: event.name, frequency: frequency) - let knownExpectedParameters = knownExpectedParameters(for: event) - let callbackExecutedExpectation = expectation(description: "The PixelKit callback has been executed") - - if frequency == .dailyAndCount { - callbackExecutedExpectation.expectedFulfillmentCount = 2 - } - - // Ensure PixelKit is torn down before setting it back up, avoiding unit test race conditions: - PixelKit.tearDown() - - PixelKit.setUp(dryRun: false, - appVersion: "1.0.5", - source: "test-app", - defaultHeaders: [:], - defaults: userDefaults) { firedPixelName, _, firedParameters, _, _, completion in - callbackExecutedExpectation.fulfill() - - let firedParameters = Self.filterStandardPixelParameters(from: firedParameters) - - // Internal validations - XCTAssertTrue(expectedPixelNames.contains(firedPixelName), file: file, line: line) - XCTAssertTrue(knownExpectedParameters.allSatisfy { (key, value) in - firedParameters[key] == value - }) - - if frequency == .dailyAndCount { - XCTAssertTrue(firedPixelName.hasPrefix(expectations.pixelName)) - XCTAssertTrue(firedPixelName.hasSuffix("_c") || firedPixelName.hasSuffix("_d")) - XCTAssertEqual(firedPixelName.count, expectations.pixelName.count + 2) - let exp = self.expectedPixelNames(originalName: expectations.pixelName, frequency: frequency) - XCTAssertTrue(exp.contains(firedPixelName)) - } else { - XCTAssertEqual(expectations.pixelName, firedPixelName) - } - XCTAssertEqual(firedParameters, expectations.parameters) - - completion(true, nil) - } - - PixelKit.fire(event, frequency: frequency) - waitForExpectations(timeout: 0.1) - } - - func expectedPixelNames(originalName: String, frequency: PixelKit.Frequency) -> [String] { - let expectedPixelNameWithoutSuffix = originalName.hasPrefix(Self.pixelPlatformPrefix) ? originalName : Self.pixelPlatformPrefix + originalName - var expectedPixelNames: [String] = [] - - switch frequency { - case .standard: - expectedPixelNames.append(expectedPixelNameWithoutSuffix) - case .legacyInitial: - expectedPixelNames.append(expectedPixelNameWithoutSuffix) - case .unique: - expectedPixelNames.append(expectedPixelNameWithoutSuffix) - case .legacyDaily: - expectedPixelNames.append(expectedPixelNameWithoutSuffix) - case .daily: - expectedPixelNames.append(expectedPixelNameWithoutSuffix.appending("_d")) - case .dailyAndCount: - expectedPixelNames.append(expectedPixelNameWithoutSuffix.appending("_d")) - expectedPixelNames.append(expectedPixelNameWithoutSuffix.appending("_c")) - } - return expectedPixelNames - } -} diff --git a/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitParametersTests.swift b/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitParametersTests.swift deleted file mode 100644 index 4d661d3336..0000000000 --- a/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitParametersTests.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// PixelKitParametersTests.swift -// -// Copyright © 2024 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 XCTest -@testable import PixelKit -import PixelKitTestingUtilities - -final class PixelKitParametersTests: XCTestCase { - - /// Test events for convenience - /// - private enum TestEvent: PixelKitEventV2 { - case errorEvent(error: Error) - - var name: String { - switch self { - case .errorEvent: - return "error_event" - } - } - - var parameters: [String: String]? { - nil - } - - var error: Error? { - switch self { - case .errorEvent(let error): - error - } - } - } - - /// Test that when firing pixels that include multiple levels of underlying error information, all levels - /// are properly included in the pixel. - /// - func testUnderlyingErrorInformationParameters() { - let underlyingError3 = NSError(domain: "test", code: 3) - let underlyingError2 = NSError( - domain: "test", - code: 2, - userInfo: [ - NSUnderlyingErrorKey: underlyingError3 as NSError - ]) - let topLevelError = NSError( - domain: "test", - code: 1, - userInfo: [ - NSUnderlyingErrorKey: underlyingError2 as NSError - ]) - - fire(TestEvent.errorEvent(error: topLevelError), - frequency: .standard, - and: .expect(pixelName: "m_mac_error_event", - error: topLevelError, - underlyingErrors: [underlyingError2, underlyingError3]), - file: #filePath, - line: #line) - } -} diff --git a/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift b/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift deleted file mode 100644 index fed5b7789d..0000000000 --- a/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift +++ /dev/null @@ -1,385 +0,0 @@ -// -// PixelKitTests.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 XCTest -@testable import PixelKit -import os.log // swiftlint:disable:this enforce_os_log_wrapper - -final class PixelKitTests: XCTestCase { - - private func userDefaults() -> UserDefaults { - UserDefaults(suiteName: "testing_\(UUID().uuidString)")! - } - - /// Test events for convenience - /// - private enum TestEvent: String, PixelKitEvent { - case testEvent - case testEventWithoutParameters - case dailyEvent - case dailyEventWithoutParameters - case dailyAndContinuousEvent - case dailyAndContinuousEventWithoutParameters - case uniqueEvent - - var name: String { - switch self { - case .uniqueEvent: - return "\(rawValue)_u" - default: - return rawValue - } - } - - var parameters: [String: String]? { - switch self { - case .testEvent, .dailyEvent, .dailyAndContinuousEvent, .uniqueEvent: - return [ - "eventParam1": "eventParamValue1", - "eventParam2": "eventParamValue2" - ] - case .testEventWithoutParameters, .dailyEventWithoutParameters, .dailyAndContinuousEventWithoutParameters: - return nil - } - } - - var frequency: PixelKit.Frequency { - switch self { - case .testEvent, .testEventWithoutParameters: - return .standard - case .uniqueEvent: - return .unique - case .dailyEvent, .dailyEventWithoutParameters: - return .daily - case .dailyAndContinuousEvent, .dailyAndContinuousEventWithoutParameters: - return .dailyAndCount - } - } - } - - /// Test that a dry run won't execute the fire request callback. - /// - func testDryRunWontExecuteCallback() async { - let appVersion = "1.0.5" - let headers: [String: String] = [:] - - let pixelKit = PixelKit(dryRun: true, appVersion: appVersion, defaultHeaders: headers, dailyPixelCalendar: nil, defaults: userDefaults()) { _, _, _, _, _, _ in - - XCTFail("This callback should not be executed when doing a dry run") - } - - pixelKit.fire(TestEvent.testEvent) - } - - /// Tests firing a sample pixel and ensuring that all fields are properly set in the fire request callback. - /// - func testFiringASamplePixel() { - // Prepare test parameters - let appVersion = "1.0.5" - let headers = ["a": "2", "b": "3", "c": "2000"] - let event = TestEvent.testEvent - let userDefaults = userDefaults() - - // Set expectations - let expectedPixelName = "m_mac_\(event.name)" - let fireCallbackCalled = expectation(description: "Expect the pixel firing callback to be called") - - // Prepare mock to validate expectations - let pixelKit = PixelKit(dryRun: false, - appVersion: appVersion, - defaultHeaders: headers, - dailyPixelCalendar: nil, - defaults: userDefaults) { firedPixelName, firedHeaders, parameters, _, _, _ in - - fireCallbackCalled.fulfill() - - XCTAssertEqual(expectedPixelName, firedPixelName) - XCTAssertTrue(headers.allSatisfy({ key, value in - firedHeaders[key] == value - })) - - 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 - pixelKit.fire(event) - - // Wait for expectations to be fulfilled - wait(for: [fireCallbackCalled], timeout: 0.5) - } - - /// We test firing a daily pixel for the first time executes the fire request callback with the right parameters - /// - func testFiringDailyPixelForTheFirstTime() { - // Prepare test parameters - let appVersion = "1.0.5" - let headers = ["a": "2", "b": "3", "c": "2000"] - let event = TestEvent.dailyEvent - let userDefaults = userDefaults() - - // Set expectations - let expectedPixelName = "m_mac_\(event.name)_d" - let expectedMoreInfoString = "See \(PixelKit.duckDuckGoMorePrivacyInfo)" - let fireCallbackCalled = expectation(description: "Expect the pixel firing callback to be called") - - // Prepare mock to validate expectations - let pixelKit = PixelKit(dryRun: false, - appVersion: appVersion, - defaultHeaders: headers, - dailyPixelCalendar: nil, - defaults: userDefaults) { firedPixelName, firedHeaders, parameters, _, _, _ in - - fireCallbackCalled.fulfill() - - XCTAssertEqual(expectedPixelName, firedPixelName) - XCTAssertTrue(headers.allSatisfy({ key, value in - firedHeaders[key] == value - })) - - 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, frequency: .daily) - - // Wait for expectations to be fulfilled - wait(for: [fireCallbackCalled], timeout: 0.5) - } - - /// We test firing a daily pixel a second time does not execute the fire request callback. - /// - func testDailyPixelDoubleFiringFrequency() { - // Prepare test parameters - let appVersion = "1.0.5" - let headers = ["a": "2", "b": "3", "c": "2000"] - let event = TestEvent.dailyEvent - let userDefaults = userDefaults() - - // Set expectations - let expectedPixelName = "m_mac_\(event.name)_d" - let expectedMoreInfoString = "See \(PixelKit.duckDuckGoMorePrivacyInfo)" - let fireCallbackCalled = expectation(description: "Expect the pixel firing callback to be called") - fireCallbackCalled.expectedFulfillmentCount = 1 - fireCallbackCalled.assertForOverFulfill = true - - // Prepare mock to validate expectations - let pixelKit = PixelKit(dryRun: false, - appVersion: appVersion, - defaultHeaders: headers, - dailyPixelCalendar: nil, - defaults: userDefaults) { firedPixelName, firedHeaders, parameters, _, _, _ in - - fireCallbackCalled.fulfill() - - XCTAssertEqual(expectedPixelName, firedPixelName) - XCTAssertTrue(headers.allSatisfy({ key, value in - firedHeaders[key] == value - })) - - 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, frequency: .daily) - pixelKit.fire(event, frequency: .daily) - - // Wait for expectations to be fulfilled - wait(for: [fireCallbackCalled], timeout: 0.5) - } - - /// Test firing a daily pixel a few times - func testDailyPixelFrequency() { - // Prepare test parameters - let appVersion = "1.0.5" - let headers = ["a": "2", "b": "3", "c": "2000"] - let event = TestEvent.dailyEvent - let userDefaults = userDefaults() - - let timeMachine = TimeMachine() - - // Set expectations - let fireCallbackCalled = expectation(description: "Expect the pixel firing callback to be called") - fireCallbackCalled.expectedFulfillmentCount = 3 - fireCallbackCalled.assertForOverFulfill = true - - // Prepare mock to validate expectations - let pixelKit = PixelKit(dryRun: false, - appVersion: appVersion, - defaultHeaders: headers, - dailyPixelCalendar: nil, - dateGenerator: timeMachine.now, - defaults: userDefaults) { _, _, _, _, _, _ in - fireCallbackCalled.fulfill() - } - - // Run test - pixelKit.fire(event, frequency: .daily) // Fired - timeMachine.travel(by: .hour, value: 2) - pixelKit.fire(event, frequency: .legacyDaily) // Skipped - - timeMachine.travel(by: .day, value: 1) - timeMachine.travel(by: .hour, value: 2) - pixelKit.fire(event, frequency: .legacyDaily) // Fired - - timeMachine.travel(by: .hour, value: 10) - pixelKit.fire(event, frequency: .legacyDaily) // Skipped - - timeMachine.travel(by: .day, value: 1) - pixelKit.fire(event, frequency: .legacyDaily) // Fired - - // Wait for expectations to be fulfilled - wait(for: [fireCallbackCalled], timeout: 0.5) - } - - /// Test firing a unique pixel - func testUniquePixel() { - // Prepare test parameters - let appVersion = "1.0.5" - let headers = ["a": "2", "b": "3", "c": "2000"] - let event = TestEvent.uniqueEvent - let userDefaults = userDefaults() - - let timeMachine = TimeMachine() - - // Set expectations - let fireCallbackCalled = expectation(description: "Expect the pixel firing callback to be called") - fireCallbackCalled.expectedFulfillmentCount = 1 - fireCallbackCalled.assertForOverFulfill = true - - let pixelKit = PixelKit(dryRun: false, - appVersion: appVersion, - defaultHeaders: headers, - dailyPixelCalendar: nil, - dateGenerator: timeMachine.now, - defaults: userDefaults) { _, _, _, _, _, _ in - fireCallbackCalled.fulfill() - } - - // Run test - pixelKit.fire(event, frequency: .unique) // Fired - timeMachine.travel(by: .hour, value: 2) - pixelKit.fire(event, frequency: .unique) // Skipped (already fired) - - timeMachine.travel(by: .day, value: 1) - timeMachine.travel(by: .hour, value: 2) - pixelKit.fire(event, frequency: .unique) // Skipped (already fired) - - timeMachine.travel(by: .hour, value: 10) - pixelKit.fire(event, frequency: .unique) // Skipped (already fired) - - timeMachine.travel(by: .day, value: 1) - pixelKit.fire(event, frequency: .unique) // Skipped (already fired) - - // Wait for expectations to be fulfilled - wait(for: [fireCallbackCalled], timeout: 0.5) - } - - func testVPNCohort() { - XCTAssertEqual(PixelKit.cohort(from: nil), "") - assertCohortEqual(.init(year: 2023, month: 1, day: 1), reportAs: "week-1") - assertCohortEqual(.init(year: 2024, month: 2, day: 24), reportAs: "week-60") - } - - private func assertCohortEqual(_ cohort: DateComponents, reportAs reportedCohort: String) { - var calendar = Calendar.current - calendar.timeZone = TimeZone(secondsFromGMT: 0)! - calendar.locale = Locale(identifier: "en_US_POSIX") - - let cohort = calendar.date(from: cohort) - let timeMachine = TimeMachine(calendar: calendar, date: cohort) - - PixelKit.setUp(appVersion: "test", - defaultHeaders: [:], - dailyPixelCalendar: calendar, - dateGenerator: timeMachine.now, - defaults: userDefaults()) { _, _, _, _, _, _ in } - - // 1st week - XCTAssertEqual(PixelKit.cohort(from: cohort, dateGenerator: timeMachine.now), reportedCohort) - - // 2nd week - timeMachine.travel(by: .weekOfYear, value: 1) - XCTAssertEqual(PixelKit.cohort(from: cohort, dateGenerator: timeMachine.now), reportedCohort) - - // 3rd week - timeMachine.travel(by: .weekOfYear, value: 1) - XCTAssertEqual(PixelKit.cohort(from: cohort, dateGenerator: timeMachine.now), reportedCohort) - - // 4th week - timeMachine.travel(by: .weekOfYear, value: 1) - XCTAssertEqual(PixelKit.cohort(from: cohort, dateGenerator: timeMachine.now), reportedCohort) - - // 5th week - timeMachine.travel(by: .weekOfYear, value: 1) - XCTAssertEqual(PixelKit.cohort(from: cohort, dateGenerator: timeMachine.now), reportedCohort) - - // 6th week - timeMachine.travel(by: .weekOfYear, value: 1) - XCTAssertEqual(PixelKit.cohort(from: cohort, dateGenerator: timeMachine.now), reportedCohort) - - // 7th week - timeMachine.travel(by: .weekOfYear, value: 1) - XCTAssertEqual(PixelKit.cohort(from: cohort, dateGenerator: timeMachine.now), reportedCohort) - - // 8th week - timeMachine.travel(by: .weekOfYear, value: 1) - XCTAssertEqual(PixelKit.cohort(from: cohort, dateGenerator: timeMachine.now), "") - } -} - -private class TimeMachine { - private var date: Date - private let calendar: Calendar - - init(calendar: Calendar? = nil, date: Date? = nil) { - self.calendar = calendar ?? { - var calendar = Calendar.current - calendar.timeZone = TimeZone(secondsFromGMT: 0)! - calendar.locale = Locale(identifier: "en_US_POSIX") - return calendar - }() - self.date = date ?? .init(timeIntervalSince1970: 0) - } - - func travel(by component: Calendar.Component, value: Int) { - date = calendar.date(byAdding: component, value: value, to: now())! - } - - func now() -> Date { - date - } -} diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 9092bb8c50..41c971172f 100644 --- a/LocalPackages/SubscriptionUI/Package.swift +++ b/LocalPackages/SubscriptionUI/Package.swift @@ -12,7 +12,7 @@ let package = Package( targets: ["SubscriptionUI"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "138.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "139.0.0"), .package(path: "../SwiftUIExtensions") ], targets: [ @@ -24,7 +24,11 @@ let package = Package( ], resources: [ .process("Resources") - ]), + ], + swiftSettings: [ + .define("DEBUG", .when(configuration: .debug)) + ] + ), .testTarget( name: "SubscriptionUITests", dependencies: ["SubscriptionUI"]), diff --git a/UnitTests/Autofill/Mocks/MockAutofillActionExecutor.swift b/UnitTests/Autofill/Mocks/MockAutofillActionExecutor.swift index bb7a4ec8bb..d94b13ccb0 100644 --- a/UnitTests/Autofill/Mocks/MockAutofillActionExecutor.swift +++ b/UnitTests/Autofill/Mocks/MockAutofillActionExecutor.swift @@ -27,7 +27,7 @@ final class MockAutofillActionBuilder: AutofillActionBuilder { var mockPresenter: MockAutofillActionPresenter? func buildExecutor() -> AutofillActionExecutor? { - guard let secureVault = try? MockSecureVaultFactory.makeVault(errorReporter: nil) else { return nil } + guard let secureVault = try? MockSecureVaultFactory.makeVault(reporter: nil) else { return nil } let syncService = MockDDGSyncing(authState: .inactive, scheduler: CapturingScheduler(), isSyncInProgress: false) let executor = MockAutofillActionExecutor(userAuthenticator: UserAuthenticatorMock(), secureVault: secureVault, syncService: syncService) self.mockExecutor = executor diff --git a/UnitTests/Autofill/Tests/AutofillDeleteAllPasswordsExecutorTests.swift b/UnitTests/Autofill/Tests/AutofillDeleteAllPasswordsExecutorTests.swift index f34960a14f..3b262f145d 100644 --- a/UnitTests/Autofill/Tests/AutofillDeleteAllPasswordsExecutorTests.swift +++ b/UnitTests/Autofill/Tests/AutofillDeleteAllPasswordsExecutorTests.swift @@ -30,7 +30,7 @@ final class AutofillDeleteAllPasswordsExecutorTests: XCTestCase { private var syncService: DDGSyncing! override func setUpWithError() throws { - secureVault = try MockSecureVaultFactory.makeVault(errorReporter: nil) + secureVault = try MockSecureVaultFactory.makeVault(reporter: nil) syncService = MockDDGSyncing(authState: .inactive, scheduler: scheduler, isSyncInProgress: false) sut = .init(userAuthenticator: mockAuthenticator, secureVault: secureVault, syncService: syncService) } diff --git a/UnitTests/DataExport/CSVLoginExporterTests.swift b/UnitTests/DataExport/CSVLoginExporterTests.swift index 20d244968e..bd3c079383 100644 --- a/UnitTests/DataExport/CSVLoginExporterTests.swift +++ b/UnitTests/DataExport/CSVLoginExporterTests.swift @@ -25,7 +25,7 @@ class CSVLoginExporterTests: XCTestCase { func testWhenExportingLogins_ThenLoginsArePersistedToDisk() throws { let mockFileStore = FileStoreMock() - let vault = try MockSecureVaultFactory.makeVault(errorReporter: nil) + let vault = try MockSecureVaultFactory.makeVault(reporter: nil) vault.addWebsiteCredentials(identifiers: [1]) diff --git a/UnitTests/DataExport/MockSecureVault.swift b/UnitTests/DataExport/MockSecureVault.swift index c92a6f6189..d9d55a92fa 100644 --- a/UnitTests/DataExport/MockSecureVault.swift +++ b/UnitTests/DataExport/MockSecureVault.swift @@ -26,7 +26,7 @@ typealias MockVaultFactory = SecureVaultFactory( makeCryptoProvider: { return MockCryptoProvider() - }, makeKeyStoreProvider: { + }, makeKeyStoreProvider: { _ in let provider = MockKeyStoreProvider() provider._l1Key = "key".data(using: .utf8) return provider diff --git a/UnitTests/HomePage/DataImportProviderTests.swift b/UnitTests/HomePage/DataImportProviderTests.swift index 325f97e461..a67468dd72 100644 --- a/UnitTests/HomePage/DataImportProviderTests.swift +++ b/UnitTests/HomePage/DataImportProviderTests.swift @@ -55,7 +55,7 @@ final class DataImportProviderTests: XCTestCase { override func setUp() { UserDefaultsWrapper.clearAll() - vault = try! MockSecureVaultFactory.makeVault(errorReporter: nil) + vault = try! MockSecureVaultFactory.makeVault(reporter: nil) vault.storedAccounts = notImportedAccounts vault.storedIdentities = [] vault.storedCards = [] diff --git a/UnitTests/Preferences/AutofillPreferencesModelTests.swift b/UnitTests/Preferences/AutofillPreferencesModelTests.swift index 79341abe79..9851f65f72 100644 --- a/UnitTests/Preferences/AutofillPreferencesModelTests.swift +++ b/UnitTests/Preferences/AutofillPreferencesModelTests.swift @@ -49,7 +49,7 @@ final class UserAuthenticatorMock: UserAuthenticating { final class AutofillPreferencesModelTests: XCTestCase { func neverPromptWebsitesManager() throws -> AutofillNeverPromptWebsitesManager { - try AutofillNeverPromptWebsitesManager(secureVault: MockSecureVaultFactory.makeVault(errorReporter: nil)) + try AutofillNeverPromptWebsitesManager(secureVault: MockSecureVaultFactory.makeVault(reporter: nil)) } @MainActor