From 10e5fc8c8d506ec38e86f20213fcdad16c208706 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Wed, 28 Feb 2024 19:22:41 +0600 Subject: [PATCH 01/10] Fix download relaunched (#2275) Task/Issue URL: https://app.asana.com/0/1199178362774117/1203556496529649/f --- .../NavigationActionExtension.swift | 7 +++++ .../View/AppKit/LoadingProgressView.swift | 8 +++++- DuckDuckGo/Tab/Model/Tab.swift | 2 ++ .../TabExtensions/DownloadsTabExtension.swift | 28 +++++++++++++++---- .../Permissions/TabPermissionsTests.swift | 18 ++++++------ 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/DuckDuckGo/Common/Extensions/NavigationActionExtension.swift b/DuckDuckGo/Common/Extensions/NavigationActionExtension.swift index de1496ef9a..f633e99656 100644 --- a/DuckDuckGo/Common/Extensions/NavigationActionExtension.swift +++ b/DuckDuckGo/Common/Extensions/NavigationActionExtension.swift @@ -31,6 +31,13 @@ extension NavigationAction { return false } + var isCustom: Bool { + if case .custom = self.navigationType { + return true + } + return false + } + } extension CustomNavigationType { diff --git a/DuckDuckGo/Common/View/AppKit/LoadingProgressView.swift b/DuckDuckGo/Common/View/AppKit/LoadingProgressView.swift index 0c16098da7..5dd87c33e8 100644 --- a/DuckDuckGo/Common/View/AppKit/LoadingProgressView.swift +++ b/DuckDuckGo/Common/View/AppKit/LoadingProgressView.swift @@ -118,6 +118,7 @@ final class LoadingProgressView: NSView, CAAnimationDelegate { && progressMask.animation(forKey: Constants.fadeOutAnimationKey) == nil else { return } + self.lastEvent = ProgressEvent(progress: Constants.max, interval: Constants.hideAnimationDuration) increaseProgress(to: Constants.max, animationDuration: Constants.hideAnimationDuration) } @@ -302,7 +303,12 @@ extension LoadingProgressView { for (idx, step) in milestones.enumerated() { if let event = lastProgressEvent { - if event.progress >= step.progress { + if event.progress == Constants.max { + // 100%: finish fast + nextStepIdx = milestones.indices.last! + estimatedElapsedTime = TimeInterval.greatestFiniteMagnitude + break + } else if event.progress >= step.progress { estimatedElapsedTime += step.interval } else { // take percentage of estimated time for the current step based of (actual / estimated) progress difference diff --git a/DuckDuckGo/Tab/Model/Tab.swift b/DuckDuckGo/Tab/Model/Tab.swift index a8dc0f6c89..10beaf65c1 100644 --- a/DuckDuckGo/Tab/Model/Tab.swift +++ b/DuckDuckGo/Tab/Model/Tab.swift @@ -665,6 +665,8 @@ protocol NewWindowPolicyDecisionMaker { } else if content != self.content { self.content = content } + } else if self.content.isUrl { + self.content = .none } self.updateTitle() // The title might not change if webView doesn't think anything is different so update title here as well } diff --git a/DuckDuckGo/Tab/TabExtensions/DownloadsTabExtension.swift b/DuckDuckGo/Tab/TabExtensions/DownloadsTabExtension.swift index ab54bb1701..79ce4aed1d 100644 --- a/DuckDuckGo/Tab/TabExtensions/DownloadsTabExtension.swift +++ b/DuckDuckGo/Tab/TabExtensions/DownloadsTabExtension.swift @@ -30,8 +30,9 @@ protocol TabDownloadsDelegate: AnyObject { final class DownloadsTabExtension: NSObject { private let downloadManager: FileDownloadManagerProtocol - private let isBurner: Bool private let downloadsPreferences: DownloadsPreferences + private let isBurner: Bool + private var isRestoringSessionState = false @Published private(set) var savePanelDialogRequest: SavePanelDialogRequest? { @@ -103,7 +104,16 @@ extension DownloadsTabExtension: NavigationResponder { @MainActor func decidePolicy(for navigationAction: NavigationAction, preferences: inout NavigationPreferences) async -> NavigationActionPolicy? { - if navigationAction.shouldDownload + if case .sessionRestoration = navigationAction.navigationType { + self.isRestoringSessionState = true + } else if isRestoringSessionState, + navigationAction.isUserInitiated || navigationAction.isCustom || navigationAction.isUserEnteredUrl + || [.reload, .formSubmitted, .formResubmitted, .alternateHtmlLoad, .reload].contains(navigationAction.navigationType) + || navigationAction.navigationType.isBackForward { + self.isRestoringSessionState = false + } + + if (navigationAction.shouldDownload && !self.isRestoringSessionState) // to be modularized later, modifiers should be collected on click (and key down!) event and passed as .custom NavigationType || (navigationAction.navigationType.isLinkActivated && NSApp.isOptionPressed && !NSApp.isCommandPressed) { @@ -115,13 +125,19 @@ extension DownloadsTabExtension: NavigationResponder { @MainActor func decidePolicy(for navigationResponse: NavigationResponse) async -> NavigationResponsePolicy? { + // get an initial Navigation Action + let firstNavigationAction = navigationResponse.mainFrameNavigation?.redirectHistory.first + ?? navigationResponse.mainFrameNavigation?.navigationAction + guard navigationResponse.httpResponse?.isSuccessful == true, - !navigationResponse.canShowMIMEType || navigationResponse.shouldDownload - else { - return .next + !navigationResponse.canShowMIMEType || navigationResponse.shouldDownload else { + return .next // proceed with normal page loading } + // prevent download twice for session restoration/tab reopening requests - guard !navigationResponse.isForMainFrame || navigationResponse.mainFrameNavigation?.request.cachePolicy != .returnCacheDataElseLoad else { + guard firstNavigationAction?.request.cachePolicy != .returnCacheDataElseLoad, + !isRestoringSessionState + else { return .cancel } diff --git a/UnitTests/Permissions/TabPermissionsTests.swift b/UnitTests/Permissions/TabPermissionsTests.swift index bed63d5ae3..d51411e6c4 100644 --- a/UnitTests/Permissions/TabPermissionsTests.swift +++ b/UnitTests/Permissions/TabPermissionsTests.swift @@ -69,7 +69,7 @@ final class TabPermissionsTests: XCTestCase { @MainActor func testWhenExternalAppPermissionRequestedAndGranted_AppIsOpened() async throws { - let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self]) + let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self, DownloadsTabExtension.self]) let workspace = WorkspaceMock() let tab = Tab(content: .none, webViewConfiguration: webViewConfiguration, workspace: workspace, privacyFeatures: privacyFeaturesMock, extensionsBuilder: extensionsBuilder) @@ -150,7 +150,7 @@ final class TabPermissionsTests: XCTestCase { @MainActor func testWhenExternalAppPermissionRequestedAndGrantedAndPersisted_AppIsOpened() async throws { - let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self]) + let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self, DownloadsTabExtension.self]) let workspace = WorkspaceMock() let tab = Tab(content: .none, webViewConfiguration: webViewConfiguration, workspace: workspace, privacyFeatures: privacyFeaturesMock, permissionManager: PermissionManagerMock(), extensionsBuilder: extensionsBuilder) @@ -222,7 +222,7 @@ final class TabPermissionsTests: XCTestCase { @MainActor func testWhenExternalAppPermissionEnteredByUser_permissionIsQueriedAndAppIsOpened() async throws { - let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self]) + let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self, DownloadsTabExtension.self]) let workspace = WorkspaceMock() let tab = Tab(content: .none, webViewConfiguration: webViewConfiguration, workspace: workspace, privacyFeatures: privacyFeaturesMock, extensionsBuilder: extensionsBuilder) @@ -269,7 +269,7 @@ final class TabPermissionsTests: XCTestCase { @MainActor func testWhenExternalAppPermissionRejected_AppIsNotOpened() async throws { - let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self]) + let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self, DownloadsTabExtension.self]) let workspace = WorkspaceMock() let tab = Tab(content: .none, webViewConfiguration: webViewConfiguration, workspace: workspace, privacyFeatures: privacyFeaturesMock, extensionsBuilder: extensionsBuilder) @@ -313,7 +313,7 @@ final class TabPermissionsTests: XCTestCase { @MainActor func testWhenExternalAppNotFound_AppIsNotOpened() async throws { - let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self]) + let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self, DownloadsTabExtension.self]) let workspace = WorkspaceMock() let tab = Tab(content: .none, webViewConfiguration: webViewConfiguration, workspace: workspace, privacyFeatures: privacyFeaturesMock, extensionsBuilder: extensionsBuilder) @@ -351,7 +351,7 @@ final class TabPermissionsTests: XCTestCase { @MainActor func testWhenExternalAppNotFoundForUserEnteredUrl_SearchIsDone() async throws { - let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self]) + let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self, DownloadsTabExtension.self]) let workspace = WorkspaceMock() let tab = Tab(content: .none, webViewConfiguration: webViewConfiguration, workspace: workspace, privacyFeatures: privacyFeaturesMock, extensionsBuilder: extensionsBuilder) @@ -393,7 +393,7 @@ final class TabPermissionsTests: XCTestCase { @MainActor func testWhenSessionIsRestored_externalAppIsNotOpened() { var eDidCancel: XCTestExpectation! - let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self]) { builder in { _, _ in + let extensionsBuilder = TestTabExtensionsBuilder(load: [ExternalAppSchemeHandler.self, DownloadsTabExtension.self]) { builder in { _, _ in builder.add { TestsClosureNavigationResponderTabExtension(.init { _, _ in .next @@ -432,10 +432,10 @@ final class TabPermissionsTests: XCTestCase { } permissionRequest.fulfill() } - eDidCancel = expectation(description: "didCancel external app should be called") + eDidCancel = expectation(description: "external app permission requested") // but should open auth query on reload - tab.reload() + tab.setContent(.url(externalUrl, source: .reload)) waitForExpectations(timeout: 2) From 19b85fbc268da5a3e92af86294161ba12534e507 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Wed, 28 Feb 2024 16:59:17 +0100 Subject: [PATCH 02/10] Fixes a crash in the VPN (#2282) Task/Issue URL: https://app.asana.com/0/414235014887631/1206703155649003/f Tech Design URL: CC: iOS PR: https://github.com/duckduckgo/iOS/pull/2513 BSK PR: https://github.com/duckduckgo/BrowserServicesKit/pull/685 ## Description Fixes a crash in the VPN. --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/PixelKit/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SwiftUIExtensions/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- LocalPackages/XPCHelper/Package.swift | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 8cc3fcf61c..2e052a9df9 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13577,7 +13577,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 111.1.1; + version = "111.1.1-1"; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ef6b11ab0e..7273c7c6a2 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "e3140633373b14b3d1fca25b098869cdaa753913", - "version" : "111.1.1" + "revision" : "68b7b5ae15073b16092f0fb3db218a4d11e80a06", + "version" : "111.1.1-1" } }, { diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 4d25c04c82..b91170fa44 100644 --- a/LocalPackages/DataBrokerProtection/Package.swift +++ b/LocalPackages/DataBrokerProtection/Package.swift @@ -29,7 +29,7 @@ let package = Package( targets: ["DataBrokerProtection"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1-1"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper") diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index ce9f3e231b..0b079b0213 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -13,7 +13,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1-1"), ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index d7a03b3840..71ccb3daab 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1-1"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems") diff --git a/LocalPackages/PixelKit/Package.swift b/LocalPackages/PixelKit/Package.swift index b67d4426dd..48faf6708a 100644 --- a/LocalPackages/PixelKit/Package.swift +++ b/LocalPackages/PixelKit/Package.swift @@ -20,7 +20,7 @@ let package = Package( ) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1-1"), ], targets: [ .target( diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index fecf8da6f9..9ab3126988 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: "111.1.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1-1"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SwiftUIExtensions/Package.swift b/LocalPackages/SwiftUIExtensions/Package.swift index d9c2ead7e0..53d75a81cc 100644 --- a/LocalPackages/SwiftUIExtensions/Package.swift +++ b/LocalPackages/SwiftUIExtensions/Package.swift @@ -11,7 +11,7 @@ let package = Package( .library(name: "PreferencesViews", targets: ["PreferencesViews"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1-1"), ], targets: [ .target( diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 6e815be716..b8079d9846 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(path: "../SwiftUIExtensions"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1-1"), ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index 69bdfde1b8..9e172234e2 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -16,7 +16,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1-1"), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/LocalPackages/XPCHelper/Package.swift b/LocalPackages/XPCHelper/Package.swift index d909c2db38..917cf7e2cb 100644 --- a/LocalPackages/XPCHelper/Package.swift +++ b/LocalPackages/XPCHelper/Package.swift @@ -30,7 +30,7 @@ let package = Package( .library(name: "XPCHelper", targets: ["XPCHelper"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "111.1.1-1"), ], targets: [ .target( From cc8dcb1224c236fd9661bb5c53fbc4fce0e14567 Mon Sep 17 00:00:00 2001 From: Sabrina Tardio <44158575+SabrinaTardio@users.noreply.github.com> Date: Wed, 28 Feb 2024 17:02:11 +0100 Subject: [PATCH 03/10] fix misalignment (#2283) Task/Issue URL: https://app.asana.com/0/1199230911884351/1206695179785373/f **Description**: Fix Setting title misalignment **Steps to test this PR**: 1. Open settings and check titles are aligned --- .../Sources/PreferencesViews/PreferencesViews.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/LocalPackages/SwiftUIExtensions/Sources/PreferencesViews/PreferencesViews.swift b/LocalPackages/SwiftUIExtensions/Sources/PreferencesViews/PreferencesViews.swift index c0a34f4d46..ad3c14b9f8 100644 --- a/LocalPackages/SwiftUIExtensions/Sources/PreferencesViews/PreferencesViews.swift +++ b/LocalPackages/SwiftUIExtensions/Sources/PreferencesViews/PreferencesViews.swift @@ -29,7 +29,6 @@ public struct TextMenuTitle: View { public var body: some View { Text(text) .font(Const.Fonts.preferencePaneTitle) - .padding(.horizontal) } } From 77c993072bbe9c7b4df8802b9aec2b46c42eb88e Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Wed, 28 Feb 2024 19:12:13 +0100 Subject: [PATCH 04/10] Fixes an issue where remove all wasn't working for the list of fp sites (#2285) Task/Issue URL: https://app.asana.com/0/1177771139624306/1206711807883261/f Tech Design URL: CC: ## Description "Remove all" fireproofed sites not working. --- DuckDuckGo/Preferences/View/FireproofDomains.storyboard | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DuckDuckGo/Preferences/View/FireproofDomains.storyboard b/DuckDuckGo/Preferences/View/FireproofDomains.storyboard index 02cf85ff14..6c83c4dda2 100644 --- a/DuckDuckGo/Preferences/View/FireproofDomains.storyboard +++ b/DuckDuckGo/Preferences/View/FireproofDomains.storyboard @@ -29,6 +29,9 @@ + + + From f33051437131d10da5a8e81ac6e9ee3a04415625 Mon Sep 17 00:00:00 2001 From: Dax the Duck Date: Wed, 28 Feb 2024 18:42:28 +0000 Subject: [PATCH 05/10] Bump version to 1.77.0 (129) --- Configuration/BuildNumber.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Configuration/BuildNumber.xcconfig b/Configuration/BuildNumber.xcconfig index cc8e57a8b9..3f4f3b4e21 100644 --- a/Configuration/BuildNumber.xcconfig +++ b/Configuration/BuildNumber.xcconfig @@ -1 +1 @@ -CURRENT_PROJECT_VERSION = 128 +CURRENT_PROJECT_VERSION = 129 From febcc0c073b5bebbfa97dedb9f7a47d0fd13e646 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Thu, 29 Feb 2024 11:31:30 +0600 Subject: [PATCH 06/10] Test fixes (#2278) Task/Issue URL: https://app.asana.com/0/0/1206696533817490/f --- DuckDuckGo.xcodeproj/project.pbxproj | 48 +++---- .../DuckDuckGo Privacy Browser.xcscheme | 12 -- DuckDuckGo/Common/Database/Database.swift | 24 ++-- .../Common/Extensions/URLExtension.swift | 3 +- .../MainWindow/MainViewController.swift | 8 +- .../View/AddressBarViewController.swift | 2 +- .../NavigationBar/View/MoreOptionsMenu.swift | 10 +- DuckDuckGo/Tab/Model/Tab.swift | 10 +- DuckDuckGo/Tab/View/BrowserTabView.swift | 20 ++- .../Tab/View/BrowserTabViewController.swift | 22 ++-- .../Downloads/DownloadsIntegrationTests.swift | 15 ++- .../History/HistoryIntegrationTests.swift | 21 ++- IntegrationTests/Tab/AddressBarTests.swift | 122 ++++++++++-------- IntegrationTests/Tab/ErrorPageTests.swift | 49 ++++--- .../Model/Actions/EmailConfirmation.swift | 2 +- .../Operations/DataBrokerOperation.swift | 2 +- .../Services/CaptchaService.swift | 13 +- .../Services/EmailService.swift | 8 +- .../CaptchaServiceTests.swift | 4 +- .../EmailServiceTests.swift | 16 +-- .../DataBrokerProtectionTests/Mocks.swift | 6 +- .../App/AppStateChangePublisherTests.swift | 71 ++++------ UnitTests/App/DeallocationTests.swift | 2 - .../ConnectBitwardenViewModelTests.swift | 15 ++- .../Extensions/FutureExtensionTests.swift | 6 +- .../FileManagerTempDirReplacement.swift | 13 +- UnitTests/Common/TestRunHelper.swift | 5 +- UnitTests/Fire/Model/FireTests.swift | 11 +- UnitTests/Menus/MoreOptionsMenuTests.swift | 61 +++++---- .../FireproofingReferenceTests.swift | 55 +++----- .../TabBar/ViewModel/TabLazyLoaderTests.swift | 10 +- .../AdClickAttributionTabExtensionTests.swift | 3 + 32 files changed, 373 insertions(+), 296 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index c6ec2df9f9..32a7701d5f 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3171,13 +3171,6 @@ remoteGlobalIDString = 3706FA6A293F65D500E42796; remoteInfo = "DuckDuckGo Privacy Browser App Store"; }; - 4B1AD8A225FC27E200261379 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = AA585D76248FD31100E9A3E2 /* Project object */; - proxyType = 1; - remoteGlobalIDString = AA585D7D248FD31100E9A3E2; - remoteInfo = "DuckDuckGo Privacy Browser"; - }; 4BA7C4DE2B3F6F4900AFE511 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = AA585D76248FD31100E9A3E2 /* Project object */; @@ -3213,19 +3206,26 @@ remoteGlobalIDString = 4B2537592A11BE7300610219; remoteInfo = NetworkProtectionSystemExtension; }; - AA585D91248FD31400E9A3E2 /* PBXContainerItemProxy */ = { + B696E8182B8619D6008368F0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = AA585D76248FD31100E9A3E2 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B6EC37E729B5DA2A001ACE79; + remoteInfo = "tests-server"; + }; + B6CAC23C2B8F0EC6006CD402 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = AA585D76248FD31100E9A3E2 /* Project object */; proxyType = 1; remoteGlobalIDString = AA585D7D248FD31100E9A3E2; - remoteInfo = DuckDuckGo; + remoteInfo = "DuckDuckGo Privacy Browser"; }; - B696E8182B8619D6008368F0 /* PBXContainerItemProxy */ = { + B6CAC23E2B8F0ECA006CD402 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = AA585D76248FD31100E9A3E2 /* Project object */; proxyType = 1; - remoteGlobalIDString = B6EC37E729B5DA2A001ACE79; - remoteInfo = "tests-server"; + remoteGlobalIDString = AA585D7D248FD31100E9A3E2; + remoteInfo = "DuckDuckGo Privacy Browser"; }; B6EC37F129B5DA8F001ACE79 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -8436,9 +8436,9 @@ buildRules = ( ); dependencies = ( + B6CAC23F2B8F0ECA006CD402 /* PBXTargetDependency */, B69D06162A4C0ACD0032D14D /* PBXTargetDependency */, B6EC37F229B5DA8F001ACE79 /* PBXTargetDependency */, - 4B1AD8A325FC27E200261379 /* PBXTargetDependency */, ); name = "Integration Tests"; packageProductDependencies = ( @@ -8812,8 +8812,8 @@ buildRules = ( ); dependencies = ( + B6CAC23D2B8F0EC6006CD402 /* PBXTargetDependency */, B69D06142A4C0AC50032D14D /* PBXTargetDependency */, - AA585D92248FD31400E9A3E2 /* PBXTargetDependency */, ); name = "Unit Tests"; packageProductDependencies = ( @@ -12556,11 +12556,6 @@ target = 3706FA6A293F65D500E42796 /* DuckDuckGo Privacy Browser App Store */; targetProxy = 376113D52B29CD6800E794BB /* PBXContainerItemProxy */; }; - 4B1AD8A325FC27E200261379 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = AA585D7D248FD31100E9A3E2 /* DuckDuckGo Privacy Browser */; - targetProxy = 4B1AD8A225FC27E200261379 /* PBXContainerItemProxy */; - }; 4B4BEC4A2A11B627001D9AC5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = 4B4BEC492A11B627001D9AC5 /* NetworkProtection */; @@ -12606,11 +12601,6 @@ target = 4B2537592A11BE7300610219 /* NetworkProtectionSystemExtension */; targetProxy = 7BEC18302AD5DA3300D30536 /* PBXContainerItemProxy */; }; - AA585D92248FD31400E9A3E2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = AA585D7D248FD31100E9A3E2 /* DuckDuckGo Privacy Browser */; - targetProxy = AA585D91248FD31400E9A3E2 /* PBXContainerItemProxy */; - }; B6080B9D2B20AF7700B418EF /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; @@ -12664,6 +12654,16 @@ isa = PBXTargetDependency; productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; }; + B6CAC23D2B8F0EC6006CD402 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = AA585D7D248FD31100E9A3E2 /* DuckDuckGo Privacy Browser */; + targetProxy = B6CAC23C2B8F0EC6006CD402 /* PBXContainerItemProxy */; + }; + B6CAC23F2B8F0ECA006CD402 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = AA585D7D248FD31100E9A3E2 /* DuckDuckGo Privacy Browser */; + targetProxy = B6CAC23E2B8F0ECA006CD402 /* PBXContainerItemProxy */; + }; B6EC37F229B5DA8F001ACE79 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = B6EC37E729B5DA2A001ACE79 /* tests-server */; diff --git a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser.xcscheme b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser.xcscheme index 7a2328d13e..d9bdde676a 100644 --- a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser.xcscheme +++ b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser.xcscheme @@ -144,18 +144,9 @@ - - - - - - @@ -165,9 +156,6 @@ - - NSView? { - var content = subviews.last - - if containsHostingView { - content = content?.subviews.first + guard let content = subviews.last else { return nil } - assert(content?.className.contains("NSHostingView") == true) + if containsHostingView && !content.isHostingView, + let subview = content.subviews.first { + assert(subview.isHostingView) + return subview } return content diff --git a/DuckDuckGo/Tab/View/BrowserTabViewController.swift b/DuckDuckGo/Tab/View/BrowserTabViewController.swift index fffd82a5ac..0c88c046bd 100644 --- a/DuckDuckGo/Tab/View/BrowserTabViewController.swift +++ b/DuckDuckGo/Tab/View/BrowserTabViewController.swift @@ -27,7 +27,6 @@ import WebKit final class BrowserTabViewController: NSViewController { private lazy var browserTabView = BrowserTabView(frame: .zero, backgroundColor: .browserTabBackground) - private lazy var homePageView = NSView() private lazy var hoverLabel = NSTextField(string: URL.duckDuckGo.absoluteString) private lazy var hoverLabelContainer = ColorView(frame: .zero, backgroundColor: .browserTabBackground, borderWidth: 0) @@ -67,9 +66,6 @@ final class BrowserTabViewController: NSViewController { override func loadView() { view = browserTabView - homePageView.translatesAutoresizingMaskIntoConstraints = false - view.addAndLayout(homePageView) - hoverLabelContainer.cornerRadius = 4 view.addSubview(hoverLabelContainer) @@ -84,9 +80,6 @@ final class BrowserTabViewController: NSViewController { hoverLabelContainer.addSubview(hoverLabel) setupLayout() - - let homePageViewController = HomePageViewController(tabCollectionViewModel: tabCollectionViewModel, bookmarkManager: bookmarkManager) - self.addAndLayoutChild(homePageViewController, into: homePageView) } private func setupLayout() { @@ -536,10 +529,10 @@ final class BrowserTabViewController: NSViewController { // MARK: - Browser Tabs private func removeAllTabContent(includingWebView: Bool = true) { - self.homePageView.removeFromSuperview() transientTabContentViewController?.removeCompletely() preferencesViewController?.removeCompletely() bookmarksViewController?.removeCompletely() + homePageViewController?.removeCompletely() #if DBP dataBrokerProtectionHomeViewController?.removeCompletely() #endif @@ -600,7 +593,7 @@ final class BrowserTabViewController: NSViewController { case .newtab: removeAllTabContent() - view.addAndLayout(homePageView) + addAndLayoutChild(homePageViewControllerCreatingIfNeeded()) #if DBP case .dataBrokerProtection: @@ -655,6 +648,17 @@ final class BrowserTabViewController: NSViewController { } } + // MARK: - New Tab page + + var homePageViewController: HomePageViewController? + private func homePageViewControllerCreatingIfNeeded() -> HomePageViewController { + return homePageViewController ?? { + let homePageViewController = HomePageViewController(tabCollectionViewModel: tabCollectionViewModel, bookmarkManager: bookmarkManager) + self.homePageViewController = homePageViewController + return homePageViewController + }() + } + #if DBP // MARK: - DataBrokerProtection diff --git a/IntegrationTests/Downloads/DownloadsIntegrationTests.swift b/IntegrationTests/Downloads/DownloadsIntegrationTests.swift index 4f23f77ba0..5a263d3f02 100644 --- a/IntegrationTests/Downloads/DownloadsIntegrationTests.swift +++ b/IntegrationTests/Downloads/DownloadsIntegrationTests.swift @@ -35,9 +35,22 @@ class DownloadsIntegrationTests: XCTestCase { (window.contentViewController as! MainViewController).browserTabViewController.tabViewModel! } + var contentBlockingMock: ContentBlockingMock! + var privacyFeaturesMock: AnyPrivacyFeatures! + var privacyConfiguration: MockPrivacyConfiguration { + contentBlockingMock.privacyConfigurationManager.privacyConfig as! MockPrivacyConfiguration + } + @MainActor override func setUp() { - window = WindowsManager.openNewWindow(with: Tab(content: .none))! + contentBlockingMock = ContentBlockingMock() + privacyFeaturesMock = AppPrivacyFeatures(contentBlocking: contentBlockingMock, httpsUpgradeStore: HTTPSUpgradeStoreMock()) + // disable waiting for CBR compilation on navigation + privacyConfiguration.isFeatureKeyEnabled = { _, _ in + return false + } + + window = WindowsManager.openNewWindow(with: Tab(content: .none, privacyFeatures: privacyFeaturesMock))! } @MainActor diff --git a/IntegrationTests/History/HistoryIntegrationTests.swift b/IntegrationTests/History/HistoryIntegrationTests.swift index 3d8bb129bf..95eb98129d 100644 --- a/IntegrationTests/History/HistoryIntegrationTests.swift +++ b/IntegrationTests/History/HistoryIntegrationTests.swift @@ -35,8 +35,21 @@ class HistoryIntegrationTests: XCTestCase { mainViewController.browserTabViewController.tabViewModel! } + var contentBlockingMock: ContentBlockingMock! + var privacyFeaturesMock: AnyPrivacyFeatures! + var privacyConfiguration: MockPrivacyConfiguration { + contentBlockingMock.privacyConfigurationManager.privacyConfig as! MockPrivacyConfiguration + } + @MainActor override func setUp() async throws { + contentBlockingMock = ContentBlockingMock() + privacyFeaturesMock = AppPrivacyFeatures(contentBlocking: contentBlockingMock, httpsUpgradeStore: HTTPSUpgradeStoreMock()) + // disable waiting for CBR compilation on navigation + privacyConfiguration.isFeatureKeyEnabled = { _, _ in + return false + } + await withCheckedContinuation { continuation in HistoryCoordinator.shared.burnAll { continuation.resume(returning: ()) @@ -55,7 +68,7 @@ class HistoryIntegrationTests: XCTestCase { @MainActor func testWhenPageTitleIsUpdated_historyEntryTitleUpdated() async throws { - let tab = Tab(content: .newtab) + let tab = Tab(content: .newtab, privacyFeatures: privacyFeaturesMock) window = WindowsManager.openNewWindow(with: tab)! let html = """ @@ -99,7 +112,7 @@ class HistoryIntegrationTests: XCTestCase { @MainActor func testWhenSameDocumentNavigation_historyEntryTitleUpdated() async throws { - let tab = Tab(content: .newtab) + let tab = Tab(content: .newtab, privacyFeatures: privacyFeaturesMock) window = WindowsManager.openNewWindow(with: tab)! let html = """ @@ -143,7 +156,7 @@ class HistoryIntegrationTests: XCTestCase { @MainActor func testWhenNavigatingToSamePage_visitIsAdded() async throws { - let tab = Tab(content: .newtab) + let tab = Tab(content: .newtab, privacyFeatures: privacyFeaturesMock) window = WindowsManager.openNewWindow(with: tab)! let urls = [ @@ -163,7 +176,7 @@ class HistoryIntegrationTests: XCTestCase { @MainActor func testWhenNavigatingBack_visitIsNotAdded() async throws { - let tab = Tab(content: .newtab) + let tab = Tab(content: .newtab, privacyFeatures: privacyFeaturesMock) window = WindowsManager.openNewWindow(with: tab)! let urls = [ diff --git a/IntegrationTests/Tab/AddressBarTests.swift b/IntegrationTests/Tab/AddressBarTests.swift index 6494b2c3d5..deace94f7f 100644 --- a/IntegrationTests/Tab/AddressBarTests.swift +++ b/IntegrationTests/Tab/AddressBarTests.swift @@ -48,12 +48,25 @@ class AddressBarTests: XCTestCase { mainViewController.navigationBarViewController.addressBarViewController!.addressBarTextField } + var contentBlockingMock: ContentBlockingMock! + var privacyFeaturesMock: AnyPrivacyFeatures! + var privacyConfiguration: MockPrivacyConfiguration { + contentBlockingMock.privacyConfigurationManager.privacyConfig as! MockPrivacyConfiguration + } + var webViewConfiguration: WKWebViewConfiguration! var schemeHandler: TestSchemeHandler! static let testHtml = "Titletest" @MainActor override func setUp() async throws { + contentBlockingMock = ContentBlockingMock() + privacyFeaturesMock = AppPrivacyFeatures(contentBlocking: contentBlockingMock, httpsUpgradeStore: HTTPSUpgradeStoreMock()) + // disable waiting for CBR compilation on navigation + privacyConfiguration.isFeatureKeyEnabled = { _, _ in + return false + } + schemeHandler = TestSchemeHandler() WKWebView.customHandlerSchemes = [.http, .https] @@ -75,6 +88,7 @@ class AddressBarTests: XCTestCase { StartupPreferences.shared.launchToCustomHomePage = false WindowControllersManager.shared.pinnedTabsManager.setUp(with: .init()) + NSApp.activate(ignoringOtherApps: true) } @MainActor @@ -129,7 +143,7 @@ class AddressBarTests: XCTestCase { func testWhenUserStartsTypingOnNewTabPageLoad_userInputIsNotReset() async throws { // open Tab with newtab page - let tab = Tab(content: .newtab) + let tab = Tab(content: .newtab, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) var isNavigationFinished = false @@ -178,16 +192,16 @@ class AddressBarTests: XCTestCase { func testWhenSwitchingBetweenTabs_addressBarFocusStateIsCorrect() async throws { let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [ - Tab(content: .newtab), - Tab(content: .settings(pane: .about)), - Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration), - Tab(content: .bookmarks), - Tab(content: .newtab), - Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration), - Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration), - Tab(content: .newtab), - Tab(content: .newtab), - Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration), + Tab(content: .newtab, privacyFeatures: privacyFeaturesMock), + Tab(content: .settings(pane: .about), privacyFeatures: privacyFeaturesMock), + Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock), + Tab(content: .bookmarks, privacyFeatures: privacyFeaturesMock), + Tab(content: .newtab, privacyFeatures: privacyFeaturesMock), + Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock), + Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock), + Tab(content: .newtab, privacyFeatures: privacyFeaturesMock), + Tab(content: .newtab, privacyFeatures: privacyFeaturesMock), + Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock), ])) AppearancePreferences.shared.showFullURL = true window = WindowsManager.openNewWindow(with: viewModel)! @@ -207,47 +221,47 @@ class AddressBarTests: XCTestCase { } func testWhenRestoringToOnboarding_addressBarIsNotActive() async throws { - let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .onboarding)])) + let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .onboarding, privacyFeatures: privacyFeaturesMock)])) window = WindowsManager.openNewWindow(with: viewModel)! XCTAssertEqual(window.firstResponder, mainViewController.browserTabViewController.transientTabContentViewController!.view) } func testWhenRestoringToSettings_addressBarIsNotActive() async throws { - let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .settings(pane: .appearance))])) + let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .settings(pane: .appearance), privacyFeatures: privacyFeaturesMock)])) window = WindowsManager.openNewWindow(with: viewModel)! XCTAssertEqual(window.firstResponder, mainViewController.browserTabViewController.preferencesViewController!.view) } func testWhenRestoringToBookmarks_addressBarIsNotActive() async throws { - let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .bookmarks)])) + let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .bookmarks, privacyFeatures: privacyFeaturesMock)])) window = WindowsManager.openNewWindow(with: viewModel)! XCTAssertEqual(window.firstResponder, mainViewController.browserTabViewController.bookmarksViewController!.view) } func testWhenRestoringToURL_addressBarIsNotActive() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .loadedByStateRestoration), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .loadedByStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! XCTAssertEqual(window.firstResponder, tab.webView) } func testWhenRestoringToNewTab_addressBarIsActive() async throws { - let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .newtab)])) + let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .newtab, privacyFeatures: privacyFeaturesMock)])) window = WindowsManager.openNewWindow(with: viewModel)! XCTAssertTrue(isAddressBarFirstResponder) } func testWhenOpeningNewTab_addressBarIsActivated() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .loadedByStateRestoration), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .loadedByStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! XCTAssertEqual(window.firstResponder, tab.webView) - viewModel.append(tab: Tab(content: .newtab), selected: true) + viewModel.append(tab: Tab(content: .newtab, privacyFeatures: privacyFeaturesMock), selected: true) try await Task.sleep(interval: 0.01) XCTAssertTrue(isAddressBarFirstResponder) - viewModel.append(tab: Tab(content: .newtab), selected: true) + viewModel.append(tab: Tab(content: .newtab, privacyFeatures: privacyFeaturesMock), selected: true) try await Task.sleep(interval: 0.01) XCTAssertTrue(isAddressBarFirstResponder) @@ -262,16 +276,16 @@ class AddressBarTests: XCTestCase { func testWhenSwitchingBetweenTabsWithTypedValue_typedValueIsPreserved() async throws { let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [ - Tab(content: .newtab), - Tab(content: .settings(pane: .about)), - Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration), - Tab(content: .bookmarks), - Tab(content: .newtab), - Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration), - Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration), - Tab(content: .newtab), - Tab(content: .newtab), - Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration), + Tab(content: .newtab, privacyFeatures: privacyFeaturesMock), + Tab(content: .settings(pane: .about), privacyFeatures: privacyFeaturesMock), + Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock), + Tab(content: .bookmarks, privacyFeatures: privacyFeaturesMock), + Tab(content: .newtab, privacyFeatures: privacyFeaturesMock), + Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock), + Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock), + Tab(content: .newtab, privacyFeatures: privacyFeaturesMock), + Tab(content: .newtab, privacyFeatures: privacyFeaturesMock), + Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock), ])) window = WindowsManager.openNewWindow(with: viewModel)! @@ -300,8 +314,8 @@ class AddressBarTests: XCTestCase { func testWhenSwitchingBetweenURLTabs_addressBarIsDeactivated() async throws { let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [ - Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration), - Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration), + Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock), + Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock), ])) window = WindowsManager.openNewWindow(with: viewModel)! @@ -319,7 +333,7 @@ class AddressBarTests: XCTestCase { } func testWhenDeactivatingAddressBar_webViewShouldBecomeFirstResponder() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! @@ -333,7 +347,7 @@ class AddressBarTests: XCTestCase { } func testWhenGoingBack_addressBarIsDeactivated() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .loadedByStateRestoration), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .loadedByStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! @@ -359,7 +373,7 @@ class AddressBarTests: XCTestCase { } func testWhenGoingBackToNewtabPage_addressBarIsActivated() async throws { - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! @@ -396,7 +410,7 @@ class AddressBarTests: XCTestCase { } func testWhenGoingBackToNewtabPageFromSettings_addressBarIsActivated() async throws { - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! @@ -421,7 +435,7 @@ class AddressBarTests: XCTestCase { } func testWhenGoingBackToNewtabPageFromBookmarks_addressBarIsActivated() async throws { - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! @@ -446,7 +460,7 @@ class AddressBarTests: XCTestCase { } func testWhenTabReloaded_addressBarIsDeactivated() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! @@ -468,7 +482,7 @@ class AddressBarTests: XCTestCase { return .failure(URLError(.notConnectedToInternet)) }] - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! @@ -486,7 +500,7 @@ class AddressBarTests: XCTestCase { } func testWhenTabReloadedBySubmittingSameAddressAndAddressIsActivated_addressBarIsKeptActiveOnPageLoad() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .userEntered("")), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .userEntered("")), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! _=try await tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise().value @@ -507,7 +521,7 @@ class AddressBarTests: XCTestCase { } func testWhenEditingSerpURL_serpIconIsDisplayed() async throws { - let tab = Tab(content: .url(.makeSearchUrl(from: "catz")!, credential: nil, source: .userEntered("catz")), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.makeSearchUrl(from: "catz")!, credential: nil, source: .userEntered("catz")), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! _=try await tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise().value @@ -518,7 +532,7 @@ class AddressBarTests: XCTestCase { } func testWhenOpeningBookmark_addressBarIsDeactivated() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! try await tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise().value @@ -532,7 +546,7 @@ class AddressBarTests: XCTestCase { } func testWhenOpeningHistoryEntry_addressBarIsDeactivated() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! try await tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise().value @@ -546,7 +560,7 @@ class AddressBarTests: XCTestCase { } func testWhenOpeningURLfromUI_addressBarIsDeactivated() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! try await tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise().value @@ -562,7 +576,7 @@ class AddressBarTests: XCTestCase { func testWhenHomePageIsOpened_addressBarIsDeactivated() async throws { StartupPreferences.shared.launchToCustomHomePage = true - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .webViewUpdated), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! @@ -579,7 +593,7 @@ class AddressBarTests: XCTestCase { } func testWhenAddressSubmitted_addressBarIsDeactivated() async throws { - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! _=try await tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise().value @@ -592,7 +606,7 @@ class AddressBarTests: XCTestCase { } func testWhenAddressSubmittedAndAddressBarIsReactivated_addressBarIsKeptActiveOnPageLoad() async throws { - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! _=try await tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise().value @@ -636,7 +650,7 @@ class AddressBarTests: XCTestCase { } }] - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .userEntered("")), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .userEntered("")), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! XCTAssertEqual(addressBarValue, URL.duckDuckGo.absoluteString) @@ -683,7 +697,7 @@ class AddressBarTests: XCTestCase { } }] - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .userEntered("")), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .userEntered("")), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! let page1loadedPromise = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() @@ -704,10 +718,10 @@ class AddressBarTests: XCTestCase { } func testWhenActivatingWindowWithPinnedTabOpen_webViewBecomesFirstResponder() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .userEntered("")), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .userEntered("")), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) WindowControllersManager.shared.pinnedTabsManager.setUp(with: TabCollection(tabs: [tab])) - let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .newtab)])) + let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .newtab, privacyFeatures: privacyFeaturesMock)])) let tabLoadedPromise = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() window = WindowsManager.openNewWindow(with: viewModel)! viewModel.select(at: .pinned(0)) @@ -715,7 +729,7 @@ class AddressBarTests: XCTestCase { XCTAssertEqual(window.firstResponder, tab.webView) - let viewModel2 = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .newtab)])) + let viewModel2 = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .newtab, privacyFeatures: privacyFeaturesMock)])) let window2 = WindowsManager.openNewWindow(with: viewModel2)! defer { window2.close() @@ -735,10 +749,10 @@ class AddressBarTests: XCTestCase { } func testWhenActivatingWindowWithPinnedTabWhenAddressBarIsActive_addressBarIsKeptActive() async throws { - let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .userEntered("")), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .userEntered("")), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) WindowControllersManager.shared.pinnedTabsManager.setUp(with: TabCollection(tabs: [tab])) - let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .newtab)])) + let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .newtab, privacyFeatures: privacyFeaturesMock)])) let tabLoadedPromise = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() window = WindowsManager.openNewWindow(with: viewModel)! viewModel.select(at: .pinned(0)) @@ -746,7 +760,7 @@ class AddressBarTests: XCTestCase { XCTAssertEqual(window.firstResponder, tab.webView) - let viewModel2 = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .newtab)])) + let viewModel2 = TabCollectionViewModel(tabCollection: TabCollection(tabs: [Tab(content: .newtab, privacyFeatures: privacyFeaturesMock)])) let window2 = WindowsManager.openNewWindow(with: viewModel2)! defer { window2.close() diff --git a/IntegrationTests/Tab/ErrorPageTests.swift b/IntegrationTests/Tab/ErrorPageTests.swift index 47b1641089..8e6bf5c61b 100644 --- a/IntegrationTests/Tab/ErrorPageTests.swift +++ b/IntegrationTests/Tab/ErrorPageTests.swift @@ -35,6 +35,12 @@ class ErrorPageTests: XCTestCase { mainViewController.browserTabViewController.tabViewModel! } + var contentBlockingMock: ContentBlockingMock! + var privacyFeaturesMock: AnyPrivacyFeatures! + var privacyConfiguration: MockPrivacyConfiguration { + contentBlockingMock.privacyConfigurationManager.privacyConfig as! MockPrivacyConfiguration + } + var webViewConfiguration: WKWebViewConfiguration! var schemeHandler: TestSchemeHandler! @@ -104,6 +110,13 @@ class ErrorPageTests: XCTestCase { @MainActor override func setUp() async throws { + contentBlockingMock = ContentBlockingMock() + privacyFeaturesMock = AppPrivacyFeatures(contentBlocking: contentBlockingMock, httpsUpgradeStore: HTTPSUpgradeStoreMock()) + // disable waiting for CBR compilation on navigation + privacyConfiguration.isFeatureKeyEnabled = { _, _ in + return false + } + schemeHandler = TestSchemeHandler() WKWebView.customHandlerSchemes = [.http, .https] @@ -132,7 +145,7 @@ class ErrorPageTests: XCTestCase { func testWhenPageFailsToLoad_errorPageShown() async throws { // open Tab with newtab page - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! let eNewtabPageLoaded = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() @@ -172,8 +185,8 @@ class ErrorPageTests: XCTestCase { func testWhenTabWithNoConnectionErrorActivated_reloadTriggered() async throws { // open 2 Tabs with newtab page - let tab1 = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) - let tab2 = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab1 = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) + let tab2 = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let tabsViewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab1, tab2])) window = WindowsManager.openNewWindow(with: tabsViewModel)! @@ -217,8 +230,8 @@ class ErrorPageTests: XCTestCase { schemeHandler.middleware = [{ _ in .failure(NSError.connectionLost) }] - let tab1 = Tab(content: .url(.test, source: .link), webViewConfiguration: webViewConfiguration) - let tab2 = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab1 = Tab(content: .url(.test, source: .link), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) + let tab2 = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let tabsViewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab1, tab2])) window = WindowsManager.openNewWindow(with: tabsViewModel)! @@ -270,8 +283,8 @@ class ErrorPageTests: XCTestCase { schemeHandler.middleware = [{ _ in .failure(NSError.hostNotFound) }] - let tab1 = Tab(content: .url(.test, source: .link), webViewConfiguration: webViewConfiguration) - let tab2 = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab1 = Tab(content: .url(.test, source: .link), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) + let tab2 = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let tabsViewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab1, tab2])) window = WindowsManager.openNewWindow(with: tabsViewModel)! @@ -300,7 +313,7 @@ class ErrorPageTests: XCTestCase { schemeHandler.middleware = [{ _ in .failure(NSError.hostNotFound) }] - let tab = Tab(content: .url(.test, source: .link), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.test, source: .link), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) window = WindowsManager.openNewWindow(with: tab)! // wait for navigation to fail @@ -352,7 +365,7 @@ class ErrorPageTests: XCTestCase { schemeHandler.middleware = [{ _ in .failure(NSError.hostNotFound) }] - let tab = Tab(content: .url(.test, source: .link), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.test, source: .link), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) window = WindowsManager.openNewWindow(with: tab)! // wait for navigation to fail @@ -406,7 +419,7 @@ class ErrorPageTests: XCTestCase { func testWhenPageLoadedAndFailsOnRefreshAndOnConsequentRefresh_errorPageIsUpdatedKeepingForwardHistory() async throws { // open Tab with newtab page - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! let eNewtabPageLoaded = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() @@ -482,7 +495,7 @@ class ErrorPageTests: XCTestCase { func testWhenPageLoadedAndFailsOnRefreshAndSucceedsOnConsequentRefresh_forwardHistoryIsPreserved() async throws { // open Tab with newtab page - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! let eNewtabPageLoaded = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() @@ -550,7 +563,7 @@ class ErrorPageTests: XCTestCase { func testWhenReloadingBySubmittingSameURL_errorPageRemainsSame() async throws { // open Tab with newtab page - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! let eNewtabPageLoaded = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() @@ -625,7 +638,7 @@ class ErrorPageTests: XCTestCase { func testWhenGoingToAnotherUrlFails_newBackForwardHistoryItemIsAdded() async throws { // open Tab with newtab page - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! let eNewtabPageLoaded = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() @@ -700,7 +713,7 @@ class ErrorPageTests: XCTestCase { func testWhenGoingToAnotherUrlSucceeds_newBackForwardHistoryItemIsAdded() async throws { // open Tab with newtab page - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! let eNewtabPageLoaded = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() @@ -772,7 +785,7 @@ class ErrorPageTests: XCTestCase { .failure(NSError.noConnection) }] - let tab = Tab(content: .url(.test, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, interactionStateData: Self.sessionStateData) + let tab = Tab(content: .url(.test, source: .pendingStateRestoration), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock, interactionStateData: Self.sessionStateData) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! let eNewtabPageLoaded = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() @@ -784,7 +797,7 @@ class ErrorPageTests: XCTestCase { .ok(.html(Self.testHtml)) }] // open new tab - viewModel.appendNewTab() + viewModel.append(tab: Tab(content: .newtab, privacyFeatures: privacyFeaturesMock)) // select the failing tab triggering its reload let eReloadFinished = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() @@ -812,7 +825,7 @@ class ErrorPageTests: XCTestCase { return .ok(.html(Self.testHtml)) }] - let tab = Tab(content: .url(.alternative, source: .ui), webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .url(.alternative, source: .ui), webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let eNavigationFinished = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() let manager = PinnedTabsManager() manager.pin(tab) @@ -856,7 +869,7 @@ class ErrorPageTests: XCTestCase { func testWhenPageFailsToLoadAfterRedirect_errorPageShown() async throws { // open Tab with newtab page - let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration) + let tab = Tab(content: .newtab, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock) let viewModel = TabCollectionViewModel(tabCollection: TabCollection(tabs: [tab])) window = WindowsManager.openNewWindow(with: viewModel)! let eNewtabPageLoaded = tab.webViewDidFinishNavigationPublisher.timeout(5).first().promise() diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/EmailConfirmation.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/EmailConfirmation.swift index a96160ec29..1983c38470 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/EmailConfirmation.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/EmailConfirmation.swift @@ -21,5 +21,5 @@ import Foundation struct EmailConfirmationAction: Action { let id: String let actionType: ActionType - let pollingTime: Int + let pollingTime: TimeInterval } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerOperation.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerOperation.swift index 37cd385e4e..8b74fdb0e5 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerOperation.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerOperation.swift @@ -124,7 +124,7 @@ extension DataBrokerOperation { let url = try await emailService.getConfirmationLink( from: email, numberOfRetries: 100, // Move to constant - pollingIntervalInSeconds: action.pollingTime, + pollingInterval: action.pollingTime, shouldRunNextStep: shouldRunNextStep ) stageCalculator?.fireOptOutEmailReceive() diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Services/CaptchaService.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Services/CaptchaService.swift index 64ac37e22f..e7851376ad 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Services/CaptchaService.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Services/CaptchaService.swift @@ -85,6 +85,7 @@ protocol CaptchaServiceProtocol { /// - Returns: `CaptchaTransactionId` an identifier so we can later use to fetch the resolved captcha information func submitCaptchaInformation(_ captchaInfo: GetCaptchaInfoResponse, retries: Int, + pollingInterval: TimeInterval, shouldRunNextStep: @escaping () -> Bool) async throws -> CaptchaTransactionId /// Fetches the resolved captcha information with the passed transaction ID. @@ -97,13 +98,13 @@ protocol CaptchaServiceProtocol { /// - Returns: `CaptchaResolveData` a string containing the data to resolve the captcha func submitCaptchaToBeResolved(for transactionID: CaptchaTransactionId, retries: Int, - pollingInterval: Int, + pollingInterval: TimeInterval, shouldRunNextStep: @escaping () -> Bool) async throws -> CaptchaResolveData } extension CaptchaServiceProtocol { func submitCaptchaInformation(_ captchaInfo: GetCaptchaInfoResponse, shouldRunNextStep: @escaping () -> Bool) async throws -> CaptchaTransactionId { - try await submitCaptchaInformation(captchaInfo, retries: 5, shouldRunNextStep: shouldRunNextStep) + try await submitCaptchaInformation(captchaInfo, retries: 5, pollingInterval: 1, shouldRunNextStep: shouldRunNextStep) } func submitCaptchaToBeResolved(for transactionID: CaptchaTransactionId, shouldRunNextStep: @escaping () -> Bool) async throws -> CaptchaResolveData { @@ -137,6 +138,7 @@ struct CaptchaService: CaptchaServiceProtocol { func submitCaptchaInformation(_ captchaInfo: GetCaptchaInfoResponse, retries: Int = 5, + pollingInterval: TimeInterval = 1, shouldRunNextStep: @escaping () -> Bool) async throws -> CaptchaTransactionId { guard let captchaSubmitResult = try? await submitCaptchaInformationRequest(captchaInfo) else { throw CaptchaServiceError.errorWhenSubmittingCaptcha @@ -157,9 +159,10 @@ struct CaptchaService: CaptchaServiceProtocol { if retries == 0 { throw CaptchaServiceError.timedOutWhenSubmittingCaptcha } - try await Task.sleep(nanoseconds: UInt64(1 * Double(NSEC_PER_SEC))) + try await Task.sleep(nanoseconds: UInt64(pollingInterval * 1000) * NSEC_PER_MSEC) return try await submitCaptchaInformation(captchaInfo, retries: retries - 1, + pollingInterval: pollingInterval, shouldRunNextStep: shouldRunNextStep) case .failureCritical: throw CaptchaServiceError.criticalFailureWhenSubmittingCaptcha @@ -195,7 +198,7 @@ struct CaptchaService: CaptchaServiceProtocol { func submitCaptchaToBeResolved(for transactionID: CaptchaTransactionId, retries: Int = 100, - pollingInterval: Int = 50, + pollingInterval: TimeInterval = 50, shouldRunNextStep: @escaping () -> Bool) async throws -> CaptchaResolveData { guard let captchaResolveResult = try? await submitCaptchaToBeResolvedRequest(transactionID) else { throw CaptchaServiceError.errorWhenFetchingCaptchaResult @@ -218,7 +221,7 @@ struct CaptchaService: CaptchaServiceProtocol { if retries == 0 { throw CaptchaServiceError.timedOutWhenFetchingCaptchaResult } - try await Task.sleep(nanoseconds: UInt64(pollingInterval) * NSEC_PER_SEC) + try await Task.sleep(nanoseconds: UInt64(pollingInterval * 1000) * NSEC_PER_MSEC) return try await submitCaptchaToBeResolved(for: transactionID, retries: retries - 1, pollingInterval: pollingInterval, diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Services/EmailService.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Services/EmailService.swift index 038c72c2d8..33c2d30cf4 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Services/EmailService.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Services/EmailService.swift @@ -33,7 +33,7 @@ protocol EmailServiceProtocol { func getEmail(dataBrokerURL: String?) async throws -> String func getConfirmationLink(from email: String, numberOfRetries: Int, - pollingIntervalInSeconds: Int, + pollingInterval: TimeInterval, shouldRunNextStep: @escaping () -> Bool) async throws -> URL } @@ -78,9 +78,9 @@ struct EmailService: EmailServiceProtocol { func getConfirmationLink(from email: String, numberOfRetries: Int = 100, - pollingIntervalInSeconds: Int = 30, + pollingInterval: TimeInterval = 30, shouldRunNextStep: @escaping () -> Bool) async throws -> URL { - let pollingTimeInNanoSecondsSeconds = UInt64(pollingIntervalInSeconds) * NSEC_PER_SEC + let pollingTimeInNanoSecondsSeconds = UInt64(pollingInterval * 1000) * NSEC_PER_MSEC guard let emailResult = try? await extractEmailLink(email: email) else { throw EmailError.cantFindEmail @@ -107,7 +107,7 @@ struct EmailService: EmailServiceProtocol { try await Task.sleep(nanoseconds: pollingTimeInNanoSecondsSeconds) return try await getConfirmationLink(from: email, numberOfRetries: numberOfRetries - 1, - pollingIntervalInSeconds: pollingIntervalInSeconds, + pollingInterval: pollingInterval, shouldRunNextStep: shouldRunNextStep) case .unknown: throw EmailError.unknownStatusReceived(email: email) diff --git a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/CaptchaServiceTests.swift b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/CaptchaServiceTests.swift index 0f325dd5cc..432a9ed274 100644 --- a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/CaptchaServiceTests.swift +++ b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/CaptchaServiceTests.swift @@ -97,7 +97,7 @@ final class CaptchaServiceTests: XCTestCase { let sut = CaptchaService(urlSession: mockURLSession, redeemUseCase: MockRedeemUseCase()) do { - _ = try await sut.submitCaptchaInformation(GetCaptchaInfoResponse.mock, retries: 2, shouldRunNextStep: { true }) + _ = try await sut.submitCaptchaInformation(GetCaptchaInfoResponse.mock, retries: 2, pollingInterval: 0.01, shouldRunNextStep: { true }) XCTFail("Expected an error to be thrown") } catch { if let error = error as? CaptchaServiceError, case .timedOutWhenSubmittingCaptcha = error { @@ -175,7 +175,7 @@ final class CaptchaServiceTests: XCTestCase { let sut = CaptchaService(urlSession: mockURLSession, redeemUseCase: MockRedeemUseCase()) do { - _ = try await sut.submitCaptchaToBeResolved(for: "123456", retries: 2, pollingInterval: 1, shouldRunNextStep: { true }) + _ = try await sut.submitCaptchaToBeResolved(for: "123456", retries: 2, pollingInterval: 0.01, shouldRunNextStep: { true }) XCTFail("Expected an error to be thrown") } catch { if let error = error as? CaptchaServiceError, case .timedOutWhenFetchingCaptchaResult = error { diff --git a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/EmailServiceTests.swift b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/EmailServiceTests.swift index c82680d1e9..d7bc45e90c 100644 --- a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/EmailServiceTests.swift +++ b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/EmailServiceTests.swift @@ -99,8 +99,8 @@ final class EmailServiceTests: XCTestCase { do { _ = try await sut.getConfirmationLink( from: "some@email.com", - numberOfRetries: 2, - pollingIntervalInSeconds: 2, + numberOfRetries: 20, + pollingInterval: 0.01, shouldRunNextStep: { true } ) } catch { @@ -126,7 +126,7 @@ final class EmailServiceTests: XCTestCase { _ = try await sut.getConfirmationLink( from: "some@email.com", numberOfRetries: 2, - pollingIntervalInSeconds: 2, + pollingInterval: 0.01, shouldRunNextStep: { true } ) } catch { @@ -155,7 +155,7 @@ final class EmailServiceTests: XCTestCase { let url = try await sut.getConfirmationLink( from: "some@email.com", numberOfRetries: 2, - pollingIntervalInSeconds: 2, + pollingInterval: 0.01, shouldRunNextStep: { true } ) XCTAssertEqual(url.absoluteString, "www.duckduckgo.com") @@ -174,8 +174,8 @@ final class EmailServiceTests: XCTestCase { do { _ = try await sut.getConfirmationLink( from: "some@email.com", - numberOfRetries: 2, - pollingIntervalInSeconds: 2, + numberOfRetries: 20, + pollingInterval: 0.01, shouldRunNextStep: { true } ) } catch { @@ -198,7 +198,7 @@ final class EmailServiceTests: XCTestCase { _ = try await sut.getConfirmationLink( from: "some@email.com", numberOfRetries: 1, - pollingIntervalInSeconds: 1, + pollingInterval: 0.01, shouldRunNextStep: { true } ) } catch { @@ -221,7 +221,7 @@ final class EmailServiceTests: XCTestCase { let url = try await sut.getConfirmationLink( from: "some@email.com", numberOfRetries: 1, - pollingIntervalInSeconds: 1, + pollingInterval: 0.01, shouldRunNextStep: { true } ) XCTAssertEqual(url.absoluteString, "www.duckduckgo.com") diff --git a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift index 575c0cdd17..2322840918 100644 --- a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift +++ b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift @@ -242,7 +242,7 @@ final class EmailServiceMock: EmailServiceProtocol { return "test@duck.com" } - func getConfirmationLink(from email: String, numberOfRetries: Int, pollingIntervalInSeconds: Int, shouldRunNextStep: @escaping () -> Bool) async throws -> URL { + func getConfirmationLink(from email: String, numberOfRetries: Int, pollingInterval: TimeInterval, shouldRunNextStep: @escaping () -> Bool) async throws -> URL { if shouldThrow { throw DataBrokerProtectionError.emailError(nil) } @@ -261,7 +261,7 @@ final class CaptchaServiceMock: CaptchaServiceProtocol { var wasSubmitCaptchaToBeResolvedCalled = false var shouldThrow = false - func submitCaptchaInformation(_ captchaInfo: GetCaptchaInfoResponse, retries: Int, shouldRunNextStep: @escaping () -> Bool) async throws -> CaptchaTransactionId { + func submitCaptchaInformation(_ captchaInfo: GetCaptchaInfoResponse, retries: Int, pollingInterval: TimeInterval, shouldRunNextStep: @escaping () -> Bool) async throws -> CaptchaTransactionId { if shouldThrow { throw CaptchaServiceError.errorWhenSubmittingCaptcha } @@ -271,7 +271,7 @@ final class CaptchaServiceMock: CaptchaServiceProtocol { return "transactionID" } - func submitCaptchaToBeResolved(for transactionID: CaptchaTransactionId, retries: Int, pollingInterval: Int, shouldRunNextStep: @escaping () -> Bool) async throws -> CaptchaResolveData { + func submitCaptchaToBeResolved(for transactionID: CaptchaTransactionId, retries: Int, pollingInterval: TimeInterval, shouldRunNextStep: @escaping () -> Bool) async throws -> CaptchaResolveData { if shouldThrow { throw CaptchaServiceError.errorWhenFetchingCaptchaResult } diff --git a/UnitTests/App/AppStateChangePublisherTests.swift b/UnitTests/App/AppStateChangePublisherTests.swift index 28409bc9e8..f2dac58312 100644 --- a/UnitTests/App/AppStateChangePublisherTests.swift +++ b/UnitTests/App/AppStateChangePublisherTests.swift @@ -36,26 +36,10 @@ final class AppStateChangePublisherTests: XCTestCase { } } - final class MultiExpectation { - let e: XCTestExpectation - let count: Int - var counter = 0 - - init(e: XCTestExpectation, count: Int) { - self.e = e - self.count = count - } - - func fulfill() { - counter += 1 - if counter >= count { - e.fulfill() - } - } - } - - func expect(description expectationDescription: String, events: Int) -> MultiExpectation { - MultiExpectation(e: expectation(description: description), count: events) + func expect(description expectationDescription: String, events: Int) -> XCTestExpectation { + let e = expectation(description: description) + e.expectedFulfillmentCount = events + return e } // MARK: - @@ -68,12 +52,12 @@ final class AppStateChangePublisherTests: XCTestCase { e.fulfill() }.store(in: &cancellables) - WindowsManager.openNewWindow() + WindowsManager.openNewWindow(with: Tab(content: .none)) waitForExpectations(timeout: 0.3, handler: nil) } func testWhenManyWindowsOpenedThenStateChangePublished() { - WindowsManager.openNewWindow() + WindowsManager.openNewWindow(with: Tab(content: .none)) let n = 7 let e = expect(description: "Windows Opened fire State change", events: n) @@ -84,14 +68,15 @@ final class AppStateChangePublisherTests: XCTestCase { }.store(in: &cancellables) for _ in (0...promise() var value: String? let c = promise.future.sink { @@ -243,8 +243,7 @@ final class FutureExtensionTests: XCTestCase { withExtendedLifetime(c, {}) } - @MainActor - func testInstantlyFulfilledPromiseAsyncHasValue() async { + func testInstantlyFulfilledPromiseAsyncHasValue() { let promise = Future.promise() promise.fulfill("test") var value: String? @@ -324,7 +323,6 @@ final class FutureExtensionTests: XCTestCase { @MainActor func testWhenFirstSucceeds_getFutureReceivesValue() async throws { - let subj = PassthroughSubject() let future = subj.first().promise() diff --git a/UnitTests/Common/FileManagerTempDirReplacement.swift b/UnitTests/Common/FileManagerTempDirReplacement.swift index 9fc60b0c67..1abeca35c1 100644 --- a/UnitTests/Common/FileManagerTempDirReplacement.swift +++ b/UnitTests/Common/FileManagerTempDirReplacement.swift @@ -17,6 +17,7 @@ // import Foundation +@testable import DuckDuckGo_Privacy_Browser extension FileManager { @@ -34,8 +35,16 @@ extension FileManager { return testsTempDir } - func cleanupTemporaryDirectory() { - try? self.removeItem(at: self.temporaryDirectory) + func cleanupTemporaryDirectory(excluding: Set = []) { + if excluding.isEmpty { + try? self.removeItem(at: self.temporaryDirectory) + } else { + let temporaryDirectory = self.temporaryDirectory + for file in (try? self.contentsOfDirectory(atPath: self.temporaryDirectory.path)) ?? [] where !excluding.contains(file) { + try? self.removeItem(at: temporaryDirectory.appendingPathComponent(file)) + } + } + _=self.temporaryDirectory } diff --git a/UnitTests/Common/TestRunHelper.swift b/UnitTests/Common/TestRunHelper.swift index cfe1a56889..a18f9785bd 100644 --- a/UnitTests/Common/TestRunHelper.swift +++ b/UnitTests/Common/TestRunHelper.swift @@ -52,7 +52,9 @@ extension TestRunHelper: XCTestObservation { func testBundleDidFinish(_ testBundle: Bundle) { if case .integrationTests = NSApp.runType { - FileManager.default.cleanupTemporaryDirectory() + FileManager.default.cleanupTemporaryDirectory(excluding: ["Database.sqlite", + "Database.sqlite-wal", + "Database.sqlite-shm"]) } } @@ -68,6 +70,7 @@ extension TestRunHelper: XCTestObservation { if case .unitTests = NSApp.runType { // cleanup dedicated temporary directory before each test run FileManager.default.cleanupTemporaryDirectory() + NSAnimationContext.current.duration = 0 } NSApp.swizzled_currentEvent = nil } diff --git a/UnitTests/Fire/Model/FireTests.swift b/UnitTests/Fire/Model/FireTests.swift index c47facae50..fa3bbf8efa 100644 --- a/UnitTests/Fire/Model/FireTests.swift +++ b/UnitTests/Fire/Model/FireTests.swift @@ -27,6 +27,13 @@ final class FireTests: XCTestCase { var cancellables = Set() + override func tearDown() { + WindowsManager.closeWindows() + for controller in WindowControllersManager.shared.mainWindowControllers { + WindowControllersManager.shared.unregister(controller) + } + } + func testWhenBurnAll_ThenAllWindowsAreClosed() { let manager = WebCacheManagerMock() let historyCoordinator = HistoryCoordinatingMock() @@ -203,8 +210,8 @@ fileprivate extension TabCollectionViewModel { static func makeTabCollectionViewModel(with pinnedTabsManager: PinnedTabsManager? = nil) -> TabCollectionViewModel { let tabCollectionViewModel = TabCollectionViewModel(tabCollection: .init(), pinnedTabsManager: pinnedTabsManager ?? WindowControllersManager.shared.pinnedTabsManager) - tabCollectionViewModel.appendNewTab() - tabCollectionViewModel.appendNewTab() + tabCollectionViewModel.append(tab: Tab(content: .none)) + tabCollectionViewModel.append(tab: Tab(content: .none)) return tabCollectionViewModel } diff --git a/UnitTests/Menus/MoreOptionsMenuTests.swift b/UnitTests/Menus/MoreOptionsMenuTests.swift index f64d87be9b..8c0b0c237b 100644 --- a/UnitTests/Menus/MoreOptionsMenuTests.swift +++ b/UnitTests/Menus/MoreOptionsMenuTests.swift @@ -30,7 +30,23 @@ final class MoreOptionsMenuTests: XCTestCase { var tabCollectionViewModel: TabCollectionViewModel! var passwordManagerCoordinator: PasswordManagerCoordinator! var capturingActionDelegate: CapturingOptionsButtonMenuDelegate! - var moreOptionMenu: MoreOptionsMenu! + lazy var moreOptionMenu: MoreOptionsMenu! = { +#if NETWORK_PROTECTION + let menu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, + passwordManagerCoordinator: passwordManagerCoordinator, + networkProtectionFeatureVisibility: networkProtectionVisibilityMock, + sharingMenu: NSMenu(), + internalUserDecider: internalUserDecider) +#else + let menu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, + passwordManagerCoordinator: passwordManagerCoordinator, + sharingMenu: NSMenu(), + internalUserDecider: internalUserDecider) +#endif + menu.actionDelegate = capturingActionDelegate + return menu + }() + var internalUserDecider: InternalUserDeciderMock! #if NETWORK_PROTECTION @@ -46,18 +62,7 @@ final class MoreOptionsMenuTests: XCTestCase { #if NETWORK_PROTECTION networkProtectionVisibilityMock = NetworkProtectionVisibilityMock(visible: false) - - moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, - passwordManagerCoordinator: passwordManagerCoordinator, - networkProtectionFeatureVisibility: networkProtectionVisibilityMock, - internalUserDecider: internalUserDecider) -#else - moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, - passwordManagerCoordinator: passwordManagerCoordinator, - internalUserDecider: internalUserDecider) #endif - - moreOptionMenu.actionDelegate = capturingActionDelegate } override func tearDown() { @@ -70,14 +75,16 @@ final class MoreOptionsMenuTests: XCTestCase { func testThatMoreOptionMenuHasTheExpectedItems_WhenNetworkProtectionIsEnabled() { #if NETWORK_PROTECTION - let moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, - passwordManagerCoordinator: passwordManagerCoordinator, - networkProtectionFeatureVisibility: NetworkProtectionVisibilityMock(visible: true), - internalUserDecider: internalUserDecider) + moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, + passwordManagerCoordinator: passwordManagerCoordinator, + networkProtectionFeatureVisibility: NetworkProtectionVisibilityMock(visible: true), + sharingMenu: NSMenu(), + internalUserDecider: internalUserDecider) #else - let moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, - passwordManagerCoordinator: passwordManagerCoordinator, - internalUserDecider: internalUserDecider) + moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, + passwordManagerCoordinator: passwordManagerCoordinator, + sharingMenu: NSMenu(), + internalUserDecider: internalUserDecider) #endif XCTAssertEqual(moreOptionMenu.items[0].title, "Send Feedback") @@ -107,14 +114,16 @@ final class MoreOptionsMenuTests: XCTestCase { func testThatMoreOptionMenuHasTheExpectedItems_WhenNetworkProtectionIsDisabled() { #if NETWORK_PROTECTION - let moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, - passwordManagerCoordinator: passwordManagerCoordinator, - networkProtectionFeatureVisibility: NetworkProtectionVisibilityMock(visible: false), - internalUserDecider: internalUserDecider) + moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, + passwordManagerCoordinator: passwordManagerCoordinator, + networkProtectionFeatureVisibility: NetworkProtectionVisibilityMock(visible: false), + sharingMenu: NSMenu(), + internalUserDecider: internalUserDecider) #else - let moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, - passwordManagerCoordinator: passwordManagerCoordinator, - internalUserDecider: internalUserDecider) + moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, + passwordManagerCoordinator: passwordManagerCoordinator, + sharingMenu: NSMenu(), + internalUserDecider: internalUserDecider) #endif XCTAssertEqual(moreOptionMenu.items[0].title, "Send Feedback") diff --git a/UnitTests/PrivacyReferenceTests/FireproofingReferenceTests.swift b/UnitTests/PrivacyReferenceTests/FireproofingReferenceTests.swift index 3f51d5d926..ef5f327672 100644 --- a/UnitTests/PrivacyReferenceTests/FireproofingReferenceTests.swift +++ b/UnitTests/PrivacyReferenceTests/FireproofingReferenceTests.swift @@ -46,25 +46,19 @@ final class FireproofingReferenceTests: XCTestCase { } /// Test disabled until Privacy Reference Tests contain the new Fire Button and Fireproofing logic - func testFireproofing() throws { + @MainActor + func testFireproofing() async throws { referenceTests = testData.fireButtonFireproofing.tests.filter { $0.exceptPlatforms.contains("macos-browser") == false } - let testsExecuted = expectation(description: "tests executed") - testsExecuted.expectedFulfillmentCount = referenceTests.count - - runReferenceTests(onTestExecuted: testsExecuted) - - waitForExpectations(timeout: 30, handler: nil) - } - - private func runReferenceTests(onTestExecuted: XCTestExpectation) { - - guard let test = referenceTests.popLast() else { - return + for test in referenceTests { + await runReferenceTest(test) } + } + @MainActor + private func runReferenceTest(_ test: Test) async { os_log("Testing %s", test.name) let loginDomains = testData.fireButtonFireproofing.fireproofedSites.map { sanitizedSite($0) } @@ -77,33 +71,20 @@ final class FireproofingReferenceTests: XCTestCase { return } - Task { @MainActor in - await dataStore.cookieStore?.setCookie(cookie) - await webCacheManager.clear() - - let hotCookies = await dataStore.cookieStore?.allCookies() - let testCookie = hotCookies?.filter { $0.name == test.cookieName }.first + await dataStore.cookieStore?.setCookie(cookie) + await webCacheManager.clear() - if test.expectCookieRemoved { - XCTAssertNil(testCookie, "Cookie should not exist for test: \(test.name)") - } else { - XCTAssertNotNil(testCookie, "Cookie should exist for test: \(test.name)") - } - - if let cookie = testCookie { - await dataStore.cookieStore?.deleteCookie(cookie) - } - - DispatchQueue.main.async { [weak self] in - onTestExecuted.fulfill() + let hotCookies = await dataStore.cookieStore?.allCookies() + let testCookie = hotCookies?.filter { $0.name == test.cookieName }.first - guard let self = self else { - XCTFail("\(#function): Failed to unwrap self") - return - } + if test.expectCookieRemoved { + XCTAssertNil(testCookie, "Cookie should not exist for test: \(test.name)") + } else { + XCTAssertNotNil(testCookie, "Cookie should exist for test: \(test.name)") + } - self.runReferenceTests(onTestExecuted: onTestExecuted) - } + if let cookie = testCookie { + await dataStore.cookieStore?.deleteCookie(cookie) } } diff --git a/UnitTests/TabBar/ViewModel/TabLazyLoaderTests.swift b/UnitTests/TabBar/ViewModel/TabLazyLoaderTests.swift index b14feb90fd..75012b3bee 100644 --- a/UnitTests/TabBar/ViewModel/TabLazyLoaderTests.swift +++ b/UnitTests/TabBar/ViewModel/TabLazyLoaderTests.swift @@ -199,7 +199,7 @@ class TabLazyLoaderTests: XCTestCase { XCTAssertEqual(try XCTUnwrap(didFinishEvents.first), true) } - func testThatLazyLoadingDoesNotStartIfCurrentUrlTabDoesNotFinishLoading() { + func testThatLazyLoadingDoesNotStartIfCurrentUrlTabDoesNotFinishLoading() async throws { let reloadExpectation = expectation(description: "TabMock.reload() called") reloadExpectation.isInverted = true @@ -212,15 +212,15 @@ class TabLazyLoaderTests: XCTestCase { let lazyLoader = TabLazyLoader(dataSource: dataSource) - var didFinishEvents: [Bool] = [] - lazyLoader?.lazyLoadingDidFinishPublisher.sink(receiveValue: { didFinishEvents.append($0) }).store(in: &cancellables) + lazyLoader?.lazyLoadingDidFinishPublisher.sink { _ in + XCTFail("Unexpected didFinish event") + }.store(in: &cancellables) // When lazyLoader?.scheduleLazyLoading() // Then - waitForExpectations(timeout: 0.1) - XCTAssertEqual(didFinishEvents.count, 0) + await fulfillment(of: [reloadExpectation], timeout: 0.1) } func testThatLazyLoadingStopsAfterLoadingMaximumNumberOfTabs() throws { diff --git a/UnitTests/TabExtensionsTests/AdClickAttributionTabExtensionTests.swift b/UnitTests/TabExtensionsTests/AdClickAttributionTabExtensionTests.swift index 243dde4f70..ee57cd7865 100644 --- a/UnitTests/TabExtensionsTests/AdClickAttributionTabExtensionTests.swift +++ b/UnitTests/TabExtensionsTests/AdClickAttributionTabExtensionTests.swift @@ -450,8 +450,11 @@ class AdClickAttributionTabExtensionTests: XCTestCase { userScriptInstalled.fulfill() } let tab = Tab(content: .none, privacyFeatures: privacyFeaturesMock, extensionsBuilder: extensionsBuilder, shouldLoadInBackground: true) + + let makeContentBlockerRulesCalled = expectation(description: "makeContentBlockerRulesCalled") DispatchQueue.main.async { self.makeContentBlockerRulesUserScript() + makeContentBlockerRulesCalled.fulfill() } waitForExpectations(timeout: 1) From 05c7db65af975e8c0d5aaa10de448a8e295c60dd Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Thu, 29 Feb 2024 14:00:01 +0600 Subject: [PATCH 07/10] Fix local file state restoration (#2248) Task/Issue URL: https://app.asana.com/0/1177771139624306/1206643452552019/f --- DuckDuckGo/Tab/Model/Tab.swift | 32 +++++++++++-------- DuckDuckGo/Tab/ViewModel/TabViewModel.swift | 2 ++ .../TabBar/View/TabBarViewController.swift | 2 +- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/DuckDuckGo/Tab/Model/Tab.swift b/DuckDuckGo/Tab/Model/Tab.swift index b01da67e1b..297e4d55eb 100644 --- a/DuckDuckGo/Tab/Model/Tab.swift +++ b/DuckDuckGo/Tab/Model/Tab.swift @@ -1012,7 +1012,7 @@ protocol NewWindowPolicyDecisionMaker { if webView.url == url, webView.backForwardList.currentItem?.url == url, !webView.isLoading { return reload() } - if restoreInteractionStateDataIfNeeded() { return nil /* session restored */ } + if restoreInteractionStateIfNeeded() { return nil /* session restored */ } invalidateInteractionStateData() if url.isFileURL { @@ -1051,30 +1051,36 @@ protocol NewWindowPolicyDecisionMaker { } @MainActor - private func restoreInteractionStateDataIfNeeded() -> Bool { + private func restoreInteractionStateIfNeeded() -> Bool { // only restore session from interactionStateData passed to Tab.init guard case .loadCachedFromTabContent(let interactionStateData) = self.interactionState else { return false } if let url = content.urlForWebView, url.isFileURL { // request file system access before restoration - _ = webView.loadFileURL(url, allowingReadAccessTo: URL(fileURLWithPath: "/")) - } - - if #available(macOS 12.0, *) { - webView.interactionState = interactionStateData + webView.navigator(distributedNavigationDelegate: navigationDelegate) + .loadFileURL(url, allowingReadAccessTo: url)? + .overrideResponders(navigationDidFinish: { [weak self] _ in + self?.restoreInteractionState(with: interactionStateData) + }, navigationDidFail: { [weak self] _, _ in + self?.restoreInteractionState(with: interactionStateData) + }) } else { - do { - try webView.restoreSessionState(from: interactionStateData) - } catch { - os_log("Tab:setupWebView could not restore session state %s", type: .error, "\(error)") - return false - } + restoreInteractionState(with: interactionStateData) } + invalidateInteractionStateData() return true } + private func restoreInteractionState(with interactionStateData: Data) { + guard #available(macOS 12.0, *) else { + try? webView.restoreSessionState(from: interactionStateData) + return + } + webView.interactionState = interactionStateData + } + private func addHomePageToWebViewIfNeeded() { guard NSApp.runType.requiresEnvironment else { return } if content == .newtab && webView.url == nil { diff --git a/DuckDuckGo/Tab/ViewModel/TabViewModel.swift b/DuckDuckGo/Tab/ViewModel/TabViewModel.swift index 20adafb0dc..3f9cb377d9 100644 --- a/DuckDuckGo/Tab/ViewModel/TabViewModel.swift +++ b/DuckDuckGo/Tab/ViewModel/TabViewModel.swift @@ -300,6 +300,8 @@ final class TabViewModel { title = tabTitle } else if let host = tab.url?.host?.droppingWwwPrefix() { title = host + } else if let url = tab.url, url.isFileURL { + title = url.lastPathComponent } else { title = addressBarString } diff --git a/DuckDuckGo/TabBar/View/TabBarViewController.swift b/DuckDuckGo/TabBar/View/TabBarViewController.swift index c00b5854a0..f3677287ca 100644 --- a/DuckDuckGo/TabBar/View/TabBarViewController.swift +++ b/DuckDuckGo/TabBar/View/TabBarViewController.swift @@ -488,7 +488,7 @@ final class TabBarViewController: NSViewController { if dividedWidth < TabBarViewItem.Width.minimumSelected.rawValue { dividedWidth = (tabsWidth - TabBarViewItem.Width.minimumSelected.rawValue) / (numberOfItems - 1) } - return min(TabBarViewItem.Width.maximum.rawValue, max(minimumWidth, dividedWidth)) + return min(TabBarViewItem.Width.maximum.rawValue, max(minimumWidth, dividedWidth)).rounded() } else { return minimumWidth } From 0abdf0633be99d493ca4d3e49bfcfec23ca4a91f Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Thu, 29 Feb 2024 16:17:08 +0600 Subject: [PATCH 08/10] disable assertion when burning (#2281) Task/Issue URL: https://app.asana.com/0/1201037661562251/1206696399092955/f --- DuckDuckGo/MainWindow/MainViewController.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/DuckDuckGo/MainWindow/MainViewController.swift b/DuckDuckGo/MainWindow/MainViewController.swift index afeee4c7e3..3b25f0524c 100644 --- a/DuckDuckGo/MainWindow/MainViewController.swift +++ b/DuckDuckGo/MainWindow/MainViewController.swift @@ -419,7 +419,6 @@ final class MainViewController: NSViewController { func adjustFirstResponder(selectedTabViewModel: TabViewModel? = nil, tabContent: Tab.TabContent? = nil, force: Bool = false) { guard let selectedTabViewModel = selectedTabViewModel ?? tabCollectionViewModel.selectedTabViewModel else { - assertionFailure("No tab view model selected") return } let tabContent = tabContent ?? selectedTabViewModel.tab.content From 83eae5d56c8829d6e3c196105e15c78cd1880456 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Thu, 29 Feb 2024 11:31:40 +0100 Subject: [PATCH 09/10] Fixes a compilation error in Xcode 15.3 (#2289) Task/Issue URL: https://app.asana.com/0/1199230911884351/1206685505427053/f --- DuckDuckGo/Common/Extensions/URLRequestExtension.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGo/Common/Extensions/URLRequestExtension.swift b/DuckDuckGo/Common/Extensions/URLRequestExtension.swift index b25a3968b3..5155b0cb57 100644 --- a/DuckDuckGo/Common/Extensions/URLRequestExtension.swift +++ b/DuckDuckGo/Common/Extensions/URLRequestExtension.swift @@ -37,7 +37,7 @@ extension URLRequest { request.setValue(userAgent, forHTTPHeaderField: HeaderKey.userAgent.rawValue) let languages = Locale.preferredLanguages.prefix(6) - let acceptLanguage = languages.enumerated().map { index, language in + let acceptLanguage: String = languages.enumerated().map { index, language in let q = 1.0 - (Double(index) * 0.1) return "\(language);q=\(q)" }.joined(separator: ", ") From abe67a709f67b5852d77ae8e0a80021a5b47b8db Mon Sep 17 00:00:00 2001 From: Fernando Bunn Date: Thu, 29 Feb 2024 12:52:53 +0000 Subject: [PATCH 10/10] DBP: Support new dataSource property (#2267) Task/Issue URL: https://app.asana.com/0/1204167627774280/1206602738361283/f **Description**: Add new datasource property support --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 8 +-- .../DataBrokerProtection/Package.swift | 2 +- .../DataBrokerProtection/Model/Action.swift | 11 +++- .../Model/Actions/Click.swift | 1 + .../Model/Actions/EmailConfirmation.swift | 1 + .../Model/Actions/Expectaction.swift | 1 + .../Model/Actions/Extract.swift | 1 + .../Model/Actions/FillForm.swift | 1 + .../Model/Actions/GetCaptchaInfo.swift | 1 + .../Model/Actions/Navigate.swift | 1 + .../Model/Actions/SolveCaptcha.swift | 1 + .../Model/CCFRequestParameters.swift | 18 ++++-- .../Model/CCFResponseParameters.swift | 3 + .../Operations/DataBrokerOperation.swift | 6 +- .../JSON/advancedbackgroundchecks.com.json | 6 +- .../Resources/JSON/backgroundcheck.run.json | 12 ++-- .../Resources/JSON/centeda.com.json | 12 ++-- .../Resources/JSON/clubset.com.json | 12 ++-- .../Resources/JSON/clustrmaps.com.json | 12 ++-- .../Resources/JSON/councilon.com.json | 12 ++-- .../Resources/JSON/curadvisor.com.json | 12 ++-- .../JSON/cyberbackgroundchecks.com.json | 12 ++-- .../Resources/JSON/dataveria.com.json | 12 ++-- .../JSON/fastbackgroundcheck.com.json | 12 ++-- .../Resources/JSON/fastpeoplesearch.com.json | 64 +++++++++++++++++++ .../JSON/freepeopledirectory.com.json | 10 +-- .../Resources/JSON/inforver.com.json | 8 +-- .../Resources/JSON/kwold.com.json | 12 ++-- .../Resources/JSON/neighbor.report.json | 26 ++++---- .../Resources/JSON/newenglandfacts.com.json | 12 ++-- .../Resources/JSON/officialusa.com.json | 8 +-- .../JSON/people-background-check.com.json | 12 ++-- .../Resources/JSON/peoplefinders.com.json | 34 +++++----- .../Resources/JSON/peoplesearchnow.com.json | 12 ++-- .../Resources/JSON/pub360.com.json | 12 ++-- .../Resources/JSON/publicreports.com.json | 12 ++-- .../Resources/JSON/quickpeopletrace.com.json | 12 ++-- .../Resources/JSON/searchpeoplefree.com.json | 12 ++-- .../JSON/smartbackgroundchecks.com.json | 12 ++-- .../Resources/JSON/spokeo.com.json | 28 ++++---- .../Resources/JSON/truepeoplesearch.com.json | 12 ++-- .../Resources/JSON/usa-people-search.com.json | 12 ++-- .../Resources/JSON/usatrace.com.json | 12 ++-- .../Resources/JSON/usphonebook.com.json | 12 ++-- .../Resources/JSON/verecor.com.json | 28 ++++---- .../Resources/JSON/vericora.com.json | 12 ++-- .../Resources/JSON/veriforia.com.json | 12 ++-- .../Resources/JSON/veripages.com.json | 12 ++-- .../Resources/JSON/virtory.com.json | 12 ++-- .../Resources/JSON/wellnut.com.json | 12 ++-- .../ActionsHandlerTests.swift | 8 +-- .../DataBrokerOperationActionTests.swift | 20 +++--- .../DataBrokerProtectionTests/Mocks.swift | 18 ++---- LocalPackages/LoginItems/Package.swift | 2 +- .../NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- .../SystemExtensionManager/Package.swift | 2 +- 59 files changed, 395 insertions(+), 255 deletions(-) create mode 100644 LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/fastpeoplesearch.com.json diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 32a7701d5f..92dddde1b0 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13583,7 +13583,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 112.0.1; + version = 113.0.0; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index dc7e5c7589..b43fb91512 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "c513f0f0fedc1de65591d46908ddef530b0dc001", - "version" : "112.0.1" + "revision" : "f903ffcbc51e85ac262c355b56726e3387957a80", + "version" : "113.0.0" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "36ddba2cbac52a41b9a9275af06d32fa8a56d2d7", - "version" : "4.64.0" + "revision" : "a3690b7666a3617693383d948cb492513f6aa569", + "version" : "5.0.0" } }, { diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index e28164bb3f..8ce6dfa876 100644 --- a/LocalPackages/DataBrokerProtection/Package.swift +++ b/LocalPackages/DataBrokerProtection/Package.swift @@ -29,7 +29,7 @@ let package = Package( targets: ["DataBrokerProtection"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "112.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "113.0.0"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Action.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Action.swift index fc35847703..10204cc503 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Action.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Action.swift @@ -29,14 +29,19 @@ enum ActionType: String, Codable, Sendable { case solveCaptcha } +enum DataSource: String, Codable { + case userProfile + case extractedProfile +} + protocol Action: Codable, Sendable { var id: String { get } var actionType: ActionType { get } var needsEmail: Bool { get } + var dataSource: DataSource { get } } extension Action { - var needsEmail: Bool { - get { false } - } + var needsEmail: Bool { false } + var dataSource: DataSource { .userProfile } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Click.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Click.swift index 582921c593..a75fe0113f 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Click.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Click.swift @@ -22,4 +22,5 @@ struct ClickAction: Action { let id: String let actionType: ActionType let elements: [PageElement] + let dataSource: DataSource? } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/EmailConfirmation.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/EmailConfirmation.swift index 1983c38470..5b3b5bcbdb 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/EmailConfirmation.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/EmailConfirmation.swift @@ -22,4 +22,5 @@ struct EmailConfirmationAction: Action { let id: String let actionType: ActionType let pollingTime: TimeInterval + let dataSource: DataSource? } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Expectaction.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Expectaction.swift index 60f5f2bd5a..33722a5f84 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Expectaction.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Expectaction.swift @@ -34,4 +34,5 @@ internal struct ExpectationAction: Action { let id: String let actionType: ActionType let expectations: [Item] + let dataSource: DataSource? } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Extract.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Extract.swift index 4f5c675bc2..97dcfea382 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Extract.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Extract.swift @@ -21,4 +21,5 @@ struct ExtractAction: Action { let actionType: ActionType let selector: String let profile: ExtractProfileSelectors + let dataSource: DataSource? } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/FillForm.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/FillForm.swift index 38abcb88cc..3a54a941be 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/FillForm.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/FillForm.swift @@ -23,6 +23,7 @@ struct FillFormAction: Action { let actionType: ActionType let selector: String let elements: [PageElement] + let dataSource: DataSource? var needsEmail: Bool { elements.contains { $0.type == "email" } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/GetCaptchaInfo.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/GetCaptchaInfo.swift index a6b1ffdd09..9d7c9ebf2d 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/GetCaptchaInfo.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/GetCaptchaInfo.swift @@ -22,4 +22,5 @@ struct GetCaptchaInfoAction: Action { let id: String let actionType: ActionType let selector: String + let dataSource: DataSource? } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Navigate.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Navigate.swift index 03dd465d80..fc8a72782b 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Navigate.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/Navigate.swift @@ -21,4 +21,5 @@ struct NavigateAction: Action { let actionType: ActionType let url: String let ageRange: [String]? + let dataSource: DataSource? } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/SolveCaptcha.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/SolveCaptcha.swift index 3ef795394f..64351aab68 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/SolveCaptcha.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/Actions/SolveCaptcha.swift @@ -22,4 +22,5 @@ struct SolveCaptchaAction: Action { let id: String let actionType: ActionType let selector: String + let dataSource: DataSource? } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/CCFRequestParameters.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/CCFRequestParameters.swift index a9e4c74ba4..ff30e4f541 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/CCFRequestParameters.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/CCFRequestParameters.swift @@ -19,9 +19,8 @@ import Foundation enum CCFRequestData: Encodable { - case profile(ProfileQuery) - case extractedProfile(ExtractedProfile) case solveCaptcha(CaptchaToken) + case userData(ProfileQuery, ExtractedProfile?) } struct CaptchaToken: Encodable, Sendable { @@ -33,6 +32,11 @@ struct InitParams: Encodable { let dataBrokerData: DataBroker } +private enum UserDataCodingKeys: String, CodingKey { + case userProfile + case extractedProfile +} + struct ActionRequest: Encodable { let action: Action let data: CCFRequestData? @@ -47,12 +51,14 @@ struct ActionRequest: Encodable { var container = encoder.container(keyedBy: CodingKeys.self) switch data { - case .profile(let profileQuery): - try container.encode(profileQuery, forKey: .data) case .solveCaptcha(let captchaToken): try container.encode(captchaToken, forKey: .data) - case .extractedProfile(let extractedProfile): - try container.encode(extractedProfile, forKey: .data) + case .userData(let profileQuery, let extractedProfile): + var userDataContainer = container.nestedContainer(keyedBy: UserDataCodingKeys.self, forKey: .data) + try userDataContainer.encode(profileQuery, forKey: .userProfile) + if let extractedProfile = extractedProfile { + try userDataContainer.encode(extractedProfile, forKey: .extractedProfile) + } default: assertionFailure("Data not found. Please add the mission data to the encoding list.") } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/CCFResponseParameters.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/CCFResponseParameters.swift index 593c8e1013..f23d09ff10 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/CCFResponseParameters.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/CCFResponseParameters.swift @@ -74,17 +74,20 @@ struct CCFSuccessResponse: Decodable { let actionID: String let actionType: ActionType let response: CCFSuccessData? + let meta: [String: Any]? enum CodingKeys: CodingKey { case actionID case actionType case response + case meta } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.actionID = try container.decode(String.self, forKey: .actionID) self.actionType = try container.decode(ActionType.self, forKey: .actionType) + self.meta = try container.decodeIfPresent([String: Any].self, forKey: .meta) switch actionType { case .navigate: diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerOperation.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerOperation.swift index 8b74fdb0e5..1feb38e323 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerOperation.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Operations/DataBrokerOperation.swift @@ -111,11 +111,7 @@ extension DataBrokerOperation { stageCalculator?.setStage(.captchaParse) } - if let extractedProfile = self.extractedProfile { - await webViewHandler?.execute(action: action, data: .extractedProfile(extractedProfile)) - } else { - await webViewHandler?.execute(action: action, data: .profile(query.profileQuery)) - } + await webViewHandler?.execute(action: action, data: .userData(query.profileQuery, self.extractedProfile)) } private func runEmailConfirmationAction(action: EmailConfirmationAction) async throws { diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/advancedbackgroundchecks.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/advancedbackgroundchecks.com.json index d7daac5036..e14795a195 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.5", + "version": "0.1.6", "parent": "peoplefinders.com", "addedDatetime": 1678060800000, "steps": [ @@ -45,7 +45,9 @@ "separator": "," }, "profileUrl": { - "selector": ".link-to-details" + "selector": ".link-to-details", + "identifierType": "path", + "identifier": "https://www.advancedbackgroundchecks.com/${id}" } } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/backgroundcheck.run.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/backgroundcheck.run.json index 552923ca1f..851d5d6dac 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/backgroundcheck.run.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/backgroundcheck.run.json @@ -1,7 +1,7 @@ { "name": "backgroundcheck.run", "url": "backgroundcheck.run", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1677736800000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "5f90e39f-cb94-4b8d-94ed-48ba0060dc08", + "id": "64967cc5-ebf6-4c27-b12c-8f15dceb2678", "url": "https://backgroundcheck.run/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}" }, { "actionType": "extract", - "id": "3225fa15-4e00-4e6a-bfc7-a85dfb504c86", + "id": "57dfbc89-94c8-49f0-9952-c58c92883ffd", "selector": ".b-pfl-list", "profile": { "name": { @@ -39,7 +39,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://backgroundcheck.run/person/${id}" } } } @@ -56,4 +58,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/centeda.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/centeda.com.json index 7050bab137..538505a7fe 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/centeda.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/centeda.com.json @@ -1,9 +1,9 @@ { "name": "Centeda", "url": "centeda.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", - "addedDatetime": 1677715200000, + "addedDatetime": 1677736800000, "steps": [ { "stepType": "scan", @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "af9c9f03-e778-4c29-85fc-e5cbbfec563c", + "id": "ce7caa09-bcf4-4bf9-bc7a-024c2c50bd1f", "url": "https://centeda.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "79fa2a1c-65b4-417a-a8ac-2ca6d729ffc1", + "id": "e779b827-702d-402d-ae79-f3681ad50008", "selector": ".search-result > a", "profile": { "name": { @@ -47,7 +47,9 @@ "selector": ".//div[@class='col-sm-24 col-md-8 related-to']//li" }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "param", + "identifier": "pid" } } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/clubset.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/clubset.com.json index 8b6801fc48..7b27290378 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/clubset.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/clubset.com.json @@ -1,7 +1,7 @@ { "name": "Clubset", "url": "clubset.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1702965600000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "5c559c67-c13c-4055-a318-6ba35d62a2cf", + "id": "9b8c7984-a54a-40d1-8e2e-56cd1910ec61", "url": "https://clubset.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state|upcase}&city=${city|capitalize}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "866bdfc5-069e-4734-9ce0-a19976fa796b", + "id": "dee8a12e-b8bd-4a37-b77d-8330d8eda4cb", "selector": ".card", "profile": { "name": { @@ -51,7 +51,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://clubset.com/profile/${id}" } } } @@ -68,4 +70,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/clustrmaps.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/clustrmaps.com.json index 4c2bd20999..0ac6a9698f 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/clustrmaps.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/clustrmaps.com.json @@ -1,7 +1,7 @@ { "name": "ClustrMaps", "url": "clustrmaps.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "neighbor.report", "addedDatetime": 1692594000000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "e6929e37-4764-450a-be2a-73479f11842a", + "id": "c4d4ce8d-0b33-46cb-8e73-a544b362460d", "url": "https://clustrmaps.com/persons/${firstName}-${lastName}/${state|stateFull|capitalize}/${city|hyphenated}" }, { "actionType": "extract", - "id": "06f39df7-89c2-40da-b288-cdf3ed0e4bfd", + "id": "f0e4f08c-c999-451c-b195-93f481c0a4de", "selector": ".//div[@itemprop='Person']", "profile": { "name": { @@ -39,7 +39,9 @@ "afterText": "Associated persons:" }, "profileUrl": { - "selector": ".persons" + "selector": ".persons", + "identifierType": "path", + "identifier": "https://clustrmaps.com/person/${id}" } } } @@ -56,4 +58,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/councilon.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/councilon.com.json index 3df8d7f195..08485294f7 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/councilon.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/councilon.com.json @@ -1,7 +1,7 @@ { "name": "Councilon", "url": "councilon.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1702965600000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "a5052dda-d4e7-4d3f-97bc-ef9f0aa9ae5f", + "id": "ac6caadd-7930-4776-8473-9403b568611e", "url": "https://councilon.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "55a50a37-9b1b-40fa-8533-af1273a26258", + "id": "5629ad0b-1f33-480f-a6ec-5add91b2dce8", "selector": ".card", "profile": { "name": { @@ -51,7 +51,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://councilon.com/doc/${id}" } } } @@ -68,4 +70,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/curadvisor.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/curadvisor.com.json index 3b59ed585e..967a01237a 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/curadvisor.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/curadvisor.com.json @@ -1,7 +1,7 @@ { "name": "CurAdvisor", "url": "curadvisor.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1703052000000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "ab5503c7-bd11-4320-b38e-c637b239182e", + "id": "e25dd6a6-60da-4d55-b544-bb03216f9e99", "url": "https://curadvisor.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "d273c1cf-2635-40d7-b26f-6f34467282cf", + "id": "c9babcb9-540e-48ac-900b-b32229e28124", "selector": ".card", "profile": { "name": { @@ -51,7 +51,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://curadvisor.com/pro/${id}" } } } @@ -68,4 +70,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/cyberbackgroundchecks.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/cyberbackgroundchecks.com.json index f930834db9..f30232f7c4 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/cyberbackgroundchecks.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/cyberbackgroundchecks.com.json @@ -1,7 +1,7 @@ { "name": "Cyber Background Checks", "url": "cyberbackgroundchecks.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "peoplefinders.com", "addedDatetime": 1705644000000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "d8c84470-d8b3-4c46-a645-01cc6b139b3b", + "id": "9f5caaf9-5bd7-494e-bfbb-e33c4927cdb3", "url": "https://www.cyberbackgroundchecks.com/people/${firstName}-${lastName}/${state}/${city}" }, { "actionType": "extract", - "id": "b4c12cf2-0fd6-4209-8816-3bf2cce23cde", + "id": "d6c07b68-7a33-45a4-9e8e-ae6f9262ef29", "selector": ".card", "profile": { "name": { @@ -41,7 +41,9 @@ "findElements": true }, "profileUrl": { - "selector": ".//a[@class='btn btn-primary btn-block']" + "selector": ".//a[@class='btn btn-primary btn-block']", + "identifierType": "path", + "identifier": "https://www.cyberbackgroundchecks.com/detail/${firstName}-${middleName}-${lastName}/${id}" } } } @@ -58,4 +60,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/dataveria.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/dataveria.com.json index 9949e04675..cfa6b1f008 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/dataveria.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/dataveria.com.json @@ -1,7 +1,7 @@ { "name": "Dataveria", "url": "dataveria.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1677736800000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "a8f3a259-2d39-4ae3-ac13-65aa63a53331", + "id": "92f18635-ddbb-4700-afcd-055f80f721b8", "url": "https://dataveria.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "e810cc23-2d2a-4e6e-b06f-dfc8a2e1e85d", + "id": "441a4974-cc5a-401d-aec5-f597956327ff", "selector": ".search-item", "profile": { "name": { @@ -48,7 +48,9 @@ "beforeText": "," }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://dataveria.com/view/${id}" } } } @@ -65,4 +67,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/fastbackgroundcheck.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/fastbackgroundcheck.com.json index 9c1129a333..63617f9e70 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/fastbackgroundcheck.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/fastbackgroundcheck.com.json @@ -1,7 +1,7 @@ { "name": "FastBackgroundCheck.com", "url": "fastbackgroundcheck.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "peoplefinders.com", "addedDatetime": 1706248800000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "997adf8d-023c-409e-9206-57871cd25f0a", + "id": "58fdfa90-9b0c-4fda-8961-e73502f68474", "url": "https://www.fastbackgroundcheck.com/people/${firstName}-${lastName}/${city}-${state}" }, { "actionType": "extract", - "id": "2f531e34-2ac0-4743-a760-065187d6c951", + "id": "14dfda23-a4c3-483f-a67f-e89322636036", "selector": ".person-container", "profile": { "name": { @@ -49,7 +49,9 @@ "separator": "•" }, "profileUrl": { - "selector": ".//a[contains(@title, 'See full background')]" + "selector": ".//a[contains(@title, 'See full background')]", + "identifierType": "path", + "identifier": "https://www.fastbackgroundcheck.com/people/${firstName}-${lastName}/id/${id}" } } } @@ -66,4 +68,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/fastpeoplesearch.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/fastpeoplesearch.com.json new file mode 100644 index 0000000000..6d27a05e46 --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/fastpeoplesearch.com.json @@ -0,0 +1,64 @@ +{ + "name": "FastPeopleSearch", + "url": "fastpeoplesearch.com", + "version": "0.1.5", + "parent": "peoplefinders.com", + "addedDatetime": 1675317600000, + "steps": [ + { + "stepType": "scan", + "scanType": "templatedUrl", + "actions": [ + { + "actionType": "navigate", + "id": "040e0a0a-095a-490e-8c55-ee7b66732030", + "url": "https://www.fastpeoplesearch.com/name/${firstName}-${lastName}_${city}-${state}" + }, + { + "actionType": "extract", + "id": "f7a316c3-f4c0-46b5-be2d-b8df71852a26", + "selector": ".card", + "profile": { + "name": { + "selector": ".larger" + }, + "alternativeNamesList": { + "selector": ".//h3[contains(strong, 'AKA')]/following-sibling::span | .//span[contains(text(), 'Goes By')]/strong", + "findElements": true + }, + "age": { + "selector": ".//div[@class='card-block']", + "afterText": "Age:", + "beforeText": "Full Name:" + }, + "addressFullList": { + "selector": ".//h3[contains(strong, 'Past Addresses')]/following-sibling::div/div/a", + "findElements": true + }, + "addressCityState": { + "selector": ".grey" + }, + "relativesList": { + "selector": ".//h3[contains(strong, 'Relatives')]/following-sibling::a[@class='nowrap']", + "findElements": true, + "separator": "•" + }, + "profileUrl": { + "selector": ".link-to-details" + } + } + } + ] + }, + { + "stepType": "optOut", + "optOutType": "parentSiteOptOut", + "actions": [] + } + ], + "schedulingConfig": { + "retryError": 48, + "confirmOptOutScan": 72, + "maintenanceScan": 240 + } +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/freepeopledirectory.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/freepeopledirectory.com.json index 9d114d48b3..a96ac52bab 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/freepeopledirectory.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/freepeopledirectory.com.json @@ -1,7 +1,7 @@ { "name": "FreePeopleDirectory", "url": "freepeopledirectory.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "spokeo.com", "addedDatetime": 1674540000000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "b8b912b0-201d-4cd1-8237-235c34fe0fea", + "id": "f1510c8b-f010-4e6f-a748-d34c7777edd7", "url": "https://www.freepeopledirectory.com/name/${firstName}-${lastName}/${state|upcase}/${city}" }, { "actionType": "extract", - "id": "50e30922-ef1d-4820-abbd-f536378472d4", + "id": "cc77e311-7660-43a2-88ae-2c179840f6df", "selector": ".whole-card", "profile": { "name": { @@ -37,7 +37,9 @@ "separator": "," }, "profileUrl": { - "selector": ".//a[@class='button']" + "selector": ".//a[@class='button']", + "identifierType": "path", + "identifier": "https://www.freepeopledirectory.com/person/${firstName}-${lastName}/${city|capitalize}-${state|upcase}/${id}" } } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/inforver.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/inforver.com.json index 2c035a980c..dd5e640a84 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/inforver.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/inforver.com.json @@ -1,7 +1,7 @@ { "name": "Inforver", "url": "inforver.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1677736800000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "85fac850-36ad-4d9c-ad7c-c1250c7b5585", + "id": "840da5cd-0581-4692-af09-ce89c83e6786", "url": "https://inforver.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "e5e9c1b0-4af4-4fb6-bd2d-7d026ffd95e7", + "id": "4cabd3c9-83bd-4cfb-9acb-d20738bfea21", "selector": ".search-item", "profile": { "name": { @@ -65,4 +65,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/kwold.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/kwold.com.json index 5f7e750909..46f723a0d5 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/kwold.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/kwold.com.json @@ -1,7 +1,7 @@ { "name": "Kwold", "url": "kwold.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1702965600000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "936eee30-d31e-48fb-8cc4-9391869934b9", + "id": "878e00ab-dbad-4ca9-a303-645702a36ee2", "url": "https://kwold.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "870ee174-275a-4ea8-b2d7-a222418e5de9", + "id": "ec9f8ae6-199e-441b-9722-ffc6737b4595", "selector": ".card", "profile": { "name": { @@ -51,7 +51,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://kwold.com/pp/${id}" } } } @@ -68,4 +70,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/neighbor.report.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/neighbor.report.json index 92a0d2af57..8e09a3db50 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/neighbor.report.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/neighbor.report.json @@ -1,7 +1,7 @@ { "name": "Neighbor Report", "url": "neighbor.report", - "version": "0.1.4", + "version": "0.1.5", "addedDatetime": 1703570400000, "steps": [ { @@ -10,12 +10,12 @@ "actions": [ { "actionType": "navigate", - "id": "bbaf8a18-fef8-42a6-9682-747b8ff485b2", + "id": "22f67a44-d538-48a0-b6f4-c783123c6dfa", "url": "https://neighbor.report/${firstName}-${lastName}/${state|stateFull|hyphenated}/${city|hyphenated}" }, { "actionType": "extract", - "id": "0dac4a6d-1291-47c3-97b8-56200f751ac8", + "id": "14ff868b-b6cc-485e-a5cf-93357a63c2ac", "selector": ".lstd", "profile": { "name": { @@ -39,7 +39,9 @@ "separator": "," }, "profileUrl": { - "selector": "(.//a[@class='persons'])[1]" + "selector": "(.//a[@class='persons'])[1]", + "identifierType": "path", + "identifier": "https://neighbor.report/person/${id}" } } } @@ -51,12 +53,12 @@ "actions": [ { "actionType": "navigate", - "id": "b1f7f4ab-51b0-4885-ba73-97be0822d0ba", + "id": "477f4e90-686c-400e-8d45-65749ff60b5d", "url": "https://neighbor.report/remove" }, { "actionType": "fillForm", - "id": "743afa6c-7dea-4115-934b-bea369307acd", + "id": "335b078c-d27f-4045-8a36-2cc0c125d271", "selector": ".form-horizontal", "elements": [ { @@ -75,17 +77,17 @@ }, { "actionType": "getCaptchaInfo", - "id": "24ce0da0-7cc3-47e7-bf8e-6f5fe98b7a91", + "id": "0ed843a1-2788-454c-a666-17906d2991cb", "selector": ".recaptcha-div" }, { "actionType": "solveCaptcha", - "id": "b720de9a-f519-466f-980d-d9c52d8870a2", + "id": "e6f3b3c5-e61c-4e75-878d-cecbaae26013", "selector": ".recaptcha-div" }, { "actionType": "click", - "id": "46690938-f112-4091-bd07-b5641e38151f", + "id": "8544dcb5-5bd7-4045-91a8-23bbfad7bfc8", "elements": [ { "type": "button", @@ -95,7 +97,7 @@ }, { "actionType": "click", - "id": "07cfed17-9d75-471a-b6a0-0522add35ffa", + "id": "6748ca30-0044-4e9a-8a35-5d686359688c", "elements": [ { "type": "button", @@ -109,7 +111,7 @@ }, { "actionType": "expectation", - "id": "ebd61347-60e1-4c19-bc41-dd1ce36d3138", + "id": "a56fcc4c-fdd4-4d92-96b3-a8b89d10ca80", "expectations": [ { "type": "text", @@ -126,4 +128,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/newenglandfacts.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/newenglandfacts.com.json index 54f8d23ac8..0ca000936a 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/newenglandfacts.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/newenglandfacts.com.json @@ -1,7 +1,7 @@ { "name": "New England Facts", "url": "newenglandfacts.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1703052000000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "05725a5a-ec3f-49c8-875b-ab9787b9385f", + "id": "ecac2e82-71fd-4a3d-ba7e-bfe46b0a3db8", "url": "https://newenglandfacts.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "7f41b78a-bb65-4bb2-a6ca-1a6ab55890ce", + "id": "633a36d1-a68c-4435-93eb-de82d940e7f7", "selector": ".b-pfl-list", "profile": { "name": { @@ -49,7 +49,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://newenglandfacts.com/people/${id}" } } } @@ -66,4 +68,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/officialusa.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/officialusa.com.json index 9cb63483be..c744321e1e 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/officialusa.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/officialusa.com.json @@ -1,7 +1,7 @@ { "name": "OfficialUSA", "url": "officialusa.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "neighbor.report", "addedDatetime": 1692594000000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "b430e29e-89f0-4994-96b2-08d0cbdc388c", + "id": "947ca80c-3331-4425-9ad3-ab25e2170f29", "url": "https://officialusa.com/names/${firstName}-${lastName}/" }, { "actionType": "extract", - "id": "d989f3b7-9b8a-44a6-a51e-70762255f3fc", + "id": "fd803889-7f13-4955-8cec-eac551f5c5f2", "selector": ".person", "profile": { "name": { @@ -49,4 +49,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/people-background-check.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/people-background-check.com.json index b8550c93e4..51c4807584 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/people-background-check.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/people-background-check.com.json @@ -1,7 +1,7 @@ { "name": "People Background Check", "url": "people-background-check.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1702965600000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "6fee90c5-5f7e-4fd0-badf-069e2b94a65d", + "id": "86bd784e-350b-42c1-825f-4625e6f8eb87", "url": "https://people-background-check.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}" }, { "actionType": "extract", - "id": "ee03ba42-e9a5-4489-a7d6-d50bf21238aa", + "id": "06e575b5-ac64-4bf5-b5e7-6e39e5a474fb", "selector": ".b-pfl-list", "profile": { "name": { @@ -39,7 +39,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://people-background-check.com/${id}" } } } @@ -56,4 +58,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/peoplefinders.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/peoplefinders.com.json index 34bc5b8770..e9d117aa44 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/peoplefinders.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/peoplefinders.com.json @@ -1,7 +1,7 @@ { "name": "PeopleFinders", "url": "peoplefinders.com", - "version": "0.1.4", + "version": "0.1.5", "addedDatetime": 1677132000000, "steps": [ { @@ -10,12 +10,12 @@ "actions": [ { "actionType": "navigate", - "id": "71c7cb2f-14fe-43b8-9623-452b8bd10d4e", + "id": "12c69911-415b-4904-8162-d7993d44e348", "url": "https://www.peoplefinders.com/people/${firstName}-${lastName}/${state}/${city}?landing=all&age=${age}" }, { "actionType": "extract", - "id": "5c5af912-091f-4f48-922f-ba554951ddd9", + "id": "f35cbfda-053f-444c-93b7-36e9bed2612b", "selector": ".record", "profile": { "name": { @@ -37,7 +37,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "param", + "identifier": "id" } } } @@ -49,12 +51,12 @@ "actions": [ { "actionType": "navigate", - "id": "4b065fde-35c7-43d7-aed6-3abcdac94f08", + "id": "da658a1f-254b-42c6-b78a-f93655048db8", "url": "https://www.peoplefinders.com/opt-out" }, { "actionType": "click", - "id": "b5c0929e-e362-4570-815b-0433ef97fddf", + "id": "c15a2587-ff08-4ec6-b7c0-0744273d57a9", "elements": [ { "type": "button", @@ -64,7 +66,7 @@ }, { "actionType": "fillForm", - "id": "2fb91804-e5ea-414e-9354-fba98f3c00e1", + "id": "5685d436-32d5-4de0-a2b8-d5bbb4fa778d", "selector": ".opt-out-form", "elements": [ { @@ -79,17 +81,17 @@ }, { "actionType": "getCaptchaInfo", - "id": "4b9706ef-dd9b-47d6-b337-12f66a5f9138", + "id": "fcf4b0cf-9bb4-42e6-a2a9-68e4f2a25a2c", "selector": ".g-recaptcha" }, { "actionType": "solveCaptcha", - "id": "770019d3-fa88-400a-8480-7cc31d6b3382", + "id": "25c7fbb0-0508-4f93-aeb8-3642ecef8c33", "selector": ".g-recaptcha" }, { "actionType": "click", - "id": "a7285f44-6c99-44b1-8199-eb6c383fe12b", + "id": "4ac6a176-ddaf-437f-8d8f-2dde0fe6b0ed", "elements": [ { "type": "button", @@ -99,22 +101,22 @@ }, { "actionType": "emailConfirmation", - "id": "05cc08ea-fb80-40fb-8cce-3ca674eea03b", + "id": "6f43425f-a49d-4eac-bec2-794c5f6bd687", "pollingTime": 30 }, { "actionType": "getCaptchaInfo", - "id": "8cb4256a-b162-407f-8434-5536c7560c98", + "id": "45f59ed0-3a36-4ab6-9c45-e906471fb3e4", "selector": ".g-recaptcha" }, { "actionType": "solveCaptcha", - "id": "38c64eec-6bd9-4751-a7cf-8cbe9901b0f6", + "id": "85469ad1-8870-449d-961e-22ea10738ec0", "selector": ".g-recaptcha" }, { "actionType": "click", - "id": "d1d25423-912b-4828-825b-eb83809ada08", + "id": "cab0438c-1770-4dac-930d-041d44772172", "elements": [ { "type": "button", @@ -124,7 +126,7 @@ }, { "actionType": "expectation", - "id": "fdb755da-8970-426f-b09e-12165c2169dd", + "id": "bc09540c-8aeb-4d9f-b515-0ebb6f4583a5", "expectations": [ { "type": "url", @@ -140,4 +142,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/peoplesearchnow.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/peoplesearchnow.com.json index 6189f3d311..1230dd8338 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/peoplesearchnow.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/peoplesearchnow.com.json @@ -1,7 +1,7 @@ { "name": "People Search Now", "url": "peoplesearchnow.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "peoplefinders.com", "addedDatetime": 1705989600000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "db9e093d-68c2-45e1-a529-29a2dc67dfab", + "id": "80be0e78-1499-4d5d-83bb-deb8b6c92e8d", "url": "https://peoplesearchnow.com/person/${firstName}-${lastName}_${city}_${state}/" }, { "actionType": "extract", - "id": "78912133-761b-4971-9780-4e16c8dd43b2", + "id": "79098855-0459-4f26-877b-039700e098b3", "selector": ".result-search-block", "profile": { "name": { @@ -41,7 +41,9 @@ "findElements": true }, "profileUrl": { - "selector": ".result-search-block-title a" + "selector": ".result-search-block-title a", + "identifierType": "path", + "identifier": "https://www.peoplesearchnow.com/name/${firstName}-${middleName}-${lastName}/${id}" } } } @@ -58,4 +60,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/pub360.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/pub360.com.json index 815fdcb8fc..f43c1ba8ad 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/pub360.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/pub360.com.json @@ -1,7 +1,7 @@ { "name": "Pub360", "url": "pub360.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1677736800000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "8e2a1251-2685-476a-b4c1-53d138331abe", + "id": "6ed70f0e-db89-44e1-ab8d-f27a1f4fc3ac", "url": "https://pub360.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "9ce62e6f-b103-45f6-9f92-56785eb22320", + "id": "3bdb06db-9c0b-46fb-b572-b31a6f4b6445", "selector": ".search-item", "profile": { "name": { @@ -48,7 +48,9 @@ "beforeText": "," }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://pub360.com/entry/${id}" } } } @@ -65,4 +67,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/publicreports.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/publicreports.com.json index 5ea3d241e4..6e8dc7e14b 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/publicreports.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/publicreports.com.json @@ -1,7 +1,7 @@ { "name": "PublicReports", "url": "publicreports.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1703052000000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "b995b1bf-6610-4085-9d07-d38857807535", + "id": "cdd6e94e-ad5d-4331-bb0d-8212e52e0efb", "url": "https://publicreports.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "7fb121fb-e2a0-4fa2-9b97-51130104971c", + "id": "64808ea7-0f52-45ef-a374-dafe8b9272e7", "selector": ".card", "profile": { "name": { @@ -51,7 +51,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://neighbor.report/person/${id}" } } } @@ -68,4 +70,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/quickpeopletrace.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/quickpeopletrace.com.json index e8b18f9ec8..e598516676 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/quickpeopletrace.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/quickpeopletrace.com.json @@ -1,7 +1,7 @@ { "name": "Quick People Trace", "url": "quickpeopletrace.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "peoplefinders.com", "addedDatetime": 1674540000000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "2db8c120-a8c3-4aa0-a9ce-b075ca85fc68", + "id": "d97db33b-c755-48b1-b751-51541d55b0fe", "url": "https://www.quickpeopletrace.com/search/?addresssearch=1&tabid=1&teaser-firstname=${firstName}&teaser-middlename=&teaser-lastname=${lastName}&teaser-city=${city}&teaser-state=${state|upcase}&teaser-submitted=Search" }, { "actionType": "extract", - "id": "bd48b737-89c4-408a-a28c-2dfa828aebd8", + "id": "54cdba05-95bd-4142-b97c-4cafc59059df", "selector": "//table/tbody/tr[position() > 1]", "profile": { "name": { @@ -33,7 +33,9 @@ "findElements": true }, "profileUrl": { - "selector": ".//a[@class='btn red-btn']" + "selector": ".//a[@class='btn red-btn']", + "identifierType": "param", + "identifier": "id" } } } @@ -50,4 +52,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/searchpeoplefree.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/searchpeoplefree.com.json index 4a68c912e3..2509ae50e8 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/searchpeoplefree.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/searchpeoplefree.com.json @@ -1,7 +1,7 @@ { "name": "Search People FREE", "url": "searchpeoplefree.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "peoplefinders.com", "addedDatetime": 1703052000000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "f5bad072-6f55-4357-b23b-1df4c9584e67", + "id": "a85625a6-4607-4fea-9fa4-38294a7de727", "url": "https://searchpeoplefree.com/find/${firstName}-${lastName}/${state}/${city}" }, { "actionType": "extract", - "id": "749fb8fe-9994-41e2-a0ea-ae6334c5aee0", + "id": "f41ee88d-149e-48ac-9371-efbaa151c773", "selector": "//li[@class='toc l-i mb-5']", "profile": { "name": { @@ -51,7 +51,9 @@ "findElements": true }, "profileUrl": { - "selector": ".//a[contains(@class, 'btn-continue')]" + "selector": ".//a[contains(@class, 'btn-continue')]", + "identifierType": "path", + "identifier": "https://www.searchpeoplefree.com/find/${firstName}-${lastName}/${id}" } } } @@ -68,4 +70,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/smartbackgroundchecks.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/smartbackgroundchecks.com.json index 23f588c796..7941c945da 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/smartbackgroundchecks.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/smartbackgroundchecks.com.json @@ -1,7 +1,7 @@ { "name": "SmartBackgroundChecks", "url": "smartbackgroundchecks.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "peoplefinders.com", "addedDatetime": 1678082400000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "1c6bdc6e-12dd-47db-b5b0-13055c1f3d5d", + "id": "290d3add-c786-4ecf-a528-50b2a240f791", "url": "https://www.smartbackgroundchecks.com/people/${firstName}-${lastName}/${city}/${state}" }, { "actionType": "extract", - "id": "ac554b4f-e4a0-44c5-81a6-c04e46e4ce3b", + "id": "2e04c4da-5f4b-4ab3-bd9e-4d4300d51f63", "selector": ".card-block", "profile": { "name": { @@ -42,7 +42,9 @@ "findElements": true }, "profileUrl": { - "selector": ".//h2//a" + "selector": ".//h2//a", + "identifierType": "path", + "identifier": "https://www.smartbackgroundchecks.com/people/${firstName}-${lastName}/${id}" } } } @@ -59,4 +61,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/spokeo.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/spokeo.com.json index 3c0f0008f8..f459f5a1d9 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/spokeo.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/spokeo.com.json @@ -1,7 +1,7 @@ { "name": "Spokeo", "url": "spokeo.com", - "version": "0.1.4", + "version": "0.1.5", "addedDatetime": 1692594000000, "mirrorSites": [ { @@ -36,12 +36,12 @@ "actions": [ { "actionType": "navigate", - "id": "9b617d27-b330-46fc-bdb0-6239c0873897", + "id": "02538105-0a5d-46f1-9edc-c643b3f87f20", "url": "https://www.spokeo.com/${firstName}-${lastName}/${state|stateFull}/${city}" }, { "actionType": "extract", - "id": "4f7124c2-bd8c-4649-84f2-04f0962225b5", + "id": "569c27a3-6116-4136-84e7-67af0e73fe97", "selector": ".single-column-list-item", "profile": { "name": { @@ -61,7 +61,9 @@ "findElements": true }, "profileUrl": { - "selector": ".title" + "selector": ".title", + "identifierType": "path", + "identifier": "https://www.spokeo.com/${firstName}-${lastName}/${state|stateFull}/${city|hyphenated}/${id}" } } } @@ -73,12 +75,12 @@ "actions": [ { "actionType": "navigate", - "id": "df75e4fb-f14b-4b65-afe2-82e03b71c6a9", + "id": "4899529f-b55c-42ab-a91b-1a2abd91a369", "url": "https://www.spokeo.com/optout" }, { "actionType": "fillForm", - "id": "42cbfc2b-d96b-4bd6-8d16-0542a672d869", + "id": "eeb19a12-9664-45ae-9fbc-b961f0925ef0", "selector": ".optout_container", "elements": [ { @@ -93,17 +95,17 @@ }, { "actionType": "getCaptchaInfo", - "id": "e1581b9e-7460-4bbd-a010-634c2db12ca1", + "id": "1de65c74-7d06-4ffe-b569-b4b0619e7f79", "selector": "#g-recaptcha" }, { "actionType": "solveCaptcha", - "id": "01ca39d9-e842-41cf-b0f9-a7d517bc0dd6", + "id": "fcdc9be7-ce35-479b-8f05-eb81a1d77d51", "selector": "#g-recaptcha" }, { "actionType": "click", - "id": "7556edd5-570b-4c4a-acc7-f1066138d513", + "id": "5bccd84d-cda2-4b55-815f-e1ca18168cc4", "elements": [ { "type": "button", @@ -113,7 +115,7 @@ }, { "actionType": "expectation", - "id": "f7b5125e-0dda-4a14-8943-8c20c09125bc", + "id": "adcf6b50-f894-4501-8cde-9ab40048c4b2", "expectations": [ { "type": "text", @@ -124,12 +126,12 @@ }, { "actionType": "emailConfirmation", - "id": "dbd875b6-bdc7-48ca-962b-885941e6284a", + "id": "4bbfb20c-dd3c-46a5-b198-3502f778f373", "pollingTime": 30 }, { "actionType": "expectation", - "id": "b2f1c371-d779-4b3b-8516-0d13169cf873", + "id": "11e8206f-5cbc-4e1a-89e1-67a57537e8a3", "expectations": [ { "type": "text", @@ -146,4 +148,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/truepeoplesearch.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/truepeoplesearch.com.json index a226c959a0..32cbc5f9db 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/truepeoplesearch.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/truepeoplesearch.com.json @@ -1,7 +1,7 @@ { "name": "TruePeopleSearch", "url": "truepeoplesearch.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "peoplefinders.com", "addedDatetime": 1703138400000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "12eb70c1-53d5-4881-9dce-74ed4fada583", + "id": "127f6406-5630-42dc-bfdf-d7df7862f5d6", "url": "https://www.truepeoplesearch.com/results?name=${firstName}%20${lastName}&citystatezip=${city|capitalize},${state|upcase}" }, { "actionType": "extract", - "id": "881e0e21-c375-4083-a9be-86f82063849b", + "id": "267a0b26-dc67-4ed9-b5c4-a6de838765ed", "selector": ".card-summary", "profile": { "name": { @@ -43,7 +43,9 @@ "beforeText": "..." }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://www.truepeoplesearch.com/find/person/${id}" } } } @@ -60,4 +62,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usa-people-search.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usa-people-search.com.json index b8fba84277..0f276a2b0a 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usa-people-search.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usa-people-search.com.json @@ -1,7 +1,7 @@ { "name": "USA People Search", "url": "usa-people-search.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "peoplefinders.com", "addedDatetime": 1678082400000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "67e80e69-f542-4714-8705-c43af630ac72", + "id": "3cb9a2ce-6443-4934-9df3-ec63a181d9bb", "url": "https://usa-people-search.com/name/${firstName|downcase}-${lastName|downcase}/${city|downcase}-${state|stateFull|downcase}?age=${age}" }, { "actionType": "extract", - "id": "c0a82b15-7564-4e12-8c4e-084174242623", + "id": "44e9b66c-c43c-4112-b51e-f7decd83049e", "selector": ".card-block", "profile": { "name": { @@ -46,7 +46,9 @@ "separator": "," }, "profileUrl": { - "selector": ".link-to-details" + "selector": ".link-to-details", + "identifierType": "path", + "identifier": "https://www.usa-people-search.com/${firstName}-${middleName}-${lastName}/${id}" } } } @@ -63,4 +65,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usatrace.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usatrace.com.json index 4645c85dd0..d0f60daa9f 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usatrace.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usatrace.com.json @@ -1,7 +1,7 @@ { "name": "USA Trace", "url": "usatrace.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "peoplefinders.com", "addedDatetime": 1674540000000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "17217b04-28ae-4262-aa33-ee3695bb6bd6", + "id": "06a2d15f-19ba-45b7-b606-fdd9c9cdb751", "url": "https://www.usatrace.com/people-search/${firstName}-${lastName}/${city}-${state|upcase}" }, { "actionType": "extract", - "id": "426d8e8a-2f32-46f3-9d1d-e7f6e2fddadb", + "id": "3aecf1d1-458a-4252-b27d-0038ce15284d", "selector": "//table/tbody/tr[position() > 1]", "profile": { "name": { @@ -33,7 +33,9 @@ "findElements": true }, "profileUrl": { - "selector": ".//a[@class='btn red-btn']" + "selector": ".//a[@class='btn red-btn']", + "identifierType": "param", + "identifier": "id" } } } @@ -50,4 +52,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usphonebook.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usphonebook.com.json index 5aff073d4a..6a05e4c47f 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usphonebook.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/usphonebook.com.json @@ -1,7 +1,7 @@ { "name": "USPhoneBook", "url": "usphonebook.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "peoplefinders.com", "addedDatetime": 1678082400000, "steps": [ @@ -11,12 +11,12 @@ "actions": [ { "actionType": "navigate", - "id": "6ee93554-95da-4a36-a7f7-c059d8f53ca3", + "id": "98a804b2-115c-4c2c-8e97-3f3679cd3fbb", "url": "https://www.usphonebook.com/${firstName}-${lastName}/${state|stateFull}/${city}" }, { "actionType": "extract", - "id": "fffae12f-4ca1-4a8f-81b9-00adf0487129", + "id": "fd2f1b35-bf37-426f-b39b-f4b280513e53", "selector": ".ls_contacts-people-finder-wrapper", "profile": { "name": { @@ -40,7 +40,9 @@ "separator": "," }, "profileUrl": { - "selector": ".ls_success-extra-margin" + "selector": ".ls_success-extra-margin", + "identifierType": "path", + "identifier": "https://www.usphonebook.com/${firstName}-${lastName}/${id}" } } } @@ -57,4 +59,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/verecor.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/verecor.com.json index 5aff5bd46e..493539fa15 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/verecor.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/verecor.com.json @@ -1,7 +1,7 @@ { "name": "Verecor", "url": "verecor.com", - "version": "0.1.4", + "version": "0.1.5", "addedDatetime": 1677132000000, "steps": [ { @@ -10,7 +10,7 @@ "actions": [ { "actionType": "navigate", - "id": "37fc63a6-e434-4ba0-9e9e-d80898e4dfa4", + "id": "e007a43a-da7b-493c-aaae-53cd58712d31", "url": "https://verecor.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -24,7 +24,7 @@ }, { "actionType": "extract", - "id": "a955924c-7959-48c8-9511-3f843baed729", + "id": "59e6d7e7-6159-4414-85ff-5dc7dbf6ddfc", "selector": ".search-item", "profile": { "name": { @@ -47,7 +47,9 @@ "beforeText": "," }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://verecor.com/view/${id}" } } } @@ -59,12 +61,12 @@ "actions": [ { "actionType": "navigate", - "id": "85cd9682-94d8-46ac-9999-e03dfa9f8d4e", + "id": "725e8cf0-06bf-433a-9945-6d554a64df9e", "url": "https://verecor.com/ng/control/privacy" }, { "actionType": "fillForm", - "id": "ed45c76b-e537-4072-9f46-9515c6e215be", + "id": "5b8d015c-0f73-46c7-8faa-f5350000e312", "selector": ".ahm", "elements": [ { @@ -83,17 +85,17 @@ }, { "actionType": "getCaptchaInfo", - "id": "0e1474f0-24fe-4f6a-8d2e-2dfd91cf574b", + "id": "fc5d8371-2449-4d82-8f33-f85daf92a2ca", "selector": ".g-recaptcha" }, { "actionType": "solveCaptcha", - "id": "52a858f5-7dc5-40aa-aaa7-7090e06ea55e", + "id": "c1d7f88e-ae27-4ffc-a358-5ddb49eb602f", "selector": ".g-recaptcha" }, { "actionType": "click", - "id": "759e0dd2-3a93-42a8-9a83-5e3408f5566b", + "id": "13b946a4-d75e-4b53-ad40-eb77a4b1b53e", "elements": [ { "type": "button", @@ -103,7 +105,7 @@ }, { "actionType": "expectation", - "id": "089924be-5ea3-48a9-a325-8976d262f39b", + "id": "bbc76986-de00-4a1d-b089-0b9d41c0ccf5", "expectations": [ { "type": "text", @@ -114,12 +116,12 @@ }, { "actionType": "emailConfirmation", - "id": "8094718e-412a-418f-b74d-cd4fc5e42c56", + "id": "38a06696-6818-4047-957d-1c23c1e5bf19", "pollingTime": 30 }, { "actionType": "expectation", - "id": "af8fb89b-88d2-4901-b90c-eaac3c7566db", + "id": "13980ac7-ea82-4c76-a07b-d1d64776f23b", "expectations": [ { "type": "text", @@ -136,4 +138,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/vericora.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/vericora.com.json index c7a3bad5c2..604ed4320f 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/vericora.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/vericora.com.json @@ -1,7 +1,7 @@ { "name": "Vericora", "url": "vericora.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1677736800000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "69175f1a-0024-4efd-ab3e-67bcf915a770", + "id": "8e8c6092-f40e-4383-82f6-1498005d342f", "url": "https://vericora.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "bd941009-4462-4d59-ba44-46250f580531", + "id": "e7d234aa-9241-460b-b614-f3dc0cc7840e", "selector": ".search-item", "profile": { "name": { @@ -48,7 +48,9 @@ "beforeText": "," }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://vericora.com/view/${id}" } } } @@ -65,4 +67,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/veriforia.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/veriforia.com.json index 5f4f307f92..50f9cdd31b 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/veriforia.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/veriforia.com.json @@ -1,7 +1,7 @@ { "name": "Veriforia", "url": "veriforia.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1677736800000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "17442975-944c-4b01-8518-7f1dff171ad2", + "id": "7e7f0952-40cf-4cf4-92cb-3d6cc3464219", "url": "https://veriforia.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "32e963e1-4959-4e5e-981b-550f1bf36f9a", + "id": "e5894fdf-3afb-459e-b1a3-a8852d116346", "selector": ".search-item", "profile": { "name": { @@ -48,7 +48,9 @@ "beforeText": "," }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://veriforia.com/view/${id}" } } } @@ -65,4 +67,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/veripages.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/veripages.com.json index 61becad701..07ad1789ec 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/veripages.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/veripages.com.json @@ -1,7 +1,7 @@ { "name": "Veripages", "url": "veripages.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1691989200000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "2346b569-1c46-4ef9-8ea0-fa18bea967fa", + "id": "658fce8a-8bc7-4fb7-9f52-4cdbf2e90054", "url": "https://veripages.com/inner/profile/search?fname=${firstName}&lname=${lastName}&fage=${age|ageRange}&state=${state}&city=${city}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "c4281ca8-d4d0-4091-b6c2-3094801e99c0", + "id": "4bb4d602-8697-4ad0-ab7e-fef2b5b8406c", "selector": ".search-item", "profile": { "name": { @@ -50,7 +50,9 @@ "beforeText": "," }, "profileUrl": { - "selector": ".//div[@class='search-item-title']//a" + "selector": ".//div[@class='search-item-title']//a", + "identifierType": "path", + "identifier": "https://veripages.com/profile/${firstName}-${lastName}/${id}" } } } @@ -67,4 +69,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/virtory.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/virtory.com.json index 3d94019338..c5e7e3f41a 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/virtory.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/virtory.com.json @@ -1,7 +1,7 @@ { "name": "Virtory", "url": "virtory.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1703052000000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "0568e4f5-73c2-4b1a-9eb6-ac3571b1a01e", + "id": "dcd02b38-c2a2-462b-979c-5af85260ff64", "url": "https://virtory.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "df2216f3-0890-4d13-b2aa-233084167720", + "id": "3ab2b9a0-647d-4ad2-9709-ef934c977a48", "selector": ".card", "profile": { "name": { @@ -51,7 +51,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://virtory.com/prof/${id}" } } } @@ -68,4 +70,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/wellnut.com.json b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/wellnut.com.json index 12c43b7fa4..7682b90f8b 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/wellnut.com.json +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON/wellnut.com.json @@ -1,7 +1,7 @@ { "name": "Wellnut", "url": "wellnut.com", - "version": "0.1.4", + "version": "0.1.5", "parent": "verecor.com", "addedDatetime": 1703052000000, "steps": [ @@ -11,7 +11,7 @@ "actions": [ { "actionType": "navigate", - "id": "a38752f3-ae69-45c3-ba3f-3a73e549e644", + "id": "673ccaec-2c34-42b9-806c-c453c02d8b94", "url": "https://wellnut.com/profile/search?fname=${firstName}&lname=${lastName}&state=${state}&city=${city}&fage=${age|ageRange}", "ageRange": [ "18-30", @@ -25,7 +25,7 @@ }, { "actionType": "extract", - "id": "b7747e92-5fe5-46f7-b083-5df6fbdc2b84", + "id": "2846bcb5-84c4-4f20-8ff8-6118849b9828", "selector": ".card", "profile": { "name": { @@ -51,7 +51,9 @@ "findElements": true }, "profileUrl": { - "selector": "a" + "selector": "a", + "identifierType": "path", + "identifier": "https://wellnut.com/person/${id}" } } } @@ -68,4 +70,4 @@ "confirmOptOutScan": 72, "maintenanceScan": 240 } -} \ No newline at end of file +} diff --git a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/ActionsHandlerTests.swift b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/ActionsHandlerTests.swift index 14ea842ed1..424d45bb73 100644 --- a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/ActionsHandlerTests.swift +++ b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/ActionsHandlerTests.swift @@ -29,8 +29,8 @@ final class ActionsHandlerTests: XCTestCase { } func testWhenNextStepDoesNotFindAnyMoreActions_thenNilIsReturned() { - let firstAction = NavigateAction(id: "navigate1", actionType: .navigate, url: "url", ageRange: [String]()) - let secondAction = NavigateAction(id: "navigate2", actionType: .navigate, url: "url", ageRange: [String]()) + let firstAction = NavigateAction(id: "navigate1", actionType: .navigate, url: "url", ageRange: [String](), dataSource: nil) + let secondAction = NavigateAction(id: "navigate2", actionType: .navigate, url: "url", ageRange: [String](), dataSource: nil) let step = Step(type: .scan, actions: [firstAction, secondAction]) let sut = ActionsHandler(step: step) @@ -41,8 +41,8 @@ final class ActionsHandlerTests: XCTestCase { } func testWhenNextStepFindsAnAction_thenThatNextActionIsReturned() { - let firstAction = NavigateAction(id: "navigate1", actionType: .navigate, url: "url", ageRange: [String]()) - let secondAction = NavigateAction(id: "navigate2", actionType: .navigate, url: "url", ageRange: [String]()) + let firstAction = NavigateAction(id: "navigate1", actionType: .navigate, url: "url", ageRange: [String](), dataSource: nil) + let secondAction = NavigateAction(id: "navigate2", actionType: .navigate, url: "url", ageRange: [String](), dataSource: nil) let step = Step(type: .scan, actions: [firstAction, secondAction]) let sut = ActionsHandler(step: step) diff --git a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerOperationActionTests.swift b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerOperationActionTests.swift index 54e6abbad0..850187b136 100644 --- a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerOperationActionTests.swift +++ b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerOperationActionTests.swift @@ -35,7 +35,7 @@ final class DataBrokerOperationActionTests: XCTestCase { } func testWhenEmailConfirmationActionSucceeds_thenExtractedLinkIsOpened() async { - let emailConfirmationAction = EmailConfirmationAction(id: "", actionType: .emailConfirmation, pollingTime: 1) + let emailConfirmationAction = EmailConfirmationAction(id: "", actionType: .emailConfirmation, pollingTime: 1, dataSource: nil) let step = Step(type: .optOut, actions: [emailConfirmationAction]) let extractedProfile = ExtractedProfile(email: "test@duck.com") let sut = OptOutOperation( @@ -57,7 +57,7 @@ final class DataBrokerOperationActionTests: XCTestCase { } func testWhenEmailConfirmationActionHasNoEmail_thenNoURLIsLoadedAndWebViewFinishes() async { - let emailConfirmationAction = EmailConfirmationAction(id: "", actionType: .emailConfirmation, pollingTime: 1) + let emailConfirmationAction = EmailConfirmationAction(id: "", actionType: .emailConfirmation, pollingTime: 1, dataSource: nil) let step = Step(type: .optOut, actions: [emailConfirmationAction]) let noEmailExtractedProfile = ExtractedProfile() let sut = OptOutOperation( @@ -85,7 +85,7 @@ final class DataBrokerOperationActionTests: XCTestCase { } func testWhenOnEmailConfirmationActionEmailServiceThrows_thenOperationThrows() async { - let emailConfirmationAction = EmailConfirmationAction(id: "", actionType: .emailConfirmation, pollingTime: 1) + let emailConfirmationAction = EmailConfirmationAction(id: "", actionType: .emailConfirmation, pollingTime: 1, dataSource: nil) let step = Step(type: .optOut, actions: [emailConfirmationAction]) let extractedProfile = ExtractedProfile(email: "test@duck.com") emailService.shouldThrow = true @@ -114,7 +114,7 @@ final class DataBrokerOperationActionTests: XCTestCase { } func testWhenActionNeedsEmail_thenExtractedProfileEmailIsSet() async { - let fillFormAction = FillFormAction(id: "1", actionType: .fillForm, selector: "#test", elements: [.init(type: "email", selector: "#email", parent: nil)]) + let fillFormAction = FillFormAction(id: "1", actionType: .fillForm, selector: "#test", elements: [.init(type: "email", selector: "#email", parent: nil)], dataSource: nil) let step = Step(type: .optOut, actions: [fillFormAction]) let sut = OptOutOperation( privacyConfig: PrivacyConfigurationManagingMock(), @@ -130,11 +130,11 @@ final class DataBrokerOperationActionTests: XCTestCase { await sut.runNextAction(fillFormAction) XCTAssertEqual(sut.extractedProfile?.email, "test@duck.com") - XCTAssertTrue(webViewHandler.wasExecuteCalledForExtractedProfile) + XCTAssertTrue(webViewHandler.wasExecuteCalledForUserData) } func testWhenGetEmailServiceFails_thenOperationThrows() async { - let fillFormAction = FillFormAction(id: "1", actionType: .fillForm, selector: "#test", elements: [.init(type: "email", selector: "#email", parent: nil)]) + let fillFormAction = FillFormAction(id: "1", actionType: .fillForm, selector: "#test", elements: [.init(type: "email", selector: "#email", parent: nil)], dataSource: nil) let step = Step(type: .optOut, actions: [fillFormAction]) let sut = OptOutOperation( privacyConfig: PrivacyConfigurationManagingMock(), @@ -195,7 +195,7 @@ final class DataBrokerOperationActionTests: XCTestCase { } func testWhenSolveCaptchaActionIsRun_thenCaptchaIsResolved() async { - let solveCaptchaAction = SolveCaptchaAction(id: "1", actionType: .solveCaptcha, selector: "g-captcha") + let solveCaptchaAction = SolveCaptchaAction(id: "1", actionType: .solveCaptcha, selector: "g-captcha", dataSource: nil) let step = Step(type: .optOut, actions: [solveCaptchaAction]) let sut = OptOutOperation( privacyConfig: PrivacyConfigurationManagingMock(), @@ -215,7 +215,7 @@ final class DataBrokerOperationActionTests: XCTestCase { } func testWhenSolveCapchaActionFailsToSubmitDataToTheBackend_thenOperationFails() async { - let solveCaptchaAction = SolveCaptchaAction(id: "1", actionType: .solveCaptcha, selector: "g-captcha") + let solveCaptchaAction = SolveCaptchaAction(id: "1", actionType: .solveCaptcha, selector: "g-captcha", dataSource: nil) let step = Step(type: .optOut, actions: [solveCaptchaAction]) let sut = OptOutOperation( privacyConfig: PrivacyConfigurationManagingMock(), @@ -284,7 +284,7 @@ final class DataBrokerOperationActionTests: XCTestCase { } func testWhenRunningActionWithoutExtractedProfile_thenExecuteIsCalledWithProfileData() async { - let expectationAction = ExpectationAction(id: "1", actionType: .expectation, expectations: [Item]()) + let expectationAction = ExpectationAction(id: "1", actionType: .expectation, expectations: [Item](), dataSource: nil) let sut = OptOutOperation( privacyConfig: PrivacyConfigurationManagingMock(), prefs: ContentScopeProperties.mock, @@ -297,7 +297,7 @@ final class DataBrokerOperationActionTests: XCTestCase { await sut.runNextAction(expectationAction) - XCTAssertTrue(webViewHandler.wasExecuteCalledForProfileData) + XCTAssertTrue(webViewHandler.wasExecuteCalledForUserData) } func testWhenLoadURLDelegateIsCalled_thenCorrectMethodIsExecutedOnWebViewHandler() async { diff --git a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift index 2322840918..06839d4278 100644 --- a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift +++ b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift @@ -176,8 +176,7 @@ final class WebViewHandlerMock: NSObject, WebViewHandler { var wasLoadCalledWithURL: URL? var wasWaitForWebViewLoadCalled = false var wasFinishCalled = false - var wasExecuteCalledForExtractedProfile = false - var wasExecuteCalledForProfileData = false + var wasExecuteCalledForUserData = false var wasExecuteCalledForSolveCaptcha = false var wasExecuteJavascriptCalled = false @@ -199,18 +198,12 @@ final class WebViewHandlerMock: NSObject, WebViewHandler { func execute(action: DataBrokerProtection.Action, data: DataBrokerProtection.CCFRequestData) async { switch data { - case .profile: - wasExecuteCalledForExtractedProfile = false - wasExecuteCalledForSolveCaptcha = false - wasExecuteCalledForProfileData = true case .solveCaptcha: - wasExecuteCalledForExtractedProfile = false wasExecuteCalledForSolveCaptcha = true - wasExecuteCalledForProfileData = false - case.extractedProfile: - wasExecuteCalledForExtractedProfile = true + wasExecuteCalledForUserData = false + case .userData: + wasExecuteCalledForUserData = true wasExecuteCalledForSolveCaptcha = false - wasExecuteCalledForProfileData = false } } @@ -223,10 +216,9 @@ final class WebViewHandlerMock: NSObject, WebViewHandler { wasLoadCalledWithURL = nil wasWaitForWebViewLoadCalled = false wasFinishCalled = false - wasExecuteCalledForExtractedProfile = false wasExecuteCalledForSolveCaptcha = false - wasExecuteCalledForProfileData = false wasExecuteJavascriptCalled = false + wasExecuteCalledForUserData = false } } diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index 29195f8319..e8489be491 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "112.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "113.0.0"), ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index aa48a503a8..0e494741c2 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "112.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "113.0.0"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index e1efbbca4c..f93f27be34 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: "112.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "113.0.0"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index eded9daaa8..30421c20c1 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../SwiftUIExtensions"), .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "112.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "113.0.0"), ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index 18186f58d5..ac6b0aa0ba 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -17,7 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "112.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "113.0.0"), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite.