From da7daf03f766bc303fc8608660c33ebafe7d95e3 Mon Sep 17 00:00:00 2001 From: Michal Smaga Date: Wed, 28 Aug 2024 21:11:41 +0200 Subject: [PATCH] Add error pixels for Subscription keychain access errors (#3147) Task/Issue URL: https://app.asana.com/0/1201037661562251/1208146974665104/f **Description**: Add missing pixel reporting for subscription related keychain access errors. --- DuckDuckGo.xcodeproj/project.pbxproj | 6 ++++- .../xcshareddata/swiftpm/Package.resolved | 4 +-- .../MacPacketTunnelProvider.swift | 15 ++++++++--- DuckDuckGo/Statistics/PrivacyProPixel.swift | 27 +++++++++++++++++++ ...riptionManager+StandardConfiguration.swift | 11 ++++++++ DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 17 +++++++++--- .../DataBrokerProtection/Package.swift | 2 +- .../NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- 9 files changed, 73 insertions(+), 13 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index a94f9351cc..4218b95de4 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -185,6 +185,8 @@ 1EA7B8D52B7E078C000330A4 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = 1EA7B8D42B7E078C000330A4 /* Subscription */; }; 1ED910D52B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED910D42B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift */; }; 1ED910D62B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED910D42B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift */; }; + 1EFA1A072C7C7F0E0099F508 /* PrivacyProPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F188267F2BBEB58100D9AC4F /* PrivacyProPixel.swift */; }; + 1EFA1A082C7C7F0F0099F508 /* PrivacyProPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F188267F2BBEB58100D9AC4F /* PrivacyProPixel.swift */; }; 310E79BF294A19A8007C49E8 /* FireproofingReferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 310E79BE294A19A8007C49E8 /* FireproofingReferenceTests.swift */; }; 311B262728E73E0A00FD181A /* TabShadowConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 311B262628E73E0A00FD181A /* TabShadowConfig.swift */; }; 31267C692B640C4200FEF811 /* DataBrokerProtectionFeatureGatekeeper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C5FFB82AF64D120008A79F /* DataBrokerProtectionFeatureGatekeeper.swift */; }; @@ -11414,6 +11416,7 @@ 31A83FB72BE28D8A00F74E67 /* UserText+DBP.swift in Sources */, F1D042942BFBA12300A31506 /* DataBrokerProtectionSettings+Environment.swift in Sources */, F1C70D822BFF510000599292 /* SubscriptionEnvironment+Default.swift in Sources */, + 1EFA1A072C7C7F0E0099F508 /* PrivacyProPixel.swift in Sources */, 9D9AE91D2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift in Sources */, 9D9AE9212AAA3B450026E7DC /* UserText.swift in Sources */, 31ECDA132BED339600AE679F /* DataBrokerAuthenticationManagerBuilder.swift in Sources */, @@ -11430,6 +11433,7 @@ 31A83FB82BE28D8A00F74E67 /* UserText+DBP.swift in Sources */, F1D042952BFBA12300A31506 /* DataBrokerProtectionSettings+Environment.swift in Sources */, F1C70D832BFF510000599292 /* SubscriptionEnvironment+Default.swift in Sources */, + 1EFA1A082C7C7F0F0099F508 /* PrivacyProPixel.swift in Sources */, 9D9AE91E2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift in Sources */, 9D9AE9222AAA3B450026E7DC /* UserText.swift in Sources */, 31ECDA142BED339600AE679F /* DataBrokerAuthenticationManagerBuilder.swift in Sources */, @@ -13594,7 +13598,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 188.0.0; + version = 188.1.0; }; }; 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0898a2acca..396e8be9f2 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "faf25f57d1d61ff855216178c454616031585c07", - "version" : "188.0.0" + "revision" : "ce1b7228a38d2b18525590256051a012109cfee6", + "version" : "188.1.0" } }, { diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index baceae66e6..e8c83fb1ce 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -448,9 +448,9 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { let subscriptionEndpointService = DefaultSubscriptionEndpointService(currentServiceEnvironment: subscriptionEnvironment.serviceEnvironment) let authEndpointService = DefaultAuthEndpointService(currentServiceEnvironment: subscriptionEnvironment.serviceEnvironment) let accountManager = DefaultAccountManager(accessTokenStorage: tokenStore, - entitlementsCache: entitlementsCache, - subscriptionEndpointService: subscriptionEndpointService, - authEndpointService: authEndpointService) + entitlementsCache: entitlementsCache, + subscriptionEndpointService: subscriptionEndpointService, + authEndpointService: authEndpointService) let entitlementsCheck = { await accountManager.hasEntitlement(forProductName: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) @@ -474,6 +474,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { entitlementCheck: entitlementsCheck) setupPixels() + accountManager.delegate = self observeServerChanges() observeStatusUpdateRequests() } @@ -659,3 +660,11 @@ final class DefaultWireGuardInterface: WireGuardInterface { wgSetLogger(context, logFunction) } } + +extension MacPacketTunnelProvider: AccountManagerKeychainAccessDelegate { + + public func accountManagerKeychainAccessFailed(accessType: AccountKeychainAccessType, error: AccountKeychainAccessError) { + PixelKit.fire(PrivacyProErrorPixel.privacyProKeychainAccessError(accessType: accessType, accessError: error), + frequency: .dailyAndCount) + } +} diff --git a/DuckDuckGo/Statistics/PrivacyProPixel.swift b/DuckDuckGo/Statistics/PrivacyProPixel.swift index 5609e24ed1..c4a88a6b52 100644 --- a/DuckDuckGo/Statistics/PrivacyProPixel.swift +++ b/DuckDuckGo/Statistics/PrivacyProPixel.swift @@ -17,6 +17,7 @@ // import Foundation +import Subscription import PixelKit // swiftlint:disable private_over_fileprivate @@ -119,3 +120,29 @@ enum PrivacyProPixel: PixelKitEventV2 { return nil } } + +enum PrivacyProErrorPixel: PixelKitEventV2 { + + case privacyProKeychainAccessError(accessType: AccountKeychainAccessType, accessError: AccountKeychainAccessError) + + var name: String { + switch self { + case .privacyProKeychainAccessError: return "m_mac_privacy-pro_keychain_access_error" + } + } + + var parameters: [String: String]? { + switch self { + case .privacyProKeychainAccessError(let accessType, let accessError): + return [ + "type": accessType.rawValue, + "error": accessError.errorDescription + ] + } + } + + var error: (any Error)? { + return nil + } + +} diff --git a/DuckDuckGo/Subscription/SubscriptionManager+StandardConfiguration.swift b/DuckDuckGo/Subscription/SubscriptionManager+StandardConfiguration.swift index e9562194eb..c92a66516d 100644 --- a/DuckDuckGo/Subscription/SubscriptionManager+StandardConfiguration.swift +++ b/DuckDuckGo/Subscription/SubscriptionManager+StandardConfiguration.swift @@ -19,6 +19,7 @@ import Foundation import Subscription import Common +import PixelKit extension DefaultSubscriptionManager { @@ -53,5 +54,15 @@ extension DefaultSubscriptionManager { authEndpointService: authEndpointService, subscriptionEnvironment: subscriptionEnvironment) } + + accountManager.delegate = self + } +} + +extension DefaultSubscriptionManager: AccountManagerKeychainAccessDelegate { + + public func accountManagerKeychainAccessFailed(accessType: AccountKeychainAccessType, error: AccountKeychainAccessError) { + PixelKit.fire(PrivacyProErrorPixel.privacyProKeychainAccessError(accessType: accessType, accessError: error), + frequency: .dailyAndCount) } } diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index f2c6e25861..f271288894 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -35,7 +35,7 @@ import os.log @objc(Application) final class DuckDuckGoVPNApplication: NSApplication { - public let accountManager: AccountManager + public var accountManager: AccountManager private let _delegate: DuckDuckGoVPNAppDelegate override init() { @@ -58,9 +58,9 @@ final class DuckDuckGoVPNApplication: NSApplication { settings: UserDefaultsCacheSettings(defaultExpirationInterval: .minutes(20))) let accessTokenStorage = SubscriptionTokenKeychainStorage(keychainType: .dataProtection(.named(subscriptionAppGroup))) accountManager = DefaultAccountManager(accessTokenStorage: accessTokenStorage, - entitlementsCache: entitlementsCache, - subscriptionEndpointService: subscriptionEndpointService, - authEndpointService: authEndpointService) + entitlementsCache: entitlementsCache, + subscriptionEndpointService: subscriptionEndpointService, + authEndpointService: authEndpointService) _delegate = DuckDuckGoVPNAppDelegate(accountManager: accountManager, accessTokenStorage: accessTokenStorage, @@ -69,6 +69,7 @@ final class DuckDuckGoVPNApplication: NSApplication { setupPixelKit() self.delegate = _delegate + accountManager.delegate = _delegate #if DEBUG if accountManager.accessToken != nil { @@ -436,3 +437,11 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { } } } + +extension DuckDuckGoVPNAppDelegate: AccountManagerKeychainAccessDelegate { + + public func accountManagerKeychainAccessFailed(accessType: AccountKeychainAccessType, error: AccountKeychainAccessError) { + PixelKit.fire(PrivacyProErrorPixel.privacyProKeychainAccessError(accessType: accessType, accessError: error), + frequency: .dailyAndCount) + } +} diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 42f9b92915..b13d7fd5d7 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: "188.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "188.1.0"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), ], diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index d2ef3e55af..0b727a7e12 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -32,7 +32,7 @@ let package = Package( .library(name: "VPNAppLauncher", targets: ["VPNAppLauncher"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "188.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "188.1.0"), .package(url: "https://github.com/airbnb/lottie-spm", exact: "4.4.3"), .package(path: "../AppLauncher"), .package(path: "../UDSHelper"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 5509929cd4..bee1dc2536 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: "188.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "188.1.0"), .package(path: "../SwiftUIExtensions") ], targets: [