From 4fb7ae2b263ed8c94bbf0392f352e116d74edfc4 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Wed, 27 Dec 2023 12:23:49 -0800 Subject: [PATCH 01/11] Add timeouts to the alpha job. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The alpha job has been running for 360 minutes for the last few nights, so I’m pushing this directly to stop the bleeding while debugging the problem. --- .github/workflows/alpha.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 03c50c90d6..bb7668cf09 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -33,6 +33,7 @@ jobs: make-alpha: runs-on: macos-13 name: Make TestFlight Alpha Build + timeout-minutes: 30 env: destination: ${{ github.event.inputs.destination || inputs.destination }} From f66f0e403ab81637d6b76f4ab344cbc777f7541a Mon Sep 17 00:00:00 2001 From: amddg44 Date: Thu, 28 Dec 2023 12:06:32 +0100 Subject: [PATCH 02/11] BSK update for autofill never prompt to save for site feature (#2280) Task/Issue URL: https://app.asana.com/0/1201645688934642/1205190244970075/f Tech Design URL: CC: Description: BSK update for macOS support of never prompt to save for site feature --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- LocalPackages/DuckUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/Waitlist/Package.swift | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index cc8ed2989f..b06c9d1ea3 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9225,7 +9225,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 100.0.0; + version = 100.0.1; }; }; C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7d4b98599e..7abce468cd 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" : "c3a482a4ca22d706207d08a68db8f23f0c262040", - "version" : "100.0.0" + "revision" : "e9c344c15d550112d02853c07efeaa154e911e2b", + "version" : "100.0.1" } }, { diff --git a/LocalPackages/DuckUI/Package.swift b/LocalPackages/DuckUI/Package.swift index 8d9beaaa5d..349e53d7a9 100644 --- a/LocalPackages/DuckUI/Package.swift +++ b/LocalPackages/DuckUI/Package.swift @@ -31,7 +31,7 @@ let package = Package( targets: ["DuckUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.1"), ], targets: [ .target( diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 0339783ecd..205ddbc3f9 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -32,7 +32,7 @@ let package = Package( ], dependencies: [ .package(path: "../DuckUI"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.1"), .package(url: "https://github.com/duckduckgo/DesignResourcesKit", exact: "2.0.0") ], targets: [ diff --git a/LocalPackages/Waitlist/Package.swift b/LocalPackages/Waitlist/Package.swift index 6bc1eddd5d..1ba3524983 100644 --- a/LocalPackages/Waitlist/Package.swift +++ b/LocalPackages/Waitlist/Package.swift @@ -15,7 +15,7 @@ let package = Package( targets: ["Waitlist", "WaitlistMocks"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.1"), .package(url: "https://github.com/duckduckgo/DesignResourcesKit", exact: "2.0.0") ], targets: [ From 8f6ecd15adca8cc12992f17edb66c4b1deb86d9b Mon Sep 17 00:00:00 2001 From: Sabrina Tardio <44158575+SabrinaTardio@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:20:00 +0100 Subject: [PATCH 03/11] Update errors (#2283) Task/Issue URL: https://app.asana.com/0/0/1206203697668219/f Description: Update error messages copy and introduce a couple more detailed errors. --- ...cSettingsViewController+SyncDelegate.swift | 30 +++++++----- DuckDuckGo/SyncSettingsViewController.swift | 46 +++++++++++-------- DuckDuckGo/UserText.swift | 14 +++--- DuckDuckGo/en.lproj/Localizable.strings | 22 +++++---- 4 files changed, 69 insertions(+), 43 deletions(-) diff --git a/DuckDuckGo/SyncSettingsViewController+SyncDelegate.swift b/DuckDuckGo/SyncSettingsViewController+SyncDelegate.swift index d525348690..fca50e7b02 100644 --- a/DuckDuckGo/SyncSettingsViewController+SyncDelegate.swift +++ b/DuckDuckGo/SyncSettingsViewController+SyncDelegate.swift @@ -61,23 +61,25 @@ extension SyncSettingsViewController: SyncManagementViewModelDelegate { self.refreshDevices() navigationController?.topViewController?.dismiss(animated: true, completion: showRecoveryPDF) } catch { - handleError(SyncError.unableToSync, error: error) + handleError(SyncError.unableToSyncToServer, error: error) } } } @MainActor - func handleError(_ type: SyncError, error: Error) { + func handleError(_ type: SyncError, error: Error?) { let alertController = UIAlertController( title: type.title, - message: type.description + "\n" + error.localizedDescription, + message: [type.description, error?.localizedDescription].compactMap({ $0 }).joined(separator: "\n"), preferredStyle: .alert) let okAction = UIAlertAction(title: UserText.syncPausedAlertOkButton, style: .default, handler: nil) alertController.addAction(okAction) - if type == .unableToSync { - // Give time to the is syncing view to appear + if type == .unableToSyncToServer || + type == .unableToSyncWithDevice || + type == .unableToMergeTwoAccounts { + // Gives time to the is syncing view to appear DispatchQueue.main.asyncAfter(deadline: .now() + 1) { self.dismissPresentedViewController { [weak self] in self?.present(alertController, animated: true, completion: nil) @@ -283,12 +285,14 @@ private class PortraitNavigationController: UINavigationController { } enum SyncError { - case unableToSync - case unableToGetDevices + case unableToSyncToServer + case unableToSyncWithDevice + case unableToMergeTwoAccounts case unableToUpdateDeviceName case unableToTurnSyncOff case unableToDeleteData case unableToRemoveDevice + case unableToCreateRecoveryPdf var title: String { return UserText.syncErrorAlertTitle @@ -296,10 +300,12 @@ enum SyncError { var description: String { switch self { - case .unableToSync: - return UserText.unableToSyncDescription - case .unableToGetDevices: - return UserText.unableToGetDevicesDescription + case .unableToSyncToServer: + return UserText.unableToSyncToServerDescription + case .unableToSyncWithDevice: + return UserText.unableToSyncWithOtherDeviceDescription + case .unableToMergeTwoAccounts: + return UserText.unableToMergeTwoAccountsErrorDescription case .unableToUpdateDeviceName: return UserText.unableToUpdateDeviceNameDescription case .unableToTurnSyncOff: @@ -308,6 +314,8 @@ enum SyncError { return UserText.unableToDeleteDataDescription case .unableToRemoveDevice: return UserText.unableToRemoveDeviceDescription + case .unableToCreateRecoveryPdf: + return UserText.unableToCreateRecoveryPDF } } } diff --git a/DuckDuckGo/SyncSettingsViewController.swift b/DuckDuckGo/SyncSettingsViewController.swift index 4a72c25aba..86cb9f8b95 100644 --- a/DuckDuckGo/SyncSettingsViewController.swift +++ b/DuckDuckGo/SyncSettingsViewController.swift @@ -248,7 +248,7 @@ extension SyncSettingsViewController: ScanOrPasteCodeViewModelDelegate { self.startPolling() return self.connector?.code } catch { - self.handleError(SyncError.unableToSync, error: error) + self.handleError(SyncError.unableToSyncToServer, error: error) return nil } } @@ -274,34 +274,45 @@ extension SyncSettingsViewController: ScanOrPasteCodeViewModelDelegate { return } } catch { - handleError(SyncError.unableToSync, error: error) + handleError(SyncError.unableToSyncWithDevice, error: error) } } } func syncCodeEntered(code: String) async -> Bool { var shouldShowSyncEnabled = true - do { - guard let syncCode = try? SyncCode.decodeBase64String(code) else { - return false - } - if let recoveryKey = syncCode.recovery { - dismissPresentedViewController() - showPreparingSync() + guard let syncCode = try? SyncCode.decodeBase64String(code) else { + return false + } + if let recoveryKey = syncCode.recovery { + dismissPresentedViewController() + showPreparingSync() + do { try await loginAndShowDeviceConnected(recoveryKey: recoveryKey) return true - } else if let connectKey = syncCode.connect { - dismissPresentedViewController() - showPreparingSync() - if syncService.account == nil { + } catch { + if self.rootView.model.isSyncEnabled { + handleError(.unableToMergeTwoAccounts, error: nil) + } else { + handleError(.unableToSyncToServer, error: error) + } + } + } else if let connectKey = syncCode.connect { + dismissPresentedViewController() + showPreparingSync() + if syncService.account == nil { + do { try await syncService.createAccount(deviceName: deviceName, deviceType: deviceType) Pixel.fire(pixel: .syncSignupConnect, includedParameters: [.appVersion]) self.dismissVCAndShowRecoveryPDF() shouldShowSyncEnabled = false rootView.model.syncEnabled(recoveryCode: recoveryCode) + } catch { + handleError(.unableToSyncToServer, error: error) } + } + do { try await syncService.transmitRecoveryKey(connectKey) - self.rootView.model.$devices .removeDuplicates() .dropFirst() @@ -312,12 +323,11 @@ extension SyncSettingsViewController: ScanOrPasteCodeViewModelDelegate { self.dismissVCAndShowRecoveryPDF() } }.store(in: &cancellables) - - return true + } catch { + handleError(.unableToSyncWithDevice, error: error) } - } catch { - handleError(SyncError.unableToSync, error: error) + return true } return false } diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 88f5f98999..78896b9e00 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -860,13 +860,15 @@ But if you *do* want a peek under the hood, you can find more information about static let syncCredentialsPausedAlertDescription = NSLocalizedString("alert.sync-credentials-paused-description", value: "You have exceeded the passwords sync limit. Try deleting some passwords. Until this is resolved your passwords will not be backed up.", comment: "Description for alert shown when sync credentials paused for too many items") public static let syncPausedAlertOkButton = NSLocalizedString("alert.sync-paused-alert-ok-button", value: "OK", comment: "Confirmation button in alert") public static let syncPausedAlertLearnMoreButton = NSLocalizedString("alert.sync-paused-alert-learn-more-button", value: "Learn More", comment: "Learn more button in alert") - public static let syncErrorAlertTitle = NSLocalizedString("alert.sync-error", value: "Sync Error", comment: "Title for sync error alert") - public static let unableToSyncDescription = NSLocalizedString("alert.unable-to-sync-description", value: "Unable to sync.", comment: "Description for unable to sync error") - public static let unableToGetDevicesDescription = NSLocalizedString("alert.unable-to-get-devices-description", value: "Unable to retrieve the list of connected devices.", comment: "Description for unable to get devices error") - public static let unableToUpdateDeviceNameDescription = NSLocalizedString("alert.unable-to-update-device-name-description", value: "Unable to update the name of the device.", comment: "Description for unable to update device name error") - public static let unableToTurnSyncOffDescription = NSLocalizedString("alert.unable-to-turn-sync-off-description", value: "Unable to turn sync off.", comment: "Description for unable to turn sync off error") + public static let syncErrorAlertTitle = NSLocalizedString("alert.sync-error", value: "Sync & Backup Error", comment: "Title for sync error alert") + public static let unableToSyncToServerDescription = NSLocalizedString("alert.unable-to-sync-to-server-description", value: "Unable to connect to the server.", comment: "Description for unable to sync to server error") + public static let unableToSyncWithOtherDeviceDescription = NSLocalizedString("alert.unable-to-sync-with-other-device-description", value: "Unable to Sync with another device.", comment: "Description for unable to sync with another device error") + public static let unableToMergeTwoAccountsErrorDescription = NSLocalizedString("alert.unable-to-merge-two-accounts-description", value: "To pair these devices, turn off Sync & Backup on one device then tap \"Sync with Another Device\" on the other device.", comment: "Description for unable to merge two accounts error") + public static let unableToUpdateDeviceNameDescription = NSLocalizedString("alert.unable-to-update-device-name-description", value: "Unable to update the device name.", comment: "Description for unable to update device name error") + public static let unableToTurnSyncOffDescription = NSLocalizedString("alert.unable-to-turn-sync-off-description", value: "Unable to turn Sync & Backup off.", comment: "Description for unable to turn sync off error") public static let unableToDeleteDataDescription = NSLocalizedString("alert.unable-to-delete-data-description", value: "Unable to delete data on the server.", comment: "Description for unable to delete data error") - public static let unableToRemoveDeviceDescription = NSLocalizedString("alert.unable-to-remove-device-description", value: "Unable to remove the specified device from the synchronized devices.", comment: "Description for unable to remove device error") + public static let unableToRemoveDeviceDescription = NSLocalizedString("alert.unable-to-remove-device-description", value: "Unable to remove this device from Sync & Backup.", comment: "Description for unable to remove device error") + public static let unableToCreateRecoveryPDF = NSLocalizedString("alert.unable-to-create-recovery-pdf-description", value: "Unable to create the recovery PDF. ", comment: "Description for unable to create recovery pdf error") static let syncPausedTitle = NSLocalizedString("sync.warning.sync.paused", value: "Sync & Backup is Paused", comment: "Title of the warning message") static let syncUnavailableMessage = NSLocalizedString("sync.warning.data.syncing.disabled", value: "Sorry, but Sync & Backup is currently unavailable. Please try again later.", comment: "Data syncing unavailable warning message") static let syncUnavailableMessageUpgradeRequired = NSLocalizedString("sync.warning.data.syncing.disabled.upgrade.required", value: "Sorry, but Sync & Backup is no longer available in this app version. Please update DuckDuckGo to the latest version to continue.", comment: "Data syncing unavailable warning message") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 692c00ba01..dbbc366d23 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -140,7 +140,7 @@ "alert.sync-credentials-paused-title" = "Passwords Sync is Paused"; /* Title for sync error alert */ -"alert.sync-error" = "Sync Error"; +"alert.sync-error" = "Sync & Backup Error"; /* Learn more button in alert */ "alert.sync-paused-alert-learn-more-button" = "Learn More"; @@ -163,23 +163,29 @@ /* Save Favorite action */ "alert.title.save.favorite" = "Save Favorite"; +/* Description for unable to create recovery pdf error */ +"alert.unable-to-create-recovery-pdf-description" = "Unable to create the recovery PDF. "; + /* Description for unable to delete data error */ "alert.unable-to-delete-data-description" = "Unable to delete data on the server."; -/* Description for unable to get devices error */ -"alert.unable-to-get-devices-description" = "Unable to retrieve the list of connected devices."; +/* Description for unable to merge two accounts error */ +"alert.unable-to-merge-two-accounts-description" = "To pair these devices, turn off Sync & Backup on one device then tap \"Sync with Another Device\" on the other device."; /* Description for unable to remove device error */ -"alert.unable-to-remove-device-description" = "Unable to remove the specified device from the synchronized devices."; +"alert.unable-to-remove-device-description" = "Unable to remove this device from Sync & Backup."; + +/* Description for unable to sync to server error */ +"alert.unable-to-sync-to-server-description" = "Unable to connect to the server."; -/* Description for unable to sync error */ -"alert.unable-to-sync-description" = "Unable to sync."; +/* Description for unable to sync with another device error */ +"alert.unable-to-sync-with-other-device-description" = "Unable to Sync with another device."; /* Description for unable to turn sync off error */ -"alert.unable-to-turn-sync-off-description" = "Unable to turn sync off."; +"alert.unable-to-turn-sync-off-description" = "Unable to turn Sync & Backup off."; /* Description for unable to update device name error */ -"alert.unable-to-update-device-name-description" = "Unable to update the name of the device."; +"alert.unable-to-update-device-name-description" = "Unable to update the device name."; /* Shown on authentication screen */ "app.authentication.unlock" = "Unlock DuckDuckGo."; From 25ceec522cbe1a9688f90034be9e0633c7f17e22 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Tue, 2 Jan 2024 16:50:27 +0100 Subject: [PATCH 04/11] Remove trailing space in unableToCreateRecoveryPDF error (#2297) Task/Issue URL: https://app.asana.com/0/0/1206203697668219/f --- DuckDuckGo/UserText.swift | 2 +- DuckDuckGo/en.lproj/Localizable.strings | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 78896b9e00..579eb3b1e6 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -868,7 +868,7 @@ But if you *do* want a peek under the hood, you can find more information about public static let unableToTurnSyncOffDescription = NSLocalizedString("alert.unable-to-turn-sync-off-description", value: "Unable to turn Sync & Backup off.", comment: "Description for unable to turn sync off error") public static let unableToDeleteDataDescription = NSLocalizedString("alert.unable-to-delete-data-description", value: "Unable to delete data on the server.", comment: "Description for unable to delete data error") public static let unableToRemoveDeviceDescription = NSLocalizedString("alert.unable-to-remove-device-description", value: "Unable to remove this device from Sync & Backup.", comment: "Description for unable to remove device error") - public static let unableToCreateRecoveryPDF = NSLocalizedString("alert.unable-to-create-recovery-pdf-description", value: "Unable to create the recovery PDF. ", comment: "Description for unable to create recovery pdf error") + public static let unableToCreateRecoveryPDF = NSLocalizedString("alert.unable-to-create-recovery-pdf-description", value: "Unable to create the recovery PDF.", comment: "Description for unable to create recovery pdf error") static let syncPausedTitle = NSLocalizedString("sync.warning.sync.paused", value: "Sync & Backup is Paused", comment: "Title of the warning message") static let syncUnavailableMessage = NSLocalizedString("sync.warning.data.syncing.disabled", value: "Sorry, but Sync & Backup is currently unavailable. Please try again later.", comment: "Data syncing unavailable warning message") static let syncUnavailableMessageUpgradeRequired = NSLocalizedString("sync.warning.data.syncing.disabled.upgrade.required", value: "Sorry, but Sync & Backup is no longer available in this app version. Please update DuckDuckGo to the latest version to continue.", comment: "Data syncing unavailable warning message") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index dbbc366d23..7904d15ae1 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -164,7 +164,7 @@ "alert.title.save.favorite" = "Save Favorite"; /* Description for unable to create recovery pdf error */ -"alert.unable-to-create-recovery-pdf-description" = "Unable to create the recovery PDF. "; +"alert.unable-to-create-recovery-pdf-description" = "Unable to create the recovery PDF."; /* Description for unable to delete data error */ "alert.unable-to-delete-data-description" = "Unable to delete data on the server."; From 1c418db907f129ecce6b1c5fb8db449f0f45b1e4 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Wed, 3 Jan 2024 15:51:32 +0100 Subject: [PATCH 05/11] Allow calculations in the address bar (#2298) Task/Issue URL: https://app.asana.com/0/0/1206262563462715/f Description: Treat strings like "1.4" in address bar as search queries, not as IPs (1.0.0.4). --- .swiftlint.yml | 1 + Core/URLExtension.swift | 18 +++++++++++++---- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- DuckDuckGoTests/AppURLsTests.swift | 20 ++++++++++++++++++- LocalPackages/DuckUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/Waitlist/Package.swift | 2 +- 8 files changed, 40 insertions(+), 11 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index ae3959c57f..5808536458 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -95,3 +95,4 @@ excluded: - vendor - LocalPackages/*/Package.swift - PacketTunnelProvider/ProxyServer + - .ruby-lsp diff --git a/Core/URLExtension.swift b/Core/URLExtension.swift index 75c2cf99fe..1d65b8c0b5 100644 --- a/Core/URLExtension.swift +++ b/Core/URLExtension.swift @@ -20,6 +20,7 @@ import Foundation import JavaScriptCore import BrowserServicesKit +import Network extension URL { @@ -48,10 +49,19 @@ extension URL { break case .none: // assume http by default - guard let urlWithScheme = URL(string: URLProtocol.http.scheme + text), - // only allow 2nd+ level domains or "localhost" without scheme - urlWithScheme.host?.contains(".") == true || urlWithScheme.host == .localhost - else { return nil } + guard let urlWithScheme = URL(string: URLProtocol.http.scheme + text), let host = urlWithScheme.host else { + return nil + } + // only allow 2nd+ level domains or "localhost" without scheme + guard host.contains(".") == true || host == .localhost else { + return nil + } + if IPv4Address(host) != nil { + // Require 4 octets specified explicitly for an IPv4 address (avoid 1.4 -> 1.0.0.4 expansion) + guard host.split(separator: ".").count == 4 else { + return nil + } + } url = urlWithScheme default: diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index b06c9d1ea3..25b8245add 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9225,7 +9225,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 100.0.1; + version = 100.0.2; }; }; C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7abce468cd..963d9334c6 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" : "e9c344c15d550112d02853c07efeaa154e911e2b", - "version" : "100.0.1" + "revision" : "39a5daf268f9fcb57d95e6193eca20f7ea222de6", + "version" : "100.0.2" } }, { diff --git a/DuckDuckGoTests/AppURLsTests.swift b/DuckDuckGoTests/AppURLsTests.swift index 0d2adfdbe1..280e855dcc 100644 --- a/DuckDuckGoTests/AppURLsTests.swift +++ b/DuckDuckGoTests/AppURLsTests.swift @@ -204,6 +204,24 @@ final class AppURLsTests: XCTestCase { XCTAssertEqual(url.getParameter(named: "q"), "query") } + func testSearchUrlCreatesSearchUrlWhenFloatingPointNumberIsPassed() { + let url = URL.makeSearchURL(query: "1.4") + XCTAssertEqual(url?.getParameter(named: "q"), "1.4") + } + + func testSearchUrlCreatesSearchUrlWhenFloatingPointNumbersDivisionIsPassed() { + let url = URL.makeSearchURL(query: "1.4/3.4") + XCTAssertEqual(url?.getParameter(named: "q"), "1.4/3.4") + + let url2 = URL.makeSearchURL(query: "4/3.4") + XCTAssertEqual(url2?.getParameter(named: "q"), "4/3.4") + } + + func testSearchUrlCreatesWebUrlWhenIPv4WithFourOctetsIsPassed() { + let url = URL.makeSearchURL(query: "1.0.0.4/3.4") + XCTAssertEqual(url?.absoluteString, "http://1.0.0.4/3.4") + } + func testExtiUrlCreatesUrlWithAtbParam() throws { let url = URL.makeExtiURL(atb: "x") XCTAssertEqual(url.getParameter(named: "atb"), "x") @@ -272,7 +290,7 @@ final class AppURLsTests: XCTestCase { let result = url.searchQuery XCTAssertNil(result) } - + func testExternalDependencyURLsNotChanged() { XCTAssertEqual(URL.surrogates.absoluteString, "https://staticcdn.duckduckgo.com/surrogates.txt") XCTAssertEqual(URL.privacyConfig.absoluteString, "https://staticcdn.duckduckgo.com/trackerblocking/config/v4/ios-config.json") diff --git a/LocalPackages/DuckUI/Package.swift b/LocalPackages/DuckUI/Package.swift index 349e53d7a9..80e0a08d0f 100644 --- a/LocalPackages/DuckUI/Package.swift +++ b/LocalPackages/DuckUI/Package.swift @@ -31,7 +31,7 @@ let package = Package( targets: ["DuckUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.2"), ], targets: [ .target( diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 205ddbc3f9..09fdb7dc37 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -32,7 +32,7 @@ let package = Package( ], dependencies: [ .package(path: "../DuckUI"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.2"), .package(url: "https://github.com/duckduckgo/DesignResourcesKit", exact: "2.0.0") ], targets: [ diff --git a/LocalPackages/Waitlist/Package.swift b/LocalPackages/Waitlist/Package.swift index 1ba3524983..a666f90ef7 100644 --- a/LocalPackages/Waitlist/Package.swift +++ b/LocalPackages/Waitlist/Package.swift @@ -15,7 +15,7 @@ let package = Package( targets: ["Waitlist", "WaitlistMocks"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.2"), .package(url: "https://github.com/duckduckgo/DesignResourcesKit", exact: "2.0.0") ], targets: [ From 9f8e8e0d3ad4c17719499e1bd9c3ea122c6f9e11 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Thu, 4 Jan 2024 10:33:42 +0100 Subject: [PATCH 06/11] Update Sync End-to-End tests (#2300) Task/Issue URL: https://app.asana.com/0/414709148257752/1206261930885982/f Description: Just a label update following recent copy changes. --- .github/workflows/sync-end-to-end.yml | 2 +- .maestro/sync_tests/05_delete_account.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sync-end-to-end.yml b/.github/workflows/sync-end-to-end.yml index 5f1527de3e..025aaae511 100644 --- a/.github/workflows/sync-end-to-end.yml +++ b/.github/workflows/sync-end-to-end.yml @@ -66,7 +66,7 @@ jobs: name: Sync End To End Tests needs: build-for-sync-end-to-end-tests runs-on: macos-13 - timeout-minutes: 30 + timeout-minutes: 60 strategy: matrix: os-version: [15, 16, 17] diff --git a/.maestro/sync_tests/05_delete_account.yaml b/.maestro/sync_tests/05_delete_account.yaml index 76947f05fd..1a40d0916a 100644 --- a/.maestro/sync_tests/05_delete_account.yaml +++ b/.maestro/sync_tests/05_delete_account.yaml @@ -35,5 +35,5 @@ tags: - assertVisible: Scan QR Code - tapOn: Manually Enter Code - tapOn: Paste -- assertVisible: Sync Error +- assertVisible: Sync & Backup Error - tapOn: OK From 368ed2496b8fe8b342b8c6a6c12d71fd3d4ff283 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 10:16:02 +0000 Subject: [PATCH 07/11] Bump submodules/privacy-reference-tests from `a3acc21` to `6b7ad1e` (#2285) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- submodules/privacy-reference-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/privacy-reference-tests b/submodules/privacy-reference-tests index a3acc21947..6b7ad1e7f1 160000 --- a/submodules/privacy-reference-tests +++ b/submodules/privacy-reference-tests @@ -1 +1 @@ -Subproject commit a3acc2194758bec0f01f57dd0c5f106de01a354e +Subproject commit 6b7ad1e7f15270f9dfeb58a272199f4d57c3eb22 From 8527e680671faefecb3568b419029996c3c1d853 Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Fri, 5 Jan 2024 10:17:54 +0000 Subject: [PATCH 08/11] remove unused pixels (#2303) --- Core/PixelEvent.swift | 111 +----------------------------------------- 1 file changed, 2 insertions(+), 109 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 8d1ac89d99..9b9858f636 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -44,7 +44,6 @@ extension Pixel { case dashboardProtectionAllowlistRemove case privacyDashboardReportBrokenSite - case privacyDashboardPixelFromJS(rawPixel: String) case tabSwitcherNewLayoutSeen case tabSwitcherListEnabled @@ -59,7 +58,6 @@ extension Pixel { case settingsAutoconsentOff case browsingMenuOpened - case browsingMenuRefresh case browsingMenuNewTab case browsingMenuAddToBookmarks case browsingMenuEditBookmark @@ -98,11 +96,7 @@ extension Pixel { case tabBarTabSwitcherPressed case homeScreenShown - case homeScreenSearchTapped case homeScreenFavouriteLaunched - case homeScreenAddFavorite - case homeScreenAddFavoriteOK - case homeScreenAddFavoriteCancel case homeScreenEditFavorite case homeScreenDeleteFavorite @@ -111,38 +105,7 @@ extension Pixel { case feedbackPositive case feedbackNegativePrefix(category: String) - - case feedbackNegativeBrokenSites - case feedbackNegativeOther - - case feedbackNegativeBrowserFeaturesNav - case feedbackNegativeBrowserFeaturesTabs - case feedbackNegativeBrowserFeaturesAds - case feedbackNegativeBrowserFeaturesVideos - case feedbackNegativeBrowserFeaturesImages - case feedbackNegativeBrowserFeaturesBookmarks - case feedbackNegativeBrowserFeaturesOther - - case feedbackNegativeBadResultsTechnical - case feedbackNegativeBadResultsLayout - case feedbackNegativeBadResultsSpeed - case feedbackNegativeBadResultsLangOrRegion - case feedbackNegativeBadResultsAutocomplete - case feedbackNegativeBadResultsOther - - case feedbackNegativeCustomizationHome - case feedbackNegativeCustomizationTabs - case feedbackNegativeCustomizationUI - case feedbackNegativeCustomizationWhatCleared - case feedbackNegativeCustomizationWhenCleared - case feedbackNegativeCustomizationBookmarks - case feedbackNegativeCustomizationOther - - case feedbackNegativePerformanceSlow - case feedbackNegativePerformanceCrash - case feedbackNegativePerformanceVideo - case feedbackNegativePerformanceOther - + case brokenSiteReport case daxDialogsSerp @@ -176,14 +139,6 @@ extension Pixel { case openVoiceSearch case voiceSearchCancelled - case bookmarksFolderCreated - - case bookmarkCreatedAtTopLevel - case bookmarkCreatedInSubfolder - - case bookmarkEditedAtTopLevel - case bookmarkEditedInSubfolder - case bookmarkImportSuccess case bookmarkImportFailure case bookmarkImportFailureParsingDL @@ -210,7 +165,6 @@ extension Pixel { case downloadsSharingPredownloadedLocalFile - case downloadPreparingToStart case downloadAttemptToOpenBLOBviaJS case jsAlertShown @@ -255,7 +209,6 @@ extension Pixel { case autofillSettingsOpened case autofillLoginsSettingsEnabled case autofillLoginsSettingsDisabled - case autofillLoginsSettingsAddNewLoginErrorAttemptedToCreateDuplicate case autofillLoginsSettingsResetExcludedDisplayed case autofillLoginsSettingsResetExcludedConfirmed case autofillLoginsSettingsResetExcludedDismissed @@ -266,7 +219,6 @@ extension Pixel { case autofillJSPixelFired(_ pixel: AutofillUserScript.JSPixel) - case secureVaultInitError case secureVaultError case secureVaultInitFailedError @@ -295,7 +247,6 @@ extension Pixel { case appTPFailedToAccessPreferencesDuringSetup case appTPFailedToStartTunnel - case appTPVPNCrash case appTPVPNDisconnect case appTPVPNMemoryWarning case appTPVPNMemoryCritical @@ -435,7 +386,6 @@ extension Pixel { case contentBlockingCompilationFailed(listType: CompileRulesListType, component: ContentBlockerDebugEvents.Component) - case contentBlockingErrorReportingIssue case contentBlockingCompilationTime case ampBlockingRulesCompilationFailed @@ -491,7 +441,6 @@ extension Pixel { case debugCannotClearObservationsDatabase // Return user measurement - case debugReturnUserReadATB case debugReturnUserAddATB case debugReturnUserUpdateATB @@ -512,7 +461,6 @@ extension Pixel { case bookmarksMigrationFailed case bookmarksMigrationCouldNotPrepareDatabase case bookmarksMigrationCouldNotPrepareDatabaseOnFailedMigration - case bookmarksMigrationCouldNotValidateDatabase case bookmarksMigrationCouldNotRemoveOldStore case bookmarksMigrationCouldNotPrepareMultipleFavoriteFolders @@ -533,7 +481,6 @@ extension Pixel { case syncSentUnauthenticatedRequest case syncMetadataCouldNotLoadDatabase - case syncBookmarksProviderInitializationFailed case syncBookmarksFailed case syncCredentialsProviderInitializationFailed case syncCredentialsFailed @@ -585,7 +532,6 @@ extension Pixel.Event { case .dashboardProtectionAllowlistRemove: return "mp_wlr" case .privacyDashboardReportBrokenSite: return "mp_rb" - case .privacyDashboardPixelFromJS(let rawPixel): return rawPixel case .tabSwitcherNewLayoutSeen: return "m_ts_n" case .tabSwitcherListEnabled: return "m_ts_l" @@ -600,7 +546,6 @@ extension Pixel.Event { case .settingsAutoconsentOff: return "m_settings_autoconsent_off" case .browsingMenuOpened: return "mb" - case .browsingMenuRefresh: return "mb_rf" case .browsingMenuNewTab: return "mb_tb" case .browsingMenuAddToBookmarks: return "mb_abk" case .browsingMenuEditBookmark: return "mb_ebk" @@ -639,11 +584,7 @@ extension Pixel.Event { case .tabBarTabSwitcherPressed: return "mt_tb" case .homeScreenShown: return "mh" - case .homeScreenSearchTapped: return "mh_st" case .homeScreenFavouriteLaunched: return "mh_fl" - case .homeScreenAddFavorite: return "mh_af" - case .homeScreenAddFavoriteOK: return "mh_af_o" - case .homeScreenAddFavoriteCancel: return "mh_af_c" case .homeScreenEditFavorite: return "mh_ef" case .homeScreenDeleteFavorite: return "mh_df" @@ -652,38 +593,7 @@ extension Pixel.Event { case .feedbackPositive: return "mfbs_positive_submit" case .feedbackNegativePrefix(category: let category): return "mfbs_negative_\(category)" - - case .feedbackNegativeBrokenSites: return "mfbs_negative_brokenSites_submit" - case .feedbackNegativeOther: return "mfbs_negative_other_submit" - - case .feedbackNegativeBrowserFeaturesNav: return "mfbs_negative_browserFeatures_navigation" - case .feedbackNegativeBrowserFeaturesTabs: return "mfbs_negative_browserFeatures_tabs" - case .feedbackNegativeBrowserFeaturesAds: return "mfbs_negative_browserFeatures_ads" - case .feedbackNegativeBrowserFeaturesVideos: return "mfbs_negative_browserFeatures_videos" - case .feedbackNegativeBrowserFeaturesImages: return "mfbs_negative_browserFeatures_images" - case .feedbackNegativeBrowserFeaturesBookmarks: return "mfbs_negative_browserFeatures_bookmarks" - case .feedbackNegativeBrowserFeaturesOther: return "mfbs_negative_browserFeatures_other" - - case .feedbackNegativeBadResultsTechnical: return "mfbs_negative_badResults_technical" - case .feedbackNegativeBadResultsLayout: return "mfbs_negative_badResults_layout" - case .feedbackNegativeBadResultsSpeed: return "mfbs_negative_badResults_speed" - case .feedbackNegativeBadResultsLangOrRegion: return "mfbs_negative_badResults_langRegion" - case .feedbackNegativeBadResultsAutocomplete: return "mfbs_negative_badResults_autocomplete" - case .feedbackNegativeBadResultsOther: return "mfbs_negative_badResults_other" - - case .feedbackNegativeCustomizationHome: return "mfbs_negative_customization_home" - case .feedbackNegativeCustomizationTabs: return "mfbs_negative_customization_tabs" - case .feedbackNegativeCustomizationUI: return "mfbs_negative_customization_ui" - case .feedbackNegativeCustomizationWhatCleared: return "mfbs_negative_customization_whichDataCleared" - case .feedbackNegativeCustomizationWhenCleared: return "mfbs_negative_customization_whenDataCleared" - case .feedbackNegativeCustomizationBookmarks: return "mfbs_negative_customization_bookmarks" - case .feedbackNegativeCustomizationOther: return "mfbs_negative_customization_other" - - case .feedbackNegativePerformanceSlow: return "mfbs_negative_performance_slow" - case .feedbackNegativePerformanceCrash: return "mfbs_negative_performance_crash" - case .feedbackNegativePerformanceVideo: return "mfbs_negative_performance_video" - case .feedbackNegativePerformanceOther: return "mfbs_negative_performance_other" - + case .brokenSiteReport: return "epbf" case .daxDialogsSerp: return "m_dx_s" @@ -717,14 +627,6 @@ extension Pixel.Event { case .openVoiceSearch: return "m_open_voice_search" case .voiceSearchCancelled: return "m_voice_search_cancelled" - case .bookmarksFolderCreated: return "m_bookmarks_folder_created" - - case .bookmarkCreatedAtTopLevel: return "m_bookmark_created_at_top_level" - case .bookmarkCreatedInSubfolder: return "m_bookmark_created_in_subfolder" - - case .bookmarkEditedAtTopLevel: return "m_bookmark_edited_at_top_level" - case .bookmarkEditedInSubfolder: return "m_bookmark_edited_in_subfolder" - case .bookmarkImportSuccess: return "m_bi_s" case .bookmarkImportFailure: return "m_bi_e" case .bookmarkImportFailureParsingDL: return "m_bi_e_parsing_dl" @@ -751,7 +653,6 @@ extension Pixel.Event { case .downloadsSharingPredownloadedLocalFile: return "m_downloads_sharing_predownloaded_local_file" - case .downloadPreparingToStart: return "m_download_preparing_to_start" case .downloadAttemptToOpenBLOBviaJS: return "m_download_attempt_to_open_blob_js" case .jsAlertShown: return "m_js_alert_shown" @@ -802,8 +703,6 @@ extension Pixel.Event { case .autofillSettingsOpened: return "m_autofill_settings_opened" case .autofillLoginsSettingsEnabled: return "m_autofill_logins_settings_enabled" case .autofillLoginsSettingsDisabled: return "m_autofill_logins_settings_disabled" - case .autofillLoginsSettingsAddNewLoginErrorAttemptedToCreateDuplicate: - return "m_autofill_logins_settings_add-new-login_error_attempted-to-create-duplicate" case .autofillLoginsSettingsResetExcludedDisplayed: return "m_autofill_settings_reset_excluded_displayed" case .autofillLoginsSettingsResetExcludedConfirmed: return "m_autofill_settings_reset_excluded_confirmed" case .autofillLoginsSettingsResetExcludedDismissed: return "m_autofill_settings_reset_excluded_dismissed" @@ -815,7 +714,6 @@ extension Pixel.Event { case .autofillJSPixelFired(let pixel): return "m_ios_\(pixel.pixelName)" - case .secureVaultInitError: return "m_secure_vault_init_error" case .secureVaultError: return "m_secure_vault_error" case .secureVaultInitFailedError: return "m_secure-vault_error_init-failed" @@ -842,7 +740,6 @@ extension Pixel.Event { case .appTPFailedToAccessPreferences: return "m_apptp_failed_to_access_preferences" case .appTPFailedToAccessPreferencesDuringSetup: return "m_apptp_failed_to_access_preferences_during_setup" case .appTPFailedToStartTunnel: return "m_apptp_failed_to_start_tunnel" - case .appTPVPNCrash: return "m_apptp_vpn_crash" case .appTPVPNDisconnect: return "m_apptp_vpn_disconnect" case .appTPVPNMemoryWarning: return "m_apptp_vpn_memory_warning" case .appTPVPNMemoryCritical: return "m_apptp_vpn_memory_critical" @@ -969,7 +866,6 @@ extension Pixel.Event { case .contentBlockingCompilationFailed(let listType, let component): return "m_d_content_blocking_\(listType)_\(component)_compilation_failed" - case .contentBlockingErrorReportingIssue: return "m_content_blocking_error_reporting_issue" case .contentBlockingCompilationTime: return "m_content_blocking_compilation_time" case .ampBlockingRulesCompilationFailed: return "m_debug_amp_rules_compilation_failed" @@ -1043,7 +939,6 @@ extension Pixel.Event { case .bookmarksMigrationCouldNotPrepareDatabase: return "m_d_bookmarks_migration_could_not_prepare_database" case .bookmarksMigrationCouldNotPrepareDatabaseOnFailedMigration: return "m_d_bookmarks_migration_could_not_prepare_database_on_failed_migration" - case .bookmarksMigrationCouldNotValidateDatabase: return "m_d_bookmarks_migration_could_not_validate_database" case .bookmarksMigrationCouldNotRemoveOldStore: return "m_d_bookmarks_migration_could_not_remove_old_store" case .bookmarksMigrationCouldNotPrepareMultipleFavoriteFolders: return "m_d_bookmarks_migration_could_not_prepare_multiple_favorite_folders" @@ -1064,7 +959,6 @@ extension Pixel.Event { case .syncSentUnauthenticatedRequest: return "m_d_sync_sent_unauthenticated_request" case .syncMetadataCouldNotLoadDatabase: return "m_d_sync_metadata_could_not_load_database" - case .syncBookmarksProviderInitializationFailed: return "m_d_sync_bookmarks_provider_initialization_failed" case .syncBookmarksFailed: return "m_d_sync_bookmarks_failed" case .syncCredentialsProviderInitializationFailed: return "m_d_sync_credentials_provider_initialization_failed" case .syncCredentialsFailed: return "m_d_sync_credentials_failed" @@ -1096,7 +990,6 @@ extension Pixel.Event { case .compilationFailed: return "m_d_compilation_failed" // MARK: - Return user measurement case .debugReturnUserAddATB: return "m_debug_return_user_add_atb" - case .debugReturnUserReadATB: return "m_debug_return_user_read_atb" case .debugReturnUserUpdateATB: return "m_debug_return_user_update_atb" } From d7a6661c460b86a1ce001d718e3db10c364191a6 Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Fri, 5 Jan 2024 11:24:41 +0000 Subject: [PATCH 09/11] respect system theme on launch (#2302) --- DuckDuckGo/Base.lproj/LaunchScreen.storyboard | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/DuckDuckGo/Base.lproj/LaunchScreen.storyboard b/DuckDuckGo/Base.lproj/LaunchScreen.storyboard index b1af175bf8..f8a856d8cd 100644 --- a/DuckDuckGo/Base.lproj/LaunchScreen.storyboard +++ b/DuckDuckGo/Base.lproj/LaunchScreen.storyboard @@ -1,11 +1,11 @@ - + - - + + @@ -26,11 +26,11 @@ - + - + @@ -48,11 +48,11 @@ - - - - - - + + + + + + From f59497dccf2d5047708d7124de1f38c52b177ed9 Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Fri, 5 Jan 2024 12:58:23 +0000 Subject: [PATCH 10/11] bookmarks migration refactor (#2236) Co-authored-by: Dominik Kapusta --- Core/Pixel.swift | 1 + Core/PixelEvent.swift | 3 + Core/UserDefaultsPropertyWrapper.swift | 4 +- DuckDuckGo.xcodeproj/project.pbxproj | 8 + DuckDuckGo/AppDelegate.swift | 75 +-------- DuckDuckGo/BookmarksDatabaseSetup.swift | 153 ++++++++++++++++++ .../BookmarksMigrationAssertionTests.swift | 74 +++++++++ 7 files changed, 247 insertions(+), 71 deletions(-) create mode 100644 DuckDuckGo/BookmarksDatabaseSetup.swift create mode 100644 DuckDuckGoTests/BookmarksMigrationAssertionTests.swift diff --git a/Core/Pixel.swift b/Core/Pixel.swift index b6d16d54cf..ce0bbc2aa1 100644 --- a/Core/Pixel.swift +++ b/Core/Pixel.swift @@ -106,6 +106,7 @@ public struct PixelParameters { public static let emailKeychainKeychainOperation = "keychain_operation" public static let bookmarkErrorOrphanedFolderCount = "bookmark_error_orphaned_count" + public static let bookmarksLastGoodVersion = "previous_app_version" // Remote messaging public static let message = "message" diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 9b9858f636..0e233000cc 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -439,6 +439,7 @@ extension Pixel { case debugCantSaveBookmarkFix case debugCannotClearObservationsDatabase + case debugBookmarksMigratedMoreThanOnce // Return user measurement case debugReturnUserAddATB @@ -853,6 +854,8 @@ extension Pixel.Event { case .dbRemoteMessagingDeleteScheduledMessageError: return "m_d_db_rm_delete_scheduled_message" case .dbLocalAuthenticationError: return "m_d_local_auth_error" + case .debugBookmarksMigratedMoreThanOnce: return "m_debug_bookmarks_migrated-more-than-once" + case .configurationFetchInfo: return "m_d_cfgfetch" case .trackerDataParseFailed: return "m_d_tds_p" diff --git a/Core/UserDefaultsPropertyWrapper.swift b/Core/UserDefaultsPropertyWrapper.swift index 2cd47169db..567464b20c 100644 --- a/Core/UserDefaultsPropertyWrapper.swift +++ b/Core/UserDefaultsPropertyWrapper.swift @@ -115,8 +115,10 @@ public struct UserDefaultsWrapper { case addressBarPosition = "com.duckduckgo.ios.addressbarposition" case showFullSiteAddress = "com.duckduckgo.ios.showfullsiteaddress" + case bookmarksLastGoodVersion = "com.duckduckgo.ios.bookmarksLastGoodVersion" + case bookmarksMigrationVersion = "com.duckduckgo.ios.bookmarksMigrationVersion" + case privacyConfigCustomURL = "com.duckduckgo.ios.privacyConfigCustomURL" - } private let key: Key diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 25b8245add..f42390b652 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -460,6 +460,7 @@ 85A9C37920E0E00C00073340 /* HomeRow.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 85A9C37820E0E00C00073340 /* HomeRow.xcassets */; }; 85AE668E2097206E0014CF04 /* NotificationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 85AE668D2097206E0014CF04 /* NotificationView.xib */; }; 85AE6690209724120014CF04 /* NotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AE668F209724120014CF04 /* NotificationView.swift */; }; + 85AFA1212B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AFA1202B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift */; }; 85B9CB8921AEBDD5009001F1 /* FavoriteHomeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B9CB8821AEBDD5009001F1 /* FavoriteHomeCell.swift */; }; 85BA58551F34F49E00C6E8CA /* AppUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85BA58541F34F49E00C6E8CA /* AppUserDefaults.swift */; }; 85BA58581F34F72F00C6E8CA /* AppUserDefaultsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85BA58561F34F61C00C6E8CA /* AppUserDefaultsTests.swift */; }; @@ -477,6 +478,7 @@ 85C2970A247EB7AA0063A335 /* Text.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 85C29709247EB7AA0063A335 /* Text.xcassets */; }; 85C2971A248162CA0063A335 /* DaxOnboardingPadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C29719248162CA0063A335 /* DaxOnboardingPadViewController.swift */; }; 85C861E628FF1B5F00189466 /* HomeViewSectionRenderersExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C861E528FF1B5F00189466 /* HomeViewSectionRenderersExtension.swift */; }; + 85C8E61D2B0E47380029A6BD /* BookmarksDatabaseSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C8E61C2B0E47380029A6BD /* BookmarksDatabaseSetup.swift */; }; 85C91CA224671F4C00A11132 /* AppDeepLinkSchemes.swift in Sources */ = {isa = PBXBuildFile; fileRef = F17D723B1E8BB374003E8B0E /* AppDeepLinkSchemes.swift */; }; 85CA53A824BB343700A6288C /* Favicons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CA53A324B9F2BD00A6288C /* Favicons.swift */; }; 85CA53AA24BB376800A6288C /* NotFoundCachingDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CA53A924BB376800A6288C /* NotFoundCachingDownloader.swift */; }; @@ -1498,6 +1500,7 @@ 85A9C37820E0E00C00073340 /* HomeRow.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = HomeRow.xcassets; sourceTree = ""; }; 85AE668D2097206E0014CF04 /* NotificationView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NotificationView.xib; sourceTree = ""; }; 85AE668F209724120014CF04 /* NotificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationView.swift; sourceTree = ""; }; + 85AFA1202B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksMigrationAssertionTests.swift; sourceTree = ""; }; 85B9CB8821AEBDD5009001F1 /* FavoriteHomeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteHomeCell.swift; sourceTree = ""; }; 85BA58541F34F49E00C6E8CA /* AppUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUserDefaults.swift; sourceTree = ""; }; 85BA58561F34F61C00C6E8CA /* AppUserDefaultsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUserDefaultsTests.swift; sourceTree = ""; }; @@ -1516,6 +1519,7 @@ 85C29709247EB7AA0063A335 /* Text.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Text.xcassets; sourceTree = ""; }; 85C29719248162CA0063A335 /* DaxOnboardingPadViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaxOnboardingPadViewController.swift; sourceTree = ""; }; 85C861E528FF1B5F00189466 /* HomeViewSectionRenderersExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewSectionRenderersExtension.swift; sourceTree = ""; }; + 85C8E61C2B0E47380029A6BD /* BookmarksDatabaseSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksDatabaseSetup.swift; sourceTree = ""; }; 85CA53A324B9F2BD00A6288C /* Favicons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Favicons.swift; path = ../DuckDuckGo/Favicons.swift; sourceTree = ""; }; 85CA53A924BB376800A6288C /* NotFoundCachingDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotFoundCachingDownloader.swift; sourceTree = ""; }; 85CA53AB24BBD39300A6288C /* FaviconRequestModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconRequestModifier.swift; sourceTree = ""; }; @@ -4941,6 +4945,7 @@ 85BA58561F34F61C00C6E8CA /* AppUserDefaultsTests.swift */, 4B62C4B925B930DD008912C6 /* AppConfigurationFetchTests.swift */, 85480CB229226B1E007E8F13 /* CrashCollectionExtensionTests.swift */, + 85AFA1202B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift */, ); name = Application; sourceTree = ""; @@ -5130,6 +5135,7 @@ 850250B220D803F4002199C7 /* AtbAndVariantCleanup.swift */, 983EABB7236198F6003948D1 /* DatabaseMigration.swift */, 853C5F6021C277C7001F7A05 /* global.swift */, + 85C8E61C2B0E47380029A6BD /* BookmarksDatabaseSetup.swift */, ); name = Application; sourceTree = ""; @@ -6484,6 +6490,7 @@ C17B595A2A03AAD30055F2D1 /* PasswordGenerationPromptViewController.swift in Sources */, 8531A08E1F9950E6000484F0 /* UnprotectedSitesViewController.swift in Sources */, CBD4F13C279EBF4A00B20FD7 /* HomeMessage.swift in Sources */, + 85C8E61D2B0E47380029A6BD /* BookmarksDatabaseSetup.swift in Sources */, 4BBBBA8E2B031B4200D965DA /* VPNWaitlistViewController.swift in Sources */, 3132FA2C27A07A1B00DD7A12 /* FilePreview.swift in Sources */, 85C861E628FF1B5F00189466 /* HomeViewSectionRenderersExtension.swift in Sources */, @@ -6774,6 +6781,7 @@ C14882E427F20D9A00D59F0C /* BookmarksImporterTests.swift in Sources */, 8588026A24E424EE00C24AB6 /* AppWidthObserverTests.swift in Sources */, 8588026624E420BD00C24AB6 /* LargeOmniBarStateTests.swift in Sources */, + 85AFA1212B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift in Sources */, EE0153EB2A6FF970002A8B26 /* NetworkProtectionRootViewModelTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index 036f91edd9..0debb40415 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -21,7 +21,6 @@ import UIKit import Combine import Common import Core -import CoreData import UserNotifications import Kingfisher import WidgetKit @@ -126,17 +125,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { if testing { _ = DefaultUserAgentManager.shared Database.shared.loadStore { _, _ in } - bookmarksDatabase.loadStore { context, error in - guard let context = context else { - fatalError("Error: \(error?.localizedDescription ?? "")") - } - - let legacyStorage = LegacyBookmarksCoreDataStorage() - legacyStorage?.loadStoreAndCaches() - LegacyBookmarksStoreMigration.migrate(from: legacyStorage, - to: context) - legacyStorage?.removeStore() - } + _ = BookmarksDatabaseSetup(crashOnError: true).loadStoreAndMigrate(bookmarksDatabase: bookmarksDatabase) window?.rootViewController = UIStoryboard.init(name: "LaunchScreen", bundle: nil).instantiateInitialViewController() return true } @@ -175,66 +164,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { DatabaseMigration.migrate(to: context) } - let preMigrationErrorHandling = EventMapping { _, error, _, _ in - if let error = error { - Pixel.fire(pixel: .bookmarksCouldNotLoadDatabase, - error: error) - } else { - Pixel.fire(pixel: .bookmarksCouldNotLoadDatabase) - } - - if shouldPresentInsufficientDiskSpaceAlertAndCrash { - return - } else { - Thread.sleep(forTimeInterval: 1) - fatalError("Could not create Bookmarks database stack: \(error?.localizedDescription ?? "err")") - } + if BookmarksDatabaseSetup(crashOnError: !shouldPresentInsufficientDiskSpaceAlertAndCrash) + .loadStoreAndMigrate(bookmarksDatabase: bookmarksDatabase) { + // MARK: post-Bookmarks migration logic } - let oldFavoritesOrder = BookmarkFormFactorFavoritesMigration - .getFavoritesOrderFromPreV4Model( - dbContainerLocation: BookmarksDatabase.defaultDBLocation, - dbFileURL: BookmarksDatabase.defaultDBFileURL, - errorEvents: preMigrationErrorHandling - ) - - bookmarksDatabase.loadStore { [weak self] context, error in - guard let context = context else { - if let error = error { - Pixel.fire(pixel: .bookmarksCouldNotLoadDatabase, - error: error) - } else { - Pixel.fire(pixel: .bookmarksCouldNotLoadDatabase) - } - - if shouldPresentInsufficientDiskSpaceAlertAndCrash { - return - } else { - Thread.sleep(forTimeInterval: 1) - fatalError("Could not create Bookmarks database stack: \(error?.localizedDescription ?? "err")") - } - } - - let legacyStorage = LegacyBookmarksCoreDataStorage() - legacyStorage?.loadStoreAndCaches() - LegacyBookmarksStoreMigration.migrate(from: legacyStorage, - to: context) - legacyStorage?.removeStore() - - do { - BookmarkFormFactorFavoritesMigration.migrateToFormFactorSpecificFavorites(byCopyingExistingTo: .mobile, - preservingOrderOf: oldFavoritesOrder, - in: context) - if context.hasChanges { - try context.save(onErrorFire: .bookmarksMigrationCouldNotPrepareMultipleFavoriteFolders) - } - } catch { - Thread.sleep(forTimeInterval: 1) - fatalError("Could not prepare Bookmarks DB structure") - } - - WidgetCenter.shared.reloadAllTimelines() - } + WidgetCenter.shared.reloadAllTimelines() #if APP_TRACKING_PROTECTION appTrackingProtectionDatabase.loadStore { context, error in diff --git a/DuckDuckGo/BookmarksDatabaseSetup.swift b/DuckDuckGo/BookmarksDatabaseSetup.swift new file mode 100644 index 0000000000..4ecb1e6d51 --- /dev/null +++ b/DuckDuckGo/BookmarksDatabaseSetup.swift @@ -0,0 +1,153 @@ +// +// BookmarksDatabaseSetup.swift +// DuckDuckGo +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import CoreData +import Core +import Bookmarks +import Persistence +import Common + +struct BookmarksDatabaseSetup { + + let crashOnError: Bool + + private let migrationAssertion = BookmarksMigrationAssertion() + + func loadStoreAndMigrate(bookmarksDatabase: CoreDataDatabase) -> Bool { + let preMigrationErrorHandling = createErrorHandling() + + let oldFavoritesOrder = BookmarkFormFactorFavoritesMigration + .getFavoritesOrderFromPreV4Model( + dbContainerLocation: BookmarksDatabase.defaultDBLocation, + dbFileURL: BookmarksDatabase.defaultDBFileURL, + errorEvents: preMigrationErrorHandling + ) + + var migrationHappened = false + bookmarksDatabase.loadStore { context, error in + guard let context = assertContext(context, error, crashOnError) else { return } + self.migrateFromLegacyCoreDataStorageIfNeeded(context) + migrationHappened = self.migrateToFormFactorSpecificFavorites(context, oldFavoritesOrder) + // Add new migrations and set migrationHappened flag here. Only the last migration is relevant. + // Also bump the int passed to the assert function below. + } + + if migrationHappened { + do { + try migrationAssertion.assert(migrationVersion: 1) + } catch { + assertionFailure(error.localizedDescription) + } + } + + return migrationHappened + } + + private func migrateToFormFactorSpecificFavorites(_ context: NSManagedObjectContext, _ oldFavoritesOrder: [String]?) -> Bool { + do { + BookmarkFormFactorFavoritesMigration.migrateToFormFactorSpecificFavorites(byCopyingExistingTo: .mobile, + preservingOrderOf: oldFavoritesOrder, + in: context) + if context.hasChanges { + try context.save(onErrorFire: .bookmarksMigrationCouldNotPrepareMultipleFavoriteFolders) + return true + } + } catch { + Thread.sleep(forTimeInterval: 1) + fatalError("Could not prepare Bookmarks DB structure") + } + return false + } + + private func migrateFromLegacyCoreDataStorageIfNeeded(_ context: NSManagedObjectContext) { + let legacyStorage = LegacyBookmarksCoreDataStorage() + legacyStorage?.loadStoreAndCaches() + LegacyBookmarksStoreMigration.migrate(from: legacyStorage, to: context) + legacyStorage?.removeStore() + } + + private func assertContext(_ context: NSManagedObjectContext?, _ error: Error?, _ crashOnError: Bool) -> NSManagedObjectContext? { + guard let context = context else { + if let error = error { + Pixel.fire(pixel: .bookmarksCouldNotLoadDatabase, + error: error) + } else { + Pixel.fire(pixel: .bookmarksCouldNotLoadDatabase) + } + + if !crashOnError { + return nil + } else { + Thread.sleep(forTimeInterval: 1) + fatalError("Could not create Bookmarks database stack: \(error?.localizedDescription ?? "err")") + } + } + return context + } + + private func createErrorHandling() -> EventMapping { + return EventMapping { _, error, _, _ in + if let error = error { + Pixel.fire(pixel: .bookmarksCouldNotLoadDatabase, + error: error) + } else { + Pixel.fire(pixel: .bookmarksCouldNotLoadDatabase) + } + + if !crashOnError { + return + } else { + Thread.sleep(forTimeInterval: 1) + fatalError("Could not create Bookmarks database stack: \(error?.localizedDescription ?? "err")") + } + } + } + +} + +class BookmarksMigrationAssertion { + + enum Error: Swift.Error { + case unexpectedMigration + } + + @UserDefaultsWrapper(key: .bookmarksLastGoodVersion, defaultValue: nil) + var lastGoodVersion: String? + + @UserDefaultsWrapper(key: .bookmarksMigrationVersion, defaultValue: 0) + var migrationVersion: Int + + // Wanted to use assertions here, but that's trick to test. + func assert(migrationVersion: Int) throws { + if migrationVersion != self.migrationVersion { + // this is a new migration, so save the app version and move on + self.lastGoodVersion = Bundle.main.releaseVersionNumber + self.migrationVersion = migrationVersion + return + } + + Pixel.fire(pixel: .debugBookmarksMigratedMoreThanOnce, withAdditionalParameters: [ + PixelParameters.bookmarksLastGoodVersion: lastGoodVersion ?? "" + ]) + + throw Error.unexpectedMigration + } + +} diff --git a/DuckDuckGoTests/BookmarksMigrationAssertionTests.swift b/DuckDuckGoTests/BookmarksMigrationAssertionTests.swift new file mode 100644 index 0000000000..9e4b59f82b --- /dev/null +++ b/DuckDuckGoTests/BookmarksMigrationAssertionTests.swift @@ -0,0 +1,74 @@ +// +// BookmarksMigrationAssertionTests.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import XCTest +@testable import DuckDuckGo +@testable import Core + +class BookmarksMigrationAssertionTests: XCTestCase { + + override func setUp() async throws { + try await super.setUp() + UserDefaults.app.removeObject(forKey: UserDefaultsWrapper.Key.bookmarksMigrationVersion.rawValue) + UserDefaults.app.removeObject(forKey: UserDefaultsWrapper.Key.bookmarksLastGoodVersion.rawValue) + } + + func testWhenAssertWithDifferentVersionThenNoAssertion() { + let assertion = BookmarksMigrationAssertion() + do { + try assertion.assert(migrationVersion: 1) + } catch { + XCTFail("Unexpected throw") + } + + do { + try assertion.assert(migrationVersion: 2) + } catch { + XCTFail("Unexpected throw") + } + } + + func testWhenAssertWithSameVersionThenAssertionFails() { + let assertion = BookmarksMigrationAssertion() + do { + try assertion.assert(migrationVersion: 1) + } catch { + XCTFail("Unexpected throw") + } + + do { + try assertion.assert(migrationVersion: 1) + XCTFail("Expected throw didn't happen") + } catch { + // no-op + } + } + + func testWhenInitialStateThenNoAssertionAndLastGoodVersionSet() { + let assertion = BookmarksMigrationAssertion() + do { + try assertion.assert(migrationVersion: 1) + } catch { + XCTFail("Unexpected throw") + } + XCTAssertNotNil(assertion.lastGoodVersion) + } + +} From e62c7ea8db510c5919658749232df3eaf9408eb4 Mon Sep 17 00:00:00 2001 From: Shane Osbourne Date: Fri, 5 Jan 2024 22:38:23 +0000 Subject: [PATCH 11/11] deps BrowserServicesKit 100.0.3 + content-scope-scripts 4.59.0 (#2304) Co-authored-by: Shane Osbourne --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 10 +++++----- LocalPackages/DuckUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/Waitlist/Package.swift | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index f42390b652..ba54379e32 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9233,7 +9233,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 100.0.2; + version = 100.0.3; }; }; C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 963d9334c6..2e11dc9239 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" : "39a5daf268f9fcb57d95e6193eca20f7ea222de6", - "version" : "100.0.2" + "revision" : "f2b6a76e4ed0ce3147cdf0cba94cf0d1b928d687", + "version" : "100.0.3" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "b7ad9843e70cede0c2ca9c4260d970f62cb28156", - "version" : "4.52.0" + "revision" : "bb027f14bec7fbb1a85d308139e7a66686da160e", + "version" : "4.59.0" } }, { @@ -156,7 +156,7 @@ { "identity" : "trackerradarkit", "kind" : "remoteSourceControl", - "location" : "https://github.com/duckduckgo/TrackerRadarKit", + "location" : "https://github.com/duckduckgo/TrackerRadarKit.git", "state" : { "revision" : "a6b7ba151d9dc6684484f3785293875ec01cc1ff", "version" : "1.2.2" diff --git a/LocalPackages/DuckUI/Package.swift b/LocalPackages/DuckUI/Package.swift index 80e0a08d0f..83b4de426e 100644 --- a/LocalPackages/DuckUI/Package.swift +++ b/LocalPackages/DuckUI/Package.swift @@ -31,7 +31,7 @@ let package = Package( targets: ["DuckUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.3"), ], targets: [ .target( diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 09fdb7dc37..602593e5f1 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -32,7 +32,7 @@ let package = Package( ], dependencies: [ .package(path: "../DuckUI"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.3"), .package(url: "https://github.com/duckduckgo/DesignResourcesKit", exact: "2.0.0") ], targets: [ diff --git a/LocalPackages/Waitlist/Package.swift b/LocalPackages/Waitlist/Package.swift index a666f90ef7..4071fdceda 100644 --- a/LocalPackages/Waitlist/Package.swift +++ b/LocalPackages/Waitlist/Package.swift @@ -15,7 +15,7 @@ let package = Package( targets: ["Waitlist", "WaitlistMocks"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.3"), .package(url: "https://github.com/duckduckgo/DesignResourcesKit", exact: "2.0.0") ], targets: [