From 2abb32f06073b79d8a8b9594f4ba4d8daba1d4c6 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Thu, 25 Apr 2024 19:26:04 -0700 Subject: [PATCH] Add subscription status to the macOS metadata (#2680) Task/Issue URL: https://app.asana.com/0/1199230911884351/1207144276620677/f Tech Design URL: CC: Description: This PR adds the Privacy Pro status to the VPN metadata. It also reports if the user was a beta user (i.e. they have an old-style auth token) just in case we see anything strange related to that. --- .../VPNMetadataCollector.swift | 28 ++++++++++++++++++- .../VPNFeedbackFormViewModelTests.swift | 9 +++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/VPNFeedbackForm/VPNMetadataCollector.swift b/DuckDuckGo/VPNFeedbackForm/VPNMetadataCollector.swift index b4e463df17..925ac292d2 100644 --- a/DuckDuckGo/VPNFeedbackForm/VPNMetadataCollector.swift +++ b/DuckDuckGo/VPNFeedbackForm/VPNMetadataCollector.swift @@ -24,6 +24,7 @@ import NetworkProtection import NetworkExtension import NetworkProtectionIPC import NetworkProtectionUI +import Subscription struct VPNMetadata: Encodable { @@ -72,12 +73,19 @@ struct VPNMetadata: Encodable { let notificationsAgentIsRunning: Bool } + struct PrivacyProInfo: Encodable { + let betaParticipant: Bool + let hasPrivacyProAccount: Bool + let hasVPNEntitlement: Bool + } + let appInfo: AppInfo let deviceInfo: DeviceInfo let networkInfo: NetworkInfo let vpnState: VPNState let vpnSettingsState: VPNSettingsState let loginItemState: LoginItemState + let privacyProInfo: PrivacyProInfo func toPrettyPrintedJSON() -> String? { let encoder = JSONEncoder() @@ -138,6 +146,7 @@ final class DefaultVPNMetadataCollector: VPNMetadataCollector { let vpnState = await collectVPNState() let vpnSettingsState = collectVPNSettingsState() let loginItemState = collectLoginItemState() + let privacyProInfo = await collectPrivacyProInfo() return VPNMetadata( appInfo: appInfoMetadata, @@ -145,7 +154,8 @@ final class DefaultVPNMetadataCollector: VPNMetadataCollector { networkInfo: networkInfoMetadata, vpnState: vpnState, vpnSettingsState: vpnSettingsState, - loginItemState: loginItemState + loginItemState: loginItemState, + privacyProInfo: privacyProInfo ) } @@ -283,4 +293,20 @@ final class DefaultVPNMetadataCollector: VPNMetadataCollector { ) } + func collectPrivacyProInfo() async -> VPNMetadata.PrivacyProInfo { + let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) + let waitlistStore = WaitlistKeychainStore( + waitlistIdentifier: NetworkProtectionWaitlist.identifier, + keychainAppGroup: NetworkProtectionWaitlist.keychainAppGroup + ) + + let hasVPNEntitlement = (try? await accountManager.hasEntitlement(for: .networkProtection).get()) ?? false + + return .init( + betaParticipant: waitlistStore.isInvited, + hasPrivacyProAccount: accountManager.isUserAuthenticated, + hasVPNEntitlement: hasVPNEntitlement + ) + } + } diff --git a/UnitTests/VPNFeedbackForm/VPNFeedbackFormViewModelTests.swift b/UnitTests/VPNFeedbackForm/VPNFeedbackFormViewModelTests.swift index f5f727456e..ee1758f401 100644 --- a/UnitTests/VPNFeedbackForm/VPNFeedbackFormViewModelTests.swift +++ b/UnitTests/VPNFeedbackForm/VPNFeedbackFormViewModelTests.swift @@ -126,13 +126,20 @@ private class MockVPNMetadataCollector: VPNMetadataCollector { notificationsAgentIsRunning: true ) + let privacyProInfo = VPNMetadata.PrivacyProInfo( + betaParticipant: false, + hasPrivacyProAccount: true, + hasVPNEntitlement: true + ) + return VPNMetadata( appInfo: appInfo, deviceInfo: deviceInfo, networkInfo: networkInfo, vpnState: vpnState, vpnSettingsState: vpnSettingsState, - loginItemState: loginItemState + loginItemState: loginItemState, + privacyProInfo: privacyProInfo ) }