Skip to content

Commit

Permalink
Merge branch 'main' into bartek/data-debugging
Browse files Browse the repository at this point in the history
* main:
  Duck player support on RMF (#914)
  Update autofill to 12.1.0 (#916)
  Report Autofill failures (#893)
  Update GRDB to 2.4.0 (upstream 6.29.0, SQLCipher 4.6.0) (#915)
  Update Xcode version to 15.4 (#912)
  • Loading branch information
samsymons committed Jul 29, 2024
2 parents c747c5c + 069038c commit c5392a5
Show file tree
Hide file tree
Showing 16 changed files with 107 additions and 51 deletions.
26 changes: 13 additions & 13 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: SwiftLint
uses: docker://norionomura/swiftlint:0.54.0_swift-5.9.0
with:
Expand All @@ -22,7 +22,7 @@ jobs:

name: Run unit tests (macOS)

runs-on: macos-13-xlarge
runs-on: macos-14-xlarge
timeout-minutes: 30

outputs:
Expand All @@ -31,7 +31,7 @@ jobs:
steps:

- name: Check out the code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive

Expand All @@ -46,7 +46,7 @@ jobs:
- name: Cache SPM
if: env.cache_key_hash
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |
.build/artifacts
Expand Down Expand Up @@ -89,7 +89,7 @@ jobs:
| xargs -L 1 ./scripts/report-failed-unit-test.sh -s ${{ vars.APPLE_CI_FAILING_TESTS_FAILED_TESTS_SECTION_ID }}
- name: Upload logs
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: always()
with:
name: build-log.txt
Expand All @@ -109,13 +109,13 @@ jobs:

name: Run unit tests (iOS)

runs-on: macos-13-xlarge
runs-on: macos-14-xlarge
timeout-minutes: 30

steps:

- name: Check out the code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive

Expand All @@ -130,7 +130,7 @@ jobs:
- name: Cache SPM
if: env.cache_key_hash
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: DerivedData/SourcePackages
key: ${{ runner.os }}-spm-ios-${{ env.cache_key_hash }}
Expand All @@ -144,7 +144,7 @@ jobs:
run: |
while xcodebuild -resolvePackageDependencies \
-scheme BrowserServicesKit-Package \
-destination 'platform=iOS Simulator,name=iPhone 15' \
-destination 'platform=iOS Simulator,name=iPhone 15,OS=17' \
-derivedDataPath DerivedData \
2>&1 | grep Error; do :; done
Expand All @@ -157,7 +157,7 @@ jobs:
run: |
set -o pipefail && xcodebuild test \
-scheme BrowserServicesKit \
-destination 'platform=iOS Simulator,name=iPhone 15' \
-destination 'platform=iOS Simulator,name=iPhone 15,OS=17' \
-derivedDataPath DerivedData \
-skipPackagePluginValidation \
-skipMacroValidation \
Expand Down Expand Up @@ -187,7 +187,7 @@ jobs:
| xargs -L 1 ./scripts/report-failed-unit-test.sh -s ${{ vars.APPLE_CI_FAILING_TESTS_FAILED_TESTS_SECTION_ID }}
- name: Upload logs
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: always()
with:
name: ios-build-log.txt
Expand All @@ -203,7 +203,7 @@ jobs:

steps:
- name: Check out the code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Create Asana Task
uses: ./.github/actions/asana-failed-pr-checks
with:
Expand All @@ -222,7 +222,7 @@ jobs:

steps:
- name: Check out the code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Close Asana Task
uses: ./.github/actions/asana-failed-pr-checks
with:
Expand Down
2 changes: 1 addition & 1 deletion .xcode-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
15.2
15.4
8 changes: 4 additions & 4 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/duckduckgo-autofill.git",
"state" : {
"revision" : "2b81745565db09eee8c1cd44d38eefa1011a9f0a",
"version" : "12.0.1"
"revision" : "9fea1c6762db726328b14bb9ebfd6508849eae28",
"version" : "12.1.0"
}
},
{
"identity" : "grdb.swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/GRDB.swift.git",
"state" : {
"revision" : "9f049d7b97b1e68ffd86744b500660d34a9e79b8",
"version" : "2.3.0"
"revision" : "4225b85c9a0c50544e413a1ea1e502c802b44b35",
"version" : "2.4.0"
}
},
{
Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ let package = Package(
.library(name: "PixelKitTestingUtilities", targets: ["PixelKitTestingUtilities"]),
],
dependencies: [
.package(url: "https://github.com/duckduckgo/duckduckgo-autofill.git", exact: "12.0.1"),
.package(url: "https://github.com/duckduckgo/GRDB.swift.git", exact: "2.3.0"),
.package(url: "https://github.com/duckduckgo/duckduckgo-autofill.git", exact: "12.1.0"),
.package(url: "https://github.com/duckduckgo/GRDB.swift.git", exact: "2.4.0"),
.package(url: "https://github.com/duckduckgo/TrackerRadarKit", exact: "2.1.2"),
.package(url: "https://github.com/duckduckgo/sync_crypto", exact: "0.2.0"),
.package(url: "https://github.com/gumob/PunycodeSwift.git", exact: "2.1.0"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public enum PrivacyFeature: String {
case autoconsent
case clickToLoad
case autofill
case autofillBreakageReporter
case ampLinks
case trackingParameters
case customUserAgent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ public struct BrokenSiteReportEntry {
/// Object Creation + 30 days
let expiryDate: Date?

public init?(report: BrokenSiteReport, currentDate: Date) {
public init?(report: BrokenSiteReport, currentDate: Date, daysToExpiry: Int) {

guard let domainIdentifier = report.siteUrl.privacySafeDomainIdentifier,
let expiryDate = Calendar.current.date(byAdding: .day, value: 30, to: currentDate) else {
let expiryDate = Calendar.current.date(byAdding: .day, value: daysToExpiry, to: currentDate) else {
return nil
}
self.identifier = domainIdentifier
Expand All @@ -50,7 +50,7 @@ public struct BrokenSiteReportEntry {

}

fileprivate extension URL {
public extension URL {

/// A string containing the first 6 chars of the sha256 hash of the URL's domain part
var privacySafeDomainIdentifier: String? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,17 @@ public class BrokenSiteReporter {
public typealias PixelHandler = (_ parameters: [String: String]) -> Void
/// Pixels are sent by the main apps not by BSK, this is the closure called by the class when a pixel need to be sent
let pixelHandler: PixelHandler
let persistencyManager: ExpiryStorage
public let persistencyManager: ExpiryStorage

public init(pixelHandler: @escaping PixelHandler, keyValueStoring: KeyValueStoringDictionaryRepresentable) {
public init(pixelHandler: @escaping PixelHandler,
keyValueStoring: KeyValueStoringDictionaryRepresentable,
storageConfiguration: ExpiryStorageConfiguration = .defaultConfig) {
self.pixelHandler = pixelHandler
self.persistencyManager = ExpiryStorage(keyValueStoring: keyValueStoring)
self.persistencyManager = ExpiryStorage(keyValueStoring: keyValueStoring, configuration: storageConfiguration)
}

/// Report the site breakage
public func report(_ report: BrokenSiteReport, reportMode: BrokenSiteReport.Mode) throws {
public func report(_ report: BrokenSiteReport, reportMode: BrokenSiteReport.Mode, daysToExpiry: Int = 30) throws {

let now = Date()
let removedCount = persistencyManager.removeExpiredItems(currentDate: now)
Expand All @@ -61,7 +63,7 @@ public class BrokenSiteReporter {
var report = report

// Create history entry
guard let entry = BrokenSiteReportEntry(report: report, currentDate: now) else {
guard let entry = BrokenSiteReportEntry(report: report, currentDate: now, daysToExpiry: daysToExpiry) else {
os_log(.error, "Failed to create a history entry for broken site report")
throw BrokenSiteReporterError.failedToGenerateHistoryEntry
}
Expand Down
37 changes: 26 additions & 11 deletions Sources/PrivacyDashboard/BrokenSiteReporting/ExpiryStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,37 @@ import Persistence

public typealias KeyValueStoringDictionaryRepresentable = KeyValueStoring & DictionaryRepresentable

public struct ExpiryStorageConfiguration {

var expiryDatesStorageKey: String
var valueExpiryDateKey: String
var valueDataKey: String

public static let defaultConfig = ExpiryStorageConfiguration(
expiryDatesStorageKey: "com.duckduckgo.UserDefaultExpiryStorage",
valueExpiryDateKey: "com.duckduckgo.UserDefaultExpiryStorage.valueExpiryDate",
valueDataKey: "com.duckduckgo.UserDefaultExpiryStorage.valueData"
)

public static let autofillConfig = ExpiryStorageConfiguration(
expiryDatesStorageKey: "com.duckduckgo.AutofillUserDefaultExpiryStorage",
valueExpiryDateKey: "com.duckduckgo.AutofillUserDefaultExpiryStorage.valueExpiryDate",
valueDataKey: "com.duckduckgo.AutofillUserDefaultExpiryStorage.valueData"
)
}

/// A storage solution were each entry has an expiry date and a function for removing all expired entries is provided.
/// Any persistency solution implementing `KeyValueStoringDictionaryRepresentable` can be used.
public class ExpiryStorage {

enum Keys: String {
case expiryDatesStorage = "com.duckduckgo.UserDefaultExpiryStorage"
case valueExpiryDate = "com.duckduckgo.UserDefaultExpiryStorage.valueExpiryDate"
case valueData = "com.duckduckgo.UserDefaultExpiryStorage.valueData"
}

let localStorage: KeyValueStoringDictionaryRepresentable
let config: ExpiryStorageConfiguration

/// Default initialiser
/// - Parameter keyValueStoring: An object managing the persistency of the key-value pairs that implements `KeyValueStoringDictionaryRepresentable`
public init(keyValueStoring: KeyValueStoringDictionaryRepresentable) {
public init(keyValueStoring: KeyValueStoringDictionaryRepresentable, configuration: ExpiryStorageConfiguration = .defaultConfig) {
self.localStorage = keyValueStoring
self.config = configuration
}

/// Store a value and the desired expiry date (or removes the value if nil is passed as the value) for the provided key
Expand All @@ -46,11 +61,11 @@ public class ExpiryStorage {
/// - expiryDate: A date stored alongside the value, used by `removeExpiredItems(...)` for removing expired values.
public func set(value: Any?, forKey key: String, expiryDate: Date) {

let valueDic = [Keys.valueExpiryDate.rawValue: expiryDate, Keys.valueData.rawValue: value]
let valueDic = [config.valueExpiryDateKey: expiryDate, config.valueDataKey: value]
localStorage.set(valueDic, forKey: key)
}

/// - Returns: The stored value assiciated to the key, nil if not existent
/// - Returns: The stored value associated to the key, nil if not existent
public func value(forKey key: String) -> Any? {

return entry(forKey: key)?.value
Expand All @@ -59,8 +74,8 @@ public class ExpiryStorage {
/// - Returns: The tuple expiryDate+value associated to the key, nil if they don't exist
public func entry(forKey key: String) -> (expiryDate: Date, value: Any)? {
guard let valueDic = localStorage.object(forKey: key) as? [String: Any],
let expiryDate = valueDic[Keys.valueExpiryDate.rawValue] as? Date,
let value = valueDic[Keys.valueData.rawValue]
let expiryDate = valueDic[config.valueExpiryDateKey] as? Date,
let value = valueDic[config.valueDataKey]
else {
return nil
}
Expand Down
24 changes: 16 additions & 8 deletions Sources/RemoteMessaging/Matchers/UserAttributeMatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public struct MobileUserAttributeMatcher: AttributeMatching {
isPrivacyProSubscriptionActive: Bool,
isPrivacyProSubscriptionExpiring: Bool,
isPrivacyProSubscriptionExpired: Bool,
isDuckPlayerOnboarded: Bool,
isDuckPlayerEnabled: Bool,
dismissedMessageIds: [String]
) {
self.isWidgetInstalled = isWidgetInstalled
Expand All @@ -74,6 +76,8 @@ public struct MobileUserAttributeMatcher: AttributeMatching {
isPrivacyProSubscriptionActive: isPrivacyProSubscriptionActive,
isPrivacyProSubscriptionExpiring: isPrivacyProSubscriptionExpiring,
isPrivacyProSubscriptionExpired: isPrivacyProSubscriptionExpired,
isDuckPlayerOnboarded: isDuckPlayerOnboarded,
isDuckPlayerEnabled: isDuckPlayerEnabled,
dismissedMessageIds: dismissedMessageIds
)
}
Expand All @@ -92,8 +96,6 @@ public struct MobileUserAttributeMatcher: AttributeMatching {
public struct DesktopUserAttributeMatcher: AttributeMatching {
private let pinnedTabsCount: Int
private let hasCustomHomePage: Bool
private let isDuckPlayerOnboarded: Bool
private let isDuckPlayerEnabled: Bool
private let dismissedDeprecatedMacRemoteMessageIds: [String]

private let commonUserAttributeMatcher: CommonUserAttributeMatcher
Expand Down Expand Up @@ -122,8 +124,6 @@ public struct DesktopUserAttributeMatcher: AttributeMatching {
) {
self.pinnedTabsCount = pinnedTabsCount
self.hasCustomHomePage = hasCustomHomePage
self.isDuckPlayerOnboarded = isDuckPlayerOnboarded
self.isDuckPlayerEnabled = isDuckPlayerEnabled
self.dismissedDeprecatedMacRemoteMessageIds = dismissedDeprecatedMacRemoteMessageIds

commonUserAttributeMatcher = .init(
Expand All @@ -142,6 +142,8 @@ public struct DesktopUserAttributeMatcher: AttributeMatching {
isPrivacyProSubscriptionActive: isPrivacyProSubscriptionActive,
isPrivacyProSubscriptionExpiring: isPrivacyProSubscriptionExpiring,
isPrivacyProSubscriptionExpired: isPrivacyProSubscriptionExpired,
isDuckPlayerOnboarded: isDuckPlayerOnboarded,
isDuckPlayerEnabled: isDuckPlayerEnabled,
dismissedMessageIds: dismissedMessageIds
)
}
Expand All @@ -152,10 +154,6 @@ public struct DesktopUserAttributeMatcher: AttributeMatching {
return matchingAttribute.evaluate(for: pinnedTabsCount)
case let matchingAttribute as CustomHomePageMatchingAttribute:
return matchingAttribute.evaluate(for: hasCustomHomePage)
case let matchingAttribute as DuckPlayerOnboardedMatchingAttribute:
return matchingAttribute.evaluate(for: isDuckPlayerOnboarded)
case let matchingAttribute as DuckPlayerEnabledMatchingAttribute:
return matchingAttribute.evaluate(for: isDuckPlayerEnabled)
case let matchingAttribute as InteractedWithDeprecatedMacRemoteMessageMatchingAttribute:
if dismissedDeprecatedMacRemoteMessageIds.contains(where: { messageId in
StringArrayMatchingAttribute(matchingAttribute.value).matches(value: messageId) == .match
Expand Down Expand Up @@ -193,6 +191,8 @@ public struct CommonUserAttributeMatcher: AttributeMatching {
private let isPrivacyProSubscriptionActive: Bool
private let isPrivacyProSubscriptionExpiring: Bool
private let isPrivacyProSubscriptionExpired: Bool
private let isDuckPlayerOnboarded: Bool
private let isDuckPlayerEnabled: Bool
private let dismissedMessageIds: [String]

public init(statisticsStore: StatisticsStore,
Expand All @@ -210,6 +210,8 @@ public struct CommonUserAttributeMatcher: AttributeMatching {
isPrivacyProSubscriptionActive: Bool,
isPrivacyProSubscriptionExpiring: Bool,
isPrivacyProSubscriptionExpired: Bool,
isDuckPlayerOnboarded: Bool,
isDuckPlayerEnabled: Bool,
dismissedMessageIds: [String]
) {
self.statisticsStore = statisticsStore
Expand All @@ -227,6 +229,8 @@ public struct CommonUserAttributeMatcher: AttributeMatching {
self.isPrivacyProSubscriptionActive = isPrivacyProSubscriptionActive
self.isPrivacyProSubscriptionExpiring = isPrivacyProSubscriptionExpiring
self.isPrivacyProSubscriptionExpired = isPrivacyProSubscriptionExpired
self.isDuckPlayerOnboarded = isDuckPlayerOnboarded
self.isDuckPlayerEnabled = isDuckPlayerEnabled
self.dismissedMessageIds = dismissedMessageIds
}

Expand Down Expand Up @@ -272,6 +276,10 @@ public struct CommonUserAttributeMatcher: AttributeMatching {
}

return .fail
case let matchingAttribute as DuckPlayerOnboardedMatchingAttribute:
return matchingAttribute.evaluate(for: isDuckPlayerOnboarded)
case let matchingAttribute as DuckPlayerEnabledMatchingAttribute:
return matchingAttribute.evaluate(for: isDuckPlayerEnabled)
case let matchingAttribute as InteractedWithMessageMatchingAttribute:
if dismissedMessageIds.contains(where: { messageId in
StringArrayMatchingAttribute(matchingAttribute.value).matches(value: messageId) == .match
Expand Down
Loading

0 comments on commit c5392a5

Please sign in to comment.