From d08b1f60369674a768380007fc7242e610f40a80 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:14:43 +0100 Subject: [PATCH 01/99] Point to BSK branch and make compile --- DuckDuckGo.xcodeproj/project.pbxproj | 4 ++-- .../xcshareddata/swiftpm/Package.resolved | 9 --------- .../EventMapping+NetworkProtectionError.swift | 3 +++ .../NetworkProtection+ConvenienceInitializers.swift | 13 ++++++++++--- .../BothAppTargets/NetworkProtectionAppEvents.swift | 3 ++- .../NetworkProtectionTunnelController.swift | 3 +++ .../VPNLocation/VPNLocationViewModel.swift | 3 ++- .../NetworkProtectionUNNotificationsPresenter.swift | 4 ++++ .../MacPacketTunnelProvider.swift | 9 +++++++-- DuckDuckGoVPN/NetworkProtectionBouncer.swift | 2 +- LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/PixelKit/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SwiftUIExtensions/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- LocalPackages/XPCHelper/Package.swift | 2 +- ...tworkProtectionAgentNotificationsPresenter.swift | 3 +++ 20 files changed, 46 insertions(+), 28 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 51e2f0b5c3..a619629858 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13352,8 +13352,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { - kind = exactVersion; - version = 107.0.0; + kind = revision; + revision = 190c50eb5ca7a0d1bfd492f0ea372efb8f046797; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 954bc34c8c..e7d61d59d6 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -9,15 +9,6 @@ "version" : "3.0.0" } }, - { - "identity" : "browserserviceskit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/duckduckgo/BrowserServicesKit", - "state" : { - "revision" : "328ce451fd1593809d1470ab5a0b5242a595f88c", - "version" : "107.0.0" - } - }, { "identity" : "content-scope-scripts", "kind" : "remoteSourceControl", diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/EventMapping+NetworkProtectionError.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/EventMapping+NetworkProtectionError.swift index 60b9120fb0..1e82f384b6 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/EventMapping+NetworkProtectionError.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/EventMapping+NetworkProtectionError.swift @@ -98,6 +98,9 @@ extension EventMapping where Event == NetworkProtectionError { domainEvent = .networkProtectionUnhandledError(function: function, line: line, error: error) frequency = .standard return + case .vpnAccessRevoked: + // TODO: Handle this + return } let debugEvent = DebugEvent(eventType: .custom(domainEvent)) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift index 0838bb0c2d..8ed6ccc832 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift @@ -28,7 +28,12 @@ extension NetworkProtectionDeviceManager { let settings = VPNSettings(defaults: .netP) let keyStore = NetworkProtectionKeychainKeyStore() let tokenStore = NetworkProtectionKeychainTokenStore() - return NetworkProtectionDeviceManager(environment: settings.selectedEnvironment, tokenStore: tokenStore, keyStore: keyStore, errorEvents: .networkProtectionAppDebugEvents) + return NetworkProtectionDeviceManager( + environment: settings.selectedEnvironment, + tokenStore: tokenStore, + keyStore: keyStore, + errorEvents: .networkProtectionAppDebugEvents, subscriptionConfiguration: .init(isSubscriptionEnabled: false, isEntitlementValid: { true }) + ) } } @@ -37,14 +42,16 @@ extension NetworkProtectionCodeRedemptionCoordinator { let settings = VPNSettings(defaults: .netP) self.init(environment: settings.selectedEnvironment, tokenStore: NetworkProtectionKeychainTokenStore(), - errorEvents: .networkProtectionAppDebugEvents) + errorEvents: .networkProtectionAppDebugEvents, + isSubscriptionEnabled: false) } } extension NetworkProtectionKeychainTokenStore { convenience init() { self.init(keychainType: .default, - errorEvents: .networkProtectionAppDebugEvents) + errorEvents: .networkProtectionAppDebugEvents, + isSubscriptionEnabled: false) } } diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift index a1e96fa4cf..81c124f1ad 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift @@ -99,7 +99,8 @@ final class NetworkProtectionAppEvents { let legacyServiceName = "\(Bundle.main.bundleIdentifier!).authToken" let legacyKeychainStore = NetworkProtectionKeychainTokenStore(keychainType: .dataProtection(.unspecified), serviceName: legacyServiceName, - errorEvents: nil) + errorEvents: nil, + isSubscriptionEnabled: false) guard let token = try? legacyKeychainStore.fetchToken() else { // If fetching the token fails, we just assume we can't migrate anything and the user diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index d5eb04eecf..28da8de951 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -178,6 +178,9 @@ final class NetworkProtectionTunnelController: NetworkProtection.TunnelControlle .setDisableRekeying: // Intentional no-op as this is handled by the extension or the agent's app delegate break + case .setShouldShowExpiredEntitlementMessaging: + // TODO: Handle this + break } } diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift index 38da4de2f8..00b3e5b5d5 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift @@ -186,7 +186,8 @@ extension NetworkProtectionLocationListCompositeRepository { self.init( environment: settings.selectedEnvironment, tokenStore: NetworkProtectionKeychainTokenStore(), - errorEvents: .networkProtectionAppDebugEvents + errorEvents: .networkProtectionAppDebugEvents, + isSubscriptionEnabled: false ) } } diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift index 4237c816d2..c75d583a5a 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift @@ -46,6 +46,10 @@ extension UNNotificationCategory { /// This class takes care of requesting the presentation of notifications using UNNotificationCenter /// final class NetworkProtectionUNNotificationsPresenter: NSObject, NetworkProtectionNotificationsPresenter { + func showExpiredEntitlementNotification() { + + } + private static let threadIdentifier = "com.duckduckgo.NetworkProtectionNotificationsManager.threadIdentifier" private let appLauncher: AppLauncher diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 5770b78a2f..f8c8f09577 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -123,6 +123,9 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { .failedToParseLocationListResponse: // Needs Privacy triage for macOS Geoswitching pixels return + case .vpnAccessRevoked: + // TODO: Handle this + return } PixelKit.fire(domainEvent, frequency: .dailyAndContinuous, includeAppVersionParameter: true) @@ -226,7 +229,8 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { let debugEvents = Self.networkProtectionDebugEvents(controllerErrorStore: controllerErrorStore) let tokenStore = NetworkProtectionKeychainTokenStore(keychainType: NetworkProtectionBundle.keychainType, serviceName: Self.tokenServiceName, - errorEvents: debugEvents) + errorEvents: debugEvents, + isSubscriptionEnabled: false) let notificationsPresenter = NetworkProtectionNotificationsPresenterFactory().make(settings: settings) super.init(notificationsPresenter: notificationsPresenter, @@ -236,7 +240,8 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { tokenStore: tokenStore, debugEvents: debugEvents, providerEvents: Self.packetTunnelProviderEvents, - settings: settings) + settings: settings, + subscriptionConfiguration: .init(isSubscriptionEnabled: false, isEntitlementValid: { true })) observeConnectionStatusChanges() observeServerChanges() diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index 261121df37..2f3d8d2bdb 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -30,7 +30,7 @@ final class NetworkProtectionBouncer { /// current app. /// func requireAuthTokenOrKillApp() { - let keychainStore = NetworkProtectionKeychainTokenStore(keychainType: .default, errorEvents: nil) + let keychainStore = NetworkProtectionKeychainTokenStore(keychainType: .default, errorEvents: nil, isSubscriptionEnabled: false) guard keychainStore.isFeatureActivated else { os_log(.error, log: .networkProtection, "🔴 Stopping: Network Protection not authorized.") diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index f1681bc73f..5fd8170cc3 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: "107.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "190c50eb5ca7a0d1bfd492f0ea372efb8f046797"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper") diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index cfd61b26c4..8426c70ac8 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -13,7 +13,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "107.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "190c50eb5ca7a0d1bfd492f0ea372efb8f046797"), ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index ee441bef03..3b6de23501 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -30,7 +30,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "107.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "190c50eb5ca7a0d1bfd492f0ea372efb8f046797"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems") diff --git a/LocalPackages/PixelKit/Package.swift b/LocalPackages/PixelKit/Package.swift index b0824cf51b..9cd28bf702 100644 --- a/LocalPackages/PixelKit/Package.swift +++ b/LocalPackages/PixelKit/Package.swift @@ -20,7 +20,7 @@ let package = Package( ) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "107.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "190c50eb5ca7a0d1bfd492f0ea372efb8f046797"), ], targets: [ .target( diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 663ce90fef..9444bf8a5e 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: "107.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "190c50eb5ca7a0d1bfd492f0ea372efb8f046797"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SwiftUIExtensions/Package.swift b/LocalPackages/SwiftUIExtensions/Package.swift index 5eb9e15177..1a01f77b7b 100644 --- a/LocalPackages/SwiftUIExtensions/Package.swift +++ b/LocalPackages/SwiftUIExtensions/Package.swift @@ -11,7 +11,7 @@ let package = Package( .library(name: "PreferencesViews", targets: ["PreferencesViews"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "107.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "190c50eb5ca7a0d1bfd492f0ea372efb8f046797"), ], targets: [ .target( diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 0a162fce7d..1050878ba7 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(path: "../SwiftUIExtensions"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "107.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "190c50eb5ca7a0d1bfd492f0ea372efb8f046797"), ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index dff7a8f9a1..94035fa564 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -16,7 +16,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "107.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "190c50eb5ca7a0d1bfd492f0ea372efb8f046797"), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/LocalPackages/XPCHelper/Package.swift b/LocalPackages/XPCHelper/Package.swift index 8d16fa88c3..d485530939 100644 --- a/LocalPackages/XPCHelper/Package.swift +++ b/LocalPackages/XPCHelper/Package.swift @@ -30,7 +30,7 @@ let package = Package( .library(name: "XPCHelper", targets: ["XPCHelper"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "107.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "190c50eb5ca7a0d1bfd492f0ea372efb8f046797"), ], targets: [ .target( diff --git a/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift b/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift index 7d788892e1..ee2ccdbc89 100644 --- a/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift +++ b/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift @@ -23,6 +23,9 @@ import NetworkProtection /// the established IPC connection. /// final class NetworkProtectionAgentNotificationsPresenter: NetworkProtectionNotificationsPresenter { + func showExpiredEntitlementNotification() { + + } private let notificationCenter: NetworkProtectionNotificationCenter From ef56ab20d1d4186a916b54f6a6306640c5f6f89f Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 19 Feb 2024 15:22:45 +0100 Subject: [PATCH 02/99] Add basic hardcoded SubscriptionExpiredView --- .../SubscriptionExpiredView.swift | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift new file mode 100644 index 0000000000..251421c242 --- /dev/null +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift @@ -0,0 +1,69 @@ +// +// SubscriptionExpiredView.swift +// +// 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 SwiftUI +import SwiftUIExtensions + +struct SubscriptionExpiredView: View { + public var body: some View { + VStack(alignment: .leading, spacing: 5) { + Text("VPN disconnected due to expired subscription") + .font(.system(size: 14).weight(.bold)) + .foregroundColor(Color(.defaultText)) + .multilineText() + + Text("Subscribe to Privacy Pro to reconnect DuckDuckGo VPN.") + .font(.system(size: 13)) + .foregroundColor(Color(.defaultText)) + .multilineText() + + Button("Subscribe to Privacy Pro") { + // TODO: + } + .buttonStyle(DefaultActionButtonStyle(enabled: true)) + .padding(.top, 3) + + Divider().padding(.top, 8).padding(.bottom, 3) + + Button("Uninstall DuckDuckGo VPN") { + // TODO: + } + .buttonStyle(.borderless) + .foregroundColor(.accentColor) + .padding(.top, 3) + } + .padding(.vertical, 16) + .padding(.horizontal, 10) + .cornerRadius(8) + .background( + RoundedRectangle(cornerRadius: 6, style: .circular) + .stroke(Color(.onboardingStepBorder), lineWidth: 1) + .background( + RoundedRectangle(cornerRadius: 6, style: .circular) + .fill(Color(.onboardingStepBackground)) + ) + ) + } +} + +struct SubscriptionExpiredView_Preview: PreviewProvider { + static var previews: some View { + SubscriptionExpiredView() + } +} From 77fa698f16b1ab921ea7cbef86cc2ed08e92852e Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 20 Feb 2024 17:06:20 +0100 Subject: [PATCH 03/99] Show subscription expired prompt --- .../AccountManager+NetworkProtection.swift | 23 +++++++++++++++++++ ...etworkProtectionNavBarPopoverManager.swift | 4 +++- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 5 +++- .../DataBrokerRunCustomJSONViewModel.swift | 2 +- .../Menu/StatusBarMenu.swift | 7 ++++-- .../NetworkProtectionPopover.swift | 16 +++++++------ .../NetworkProtectionStatusView.swift | 4 +++- .../NetworkProtectionStatusViewModel.swift | 17 +++++++++++++- 8 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AccountManager+NetworkProtection.swift diff --git a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AccountManager+NetworkProtection.swift b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AccountManager+NetworkProtection.swift new file mode 100644 index 0000000000..d33ad50802 --- /dev/null +++ b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AccountManager+NetworkProtection.swift @@ -0,0 +1,23 @@ +// +// AccountManager+NetworkProtection.swift +// +// 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 NetworkProtection +import Subscription + +extension AccountManager: SubscriptionAccountManaging {} diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index 3a73bf2287..30a2d6eac4 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -23,6 +23,7 @@ import LoginItems import NetworkProtection import NetworkProtectionIPC import NetworkProtectionUI +import Subscription #if NETWORK_PROTECTION final class NetworkProtectionNavBarPopoverManager { @@ -84,7 +85,8 @@ final class NetworkProtectionNavBarPopoverManager { return menuItems }, - agentLoginItem: LoginItem.vpnMenu + agentLoginItem: LoginItem.vpnMenu, + accountManager: AccountManager() ) popover.delegate = delegate diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index e72b57d055..e60baa6c24 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -27,6 +27,7 @@ import NetworkProtectionIPC import NetworkProtectionUI import ServiceManagement import PixelKit +import Subscription @objc(Application) final class DuckDuckGoVPNApplication: NSApplication { @@ -159,7 +160,9 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { }) ] }, - agentLoginItem: nil) + agentLoginItem: nil, + accountManager: AccountManager() + ) } @MainActor diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/DebugUI/DataBrokerRunCustomJSONViewModel.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/DebugUI/DataBrokerRunCustomJSONViewModel.swift index 0ca3d48b7c..9109f0baed 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/DebugUI/DataBrokerRunCustomJSONViewModel.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/DebugUI/DataBrokerRunCustomJSONViewModel.swift @@ -241,7 +241,7 @@ final class FakeStageDurationCalculator: StageDurationCalculator { /* I wasn't able to import this mock from the background agent project, so I had to re-use it here. */ -fileprivate final class PrivacyConfigurationManagingMock: PrivacyConfigurationManaging { +private final class PrivacyConfigurationManagingMock: PrivacyConfigurationManaging { var data: Data { let configString = """ diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift index 996df614b1..16728c88f5 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift @@ -55,7 +55,8 @@ public final class StatusBarMenu: NSObject { iconProvider: IconProvider, appLauncher: AppLaunching, menuItems: @escaping () -> [MenuItem], - agentLoginItem: LoginItem?) { + agentLoginItem: LoginItem?, + accountManager: SubscriptionAccountManaging) { self.model = model let statusItem = statusItem ?? NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) @@ -67,7 +68,9 @@ public final class StatusBarMenu: NSObject { statusReporter: statusReporter, appLauncher: appLauncher, menuItems: menuItems, - agentLoginItem: agentLoginItem) + agentLoginItem: agentLoginItem, + accountManager: accountManager) + popover.behavior = .transient super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift index 85485aa0f1..39cf32e29c 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift @@ -55,16 +55,18 @@ public final class NetworkProtectionPopover: NSPopover { statusReporter: NetworkProtectionStatusReporter, appLauncher: AppLaunching, menuItems: @escaping () -> [MenuItem], - agentLoginItem: LoginItem?) { + agentLoginItem: LoginItem?, + accountManager: SubscriptionAccountManaging) { self.statusReporter = statusReporter self.model = NetworkProtectionStatusView.Model(controller: controller, - onboardingStatusPublisher: onboardingStatusPublisher, - statusReporter: statusReporter, - debugInformationPublisher: debugInformationPublisher.eraseToAnyPublisher(), - appLauncher: appLauncher, - menuItems: menuItems, - agentLoginItem: agentLoginItem) + onboardingStatusPublisher: onboardingStatusPublisher, + statusReporter: statusReporter, + debugInformationPublisher: debugInformationPublisher.eraseToAnyPublisher(), + appLauncher: appLauncher, + menuItems: menuItems, + agentLoginItem: agentLoginItem, + accountManager: accountManager) super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift index 66f9bb15ea..19d4d505b4 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift @@ -50,7 +50,9 @@ public struct NetworkProtectionStatusView: View { public var body: some View { VStack(spacing: 0) { - if let promptActionViewModel = model.promptActionViewModel { + if model.shouldShowSubscriptionExpired { + SubscriptionExpiredView() + } else if let promptActionViewModel = model.promptActionViewModel { PromptActionView(model: promptActionViewModel) .padding(.horizontal, 5) .padding(.top, 5) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 2a86e999d0..17fa86a972 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -93,6 +93,8 @@ extension NetworkProtectionStatusView { /// private let runLoopMode: RunLoop.Mode? + private let accountManager: SubscriptionAccountManaging + private var cancellables = Set() // MARK: - Dispatch Queues @@ -111,7 +113,8 @@ extension NetworkProtectionStatusView { appLauncher: AppLaunching, menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, - runLoopMode: RunLoop.Mode? = nil) { + runLoopMode: RunLoop.Mode? = nil, + accountManager: SubscriptionAccountManaging) { self.tunnelController = controller self.onboardingStatusPublisher = onboardingStatusPublisher @@ -120,6 +123,7 @@ extension NetworkProtectionStatusView { self.menuItems = menuItems self.agentLoginItem = agentLoginItem self.runLoopMode = runLoopMode + self.accountManager = accountManager tunnelControllerViewModel = TunnelControllerViewModel(controller: tunnelController, onboardingStatusPublisher: onboardingStatusPublisher, @@ -146,6 +150,14 @@ extension NetworkProtectionStatusView { self?.onboardingStatus = status } .store(in: &cancellables) + + Task { + if await accountManager.hasEntitlement(for: "subscriber") { + shouldShowSubscriptionExpired = false + } else { + shouldShowSubscriptionExpired = true + } + } } func refreshLoginItemStatus() { @@ -281,6 +293,9 @@ extension NetworkProtectionStatusView { let tunnelControllerViewModel: TunnelControllerViewModel + @Published + var shouldShowSubscriptionExpired: Bool = false + var promptActionViewModel: PromptActionView.Model? { #if !APPSTORE && !DEBUG guard Bundle.main.isInApplicationDirectory else { From 4b963122dc891bdeef30e83af66e867e06c8934f Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 20 Feb 2024 17:07:51 +0100 Subject: [PATCH 04/99] Show expired entitlement notifications --- .../NetworkProtectionUNNotificationsPresenter.swift | 10 +++++++--- .../UserText+NetworkProtectionExtensions.swift | 2 ++ .../NetworkProtectionAgentNotificationsPresenter.swift | 7 ++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift index c75d583a5a..998ca2d878 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift @@ -46,9 +46,6 @@ extension UNNotificationCategory { /// This class takes care of requesting the presentation of notifications using UNNotificationCenter /// final class NetworkProtectionUNNotificationsPresenter: NSObject, NetworkProtectionNotificationsPresenter { - func showExpiredEntitlementNotification() { - - } private static let threadIdentifier = "com.duckduckgo.NetworkProtectionNotificationsManager.threadIdentifier" @@ -137,6 +134,12 @@ final class NetworkProtectionUNNotificationsPresenter: NSObject, NetworkProtecti showNotification(.superseded, content) } + func showExpiredEntitlementNotification() { + let content = notificationContent(title: UserText.networkProtectionEntitlementExpiredNotificationTitle, + subtitle: UserText.networkProtectionEntitlementExpiredNotificationBody) + showNotification(.expiredEntitlement, content) + } + func showTestNotification() { // These strings are deliberately hardcoded as we don't want them localized, they're only for debugging: let content = notificationContent(title: "Test notification", @@ -165,6 +168,7 @@ public enum NetworkProtectionNotificationIdentifier: String { case reconnecting = "network-protection.notification.reconnecting" case connected = "network-protection.notification.connected" case superseded = "network-protection.notification.superseded" + case expiredEntitlement = "network-protection.notification.expired-entitlement" case test = "network-protection.notification.test" } diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/UserText+NetworkProtectionExtensions.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/UserText+NetworkProtectionExtensions.swift index 219b048584..b4cf049d12 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/UserText+NetworkProtectionExtensions.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/UserText+NetworkProtectionExtensions.swift @@ -43,4 +43,6 @@ final class UserText { static let networkProtectionSupersededNotificationSubtitle = NSLocalizedString("network.protection.superceded.notification.subtitle", value: "A VPN app on your device may have disabled it. Click to re-enable.", comment: "The subtitle of the notification shown when VPN connection is replaced by another app VPN connection taking over") static let networkProtectionSupersededReconnectActionTitle = NSLocalizedString("network.protection.superceded.action.reconnect.title", value: "Re-enable", comment: "The title of the `Reconnect` notification action button shown when VPN connection is replaced by another app VPN connection taking over") + static let networkProtectionEntitlementExpiredNotificationTitle = NSLocalizedString("network.protection.entitlement.expired.notification.title", value: "VPN disconnected due to expired subscription.", comment: "The title of the notification when Privacy Pro subscription expired") + static let networkProtectionEntitlementExpiredNotificationBody = NSLocalizedString("network.protection.entitlement.expired.notification.body", value: "Subscribe to Privacy Pro to reconnect DuckDuckGo VPN.", comment: "The body of the notification when Privacy Pro subscription expired") } diff --git a/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift b/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift index ee2ccdbc89..68edf3d446 100644 --- a/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift +++ b/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift @@ -23,9 +23,6 @@ import NetworkProtection /// the established IPC connection. /// final class NetworkProtectionAgentNotificationsPresenter: NetworkProtectionNotificationsPresenter { - func showExpiredEntitlementNotification() { - - } private let notificationCenter: NetworkProtectionNotificationCenter @@ -51,6 +48,10 @@ final class NetworkProtectionAgentNotificationsPresenter: NetworkProtectionNotif notificationCenter.post(.showVPNSupersededNotification) } + func showExpiredEntitlementNotification() { + notificationCenter.post(.showExpiredEntitlementNotification) + } + func showTestNotification() { notificationCenter.post(.showTestNotification) } From c71c7a880ca5dd64e00be394023d029bb78d0f43 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 23 Feb 2024 16:05:35 +0100 Subject: [PATCH 05/99] wip --- .../App/DuckDuckGoPrivacyPro.xcconfig | 2 +- DuckDuckGo.xcodeproj/project.pbxproj | 28 ++++++++++++++++++ DuckDuckGo/InfoPlist.xcstrings | 2 +- .../MacPacketTunnelProvider.swift | 25 +++++++++++++++- .../NetworkProtectionStatusViewModel.swift | 29 ++++++++++++++----- Submodules/privacy-reference-tests | 2 +- 6 files changed, 77 insertions(+), 11 deletions(-) diff --git a/Configuration/App/DuckDuckGoPrivacyPro.xcconfig b/Configuration/App/DuckDuckGoPrivacyPro.xcconfig index d7cbfb5168..c42cdf5c57 100644 --- a/Configuration/App/DuckDuckGoPrivacyPro.xcconfig +++ b/Configuration/App/DuckDuckGoPrivacyPro.xcconfig @@ -21,6 +21,6 @@ #include "DuckDuckGo.xcconfig" -FEATURE_FLAGS = FEEDBACK NETWORK_PROTECTION SPARKLE SUBSCRIPTION DBP STRIPE +FEATURE_FLAGS = FEEDBACK NETWORK_PROTECTION SPARKLE SUBSCRIPTION DBP NOSTRIPE PRODUCT_NAME = $(PRODUCT_NAME_PREFIX) Privacy Pro PRODUCT_MODULE_NAME = DuckDuckGo_Privacy_Browser diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index a619629858..f157bb453f 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3058,6 +3058,13 @@ EAC80DE0271F6C0100BBF02D /* fb-sdk.js in Resources */ = {isa = PBXBuildFile; fileRef = EAC80DDF271F6C0100BBF02D /* fb-sdk.js */; }; EAE42800275D47FA00DAC26B /* ClickToLoadModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE427FF275D47FA00DAC26B /* ClickToLoadModel.swift */; }; EAFAD6CA2728BD1200F9DF00 /* clickToLoad.js in Resources */ = {isa = PBXBuildFile; fileRef = EAFAD6C92728BD1200F9DF00 /* clickToLoad.js */; }; + EE297CBD2B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */; }; + EE297CBE2B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */; }; + EE297CC12B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */; }; + EE297CC22B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */; }; + EE297CC32B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */; }; + EE297CC52B83EF480083DB29 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE297CC42B83EF480083DB29 /* Subscription */; }; + EE297CC72B83EF510083DB29 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE297CC62B83EF510083DB29 /* Subscription */; }; EE339228291BDEFD009F62C1 /* JSAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE339227291BDEFD009F62C1 /* JSAlertController.swift */; }; EE66666F2B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; EE6666702B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; @@ -4402,11 +4409,13 @@ EAC80DDF271F6C0100BBF02D /* fb-sdk.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "fb-sdk.js"; sourceTree = ""; }; EAE427FF275D47FA00DAC26B /* ClickToLoadModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClickToLoadModel.swift; sourceTree = ""; }; EAFAD6C92728BD1200F9DF00 /* clickToLoad.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = clickToLoad.js; sourceTree = ""; }; + EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountManager+NetworkProtection.swift"; sourceTree = ""; }; EE339227291BDEFD009F62C1 /* JSAlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSAlertController.swift; sourceTree = ""; }; EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationsHostingViewController.swift; sourceTree = ""; }; EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNCountryLabelsModel.swift; sourceTree = ""; }; EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNLocationViewModel.swift; sourceTree = ""; }; EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLauncher.swift; sourceTree = ""; }; + EEBE97B22B7E48A600404915 /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = ""; }; EEC111E3294D06020086524F /* JSAlert.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = JSAlert.storyboard; sourceTree = ""; }; EEC111E5294D06290086524F /* JSAlertViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSAlertViewModel.swift; sourceTree = ""; }; EEC4A6682B2C87D300F7C0AA /* VPNLocationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationView.swift; sourceTree = ""; }; @@ -4507,6 +4516,7 @@ buildActionMask = 2147483647; files = ( 4B41EDAB2B1544B2001EEDF4 /* LoginItems in Frameworks */, + EE297CC52B83EF480083DB29 /* Subscription in Frameworks */, 7BEEA5122AD1235B00A9E72B /* NetworkProtectionIPC in Frameworks */, 7BA7CC5F2AD1210C0042E5CE /* Networking in Frameworks */, 7BEEA5162AD1236E00A9E72B /* NetworkProtectionUI in Frameworks */, @@ -4523,6 +4533,7 @@ 7BFCB7502ADE7E2300DA3EA7 /* PixelKit in Frameworks */, 7BA7CC612AD1211C0042E5CE /* Networking in Frameworks */, 7BEEA5142AD1236300A9E72B /* NetworkProtectionIPC in Frameworks */, + EE297CC72B83EF510083DB29 /* Subscription in Frameworks */, EE7295EF2A545C12008C0991 /* NetworkProtection in Frameworks */, 4B2D067F2A1334D700DE1F49 /* NetworkProtectionUI in Frameworks */, 4BA7C4DD2B3F64E500AFE511 /* LoginItems in Frameworks */, @@ -6620,6 +6631,7 @@ AA585D75248FD31100E9A3E2 = { isa = PBXGroup; children = ( + EEBE97B22B7E48A600404915 /* BrowserServicesKit */, 378B5886295CF2A4002C0CC0 /* Configuration */, 378E279C2970217400FCADA2 /* LocalPackages */, 7BB108552A43375D000AB95F /* LocalThirdParty */, @@ -8193,6 +8205,7 @@ 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */, 7B934C402A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift */, 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */, + EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */, ); path = AppAndExtensionAndAgentTargets; sourceTree = ""; @@ -8398,6 +8411,7 @@ 7BEC182E2AD5D8DC00D30536 /* SystemExtensionManager */, 7BFCB74D2ADE7E1A00DA3EA7 /* PixelKit */, 4B41EDAA2B1544B2001EEDF4 /* LoginItems */, + EE297CC42B83EF480083DB29 /* Subscription */, ); productName = DuckDuckGoAgent; productReference = 4B2D06392A11CFBB00DE1F49 /* DuckDuckGo VPN.app */; @@ -8427,6 +8441,7 @@ 7BEEA5132AD1236300A9E72B /* NetworkProtectionIPC */, 7BFCB74F2ADE7E2300DA3EA7 /* PixelKit */, 4BA7C4DC2B3F64E500AFE511 /* LoginItems */, + EE297CC62B83EF510083DB29 /* Subscription */, ); productName = DuckDuckGoAgentAppStore; productReference = 4B2D06692A13318400DE1F49 /* DuckDuckGo VPN App Store.app */; @@ -9724,6 +9739,7 @@ 3706FB60293F65D500E42796 /* PasswordManagementIdentityItemView.swift in Sources */, 3706FB61293F65D500E42796 /* ProgressExtension.swift in Sources */, B6F9BDD92B45B7D900677B33 /* AddBookmarkModalViewModel.swift in Sources */, + EE297CBE2B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */, 3706FB62293F65D500E42796 /* CSVParser.swift in Sources */, 3706FB64293F65D500E42796 /* PixelDataModel.xcdatamodeld in Sources */, B626A75B29921FAA00053070 /* NavigationActionPolicyExtension.swift in Sources */, @@ -10527,6 +10543,7 @@ EEC589DB2A4F1CE700BCD60C /* AppLauncher.swift in Sources */, B65DA5EF2A77CC3A00CBEE8D /* Bundle+NetworkProtectionExtensions.swift in Sources */, 4BF0E5072AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */, + EE297CC12B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */, 7BA7CC442AD11E490042E5CE /* UserText.swift in Sources */, 4BF0E5142AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, 7BA7CC422AD11E420042E5CE /* NetworkProtectionBouncer.swift in Sources */, @@ -10560,6 +10577,7 @@ 7BAF9E4D2A8A3CCB002D3B6E /* UserDefaults+NetworkProtectionShared.swift in Sources */, 7BA7CC392AD11E2D0042E5CE /* DuckDuckGoVPNAppDelegate.swift in Sources */, 7BA7CC552AD11FFB0042E5CE /* NetworkProtectionOptionKeyExtension.swift in Sources */, + EE297CC22B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */, 7BA7CC3D2AD11E380042E5CE /* TunnelControllerIPCService.swift in Sources */, 4BA7C4DA2B3F639800AFE511 /* NetworkProtectionTunnelController.swift in Sources */, 7BA7CC432AD11E480042E5CE /* UserText.swift in Sources */, @@ -11276,6 +11294,7 @@ 4B957BA12AC7AE700062CA31 /* UserDefaults+NetworkProtectionShared.swift in Sources */, 4B957BA22AC7AE700062CA31 /* NavigationActionPolicyExtension.swift in Sources */, 4B957BA32AC7AE700062CA31 /* CIImageExtension.swift in Sources */, + EE297CC32B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */, 4B957BA42AC7AE700062CA31 /* NSMenuExtension.swift in Sources */, 4B957BA52AC7AE700062CA31 /* MainWindowController.swift in Sources */, 4B957BA62AC7AE700062CA31 /* Tab.swift in Sources */, @@ -11524,6 +11543,7 @@ 4B379C2227BDBA29008A968E /* LocalAuthenticationService.swift in Sources */, 37CEFCA92A6737A2001EF741 /* CredentialsCleanupErrorHandling.swift in Sources */, 4BB99D0326FE191E001E4761 /* SafariBookmarksReader.swift in Sources */, + EE297CBD2B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */, 1DA6D0FD2A1FF9A100540406 /* HTTPCookie.swift in Sources */, AACF6FD626BC366D00CF09F9 /* SafariVersionReader.swift in Sources */, 4BE65485271FCD7B008D1D63 /* LoginFaviconView.swift in Sources */, @@ -13988,6 +14008,14 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Configuration; }; + EE297CC42B83EF480083DB29 /* Subscription */ = { + isa = XCSwiftPackageProductDependency; + productName = Subscription; + }; + EE297CC62B83EF510083DB29 /* Subscription */ = { + isa = XCSwiftPackageProductDependency; + productName = Subscription; + }; EE7295E22A545B9A008C0991 /* NetworkProtection */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; diff --git a/DuckDuckGo/InfoPlist.xcstrings b/DuckDuckGo/InfoPlist.xcstrings index 4d7c2d94c0..70d7389fb7 100644 --- a/DuckDuckGo/InfoPlist.xcstrings +++ b/DuckDuckGo/InfoPlist.xcstrings @@ -8,7 +8,7 @@ "en" : { "stringUnit" : { "state" : "new", - "value" : "DuckDuckGo" + "value" : "DuckDuckGo Privacy Pro" } } } diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index f8c8f09577..a017df7a75 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -241,7 +241,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { debugEvents: debugEvents, providerEvents: Self.packetTunnelProviderEvents, settings: settings, - subscriptionConfiguration: .init(isSubscriptionEnabled: false, isEntitlementValid: { true })) + subscriptionConfiguration: .makeConfiguration()) observeConnectionStatusChanges() observeServerChanges() @@ -416,3 +416,26 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { } } + +extension PacketTunnelProvider.SubscriptionConfiguration { +#if SUBSCRIPTION + static func makeConfiguration() -> PacketTunnelProvider.SubscriptionConfiguration { + .init( + isSubscriptionEnabled: true, + isEntitlementValid: Self.isEntitlementValid + ) + } + + static func isEntitlementValid() async -> Bool { + // todo - https://app.asana.com/0/0/1206470585910128/f + await AccountManager().hasEntitlement(for: "dummy1") + } +#else + static func makeConfiguration() -> PacketTunnelProvider.SubscriptionConfiguration { + .init( + isSubscriptionEnabled: false, + isEntitlementValid: { true } + ) + } +#endif +} diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 17fa86a972..2cdcc5a1b4 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -94,6 +94,7 @@ extension NetworkProtectionStatusView { private let runLoopMode: RunLoop.Mode? private let accountManager: SubscriptionAccountManaging + private let entitlementMonitor: NetworkProtectionEntitlementMonitor private var cancellables = Set() @@ -124,6 +125,7 @@ extension NetworkProtectionStatusView { self.agentLoginItem = agentLoginItem self.runLoopMode = runLoopMode self.accountManager = accountManager + self.entitlementMonitor = NetworkProtectionEntitlementMonitor() tunnelControllerViewModel = TunnelControllerViewModel(controller: tunnelController, onboardingStatusPublisher: onboardingStatusPublisher, @@ -151,13 +153,26 @@ extension NetworkProtectionStatusView { } .store(in: &cancellables) - Task { - if await accountManager.hasEntitlement(for: "subscriber") { - shouldShowSubscriptionExpired = false - } else { - shouldShowSubscriptionExpired = true - } - } +// Task { +// await entitlementMonitor.start { +// await accountManager.hasEntitlement(for: "subscriber") +// } callback: { [weak self] result in +// guard let self else { return } +// switch result { +// case .validEntitlement: +// self.shouldShowSubscriptionExpired = false +// case .error(let error): +// guard case .invalid = error else { break } +// self.shouldShowSubscriptionExpired = true +// } +// } +// +// if await accountManager.hasEntitlement(for: "subscriber") { +// shouldShowSubscriptionExpired = false +// } else { +// shouldShowSubscriptionExpired = true +// } +// } } func refreshLoginItemStatus() { diff --git a/Submodules/privacy-reference-tests b/Submodules/privacy-reference-tests index 6b7ad1e7f1..438faf5160 160000 --- a/Submodules/privacy-reference-tests +++ b/Submodules/privacy-reference-tests @@ -1 +1 @@ -Subproject commit 6b7ad1e7f15270f9dfeb58a272199f4d57c3eb22 +Subproject commit 438faf5160f7db0fd2f2952945a809a33a9cdbac From b7b881b9981a366945f15ee4a11332d05f85b6c3 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 26 Feb 2024 16:05:14 +0100 Subject: [PATCH 06/99] wip --- DuckDuckGo.xcodeproj/project.pbxproj | 12 ---------- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- .../View/NavigationBarViewController.swift | 1 + .../AccountManager+NetworkProtection.swift | 23 ------------------- ...rkProtection+ConvenienceInitializers.swift | 7 +++--- ...etworkProtectionNavBarPopoverManager.swift | 5 ++-- ...rkProtectionSubscriptionEventHandler.swift | 7 +++--- .../MacPacketTunnelProvider.swift | 6 ++++- .../Menu/StatusBarMenu.swift | 4 ++-- .../NetworkProtectionPopover.swift | 4 ++-- .../NetworkProtectionStatusViewModel.swift | 4 ++-- 11 files changed, 25 insertions(+), 52 deletions(-) delete mode 100644 DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AccountManager+NetworkProtection.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index f157bb453f..739f828e54 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3058,11 +3058,6 @@ EAC80DE0271F6C0100BBF02D /* fb-sdk.js in Resources */ = {isa = PBXBuildFile; fileRef = EAC80DDF271F6C0100BBF02D /* fb-sdk.js */; }; EAE42800275D47FA00DAC26B /* ClickToLoadModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE427FF275D47FA00DAC26B /* ClickToLoadModel.swift */; }; EAFAD6CA2728BD1200F9DF00 /* clickToLoad.js in Resources */ = {isa = PBXBuildFile; fileRef = EAFAD6C92728BD1200F9DF00 /* clickToLoad.js */; }; - EE297CBD2B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */; }; - EE297CBE2B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */; }; - EE297CC12B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */; }; - EE297CC22B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */; }; - EE297CC32B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */; }; EE297CC52B83EF480083DB29 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE297CC42B83EF480083DB29 /* Subscription */; }; EE297CC72B83EF510083DB29 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE297CC62B83EF510083DB29 /* Subscription */; }; EE339228291BDEFD009F62C1 /* JSAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE339227291BDEFD009F62C1 /* JSAlertController.swift */; }; @@ -4409,7 +4404,6 @@ EAC80DDF271F6C0100BBF02D /* fb-sdk.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "fb-sdk.js"; sourceTree = ""; }; EAE427FF275D47FA00DAC26B /* ClickToLoadModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClickToLoadModel.swift; sourceTree = ""; }; EAFAD6C92728BD1200F9DF00 /* clickToLoad.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = clickToLoad.js; sourceTree = ""; }; - EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountManager+NetworkProtection.swift"; sourceTree = ""; }; EE339227291BDEFD009F62C1 /* JSAlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSAlertController.swift; sourceTree = ""; }; EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationsHostingViewController.swift; sourceTree = ""; }; EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNCountryLabelsModel.swift; sourceTree = ""; }; @@ -8205,7 +8199,6 @@ 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */, 7B934C402A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift */, 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */, - EE297CBC2B83B8720083DB29 /* AccountManager+NetworkProtection.swift */, ); path = AppAndExtensionAndAgentTargets; sourceTree = ""; @@ -9739,7 +9732,6 @@ 3706FB60293F65D500E42796 /* PasswordManagementIdentityItemView.swift in Sources */, 3706FB61293F65D500E42796 /* ProgressExtension.swift in Sources */, B6F9BDD92B45B7D900677B33 /* AddBookmarkModalViewModel.swift in Sources */, - EE297CBE2B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */, 3706FB62293F65D500E42796 /* CSVParser.swift in Sources */, 3706FB64293F65D500E42796 /* PixelDataModel.xcdatamodeld in Sources */, B626A75B29921FAA00053070 /* NavigationActionPolicyExtension.swift in Sources */, @@ -10543,7 +10535,6 @@ EEC589DB2A4F1CE700BCD60C /* AppLauncher.swift in Sources */, B65DA5EF2A77CC3A00CBEE8D /* Bundle+NetworkProtectionExtensions.swift in Sources */, 4BF0E5072AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */, - EE297CC12B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */, 7BA7CC442AD11E490042E5CE /* UserText.swift in Sources */, 4BF0E5142AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, 7BA7CC422AD11E420042E5CE /* NetworkProtectionBouncer.swift in Sources */, @@ -10577,7 +10568,6 @@ 7BAF9E4D2A8A3CCB002D3B6E /* UserDefaults+NetworkProtectionShared.swift in Sources */, 7BA7CC392AD11E2D0042E5CE /* DuckDuckGoVPNAppDelegate.swift in Sources */, 7BA7CC552AD11FFB0042E5CE /* NetworkProtectionOptionKeyExtension.swift in Sources */, - EE297CC22B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */, 7BA7CC3D2AD11E380042E5CE /* TunnelControllerIPCService.swift in Sources */, 4BA7C4DA2B3F639800AFE511 /* NetworkProtectionTunnelController.swift in Sources */, 7BA7CC432AD11E480042E5CE /* UserText.swift in Sources */, @@ -11294,7 +11284,6 @@ 4B957BA12AC7AE700062CA31 /* UserDefaults+NetworkProtectionShared.swift in Sources */, 4B957BA22AC7AE700062CA31 /* NavigationActionPolicyExtension.swift in Sources */, 4B957BA32AC7AE700062CA31 /* CIImageExtension.swift in Sources */, - EE297CC32B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */, 4B957BA42AC7AE700062CA31 /* NSMenuExtension.swift in Sources */, 4B957BA52AC7AE700062CA31 /* MainWindowController.swift in Sources */, 4B957BA62AC7AE700062CA31 /* Tab.swift in Sources */, @@ -11543,7 +11532,6 @@ 4B379C2227BDBA29008A968E /* LocalAuthenticationService.swift in Sources */, 37CEFCA92A6737A2001EF741 /* CredentialsCleanupErrorHandling.swift in Sources */, 4BB99D0326FE191E001E4761 /* SafariBookmarksReader.swift in Sources */, - EE297CBD2B83B8720083DB29 /* AccountManager+NetworkProtection.swift in Sources */, 1DA6D0FD2A1FF9A100540406 /* HTTPCookie.swift in Sources */, AACF6FD626BC366D00CF09F9 /* SafariVersionReader.swift in Sources */, 4BE65485271FCD7B008D1D63 /* LoginFaviconView.swift in Sources */, diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e7d61d59d6..86989eb3e4 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/content-scope-scripts", "state" : { - "revision" : "063b560e59a50e03d9b00b88a7fcb2ed2b562395", - "version" : "4.61.0" + "revision" : "36ddba2cbac52a41b9a9275af06d32fa8a56d2d7", + "version" : "4.64.0" } }, { diff --git a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift index c2facfea75..bbe6413f7a 100644 --- a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift +++ b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift @@ -333,6 +333,7 @@ final class NavigationBarViewController: NSViewController { let accountManager = AccountManager() let networkProtectionTokenStorage = NetworkProtectionKeychainTokenStore() + // TODO: The issue is here if accountManager.accessToken != nil && (try? networkProtectionTokenStorage.fetchToken()) == nil { print("[NetP Subscription] Got access token but not auth token, meaning token exchange failed") return diff --git a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AccountManager+NetworkProtection.swift b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AccountManager+NetworkProtection.swift deleted file mode 100644 index d33ad50802..0000000000 --- a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AccountManager+NetworkProtection.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// AccountManager+NetworkProtection.swift -// -// 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 NetworkProtection -import Subscription - -extension AccountManager: SubscriptionAccountManaging {} diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift index 8ed6ccc832..60d1d5d32a 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift @@ -32,7 +32,8 @@ extension NetworkProtectionDeviceManager { environment: settings.selectedEnvironment, tokenStore: tokenStore, keyStore: keyStore, - errorEvents: .networkProtectionAppDebugEvents, subscriptionConfiguration: .init(isSubscriptionEnabled: false, isEntitlementValid: { true }) + errorEvents: .networkProtectionAppDebugEvents, + isSubscriptionEnabled: true ) } } @@ -43,7 +44,7 @@ extension NetworkProtectionCodeRedemptionCoordinator { self.init(environment: settings.selectedEnvironment, tokenStore: NetworkProtectionKeychainTokenStore(), errorEvents: .networkProtectionAppDebugEvents, - isSubscriptionEnabled: false) + isSubscriptionEnabled: true) } } @@ -51,7 +52,7 @@ extension NetworkProtectionKeychainTokenStore { convenience init() { self.init(keychainType: .default, errorEvents: .networkProtectionAppDebugEvents, - isSubscriptionEnabled: false) + isSubscriptionEnabled: true) } } diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index 30a2d6eac4..3136c827de 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -86,8 +86,9 @@ final class NetworkProtectionNavBarPopoverManager { return menuItems }, agentLoginItem: LoginItem.vpnMenu, - accountManager: AccountManager() - ) + entitlementCheck: { + await AccountManager().hasEntitlement(for: .networkProtection) + }) popover.delegate = delegate networkProtectionPopover = popover diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift index 7ad69d346b..3dcac1a162 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift @@ -52,10 +52,11 @@ final class NetworkProtectionSubscriptionEventHandler { Task { do { - try await networkProtectionRedemptionCoordinator.exchange(accessToken: token) - print("[NetP Subscription] Exchanged access token for auth token successfully") + // todo - https://app.asana.com/0/0/1206541966681608/f + try NetworkProtectionKeychainTokenStore().store(NetworkProtectionKeychainTokenStore.makeToken(from: token)) + print("[NetP Subscription] Stored derived NetP auth token") } catch { - print("[NetP Subscription] Failed to exchange access token for auth token: \(error)") + print("[NetP Subscription] Failed to store derived NetP auth token: \(error)") } } } diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index a017df7a75..4031bfa7ea 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -23,6 +23,7 @@ import NetworkProtection import NetworkExtension import Networking import PixelKit +import Subscription final class MacPacketTunnelProvider: PacketTunnelProvider { @@ -241,7 +242,10 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { debugEvents: debugEvents, providerEvents: Self.packetTunnelProviderEvents, settings: settings, - subscriptionConfiguration: .makeConfiguration()) + isSubscriptionEnabled: true, + entitlementCheck: { + await AccountManager().hasEntitlement(for: .networkProtection) + }) observeConnectionStatusChanges() observeServerChanges() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift index 16728c88f5..af151712fd 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift @@ -56,7 +56,7 @@ public final class StatusBarMenu: NSObject { appLauncher: AppLaunching, menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, - accountManager: SubscriptionAccountManaging) { + entitlementCheck: @escaping () async -> Swift.Result) { self.model = model let statusItem = statusItem ?? NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) @@ -69,7 +69,7 @@ public final class StatusBarMenu: NSObject { appLauncher: appLauncher, menuItems: menuItems, agentLoginItem: agentLoginItem, - accountManager: accountManager) + entitlementCheck: entitlementCheck) popover.behavior = .transient diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift index 39cf32e29c..16d892aa18 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift @@ -56,7 +56,7 @@ public final class NetworkProtectionPopover: NSPopover { appLauncher: AppLaunching, menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, - accountManager: SubscriptionAccountManaging) { + entitlementCheck: @escaping () async -> Swift.Result) { self.statusReporter = statusReporter self.model = NetworkProtectionStatusView.Model(controller: controller, @@ -66,7 +66,7 @@ public final class NetworkProtectionPopover: NSPopover { appLauncher: appLauncher, menuItems: menuItems, agentLoginItem: agentLoginItem, - accountManager: accountManager) + entitlementCheck: entitlementCheck) super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 2cdcc5a1b4..590a640adf 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -93,7 +93,7 @@ extension NetworkProtectionStatusView { /// private let runLoopMode: RunLoop.Mode? - private let accountManager: SubscriptionAccountManaging + private let entitlementCheck: @escaping () async -> Swift.Result private let entitlementMonitor: NetworkProtectionEntitlementMonitor private var cancellables = Set() @@ -115,7 +115,7 @@ extension NetworkProtectionStatusView { menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, runLoopMode: RunLoop.Mode? = nil, - accountManager: SubscriptionAccountManaging) { + entitlementCheck: @escaping () async -> Swift.Result) { self.tunnelController = controller self.onboardingStatusPublisher = onboardingStatusPublisher From 1d2744b1628f4c465799659550b68b6412bab8bc Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:34:45 +0100 Subject: [PATCH 07/99] Get it compiling again --- .../MacPacketTunnelProvider.swift | 28 ++++++--------- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 6 ++-- .../NetworkProtectionPopover.swift | 3 +- .../NetworkProtectionStatusViewModel.swift | 35 +++++++------------ Submodules/privacy-reference-tests | 2 +- 5 files changed, 30 insertions(+), 44 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 1761171e92..2914dc8726 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -23,7 +23,7 @@ import NetworkProtection import NetworkExtension import Networking import PixelKit -import Subscription +// import Subscription final class MacPacketTunnelProvider: PacketTunnelProvider { @@ -244,7 +244,11 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { settings: settings, isSubscriptionEnabled: true, entitlementCheck: { +#if SUBSCRIPTION && NETP_SYSTEM_EXTENSION await AccountManager().hasEntitlement(for: .networkProtection) +#else + return .success(true) +#endif }) observeServerChanges() @@ -424,27 +428,15 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { } } -} - -extension PacketTunnelProvider.SubscriptionConfiguration { -#if SUBSCRIPTION - static func makeConfiguration() -> PacketTunnelProvider.SubscriptionConfiguration { - .init( - isSubscriptionEnabled: true, - isEntitlementValid: Self.isEntitlementValid - ) - } - +#if SUBSCRIPTION && NETP_SYSTEM_EXTENSION static func isEntitlementValid() async -> Bool { // todo - https://app.asana.com/0/0/1206470585910128/f - await AccountManager().hasEntitlement(for: "dummy1") + await AccountManager().hasEntitlement(for: .networkProtection) } #else - static func makeConfiguration() -> PacketTunnelProvider.SubscriptionConfiguration { - .init( - isSubscriptionEnabled: false, - isEntitlementValid: { true } - ) + static func isEntitlementValid() async -> Bool { + return false } #endif + } diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index f17dcf0c50..4ae7e6bbc1 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -131,7 +131,7 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { }() private func handleControllerEvent(_ event: TransparentProxyController.Event) { - PixelKit.fire(event) + } @MainActor @@ -233,7 +233,9 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { }, agentLoginItem: nil, isMenuBarStatusView: true, - accountManager: AccountManager() + entitlementCheck: { + return await AccountManager().hasEntitlement(for: .networkProtection) + }) } @MainActor diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift index 692ee624bd..59dba8a458 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift @@ -67,7 +67,8 @@ public final class NetworkProtectionPopover: NSPopover { appLauncher: appLauncher, menuItems: menuItems, agentLoginItem: agentLoginItem, - isMenuBarStatusView: isMenuBarStatusView) + isMenuBarStatusView: isMenuBarStatusView, + entitlementCheck: entitlementCheck) super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 7fc33022b7..912d75807b 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -94,7 +94,6 @@ extension NetworkProtectionStatusView { /// private let runLoopMode: RunLoop.Mode? - private let entitlementCheck: @escaping () async -> Swift.Result private let entitlementMonitor: NetworkProtectionEntitlementMonitor private var cancellables = Set() @@ -127,7 +126,6 @@ extension NetworkProtectionStatusView { self.agentLoginItem = agentLoginItem self.isMenuBarStatusView = isMenuBarStatusView self.runLoopMode = runLoopMode - self.accountManager = accountManager self.entitlementMonitor = NetworkProtectionEntitlementMonitor() tunnelControllerViewModel = TunnelControllerViewModel(controller: tunnelController, @@ -156,26 +154,19 @@ extension NetworkProtectionStatusView { } .store(in: &cancellables) -// Task { -// await entitlementMonitor.start { -// await accountManager.hasEntitlement(for: "subscriber") -// } callback: { [weak self] result in -// guard let self else { return } -// switch result { -// case .validEntitlement: -// self.shouldShowSubscriptionExpired = false -// case .error(let error): -// guard case .invalid = error else { break } -// self.shouldShowSubscriptionExpired = true -// } -// } -// -// if await accountManager.hasEntitlement(for: "subscriber") { -// shouldShowSubscriptionExpired = false -// } else { -// shouldShowSubscriptionExpired = true -// } -// } + Task { + await entitlementMonitor.start(entitlementCheck: entitlementCheck) { [weak self] result in + guard let self else { return } + switch result { + case .validEntitlement: + self.shouldShowSubscriptionExpired = false + case .invalidEntitlement: + self.shouldShowSubscriptionExpired = true + case .error: + break + } + } + } } func refreshLoginItemStatus() { diff --git a/Submodules/privacy-reference-tests b/Submodules/privacy-reference-tests index 40ce86837d..438faf5160 160000 --- a/Submodules/privacy-reference-tests +++ b/Submodules/privacy-reference-tests @@ -1 +1 @@ -Subproject commit 40ce86837def0adbf558f00ed0531ab4df5839a8 +Subproject commit 438faf5160f7db0fd2f2952945a809a33a9cdbac From 52f17d407f511d0015ba321ee384f466774d58ba Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:16:59 +0100 Subject: [PATCH 08/99] Update to handle recent merge from Anh --- .../BothAppTargets/NetworkProtectionTunnelController.swift | 2 +- .../NetworkProtectionUNNotificationsPresenter.swift | 2 +- .../NetworkProtectionAgentNotificationsPresenter.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index 7ae6baff7e..c50b3d4e0e 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -242,7 +242,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr .setDisableRekeying: // Intentional no-op as this is handled by the extension or the agent's app delegate break - case .setShouldShowExpiredEntitlementMessaging: + case .setShowEntitlementAlert, .setShowEntitlementNotification: // TODO: Handle this break } diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift index 998ca2d878..7ee5c960ac 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift @@ -134,7 +134,7 @@ final class NetworkProtectionUNNotificationsPresenter: NSObject, NetworkProtecti showNotification(.superseded, content) } - func showExpiredEntitlementNotification() { + func showEntitlementNotification(completion: @escaping (Error?) -> Void) { let content = notificationContent(title: UserText.networkProtectionEntitlementExpiredNotificationTitle, subtitle: UserText.networkProtectionEntitlementExpiredNotificationBody) showNotification(.expiredEntitlement, content) diff --git a/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift b/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift index 68edf3d446..7c5e7813b1 100644 --- a/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift +++ b/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift @@ -48,7 +48,7 @@ final class NetworkProtectionAgentNotificationsPresenter: NetworkProtectionNotif notificationCenter.post(.showVPNSupersededNotification) } - func showExpiredEntitlementNotification() { + func showEntitlementNotification(completion: @escaping (Error?) -> Void) { notificationCenter.post(.showExpiredEntitlementNotification) } From fed430ba935ba17b09b11a0351d9f827ae00d990 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:29:45 +0100 Subject: [PATCH 09/99] Use subscription app group for AccountManager --- Configuration/AppStore.xcconfig | 6 +++ Configuration/DeveloperID.xcconfig | 6 +++ DuckDuckGo/Application/AppDelegate.swift | 1 + .../Common/Extensions/BundleExtension.swift | 3 ++ DuckDuckGo/DuckDuckGo.entitlements | 1 + DuckDuckGo/DuckDuckGoAppStore.entitlements | 1 + DuckDuckGo/DuckDuckGoDebug.entitlements | 1 + DuckDuckGo/Info.plist | 54 ++++++++++--------- DuckDuckGo/Menus/MainMenu.swift | 2 +- .../NetworkProtectionTunnelController.swift | 12 ++++- ...NetworkProtectionAppExtension.entitlements | 1 + .../View/PreferencesRootView.swift | 12 ++++- .../SubscriptionPagesUserScript.swift | 12 ++--- DuckDuckGoVPN/DuckDuckGoVPN.entitlements | 3 +- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 9 +++- .../DuckDuckGoVPNAppStore.entitlements | 1 + DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements | 3 +- DuckDuckGoVPN/Info-AppStore.plist | 2 + DuckDuckGoVPN/Info.plist | 2 + .../DebugMenu/DebugPurchaseModel.swift | 9 ++-- .../DebugPurchaseViewController.swift | 4 +- .../DebugMenu/SubscriptionDebugMenu.swift | 13 +++-- .../PreferencesSubscriptionModel.swift | 14 ++--- .../Model/ShareSubscriptionAccessModel.swift | 6 ++- .../SubscriptionAccessViewController.swift | 6 ++- NetworkProtectionAppExtension/Info.plist | 2 + 26 files changed, 127 insertions(+), 59 deletions(-) diff --git a/Configuration/AppStore.xcconfig b/Configuration/AppStore.xcconfig index 0ad3f9f6b5..7095b66b0b 100644 --- a/Configuration/AppStore.xcconfig +++ b/Configuration/AppStore.xcconfig @@ -41,6 +41,12 @@ NETP_APP_GROUP[config=Review][sdk=macos*] = $(NETP_BASE_APP_GROUP).review NETP_APP_GROUP[config=Debug][sdk=macos*] = $(NETP_BASE_APP_GROUP).debug NETP_APP_GROUP[config=Release][sdk=macos*] = $(NETP_BASE_APP_GROUP) +SUBSCRIPTION_BASE_APP_GROUP = $(DEVELOPMENT_TEAM).com.duckduckgo.macos.browser.subscription +SUBSCRIPTION_APP_GROUP[config=CI][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).debug +SUBSCRIPTION_APP_GROUP[config=Review][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).review +SUBSCRIPTION_APP_GROUP[config=Debug][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).debug +SUBSCRIPTION_APP_GROUP[config=Release][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP) + AGENT_BUNDLE_ID_BASE[sdk=*] = com.duckduckgo.mobile.ios.vpn.agent AGENT_BUNDLE_ID[sdk=*] = $(AGENT_BUNDLE_ID_BASE) AGENT_BUNDLE_ID[config=Debug][sdk=*] = $(AGENT_BUNDLE_ID_BASE).debug diff --git a/Configuration/DeveloperID.xcconfig b/Configuration/DeveloperID.xcconfig index b66acc76d2..e5d9ed5daa 100644 --- a/Configuration/DeveloperID.xcconfig +++ b/Configuration/DeveloperID.xcconfig @@ -45,6 +45,12 @@ NETP_APP_GROUP[config=Review][sdk=*] = $(NETP_BASE_APP_GROUP).review NETP_APP_GROUP[config=Debug][sdk=*] = $(NETP_BASE_APP_GROUP).debug NETP_APP_GROUP[config=Release][sdk=*] = $(NETP_BASE_APP_GROUP) +SUBSCRIPTION_BASE_APP_GROUP = $(DEVELOPMENT_TEAM).com.duckduckgo.macos.browser.subscription +SUBSCRIPTION_APP_GROUP[config=CI][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).debug +SUBSCRIPTION_APP_GROUP[config=Review][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).review +SUBSCRIPTION_APP_GROUP[config=Debug][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).debug +SUBSCRIPTION_APP_GROUP[config=Release][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP) + SYSEX_MACH_SERVICE_NAME[sdk=*] = $(NETP_APP_GROUP).ipc SYSEX_MACH_SERVICE_NAME[config=CI][sdk=*] = $(NETP_APP_GROUP).ipc SYSEX_MACH_SERVICE_NAME[config=Review][sdk=*] = $(NETP_APP_GROUP).ipc diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index 95f1317564..e2cf76948f 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -286,6 +286,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel #else SubscriptionPurchaseEnvironment.current = .appStore #endif + SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging await AccountManager().checkSubscriptionState() } #endif diff --git a/DuckDuckGo/Common/Extensions/BundleExtension.swift b/DuckDuckGo/Common/Extensions/BundleExtension.swift index 7fceb79361..0a9fbafcf6 100644 --- a/DuckDuckGo/Common/Extensions/BundleExtension.swift +++ b/DuckDuckGo/Common/Extensions/BundleExtension.swift @@ -102,6 +102,8 @@ extension Bundle { appGroupName = "DBP_APP_GROUP" case .netP: appGroupName = "NETP_APP_GROUP" + case .subs: + appGroupName = "SUBSCRIPTION_APP_GROUP" } guard let appGroup = object(forInfoDictionaryKey: appGroupName) as? String else { @@ -128,4 +130,5 @@ extension Bundle { enum BundleGroup { case netP case dbp + case subs } diff --git a/DuckDuckGo/DuckDuckGo.entitlements b/DuckDuckGo/DuckDuckGo.entitlements index 757dc88e2c..3b77ae2b3a 100644 --- a/DuckDuckGo/DuckDuckGo.entitlements +++ b/DuckDuckGo/DuckDuckGo.entitlements @@ -28,6 +28,7 @@ $(AppIdentifierPrefix)com.duckduckgo.macos.browser $(NETP_APP_GROUP) $(DBP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) diff --git a/DuckDuckGo/DuckDuckGoAppStore.entitlements b/DuckDuckGo/DuckDuckGoAppStore.entitlements index 97443cb452..b4153637dd 100644 --- a/DuckDuckGo/DuckDuckGoAppStore.entitlements +++ b/DuckDuckGo/DuckDuckGoAppStore.entitlements @@ -55,6 +55,7 @@ $(DBP_APP_GROUP) $(AppIdentifierPrefix)com.duckduckgo.mobile.ios $(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) diff --git a/DuckDuckGo/DuckDuckGoDebug.entitlements b/DuckDuckGo/DuckDuckGoDebug.entitlements index dad1686cba..ae4d67533b 100644 --- a/DuckDuckGo/DuckDuckGoDebug.entitlements +++ b/DuckDuckGo/DuckDuckGoDebug.entitlements @@ -27,6 +27,7 @@ $(AppIdentifierPrefix)com.duckduckgo.macos.browser $(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) $(DBP_APP_GROUP) diff --git a/DuckDuckGo/Info.plist b/DuckDuckGo/Info.plist index a1b9b583bb..8c7dca0e52 100644 --- a/DuckDuckGo/Info.plist +++ b/DuckDuckGo/Info.plist @@ -2,8 +2,10 @@ - NSPrincipalClass - $(INFOPLIST_KEY_NSPrincipalClass) + AGENT_BUNDLE_ID + $(AGENT_BUNDLE_ID) + AGENT_PRODUCT_NAME + $(AGENT_PRODUCT_NAME) CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDocumentTypes @@ -77,10 +79,28 @@ CFBundleVersion $(CURRENT_PROJECT_VERSION) + DBP_APP_GROUP + $(DBP_APP_GROUP) + DBP_BACKGROUND_AGENT_BUNDLE_ID + $(DBP_BACKGROUND_AGENT_BUNDLE_ID) + DBP_BACKGROUND_AGENT_PRODUCT_NAME + $(DBP_BACKGROUND_AGENT_PRODUCT_NAME) + DISTRIBUTED_NOTIFICATIONS_PREFIX + $(DISTRIBUTED_NOTIFICATIONS_PREFIX) + ITSAppUsesNonExemptEncryption + LSApplicationCategoryType public.app-category.productivity LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) + NETP_APP_GROUP + $(NETP_APP_GROUP) + NOTIFICATIONS_AGENT_BUNDLE_ID + $(NOTIFICATIONS_AGENT_BUNDLE_ID) + NOTIFICATIONS_AGENT_PRODUCT_NAME + $(NOTIFICATIONS_AGENT_PRODUCT_NAME) + NSAppDataUsageDescription + DuckDuckGo will securely access your Bitwarden vault to autofill your passwords. To prevent this dialog in the future, go to Mac System Settings > Privacy & Security > Full Disk Access and toggle DuckDuckGo on, or switch back to the built-in password manager. NSAppTransportSecurity NSAllowsArbitraryLoadsInWebContent @@ -96,43 +116,25 @@ Allows you to share your location NSMicrophoneUsageDescription Allows you to share recordings - NSAppDataUsageDescription - DuckDuckGo will securely access your Bitwarden vault to autofill your passwords. To prevent this dialog in the future, go to Mac System Settings > Privacy & Security > Full Disk Access and toggle DuckDuckGo on, or switch back to the built-in password manager. + NSPrincipalClass + $(INFOPLIST_KEY_NSPrincipalClass) NSSupportsAutomaticTermination NSSupportsSuddenTermination SUAllowsAutomaticUpdates + SUBSCRIPTION_APP_GROUP + $(SUBSCRIPTION_APP_GROUP) SUEnableAutomaticChecks SUFeedURL https://staticcdn.duckduckgo.com/macos-desktop-browser/appcast2.xml - SUScheduledCheckInterval - 10800 SUPublicEDKey ZaO/DNMzMPBldh40b5xVrpNBmqRkuGY0BNRCUng2qRo= + SUScheduledCheckInterval + 10800 ViewBridgeService - ITSAppUsesNonExemptEncryption - - NOTIFICATIONS_AGENT_BUNDLE_ID - $(NOTIFICATIONS_AGENT_BUNDLE_ID) - NOTIFICATIONS_AGENT_PRODUCT_NAME - $(NOTIFICATIONS_AGENT_PRODUCT_NAME) - AGENT_BUNDLE_ID - $(AGENT_BUNDLE_ID) - AGENT_PRODUCT_NAME - $(AGENT_PRODUCT_NAME) - NETP_APP_GROUP - $(NETP_APP_GROUP) - DBP_APP_GROUP - $(DBP_APP_GROUP) - DISTRIBUTED_NOTIFICATIONS_PREFIX - $(DISTRIBUTED_NOTIFICATIONS_PREFIX) - DBP_BACKGROUND_AGENT_BUNDLE_ID - $(DBP_BACKGROUND_AGENT_BUNDLE_ID) - DBP_BACKGROUND_AGENT_PRODUCT_NAME - $(DBP_BACKGROUND_AGENT_PRODUCT_NAME) diff --git a/DuckDuckGo/Menus/MainMenu.swift b/DuckDuckGo/Menus/MainMenu.swift index 7cf629775f..6e0aab64ed 100644 --- a/DuckDuckGo/Menus/MainMenu.swift +++ b/DuckDuckGo/Menus/MainMenu.swift @@ -593,7 +593,7 @@ import SubscriptionUI #if SUBSCRIPTION SubscriptionDebugMenu(currentViewController: { WindowControllersManager.shared.lastKeyMainWindowController?.mainViewController - }) + }, appGroup: Bundle.main.appGroup(bundle: .subs)) #endif NSMenuItem(title: "Logging").submenu(setupLoggingMenu()) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index c50b3d4e0e..1a65fc2039 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -29,6 +29,8 @@ import NetworkProtectionUI import Networking import PixelKit +import Subscription + #if NETP_SYSTEM_EXTENSION import SystemExtensionManager import SystemExtensions @@ -43,6 +45,8 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr let settings: VPNSettings + let accountManager = AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)) + // MARK: - Combine Cancellables private var cancellables = Set() @@ -503,7 +507,13 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr var options = [String: NSObject]() options[NetworkProtectionOptionKey.activationAttemptId] = UUID().uuidString as NSString - options[NetworkProtectionOptionKey.authToken] = try tokenStore.fetchToken() as NSString? + if let accessToken = accountManager.accessToken { + os_log(.error, log: .networkProtection, "🟢 TunnelController found token: %{public}d", accessToken) + options[NetworkProtectionOptionKey.authToken] = NetworkProtectionKeychainTokenStore.makeToken(from: accessToken) as NSString? + } else { + os_log(.error, log: .networkProtection, "🔴 TunnelController found no token :(") + options[NetworkProtectionOptionKey.authToken] = try tokenStore.fetchToken() as NSString? + } options[NetworkProtectionOptionKey.selectedEnvironment] = settings.selectedEnvironment.rawValue as NSString options[NetworkProtectionOptionKey.selectedServer] = settings.selectedServer.stringValue as? NSString diff --git a/DuckDuckGo/NetworkProtectionAppExtension.entitlements b/DuckDuckGo/NetworkProtectionAppExtension.entitlements index d37610bb07..e2ec46d330 100644 --- a/DuckDuckGo/NetworkProtectionAppExtension.entitlements +++ b/DuckDuckGo/NetworkProtectionAppExtension.entitlements @@ -26,6 +26,7 @@ $(AppIdentifierPrefix)com.duckduckgo.mobile.ios $(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) diff --git a/DuckDuckGo/Preferences/View/PreferencesRootView.swift b/DuckDuckGo/Preferences/View/PreferencesRootView.swift index 2e298e833d..1233bfc89b 100644 --- a/DuckDuckGo/Preferences/View/PreferencesRootView.swift +++ b/DuckDuckGo/Preferences/View/PreferencesRootView.swift @@ -121,13 +121,21 @@ enum Preferences { openURLHandler: openURL, goToSyncPreferences: { self.model.selectPane(.sync) }) - return PreferencesSubscriptionModel(openURLHandler: openURL, - sheetActionHandler: sheetActionHandler) + return PreferencesSubscriptionModel(accountManager: AccountManager(), + openURLHandler: openURL, + sheetActionHandler: sheetActionHandler, + subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) } #endif } } +public extension AccountManager { + convenience init() { + self.init(appGroup: Bundle.main.appGroup(bundle: .subs)) + } +} + struct SyncView: View { var body: some View { diff --git a/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift b/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift index e534521982..dd2a71ae42 100644 --- a/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift +++ b/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift @@ -226,7 +226,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { let emailAccessToken = try? EmailManager().getToken() os_log(.info, log: .subscription, "[Purchase] Purchasing") - switch await AppStorePurchaseFlow.purchaseSubscription(with: subscriptionSelection.id, emailAccessToken: emailAccessToken) { + switch await AppStorePurchaseFlow.purchaseSubscription(with: subscriptionSelection.id, emailAccessToken: emailAccessToken, subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) { case .success: break case .failure(let error): @@ -239,7 +239,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { os_log(.info, log: .subscription, "[Purchase] Completing purchase") - switch await AppStorePurchaseFlow.completeSubscriptionPurchase() { + switch await AppStorePurchaseFlow.completeSubscriptionPurchase(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) { case .success(let purchaseUpdate): await pushPurchaseUpdate(originalMessage: message, purchaseUpdate: purchaseUpdate) case .failure(let error): @@ -270,7 +270,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { WindowControllersManager.shared.show(url: .settingsPane(.sync), source: .ui, newTab: true) }) - let vc = SubscriptionAccessViewController(actionHandlers: actionHandlers) + let vc = SubscriptionAccessViewController(accountManager: AccountManager(), actionHandlers: actionHandlers, subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) WindowControllersManager.shared.lastKeyMainWindowController?.mainViewController.presentAsSheet(vc) } @@ -317,7 +317,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { let progressViewController = await ProgressViewController(title: UserText.completingPurchaseTitle) await mainViewController?.presentAsSheet(progressViewController) - await StripePurchaseFlow.completeSubscriptionPurchase() + await StripePurchaseFlow.completeSubscriptionPurchase(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) await mainViewController?.dismiss(progressViewController) return [String: String]() // cannot be nil @@ -354,7 +354,7 @@ extension SubscriptionPagesUseSubscriptionFeature { guard case .success = await PurchaseManager.shared.syncAppleIDAccount() else { return } - switch await AppStoreRestoreFlow.restoreAccountFromPastPurchase() { + switch await AppStoreRestoreFlow.restoreAccountFromPastPurchase(appGroup: Bundle.main.appGroup(bundle: .subs)) { case .success: onSuccessHandler() case .failure(let error): @@ -411,7 +411,7 @@ extension MainWindowController { window.show(.subscriptionFoundAlert(), firstButtonAction: { if #available(macOS 12.0, *) { Task { - _ = await AppStoreRestoreFlow.restoreAccountFromPastPurchase() + _ = await AppStoreRestoreFlow.restoreAccountFromPastPurchase(appGroup: Bundle.main.appGroup(bundle: .subs)) originalMessage.webView?.reload() } } diff --git a/DuckDuckGoVPN/DuckDuckGoVPN.entitlements b/DuckDuckGoVPN/DuckDuckGoVPN.entitlements index 2797c3f947..90d49dddf5 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPN.entitlements +++ b/DuckDuckGoVPN/DuckDuckGoVPN.entitlements @@ -15,7 +15,8 @@ keychain-access-groups - $(NETP_APP_GROUP) + $(AppIdentifierPrefix)$(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 4ae7e6bbc1..ac7ce84671 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -44,6 +44,13 @@ final class DuckDuckGoVPNApplication: NSApplication { super.init() self.delegate = _delegate + let accountManager = AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)) + + if let token = accountManager.accessToken { + os_log(.error, log: .networkProtection, "🟢 VPN Agent found token: %{public}d", token) + } else { + os_log(.error, log: .networkProtection, "🔴 VPN Agent found no token") + } } required init?(coder: NSCoder) { @@ -234,7 +241,7 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { agentLoginItem: nil, isMenuBarStatusView: true, entitlementCheck: { - return await AccountManager().hasEntitlement(for: .networkProtection) + return await AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)).hasEntitlement(for: .networkProtection) }) } diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppStore.entitlements b/DuckDuckGoVPN/DuckDuckGoVPNAppStore.entitlements index 7d375721de..5e706138b5 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppStore.entitlements +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppStore.entitlements @@ -11,6 +11,7 @@ keychain-access-groups $(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) com.apple.security.application-groups diff --git a/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements b/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements index f531d0bc0c..2699e730cf 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements +++ b/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements @@ -15,7 +15,8 @@ keychain-access-groups - $(NETP_APP_GROUP) + $(AppIdentifierPrefix)$(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) diff --git a/DuckDuckGoVPN/Info-AppStore.plist b/DuckDuckGoVPN/Info-AppStore.plist index a1b2b02a02..26b434800b 100644 --- a/DuckDuckGoVPN/Info-AppStore.plist +++ b/DuckDuckGoVPN/Info-AppStore.plist @@ -8,6 +8,8 @@ $(NETP_APP_GROUP) PROXY_EXTENSION_BUNDLE_ID $(PROXY_EXTENSION_BUNDLE_ID) + SUBSCRIPTION_APP_GROUP + $(SUBSCRIPTION_APP_GROUP) TUNNEL_EXTENSION_BUNDLE_ID $(TUNNEL_EXTENSION_BUNDLE_ID) LSApplicationCategoryType diff --git a/DuckDuckGoVPN/Info.plist b/DuckDuckGoVPN/Info.plist index a1b2b02a02..26b434800b 100644 --- a/DuckDuckGoVPN/Info.plist +++ b/DuckDuckGoVPN/Info.plist @@ -8,6 +8,8 @@ $(NETP_APP_GROUP) PROXY_EXTENSION_BUNDLE_ID $(PROXY_EXTENSION_BUNDLE_ID) + SUBSCRIPTION_APP_GROUP + $(SUBSCRIPTION_APP_GROUP) TUNNEL_EXTENSION_BUNDLE_ID $(TUNNEL_EXTENSION_BUNDLE_ID) LSApplicationCategoryType diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift index 273a043618..a8fa790ff5 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift @@ -24,13 +24,16 @@ import Subscription public final class DebugPurchaseModel: ObservableObject { var purchaseManager: PurchaseManager - var accountManager: AccountManager = AccountManager() + var accountManager: AccountManager + private let subscriptionAppGroup: String @Published var subscriptions: [SubscriptionRowModel] - init(manager: PurchaseManager, subscriptions: [SubscriptionRowModel] = []) { + init(manager: PurchaseManager, subscriptions: [SubscriptionRowModel] = [], subscriptionAppGroup: String) { self.purchaseManager = manager self.subscriptions = subscriptions + self.subscriptionAppGroup = subscriptionAppGroup + self.accountManager = AccountManager(appGroup: subscriptionAppGroup) } @MainActor @@ -38,7 +41,7 @@ public final class DebugPurchaseModel: ObservableObject { print("Attempting purchase: \(product.displayName)") Task { - await AppStorePurchaseFlow.purchaseSubscription(with: product.id, emailAccessToken: nil) + await AppStorePurchaseFlow.purchaseSubscription(with: product.id, emailAccessToken: nil, subscriptionAppGroup: subscriptionAppGroup) } } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseViewController.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseViewController.swift index 0d9c34bcbb..1573bec52e 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseViewController.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseViewController.swift @@ -34,9 +34,9 @@ public final class DebugPurchaseViewController: NSViewController { fatalError("init(coder:) has not been implemented") } - public init() { + public init(subscriptionAppGroup: String) { manager = PurchaseManager.shared - model = DebugPurchaseModel(manager: manager) + model = DebugPurchaseModel(manager: manager, subscriptionAppGroup: subscriptionAppGroup) super.init(nibName: nil, bundle: nil) } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift index fcba4739e3..7fda15eacb 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift @@ -22,7 +22,8 @@ import Subscription public final class SubscriptionDebugMenu: NSMenuItem { var currentViewController: () -> NSViewController? - private let accountManager = AccountManager() + private let accountManager: AccountManager + private let appGroup: String private var _purchaseManager: Any? @available(macOS 12.0, *) @@ -38,8 +39,10 @@ public final class SubscriptionDebugMenu: NSMenuItem { fatalError("init(coder:) has not been implemented") } - public init(currentViewController: @escaping () -> NSViewController?) { + public init(currentViewController: @escaping () -> NSViewController?, appGroup: String) { self.currentViewController = currentViewController + self.accountManager = AccountManager(appGroup: appGroup) + self.appGroup = appGroup super.init(title: "Subscription", action: nil, keyEquivalent: "") self.submenu = submenuItem } @@ -105,7 +108,7 @@ public final class SubscriptionDebugMenu: NSMenuItem { let entitlements: [AccountManager.Entitlement] = [.networkProtection, .dataBrokerProtection, .identityTheftRestoration] for entitlement in entitlements { - if case let .success(result) = await AccountManager().hasEntitlement(for: entitlement) { + if case let .success(result) = await accountManager.hasEntitlement(for: entitlement) { let resultSummary = "Entitlement check for \(entitlement.rawValue): \(result)" results.append(resultSummary) print(resultSummary) @@ -141,7 +144,7 @@ public final class SubscriptionDebugMenu: NSMenuItem { func restorePurchases(_ sender: Any?) { if #available(macOS 12.0, *) { Task { - await AppStoreRestoreFlow.restoreAccountFromPastPurchase() + await AppStoreRestoreFlow.restoreAccountFromPastPurchase(appGroup: appGroup) } } } @@ -171,7 +174,7 @@ public final class SubscriptionDebugMenu: NSMenuItem { @IBAction func showPurchaseView(_ sender: Any?) { if #available(macOS 12.0, *) { - currentViewController()?.presentAsSheet(DebugPurchaseViewController()) + currentViewController()?.presentAsSheet(DebugPurchaseViewController(subscriptionAppGroup: appGroup)) } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift index 22ab992e79..b126d20a10 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift @@ -32,16 +32,18 @@ public final class PreferencesSubscriptionModel: ObservableObject { private let accountManager: AccountManager private let openURLHandler: (URL) -> Void private let sheetActionHandler: SubscriptionAccessActionHandlers + private let subscriptionAppGroup: String private var fetchSubscriptionDetailsTask: Task<(), Never>? private var signInObserver: Any? private var signOutObserver: Any? - public init(accountManager: AccountManager = AccountManager(), openURLHandler: @escaping (URL) -> Void, sheetActionHandler: SubscriptionAccessActionHandlers) { + public init(accountManager: AccountManager, openURLHandler: @escaping (URL) -> Void, sheetActionHandler: SubscriptionAccessActionHandlers, subscriptionAppGroup: String) { self.accountManager = accountManager self.openURLHandler = openURLHandler self.sheetActionHandler = sheetActionHandler + self.subscriptionAppGroup = subscriptionAppGroup self.isUserAuthenticated = accountManager.isUserAuthenticated @@ -70,7 +72,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { private func makeSubscriptionAccessModel() -> SubscriptionAccessModel { if accountManager.isUserAuthenticated { - ShareSubscriptionAccessModel(actionHandlers: sheetActionHandler, email: accountManager.email) + ShareSubscriptionAccessModel(actionHandlers: sheetActionHandler, email: accountManager.email, appGroup: subscriptionAppGroup) } else { ActivateSubscriptionAccessModel(actionHandlers: sheetActionHandler) } @@ -120,7 +122,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { NSWorkspace.shared.open(.manageSubscriptionsInAppStoreAppURL) case .stripe: Task { - guard let accessToken = AccountManager().accessToken, let externalID = AccountManager().externalID, + guard let accessToken = accountManager.accessToken, let externalID = accountManager.externalID, case let .success(response) = await SubscriptionService.getCustomerPortalURL(accessToken: accessToken, externalID: externalID) else { return } guard let customerPortalURL = URL(string: response.customerPortalUrl) else { return } @@ -135,7 +137,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { switch await AuthService.storeLogin(signature: lastTransactionJWSRepresentation) { case .success(let response): - return response.externalID == AccountManager().externalID + return response.externalID == accountManager.externalID case .failure: return false } @@ -190,7 +192,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { if case .success(let response) = await SubscriptionService.getSubscriptionDetails(token: token) { if !response.isSubscriptionActive { - AccountManager().signOut() + self?.accountManager.signOut() return } @@ -199,7 +201,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { self?.subscriptionPlatform = response.platform } - if case let .success(entitlements) = await AccountManager().fetchEntitlements() { + if case let .success(entitlements) = await self?.accountManager.fetchEntitlements() { self?.cachedEntitlements = entitlements } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift index 22c7822c7f..27cb6ac20f 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift @@ -23,14 +23,16 @@ public final class ShareSubscriptionAccessModel: SubscriptionAccessModel { public var title = UserText.shareModalTitle public var description = UserText.shareModalDescription + private let appGroup: String private var actionHandlers: SubscriptionAccessActionHandlers private var email: String? private var hasEmail: Bool { !(email?.isEmpty ?? true) } - public init(actionHandlers: SubscriptionAccessActionHandlers, email: String?) { + public init(actionHandlers: SubscriptionAccessActionHandlers, email: String?, appGroup: String) { self.actionHandlers = actionHandlers self.email = email + self.appGroup = appGroup } public func descriptionHeader(for channel: AccessChannel) -> String? { @@ -69,7 +71,7 @@ public final class ShareSubscriptionAccessModel: SubscriptionAccessModel { Task { if SubscriptionPurchaseEnvironment.current == .appStore { if #available(macOS 12.0, iOS 15.0, *) { - await AppStoreAccountManagementFlow.refreshAuthTokenIfNeeded() + await AppStoreAccountManagementFlow.refreshAuthTokenIfNeeded(subscriptionAppGroup: appGroup) } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift index 103f9c927e..8f97c6be14 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift @@ -24,14 +24,16 @@ public final class SubscriptionAccessViewController: NSViewController { private let accountManager: AccountManager private var actionHandlers: SubscriptionAccessActionHandlers + private let subscriptionAppGroup: String public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - public init(accountManager: AccountManager = AccountManager(), actionHandlers: SubscriptionAccessActionHandlers) { + public init(accountManager: AccountManager, actionHandlers: SubscriptionAccessActionHandlers, subscriptionAppGroup: String) { self.accountManager = accountManager self.actionHandlers = actionHandlers + self.subscriptionAppGroup = subscriptionAppGroup super.init(nibName: nil, bundle: nil) } @@ -55,7 +57,7 @@ public final class SubscriptionAccessViewController: NSViewController { private func makeSubscriptionAccessModel() -> SubscriptionAccessModel { if accountManager.isUserAuthenticated { - ShareSubscriptionAccessModel(actionHandlers: actionHandlers, email: accountManager.email) + ShareSubscriptionAccessModel(actionHandlers: actionHandlers, email: accountManager.email, appGroup: subscriptionAppGroup) } else { ActivateSubscriptionAccessModel(actionHandlers: actionHandlers) } diff --git a/NetworkProtectionAppExtension/Info.plist b/NetworkProtectionAppExtension/Info.plist index afaad4a3af..57558f7205 100644 --- a/NetworkProtectionAppExtension/Info.plist +++ b/NetworkProtectionAppExtension/Info.plist @@ -13,5 +13,7 @@ NSExtensionPrincipalClass $(PRODUCT_MODULE_NAME).MacPacketTunnelProvider + SUBSCRIPTION_APP_GROUP + $(SUBSCRIPTION_APP_GROUP) From c00bbb13c8e79dcd29af4d72c88f90a6454e1066 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:27:13 +0100 Subject: [PATCH 10/99] Pull out AccountManager extension into file --- DuckDuckGo.xcodeproj/project.pbxproj | 44 ++++++++++++++----- .../View/PreferencesRootView.swift | 6 --- .../AccountManagerExtension.swift | 26 +++++++++++ 3 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 DuckDuckGo/Subscription/AccountManagerExtension.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 8e128dcbdb..315a500076 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3099,6 +3099,11 @@ EE7295EF2A545C12008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295EE2A545C12008C0991 /* NetworkProtection */; }; EEA3EEB12B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */; }; EEA3EEB32B24EC0600E8333A /* VPNLocationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */; }; + EEA4A6402B90E7490046A237 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */; }; + EEA4A6412B90E78C0046A237 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */; }; + EEA4A6422B90E78E0046A237 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */; }; + EEA4A6432B90E7C00046A237 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */; }; + EEA4A6442B90E7C10046A237 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */; }; EEAD7A7A2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; EEAD7A7B2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; EEAD7A7C2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; @@ -4452,6 +4457,7 @@ EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationsHostingViewController.swift; sourceTree = ""; }; EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNCountryLabelsModel.swift; sourceTree = ""; }; EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNLocationViewModel.swift; sourceTree = ""; }; + EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountManagerExtension.swift; sourceTree = ""; }; EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLauncher.swift; sourceTree = ""; }; EEBE97B22B7E48A600404915 /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = ""; }; EEC111E3294D06020086524F /* JSAlert.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = JSAlert.storyboard; sourceTree = ""; }; @@ -6751,12 +6757,13 @@ AA585D80248FD31100E9A3E2 /* DuckDuckGo */ = { isa = PBXGroup; children = ( - B658BAB52B0F845D00D1F2C7 /* Localizable.xcstrings */, AA4D700525545EDE00C3411E /* Application */, + AA585D85248FD31400E9A3E2 /* Assets.xcassets */, B31055BB27A1BA0E001AC618 /* Autoconsent */, 7B1E819A27C8874900FF0E60 /* Autofill */, AAC5E4C025D6A6A9007F5990 /* Bookmarks */, 4BFD356E283ADE8B00CE9234 /* BookmarksBar */, + 4B677454255DC18000025BD8 /* Bridging.h */, AA86491324D831B9001BABEE /* Common */, 85D33F1025C82E93002B91A6 /* Configuration */, 4B6160D125B14E5E007DE5B2 /* ContentBlocker */, @@ -6765,6 +6772,11 @@ 4B723DEA26B0002B00E14D75 /* DataImport */, 3192EC862A4DCF0E001E97A5 /* DBP */, 4B379C1C27BDB7EA008A968E /* DeviceAuthentication */, + AA585D8B248FD31400E9A3E2 /* DuckDuckGo.entitlements */, + 37D9BBA329376EE8000B99F9 /* DuckDuckGoAppStore.entitlements */, + 377E54382937B7C400780A0A /* DuckDuckGoAppStoreCI.entitlements */, + AAD86E502678D104005C11BE /* DuckDuckGoCI.entitlements */, + 4B5F15032A1570F10060320F /* DuckDuckGoDebug.entitlements */, 4B65143C26392483005B46EB /* Email */, B68412192B6A16030092F66A /* ErrorPage */, AA5FA695275F823900DCE9C9 /* Favicons */, @@ -6777,13 +6789,18 @@ B65536902684409300085A79 /* Geolocation */, AAE75275263B036300B973F8 /* History */, AAE71DB225F66A0900D74437 /* HomePage */, + 56CEE9092B7A66C500CF10AA /* Info.plist */, + 56CEE90D2B7A6DE100CF10AA /* InfoPlist.xcstrings */, EEAEA3F4294D05CF00D04DF3 /* JSAlert */, + B658BAB52B0F845D00D1F2C7 /* Localizable.xcstrings */, 9D03F5A22AA74829001A50E8 /* LoginItems */, AA585DB02490E6FA00E9A3E2 /* MainWindow */, AA97BF4425135CB60014931A /* Menus */, 85378D9A274E618C007C5CBF /* MessageViews */, AA86491524D83384001BABEE /* NavigationBar */, 4B4D60542A0B29FA00BCD287 /* NetworkProtection */, + 4B2D06642A132F3A00DE1F49 /* NetworkProtectionAppExtension.entitlements */, + 4B5F14C42A145D6A0060320F /* NetworkProtectionVPNController.entitlements */, 85B7184727677A7D00B4277F /* Onboarding */, 1D074B252909A371006E4AC3 /* PasswordManager */, B64C84DB2692D6E80048FEBE /* Permissions */, @@ -6796,6 +6813,7 @@ 4B677422255DBEB800025BD8 /* SmarterEncryption */, B68458AE25C7E75100DC17B6 /* StateRestoration */, B6A9E44E26142AF90067D1B9 /* Statistics */, + EEA4A63E2B90E7210046A237 /* Subscription */, AACB8E7224A4C8BC005F2218 /* Suggestions */, 3775913429AB99DA00E26367 /* Sync */, AA86491B24D837DE001BABEE /* Tab */, @@ -6807,17 +6825,6 @@ 4B9DB0062A983B23000927DB /* Waitlist */, AA6EF9AE25066F99004754E6 /* Windows */, 31F28C4B28C8EE9000119F70 /* YoutubePlayer */, - AA585D85248FD31400E9A3E2 /* Assets.xcassets */, - 4B677454255DC18000025BD8 /* Bridging.h */, - AAD86E502678D104005C11BE /* DuckDuckGoCI.entitlements */, - AA585D8B248FD31400E9A3E2 /* DuckDuckGo.entitlements */, - 4B5F15032A1570F10060320F /* DuckDuckGoDebug.entitlements */, - 37D9BBA329376EE8000B99F9 /* DuckDuckGoAppStore.entitlements */, - 377E54382937B7C400780A0A /* DuckDuckGoAppStoreCI.entitlements */, - 4B2D06642A132F3A00DE1F49 /* NetworkProtectionAppExtension.entitlements */, - 4B5F14C42A145D6A0060320F /* NetworkProtectionVPNController.entitlements */, - 56CEE9092B7A66C500CF10AA /* Info.plist */, - 56CEE90D2B7A6DE100CF10AA /* InfoPlist.xcstrings */, ); path = DuckDuckGo; sourceTree = ""; @@ -8269,6 +8276,14 @@ path = VPNLocation; sourceTree = ""; }; + EEA4A63E2B90E7210046A237 /* Subscription */ = { + isa = PBXGroup; + children = ( + EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */, + ); + path = Subscription; + sourceTree = ""; + }; EEAEA3F4294D05CF00D04DF3 /* JSAlert */ = { isa = PBXGroup; children = ( @@ -9668,6 +9683,7 @@ 3706FEBF293F6EFF00E42796 /* BWError.swift in Sources */, 3706FAC6293F65D500E42796 /* ConnectBitwardenViewController.swift in Sources */, EEC589DA2A4F1CE400BCD60C /* AppLauncher.swift in Sources */, + EEA4A6412B90E78C0046A237 /* AccountManagerExtension.swift in Sources */, 3706FAC8293F65D500E42796 /* AppTrackerDataSetProvider.swift in Sources */, 3706FAC9293F65D500E42796 /* EncryptionKeyGeneration.swift in Sources */, 3706FACA293F65D500E42796 /* TabLazyLoader.swift in Sources */, @@ -10662,6 +10678,7 @@ 7B0694982B6E980F00FA4DBA /* VPNProxyLauncher.swift in Sources */, EEC589DB2A4F1CE700BCD60C /* AppLauncher.swift in Sources */, B65DA5EF2A77CC3A00CBEE8D /* Bundle+NetworkProtectionExtensions.swift in Sources */, + EEA4A6432B90E7C00046A237 /* AccountManagerExtension.swift in Sources */, 4BF0E5072AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */, 7BA7CC442AD11E490042E5CE /* UserText.swift in Sources */, 4BF0E5142AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, @@ -10695,6 +10712,7 @@ B65DA5F02A77CC3C00CBEE8D /* Bundle+NetworkProtectionExtensions.swift in Sources */, 7BAF9E4D2A8A3CCB002D3B6E /* UserDefaults+NetworkProtectionShared.swift in Sources */, 7BA7CC392AD11E2D0042E5CE /* DuckDuckGoVPNAppDelegate.swift in Sources */, + EEA4A6442B90E7C10046A237 /* AccountManagerExtension.swift in Sources */, 7BA7CC552AD11FFB0042E5CE /* NetworkProtectionOptionKeyExtension.swift in Sources */, 7BA7CC3D2AD11E380042E5CE /* TunnelControllerIPCService.swift in Sources */, 4BA7C4DA2B3F639800AFE511 /* NetworkProtectionTunnelController.swift in Sources */, @@ -11359,6 +11377,7 @@ B6ABC5982B4861D4008343B9 /* FocusableTextField.swift in Sources */, 4B957B752AC7AE700062CA31 /* RandomAccessCollectionExtension.swift in Sources */, 4B957B762AC7AE700062CA31 /* NSOutlineViewExtensions.swift in Sources */, + EEA4A6422B90E78E0046A237 /* AccountManagerExtension.swift in Sources */, 4B957B772AC7AE700062CA31 /* AppDelegate.swift in Sources */, 4B957B782AC7AE700062CA31 /* ContentOverlayViewController.swift in Sources */, 4B957B792AC7AE700062CA31 /* ContentBlockingTabExtension.swift in Sources */, @@ -12042,6 +12061,7 @@ 4BB99D0126FE191E001E4761 /* ChromiumBookmarksReader.swift in Sources */, B6C0B23426E71BCD0031CB7F /* Downloads.xcdatamodeld in Sources */, AAE8B110258A456C00E81239 /* TabPreviewViewController.swift in Sources */, + EEA4A6402B90E7490046A237 /* AccountManagerExtension.swift in Sources */, B6C8CAA72AD010DD0060E1CD /* YandexDataImporter.swift in Sources */, EE66666F2B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */, 37CC53EC27E8A4D10028713D /* PreferencesPrivacyView.swift in Sources */, diff --git a/DuckDuckGo/Preferences/View/PreferencesRootView.swift b/DuckDuckGo/Preferences/View/PreferencesRootView.swift index 1233bfc89b..ffc802493a 100644 --- a/DuckDuckGo/Preferences/View/PreferencesRootView.swift +++ b/DuckDuckGo/Preferences/View/PreferencesRootView.swift @@ -130,12 +130,6 @@ enum Preferences { } } -public extension AccountManager { - convenience init() { - self.init(appGroup: Bundle.main.appGroup(bundle: .subs)) - } -} - struct SyncView: View { var body: some View { diff --git a/DuckDuckGo/Subscription/AccountManagerExtension.swift b/DuckDuckGo/Subscription/AccountManagerExtension.swift new file mode 100644 index 0000000000..09804e4d3d --- /dev/null +++ b/DuckDuckGo/Subscription/AccountManagerExtension.swift @@ -0,0 +1,26 @@ +// +// AccountManagerExtension.swift +// +// 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 Subscription + +public extension AccountManager { + convenience init() { + self.init(appGroup: Bundle.main.appGroup(bundle: .subs)) + } +} From 38a20b3b02623bdf1fc3f9438cc84b4913fbede2 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:31:54 +0100 Subject: [PATCH 11/99] wip --- DuckDuckGoVPN/NetworkProtectionBouncer.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index 2f3d8d2bdb..a9c362884d 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -21,6 +21,7 @@ import Foundation import NetworkProtection import ServiceManagement import AppKit +import Subscription /// Class that implements the necessary logic to ensure Network Protection is enabled, or prevent the app from running otherwise. /// @@ -30,9 +31,11 @@ final class NetworkProtectionBouncer { /// current app. /// func requireAuthTokenOrKillApp() { + let accountManager = AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)) let keychainStore = NetworkProtectionKeychainTokenStore(keychainType: .default, errorEvents: nil, isSubscriptionEnabled: false) - guard keychainStore.isFeatureActivated else { + // TODO: Do entitlements check, not this + guard accountManager.accessToken != nil || keychainStore.isFeatureActivated else { os_log(.error, log: .networkProtection, "🔴 Stopping: Network Protection not authorized.") // EXIT_SUCCESS ensures the login item won't relaunch From 8b9fce798fb3e61df7ccf62fb798b6c93709e625 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:51:26 +0100 Subject: [PATCH 12/99] Point to BSK commit --- DuckDuckGo.xcodeproj/project.pbxproj | 4 ++-- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 3 +-- LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- 8 files changed, 9 insertions(+), 10 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 92dddde1b0..b380b5a79a 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13582,8 +13582,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { - kind = exactVersion; - version = 113.0.0; + kind = revision; + revision = 8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b43fb91512..a31069f6b1 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,8 +23,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "f903ffcbc51e85ac262c355b56726e3387957a80", - "version" : "113.0.0" + "revision" : "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611" } }, { diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 8ce6dfa876..86be496221 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: "113.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index e8489be491..57a36ed238 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "113.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611") ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index 0e494741c2..2b123bf057 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "113.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index f93f27be34..ca7b60807b 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: "113.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 30421c20c1..445aa685d8 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../SwiftUIExtensions"), .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "113.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611") ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index ac6b0aa0ba..b096a7cea0 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -17,7 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "113.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From 2c48e94c3c7427f4fc67ebdfac90296096531c7a Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:29:45 +0100 Subject: [PATCH 13/99] Use subscription app group for AccountManager --- Configuration/AppStore.xcconfig | 6 +++ Configuration/DeveloperID.xcconfig | 6 +++ DuckDuckGo/Application/AppDelegate.swift | 1 + .../Common/Extensions/BundleExtension.swift | 3 ++ DuckDuckGo/DuckDuckGo.entitlements | 1 + DuckDuckGo/DuckDuckGoAppStore.entitlements | 1 + DuckDuckGo/DuckDuckGoDebug.entitlements | 1 + DuckDuckGo/Info.plist | 54 ++++++++++--------- DuckDuckGo/Menus/MainMenu.swift | 2 +- .../NetworkProtectionTunnelController.swift | 12 ++++- ...NetworkProtectionAppExtension.entitlements | 1 + .../View/PreferencesRootView.swift | 10 +++- .../SubscriptionPagesUserScript.swift | 12 ++--- DuckDuckGoVPN/DuckDuckGoVPN.entitlements | 3 +- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 7 +++ .../DuckDuckGoVPNAppStore.entitlements | 1 + DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements | 3 +- DuckDuckGoVPN/Info-AppStore.plist | 2 + DuckDuckGoVPN/Info.plist | 2 + .../DebugMenu/DebugPurchaseModel.swift | 9 ++-- .../DebugPurchaseViewController.swift | 4 +- .../DebugMenu/SubscriptionDebugMenu.swift | 13 +++-- .../PreferencesSubscriptionModel.swift | 15 +++--- .../Model/ShareSubscriptionAccessModel.swift | 6 ++- .../SubscriptionAccessViewController.swift | 6 ++- NetworkProtectionAppExtension/Info.plist | 2 + 26 files changed, 126 insertions(+), 57 deletions(-) diff --git a/Configuration/AppStore.xcconfig b/Configuration/AppStore.xcconfig index 0ad3f9f6b5..7095b66b0b 100644 --- a/Configuration/AppStore.xcconfig +++ b/Configuration/AppStore.xcconfig @@ -41,6 +41,12 @@ NETP_APP_GROUP[config=Review][sdk=macos*] = $(NETP_BASE_APP_GROUP).review NETP_APP_GROUP[config=Debug][sdk=macos*] = $(NETP_BASE_APP_GROUP).debug NETP_APP_GROUP[config=Release][sdk=macos*] = $(NETP_BASE_APP_GROUP) +SUBSCRIPTION_BASE_APP_GROUP = $(DEVELOPMENT_TEAM).com.duckduckgo.macos.browser.subscription +SUBSCRIPTION_APP_GROUP[config=CI][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).debug +SUBSCRIPTION_APP_GROUP[config=Review][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).review +SUBSCRIPTION_APP_GROUP[config=Debug][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).debug +SUBSCRIPTION_APP_GROUP[config=Release][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP) + AGENT_BUNDLE_ID_BASE[sdk=*] = com.duckduckgo.mobile.ios.vpn.agent AGENT_BUNDLE_ID[sdk=*] = $(AGENT_BUNDLE_ID_BASE) AGENT_BUNDLE_ID[config=Debug][sdk=*] = $(AGENT_BUNDLE_ID_BASE).debug diff --git a/Configuration/DeveloperID.xcconfig b/Configuration/DeveloperID.xcconfig index b66acc76d2..e5d9ed5daa 100644 --- a/Configuration/DeveloperID.xcconfig +++ b/Configuration/DeveloperID.xcconfig @@ -45,6 +45,12 @@ NETP_APP_GROUP[config=Review][sdk=*] = $(NETP_BASE_APP_GROUP).review NETP_APP_GROUP[config=Debug][sdk=*] = $(NETP_BASE_APP_GROUP).debug NETP_APP_GROUP[config=Release][sdk=*] = $(NETP_BASE_APP_GROUP) +SUBSCRIPTION_BASE_APP_GROUP = $(DEVELOPMENT_TEAM).com.duckduckgo.macos.browser.subscription +SUBSCRIPTION_APP_GROUP[config=CI][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).debug +SUBSCRIPTION_APP_GROUP[config=Review][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).review +SUBSCRIPTION_APP_GROUP[config=Debug][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP).debug +SUBSCRIPTION_APP_GROUP[config=Release][sdk=*] = $(SUBSCRIPTION_BASE_APP_GROUP) + SYSEX_MACH_SERVICE_NAME[sdk=*] = $(NETP_APP_GROUP).ipc SYSEX_MACH_SERVICE_NAME[config=CI][sdk=*] = $(NETP_APP_GROUP).ipc SYSEX_MACH_SERVICE_NAME[config=Review][sdk=*] = $(NETP_APP_GROUP).ipc diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index 54df1cd906..c0a706dbd4 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -295,6 +295,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel #else SubscriptionPurchaseEnvironment.current = .appStore #endif + SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging await AccountManager().checkSubscriptionState() } #endif diff --git a/DuckDuckGo/Common/Extensions/BundleExtension.swift b/DuckDuckGo/Common/Extensions/BundleExtension.swift index 7fceb79361..0a9fbafcf6 100644 --- a/DuckDuckGo/Common/Extensions/BundleExtension.swift +++ b/DuckDuckGo/Common/Extensions/BundleExtension.swift @@ -102,6 +102,8 @@ extension Bundle { appGroupName = "DBP_APP_GROUP" case .netP: appGroupName = "NETP_APP_GROUP" + case .subs: + appGroupName = "SUBSCRIPTION_APP_GROUP" } guard let appGroup = object(forInfoDictionaryKey: appGroupName) as? String else { @@ -128,4 +130,5 @@ extension Bundle { enum BundleGroup { case netP case dbp + case subs } diff --git a/DuckDuckGo/DuckDuckGo.entitlements b/DuckDuckGo/DuckDuckGo.entitlements index 757dc88e2c..3b77ae2b3a 100644 --- a/DuckDuckGo/DuckDuckGo.entitlements +++ b/DuckDuckGo/DuckDuckGo.entitlements @@ -28,6 +28,7 @@ $(AppIdentifierPrefix)com.duckduckgo.macos.browser $(NETP_APP_GROUP) $(DBP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) diff --git a/DuckDuckGo/DuckDuckGoAppStore.entitlements b/DuckDuckGo/DuckDuckGoAppStore.entitlements index 97443cb452..b4153637dd 100644 --- a/DuckDuckGo/DuckDuckGoAppStore.entitlements +++ b/DuckDuckGo/DuckDuckGoAppStore.entitlements @@ -55,6 +55,7 @@ $(DBP_APP_GROUP) $(AppIdentifierPrefix)com.duckduckgo.mobile.ios $(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) diff --git a/DuckDuckGo/DuckDuckGoDebug.entitlements b/DuckDuckGo/DuckDuckGoDebug.entitlements index dad1686cba..ae4d67533b 100644 --- a/DuckDuckGo/DuckDuckGoDebug.entitlements +++ b/DuckDuckGo/DuckDuckGoDebug.entitlements @@ -27,6 +27,7 @@ $(AppIdentifierPrefix)com.duckduckgo.macos.browser $(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) $(DBP_APP_GROUP) diff --git a/DuckDuckGo/Info.plist b/DuckDuckGo/Info.plist index a1b9b583bb..8c7dca0e52 100644 --- a/DuckDuckGo/Info.plist +++ b/DuckDuckGo/Info.plist @@ -2,8 +2,10 @@ - NSPrincipalClass - $(INFOPLIST_KEY_NSPrincipalClass) + AGENT_BUNDLE_ID + $(AGENT_BUNDLE_ID) + AGENT_PRODUCT_NAME + $(AGENT_PRODUCT_NAME) CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDocumentTypes @@ -77,10 +79,28 @@ CFBundleVersion $(CURRENT_PROJECT_VERSION) + DBP_APP_GROUP + $(DBP_APP_GROUP) + DBP_BACKGROUND_AGENT_BUNDLE_ID + $(DBP_BACKGROUND_AGENT_BUNDLE_ID) + DBP_BACKGROUND_AGENT_PRODUCT_NAME + $(DBP_BACKGROUND_AGENT_PRODUCT_NAME) + DISTRIBUTED_NOTIFICATIONS_PREFIX + $(DISTRIBUTED_NOTIFICATIONS_PREFIX) + ITSAppUsesNonExemptEncryption + LSApplicationCategoryType public.app-category.productivity LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) + NETP_APP_GROUP + $(NETP_APP_GROUP) + NOTIFICATIONS_AGENT_BUNDLE_ID + $(NOTIFICATIONS_AGENT_BUNDLE_ID) + NOTIFICATIONS_AGENT_PRODUCT_NAME + $(NOTIFICATIONS_AGENT_PRODUCT_NAME) + NSAppDataUsageDescription + DuckDuckGo will securely access your Bitwarden vault to autofill your passwords. To prevent this dialog in the future, go to Mac System Settings > Privacy & Security > Full Disk Access and toggle DuckDuckGo on, or switch back to the built-in password manager. NSAppTransportSecurity NSAllowsArbitraryLoadsInWebContent @@ -96,43 +116,25 @@ Allows you to share your location NSMicrophoneUsageDescription Allows you to share recordings - NSAppDataUsageDescription - DuckDuckGo will securely access your Bitwarden vault to autofill your passwords. To prevent this dialog in the future, go to Mac System Settings > Privacy & Security > Full Disk Access and toggle DuckDuckGo on, or switch back to the built-in password manager. + NSPrincipalClass + $(INFOPLIST_KEY_NSPrincipalClass) NSSupportsAutomaticTermination NSSupportsSuddenTermination SUAllowsAutomaticUpdates + SUBSCRIPTION_APP_GROUP + $(SUBSCRIPTION_APP_GROUP) SUEnableAutomaticChecks SUFeedURL https://staticcdn.duckduckgo.com/macos-desktop-browser/appcast2.xml - SUScheduledCheckInterval - 10800 SUPublicEDKey ZaO/DNMzMPBldh40b5xVrpNBmqRkuGY0BNRCUng2qRo= + SUScheduledCheckInterval + 10800 ViewBridgeService - ITSAppUsesNonExemptEncryption - - NOTIFICATIONS_AGENT_BUNDLE_ID - $(NOTIFICATIONS_AGENT_BUNDLE_ID) - NOTIFICATIONS_AGENT_PRODUCT_NAME - $(NOTIFICATIONS_AGENT_PRODUCT_NAME) - AGENT_BUNDLE_ID - $(AGENT_BUNDLE_ID) - AGENT_PRODUCT_NAME - $(AGENT_PRODUCT_NAME) - NETP_APP_GROUP - $(NETP_APP_GROUP) - DBP_APP_GROUP - $(DBP_APP_GROUP) - DISTRIBUTED_NOTIFICATIONS_PREFIX - $(DISTRIBUTED_NOTIFICATIONS_PREFIX) - DBP_BACKGROUND_AGENT_BUNDLE_ID - $(DBP_BACKGROUND_AGENT_BUNDLE_ID) - DBP_BACKGROUND_AGENT_PRODUCT_NAME - $(DBP_BACKGROUND_AGENT_PRODUCT_NAME) diff --git a/DuckDuckGo/Menus/MainMenu.swift b/DuckDuckGo/Menus/MainMenu.swift index 7d97cd4284..1b933e88f1 100644 --- a/DuckDuckGo/Menus/MainMenu.swift +++ b/DuckDuckGo/Menus/MainMenu.swift @@ -604,7 +604,7 @@ import SubscriptionUI updateInternalTestingFlag: { isInternalTestingWrapper.wrappedValue = $0 }, currentViewController: { WindowControllersManager.shared.lastKeyMainWindowController?.mainViewController - }) + }, appGroup: Bundle.main.appGroup(bundle: .subs)) #endif NSMenuItem(title: "Logging").submenu(setupLoggingMenu()) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index e86a508f2d..bd9035bc09 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -29,6 +29,8 @@ import NetworkProtectionUI import Networking import PixelKit +import Subscription + #if NETP_SYSTEM_EXTENSION import SystemExtensionManager import SystemExtensions @@ -43,6 +45,8 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr let settings: VPNSettings + let accountManager = AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)) + // MARK: - Combine Cancellables private var cancellables = Set() @@ -500,7 +504,13 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr var options = [String: NSObject]() options[NetworkProtectionOptionKey.activationAttemptId] = UUID().uuidString as NSString - options[NetworkProtectionOptionKey.authToken] = try tokenStore.fetchToken() as NSString? + if let accessToken = accountManager.accessToken { + os_log(.error, log: .networkProtection, "🟢 TunnelController found token: %{public}d", accessToken) + options[NetworkProtectionOptionKey.authToken] = NetworkProtectionKeychainTokenStore.makeToken(from: accessToken) as NSString? + } else { + os_log(.error, log: .networkProtection, "🔴 TunnelController found no token :(") + options[NetworkProtectionOptionKey.authToken] = try tokenStore.fetchToken() as NSString? + } options[NetworkProtectionOptionKey.selectedEnvironment] = settings.selectedEnvironment.rawValue as NSString options[NetworkProtectionOptionKey.selectedServer] = settings.selectedServer.stringValue as? NSString diff --git a/DuckDuckGo/NetworkProtectionAppExtension.entitlements b/DuckDuckGo/NetworkProtectionAppExtension.entitlements index d37610bb07..e2ec46d330 100644 --- a/DuckDuckGo/NetworkProtectionAppExtension.entitlements +++ b/DuckDuckGo/NetworkProtectionAppExtension.entitlements @@ -26,6 +26,7 @@ $(AppIdentifierPrefix)com.duckduckgo.mobile.ios $(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) diff --git a/DuckDuckGo/Preferences/View/PreferencesRootView.swift b/DuckDuckGo/Preferences/View/PreferencesRootView.swift index 517ac73e9e..0fc0691830 100644 --- a/DuckDuckGo/Preferences/View/PreferencesRootView.swift +++ b/DuckDuckGo/Preferences/View/PreferencesRootView.swift @@ -134,12 +134,20 @@ enum Preferences { return PreferencesSubscriptionModel(openURLHandler: openURL, openVPNHandler: openVPN, openDBPHandler: openDBP, - sheetActionHandler: sheetActionHandler) + sheetActionHandler: sheetActionHandler, + subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) + } #endif } } +public extension AccountManager { + convenience init() { + self.init(appGroup: Bundle.main.appGroup(bundle: .subs)) + } +} + struct SyncView: View { var body: some View { diff --git a/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift b/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift index 2c2ce64d58..384748d320 100644 --- a/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift +++ b/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift @@ -226,7 +226,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { let emailAccessToken = try? EmailManager().getToken() os_log(.info, log: .subscription, "[Purchase] Purchasing") - switch await AppStorePurchaseFlow.purchaseSubscription(with: subscriptionSelection.id, emailAccessToken: emailAccessToken) { + switch await AppStorePurchaseFlow.purchaseSubscription(with: subscriptionSelection.id, emailAccessToken: emailAccessToken, subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) { case .success: break case .failure(let error): @@ -239,7 +239,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { os_log(.info, log: .subscription, "[Purchase] Completing purchase") - switch await AppStorePurchaseFlow.completeSubscriptionPurchase() { + switch await AppStorePurchaseFlow.completeSubscriptionPurchase(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) { case .success(let purchaseUpdate): await pushPurchaseUpdate(originalMessage: message, purchaseUpdate: purchaseUpdate) case .failure(let error): @@ -270,7 +270,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { WindowControllersManager.shared.show(url: .settingsPane(.sync), source: .ui, newTab: true) }) - let vc = SubscriptionAccessViewController(actionHandlers: actionHandlers) + let vc = SubscriptionAccessViewController(accountManager: AccountManager(), actionHandlers: actionHandlers, subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) WindowControllersManager.shared.lastKeyMainWindowController?.mainViewController.presentAsSheet(vc) } @@ -318,7 +318,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { let progressViewController = await ProgressViewController(title: UserText.completingPurchaseTitle) await mainViewController?.presentAsSheet(progressViewController) - await StripePurchaseFlow.completeSubscriptionPurchase() + await StripePurchaseFlow.completeSubscriptionPurchase(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) await mainViewController?.dismiss(progressViewController) return [String: String]() // cannot be nil @@ -355,7 +355,7 @@ extension SubscriptionPagesUseSubscriptionFeature { guard case .success = await PurchaseManager.shared.syncAppleIDAccount() else { return } - switch await AppStoreRestoreFlow.restoreAccountFromPastPurchase() { + switch await AppStoreRestoreFlow.restoreAccountFromPastPurchase(appGroup: Bundle.main.appGroup(bundle: .subs)) { case .success: onSuccessHandler() case .failure(let error): @@ -412,7 +412,7 @@ extension MainWindowController { window.show(.subscriptionFoundAlert(), firstButtonAction: { if #available(macOS 12.0, *) { Task { - _ = await AppStoreRestoreFlow.restoreAccountFromPastPurchase() + _ = await AppStoreRestoreFlow.restoreAccountFromPastPurchase(appGroup: Bundle.main.appGroup(bundle: .subs)) originalMessage.webView?.reload() } } diff --git a/DuckDuckGoVPN/DuckDuckGoVPN.entitlements b/DuckDuckGoVPN/DuckDuckGoVPN.entitlements index 2797c3f947..90d49dddf5 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPN.entitlements +++ b/DuckDuckGoVPN/DuckDuckGoVPN.entitlements @@ -15,7 +15,8 @@ keychain-access-groups - $(NETP_APP_GROUP) + $(AppIdentifierPrefix)$(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 959a167edf..fa2519bdfb 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -43,6 +43,13 @@ final class DuckDuckGoVPNApplication: NSApplication { super.init() self.delegate = _delegate + let accountManager = AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)) + + if let token = accountManager.accessToken { + os_log(.error, log: .networkProtection, "🟢 VPN Agent found token: %{public}d", token) + } else { + os_log(.error, log: .networkProtection, "🔴 VPN Agent found no token") + } } required init?(coder: NSCoder) { diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppStore.entitlements b/DuckDuckGoVPN/DuckDuckGoVPNAppStore.entitlements index 7d375721de..5e706138b5 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppStore.entitlements +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppStore.entitlements @@ -11,6 +11,7 @@ keychain-access-groups $(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) com.apple.security.application-groups diff --git a/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements b/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements index f531d0bc0c..2699e730cf 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements +++ b/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements @@ -15,7 +15,8 @@ keychain-access-groups - $(NETP_APP_GROUP) + $(AppIdentifierPrefix)$(NETP_APP_GROUP) + $(SUBSCRIPTION_APP_GROUP) diff --git a/DuckDuckGoVPN/Info-AppStore.plist b/DuckDuckGoVPN/Info-AppStore.plist index a1b2b02a02..26b434800b 100644 --- a/DuckDuckGoVPN/Info-AppStore.plist +++ b/DuckDuckGoVPN/Info-AppStore.plist @@ -8,6 +8,8 @@ $(NETP_APP_GROUP) PROXY_EXTENSION_BUNDLE_ID $(PROXY_EXTENSION_BUNDLE_ID) + SUBSCRIPTION_APP_GROUP + $(SUBSCRIPTION_APP_GROUP) TUNNEL_EXTENSION_BUNDLE_ID $(TUNNEL_EXTENSION_BUNDLE_ID) LSApplicationCategoryType diff --git a/DuckDuckGoVPN/Info.plist b/DuckDuckGoVPN/Info.plist index a1b2b02a02..26b434800b 100644 --- a/DuckDuckGoVPN/Info.plist +++ b/DuckDuckGoVPN/Info.plist @@ -8,6 +8,8 @@ $(NETP_APP_GROUP) PROXY_EXTENSION_BUNDLE_ID $(PROXY_EXTENSION_BUNDLE_ID) + SUBSCRIPTION_APP_GROUP + $(SUBSCRIPTION_APP_GROUP) TUNNEL_EXTENSION_BUNDLE_ID $(TUNNEL_EXTENSION_BUNDLE_ID) LSApplicationCategoryType diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift index 273a043618..a8fa790ff5 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift @@ -24,13 +24,16 @@ import Subscription public final class DebugPurchaseModel: ObservableObject { var purchaseManager: PurchaseManager - var accountManager: AccountManager = AccountManager() + var accountManager: AccountManager + private let subscriptionAppGroup: String @Published var subscriptions: [SubscriptionRowModel] - init(manager: PurchaseManager, subscriptions: [SubscriptionRowModel] = []) { + init(manager: PurchaseManager, subscriptions: [SubscriptionRowModel] = [], subscriptionAppGroup: String) { self.purchaseManager = manager self.subscriptions = subscriptions + self.subscriptionAppGroup = subscriptionAppGroup + self.accountManager = AccountManager(appGroup: subscriptionAppGroup) } @MainActor @@ -38,7 +41,7 @@ public final class DebugPurchaseModel: ObservableObject { print("Attempting purchase: \(product.displayName)") Task { - await AppStorePurchaseFlow.purchaseSubscription(with: product.id, emailAccessToken: nil) + await AppStorePurchaseFlow.purchaseSubscription(with: product.id, emailAccessToken: nil, subscriptionAppGroup: subscriptionAppGroup) } } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseViewController.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseViewController.swift index 0d9c34bcbb..1573bec52e 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseViewController.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseViewController.swift @@ -34,9 +34,9 @@ public final class DebugPurchaseViewController: NSViewController { fatalError("init(coder:) has not been implemented") } - public init() { + public init(subscriptionAppGroup: String) { manager = PurchaseManager.shared - model = DebugPurchaseModel(manager: manager) + model = DebugPurchaseModel(manager: manager, subscriptionAppGroup: subscriptionAppGroup) super.init(nibName: nil, bundle: nil) } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift index b3c8823cc2..1c40d8cf29 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift @@ -27,7 +27,8 @@ public final class SubscriptionDebugMenu: NSMenuItem { var updateInternalTestingFlag: (Bool) -> Void var currentViewController: () -> NSViewController? - private let accountManager = AccountManager() + private let accountManager: AccountManager + private let appGroup: String private var _purchaseManager: Any? @available(macOS 12.0, *) @@ -47,13 +48,15 @@ public final class SubscriptionDebugMenu: NSMenuItem { updateEnvironment: @escaping (String) -> Void, isInternalTestingEnabled: @escaping () -> Bool, updateInternalTestingFlag: @escaping (Bool) -> Void, - currentViewController: @escaping () -> NSViewController?) { + currentViewController: @escaping () -> NSViewController?, + appGroup: String) { self.currentEnvironment = currentEnvironment self.updateEnvironment = updateEnvironment self.isInternalTestingEnabled = isInternalTestingEnabled self.updateInternalTestingFlag = updateInternalTestingFlag self.currentViewController = currentViewController - + self.accountManager = AccountManager(appGroup: appGroup) + self.appGroup = appGroup super.init(title: "Subscription", action: nil, keyEquivalent: "") self.submenu = makeSubmenu() } @@ -157,7 +160,7 @@ public final class SubscriptionDebugMenu: NSMenuItem { let entitlements: [AccountManager.Entitlement] = [.networkProtection, .dataBrokerProtection, .identityTheftRestoration] for entitlement in entitlements { - if case let .success(result) = await AccountManager().hasEntitlement(for: entitlement) { + if case let .success(result) = await accountManager.hasEntitlement(for: entitlement) { let resultSummary = "Entitlement check for \(entitlement.rawValue): \(result)" results.append(resultSummary) print(resultSummary) @@ -219,7 +222,7 @@ public final class SubscriptionDebugMenu: NSMenuItem { func restorePurchases(_ sender: Any?) { if #available(macOS 12.0, *) { Task { - await AppStoreRestoreFlow.restoreAccountFromPastPurchase() + await AppStoreRestoreFlow.restoreAccountFromPastPurchase(appGroup: appGroup) } } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift index 2364975249..22052dd64e 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift @@ -34,6 +34,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { private let openVPNHandler: () -> Void private let openDBPHandler: () -> Void private let sheetActionHandler: SubscriptionAccessActionHandlers + private let subscriptionAppGroup: String private var fetchSubscriptionDetailsTask: Task<(), Never>? @@ -44,12 +45,14 @@ public final class PreferencesSubscriptionModel: ObservableObject { openURLHandler: @escaping (URL) -> Void, openVPNHandler: @escaping () -> Void, openDBPHandler: @escaping () -> Void, - sheetActionHandler: SubscriptionAccessActionHandlers) { + sheetActionHandler: SubscriptionAccessActionHandlers, + subscriptionAppGroup: String) { self.accountManager = accountManager self.openURLHandler = openURLHandler self.openVPNHandler = openVPNHandler self.openDBPHandler = openDBPHandler self.sheetActionHandler = sheetActionHandler + self.subscriptionAppGroup = subscriptionAppGroup self.isUserAuthenticated = accountManager.isUserAuthenticated @@ -78,7 +81,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { private func makeSubscriptionAccessModel() -> SubscriptionAccessModel { if accountManager.isUserAuthenticated { - ShareSubscriptionAccessModel(actionHandlers: sheetActionHandler, email: accountManager.email) + ShareSubscriptionAccessModel(actionHandlers: sheetActionHandler, email: accountManager.email, appGroup: subscriptionAppGroup) } else { ActivateSubscriptionAccessModel(actionHandlers: sheetActionHandler) } @@ -128,7 +131,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { NSWorkspace.shared.open(.manageSubscriptionsInAppStoreAppURL) case .stripe: Task { - guard let accessToken = AccountManager().accessToken, let externalID = AccountManager().externalID, + guard let accessToken = accountManager.accessToken, let externalID = accountManager.externalID, case let .success(response) = await SubscriptionService.getCustomerPortalURL(accessToken: accessToken, externalID: externalID) else { return } guard let customerPortalURL = URL(string: response.customerPortalUrl) else { return } @@ -143,7 +146,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { switch await AuthService.storeLogin(signature: lastTransactionJWSRepresentation) { case .success(let response): - return response.externalID == AccountManager().externalID + return response.externalID == accountManager.externalID case .failure: return false } @@ -198,7 +201,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { if case .success(let response) = await SubscriptionService.getSubscriptionDetails(token: token) { if !response.isSubscriptionActive { - AccountManager().signOut() + self?.accountManager.signOut() return } @@ -207,7 +210,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { self?.subscriptionPlatform = response.platform } - if case let .success(entitlements) = await AccountManager().fetchEntitlements() { + if case let .success(entitlements) = await self?.accountManager.fetchEntitlements() { self?.cachedEntitlements = entitlements } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift index 22c7822c7f..27cb6ac20f 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift @@ -23,14 +23,16 @@ public final class ShareSubscriptionAccessModel: SubscriptionAccessModel { public var title = UserText.shareModalTitle public var description = UserText.shareModalDescription + private let appGroup: String private var actionHandlers: SubscriptionAccessActionHandlers private var email: String? private var hasEmail: Bool { !(email?.isEmpty ?? true) } - public init(actionHandlers: SubscriptionAccessActionHandlers, email: String?) { + public init(actionHandlers: SubscriptionAccessActionHandlers, email: String?, appGroup: String) { self.actionHandlers = actionHandlers self.email = email + self.appGroup = appGroup } public func descriptionHeader(for channel: AccessChannel) -> String? { @@ -69,7 +71,7 @@ public final class ShareSubscriptionAccessModel: SubscriptionAccessModel { Task { if SubscriptionPurchaseEnvironment.current == .appStore { if #available(macOS 12.0, iOS 15.0, *) { - await AppStoreAccountManagementFlow.refreshAuthTokenIfNeeded() + await AppStoreAccountManagementFlow.refreshAuthTokenIfNeeded(subscriptionAppGroup: appGroup) } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift index 103f9c927e..8f97c6be14 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift @@ -24,14 +24,16 @@ public final class SubscriptionAccessViewController: NSViewController { private let accountManager: AccountManager private var actionHandlers: SubscriptionAccessActionHandlers + private let subscriptionAppGroup: String public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - public init(accountManager: AccountManager = AccountManager(), actionHandlers: SubscriptionAccessActionHandlers) { + public init(accountManager: AccountManager, actionHandlers: SubscriptionAccessActionHandlers, subscriptionAppGroup: String) { self.accountManager = accountManager self.actionHandlers = actionHandlers + self.subscriptionAppGroup = subscriptionAppGroup super.init(nibName: nil, bundle: nil) } @@ -55,7 +57,7 @@ public final class SubscriptionAccessViewController: NSViewController { private func makeSubscriptionAccessModel() -> SubscriptionAccessModel { if accountManager.isUserAuthenticated { - ShareSubscriptionAccessModel(actionHandlers: actionHandlers, email: accountManager.email) + ShareSubscriptionAccessModel(actionHandlers: actionHandlers, email: accountManager.email, appGroup: subscriptionAppGroup) } else { ActivateSubscriptionAccessModel(actionHandlers: actionHandlers) } diff --git a/NetworkProtectionAppExtension/Info.plist b/NetworkProtectionAppExtension/Info.plist index afaad4a3af..57558f7205 100644 --- a/NetworkProtectionAppExtension/Info.plist +++ b/NetworkProtectionAppExtension/Info.plist @@ -13,5 +13,7 @@ NSExtensionPrincipalClass $(PRODUCT_MODULE_NAME).MacPacketTunnelProvider + SUBSCRIPTION_APP_GROUP + $(SUBSCRIPTION_APP_GROUP) From a322b65780d49aa1cddf18bccb45b43cbdde7c04 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:27:13 +0100 Subject: [PATCH 14/99] Fix some stuff post-cherry-picking --- DuckDuckGo.xcodeproj/project.pbxproj | 60 +++++++++++++++---- DuckDuckGo/InfoPlist.xcstrings | 2 +- .../View/NavigationBarViewController.swift | 8 +-- .../NetworkProtectionTunnelController.swift | 8 +-- .../View/PreferencesRootView.swift | 6 -- .../AccountManagerExtension.swift | 26 ++++++++ .../SubscriptionPagesUserScript.swift | 2 +- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 3 + .../DebugMenu/SubscriptionDebugMenu.swift | 2 +- .../PreferencesSubscriptionModel.swift | 5 +- 10 files changed, 87 insertions(+), 35 deletions(-) create mode 100644 DuckDuckGo/Subscription/AccountManagerExtension.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index b380b5a79a..e7eb43ac44 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3087,6 +3087,13 @@ EAC80DE0271F6C0100BBF02D /* fb-sdk.js in Resources */ = {isa = PBXBuildFile; fileRef = EAC80DDF271F6C0100BBF02D /* fb-sdk.js */; }; EAE42800275D47FA00DAC26B /* ClickToLoadModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE427FF275D47FA00DAC26B /* ClickToLoadModel.swift */; }; EAFAD6CA2728BD1200F9DF00 /* clickToLoad.js in Resources */ = {isa = PBXBuildFile; fileRef = EAFAD6C92728BD1200F9DF00 /* clickToLoad.js */; }; + EE0629722B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */; }; + EE0629732B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */; }; + EE0629742B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */; }; + EE0629752B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */; }; + EE0629762B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */; }; + EE2F9C5B2B90F2FF00D45FC9 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE2F9C5A2B90F2FF00D45FC9 /* Subscription */; }; + EE2F9C5D2B90F31B00D45FC9 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE2F9C5C2B90F31B00D45FC9 /* Subscription */; }; EE339228291BDEFD009F62C1 /* JSAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE339227291BDEFD009F62C1 /* JSAlertController.swift */; }; EE66666F2B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; EE6666702B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; @@ -4448,6 +4455,7 @@ EAC80DDF271F6C0100BBF02D /* fb-sdk.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "fb-sdk.js"; sourceTree = ""; }; EAE427FF275D47FA00DAC26B /* ClickToLoadModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClickToLoadModel.swift; sourceTree = ""; }; EAFAD6C92728BD1200F9DF00 /* clickToLoad.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = clickToLoad.js; sourceTree = ""; }; + EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManagerExtension.swift; sourceTree = ""; }; EE339227291BDEFD009F62C1 /* JSAlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSAlertController.swift; sourceTree = ""; }; EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationsHostingViewController.swift; sourceTree = ""; }; EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNCountryLabelsModel.swift; sourceTree = ""; }; @@ -4561,6 +4569,7 @@ 7BEEA5162AD1236E00A9E72B /* NetworkProtectionUI in Frameworks */, 7BFCB74E2ADE7E1A00DA3EA7 /* PixelKit in Frameworks */, EE7295ED2A545C0A008C0991 /* NetworkProtection in Frameworks */, + EE2F9C5B2B90F2FF00D45FC9 /* Subscription in Frameworks */, 7BEC182F2AD5D8DC00D30536 /* SystemExtensionManager in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4570,6 +4579,7 @@ buildActionMask = 2147483647; files = ( 7BFCB7502ADE7E2300DA3EA7 /* PixelKit in Frameworks */, + EE2F9C5D2B90F31B00D45FC9 /* Subscription in Frameworks */, 7BA7CC612AD1211C0042E5CE /* Networking in Frameworks */, 7BEEA5142AD1236300A9E72B /* NetworkProtectionIPC in Frameworks */, 7B00997F2B6508C200FE7C31 /* NetworkProtectionProxy in Frameworks */, @@ -4916,6 +4926,7 @@ 1EA7B8D62B7E124E000330A4 /* Subscription */ = { isa = PBXGroup; children = ( + EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */, 1EA7B8D72B7E1283000330A4 /* SubscriptionFeatureAvailability.swift */, ); path = Subscription; @@ -6723,6 +6734,7 @@ 565E46DE2B2725DD0013AC2A /* SyncE2EUITests */, AA585D7F248FD31100E9A3E2 /* Products */, 85AE2FF024A33A2D002D507F /* Frameworks */, + EE0629702B90EE3500D868B4 /* Recovered References */, ); sourceTree = ""; }; @@ -6755,12 +6767,13 @@ AA585D80248FD31100E9A3E2 /* DuckDuckGo */ = { isa = PBXGroup; children = ( - B658BAB52B0F845D00D1F2C7 /* Localizable.xcstrings */, AA4D700525545EDE00C3411E /* Application */, + AA585D85248FD31400E9A3E2 /* Assets.xcassets */, B31055BB27A1BA0E001AC618 /* Autoconsent */, 7B1E819A27C8874900FF0E60 /* Autofill */, AAC5E4C025D6A6A9007F5990 /* Bookmarks */, 4BFD356E283ADE8B00CE9234 /* BookmarksBar */, + 4B677454255DC18000025BD8 /* Bridging.h */, AA86491324D831B9001BABEE /* Common */, 85D33F1025C82E93002B91A6 /* Configuration */, 4B6160D125B14E5E007DE5B2 /* ContentBlocker */, @@ -6769,6 +6782,11 @@ 4B723DEA26B0002B00E14D75 /* DataImport */, 3192EC862A4DCF0E001E97A5 /* DBP */, 4B379C1C27BDB7EA008A968E /* DeviceAuthentication */, + AA585D8B248FD31400E9A3E2 /* DuckDuckGo.entitlements */, + 37D9BBA329376EE8000B99F9 /* DuckDuckGoAppStore.entitlements */, + 377E54382937B7C400780A0A /* DuckDuckGoAppStoreCI.entitlements */, + AAD86E502678D104005C11BE /* DuckDuckGoCI.entitlements */, + 4B5F15032A1570F10060320F /* DuckDuckGoDebug.entitlements */, 4B65143C26392483005B46EB /* Email */, B68412192B6A16030092F66A /* ErrorPage */, AA5FA695275F823900DCE9C9 /* Favicons */, @@ -6781,13 +6799,18 @@ B65536902684409300085A79 /* Geolocation */, AAE75275263B036300B973F8 /* History */, AAE71DB225F66A0900D74437 /* HomePage */, + 56CEE9092B7A66C500CF10AA /* Info.plist */, + 56CEE90D2B7A6DE100CF10AA /* InfoPlist.xcstrings */, EEAEA3F4294D05CF00D04DF3 /* JSAlert */, + B658BAB52B0F845D00D1F2C7 /* Localizable.xcstrings */, 9D03F5A22AA74829001A50E8 /* LoginItems */, AA585DB02490E6FA00E9A3E2 /* MainWindow */, AA97BF4425135CB60014931A /* Menus */, 85378D9A274E618C007C5CBF /* MessageViews */, AA86491524D83384001BABEE /* NavigationBar */, 4B4D60542A0B29FA00BCD287 /* NetworkProtection */, + 4B2D06642A132F3A00DE1F49 /* NetworkProtectionAppExtension.entitlements */, + 4B5F14C42A145D6A0060320F /* NetworkProtectionVPNController.entitlements */, 85B7184727677A7D00B4277F /* Onboarding */, 1D074B252909A371006E4AC3 /* PasswordManager */, B64C84DB2692D6E80048FEBE /* Permissions */, @@ -6812,17 +6835,6 @@ 4B9DB0062A983B23000927DB /* Waitlist */, AA6EF9AE25066F99004754E6 /* Windows */, 31F28C4B28C8EE9000119F70 /* YoutubePlayer */, - AA585D85248FD31400E9A3E2 /* Assets.xcassets */, - 4B677454255DC18000025BD8 /* Bridging.h */, - AAD86E502678D104005C11BE /* DuckDuckGoCI.entitlements */, - AA585D8B248FD31400E9A3E2 /* DuckDuckGo.entitlements */, - 4B5F15032A1570F10060320F /* DuckDuckGoDebug.entitlements */, - 37D9BBA329376EE8000B99F9 /* DuckDuckGoAppStore.entitlements */, - 377E54382937B7C400780A0A /* DuckDuckGoAppStoreCI.entitlements */, - 4B2D06642A132F3A00DE1F49 /* NetworkProtectionAppExtension.entitlements */, - 4B5F14C42A145D6A0060320F /* NetworkProtectionVPNController.entitlements */, - 56CEE9092B7A66C500CF10AA /* Info.plist */, - 56CEE90D2B7A6DE100CF10AA /* InfoPlist.xcstrings */, ); path = DuckDuckGo; sourceTree = ""; @@ -8262,6 +8274,13 @@ path = fonts; sourceTree = ""; }; + EE0629702B90EE3500D868B4 /* Recovered References */ = { + isa = PBXGroup; + children = ( + ); + name = "Recovered References"; + sourceTree = ""; + }; EEA3EEAF2B24EB5100E8333A /* VPNLocation */ = { isa = PBXGroup; children = ( @@ -8501,6 +8520,7 @@ 7BFCB74D2ADE7E1A00DA3EA7 /* PixelKit */, 4B41EDAA2B1544B2001EEDF4 /* LoginItems */, 7B00997C2B6508B700FE7C31 /* NetworkProtectionProxy */, + EE2F9C5A2B90F2FF00D45FC9 /* Subscription */, ); productName = DuckDuckGoAgent; productReference = 4B2D06392A11CFBB00DE1F49 /* DuckDuckGo VPN.app */; @@ -8533,6 +8553,7 @@ 7BFCB74F2ADE7E2300DA3EA7 /* PixelKit */, 7B00997E2B6508C200FE7C31 /* NetworkProtectionProxy */, 4BA7C4DC2B3F64E500AFE511 /* LoginItems */, + EE2F9C5C2B90F31B00D45FC9 /* Subscription */, ); productName = DuckDuckGoAgentAppStore; productReference = 4B2D06692A13318400DE1F49 /* DuckDuckGo VPN App Store.app */; @@ -10046,6 +10067,7 @@ B684121D2B6A1D880092F66A /* ErrorPageHTMLTemplate.swift in Sources */, 3706FBD2293F65D500E42796 /* RunningApplicationCheck.swift in Sources */, 3706FBD3293F65D500E42796 /* StatePersistenceService.swift in Sources */, + EE0629732B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */, 3706FBD4293F65D500E42796 /* WindowManager+StateRestoration.swift in Sources */, 7B430EA22A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift in Sources */, 3706FBD5293F65D500E42796 /* TabCollection+NSSecureCoding.swift in Sources */, @@ -10684,6 +10706,7 @@ 7B8DB31A2B504D7500EC16DA /* VPNAppEventsHandler.swift in Sources */, 7BA7CC532AD11FCE0042E5CE /* Bundle+VPN.swift in Sources */, 7BFE95562A9DF29B0081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */, + EE0629742B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */, 7BA7CC5D2AD120C30042E5CE /* EventMapping+NetworkProtectionError.swift in Sources */, 7BA7CC4A2AD11EA00042E5CE /* NetworkProtectionTunnelController.swift in Sources */, 7BD1688E2AD4A4C400D24876 /* NetworkExtensionController.swift in Sources */, @@ -10717,6 +10740,7 @@ 4B0EF7292B5780EB009D6481 /* VPNAppEventsHandler.swift in Sources */, 7BA7CC412AD11E420042E5CE /* NetworkProtectionBouncer.swift in Sources */, 4BF0E5082AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */, + EE0629752B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */, 7BA7CC582AD1203A0042E5CE /* UserText+NetworkProtection.swift in Sources */, 7BA7CC4B2AD11EC60042E5CE /* NetworkProtectionControllerErrorStore.swift in Sources */, 4BF0E5152AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, @@ -11181,6 +11205,7 @@ 4B957AB92AC7AE700062CA31 /* SerpHeadersNavigationResponder.swift in Sources */, 4B957ABA2AC7AE700062CA31 /* HomePageContinueSetUpModel.swift in Sources */, 4B957ABB2AC7AE700062CA31 /* WebKitDownloadTask.swift in Sources */, + EE0629762B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */, 4B957ABC2AC7AE700062CA31 /* ChromiumLoginReader.swift in Sources */, B6BCC5522AFE4F7D002C5499 /* DataImportTypePicker.swift in Sources */, 4B957ABD2AC7AE700062CA31 /* NSAlert+PasswordManager.swift in Sources */, @@ -11964,6 +11989,7 @@ 7BE146072A6A83C700C313B8 /* NetworkProtectionDebugMenu.swift in Sources */, B6085D092743AAB600A9C456 /* FireproofDomains.xcdatamodeld in Sources */, 85589E8227BBB8630038AD11 /* HomePageView.swift in Sources */, + EE0629722B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */, B6BF5D932947199A006742B1 /* SerpHeadersNavigationResponder.swift in Sources */, 569277C129DDCBB500B633EF /* HomePageContinueSetUpModel.swift in Sources */, B68D21CF2ACBC9FC002DA3C2 /* ContentBlockerRulesManagerMock.swift in Sources */, @@ -14227,6 +14253,16 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Configuration; }; + EE2F9C5A2B90F2FF00D45FC9 /* Subscription */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Subscription; + }; + EE2F9C5C2B90F31B00D45FC9 /* Subscription */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Subscription; + }; EE7295E22A545B9A008C0991 /* NetworkProtection */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; diff --git a/DuckDuckGo/InfoPlist.xcstrings b/DuckDuckGo/InfoPlist.xcstrings index 4d7c2d94c0..70d7389fb7 100644 --- a/DuckDuckGo/InfoPlist.xcstrings +++ b/DuckDuckGo/InfoPlist.xcstrings @@ -8,7 +8,7 @@ "en" : { "stringUnit" : { "state" : "new", - "value" : "DuckDuckGo" + "value" : "DuckDuckGo Privacy Pro" } } } diff --git a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift index eed2a83f4a..82647b4a4d 100644 --- a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift +++ b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift @@ -335,10 +335,10 @@ final class NavigationBarViewController: NSViewController { let accountManager = AccountManager() let networkProtectionTokenStorage = NetworkProtectionKeychainTokenStore() - if accountManager.accessToken != nil && (try? networkProtectionTokenStorage.fetchToken()) == nil { - print("[NetP Subscription] Got access token but not auth token, meaning token exchange failed") - return - } +// if accountManager.accessToken != nil && (try? networkProtectionTokenStorage.fetchToken()) == nil { +// print("[NetP Subscription] Got access token but not auth token, meaning token exchange failed") +// return +// } } #endif diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index bd9035bc09..54003495aa 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -504,13 +504,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr var options = [String: NSObject]() options[NetworkProtectionOptionKey.activationAttemptId] = UUID().uuidString as NSString - if let accessToken = accountManager.accessToken { - os_log(.error, log: .networkProtection, "🟢 TunnelController found token: %{public}d", accessToken) - options[NetworkProtectionOptionKey.authToken] = NetworkProtectionKeychainTokenStore.makeToken(from: accessToken) as NSString? - } else { - os_log(.error, log: .networkProtection, "🔴 TunnelController found no token :(") - options[NetworkProtectionOptionKey.authToken] = try tokenStore.fetchToken() as NSString? - } + options[NetworkProtectionOptionKey.authToken] = try tokenStore.fetchToken() as NSString? options[NetworkProtectionOptionKey.selectedEnvironment] = settings.selectedEnvironment.rawValue as NSString options[NetworkProtectionOptionKey.selectedServer] = settings.selectedServer.stringValue as? NSString diff --git a/DuckDuckGo/Preferences/View/PreferencesRootView.swift b/DuckDuckGo/Preferences/View/PreferencesRootView.swift index 0fc0691830..78ffb18954 100644 --- a/DuckDuckGo/Preferences/View/PreferencesRootView.swift +++ b/DuckDuckGo/Preferences/View/PreferencesRootView.swift @@ -142,12 +142,6 @@ enum Preferences { } } -public extension AccountManager { - convenience init() { - self.init(appGroup: Bundle.main.appGroup(bundle: .subs)) - } -} - struct SyncView: View { var body: some View { diff --git a/DuckDuckGo/Subscription/AccountManagerExtension.swift b/DuckDuckGo/Subscription/AccountManagerExtension.swift new file mode 100644 index 0000000000..09804e4d3d --- /dev/null +++ b/DuckDuckGo/Subscription/AccountManagerExtension.swift @@ -0,0 +1,26 @@ +// +// AccountManagerExtension.swift +// +// 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 Subscription + +public extension AccountManager { + convenience init() { + self.init(appGroup: Bundle.main.appGroup(bundle: .subs)) + } +} diff --git a/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift b/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift index 384748d320..2501527911 100644 --- a/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift +++ b/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift @@ -189,7 +189,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature { #if STRIPE let emailAccessToken = try? EmailManager().getToken() - switch await StripePurchaseFlow.prepareSubscriptionPurchase(emailAccessToken: emailAccessToken) { + switch await StripePurchaseFlow.prepareSubscriptionPurchase(emailAccessToken: emailAccessToken, subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) { case .success(let purchaseUpdate): await pushPurchaseUpdate(originalMessage: message, purchaseUpdate: purchaseUpdate) case .failure: diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index fa2519bdfb..695e9589a3 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -27,6 +27,7 @@ import NetworkProtectionProxy import NetworkProtectionUI import ServiceManagement import PixelKit +import Subscription @objc(Application) final class DuckDuckGoVPNApplication: NSApplication { @@ -43,6 +44,7 @@ final class DuckDuckGoVPNApplication: NSApplication { super.init() self.delegate = _delegate +#if DEBUG let accountManager = AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)) if let token = accountManager.accessToken { @@ -50,6 +52,7 @@ final class DuckDuckGoVPNApplication: NSApplication { } else { os_log(.error, log: .networkProtection, "🔴 VPN Agent found no token") } +#endif } required init?(coder: NSCoder) { diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift index 1c40d8cf29..2249af0b4d 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift @@ -194,7 +194,7 @@ public final class SubscriptionDebugMenu: NSMenuItem { @IBAction func showPurchaseView(_ sender: Any?) { if #available(macOS 12.0, *) { - currentViewController()?.presentAsSheet(DebugPurchaseViewController()) + currentViewController()?.presentAsSheet(DebugPurchaseViewController(subscriptionAppGroup: appGroup)) } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift index 22052dd64e..4bc920a747 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift @@ -41,13 +41,12 @@ public final class PreferencesSubscriptionModel: ObservableObject { private var signInObserver: Any? private var signOutObserver: Any? - public init(accountManager: AccountManager = AccountManager(), - openURLHandler: @escaping (URL) -> Void, + public init(openURLHandler: @escaping (URL) -> Void, openVPNHandler: @escaping () -> Void, openDBPHandler: @escaping () -> Void, sheetActionHandler: SubscriptionAccessActionHandlers, subscriptionAppGroup: String) { - self.accountManager = accountManager + self.accountManager = AccountManager(appGroup: subscriptionAppGroup) self.openURLHandler = openURLHandler self.openVPNHandler = openVPNHandler self.openDBPHandler = openDBPHandler From d068dff3af3d9c34e248cafe2eb3a84bf65cc1ea Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 1 Mar 2024 14:47:44 +0100 Subject: [PATCH 15/99] Point to BSK commit with migration --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 2 +- DuckDuckGo/Application/AppDelegate.swift | 4 +++- LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- 9 files changed, 11 insertions(+), 9 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index e7eb43ac44..4e1142c0dc 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13609,7 +13609,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = revision; - revision = 8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611; + revision = 5c0c48168023ede55ecf2cd410e60ca16e5dc721; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index a31069f6b1..9824c2c5ac 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,7 +23,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611" + "revision" : "5c0c48168023ede55ecf2cd410e60ca16e5dc721" } }, { diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index c0a706dbd4..13beb2f285 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -296,7 +296,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel SubscriptionPurchaseEnvironment.current = .appStore #endif SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging - await AccountManager().checkSubscriptionState() + let accountManager = AccountManager() + accountManager + await accountManager.checkSubscriptionState() } #endif } diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 86be496221..de79276945 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", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index 57a36ed238..6bd43506fd 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721") ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index 2b123bf057..4a42d4e1d6 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index ca7b60807b..0a14810934 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", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 445aa685d8..c56a0dfef4 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../SwiftUIExtensions"), .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721") ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index b096a7cea0..3d39bd69d0 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -17,7 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "8274d9bee6f4c1d6cda75c3a9ca0a8d0b79c5611") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From 3102a55423aa993b620cbbf1071ea4caf5fe05b7 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 1 Mar 2024 15:25:42 +0100 Subject: [PATCH 16/99] Migrate access token --- DuckDuckGo/Application/AppDelegate.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index 13beb2f285..0df6050766 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -297,7 +297,18 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel #endif SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging let accountManager = AccountManager() - accountManager + do { + try accountManager.migrateAccessTokenToNewStore() + } catch { + if let error = error as? AccountManager.MigrationError { + switch error { + case AccountManager.MigrationError.migrationFailed: + os_log(.default, log: .subscription, "Access token migration failed") + case AccountManager.MigrationError.noMigrationNeeded: + os_log(.default, log: .subscription, "No access token migration needed") + } + } + } await accountManager.checkSubscriptionState() } #endif From 17612bfa4b5944b62196d2a77f3a133cdad2d58b Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 1 Mar 2024 16:00:24 +0100 Subject: [PATCH 17/99] Point to update BSK branch after main merge --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 2 +- LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 155bd2ec30..17e7c76abd 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13598,7 +13598,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = revision; - revision = 5c0c48168023ede55ecf2cd410e60ca16e5dc721; + revision = cb11e5449e9767796ae539688fa4b9319db5024c; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 9824c2c5ac..b035ea93a8 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,7 +23,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "5c0c48168023ede55ecf2cd410e60ca16e5dc721" + "revision" : "cb11e5449e9767796ae539688fa4b9319db5024c" } }, { diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index de79276945..7c8f2539d2 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", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "cb11e5449e9767796ae539688fa4b9319db5024c"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index 6bd43506fd..44934f6a8a 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "cb11e5449e9767796ae539688fa4b9319db5024c") ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index 4a42d4e1d6..f04c00e598 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "cb11e5449e9767796ae539688fa4b9319db5024c"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 0a14810934..7d0933cd19 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", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "cb11e5449e9767796ae539688fa4b9319db5024c"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index c56a0dfef4..147f7c8651 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../SwiftUIExtensions"), .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "cb11e5449e9767796ae539688fa4b9319db5024c") ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index 3d39bd69d0..2f8b1069f1 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -17,7 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "5c0c48168023ede55ecf2cd410e60ca16e5dc721") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "cb11e5449e9767796ae539688fa4b9319db5024c") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From 22660429a9954893300d8b70c8594ca33ee36dfd Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 1 Mar 2024 17:23:27 +0100 Subject: [PATCH 18/99] Few fixes post merge of token branch --- DuckDuckGo.xcodeproj/project.pbxproj | 22 -------------- .../xcshareddata/swiftpm/Package.resolved | 8 ----- ...rkProtectionUNNotificationsPresenter.swift | 4 --- .../NetworkProtectionStatusViewModel.swift | 29 +++++++++---------- ...rotectionAgentNotificationsPresenter.swift | 4 --- 5 files changed, 13 insertions(+), 54 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index d22dbbb740..7d5fb2970e 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3104,11 +3104,6 @@ EE7295EF2A545C12008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295EE2A545C12008C0991 /* NetworkProtection */; }; EEA3EEB12B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */; }; EEA3EEB32B24EC0600E8333A /* VPNLocationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */; }; - EEA4A6402B90E7490046A237 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */; }; - EEA4A6412B90E78C0046A237 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */; }; - EEA4A6422B90E78E0046A237 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */; }; - EEA4A6432B90E7C00046A237 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */; }; - EEA4A6442B90E7C10046A237 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */; }; EEAD7A7A2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; EEAD7A7B2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; EEAD7A7C2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; @@ -4462,7 +4457,6 @@ EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationsHostingViewController.swift; sourceTree = ""; }; EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNCountryLabelsModel.swift; sourceTree = ""; }; EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNLocationViewModel.swift; sourceTree = ""; }; - EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountManagerExtension.swift; sourceTree = ""; }; EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLauncher.swift; sourceTree = ""; }; EEBE97B22B7E48A600404915 /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = ""; }; EEC111E3294D06020086524F /* JSAlert.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = JSAlert.storyboard; sourceTree = ""; }; @@ -4568,7 +4562,6 @@ buildActionMask = 2147483647; files = ( 4B41EDAB2B1544B2001EEDF4 /* LoginItems in Frameworks */, - EE297CC52B83EF480083DB29 /* Subscription in Frameworks */, 7B00997D2B6508B700FE7C31 /* NetworkProtectionProxy in Frameworks */, 7BEEA5122AD1235B00A9E72B /* NetworkProtectionIPC in Frameworks */, 7BA7CC5F2AD1210C0042E5CE /* Networking in Frameworks */, @@ -4588,7 +4581,6 @@ EE2F9C5D2B90F31B00D45FC9 /* Subscription in Frameworks */, 7BA7CC612AD1211C0042E5CE /* Networking in Frameworks */, 7BEEA5142AD1236300A9E72B /* NetworkProtectionIPC in Frameworks */, - EE297CC72B83EF510083DB29 /* Subscription in Frameworks */, 7B00997F2B6508C200FE7C31 /* NetworkProtectionProxy in Frameworks */, EE7295EF2A545C12008C0991 /* NetworkProtection in Frameworks */, 4B2D067F2A1334D700DE1F49 /* NetworkProtectionUI in Frameworks */, @@ -8295,14 +8287,6 @@ path = VPNLocation; sourceTree = ""; }; - EEA4A63E2B90E7210046A237 /* Subscription */ = { - isa = PBXGroup; - children = ( - EEA4A63F2B90E7490046A237 /* AccountManagerExtension.swift */, - ); - path = Subscription; - sourceTree = ""; - }; EEAEA3F4294D05CF00D04DF3 /* JSAlert */ = { isa = PBXGroup; children = ( @@ -8529,7 +8513,6 @@ 7BEC182E2AD5D8DC00D30536 /* SystemExtensionManager */, 7BFCB74D2ADE7E1A00DA3EA7 /* PixelKit */, 4B41EDAA2B1544B2001EEDF4 /* LoginItems */, - EE297CC42B83EF480083DB29 /* Subscription */, 7B00997C2B6508B700FE7C31 /* NetworkProtectionProxy */, EE2F9C5A2B90F2FF00D45FC9 /* Subscription */, ); @@ -9731,7 +9714,6 @@ 3706FEBF293F6EFF00E42796 /* BWError.swift in Sources */, 3706FAC6293F65D500E42796 /* ConnectBitwardenViewController.swift in Sources */, EEC589DA2A4F1CE400BCD60C /* AppLauncher.swift in Sources */, - EEA4A6412B90E78C0046A237 /* AccountManagerExtension.swift in Sources */, 3706FAC8293F65D500E42796 /* AppTrackerDataSetProvider.swift in Sources */, 3706FAC9293F65D500E42796 /* EncryptionKeyGeneration.swift in Sources */, 3706FACA293F65D500E42796 /* TabLazyLoader.swift in Sources */, @@ -10730,7 +10712,6 @@ 7B0694982B6E980F00FA4DBA /* VPNProxyLauncher.swift in Sources */, EEC589DB2A4F1CE700BCD60C /* AppLauncher.swift in Sources */, B65DA5EF2A77CC3A00CBEE8D /* Bundle+NetworkProtectionExtensions.swift in Sources */, - EEA4A6432B90E7C00046A237 /* AccountManagerExtension.swift in Sources */, 4BF0E5072AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */, 7BA7CC442AD11E490042E5CE /* UserText.swift in Sources */, 4BF0E5142AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, @@ -10765,7 +10746,6 @@ B65DA5F02A77CC3C00CBEE8D /* Bundle+NetworkProtectionExtensions.swift in Sources */, 7BAF9E4D2A8A3CCB002D3B6E /* UserDefaults+NetworkProtectionShared.swift in Sources */, 7BA7CC392AD11E2D0042E5CE /* DuckDuckGoVPNAppDelegate.swift in Sources */, - EEA4A6442B90E7C10046A237 /* AccountManagerExtension.swift in Sources */, 7BA7CC552AD11FFB0042E5CE /* NetworkProtectionOptionKeyExtension.swift in Sources */, 7BA7CC3D2AD11E380042E5CE /* TunnelControllerIPCService.swift in Sources */, 4BA7C4DA2B3F639800AFE511 /* NetworkProtectionTunnelController.swift in Sources */, @@ -11429,7 +11409,6 @@ B6ABC5982B4861D4008343B9 /* FocusableTextField.swift in Sources */, 4B957B752AC7AE700062CA31 /* RandomAccessCollectionExtension.swift in Sources */, 4B957B762AC7AE700062CA31 /* NSOutlineViewExtensions.swift in Sources */, - EEA4A6422B90E78E0046A237 /* AccountManagerExtension.swift in Sources */, 4B957B772AC7AE700062CA31 /* AppDelegate.swift in Sources */, 4B957B782AC7AE700062CA31 /* ContentOverlayViewController.swift in Sources */, 4B957B792AC7AE700062CA31 /* ContentBlockingTabExtension.swift in Sources */, @@ -12110,7 +12089,6 @@ 4BB99D0126FE191E001E4761 /* ChromiumBookmarksReader.swift in Sources */, B6C0B23426E71BCD0031CB7F /* Downloads.xcdatamodeld in Sources */, AAE8B110258A456C00E81239 /* TabPreviewViewController.swift in Sources */, - EEA4A6402B90E7490046A237 /* AccountManagerExtension.swift in Sources */, B6C8CAA72AD010DD0060E1CD /* YandexDataImporter.swift in Sources */, EE66666F2B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */, 37CC53EC27E8A4D10028713D /* PreferencesPrivacyView.swift in Sources */, diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b035ea93a8..cdc206489c 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -18,14 +18,6 @@ "version" : "3.0.0" } }, - { - "identity" : "browserserviceskit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/duckduckgo/BrowserServicesKit", - "state" : { - "revision" : "cb11e5449e9767796ae539688fa4b9319db5024c" - } - }, { "identity" : "content-scope-scripts", "kind" : "remoteSourceControl", diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift index 2dfb6b81de..7ee5c960ac 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/AppExtensionAndNotificationTargets/NetworkProtectionUNNotificationsPresenter.swift @@ -147,10 +147,6 @@ final class NetworkProtectionUNNotificationsPresenter: NSObject, NetworkProtecti showNotification(.test, content) } - func showEntitlementNotification(completion: @escaping (Error?) -> Void) { - // todo - } - private func showNotification(_ identifier: NetworkProtectionNotificationIdentifier, _ content: UNNotificationContent) { let request = UNNotificationRequest(identifier: identifier.rawValue, content: content, trigger: .none) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 912d75807b..b78a584a0c 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -94,8 +94,6 @@ extension NetworkProtectionStatusView { /// private let runLoopMode: RunLoop.Mode? - private let entitlementMonitor: NetworkProtectionEntitlementMonitor - private var cancellables = Set() // MARK: - Dispatch Queues @@ -126,7 +124,6 @@ extension NetworkProtectionStatusView { self.agentLoginItem = agentLoginItem self.isMenuBarStatusView = isMenuBarStatusView self.runLoopMode = runLoopMode - self.entitlementMonitor = NetworkProtectionEntitlementMonitor() tunnelControllerViewModel = TunnelControllerViewModel(controller: tunnelController, onboardingStatusPublisher: onboardingStatusPublisher, @@ -154,19 +151,19 @@ extension NetworkProtectionStatusView { } .store(in: &cancellables) - Task { - await entitlementMonitor.start(entitlementCheck: entitlementCheck) { [weak self] result in - guard let self else { return } - switch result { - case .validEntitlement: - self.shouldShowSubscriptionExpired = false - case .invalidEntitlement: - self.shouldShowSubscriptionExpired = true - case .error: - break - } - } - } +// Task { +// await entitlementMonitor.start(entitlementCheck: entitlementCheck) { [weak self] result in +// guard let self else { return } +// switch result { +// case .validEntitlement: +// self.shouldShowSubscriptionExpired = false +// case .invalidEntitlement: +// self.shouldShowSubscriptionExpired = true +// case .error: +// break +// } +// } +// } } func refreshLoginItemStatus() { diff --git a/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift b/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift index f89c3cc385..7c5e7813b1 100644 --- a/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift +++ b/NetworkProtectionSystemExtension/NetworkProtectionAgentNotificationsPresenter.swift @@ -55,8 +55,4 @@ final class NetworkProtectionAgentNotificationsPresenter: NetworkProtectionNotif func showTestNotification() { notificationCenter.post(.showTestNotification) } - - func showEntitlementNotification(completion: @escaping (Error?) -> Void) { - // todo - } } From 4f0069c7f786fc957e0593ecc580bc83dc58aa16 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 5 Mar 2024 13:51:07 +0100 Subject: [PATCH 19/99] wip --- .../App/DuckDuckGoPrivacyPro.xcconfig | 2 +- .../View/NavigationBarViewController.swift | 8 +++---- .../MacPacketTunnelProvider.swift | 4 ++-- .../NetworkProtectionStatusViewModel.swift | 24 +++++++++---------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Configuration/App/DuckDuckGoPrivacyPro.xcconfig b/Configuration/App/DuckDuckGoPrivacyPro.xcconfig index 3c4e68369f..576ce0feec 100644 --- a/Configuration/App/DuckDuckGoPrivacyPro.xcconfig +++ b/Configuration/App/DuckDuckGoPrivacyPro.xcconfig @@ -21,6 +21,6 @@ #include "DuckDuckGo.xcconfig" -FEATURE_FLAGS = FEEDBACK NETWORK_PROTECTION SPARKLE SUBSCRIPTION DBP STRIPE SUBSCRIPTION_OVERRIDE_ENABLED +FEATURE_FLAGS = FEEDBACK NETWORK_PROTECTION SPARKLE SUBSCRIPTION DBP SUBSCRIPTION_OVERRIDE_ENABLED PRODUCT_NAME = $(PRODUCT_NAME_PREFIX) Privacy Pro PRODUCT_MODULE_NAME = $(PRIVACY_PRO_PRODUCT_MODULE_NAME_OVERRIDE:default=$(DEFAULT_PRODUCT_MODULE_NAME)) diff --git a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift index b2f1e4c7b3..cfcc7cf553 100644 --- a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift +++ b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift @@ -335,10 +335,10 @@ final class NavigationBarViewController: NSViewController { let accountManager = AccountManager() let networkProtectionTokenStorage = NetworkProtectionKeychainTokenStore() -// if accountManager.accessToken != nil && (try? networkProtectionTokenStorage.fetchToken()) == nil { -// print("[NetP Subscription] Got access token but not auth token, meaning token exchange failed") -// return -// } + if accountManager.accessToken != nil && (try? networkProtectionTokenStorage.fetchToken()) == nil { + print("[NetP Subscription] Got access token but not auth token, meaning token exchange failed") + return + } } #endif diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 90c9a17a73..7d59a0ceaf 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -231,7 +231,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { let tokenStore = NetworkProtectionKeychainTokenStore(keychainType: Bundle.keychainType, serviceName: Self.tokenServiceName, errorEvents: debugEvents, - isSubscriptionEnabled: false) + isSubscriptionEnabled: true) let notificationsPresenter = NetworkProtectionNotificationsPresenterFactory().make(settings: settings) super.init(notificationsPresenter: notificationsPresenter, @@ -242,7 +242,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { debugEvents: debugEvents, providerEvents: Self.packetTunnelProviderEvents, settings: settings, - isSubscriptionEnabled: false, + isSubscriptionEnabled: true, entitlementCheck: nil) observeServerChanges() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index b78a584a0c..33991271e4 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -151,19 +151,17 @@ extension NetworkProtectionStatusView { } .store(in: &cancellables) -// Task { -// await entitlementMonitor.start(entitlementCheck: entitlementCheck) { [weak self] result in -// guard let self else { return } -// switch result { -// case .validEntitlement: -// self.shouldShowSubscriptionExpired = false -// case .invalidEntitlement: -// self.shouldShowSubscriptionExpired = true -// case .error: -// break -// } -// } -// } + Timer.publish(every: 60, on: .main, in: .default).sink { [weak self] _ in + Task { + let result = await entitlementCheck() + switch result { + case .success(let enabled): + self?.shouldShowSubscriptionExpired = !enabled + case .failure: + break + } + } + }.store(in: &cancellables) } func refreshLoginItemStatus() { From 0d92bddf7caf0b67af4eafe0ee83d4b15c3aa932 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:04:03 +0100 Subject: [PATCH 20/99] Point to updated BSK branch --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 6 +++--- LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 17e7c76abd..4efff9750e 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13598,7 +13598,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = revision; - revision = cb11e5449e9767796ae539688fa4b9319db5024c; + revision = 2fa74adb82a6478ee9f737f54d8bed75eefa725d; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b035ea93a8..ec1a58caa7 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,7 +23,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "cb11e5449e9767796ae539688fa4b9319db5024c" + "revision" : "2fa74adb82a6478ee9f737f54d8bed75eefa725d" } }, { @@ -31,8 +31,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "a3690b7666a3617693383d948cb492513f6aa569", - "version" : "5.0.0" + "revision" : "59752eb7973d3e3b0c23255ff51359f48b343f15", + "version" : "5.2.0" } }, { diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 7c8f2539d2..581c7b4433 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", revision: "cb11e5449e9767796ae539688fa4b9319db5024c"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index 44934f6a8a..ed6c5b8908 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "cb11e5449e9767796ae539688fa4b9319db5024c") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d") ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index f04c00e598..719db65cd5 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "cb11e5449e9767796ae539688fa4b9319db5024c"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 7d0933cd19..d0e5ae634e 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", revision: "cb11e5449e9767796ae539688fa4b9319db5024c"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 147f7c8651..9d0c146d87 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../SwiftUIExtensions"), .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "cb11e5449e9767796ae539688fa4b9319db5024c") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d") ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index 2f8b1069f1..1f6c356a4f 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -17,7 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "cb11e5449e9767796ae539688fa4b9319db5024c") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From 0072d395ba7bddd9c9aadbaee662c08cb6fc9208 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:10:08 +0100 Subject: [PATCH 21/99] Uncomment accidentally commented code --- .../NavigationBar/View/NavigationBarViewController.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift index b2f1e4c7b3..cfcc7cf553 100644 --- a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift +++ b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift @@ -335,10 +335,10 @@ final class NavigationBarViewController: NSViewController { let accountManager = AccountManager() let networkProtectionTokenStorage = NetworkProtectionKeychainTokenStore() -// if accountManager.accessToken != nil && (try? networkProtectionTokenStorage.fetchToken()) == nil { -// print("[NetP Subscription] Got access token but not auth token, meaning token exchange failed") -// return -// } + if accountManager.accessToken != nil && (try? networkProtectionTokenStorage.fetchToken()) == nil { + print("[NetP Subscription] Got access token but not auth token, meaning token exchange failed") + return + } } #endif From 8a1b8b625942b55c0b5427e8f8fe0186b243366f Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:12:33 +0100 Subject: [PATCH 22/99] Remove AccountManager from NetPTunnelController for now --- .../BothAppTargets/NetworkProtectionTunnelController.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index 65aa53a36d..3eb54f6f2b 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -29,8 +29,6 @@ import NetworkProtectionUI import Networking import PixelKit -import Subscription - #if NETP_SYSTEM_EXTENSION import SystemExtensionManager import SystemExtensions @@ -45,8 +43,6 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr let settings: VPNSettings - let accountManager = AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)) - // MARK: - Combine Cancellables private var cancellables = Set() From 9fda9452a31dfac7638acd75be97b0d600509de3 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 6 Mar 2024 10:53:07 +0100 Subject: [PATCH 23/99] Revert change to xcsttrings --- DuckDuckGo/InfoPlist.xcstrings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGo/InfoPlist.xcstrings b/DuckDuckGo/InfoPlist.xcstrings index 2fdf02a49b..28e181ef08 100644 --- a/DuckDuckGo/InfoPlist.xcstrings +++ b/DuckDuckGo/InfoPlist.xcstrings @@ -14,7 +14,7 @@ "en" : { "stringUnit" : { "state" : "new", - "value" : "DuckDuckGo Privacy Pro" + "value" : "DuckDuckGo" } }, "es" : { From 32d9ec4ae3fdab3e017b5a49a1774bc53fecd7f7 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 6 Mar 2024 11:14:56 +0100 Subject: [PATCH 24/99] Remove accidental service env change --- DuckDuckGo/Application/AppDelegate.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index 497d216d12..d2f5824fb4 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -291,7 +291,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel #else SubscriptionPurchaseEnvironment.current = .appStore #endif - SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging let accountManager = AccountManager() do { try accountManager.migrateAccessTokenToNewStore() From 6d1ed5f036e936f8a2ebd0b64e47af77d792af3c Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 6 Mar 2024 11:21:59 +0100 Subject: [PATCH 25/99] Revert change to netP keychain group --- DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements b/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements index 2699e730cf..44a41ea69a 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements +++ b/DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements @@ -15,7 +15,7 @@ keychain-access-groups - $(AppIdentifierPrefix)$(NETP_APP_GROUP) + $(NETP_APP_GROUP) $(SUBSCRIPTION_APP_GROUP) From cd0de7e704442edd245878adb7c760e1e3e2c730 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 6 Mar 2024 13:20:51 +0100 Subject: [PATCH 26/99] Subscription flag AccountManagerExtension --- DuckDuckGo/Subscription/AccountManagerExtension.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/Subscription/AccountManagerExtension.swift b/DuckDuckGo/Subscription/AccountManagerExtension.swift index 09804e4d3d..05e7410b14 100644 --- a/DuckDuckGo/Subscription/AccountManagerExtension.swift +++ b/DuckDuckGo/Subscription/AccountManagerExtension.swift @@ -16,7 +16,7 @@ // limitations under the License. // -import Foundation +#if SUBSCRIPTION import Subscription public extension AccountManager { @@ -24,3 +24,4 @@ public extension AccountManager { self.init(appGroup: Bundle.main.appGroup(bundle: .subs)) } } +#endif From 6231a8e6c456c0f35a1498e2883ecc0d55d93b48 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 6 Mar 2024 13:20:51 +0100 Subject: [PATCH 27/99] Subscription flag AccountManagerExtension --- DuckDuckGo/Subscription/AccountManagerExtension.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/Subscription/AccountManagerExtension.swift b/DuckDuckGo/Subscription/AccountManagerExtension.swift index 09804e4d3d..05e7410b14 100644 --- a/DuckDuckGo/Subscription/AccountManagerExtension.swift +++ b/DuckDuckGo/Subscription/AccountManagerExtension.swift @@ -16,7 +16,7 @@ // limitations under the License. // -import Foundation +#if SUBSCRIPTION import Subscription public extension AccountManager { @@ -24,3 +24,4 @@ public extension AccountManager { self.init(appGroup: Bundle.main.appGroup(bundle: .subs)) } } +#endif From e4e6ccf4ee999aae372a1538063b86c2ccf751c3 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:15:42 +0100 Subject: [PATCH 28/99] wip --- .../xcshareddata/swiftpm/Package.resolved | 8 ----- DuckDuckGo/InfoPlist.xcstrings | 18 ++++++------ ...etworkProtectionNavBarPopoverManager.swift | 16 ++++++++-- .../NetworkProtectionTunnelController.swift | 29 ++++++++++++++----- .../MacPacketTunnelProvider.swift | 25 ++++++++-------- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 20 ++++++++++--- .../NetworkProtectionStatusViewModel.swift | 19 ++++++------ 7 files changed, 82 insertions(+), 53 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ec1a58caa7..01299ade37 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -18,14 +18,6 @@ "version" : "3.0.0" } }, - { - "identity" : "browserserviceskit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/duckduckgo/BrowserServicesKit", - "state" : { - "revision" : "2fa74adb82a6478ee9f737f54d8bed75eefa725d" - } - }, { "identity" : "content-scope-scripts", "kind" : "remoteSourceControl", diff --git a/DuckDuckGo/InfoPlist.xcstrings b/DuckDuckGo/InfoPlist.xcstrings index 28e181ef08..94f1cca215 100644 --- a/DuckDuckGo/InfoPlist.xcstrings +++ b/DuckDuckGo/InfoPlist.xcstrings @@ -7,55 +7,55 @@ "localizations" : { "de" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "DuckDuckGo" } }, "en" : { "stringUnit" : { "state" : "new", - "value" : "DuckDuckGo" + "value" : "DuckDuckGo App Store" } }, "es" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "DuckDuckGo" } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "DuckDuckGo" } }, "it" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "DuckDuckGo" } }, "nl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "DuckDuckGo" } }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "DuckDuckGo" } }, "pt" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "DuckDuckGo" } }, "ru" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "DuckDuckGo" } } diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index 9e87ec1281..0d35b9c5b3 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -23,7 +23,10 @@ import LoginItems import NetworkProtection import NetworkProtectionIPC import NetworkProtectionUI + +#if SUBSCRIPTION import Subscription +#endif #if NETWORK_PROTECTION final class NetworkProtectionNavBarPopoverManager { @@ -65,6 +68,15 @@ final class NetworkProtectionNavBarPopoverManager { let onboardingStatusPublisher = UserDefaults.netP.networkProtectionOnboardingStatusPublisher _ = VPNSettings(defaults: .netP) let appLauncher = AppLauncher(appBundleURL: Bundle.main.bundleURL) +#if SUBSCRIPTION + let entitlementsCheck = { + await AccountManager().hasEntitlement(for: .networkProtection) + } +#else + let entitlementsCheck: (() async -> Result) = { + return .success(true) + } +#endif let popover = NetworkProtectionPopover(controller: controller, onboardingStatusPublisher: onboardingStatusPublisher, @@ -95,9 +107,7 @@ final class NetworkProtectionNavBarPopoverManager { }, agentLoginItem: LoginItem.vpnMenu, isMenuBarStatusView: false, - entitlementCheck: { - await AccountManager().hasEntitlement(for: .networkProtection) - }) + entitlementCheck: entitlementsCheck) popover.delegate = delegate networkProtectionPopover = popover diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index 1ac68dbd09..22ad2dedad 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -34,6 +34,10 @@ import SystemExtensionManager import SystemExtensions #endif +#if SUBSCRIPTION +import Subscription +#endif + typealias NetworkProtectionStatusChangeHandler = (NetworkProtection.ConnectionStatus) -> Void typealias NetworkProtectionConfigChangeHandler = () -> Void @@ -68,6 +72,12 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr /// Auth token store private let tokenStore: NetworkProtectionTokenStore +#if SUBSCRIPTION + // MARK: - Subscriptions + + private let accountManager = AccountManager() +#endif + // MARK: - Debug Options Support private let networkExtensionBundleID: String @@ -517,13 +527,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr var options = [String: NSObject]() options[NetworkProtectionOptionKey.activationAttemptId] = UUID().uuidString as NSString - if let accessToken = accountManager.accessToken { - os_log(.error, log: .networkProtection, "🟢 TunnelController found token: %{public}d", accessToken) - options[NetworkProtectionOptionKey.authToken] = NetworkProtectionKeychainTokenStore.makeToken(from: accessToken) as NSString? - } else { - os_log(.error, log: .networkProtection, "🔴 TunnelController found no token :(") - options[NetworkProtectionOptionKey.authToken] = try tokenStore.fetchToken() as NSString? - } + options[NetworkProtectionOptionKey.authToken] = try fetchAuthToken() options[NetworkProtectionOptionKey.selectedEnvironment] = settings.selectedEnvironment.rawValue as NSString options[NetworkProtectionOptionKey.selectedServer] = settings.selectedServer.stringValue as? NSString @@ -710,6 +714,17 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr throw TunnelFailureError(errorDescription: errorMessage.value) } } + + private func fetchAuthToken() throws -> NSString? { +#if SUBSCRIPTION + if let accessToken = accountManager.accessToken { + os_log(.error, log: .networkProtection, "🟢 TunnelController found token: %{public}d", accessToken) + return NetworkProtectionKeychainTokenStore.makeToken(from: accessToken) + } +#endif + os_log(.error, log: .networkProtection, "🔴 TunnelController found no token :(") + return try tokenStore.fetchToken() as NSString? + } } #endif diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 7d59a0ceaf..1ad98a42be 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -23,7 +23,10 @@ import NetworkProtection import NetworkExtension import Networking import PixelKit -// import Subscription + +#if SUBSCRIPTION +import Subscription +#endif final class MacPacketTunnelProvider: PacketTunnelProvider { @@ -233,6 +236,13 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { errorEvents: debugEvents, isSubscriptionEnabled: true) let notificationsPresenter = NetworkProtectionNotificationsPresenterFactory().make(settings: settings) +#if SUBSCRIPTION + let entitlementsCheck = { + await AccountManager().hasEntitlement(for: .networkProtection) + } +#else + let entitlementsCheck: (() async -> Result)? = nil +#endif super.init(notificationsPresenter: notificationsPresenter, tunnelHealthStore: tunnelHealthStore, @@ -243,7 +253,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { providerEvents: Self.packetTunnelProviderEvents, settings: settings, isSubscriptionEnabled: true, - entitlementCheck: nil) + entitlementCheck: entitlementsCheck) observeServerChanges() observeStatusUpdateRequests() @@ -422,15 +432,4 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { } } -#if SUBSCRIPTION && NETP_SYSTEM_EXTENSION - static func isEntitlementValid() async -> Bool { - // todo - https://app.asana.com/0/0/1206470585910128/f - await AccountManager().hasEntitlement(for: .networkProtection) - } -#else - static func isEntitlementValid() async -> Bool { - return false - } -#endif - } diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 9c54d21444..de66acd37a 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -27,7 +27,10 @@ import NetworkProtectionProxy import NetworkProtectionUI import ServiceManagement import PixelKit + +#if SUBSCRIPTION import Subscription +#endif @objc(Application) final class DuckDuckGoVPNApplication: NSApplication { @@ -44,7 +47,7 @@ final class DuckDuckGoVPNApplication: NSApplication { super.init() self.delegate = _delegate -#if DEBUG +#if DEBUG && SUBSCRIPTION let accountManager = AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)) if let token = accountManager.accessToken { @@ -220,6 +223,16 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { let model = StatusBarMenuModel(vpnSettings: .init(defaults: .netP)) +#if SUBSCRIPTION + let entitlementsCheck = { + await AccountManager().hasEntitlement(for: .networkProtection) + } +#else + let entitlementsCheck: (() async -> Result) = { + return .success(true) + } +#endif + return StatusBarMenu( model: model, onboardingStatusPublisher: onboardingStatusPublisher, @@ -242,9 +255,8 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { }, agentLoginItem: nil, isMenuBarStatusView: true, - entitlementCheck: { - return await AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)).hasEntitlement(for: .networkProtection) - }) + entitlementCheck: entitlementsCheck + ) } @MainActor diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 33991271e4..ea78780fff 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -57,7 +57,7 @@ extension NetworkProtectionStatusView { private(set) var onboardingStatus: OnboardingStatus = .completed var tunnelControllerViewDisabled: Bool { - onboardingStatus != .completed || loginItemNeedsApproval + onboardingStatus != .completed || loginItemNeedsApproval || shouldShowSubscriptionExpired } @MainActor @@ -94,6 +94,8 @@ extension NetworkProtectionStatusView { /// private let runLoopMode: RunLoop.Mode? + private let entitlementsMonitor = NetworkProtectionEntitlementMonitor() + private var cancellables = Set() // MARK: - Dispatch Queues @@ -151,17 +153,16 @@ extension NetworkProtectionStatusView { } .store(in: &cancellables) - Timer.publish(every: 60, on: .main, in: .default).sink { [weak self] _ in - Task { - let result = await entitlementCheck() + Task { + await entitlementsMonitor.start(entitlementCheck: entitlementCheck) { [weak self] result in switch result { - case .success(let enabled): - self?.shouldShowSubscriptionExpired = !enabled - case .failure: - break + case .validEntitlement, .error: + self?.shouldShowSubscriptionExpired = false + case .invalidEntitlement: + self?.shouldShowSubscriptionExpired = true } } - }.store(in: &cancellables) + } } func refreshLoginItemStatus() { From 7116ef05d4b2842776dde7ff027145bb6c4b0a56 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:36:24 +0100 Subject: [PATCH 29/99] Remove Subscription reference from VPNAppStore --- DuckDuckGo.xcodeproj/project.pbxproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 9478b87a49..85fbc8bcea 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3094,7 +3094,6 @@ EE0629752B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */; }; EE0629762B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */; }; EE2F9C5B2B90F2FF00D45FC9 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE2F9C5A2B90F2FF00D45FC9 /* Subscription */; }; - EE2F9C5D2B90F31B00D45FC9 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE2F9C5C2B90F31B00D45FC9 /* Subscription */; }; EE339228291BDEFD009F62C1 /* JSAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE339227291BDEFD009F62C1 /* JSAlertController.swift */; }; EE66666F2B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; EE6666702B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; @@ -4583,7 +4582,6 @@ buildActionMask = 2147483647; files = ( 7BFCB7502ADE7E2300DA3EA7 /* PixelKit in Frameworks */, - EE2F9C5D2B90F31B00D45FC9 /* Subscription in Frameworks */, 7BA7CC612AD1211C0042E5CE /* Networking in Frameworks */, 7BEEA5142AD1236300A9E72B /* NetworkProtectionIPC in Frameworks */, 7B00997F2B6508C200FE7C31 /* NetworkProtectionProxy in Frameworks */, @@ -8563,7 +8561,6 @@ 7BFCB74F2ADE7E2300DA3EA7 /* PixelKit */, 7B00997E2B6508C200FE7C31 /* NetworkProtectionProxy */, 4BA7C4DC2B3F64E500AFE511 /* LoginItems */, - EE2F9C5C2B90F31B00D45FC9 /* Subscription */, ); productName = DuckDuckGoAgentAppStore; productReference = 4B2D06692A13318400DE1F49 /* DuckDuckGo VPN App Store.app */; @@ -14302,11 +14299,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Subscription; }; - EE2F9C5C2B90F31B00D45FC9 /* Subscription */ = { - isa = XCSwiftPackageProductDependency; - package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Subscription; - }; EE7295E22A545B9A008C0991 /* NetworkProtection */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; From 1ebdf41d0a4e50890434274b3210e85797fe7f4c Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:34:46 +0100 Subject: [PATCH 30/99] appGroup -> subscriptionAppGroup --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 2 +- DuckDuckGo/Menus/MainMenu.swift | 2 +- .../Subscription/AccountManagerExtension.swift | 2 +- .../UserScripts/SubscriptionPagesUserScript.swift | 4 ++-- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 2 +- LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- .../DebugMenu/DebugPurchaseModel.swift | 2 +- .../DebugMenu/SubscriptionDebugMenu.swift | 12 ++++++------ .../Preferences/PreferencesSubscriptionModel.swift | 4 ++-- .../Model/ShareSubscriptionAccessModel.swift | 8 ++++---- .../SubscriptionAccessViewController.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- 17 files changed, 27 insertions(+), 27 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 85fbc8bcea..1cd0c3cb5a 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13635,7 +13635,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = revision; - revision = 2fa74adb82a6478ee9f737f54d8bed75eefa725d; + revision = a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ec1a58caa7..f647c9e42c 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,7 +23,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "2fa74adb82a6478ee9f737f54d8bed75eefa725d" + "revision" : "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac" } }, { diff --git a/DuckDuckGo/Menus/MainMenu.swift b/DuckDuckGo/Menus/MainMenu.swift index 62304ca73f..76064cf38a 100644 --- a/DuckDuckGo/Menus/MainMenu.swift +++ b/DuckDuckGo/Menus/MainMenu.swift @@ -626,7 +626,7 @@ import SubscriptionUI updateInternalTestingFlag: { isInternalTestingWrapper.wrappedValue = $0 }, currentViewController: { WindowControllersManager.shared.lastKeyMainWindowController?.mainViewController - }, appGroup: Bundle.main.appGroup(bundle: .subs)) + }, subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) #endif NSMenuItem(title: "Logging").submenu(setupLoggingMenu()) diff --git a/DuckDuckGo/Subscription/AccountManagerExtension.swift b/DuckDuckGo/Subscription/AccountManagerExtension.swift index 05e7410b14..c1758fb2e5 100644 --- a/DuckDuckGo/Subscription/AccountManagerExtension.swift +++ b/DuckDuckGo/Subscription/AccountManagerExtension.swift @@ -21,7 +21,7 @@ import Subscription public extension AccountManager { convenience init() { - self.init(appGroup: Bundle.main.appGroup(bundle: .subs)) + self.init(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) } } #endif diff --git a/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift b/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift index 02ff1334ef..23430ddc20 100644 --- a/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift +++ b/DuckDuckGo/Tab/UserScripts/SubscriptionPagesUserScript.swift @@ -358,7 +358,7 @@ extension SubscriptionPagesUseSubscriptionFeature { guard case .success = await PurchaseManager.shared.syncAppleIDAccount() else { return } - switch await AppStoreRestoreFlow.restoreAccountFromPastPurchase(appGroup: Bundle.main.appGroup(bundle: .subs)) { + switch await AppStoreRestoreFlow.restoreAccountFromPastPurchase(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) { case .success: onSuccessHandler() case .failure(let error): @@ -415,7 +415,7 @@ extension MainWindowController { window.show(.subscriptionFoundAlert(), firstButtonAction: { if #available(macOS 12.0, *) { Task { - _ = await AppStoreRestoreFlow.restoreAccountFromPastPurchase(appGroup: Bundle.main.appGroup(bundle: .subs)) + _ = await AppStoreRestoreFlow.restoreAccountFromPastPurchase(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) originalMessage.webView?.reload() } } diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 695e9589a3..71674bcf00 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -45,7 +45,7 @@ final class DuckDuckGoVPNApplication: NSApplication { super.init() self.delegate = _delegate #if DEBUG - let accountManager = AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)) + let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) if let token = accountManager.accessToken { os_log(.error, log: .networkProtection, "🟢 VPN Agent found token: %{public}d", token) diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 581c7b4433..2a9f3676e1 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", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index ed6c5b8908..9c08f3bc1a 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac") ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index 719db65cd5..cd7dcab79d 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index d0e5ae634e..ff8ea824c7 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", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift index a8fa790ff5..556d1d4b9f 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/DebugPurchaseModel.swift @@ -33,7 +33,7 @@ public final class DebugPurchaseModel: ObservableObject { self.purchaseManager = manager self.subscriptions = subscriptions self.subscriptionAppGroup = subscriptionAppGroup - self.accountManager = AccountManager(appGroup: subscriptionAppGroup) + self.accountManager = AccountManager(subscriptionAppGroup: subscriptionAppGroup) } @MainActor diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift index 2249af0b4d..0d3efd9948 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift @@ -28,7 +28,7 @@ public final class SubscriptionDebugMenu: NSMenuItem { var currentViewController: () -> NSViewController? private let accountManager: AccountManager - private let appGroup: String + private let subscriptionAppGroup: String private var _purchaseManager: Any? @available(macOS 12.0, *) @@ -49,14 +49,14 @@ public final class SubscriptionDebugMenu: NSMenuItem { isInternalTestingEnabled: @escaping () -> Bool, updateInternalTestingFlag: @escaping (Bool) -> Void, currentViewController: @escaping () -> NSViewController?, - appGroup: String) { + subscriptionAppGroup: String) { self.currentEnvironment = currentEnvironment self.updateEnvironment = updateEnvironment self.isInternalTestingEnabled = isInternalTestingEnabled self.updateInternalTestingFlag = updateInternalTestingFlag self.currentViewController = currentViewController - self.accountManager = AccountManager(appGroup: appGroup) - self.appGroup = appGroup + self.accountManager = AccountManager(subscriptionAppGroup: subscriptionAppGroup) + self.subscriptionAppGroup = subscriptionAppGroup super.init(title: "Subscription", action: nil, keyEquivalent: "") self.submenu = makeSubmenu() } @@ -194,7 +194,7 @@ public final class SubscriptionDebugMenu: NSMenuItem { @IBAction func showPurchaseView(_ sender: Any?) { if #available(macOS 12.0, *) { - currentViewController()?.presentAsSheet(DebugPurchaseViewController(subscriptionAppGroup: appGroup)) + currentViewController()?.presentAsSheet(DebugPurchaseViewController(subscriptionAppGroup: subscriptionAppGroup)) } } @@ -222,7 +222,7 @@ public final class SubscriptionDebugMenu: NSMenuItem { func restorePurchases(_ sender: Any?) { if #available(macOS 12.0, *) { Task { - await AppStoreRestoreFlow.restoreAccountFromPastPurchase(appGroup: appGroup) + await AppStoreRestoreFlow.restoreAccountFromPastPurchase(subscriptionAppGroup: subscriptionAppGroup) } } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift index 3d78f57d2c..6ec552200d 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift @@ -48,7 +48,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { openITRHandler: @escaping () -> Void, sheetActionHandler: SubscriptionAccessActionHandlers, subscriptionAppGroup: String) { - self.accountManager = AccountManager(appGroup: subscriptionAppGroup) + self.accountManager = AccountManager(subscriptionAppGroup: subscriptionAppGroup) self.openURLHandler = openURLHandler self.openVPNHandler = openVPNHandler self.openDBPHandler = openDBPHandler @@ -83,7 +83,7 @@ public final class PreferencesSubscriptionModel: ObservableObject { private func makeSubscriptionAccessModel() -> SubscriptionAccessModel { if accountManager.isUserAuthenticated { - ShareSubscriptionAccessModel(actionHandlers: sheetActionHandler, email: accountManager.email, appGroup: subscriptionAppGroup) + ShareSubscriptionAccessModel(actionHandlers: sheetActionHandler, email: accountManager.email, subscriptionAppGroup: subscriptionAppGroup) } else { ActivateSubscriptionAccessModel(actionHandlers: sheetActionHandler, shouldShowRestorePurchase: SubscriptionPurchaseEnvironment.current == .appStore) } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift index bacb8faeaf..d6bd361b80 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/Model/ShareSubscriptionAccessModel.swift @@ -23,7 +23,7 @@ public final class ShareSubscriptionAccessModel: SubscriptionAccessModel { public var title = UserText.shareModalTitle public var description = UserText.shareModalDescription - private let appGroup: String + private let subscriptionAppGroup: String private var actionHandlers: SubscriptionAccessActionHandlers public var email: String? @@ -31,10 +31,10 @@ public final class ShareSubscriptionAccessModel: SubscriptionAccessModel { public var emailDescription: String { hasEmail ? UserText.shareModalHasEmailDescription : UserText.shareModalNoEmailDescription } public var emailButtonTitle: String { hasEmail ? UserText.manageEmailButton : UserText.addEmailButton } - public init(actionHandlers: SubscriptionAccessActionHandlers, email: String?, appGroup: String) { + public init(actionHandlers: SubscriptionAccessActionHandlers, email: String?, subscriptionAppGroup: String) { self.actionHandlers = actionHandlers self.email = email - self.appGroup = appGroup + self.subscriptionAppGroup = subscriptionAppGroup } private var hasEmail: Bool { !(email?.isEmpty ?? true) } @@ -45,7 +45,7 @@ public final class ShareSubscriptionAccessModel: SubscriptionAccessModel { Task { if SubscriptionPurchaseEnvironment.current == .appStore { if #available(macOS 12.0, iOS 15.0, *) { - await AppStoreAccountManagementFlow.refreshAuthTokenIfNeeded(subscriptionAppGroup: appGroup) + await AppStoreAccountManagementFlow.refreshAuthTokenIfNeeded(subscriptionAppGroup: subscriptionAppGroup) } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift index b1b077754b..3833c60ff0 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/SubscriptionAccessView/SubscriptionAccessViewController.swift @@ -57,7 +57,7 @@ public final class SubscriptionAccessViewController: NSViewController { private func makeSubscriptionAccessModel() -> SubscriptionAccessModel { if accountManager.isUserAuthenticated { - ShareSubscriptionAccessModel(actionHandlers: actionHandlers, email: accountManager.email, appGroup: subscriptionAppGroup) + ShareSubscriptionAccessModel(actionHandlers: actionHandlers, email: accountManager.email, subscriptionAppGroup: subscriptionAppGroup) } else { ActivateSubscriptionAccessModel(actionHandlers: actionHandlers, shouldShowRestorePurchase: SubscriptionPurchaseEnvironment.current == .appStore) } diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 9d0c146d87..526671c5c8 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../SwiftUIExtensions"), .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac") ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index 1f6c356a4f..b2efbef02d 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -17,7 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "1.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "2fa74adb82a6478ee9f737f54d8bed75eefa725d") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From 3432ea72322f64ac70c40638b9bc09c0ed29ab2d Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 6 Mar 2024 19:19:08 +0100 Subject: [PATCH 31/99] Use UserDefaults for communicating entitlements validity --- ...erDefaults+NetworkProtectionWaitlist.swift | 2 + ...etworkProtectionNavBarPopoverManager.swift | 3 +- ...rkProtectionSubscriptionEventHandler.swift | 8 +++- .../Model/PreferencesSidebarModel.swift | 1 + DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 25 ++++++++++- ...NetworkProtectionExpiredEntitlements.swift | 44 +++++++++++++++++++ .../Menu/StatusBarMenu.swift | 6 ++- .../NetworkProtectionPopover.swift | 6 ++- .../NetworkProtectionStatusViewModel.swift | 29 +++++++----- 9 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift diff --git a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/UserDefaults+NetworkProtectionWaitlist.swift b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/UserDefaults+NetworkProtectionWaitlist.swift index c557fb2605..0b06389674 100644 --- a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/UserDefaults+NetworkProtectionWaitlist.swift +++ b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/UserDefaults+NetworkProtectionWaitlist.swift @@ -1,4 +1,5 @@ // +// // UserDefaults+NetworkProtectionWaitlist.swift // // Copyright © 2023 DuckDuckGo. All rights reserved. @@ -63,6 +64,7 @@ extension UserDefaults { } } + // Convenience declaration // Convenience declaration var networkProtectionWaitlistEnabledOverrideRawValueKey: String { UserDefaultsWrapper.Key.networkProtectionWaitlistEnabledOverrideRawValue.rawValue diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index 0d35b9c5b3..a23f036770 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -107,7 +107,8 @@ final class NetworkProtectionNavBarPopoverManager { }, agentLoginItem: LoginItem.vpnMenu, isMenuBarStatusView: false, - entitlementCheck: entitlementsCheck) + entitlementCheck: entitlementsCheck, + userDefaults: .netP) popover.delegate = delegate networkProtectionPopover = popover diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift index 3dcac1a162..c35b4fe0de 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift @@ -21,6 +21,7 @@ import Foundation import Subscription import NetworkProtection +import NetworkProtectionUI final class NetworkProtectionSubscriptionEventHandler { @@ -28,15 +29,18 @@ final class NetworkProtectionSubscriptionEventHandler { private let networkProtectionRedemptionCoordinator: NetworkProtectionCodeRedeeming private let networkProtectionTokenStorage: NetworkProtectionTokenStore private let networkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling + private let userDefaults: UserDefaults init(accountManager: AccountManaging = AccountManager(), networkProtectionRedemptionCoordinator: NetworkProtectionCodeRedeeming = NetworkProtectionCodeRedemptionCoordinator(), networkProtectionTokenStorage: NetworkProtectionTokenStore = NetworkProtectionKeychainTokenStore(), - networkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling = NetworkProtectionFeatureDisabler()) { + networkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling = NetworkProtectionFeatureDisabler(), + userDefaults: UserDefaults = .netP) { self.accountManager = accountManager self.networkProtectionRedemptionCoordinator = networkProtectionRedemptionCoordinator self.networkProtectionTokenStorage = networkProtectionTokenStorage self.networkProtectionFeatureDisabler = networkProtectionFeatureDisabler + self.userDefaults = userDefaults } func registerForSubscriptionAccountManagerEvents() { @@ -49,6 +53,7 @@ final class NetworkProtectionSubscriptionEventHandler { assertionFailure("[NetP Subscription] AccountManager signed in but token could not be retrieved") return } + userDefaults.networkProtectionEntitlementsValid = true Task { do { @@ -63,6 +68,7 @@ final class NetworkProtectionSubscriptionEventHandler { @objc private func handleAccountDidSignOut() { print("[NetP Subscription] Deleted NetP auth token after signing out from Privacy Pro") + userDefaults.networkProtectionEntitlementsValid = false Task { await networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: false) diff --git a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift index de53764fec..d1f99597d8 100644 --- a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift +++ b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift @@ -113,6 +113,7 @@ final class PreferencesSidebarModel: ObservableObject { self.refreshSections() } .store(in: &cancellables) + UserDefaults.netP.publisher(for: \.networkProtectionEntitlementsValid).receive(subscriber: DispatchQueue.main).sink { } } #endif diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index b16d37b599..2c1fced5fe 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -47,7 +47,7 @@ final class DuckDuckGoVPNApplication: NSApplication { super.init() self.delegate = _delegate -#if DEBUG +#if DEBUG && SUBSCRIPTION let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) if let token = accountManager.accessToken { @@ -255,7 +255,8 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { }, agentLoginItem: nil, isMenuBarStatusView: true, - entitlementCheck: entitlementsCheck + entitlementCheck: entitlementsCheck, + userDefaults: .netP ) } @@ -312,6 +313,24 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { let launchedOnStartup = launchInformation.wasLaunchedByStartup launchInformation.update() +#if SUBSCRIPTION + let entitlementsCheck = { + await AccountManager().hasEntitlement(for: .networkProtection) + } +#else + let entitlementsCheck: (() async -> Result) = { + return .success(true) + } +#endif + + Task { + await entitlementMonitor.start(entitlementCheck: entitlementsCheck) { result in + if case .invalidEntitlement = result { + UserDefaults.netP.networkProtectionEntitlementsValid = false + } + } + } + if launchedOnStartup { Task { let isConnected = await tunnelController.isConnected @@ -341,6 +360,8 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { } }.store(in: &cancellables) } + + private lazy var entitlementMonitor = NetworkProtectionEntitlementMonitor() } extension NSApplication { diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift new file mode 100644 index 0000000000..1852e6e653 --- /dev/null +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift @@ -0,0 +1,44 @@ +// +// UserDefaults+NetworkProtectionExpiredEntitlements.swift +// +// 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 + +public extension UserDefaults { + private enum Key: String { + case networkProtectionEntitlementsValid = "networkProtectionEntitlementsValid" + } + + // Convenience declaration + private var networkProtectionEntitlementsValidRawValueKey: String { + Key.networkProtectionEntitlementsValid.rawValue + } + + /// For KVO to work across processes (Menu App + Main App) we need to declare this dynamic var in a `UserDefaults` + /// extension, and the key for this property must match its name exactly. + /// + @objc + dynamic var networkProtectionEntitlementsValid: Bool { + get { + value(forKey: networkProtectionEntitlementsValidRawValueKey) as? Bool ?? false + } + + set { + set(newValue, forKey: networkProtectionEntitlementsValidRawValueKey) + } + } +} diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift index 015b4c21fa..b841ff679e 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift @@ -57,7 +57,8 @@ public final class StatusBarMenu: NSObject { menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, - entitlementCheck: @escaping () async -> Swift.Result) { + entitlementCheck: @escaping () async -> Swift.Result, + userDefaults: UserDefaults) { self.model = model let statusItem = statusItem ?? NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) @@ -71,7 +72,8 @@ public final class StatusBarMenu: NSObject { menuItems: menuItems, agentLoginItem: agentLoginItem, isMenuBarStatusView: isMenuBarStatusView, - entitlementCheck: entitlementCheck) + entitlementCheck: entitlementCheck, + userDefaults: userDefaults) popover.behavior = .transient diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift index 59dba8a458..bd01e5394f 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift @@ -57,7 +57,8 @@ public final class NetworkProtectionPopover: NSPopover { menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, - entitlementCheck: @escaping () async -> Swift.Result) { + entitlementCheck: @escaping () async -> Swift.Result, + userDefaults: UserDefaults) { self.statusReporter = statusReporter self.model = NetworkProtectionStatusView.Model(controller: controller, @@ -68,7 +69,8 @@ public final class NetworkProtectionPopover: NSPopover { menuItems: menuItems, agentLoginItem: agentLoginItem, isMenuBarStatusView: isMenuBarStatusView, - entitlementCheck: entitlementCheck) + entitlementCheck: entitlementCheck, + userDefaults: userDefaults) super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index ea78780fff..3ff128a1e5 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -116,7 +116,8 @@ extension NetworkProtectionStatusView { agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, runLoopMode: RunLoop.Mode? = nil, - entitlementCheck: @escaping () async -> Swift.Result) { + entitlementCheck: @escaping () async -> Swift.Result, + userDefaults: UserDefaults) { self.tunnelController = controller self.onboardingStatusPublisher = onboardingStatusPublisher @@ -153,16 +154,22 @@ extension NetworkProtectionStatusView { } .store(in: &cancellables) - Task { - await entitlementsMonitor.start(entitlementCheck: entitlementCheck) { [weak self] result in - switch result { - case .validEntitlement, .error: - self?.shouldShowSubscriptionExpired = false - case .invalidEntitlement: - self?.shouldShowSubscriptionExpired = true - } - } - } + userDefaults + .publisher(for: \.networkProtectionEntitlementsValid) + .map { !$0 } + .assign(to: \.shouldShowSubscriptionExpired, onWeaklyHeld: self) + .store(in: &cancellables) + +// Task { +// await entitlementsMonitor.start(entitlementCheck: entitlementCheck) { [weak self] result in +// switch result { +// case .validEntitlement, .error: +// self?.shouldShowSubscriptionExpired = false +// case .invalidEntitlement: +// self?.shouldShowSubscriptionExpired = true +// } +// } +// } } func refreshLoginItemStatus() { From 984febe0525d3545c15d9a7eb18e7486b55be88b Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:24:59 +0100 Subject: [PATCH 32/99] Fix entitlements notification --- .../DuckDuckGoNotificationsAppDelegate.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/DuckDuckGoNotifications/DuckDuckGoNotificationsAppDelegate.swift b/DuckDuckGoNotifications/DuckDuckGoNotificationsAppDelegate.swift index bd226a82c6..afd7309463 100644 --- a/DuckDuckGoNotifications/DuckDuckGoNotificationsAppDelegate.swift +++ b/DuckDuckGoNotifications/DuckDuckGoNotificationsAppDelegate.swift @@ -111,6 +111,12 @@ final class DuckDuckGoNotificationsAppDelegate: NSObject, NSApplicationDelegate os_log("Got notification: listener started") self?.notificationsPresenter.requestAuthorization() }.store(in: &cancellables) + + distributedNotificationCenter.publisher(for: .showExpiredEntitlementNotification) + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + self?.showEntitlementNotification() + }.store(in: &cancellables) } func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { @@ -139,6 +145,12 @@ final class DuckDuckGoNotificationsAppDelegate: NSObject, NSApplicationDelegate notificationsPresenter.showSupersededNotification() } + func showEntitlementNotification() { + os_log("Presenting Entitlements notification", log: .networkProtection, type: .info) + + notificationsPresenter.showEntitlementNotification { _ in } + } + func showTestNotification() { os_log("Presenting test notification", log: .networkProtection, type: .info) notificationsPresenter.showTestNotification() From 4bd9845fa4e54877d117433fdd5b0f728d692264 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:25:44 +0100 Subject: [PATCH 33/99] Properly enable SUBSCRIPTION flag --- Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig | 4 ++-- .../BothAppTargets/NetworkProtectionTunnelController.swift | 2 +- DuckDuckGo/Subscription/AccountManagerExtension.swift | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig b/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig index 662be4ddeb..178c5f109c 100644 --- a/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig +++ b/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig @@ -51,8 +51,8 @@ PROVISIONING_PROFILE_SPECIFIER[config=Release][sdk=macosx*] = macOS NetP VPN App FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION +FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION SUBSCRIPTION +FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION SUBSCRIPTION SWIFT_OBJC_BRIDGING_HEADER = SKIP_INSTALL = YES diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index 22ad2dedad..1a2d188761 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -719,7 +719,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr #if SUBSCRIPTION if let accessToken = accountManager.accessToken { os_log(.error, log: .networkProtection, "🟢 TunnelController found token: %{public}d", accessToken) - return NetworkProtectionKeychainTokenStore.makeToken(from: accessToken) + return NetworkProtectionKeychainTokenStore.makeToken(from: accessToken) as NSString? } #endif os_log(.error, log: .networkProtection, "🔴 TunnelController found no token :(") diff --git a/DuckDuckGo/Subscription/AccountManagerExtension.swift b/DuckDuckGo/Subscription/AccountManagerExtension.swift index c1758fb2e5..5f30dad322 100644 --- a/DuckDuckGo/Subscription/AccountManagerExtension.swift +++ b/DuckDuckGo/Subscription/AccountManagerExtension.swift @@ -17,6 +17,7 @@ // #if SUBSCRIPTION +import Foundation import Subscription public extension AccountManager { From 423f4a91d888d1b4d10a0328473e0aeed9a11a8d Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:26:56 +0100 Subject: [PATCH 34/99] Entitlements monitoring. It works. Lord be praised --- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 52 +++++++++++++------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 2c1fced5fe..caad62d149 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -313,23 +313,7 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { let launchedOnStartup = launchInformation.wasLaunchedByStartup launchInformation.update() -#if SUBSCRIPTION - let entitlementsCheck = { - await AccountManager().hasEntitlement(for: .networkProtection) - } -#else - let entitlementsCheck: (() async -> Result) = { - return .success(true) - } -#endif - - Task { - await entitlementMonitor.start(entitlementCheck: entitlementsCheck) { result in - if case .invalidEntitlement = result { - UserDefaults.netP.networkProtectionEntitlementsValid = false - } - } - } + setUpSubscriptionMonitoring() if launchedOnStartup { Task { @@ -361,6 +345,40 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { }.store(in: &cancellables) } + private func setUpSubscriptionMonitoring() { +#if SUBSCRIPTION + SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging + + let entitlementsCheck = { + await AccountManager().hasEntitlement(for: .networkProtection) + } + + Task { + await entitlementMonitor.start(entitlementCheck: entitlementsCheck) { [weak self] result in + switch result { + case .validEntitlement: + UserDefaults.netP.networkProtectionEntitlementsValid = true + case .invalidEntitlement: + UserDefaults.netP.networkProtectionEntitlementsValid = false + guard let self else { return } + Task { + let isConnected = await self.tunnelController.isConnected + if isConnected { + await self.tunnelController.stop() + } + } + case .error: + break + } + } + } +#else + let entitlementsCheck: (() async -> Result) = { + return .success(false) + } +#endif + } + private lazy var entitlementMonitor = NetworkProtectionEntitlementMonitor() } From 7f6fc7498a9020174dcd8ea3c8089181ac5473f6 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:27:22 +0100 Subject: [PATCH 35/99] Remove commented out code --- .../StatusView/NetworkProtectionStatusViewModel.swift | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 3ff128a1e5..4a9414647a 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -159,17 +159,6 @@ extension NetworkProtectionStatusView { .map { !$0 } .assign(to: \.shouldShowSubscriptionExpired, onWeaklyHeld: self) .store(in: &cancellables) - -// Task { -// await entitlementsMonitor.start(entitlementCheck: entitlementCheck) { [weak self] result in -// switch result { -// case .validEntitlement, .error: -// self?.shouldShowSubscriptionExpired = false -// case .invalidEntitlement: -// self?.shouldShowSubscriptionExpired = true -// } -// } -// } } func refreshLoginItemStatus() { From f15ddc7406f5e521fd363284366f2766801d0e4b Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:57:06 +0100 Subject: [PATCH 36/99] Just some stuff that shoulda been committed... --- DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift | 1 - DuckDuckGoVPN/NetworkProtectionBouncer.swift | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift index d1f99597d8..de53764fec 100644 --- a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift +++ b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift @@ -113,7 +113,6 @@ final class PreferencesSidebarModel: ObservableObject { self.refreshSections() } .store(in: &cancellables) - UserDefaults.netP.publisher(for: \.networkProtectionEntitlementsValid).receive(subscriber: DispatchQueue.main).sink { } } #endif diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index a9c362884d..702e9cb2ff 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -31,7 +31,7 @@ final class NetworkProtectionBouncer { /// current app. /// func requireAuthTokenOrKillApp() { - let accountManager = AccountManager(appGroup: Bundle.main.appGroup(bundle: .subs)) + let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) let keychainStore = NetworkProtectionKeychainTokenStore(keychainType: .default, errorEvents: nil, isSubscriptionEnabled: false) // TODO: Do entitlements check, not this From 14e60124dbdd435c5f86fae292629eaa98e81822 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 17:26:15 +0100 Subject: [PATCH 37/99] Handle entitlements expiring removing VPN settings --- .../Model/PreferencesSidebarModel.swift | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift index de53764fec..6dbb5fa7ec 100644 --- a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift +++ b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift @@ -21,6 +21,10 @@ import Combine import DDGSync import SwiftUI +#if SUBSCRIPTION +import Subscription +#endif + final class PreferencesSidebarModel: ObservableObject { let tabSwitcherTabs: [Tab.TabContent] @@ -78,7 +82,9 @@ final class PreferencesSidebarModel: ObservableObject { includeDuckPlayer: Bool ) { let loadSections = { -#if NETWORK_PROTECTION +#if SUBSCRIPTION + let includingVPN = UserDefaults.netP.networkProtectionEntitlementsValid && DefaultNetworkProtectionVisibility().isOnboarded +#elseif NETWORK_PROTECTION let includingVPN = DefaultNetworkProtectionVisibility().isOnboarded #else let includingVPN = false @@ -113,6 +119,16 @@ final class PreferencesSidebarModel: ObservableObject { self.refreshSections() } .store(in: &cancellables) + + UserDefaults.netP.publisher(for: \.networkProtectionEntitlementsValid) + .receive(on: DispatchQueue.main) + .sink { [weak self] entitlementsValid in + guard let self else { return } + if !entitlementsValid && self.selectedPane == .vpn { + self.selectedPane = .general + } + self.refreshSections() + }.store(in: &cancellables) } #endif From ee262e5cdbd9487e77b2a08eae29de3af345c27a Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 17:26:55 +0100 Subject: [PATCH 38/99] Add entitlements moniroting for app --- ...rkProtectionSubscriptionEventHandler.swift | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift index c35b4fe0de..97cf69d6ce 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift @@ -43,9 +43,33 @@ final class NetworkProtectionSubscriptionEventHandler { self.userDefaults = userDefaults } + private lazy var entitlementMonitor = NetworkProtectionEntitlementMonitor() + + private func setUpEntitlementMonitoring() { + SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging + + let entitlementsCheck = { + await AccountManager().hasEntitlement(for: .networkProtection) + } + + Task { + await entitlementMonitor.start(entitlementCheck: entitlementsCheck) { result in + switch result { + case .validEntitlement: + UserDefaults.netP.networkProtectionEntitlementsValid = true + case .invalidEntitlement: + UserDefaults.netP.networkProtectionEntitlementsValid = false + case .error: + break + } + } + } + } + func registerForSubscriptionAccountManagerEvents() { NotificationCenter.default.addObserver(self, selector: #selector(handleAccountDidSignIn), name: .accountDidSignIn, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleAccountDidSignOut), name: .accountDidSignOut, object: nil) + setUpEntitlementMonitoring() } @objc private func handleAccountDidSignIn() { From 8297ace2ffc0162cfe0f1dd7e4171b2635516fb4 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 17:27:46 +0100 Subject: [PATCH 39/99] Launch privacy pro page from status view --- DuckDuckGo/Application/URLEventHandler.swift | 6 +++++- .../AppAndExtensionAndAgentTargets/AppLauncher.swift | 3 +++ .../Views/StatusView/NetworkProtectionStatusView.swift | 7 ++++++- .../StatusView/NetworkProtectionStatusViewModel.swift | 9 +++++++++ .../SubscriptionExpiredView.swift | 9 +++++---- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/DuckDuckGo/Application/URLEventHandler.swift b/DuckDuckGo/Application/URLEventHandler.swift index 3af3ef418f..299ca37760 100644 --- a/DuckDuckGo/Application/URLEventHandler.swift +++ b/DuckDuckGo/Application/URLEventHandler.swift @@ -143,8 +143,12 @@ final class URLEventHandler { case AppLaunchCommand.showVPNLocations.launchURL: WindowControllersManager.shared.showPreferencesTab(withSelectedPane: .vpn) WindowControllersManager.shared.showLocationPickerSheet() - case AppLaunchCommand.moveAppToApplications.launchURL: +#if SUBSCRIPTION + case AppLaunchCommand.showPrivacyPro.launchURL: + WindowControllersManager.shared.showTab(with: .subscription(.subscriptionPurchase)) +#endif #if !APPSTORE && !DEBUG + case AppLaunchCommand.moveAppToApplications.launchURL: // this should be run after NSApplication.shared is set PFMoveToApplicationsFolderIfNecessary(false) #endif diff --git a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AppLauncher.swift b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AppLauncher.swift index 370813fb40..6433e7f44d 100644 --- a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AppLauncher.swift +++ b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/AppLauncher.swift @@ -35,6 +35,7 @@ extension AppLaunchCommand { case .showVPNLocations: return "showVPNLocations" case .enableOnDemand: return "enableOnDemand" case .moveAppToApplications: return "moveAppToApplications" + case .showPrivacyPro: return "showPrivacyPro" } } } @@ -94,6 +95,8 @@ extension AppLaunchCommand { return "networkprotection://show-settings/locations" case .moveAppToApplications: return "networkprotection://move-app-to-applications" + case .showPrivacyPro: + return "networkprotection://show-privacy-pro" default: return nil } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift index e4ce62bfba..195b3ffc24 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift @@ -51,7 +51,12 @@ public struct NetworkProtectionStatusView: View { public var body: some View { VStack(spacing: 0) { if model.shouldShowSubscriptionExpired { - SubscriptionExpiredView() + SubscriptionExpiredView { + model.openPrivacyPro() + } uninstallButtonHandler: { + + } + } else if let promptActionViewModel = model.promptActionViewModel { PromptActionView(model: promptActionViewModel) .padding(.horizontal, 5) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 4a9414647a..e4261cc1ee 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -96,6 +96,8 @@ extension NetworkProtectionStatusView { private let entitlementsMonitor = NetworkProtectionEntitlementMonitor() + private let appLauncher: AppLaunching + private var cancellables = Set() // MARK: - Dispatch Queues @@ -127,6 +129,7 @@ extension NetworkProtectionStatusView { self.agentLoginItem = agentLoginItem self.isMenuBarStatusView = isMenuBarStatusView self.runLoopMode = runLoopMode + self.appLauncher = appLauncher tunnelControllerViewModel = TunnelControllerViewModel(controller: tunnelController, onboardingStatusPublisher: onboardingStatusPublisher, @@ -178,6 +181,12 @@ extension NetworkProtectionStatusView { } } + func openPrivacyPro() { + Task { + await appLauncher.launchApp(withCommand: .showPrivacyPro) + } + } + private func subscribeToStatusChanges() { statusReporter.statusObserver.publisher .receive(on: DispatchQueue.main) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift index 251421c242..52cf3e6767 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift @@ -21,6 +21,9 @@ import SwiftUI import SwiftUIExtensions struct SubscriptionExpiredView: View { + let subscribeButtonHandler: () -> Void + let uninstallButtonHandler: () -> Void + public var body: some View { VStack(alignment: .leading, spacing: 5) { Text("VPN disconnected due to expired subscription") @@ -33,9 +36,7 @@ struct SubscriptionExpiredView: View { .foregroundColor(Color(.defaultText)) .multilineText() - Button("Subscribe to Privacy Pro") { - // TODO: - } + Button("Subscribe to Privacy Pro", action: subscribeButtonHandler) .buttonStyle(DefaultActionButtonStyle(enabled: true)) .padding(.top, 3) @@ -64,6 +65,6 @@ struct SubscriptionExpiredView: View { struct SubscriptionExpiredView_Preview: PreviewProvider { static var previews: some View { - SubscriptionExpiredView() + SubscriptionExpiredView(subscribeButtonHandler: {}, uninstallButtonHandler: {}) } } From 85c556cde8981ba1dd7ec5c9f54b44d47c1751cb Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 17:27:56 +0100 Subject: [PATCH 40/99] Tidy up var --- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index caad62d149..68b7941b65 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -345,6 +345,8 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { }.store(in: &cancellables) } + private lazy var entitlementMonitor = NetworkProtectionEntitlementMonitor() + private func setUpSubscriptionMonitoring() { #if SUBSCRIPTION SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging @@ -378,8 +380,6 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { } #endif } - - private lazy var entitlementMonitor = NetworkProtectionEntitlementMonitor() } extension NSApplication { From 5beb8f441f1019456e122396fd3888ee6a850263 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 17:35:30 +0100 Subject: [PATCH 41/99] Remove unneeded code --- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 68b7941b65..e5c875f4f9 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -374,10 +374,6 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { } } } -#else - let entitlementsCheck: (() async -> Result) = { - return .success(false) - } #endif } } From 87f58a4f0fb6183153ff787d02deb4622de59a9c Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 7 Mar 2024 17:36:30 +0100 Subject: [PATCH 42/99] Move user defaults observation to main thread --- .../Views/StatusView/NetworkProtectionStatusViewModel.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index e4261cc1ee..daf9c62a2d 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -159,6 +159,7 @@ extension NetworkProtectionStatusView { userDefaults .publisher(for: \.networkProtectionEntitlementsValid) + .receive(on: DispatchQueue.main) .map { !$0 } .assign(to: \.shouldShowSubscriptionExpired, onWeaklyHeld: self) .store(in: &cancellables) From 36f8ea34001a841606b7f7d95dc4b1cbd1d4d21b Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 8 Mar 2024 10:58:21 +0100 Subject: [PATCH 43/99] Point to update BSK branch --- DuckDuckGo.xcodeproj/project.pbxproj | 4 +--- .../xcshareddata/swiftpm/Package.resolved | 8 ++++++++ LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- 8 files changed, 15 insertions(+), 9 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 0143202721..57400efd43 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -4487,7 +4487,6 @@ EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNCountryLabelsModel.swift; sourceTree = ""; }; EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNLocationViewModel.swift; sourceTree = ""; }; EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLauncher.swift; sourceTree = ""; }; - EEBE97B22B7E48A600404915 /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = ""; }; EEC111E3294D06020086524F /* JSAlert.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = JSAlert.storyboard; sourceTree = ""; }; EEC111E5294D06290086524F /* JSAlertViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSAlertViewModel.swift; sourceTree = ""; }; EEC4A6682B2C87D300F7C0AA /* VPNLocationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationView.swift; sourceTree = ""; }; @@ -6776,7 +6775,6 @@ AA585D75248FD31100E9A3E2 = { isa = PBXGroup; children = ( - EEBE97B22B7E48A600404915 /* BrowserServicesKit */, 378B5886295CF2A4002C0CC0 /* Configuration */, 378E279C2970217400FCADA2 /* LocalPackages */, 7BB108552A43375D000AB95F /* LocalThirdParty */, @@ -13713,7 +13711,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = revision; - revision = a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac; + revision = 71c950a1aae064a48638c48a4b293d4b1c257a8d; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 3d1707c9c7..6fe567ba5c 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -27,6 +27,14 @@ "version" : "3.0.0" } }, + { + "identity" : "browserserviceskit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/duckduckgo/BrowserServicesKit", + "state" : { + "revision" : "71c950a1aae064a48638c48a4b293d4b1c257a8d" + } + }, { "identity" : "content-scope-scripts", "kind" : "remoteSourceControl", diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 077ca315f0..5fbcad3bc4 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", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index 03e5261d56..84a3de4f55 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d") ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index b9ae4f0f59..a30754bfc4 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index ff8ea824c7..6a995a051e 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", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 3321e9589c..f75d3dc0f2 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../SwiftUIExtensions"), .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d") ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index e103030d24..b70251c97e 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -17,7 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "a5b3ae827b9b659fc6cde49e7729a9e1bb1044ac") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From 7ccfee5dad8e94a3c80c6e26704d8e14410a4c49 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 8 Mar 2024 12:28:10 +0100 Subject: [PATCH 44/99] Add Subscription flag to extensions --- .../NetworkProtection/NetworkProtectionAppExtension.xcconfig | 4 ++-- .../NetworkProtectionSystemExtension.xcconfig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig b/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig index 2fb095fc56..5c67cdf327 100644 --- a/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig +++ b/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig @@ -32,8 +32,8 @@ INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023 DuckDuckGo. All right FEATURE_FLAGS[arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION +FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION +FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION PRODUCT_BUNDLE_IDENTIFIER[sdk=*] = PRODUCT_BUNDLE_IDENTIFIER[config=CI][sdk=*] = $(TUNNEL_EXTENSION_BUNDLE_ID) diff --git a/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig b/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig index c6b581e569..6cabb03058 100644 --- a/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig +++ b/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig @@ -33,8 +33,8 @@ INFOPLIST_KEY_NSSystemExtensionUsageDescription = Network Protection FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION +FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION +FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION PRODUCT_BUNDLE_IDENTIFIER[sdk=*] = $(SYSEX_BUNDLE_ID) PRODUCT_BUNDLE_IDENTIFIER[config=CI][sdk=*] = $(SYSEX_BUNDLE_ID) From b82f13dd8a24562677bd43ae1e7afed2a65b6fad Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 8 Mar 2024 12:31:41 +0100 Subject: [PATCH 45/99] Inject netP token store into accountmanager for entitlements check --- DuckDuckGo.xcodeproj/project.pbxproj | 13 ++++++ .../MacPacketTunnelProvider.swift | 6 ++- ...ore+SubscriptionTokenKeychainStorage.swift | 42 +++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 57400efd43..03a28d217b 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3113,6 +3113,9 @@ EE0629762B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */; }; EE2F9C5B2B90F2FF00D45FC9 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE2F9C5A2B90F2FF00D45FC9 /* Subscription */; }; EE339228291BDEFD009F62C1 /* JSAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE339227291BDEFD009F62C1 /* JSAlertController.swift */; }; + EE66418C2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */; }; + EE66418D2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */; }; + EE66418F2B9B1BD1005BCD17 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE66418E2B9B1BD1005BCD17 /* Subscription */; }; EE66666F2B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; EE6666702B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; EE6666712B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; @@ -4483,6 +4486,7 @@ EAFAD6C92728BD1200F9DF00 /* clickToLoad.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = clickToLoad.js; sourceTree = ""; }; EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManagerExtension.swift; sourceTree = ""; }; EE339227291BDEFD009F62C1 /* JSAlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSAlertController.swift; sourceTree = ""; }; + EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift"; sourceTree = ""; }; EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationsHostingViewController.swift; sourceTree = ""; }; EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNCountryLabelsModel.swift; sourceTree = ""; }; EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNLocationViewModel.swift; sourceTree = ""; }; @@ -4584,6 +4588,7 @@ buildActionMask = 2147483647; files = ( 37269F012B332FC8005E8E46 /* Common in Frameworks */, + EE66418F2B9B1BD1005BCD17 /* Subscription in Frameworks */, B64E429D2B908696006C1346 /* Macros in Frameworks */, EE7295E92A545BC4008C0991 /* NetworkProtection in Frameworks */, 4B2537772A11BFE100610219 /* PixelKit in Frameworks */, @@ -5605,6 +5610,7 @@ 4B41ED9F2B15437A001EEDF4 /* NetworkProtectionNotificationsPresenterFactory.swift */, EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */, 7B0099802B65C6B300FE7C31 /* MacTransparentProxyProvider.swift */, + EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */, ); path = NetworkExtensionTargets; sourceTree = ""; @@ -8553,6 +8559,7 @@ 37269F002B332FC8005E8E46 /* Common */, 7BBE2B7A2B61663C00697445 /* NetworkProtectionProxy */, B64E429C2B908696006C1346 /* Macros */, + EE66418E2B9B1BD1005BCD17 /* Subscription */, ); productName = NetworkProtectionSystemExtension; productReference = 4B25375A2A11BE7300610219 /* com.duckduckgo.macos.vpn.network-extension.debug.systemextension */; @@ -10782,6 +10789,7 @@ files = ( 4B25377A2A11C01700610219 /* UserText+NetworkProtectionExtensions.swift in Sources */, B65DA5F42A77D3FA00CBEE8D /* BundleExtension.swift in Sources */, + EE66418D2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */, 4B2D062D2A11C12300DE1F49 /* Logging.swift in Sources */, 7B2E52252A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift in Sources */, B602E8232A1E260E006D261F /* Bundle+NetworkProtectionExtensions.swift in Sources */, @@ -10890,6 +10898,7 @@ files = ( 4B41EDA02B15437A001EEDF4 /* NetworkProtectionNotificationsPresenterFactory.swift in Sources */, 4B4D609F2A0B2C7300BCD287 /* Logging.swift in Sources */, + EE66418C2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */, 7B7DFB202B7E736B009EA1A3 /* MacPacketTunnelProvider.swift in Sources */, 4B4D60A12A0B2D6100BCD287 /* NetworkProtectionOptionKeyExtension.swift in Sources */, B602E8182A1E2570006D261F /* URL+NetworkProtection.swift in Sources */, @@ -14473,6 +14482,10 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Subscription; }; + EE66418E2B9B1BD1005BCD17 /* Subscription */ = { + isa = XCSwiftPackageProductDependency; + productName = Subscription; + }; EE7295E22A545B9A008C0991 /* NetworkProtection */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 2175384f4d..80efe5f643 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -239,10 +239,12 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { let notificationsPresenter = NetworkProtectionNotificationsPresenterFactory().make(settings: settings, defaults: defaults) #if SUBSCRIPTION let entitlementsCheck = { - await AccountManager().hasEntitlement(for: .networkProtection) + await AccountManager(accessTokenStorage: tokenStore).hasEntitlement(for: .networkProtection) } + let isSubscriptionEnabled = true #else let entitlementsCheck: (() async -> Result)? = nil + let isSubscriptionEnabled = false #endif super.init(notificationsPresenter: notificationsPresenter, @@ -254,7 +256,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { providerEvents: Self.packetTunnelProviderEvents, settings: settings, defaults: defaults, - isSubscriptionEnabled: false, + isSubscriptionEnabled: isSubscriptionEnabled, entitlementCheck: entitlementsCheck) observeServerChanges() diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift new file mode 100644 index 0000000000..0e7ee9445a --- /dev/null +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift @@ -0,0 +1,42 @@ +// +// NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift +// +// 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 Subscription +import NetworkProtection +import Common + +extension NetworkProtectionKeychainTokenStore: SubscriptionTokenStorage { + public func store(accessToken: String) throws { + let tokenToStore = Self.makeToken(from: accessToken) + try store(tokenToStore) + } + + public func getAccessToken() throws -> String? { + guard var token = try fetchToken() else { return nil } + if token.hasPrefix("ddg:") { + token = token.replacingOccurrences(of: "ddg:", with: "") + } + os_log("🔵 Wrapper successfully fetched token %{token}@", log: .networkProtection, type: .info, token) + return token + } + + public func removeAccessToken() throws { + try deleteToken() + } +} From 306dd22765ad6f055fab71b0518a4094306e96ed Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:18:14 +0100 Subject: [PATCH 46/99] Send notification from agent on entitlement expiry --- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index e5c875f4f9..5e7b7e2587 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -367,6 +367,7 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { let isConnected = await self.tunnelController.isConnected if isConnected { await self.tunnelController.stop() + DistributedNotificationCenter.default().post(.showExpiredEntitlementNotification) } } case .error: From f24da6bb9c8789a3b839e7dd5dd826716e19b588 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:18:38 +0100 Subject: [PATCH 47/99] Make sure subs environment properly set up --- .../MacPacketTunnelProvider.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 80efe5f643..b7e7d0f424 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -223,6 +223,12 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { @objc public init() { self.appLauncher = AppLauncher(appBundleURL: .mainAppBundleURL) +#if SUBSCRIPTION + let isSubscriptionEnabled = true +#else + let isSubscriptionEnabled = false +#endif + #if NETP_SYSTEM_EXTENSION let defaults = UserDefaults.standard #else @@ -235,16 +241,15 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { let tokenStore = NetworkProtectionKeychainTokenStore(keychainType: Bundle.keychainType, serviceName: Self.tokenServiceName, errorEvents: debugEvents, - isSubscriptionEnabled: true) + isSubscriptionEnabled: isSubscriptionEnabled) let notificationsPresenter = NetworkProtectionNotificationsPresenterFactory().make(settings: settings, defaults: defaults) #if SUBSCRIPTION + SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging let entitlementsCheck = { await AccountManager(accessTokenStorage: tokenStore).hasEntitlement(for: .networkProtection) } - let isSubscriptionEnabled = true #else let entitlementsCheck: (() async -> Result)? = nil - let isSubscriptionEnabled = false #endif super.init(notificationsPresenter: notificationsPresenter, From f9145189e1e31c68d272c3088ef5578f3ede32ba Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 12 Mar 2024 10:26:56 +0100 Subject: [PATCH 48/99] Remove unnecessary entitlementCheck injection --- .../NetworkProtectionNavBarPopoverManager.swift | 1 - DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 11 ----------- .../NetworkProtectionUI/Menu/StatusBarMenu.swift | 2 -- .../NetworkProtectionPopover.swift | 2 -- .../StatusView/NetworkProtectionStatusViewModel.swift | 3 --- 5 files changed, 19 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index a23f036770..2bacf8f933 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -107,7 +107,6 @@ final class NetworkProtectionNavBarPopoverManager { }, agentLoginItem: LoginItem.vpnMenu, isMenuBarStatusView: false, - entitlementCheck: entitlementsCheck, userDefaults: .netP) popover.delegate = delegate diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 5e7b7e2587..27e319e7f4 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -223,16 +223,6 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { let model = StatusBarMenuModel(vpnSettings: .init(defaults: .netP)) -#if SUBSCRIPTION - let entitlementsCheck = { - await AccountManager().hasEntitlement(for: .networkProtection) - } -#else - let entitlementsCheck: (() async -> Result) = { - return .success(true) - } -#endif - return StatusBarMenu( model: model, onboardingStatusPublisher: onboardingStatusPublisher, @@ -255,7 +245,6 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { }, agentLoginItem: nil, isMenuBarStatusView: true, - entitlementCheck: entitlementsCheck, userDefaults: .netP ) } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift index b841ff679e..ba25b1485b 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift @@ -57,7 +57,6 @@ public final class StatusBarMenu: NSObject { menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, - entitlementCheck: @escaping () async -> Swift.Result, userDefaults: UserDefaults) { self.model = model @@ -72,7 +71,6 @@ public final class StatusBarMenu: NSObject { menuItems: menuItems, agentLoginItem: agentLoginItem, isMenuBarStatusView: isMenuBarStatusView, - entitlementCheck: entitlementCheck, userDefaults: userDefaults) popover.behavior = .transient diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift index bd01e5394f..2c4a264ed1 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift @@ -57,7 +57,6 @@ public final class NetworkProtectionPopover: NSPopover { menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, - entitlementCheck: @escaping () async -> Swift.Result, userDefaults: UserDefaults) { self.statusReporter = statusReporter @@ -69,7 +68,6 @@ public final class NetworkProtectionPopover: NSPopover { menuItems: menuItems, agentLoginItem: agentLoginItem, isMenuBarStatusView: isMenuBarStatusView, - entitlementCheck: entitlementCheck, userDefaults: userDefaults) super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 96b43fe284..a0260b5153 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -95,8 +95,6 @@ extension NetworkProtectionStatusView { /// private let runLoopMode: RunLoop.Mode? - private let entitlementsMonitor = NetworkProtectionEntitlementMonitor() - private let appLauncher: AppLaunching private var cancellables = Set() @@ -119,7 +117,6 @@ extension NetworkProtectionStatusView { agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, runLoopMode: RunLoop.Mode? = nil, - entitlementCheck: @escaping () async -> Swift.Result, userDefaults: UserDefaults) { self.tunnelController = controller From cc5ef2a44a92d43f2a5ad165906728987a6e1835 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:57:29 +0100 Subject: [PATCH 49/99] Handle uninstall button action from expired prompt --- DuckDuckGo.xcodeproj/project.pbxproj | 6 ++ .../View/NavigationBarViewController.swift | 5 +- ...etworkProtectionNavBarPopoverManager.swift | 12 +++- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 12 +++- DuckDuckGoVPN/VPNUninstaller.swift | 59 +++++++++++++++++++ .../Menu/StatusBarMenu.swift | 6 +- .../NetworkProtectionPopover.swift | 6 +- .../NetworkProtectionStatusView.swift | 3 +- .../NetworkProtectionStatusViewModel.swift | 12 +++- .../SubscriptionExpiredView.swift | 4 +- 10 files changed, 111 insertions(+), 14 deletions(-) create mode 100644 DuckDuckGoVPN/VPNUninstaller.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 03a28d217b..0c598a55bc 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3113,6 +3113,8 @@ EE0629762B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */; }; EE2F9C5B2B90F2FF00D45FC9 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE2F9C5A2B90F2FF00D45FC9 /* Subscription */; }; EE339228291BDEFD009F62C1 /* JSAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE339227291BDEFD009F62C1 /* JSAlertController.swift */; }; + EE3424602BA0853900173B1B /* VPNUninstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE34245D2BA0853900173B1B /* VPNUninstaller.swift */; }; + EE3424612BA0853900173B1B /* VPNUninstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE34245D2BA0853900173B1B /* VPNUninstaller.swift */; }; EE66418C2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */; }; EE66418D2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */; }; EE66418F2B9B1BD1005BCD17 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = EE66418E2B9B1BD1005BCD17 /* Subscription */; }; @@ -4486,6 +4488,7 @@ EAFAD6C92728BD1200F9DF00 /* clickToLoad.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = clickToLoad.js; sourceTree = ""; }; EE0629712B90EE8C00D868B4 /* AccountManagerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManagerExtension.swift; sourceTree = ""; }; EE339227291BDEFD009F62C1 /* JSAlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSAlertController.swift; sourceTree = ""; }; + EE34245D2BA0853900173B1B /* VPNUninstaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNUninstaller.swift; sourceTree = ""; }; EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift"; sourceTree = ""; }; EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationsHostingViewController.swift; sourceTree = ""; }; EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNCountryLabelsModel.swift; sourceTree = ""; }; @@ -6267,6 +6270,7 @@ 7BA7CC152AD11DC80042E5CE /* NetworkProtectionBouncer.swift */, 7B8DB3192B504D7500EC16DA /* VPNAppEventsHandler.swift */, 7B0694972B6E980F00FA4DBA /* VPNProxyLauncher.swift */, + EE34245D2BA0853900173B1B /* VPNUninstaller.swift */, 7BA7CC112AD11DC80042E5CE /* TunnelControllerIPCService.swift */, 7BA7CC172AD11DC80042E5CE /* UserText.swift */, 7BA7CC122AD11DC80042E5CE /* Assets.xcassets */, @@ -10828,6 +10832,7 @@ EE0629742B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */, 7BA7CC5D2AD120C30042E5CE /* EventMapping+NetworkProtectionError.swift in Sources */, 7BA7CC4A2AD11EA00042E5CE /* NetworkProtectionTunnelController.swift in Sources */, + EE3424602BA0853900173B1B /* VPNUninstaller.swift in Sources */, 7BD1688E2AD4A4C400D24876 /* NetworkExtensionController.swift in Sources */, 7BA7CC3E2AD11E380042E5CE /* TunnelControllerIPCService.swift in Sources */, 7BA7CC402AD11E3D0042E5CE /* AppLauncher+DefaultInitializer.swift in Sources */, @@ -10862,6 +10867,7 @@ EE0629752B90EE8C00D868B4 /* AccountManagerExtension.swift in Sources */, 7BA7CC582AD1203A0042E5CE /* UserText+NetworkProtection.swift in Sources */, 7BA7CC4B2AD11EC60042E5CE /* NetworkProtectionControllerErrorStore.swift in Sources */, + EE3424612BA0853900173B1B /* VPNUninstaller.swift in Sources */, 4BF0E5152AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, 7BFE95592A9DF2AF0081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */, 7BA7CC5C2AD120C30042E5CE /* EventMapping+NetworkProtectionError.swift in Sources */, diff --git a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift index 91d9f80a5f..f671fab43c 100644 --- a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift +++ b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift @@ -126,7 +126,10 @@ final class NavigationBarViewController: NSViewController { let ipcClient = TunnelControllerIPCClient(machServiceName: vpnBundleID) ipcClient.register() - let networkProtectionPopoverManager = NetworkProtectionNavBarPopoverManager(ipcClient: ipcClient) + let networkProtectionPopoverManager = NetworkProtectionNavBarPopoverManager( + ipcClient: ipcClient, + networkProtectionFeatureDisabler: NetworkProtectionFeatureDisabler() + ) self.popovers = NavigationBarPopovers(networkProtectionPopoverManager: networkProtectionPopoverManager) self.tabCollectionViewModel = tabCollectionViewModel diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index 2bacf8f933..69b947f8fb 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -32,9 +32,12 @@ import Subscription final class NetworkProtectionNavBarPopoverManager { private var networkProtectionPopover: NetworkProtectionPopover? let ipcClient: TunnelControllerIPCClient + let networkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling - init(ipcClient: TunnelControllerIPCClient) { + init(ipcClient: TunnelControllerIPCClient, + networkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling) { self.ipcClient = ipcClient + self.networkProtectionFeatureDisabler = networkProtectionFeatureDisabler } var isShown: Bool { @@ -107,7 +110,12 @@ final class NetworkProtectionNavBarPopoverManager { }, agentLoginItem: LoginItem.vpnMenu, isMenuBarStatusView: false, - userDefaults: .netP) + userDefaults: .netP, + uninstallHandler: { [weak self] in + Task { [weak self] in + await self?.networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: true) + } + }) popover.delegate = delegate networkProtectionPopover = popover diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 27e319e7f4..cd08e552ee 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -198,6 +198,10 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { VPNAppEventsHandler(tunnelController: tunnelController) }() + private lazy var vpnUninstaller: VPNUninstaller = { + VPNUninstaller(networkExtensionController: networkExtensionController, vpnConfigurationManager: VPNConfigurationManager()) + }() + /// The status bar NetworkProtection menu /// /// For some reason the App will crash if this is initialized right away, which is why it was changed to be lazy. @@ -245,7 +249,13 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { }, agentLoginItem: nil, isMenuBarStatusView: true, - userDefaults: .netP + userDefaults: .netP, + uninstallHandler: { [weak self] in + Task { [weak self] in + guard let self else { return } + await self.vpnUninstaller.uninstall(includingSystemExtension: true) + } + } ) } diff --git a/DuckDuckGoVPN/VPNUninstaller.swift b/DuckDuckGoVPN/VPNUninstaller.swift new file mode 100644 index 0000000000..2f34049a21 --- /dev/null +++ b/DuckDuckGoVPN/VPNUninstaller.swift @@ -0,0 +1,59 @@ +// +// VPNUninstaller.swift +// +// 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 NetworkProtection +import NetworkProtectionIPC + +protocol VPNUninstalling { + func uninstall(includingSystemExtension: Bool) async +} + +final class VPNUninstaller: VPNUninstalling { + static let vpnUninstalledNotificationName = NSNotification.Name(rawValue: "com.duckduckgo.NetworkProtection.uninstalled") + let networkExtensionController: NetworkExtensionController + let vpnConfiguration: VPNConfigurationManager + let defaults: UserDefaults + + init(networkExtensionController: NetworkExtensionController, vpnConfigurationManager: VPNConfigurationManager, defaults: UserDefaults = .netP) { + self.networkExtensionController = networkExtensionController + self.vpnConfiguration = vpnConfigurationManager + self.defaults = defaults + } + + func uninstall(includingSystemExtension: Bool) async { +#if NETP_SYSTEM_EXTENSION + if includingSystemExtension { + do { + try await networkExtensionController.deactivateSystemExtension() + defaults.networkProtectionOnboardingStatus = .isOnboarding(step: .userNeedsToAllowExtension) + } catch { + + } + } +#endif + + await vpnConfiguration.removeVPNConfiguration() + + if defaults.networkProtectionOnboardingStatus == .completed { + defaults.networkProtectionOnboardingStatus = .isOnboarding(step: .userNeedsToAllowVPNConfiguration) + } + + exit(EXIT_SUCCESS) + } +} diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift index ba25b1485b..0df709c8f4 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift @@ -57,7 +57,8 @@ public final class StatusBarMenu: NSObject { menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, - userDefaults: UserDefaults) { + userDefaults: UserDefaults, + uninstallHandler: @escaping () async -> Void) { self.model = model let statusItem = statusItem ?? NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) @@ -71,7 +72,8 @@ public final class StatusBarMenu: NSObject { menuItems: menuItems, agentLoginItem: agentLoginItem, isMenuBarStatusView: isMenuBarStatusView, - userDefaults: userDefaults) + userDefaults: userDefaults, + uninstallHandler: uninstallHandler) popover.behavior = .transient diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift index 2c4a264ed1..0acbf84065 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift @@ -57,7 +57,8 @@ public final class NetworkProtectionPopover: NSPopover { menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, - userDefaults: UserDefaults) { + userDefaults: UserDefaults, + uninstallHandler: @escaping () async -> Void) { self.statusReporter = statusReporter self.model = NetworkProtectionStatusView.Model(controller: controller, @@ -68,7 +69,8 @@ public final class NetworkProtectionPopover: NSPopover { menuItems: menuItems, agentLoginItem: agentLoginItem, isMenuBarStatusView: isMenuBarStatusView, - userDefaults: userDefaults) + userDefaults: userDefaults, + uninstallHandler: uninstallHandler) super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift index 195b3ffc24..dcaa2c1894 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift @@ -54,9 +54,8 @@ public struct NetworkProtectionStatusView: View { SubscriptionExpiredView { model.openPrivacyPro() } uninstallButtonHandler: { - + model.uninstallVPN() } - } else if let promptActionViewModel = model.promptActionViewModel { PromptActionView(model: promptActionViewModel) .padding(.horizontal, 5) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index a0260b5153..cf3272304d 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -97,6 +97,8 @@ extension NetworkProtectionStatusView { private let appLauncher: AppLaunching + private let uninstallHandler: () async -> Void + private var cancellables = Set() // MARK: - Dispatch Queues @@ -117,7 +119,8 @@ extension NetworkProtectionStatusView { agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, runLoopMode: RunLoop.Mode? = nil, - userDefaults: UserDefaults) { + userDefaults: UserDefaults, + uninstallHandler: @escaping () async -> Void) { self.tunnelController = controller self.onboardingStatusPublisher = onboardingStatusPublisher @@ -128,6 +131,7 @@ extension NetworkProtectionStatusView { self.isMenuBarStatusView = isMenuBarStatusView self.runLoopMode = runLoopMode self.appLauncher = appLauncher + self.uninstallHandler = uninstallHandler tunnelControllerViewModel = TunnelControllerViewModel(controller: tunnelController, onboardingStatusPublisher: onboardingStatusPublisher, @@ -182,6 +186,12 @@ extension NetworkProtectionStatusView { } } + func uninstallVPN() { + Task { + await uninstallHandler() + } + } + private func subscribeToStatusChanges() { statusReporter.statusObserver.publisher .receive(on: DispatchQueue.main) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift index 52cf3e6767..c6403ab59f 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift @@ -42,9 +42,7 @@ struct SubscriptionExpiredView: View { Divider().padding(.top, 8).padding(.bottom, 3) - Button("Uninstall DuckDuckGo VPN") { - // TODO: - } + Button("Uninstall DuckDuckGo VPN", action: uninstallButtonHandler) .buttonStyle(.borderless) .foregroundColor(.accentColor) .padding(.top, 3) From 08c8079209875a087ee7eefe16f3af5f1ab1fa92 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 12 Mar 2024 18:09:09 +0100 Subject: [PATCH 50/99] Show uninstalled message on uninstall --- .../View/NavigationBarViewController.swift | 14 +++++- .../NetworkProtectionFeatureVisibility.swift | 5 +++ DuckDuckGoVPN/VPNUninstaller.swift | 2 + .../Sources/LoginItems/LoginItem.swift | 4 ++ ...serDefault+ShowVPNUninstalledMessage.swift | 44 +++++++++++++++++++ 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefault+ShowVPNUninstalledMessage.swift diff --git a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift index f671fab43c..e09e401392 100644 --- a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift +++ b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift @@ -443,13 +443,23 @@ final class NavigationBarViewController: NSViewController { #if NETWORK_PROTECTION NotificationCenter.default.addObserver(self, - selector: #selector(showVPNUninstalledFeedback(_:)), + selector: #selector(showVPNUninstalledFeedback), name: NetworkProtectionFeatureDisabler.vpnUninstalledNotificationName, object: nil) + UserDefaults.netP + .publisher(for: \.networkProtectionShouldShowVPNUninstalledMessage) + .receive(on: DispatchQueue.main) + .sink { [weak self] shouldShowUninstalledMessage in + if shouldShowUninstalledMessage { + self?.showVPNUninstalledFeedback() + UserDefaults.netP.networkProtectionShouldShowVPNUninstalledMessage = false + } + } + .store(in: &cancellables) #endif } - @objc private func showVPNUninstalledFeedback(_ sender: Notification) { + @objc private func showVPNUninstalledFeedback() { guard view.window?.isKeyWindow == true else { return } DispatchQueue.main.async { diff --git a/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift b/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift index 35dd79662b..8754449e1b 100644 --- a/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift +++ b/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift @@ -24,6 +24,7 @@ import Common import NetworkExtension import NetworkProtection import NetworkProtectionUI +import LoginItems protocol NetworkProtectionFeatureVisibility { func isNetworkProtectionVisible() -> Bool @@ -72,11 +73,15 @@ struct DefaultNetworkProtectionVisibility: NetworkProtectionFeatureVisibility { /// Returns whether Network Protection should be uninstalled automatically. /// This is only true when the user is not an Easter Egg user, the waitlist test has ended, and the user is onboarded. func shouldUninstallAutomatically() -> Bool { +#if SUBSCRIPTION + return !defaults.networkProtectionEntitlementsValid && LoginItem.vpnMenu.status.isInstalled +#else let waitlistAccessEnded = isWaitlistUser && !waitlistIsOngoing let isNotEasterEggUser = !isEasterEggUser let isOnboarded = UserDefaults.netP.networkProtectionOnboardingStatus != .default return isNotEasterEggUser && waitlistAccessEnded && isOnboarded +#endif } /// Whether the user is fully onboarded diff --git a/DuckDuckGoVPN/VPNUninstaller.swift b/DuckDuckGoVPN/VPNUninstaller.swift index 2f34049a21..00b983c3bc 100644 --- a/DuckDuckGoVPN/VPNUninstaller.swift +++ b/DuckDuckGoVPN/VPNUninstaller.swift @@ -54,6 +54,8 @@ final class VPNUninstaller: VPNUninstalling { defaults.networkProtectionOnboardingStatus = .isOnboarding(step: .userNeedsToAllowVPNConfiguration) } + defaults.networkProtectionShouldShowVPNUninstalledMessage = true + exit(EXIT_SUCCESS) } } diff --git a/LocalPackages/LoginItems/Sources/LoginItems/LoginItem.swift b/LocalPackages/LoginItems/Sources/LoginItems/LoginItem.swift index 87fda099f7..48a16a8689 100644 --- a/LocalPackages/LoginItems/Sources/LoginItems/LoginItem.swift +++ b/LocalPackages/LoginItems/Sources/LoginItems/LoginItem.swift @@ -52,6 +52,10 @@ public struct LoginItem: Equatable, Hashable { self == .enabled } + public var isInstalled: Bool { + self == .enabled || self == .requiresApproval + } + @available(macOS 13.0, *) public init(_ status: SMAppService.Status) { switch status { diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefault+ShowVPNUninstalledMessage.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefault+ShowVPNUninstalledMessage.swift new file mode 100644 index 0000000000..8f85e818ea --- /dev/null +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefault+ShowVPNUninstalledMessage.swift @@ -0,0 +1,44 @@ +// +// UserDefault+ShowVPNUninstalledMessage.swift +// +// 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 + +public extension UserDefaults { + private enum Key { + static var networkProtectionShouldShowVPNUninstalledMessage = "networkProtectionShouldShowVPNUninstalledMessage" + } + + // Convenience declaration + private var networkProtectionShowVPNUninstalledMessageRawValueKey: String { + Key.networkProtectionShouldShowVPNUninstalledMessage + } + + /// For KVO to work across processes (Menu App + Main App) we need to declare this dynamic var in a `UserDefaults` + /// extension, and the key for this property must match its name exactly. + /// + @objc + dynamic var networkProtectionShouldShowVPNUninstalledMessage: Bool { + get { + value(forKey: networkProtectionShowVPNUninstalledMessageRawValueKey) as? Bool ?? false + } + + set { + set(newValue, forKey: networkProtectionShowVPNUninstalledMessageRawValueKey) + } + } +} From 62d0617c6a5395f0132bbdfc019fa70d29b6147c Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 12 Mar 2024 18:09:31 +0100 Subject: [PATCH 51/99] Tidy up UD extension key declaration --- .../UserDefaults+NetworkProtectionExpiredEntitlements.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift index 1852e6e653..6c8d82b740 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift @@ -19,13 +19,13 @@ import Foundation public extension UserDefaults { - private enum Key: String { - case networkProtectionEntitlementsValid = "networkProtectionEntitlementsValid" + private enum Key { + static var networkProtectionEntitlementsValid = "networkProtectionEntitlementsValid" } // Convenience declaration private var networkProtectionEntitlementsValidRawValueKey: String { - Key.networkProtectionEntitlementsValid.rawValue + Key.networkProtectionEntitlementsValid } /// For KVO to work across processes (Menu App + Main App) we need to declare this dynamic var in a `UserDefaults` From 77ef34a5e7bf4a452c34e8534fd3cc5dbd242718 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 12 Mar 2024 18:12:44 +0100 Subject: [PATCH 52/99] Adapt bouncer for subscriptions --- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 2 +- DuckDuckGoVPN/NetworkProtectionBouncer.swift | 22 ++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index cd08e552ee..4c810d4303 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -267,7 +267,7 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { setupMenuVisibility() - bouncer.requireAuthTokenOrKillApp() + bouncer.requireAuthenticationOrKillApp() // Initialize lazy properties _ = tunnelControllerIPCService diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index 702e9cb2ff..1da461ddbc 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -30,12 +30,25 @@ final class NetworkProtectionBouncer { /// Simply verifies that the Network Protection feature is enabled and if not, takes care of killing the /// current app. /// - func requireAuthTokenOrKillApp() { - let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) + func requireAuthenticationOrKillApp() { +#if SUBSCRIPTION + Task { + let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) + guard case .success(let result) = await accountManager.hasEntitlement(for: .networkProtection), result == true else { + os_log(.error, log: .networkProtection, "🔴 Stopping: Network Protection not authorized.") + + // EXIT_SUCCESS ensures the login item won't relaunch + // Ref: https://developer.apple.com/documentation/servicemanagement/smappservice/register() + // See where it mentions: + // "If the helper crashes or exits with a non-zero status, the system relaunches it" + exit(EXIT_SUCCESS) + return + } + } +#else let keychainStore = NetworkProtectionKeychainTokenStore(keychainType: .default, errorEvents: nil, isSubscriptionEnabled: false) - // TODO: Do entitlements check, not this - guard accountManager.accessToken != nil || keychainStore.isFeatureActivated else { + guard keychainStore.isFeatureActivated else { os_log(.error, log: .networkProtection, "🔴 Stopping: Network Protection not authorized.") // EXIT_SUCCESS ensures the login item won't relaunch @@ -44,5 +57,6 @@ final class NetworkProtectionBouncer { // "If the helper crashes or exits with a non-zero status, the system relaunches it" exit(EXIT_SUCCESS) } +#endif } } From 6d62ea03c18e1cfce9bdd61400341d70b753eca8 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 12 Mar 2024 20:02:40 +0100 Subject: [PATCH 53/99] Tidy up --- .../UserDefaults+NetworkProtectionWaitlist.swift | 2 -- .../NetworkProtectionNavBarPopoverManager.swift | 9 --------- .../NetworkProtectionSubscriptionEventHandler.swift | 1 - .../Preferences/Model/PreferencesSidebarModel.swift | 5 +++-- 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/UserDefaults+NetworkProtectionWaitlist.swift b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/UserDefaults+NetworkProtectionWaitlist.swift index 0b06389674..c557fb2605 100644 --- a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/UserDefaults+NetworkProtectionWaitlist.swift +++ b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/UserDefaults+NetworkProtectionWaitlist.swift @@ -1,5 +1,4 @@ // -// // UserDefaults+NetworkProtectionWaitlist.swift // // Copyright © 2023 DuckDuckGo. All rights reserved. @@ -64,7 +63,6 @@ extension UserDefaults { } } - // Convenience declaration // Convenience declaration var networkProtectionWaitlistEnabledOverrideRawValueKey: String { UserDefaultsWrapper.Key.networkProtectionWaitlistEnabledOverrideRawValue.rawValue diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index 69b947f8fb..ab91b128e7 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -71,15 +71,6 @@ final class NetworkProtectionNavBarPopoverManager { let onboardingStatusPublisher = UserDefaults.netP.networkProtectionOnboardingStatusPublisher _ = VPNSettings(defaults: .netP) let appLauncher = AppLauncher(appBundleURL: Bundle.main.bundleURL) -#if SUBSCRIPTION - let entitlementsCheck = { - await AccountManager().hasEntitlement(for: .networkProtection) - } -#else - let entitlementsCheck: (() async -> Result) = { - return .success(true) - } -#endif let popover = NetworkProtectionPopover(controller: controller, onboardingStatusPublisher: onboardingStatusPublisher, diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift index 97cf69d6ce..19855565a0 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift @@ -81,7 +81,6 @@ final class NetworkProtectionSubscriptionEventHandler { Task { do { - // todo - https://app.asana.com/0/0/1206541966681608/f try NetworkProtectionKeychainTokenStore().store(NetworkProtectionKeychainTokenStore.makeToken(from: token)) print("[NetP Subscription] Stored derived NetP auth token") } catch { diff --git a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift index 6dbb5fa7ec..5efc478ed2 100644 --- a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift +++ b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift @@ -79,11 +79,12 @@ final class PreferencesSidebarModel: ObservableObject { tabSwitcherTabs: [Tab.TabContent] = Tab.TabContent.displayableTabTypes, privacyConfigurationManager: PrivacyConfigurationManaging = ContentBlocking.shared.privacyConfigurationManager, syncService: DDGSyncing, - includeDuckPlayer: Bool + includeDuckPlayer: Bool, + userDefaults: UserDefaults = .netP ) { let loadSections = { #if SUBSCRIPTION - let includingVPN = UserDefaults.netP.networkProtectionEntitlementsValid && DefaultNetworkProtectionVisibility().isOnboarded + let includingVPN = userDefaults.networkProtectionEntitlementsValid && DefaultNetworkProtectionVisibility().isOnboarded #elseif NETWORK_PROTECTION let includingVPN = DefaultNetworkProtectionVisibility().isOnboarded #else From 415d06df6577c455d4240f5432e68d90973ddd71 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 12 Mar 2024 21:52:25 +0100 Subject: [PATCH 54/99] Fix issue with bouncer --- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 6 ++++-- DuckDuckGoVPN/NetworkProtectionBouncer.swift | 11 +++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 4c810d4303..a64ee908a5 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -47,6 +47,10 @@ final class DuckDuckGoVPNApplication: NSApplication { super.init() self.delegate = _delegate +#if SUBSCRIPTION + SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging +#endif + #if DEBUG && SUBSCRIPTION let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) @@ -348,8 +352,6 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { private func setUpSubscriptionMonitoring() { #if SUBSCRIPTION - SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging - let entitlementsCheck = { await AccountManager().hasEntitlement(for: .networkProtection) } diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index 1da461ddbc..4d2a322884 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -34,22 +34,25 @@ final class NetworkProtectionBouncer { #if SUBSCRIPTION Task { let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) - guard case .success(let result) = await accountManager.hasEntitlement(for: .networkProtection), result == true else { - os_log(.error, log: .networkProtection, "🔴 Stopping: Network Protection not authorized.") + let result = await accountManager.hasEntitlement(for: .networkProtection) + switch result { + case .success(true), .failure: + return + case .success(false): + os_log(.error, log: .networkProtection, "🔴 Stopping: Network Protection not authorized. Missing entitlement.") // EXIT_SUCCESS ensures the login item won't relaunch // Ref: https://developer.apple.com/documentation/servicemanagement/smappservice/register() // See where it mentions: // "If the helper crashes or exits with a non-zero status, the system relaunches it" exit(EXIT_SUCCESS) - return } } #else let keychainStore = NetworkProtectionKeychainTokenStore(keychainType: .default, errorEvents: nil, isSubscriptionEnabled: false) guard keychainStore.isFeatureActivated else { - os_log(.error, log: .networkProtection, "🔴 Stopping: Network Protection not authorized.") + os_log(.error, log: .networkProtection, "🔴 Stopping: Network Protection not authorized. Missing token.") // EXIT_SUCCESS ensures the login item won't relaunch // Ref: https://developer.apple.com/documentation/servicemanagement/smappservice/register() From bbe19957e77de115f3e729b76b595a5bf5b0a6b1 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 11:24:10 +0100 Subject: [PATCH 55/99] Point to updated BSK version --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 6 +++--- LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 0c598a55bc..eec5101dee 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13726,7 +13726,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = revision; - revision = 71c950a1aae064a48638c48a4b293d4b1c257a8d; + revision = 1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6fe567ba5c..decab59478 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,7 +32,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "71c950a1aae064a48638c48a4b293d4b1c257a8d" + "revision" : "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951" } }, { @@ -40,8 +40,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "59752eb7973d3e3b0c23255ff51359f48b343f15", - "version" : "5.2.0" + "revision" : "f6241631fc14cc2d0f47950bfdc4d6c30bf90130", + "version" : "5.4.0" } }, { diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 5fbcad3bc4..aa202ba93d 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", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index 84a3de4f55..d431ce1020 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951") ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index a30754bfc4..facede71e4 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 6a995a051e..df0adc4d91 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", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index f75d3dc0f2..5e4a235bd7 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../SwiftUIExtensions"), .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951") ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index b70251c97e..2d0e9bb8fb 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -17,7 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "71c950a1aae064a48638c48a4b293d4b1c257a8d") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From e0037990709fda1662cd7e72f9448df5c98bdd47 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 13:17:44 +0100 Subject: [PATCH 56/99] Point to updated BSK --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index edbf5168ea..d257df2ec2 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13785,7 +13785,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = revision; - revision = 1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951; + revision = 401144a1d913e8f0aab0589019e82fcb787c3507; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 95fff641a5..470d32507d 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,7 +32,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951" + "revision" : "401144a1d913e8f0aab0589019e82fcb787c3507" } }, { @@ -164,7 +164,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/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index aa202ba93d..e8fb8fcd79 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", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "401144a1d913e8f0aab0589019e82fcb787c3507"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index d431ce1020..9d1bc34162 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "401144a1d913e8f0aab0589019e82fcb787c3507") ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index facede71e4..95f21b1ef0 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "401144a1d913e8f0aab0589019e82fcb787c3507"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index df0adc4d91..45af5375fb 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", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "401144a1d913e8f0aab0589019e82fcb787c3507"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 5e4a235bd7..9a3b8d7581 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../SwiftUIExtensions"), .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "401144a1d913e8f0aab0589019e82fcb787c3507") ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index 2d0e9bb8fb..322840e6c0 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -17,7 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "1f8fa1f51d799b6a6e2040c5a8d8da0b25e28951") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "401144a1d913e8f0aab0589019e82fcb787c3507") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From 6acbc36b181c1297051061643f4ef752732f192e Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 13:18:38 +0100 Subject: [PATCH 57/99] Update network extension code for new accountmanager changes --- .../NetworkExtensionTargets/MacPacketTunnelProvider.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 8e62f89f1d..8b6273ae2f 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -297,9 +297,13 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { isSubscriptionEnabled: isSubscriptionEnabled) let notificationsPresenter = NetworkProtectionNotificationsPresenterFactory().make(settings: settings, defaults: defaults) #if SUBSCRIPTION + let accountManager = AccountManager( + accessTokenStorage: tokenStore, + entitlementsCache: UserDefaultsCache<[Entitlement]>(key: UserDefaultsCacheKey.subscriptionEntitlements) + ) SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging let entitlementsCheck = { - await AccountManager(accessTokenStorage: tokenStore).hasEntitlement(for: .networkProtection) + await accountManager.hasEntitlement(for: .networkProtection) } #else let entitlementsCheck: (() async -> Result)? = nil From d4005ae11ed7800ee042201a3347ee9733d3211d Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 14:07:47 +0100 Subject: [PATCH 58/99] Fix swiftlint issue --- ...etworkProtectionNavBarPopoverManager.swift | 116 +++++++++--------- 1 file changed, 59 insertions(+), 57 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index ab91b128e7..d26b2ec378 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -48,65 +48,9 @@ final class NetworkProtectionNavBarPopoverManager { #endif } - private func show(_ popover: NSPopover, positionedBelow view: NSView) { - view.isHidden = false - - popover.show(positionedBelow: view.bounds.insetFromLineOfDeath(flipped: view.isFlipped), in: view) - } - func show(positionedBelow view: NSView, withDelegate delegate: NSPopoverDelegate) { - let popover = networkProtectionPopover ?? { - - let controller = NetworkProtectionIPCTunnelController(ipcClient: ipcClient) - - let statusReporter = DefaultNetworkProtectionStatusReporter( - statusObserver: ipcClient.connectionStatusObserver, - serverInfoObserver: ipcClient.serverInfoObserver, - connectionErrorObserver: ipcClient.connectionErrorObserver, - connectivityIssuesObserver: ConnectivityIssueObserverThroughDistributedNotifications(), - controllerErrorMessageObserver: ControllerErrorMesssageObserverThroughDistributedNotifications() - ) - - let onboardingStatusPublisher = UserDefaults.netP.networkProtectionOnboardingStatusPublisher - _ = VPNSettings(defaults: .netP) - let appLauncher = AppLauncher(appBundleURL: Bundle.main.bundleURL) - - let popover = NetworkProtectionPopover(controller: controller, - onboardingStatusPublisher: onboardingStatusPublisher, - statusReporter: statusReporter, - appLauncher: appLauncher, - menuItems: { - if UserDefaults.netP.networkProtectionOnboardingStatus == .completed { - return [ - NetworkProtectionStatusView.Model.MenuItem( - name: UserText.networkProtectionNavBarStatusMenuVPNSettings, action: { - await appLauncher.launchApp(withCommand: .showSettings) - }), - NetworkProtectionStatusView.Model.MenuItem( - name: UserText.networkProtectionNavBarStatusViewShareFeedback, - action: { - await appLauncher.launchApp(withCommand: .shareFeedback) - }) - ] - } else { - return [ - NetworkProtectionStatusView.Model.MenuItem( - name: UserText.networkProtectionNavBarStatusViewShareFeedback, - action: { - await appLauncher.launchApp(withCommand: .shareFeedback) - }) - ] - } - }, - agentLoginItem: LoginItem.vpnMenu, - isMenuBarStatusView: false, - userDefaults: .netP, - uninstallHandler: { [weak self] in - Task { [weak self] in - await self?.networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: true) - } - }) + let popover = createNetworkProtectionPopover() popover.delegate = delegate networkProtectionPopover = popover @@ -116,6 +60,64 @@ final class NetworkProtectionNavBarPopoverManager { show(popover, positionedBelow: view) } + private func createNetworkProtectionPopover() -> NetworkProtectionPopover { + let controller = NetworkProtectionIPCTunnelController(ipcClient: ipcClient) + + let statusReporter = DefaultNetworkProtectionStatusReporter( + statusObserver: ipcClient.connectionStatusObserver, + serverInfoObserver: ipcClient.serverInfoObserver, + connectionErrorObserver: ipcClient.connectionErrorObserver, + connectivityIssuesObserver: ConnectivityIssueObserverThroughDistributedNotifications(), + controllerErrorMessageObserver: ControllerErrorMesssageObserverThroughDistributedNotifications() + ) + + let onboardingStatusPublisher = UserDefaults.netP.networkProtectionOnboardingStatusPublisher + _ = VPNSettings(defaults: .netP) + let appLauncher = AppLauncher(appBundleURL: Bundle.main.bundleURL) + + return NetworkProtectionPopover(controller: controller, + onboardingStatusPublisher: onboardingStatusPublisher, + statusReporter: statusReporter, + appLauncher: appLauncher, + menuItems: { + if UserDefaults.netP.networkProtectionOnboardingStatus == .completed { + return [ + NetworkProtectionStatusView.Model.MenuItem( + name: UserText.networkProtectionNavBarStatusMenuVPNSettings, action: { + await appLauncher.launchApp(withCommand: .showSettings) + }), + NetworkProtectionStatusView.Model.MenuItem( + name: UserText.networkProtectionNavBarStatusViewShareFeedback, + action: { + await appLauncher.launchApp(withCommand: .shareFeedback) + }) + ] + } else { + return [ + NetworkProtectionStatusView.Model.MenuItem( + name: UserText.networkProtectionNavBarStatusViewShareFeedback, + action: { + await appLauncher.launchApp(withCommand: .shareFeedback) + }) + ] + } + }, + agentLoginItem: LoginItem.vpnMenu, + isMenuBarStatusView: false, + userDefaults: .netP, + uninstallHandler: { [weak self] in + Task { [weak self] in + await self?.networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: true) + } + }) + } + + private func show(_ popover: NSPopover, positionedBelow view: NSView) { + view.isHidden = false + + popover.show(positionedBelow: view.bounds.insetFromLineOfDeath(flipped: view.isFlipped), in: view) + } + func toggle(positionedBelow view: NSView, withDelegate delegate: NSPopoverDelegate) { if let networkProtectionPopover, networkProtectionPopover.isShown { networkProtectionPopover.close() From 79475fb01f88db098f2f442fc4b1490e44a2f93f Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 14:13:43 +0100 Subject: [PATCH 59/99] Fix tests --- .../NetworkProtectionStatusBarMenuTests.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/LocalPackages/NetworkProtectionMac/Tests/NetworkProtectionUITests/NetworkProtectionStatusBarMenuTests.swift b/LocalPackages/NetworkProtectionMac/Tests/NetworkProtectionUITests/NetworkProtectionStatusBarMenuTests.swift index b680b062b6..5b9e7e0dea 100644 --- a/LocalPackages/NetworkProtectionMac/Tests/NetworkProtectionUITests/NetworkProtectionStatusBarMenuTests.swift +++ b/LocalPackages/NetworkProtectionMac/Tests/NetworkProtectionUITests/NetworkProtectionStatusBarMenuTests.swift @@ -56,7 +56,9 @@ final class StatusBarMenuTests: XCTestCase { appLauncher: MockAppLauncher(), menuItems: { [] }, agentLoginItem: nil, - isMenuBarStatusView: false) + isMenuBarStatusView: false, + userDefaults: .standard, + uninstallHandler: { }) menu.show() @@ -79,7 +81,9 @@ final class StatusBarMenuTests: XCTestCase { appLauncher: MockAppLauncher(), menuItems: { [] }, agentLoginItem: nil, - isMenuBarStatusView: false) + isMenuBarStatusView: false, + userDefaults: .standard, + uninstallHandler: { }) menu.hide() From edfcf214208db2f472f55fe07084f9867fc724cd Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 14:43:11 +0100 Subject: [PATCH 60/99] Slight prompt view tidy up --- .../UserText+NetworkProtectionUI.swift | 7 +++++ .../SubscriptionExpiredView.swift | 30 +++++++++++-------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift index ccd9a73ef7..453bda4e01 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift @@ -67,4 +67,11 @@ final class UserText { let localized = NSLocalizedString("network.protection.server.location.link", value: "%@...", comment: "Clickable text linking to the server location picker screen") return String(format: localized, location) } + + // MARK: Subscription Expired + + static let networkProtectionSubscriptionExpiredTitle = NSLocalizedString("network.protection.subscription.expired.title", value: "VPN disconnected due to expired subscription", comment: "Title for the prompt that tells the user their subscription expired.") + static let networkProtectionSubscriptionExpiredSubtitle = NSLocalizedString("network.protection.subscription.expired.subtitle", value: "Subscribe to Privacy Pro to reconnect DuckDuckGo VPN.", comment: "Subtitle for the prompt that tells the user their subscription expired.") + static let networkProtectionSubscriptionExpiredResubscribeButton = NSLocalizedString("network.protection.subscription.expired.resubscribe.button", value: "Subscribe to Privacy Pro", comment: "Button for the prompt that takes the user to the page to resubscribe.") + static let networkProtectionSubscriptionExpiredUninstallButton = NSLocalizedString("network.protection.subscription.expired.uninstall.button", value: "Uninstall DuckDuckGo VPN", comment: "Button for the prompt that uninstalls the VPN.") } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift index c6403ab59f..a1a0135987 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift @@ -21,40 +21,46 @@ import SwiftUI import SwiftUIExtensions struct SubscriptionExpiredView: View { + enum Constants { + static let backgroundCornerRadius = 6.0 + } + let subscribeButtonHandler: () -> Void let uninstallButtonHandler: () -> Void public var body: some View { VStack(alignment: .leading, spacing: 5) { - Text("VPN disconnected due to expired subscription") + Text(UserText.networkProtectionSubscriptionExpiredTitle) .font(.system(size: 14).weight(.bold)) .foregroundColor(Color(.defaultText)) .multilineText() - Text("Subscribe to Privacy Pro to reconnect DuckDuckGo VPN.") + Text(UserText.networkProtectionSubscriptionExpiredSubtitle) .font(.system(size: 13)) .foregroundColor(Color(.defaultText)) .multilineText() - Button("Subscribe to Privacy Pro", action: subscribeButtonHandler) - .buttonStyle(DefaultActionButtonStyle(enabled: true)) - .padding(.top, 3) + Button(UserText.networkProtectionSubscriptionExpiredResubscribeButton, action: subscribeButtonHandler) + .buttonStyle(DefaultActionButtonStyle(enabled: true)) + .padding(.top, 3) - Divider().padding(.top, 8).padding(.bottom, 3) + Divider() + .padding(.top, 8) + .padding(.bottom, 3) - Button("Uninstall DuckDuckGo VPN", action: uninstallButtonHandler) - .buttonStyle(.borderless) - .foregroundColor(.accentColor) - .padding(.top, 3) + Button(UserText.networkProtectionSubscriptionExpiredUninstallButton, action: uninstallButtonHandler) + .buttonStyle(.borderless) + .foregroundColor(.accentColor) + .padding(.top, 3) } .padding(.vertical, 16) .padding(.horizontal, 10) .cornerRadius(8) .background( - RoundedRectangle(cornerRadius: 6, style: .circular) + RoundedRectangle(cornerRadius: Constants.backgroundCornerRadius, style: .circular) .stroke(Color(.onboardingStepBorder), lineWidth: 1) .background( - RoundedRectangle(cornerRadius: 6, style: .circular) + RoundedRectangle(cornerRadius: Constants.backgroundCornerRadius, style: .circular) .fill(Color(.onboardingStepBackground)) ) ) From 8274c5d0e4f658c254b2338be3fbc3edaa763d92 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:09:47 +0100 Subject: [PATCH 61/99] Fix prompt padding --- .../Views/StatusView/NetworkProtectionStatusView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift index dcaa2c1894..aae033b17d 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusView.swift @@ -56,6 +56,7 @@ public struct NetworkProtectionStatusView: View { } uninstallButtonHandler: { model.uninstallVPN() } + .padding(5) } else if let promptActionViewModel = model.promptActionViewModel { PromptActionView(model: promptActionViewModel) .padding(.horizontal, 5) From c55a1ae016a378fe79c74c8d43315b579068d127 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:10:41 +0100 Subject: [PATCH 62/99] No entitlements cache in macpackettunnelprovider --- .../NetworkExtensionTargets/MacPacketTunnelProvider.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 8b6273ae2f..49fcaaba76 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -303,7 +303,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { ) SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging let entitlementsCheck = { - await accountManager.hasEntitlement(for: .networkProtection) + await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) } #else let entitlementsCheck: (() async -> Result)? = nil From bd67a2f50bf954a9c2d6577100ff60e1c2100c0c Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 21:15:22 +0100 Subject: [PATCH 63/99] Define cache policy for AccountManager --- .../NetworkProtectionSubscriptionEventHandler.swift | 2 +- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 2 +- DuckDuckGoVPN/NetworkProtectionBouncer.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift index 19855565a0..583e4531e7 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift @@ -49,7 +49,7 @@ final class NetworkProtectionSubscriptionEventHandler { SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging let entitlementsCheck = { - await AccountManager().hasEntitlement(for: .networkProtection) + await AccountManager().hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) } Task { diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 56c9265672..b0c8a18c12 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -355,7 +355,7 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { private func setUpSubscriptionMonitoring() { #if SUBSCRIPTION let entitlementsCheck = { - await AccountManager().hasEntitlement(for: .networkProtection) + await AccountManager().hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) } Task { diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index 4d2a322884..ae48b89822 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -34,7 +34,7 @@ final class NetworkProtectionBouncer { #if SUBSCRIPTION Task { let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) - let result = await accountManager.hasEntitlement(for: .networkProtection) + let result = await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) switch result { case .success(true), .failure: return From 9f25b6044adbb000eb6a62061cf02e4855f9c38e Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 21:40:00 +0100 Subject: [PATCH 64/99] Wrap forgotten subscription code --- ...rotectionTokenStore+SubscriptionTokenKeychainStorage.swift | 4 ++++ DuckDuckGoVPN/NetworkProtectionBouncer.swift | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift index 0e7ee9445a..68ec453f80 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift @@ -16,6 +16,8 @@ // limitations under the License. // +#if SUBSCRIPTION + import Foundation import Subscription import NetworkProtection @@ -40,3 +42,5 @@ extension NetworkProtectionKeychainTokenStore: SubscriptionTokenStorage { try deleteToken() } } + +#endif diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index ae48b89822..12ad4007c1 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -21,8 +21,10 @@ import Foundation import NetworkProtection import ServiceManagement import AppKit -import Subscription +#if SUBSCRIPTION +import Subscription +#endif /// Class that implements the necessary logic to ensure Network Protection is enabled, or prevent the app from running otherwise. /// final class NetworkProtectionBouncer { From ca07f4cbcff014562785a42ed1901a1e1628a6e0 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Wed, 13 Mar 2024 23:12:16 +0100 Subject: [PATCH 65/99] Reduce expired view title font size --- .../Views/SubscriptionExpiredView/SubscriptionExpiredView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift index a1a0135987..a4fe590b8e 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/SubscriptionExpiredView/SubscriptionExpiredView.swift @@ -31,7 +31,7 @@ struct SubscriptionExpiredView: View { public var body: some View { VStack(alignment: .leading, spacing: 5) { Text(UserText.networkProtectionSubscriptionExpiredTitle) - .font(.system(size: 14).weight(.bold)) + .font(.system(size: 13).weight(.bold)) .foregroundColor(Color(.defaultText)) .multilineText() From ba1c474d32dc6444e72f58387bb6e20402592af4 Mon Sep 17 00:00:00 2001 From: Graeme Arthur Date: Thu, 14 Mar 2024 10:24:28 +0100 Subject: [PATCH 66/99] Revert InfoPlist.xcstrings change --- DuckDuckGo/InfoPlist.xcstrings | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/InfoPlist.xcstrings b/DuckDuckGo/InfoPlist.xcstrings index 94f1cca215..cce98e8330 100644 --- a/DuckDuckGo/InfoPlist.xcstrings +++ b/DuckDuckGo/InfoPlist.xcstrings @@ -14,7 +14,7 @@ "en" : { "stringUnit" : { "state" : "new", - "value" : "DuckDuckGo App Store" + "value" : "DuckDuckGo" } }, "es" : { @@ -363,4 +363,4 @@ } }, "version" : "1.0" -} \ No newline at end of file +} From 88e71ac9167c6eef189209e5d03c9559662437a4 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:04:30 +0100 Subject: [PATCH 67/99] Remove SUBSCRIPTION flag from app extension target --- .../NetworkProtection/NetworkProtectionAppExtension.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig b/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig index 5c67cdf327..2fb095fc56 100644 --- a/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig +++ b/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig @@ -32,8 +32,8 @@ INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023 DuckDuckGo. All right FEATURE_FLAGS[arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION -FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION +FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION +FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION PRODUCT_BUNDLE_IDENTIFIER[sdk=*] = PRODUCT_BUNDLE_IDENTIFIER[config=CI][sdk=*] = $(TUNNEL_EXTENSION_BUNDLE_ID) From cf4d0e2b6653546cf99d85bb0225d2cd599c6fb9 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:20:26 +0100 Subject: [PATCH 68/99] Add SUBSCRIPTION flag to the dev ID vpn targets --- Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig | 4 ++-- .../NetworkProtectionSystemExtension.xcconfig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig b/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig index 178c5f109c..b3b7f7ef35 100644 --- a/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig +++ b/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig @@ -49,8 +49,8 @@ PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = PROVISIONING_PROFILE_SPECIFIER[config=Review][sdk=macosx*] = macOS NetP VPN App - Review (XPC) PROVISIONING_PROFILE_SPECIFIER[config=Release][sdk=macosx*] = macOS NetP VPN App - Release (XPC) -FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION +FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION SUBSCRIPTION +FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION SUBSCRIPTION FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION SUBSCRIPTION FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION SUBSCRIPTION diff --git a/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig b/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig index 6cabb03058..4e8f8370ab 100644 --- a/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig +++ b/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig @@ -31,8 +31,8 @@ INFOPLIST_FILE = NetworkProtectionSystemExtension/Info.plist INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023 DuckDuckGo. All rights reserved. INFOPLIST_KEY_NSSystemExtensionUsageDescription = Network Protection -FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION +FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION +FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION From e41ff3ed90ced61721ab5995568d490cc2ec9c31 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:29:43 +0100 Subject: [PATCH 69/99] Shorten expiry notification title to fit UI --- .../UserText+NetworkProtectionExtensions.swift | 2 +- .../Extensions/UserText+NetworkProtectionUI.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/UserText+NetworkProtectionExtensions.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/UserText+NetworkProtectionExtensions.swift index b4cf049d12..9942973576 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/UserText+NetworkProtectionExtensions.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/UserText+NetworkProtectionExtensions.swift @@ -43,6 +43,6 @@ final class UserText { static let networkProtectionSupersededNotificationSubtitle = NSLocalizedString("network.protection.superceded.notification.subtitle", value: "A VPN app on your device may have disabled it. Click to re-enable.", comment: "The subtitle of the notification shown when VPN connection is replaced by another app VPN connection taking over") static let networkProtectionSupersededReconnectActionTitle = NSLocalizedString("network.protection.superceded.action.reconnect.title", value: "Re-enable", comment: "The title of the `Reconnect` notification action button shown when VPN connection is replaced by another app VPN connection taking over") - static let networkProtectionEntitlementExpiredNotificationTitle = NSLocalizedString("network.protection.entitlement.expired.notification.title", value: "VPN disconnected due to expired subscription.", comment: "The title of the notification when Privacy Pro subscription expired") + static let networkProtectionEntitlementExpiredNotificationTitle = NSLocalizedString("network.protection.entitlement.expired.notification.title", value: "VPN disconnected", comment: "The title of the notification when Privacy Pro subscription expired") static let networkProtectionEntitlementExpiredNotificationBody = NSLocalizedString("network.protection.entitlement.expired.notification.body", value: "Subscribe to Privacy Pro to reconnect DuckDuckGo VPN.", comment: "The body of the notification when Privacy Pro subscription expired") } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift index 453bda4e01..7c559bd934 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift @@ -70,7 +70,7 @@ final class UserText { // MARK: Subscription Expired - static let networkProtectionSubscriptionExpiredTitle = NSLocalizedString("network.protection.subscription.expired.title", value: "VPN disconnected due to expired subscription", comment: "Title for the prompt that tells the user their subscription expired.") + static let networkProtectionSubscriptionExpiredTitle = NSLocalizedString("network.protection.subscription.expired.title", value: "VPN disconnected", comment: "Title for the prompt that tells the user their subscription expired.") static let networkProtectionSubscriptionExpiredSubtitle = NSLocalizedString("network.protection.subscription.expired.subtitle", value: "Subscribe to Privacy Pro to reconnect DuckDuckGo VPN.", comment: "Subtitle for the prompt that tells the user their subscription expired.") static let networkProtectionSubscriptionExpiredResubscribeButton = NSLocalizedString("network.protection.subscription.expired.resubscribe.button", value: "Subscribe to Privacy Pro", comment: "Button for the prompt that takes the user to the page to resubscribe.") static let networkProtectionSubscriptionExpiredUninstallButton = NSLocalizedString("network.protection.subscription.expired.uninstall.button", value: "Uninstall DuckDuckGo VPN", comment: "Button for the prompt that uninstalls the VPN.") From ea50ef5874e538cc74022206db33b62114a0f5ea Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:04:13 +0100 Subject: [PATCH 70/99] Point to BSK branch --- DuckDuckGo.xcodeproj/project.pbxproj | 4 ++-- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 3 ++- LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/LoginItems/Package.swift | 2 +- LocalPackages/NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/SyncUI/Package.swift | 2 +- LocalPackages/SystemExtensionManager/Package.swift | 2 +- 8 files changed, 10 insertions(+), 9 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 90ccdbc76f..42eab959d2 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13763,8 +13763,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { - kind = revision; - revision = 401144a1d913e8f0aab0589019e82fcb787c3507; + branch = "graeme/expired-entitlements-stuff"; + kind = branch; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c7fca35a88..6301ad0529 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,7 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "401144a1d913e8f0aab0589019e82fcb787c3507" + "branch" : "graeme/expired-entitlements-stuff", + "revision" : "d48ecf18f71f6a265fbc00a19c1e444bd3af0db8" } }, { diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 09b4005ac8..088997a387 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", revision: "401144a1d913e8f0aab0589019e82fcb787c3507"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", branch: "graeme/expired-entitlements-stuff"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index 9d1bc34162..0e2d71d1b3 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "401144a1d913e8f0aab0589019e82fcb787c3507") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", branch: "graeme/expired-entitlements-stuff") ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index 9edd2451bf..7c6fef53ca 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "401144a1d913e8f0aab0589019e82fcb787c3507"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", branch: "graeme/expired-entitlements-stuff"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 45af5375fb..e633df959e 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", revision: "401144a1d913e8f0aab0589019e82fcb787c3507"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", branch: "graeme/expired-entitlements-stuff"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 9a3b8d7581..4693eb6b4a 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../SwiftUIExtensions"), .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "401144a1d913e8f0aab0589019e82fcb787c3507") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", branch: "graeme/expired-entitlements-stuff") ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index 322840e6c0..58eeb26cc1 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -17,7 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/apple-toolbox.git", exact: "2.0.0"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", revision: "401144a1d913e8f0aab0589019e82fcb787c3507") + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", branch: "graeme/expired-entitlements-stuff") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From 4862c41529a9d6306fa58071da0430ebaf8e3216 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:09:31 +0100 Subject: [PATCH 71/99] Fixes after difficult merge conflicts --- .../MainWindow/MainViewController.swift | 2 +- ...etworkProtectionNavBarPopoverManager.swift | 64 +++---------------- .../NetworkProtectionTunnelController.swift | 2 +- ...rkProtectionSubscriptionEventHandler.swift | 9 --- ...ore+SubscriptionTokenKeychainStorage.swift | 2 +- .../AppLaunching/AppLaunching.swift | 1 + 6 files changed, 13 insertions(+), 67 deletions(-) diff --git a/DuckDuckGo/MainWindow/MainViewController.swift b/DuckDuckGo/MainWindow/MainViewController.swift index 5ef25c47e9..42905bbe76 100644 --- a/DuckDuckGo/MainWindow/MainViewController.swift +++ b/DuckDuckGo/MainWindow/MainViewController.swift @@ -75,7 +75,7 @@ final class MainViewController: NSViewController { let ipcClient = TunnelControllerIPCClient(machServiceName: vpnBundleID) ipcClient.register() - return NetworkProtectionNavBarPopoverManager(ipcClient: ipcClient) + return NetworkProtectionNavBarPopoverManager(ipcClient: ipcClient, networkProtectionFeatureDisabler: NetworkProtectionFeatureDisabler()) }() let networkProtectionStatusReporter: NetworkProtectionStatusReporter = { var connectivityIssuesObserver: ConnectivityIssueObserver! diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index d20e096ff0..1849ec4e87 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -38,6 +38,7 @@ protocol NetworkProtectionIPCClient { func start() func stop() } + extension TunnelControllerIPCClient: NetworkProtectionIPCClient { public var ipcStatusObserver: any NetworkProtection.ConnectionStatusObserver { connectionStatusObserver } public var ipcServerInfoObserver: any NetworkProtection.ConnectionServerInfoObserver { serverInfoObserver } @@ -46,7 +47,7 @@ extension TunnelControllerIPCClient: NetworkProtectionIPCClient { final class NetworkProtectionNavBarPopoverManager: NetPPopoverManager { private var networkProtectionPopover: NetworkProtectionPopover? - let ipcClient: TunnelControllerIPCClient + let ipcClient: NetworkProtectionIPCClient let networkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling init(ipcClient: TunnelControllerIPCClient, @@ -117,8 +118,13 @@ final class NetworkProtectionNavBarPopoverManager: NetPPopoverManager { } }, agentLoginItem: LoginItem.vpnMenu, - isMenuBarStatusView: false - ) + isMenuBarStatusView: false, + userDefaults: .netP, + uninstallHandler: { [weak self] in + Task { [weak self] in + await self?.networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: true) + } + }) popover.delegate = delegate networkProtectionPopover = popover @@ -128,58 +134,6 @@ final class NetworkProtectionNavBarPopoverManager: NetPPopoverManager { show(popover, positionedBelow: view) } - private func createNetworkProtectionPopover() -> NetworkProtectionPopover { - let controller = NetworkProtectionIPCTunnelController(ipcClient: ipcClient) - - let statusReporter = DefaultNetworkProtectionStatusReporter( - statusObserver: ipcClient.connectionStatusObserver, - serverInfoObserver: ipcClient.serverInfoObserver, - connectionErrorObserver: ipcClient.connectionErrorObserver, - connectivityIssuesObserver: ConnectivityIssueObserverThroughDistributedNotifications(), - controllerErrorMessageObserver: ControllerErrorMesssageObserverThroughDistributedNotifications() - ) - - let onboardingStatusPublisher = UserDefaults.netP.networkProtectionOnboardingStatusPublisher - _ = VPNSettings(defaults: .netP) - let appLauncher = AppLauncher(appBundleURL: Bundle.main.bundleURL) - - return NetworkProtectionPopover(controller: controller, - onboardingStatusPublisher: onboardingStatusPublisher, - statusReporter: statusReporter, - appLauncher: appLauncher, - menuItems: { - if UserDefaults.netP.networkProtectionOnboardingStatus == .completed { - return [ - NetworkProtectionStatusView.Model.MenuItem( - name: UserText.networkProtectionNavBarStatusMenuVPNSettings, action: { - await appLauncher.launchApp(withCommand: .showSettings) - }), - NetworkProtectionStatusView.Model.MenuItem( - name: UserText.networkProtectionNavBarStatusViewShareFeedback, - action: { - await appLauncher.launchApp(withCommand: .shareFeedback) - }) - ] - } else { - return [ - NetworkProtectionStatusView.Model.MenuItem( - name: UserText.networkProtectionNavBarStatusViewShareFeedback, - action: { - await appLauncher.launchApp(withCommand: .shareFeedback) - }) - ] - } - }, - agentLoginItem: LoginItem.vpnMenu, - isMenuBarStatusView: false, - userDefaults: .netP, - uninstallHandler: { [weak self] in - Task { [weak self] in - await self?.networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: true) - } - }) - } - private func show(_ popover: NSPopover, positionedBelow view: NSView) { view.isHidden = false diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index e02e7909a9..782e17c359 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -747,7 +747,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr #if SUBSCRIPTION if let accessToken = accountManager.accessToken { os_log(.error, log: .networkProtection, "🟢 TunnelController found token: %{public}d", accessToken) - return NetworkProtectionKeychainTokenStore.makeToken(from: accessToken) as NSString? + return NetworkProtectionKeychainTokenStore().makeToken(from: accessToken) as NSString? } #endif os_log(.error, log: .networkProtection, "🔴 TunnelController found no token :(") diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift index 583e4531e7..67065cbb8a 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift @@ -78,15 +78,6 @@ final class NetworkProtectionSubscriptionEventHandler { return } userDefaults.networkProtectionEntitlementsValid = true - - Task { - do { - try NetworkProtectionKeychainTokenStore().store(NetworkProtectionKeychainTokenStore.makeToken(from: token)) - print("[NetP Subscription] Stored derived NetP auth token") - } catch { - print("[NetP Subscription] Failed to store derived NetP auth token: \(error)") - } - } } @objc private func handleAccountDidSignOut() { diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift index 68ec453f80..dc0880743e 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift @@ -25,7 +25,7 @@ import Common extension NetworkProtectionKeychainTokenStore: SubscriptionTokenStorage { public func store(accessToken: String) throws { - let tokenToStore = Self.makeToken(from: accessToken) + let tokenToStore = makeToken(from: accessToken) try store(tokenToStore) } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/AppLaunching/AppLaunching.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/AppLaunching/AppLaunching.swift index 2e408557b0..e64f0a605a 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/AppLaunching/AppLaunching.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/AppLaunching/AppLaunching.swift @@ -32,6 +32,7 @@ public enum AppLaunchCommand: Codable { case stopVPN case enableOnDemand case moveAppToApplications + case showPrivacyPro } public protocol AppLaunching { From aee85b01a3b76d2d7802236e7a71cfd130e6ff3d Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:50:08 +0100 Subject: [PATCH 72/99] Fix token fetching after merge --- DuckDuckGo.xcodeproj/project.pbxproj | 10 +++-- ...rkProtection+ConvenienceInitializers.swift | 13 +++++- ...tion+VPNAgentConvenienceInitializers.swift | 40 +++++++++++++++++++ 3 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 42eab959d2..246b94fd71 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -2233,8 +2233,6 @@ 7BA7CC562AD11FFB0042E5CE /* NetworkProtectionOptionKeyExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605F2A0B29FA00BCD287 /* NetworkProtectionOptionKeyExtension.swift */; }; 7BA7CC582AD1203A0042E5CE /* UserText+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60D22A0C84F700BCD287 /* UserText+NetworkProtection.swift */; }; 7BA7CC592AD1203B0042E5CE /* UserText+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60D22A0C84F700BCD287 /* UserText+NetworkProtection.swift */; }; - 7BA7CC5A2AD120640042E5CE /* NetworkProtection+ConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60692A0B29FA00BCD287 /* NetworkProtection+ConvenienceInitializers.swift */; }; - 7BA7CC5B2AD120640042E5CE /* NetworkProtection+ConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60692A0B29FA00BCD287 /* NetworkProtection+ConvenienceInitializers.swift */; }; 7BA7CC5C2AD120C30042E5CE /* EventMapping+NetworkProtectionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60722A0B29FA00BCD287 /* EventMapping+NetworkProtectionError.swift */; }; 7BA7CC5D2AD120C30042E5CE /* EventMapping+NetworkProtectionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60722A0B29FA00BCD287 /* EventMapping+NetworkProtectionError.swift */; }; 7BA7CC5F2AD1210C0042E5CE /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 7BA7CC5E2AD1210C0042E5CE /* Networking */; }; @@ -3159,6 +3157,8 @@ EEC8EB402982CD550065AA39 /* JSAlertViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */; }; EECE10E529DD77E60044D027 /* FeatureFlag.swift in Sources */ = {isa = PBXBuildFile; fileRef = EECE10E429DD77E60044D027 /* FeatureFlag.swift */; }; EECE10E629DD77E60044D027 /* FeatureFlag.swift in Sources */ = {isa = PBXBuildFile; fileRef = EECE10E429DD77E60044D027 /* FeatureFlag.swift */; }; + EEDE50112BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDE50102BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift */; }; + EEDE50122BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDE50102BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift */; }; EEF12E6F2A2111880023E6BF /* MacPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */; }; EEF53E182950CED5002D78F4 /* JSAlertViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */; }; F1D43AEE2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */; }; @@ -4511,6 +4511,7 @@ EEC4A66C2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationPreferenceItemModel.swift; sourceTree = ""; }; EEC4A6702B2C90AB00F7C0AA /* VPNLocationPreferenceItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationPreferenceItem.swift; sourceTree = ""; }; EECE10E429DD77E60044D027 /* FeatureFlag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlag.swift; sourceTree = ""; }; + EEDE50102BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkProtection+VPNAgentConvenienceInitializers.swift"; sourceTree = ""; }; EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacPacketTunnelProvider.swift; sourceTree = ""; }; EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSAlertViewModelTests.swift; sourceTree = ""; }; F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MainMenuActions+VanillaBrowser.swift"; sourceTree = ""; }; @@ -6256,6 +6257,7 @@ 7BA7CC132AD11DC80042E5CE /* AppLauncher+DefaultInitializer.swift */, 7BA7CC0E2AD11DC80042E5CE /* DuckDuckGoVPNAppDelegate.swift */, 7BD1688D2AD4A4C400D24876 /* NetworkExtensionController.swift */, + EEDE50102BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift */, 7BA7CC152AD11DC80042E5CE /* NetworkProtectionBouncer.swift */, 7B8DB3192B504D7500EC16DA /* VPNAppEventsHandler.swift */, 7B0694972B6E980F00FA4DBA /* VPNProxyLauncher.swift */, @@ -10842,10 +10844,10 @@ files = ( B6F92BA22A691580002ABA6B /* UserDefaultsWrapper.swift in Sources */, 4B2D065B2A11D1FF00DE1F49 /* Logging.swift in Sources */, - 7BA7CC5B2AD120640042E5CE /* NetworkProtection+ConvenienceInitializers.swift in Sources */, 7BA7CC3A2AD11E2D0042E5CE /* DuckDuckGoVPNAppDelegate.swift in Sources */, 7BAF9E4C2A8A3CCA002D3B6E /* UserDefaults+NetworkProtectionShared.swift in Sources */, 7BA7CC592AD1203B0042E5CE /* UserText+NetworkProtection.swift in Sources */, + EEDE50112BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift in Sources */, 7BA7CC562AD11FFB0042E5CE /* NetworkProtectionOptionKeyExtension.swift in Sources */, 7B2DDCFA2A93B25F0039D884 /* KeychainType+ClientDefault.swift in Sources */, 7BA7CC4C2AD11EC70042E5CE /* NetworkProtectionControllerErrorStore.swift in Sources */, @@ -10880,9 +10882,9 @@ 4BA7C4DB2B3F63AE00AFE511 /* NetworkExtensionController.swift in Sources */, 4B2D067C2A13340900DE1F49 /* Logging.swift in Sources */, 7B1459552B7D438F00047F2C /* VPNProxyLauncher.swift in Sources */, + EEDE50122BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift in Sources */, B6F92BAD2A6937B5002ABA6B /* OptionalExtension.swift in Sources */, 4BA7C4D92B3F61FB00AFE511 /* BundleExtension.swift in Sources */, - 7BA7CC5A2AD120640042E5CE /* NetworkProtection+ConvenienceInitializers.swift in Sources */, EEC589DC2A4F1CE800BCD60C /* AppLauncher.swift in Sources */, 7BA7CC3F2AD11E3D0042E5CE /* AppLauncher+DefaultInitializer.swift in Sources */, 4B0EF7292B5780EB009D6481 /* VPNAppEventsHandler.swift in Sources */, diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift index fcdb50ff75..bac507f752 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift @@ -22,6 +22,10 @@ import Foundation import NetworkProtection import Common +#if SUBSCRIPTION +import Subscription +#endif + extension NetworkProtectionDeviceManager { static func create() -> NetworkProtectionDeviceManager { @@ -48,10 +52,15 @@ extension NetworkProtectionCodeRedemptionCoordinator { extension NetworkProtectionKeychainTokenStore { convenience init() { +#if SUBSCRIPTION + let accessTokenProvider: () -> String? = { AccountManager().accessToken } +#else + let accessTokenProvider: () -> String? = { } +#endif self.init(keychainType: .default, errorEvents: .networkProtectionAppDebugEvents, - isSubscriptionEnabled: false, - accessTokenProvider: { nil }) + isSubscriptionEnabled: DefaultSubscriptionFeatureAvailability().isFeatureAvailable(), + accessTokenProvider: accessTokenProvider) } } diff --git a/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift b/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift new file mode 100644 index 0000000000..3e79d6297d --- /dev/null +++ b/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift @@ -0,0 +1,40 @@ +// +// NetworkProtection+VPNAgentConvenienceInitializers.swift +// +// 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 NetworkProtection + +#if SUBSCRIPTION +import Subscription +#endif + +extension NetworkProtectionKeychainTokenStore { + convenience init() { +#if SUBSCRIPTION + let accessTokenProvider: () -> String? = { AccountManager().accessToken } + let isSubscriptionEnabled = true +#else + let accessTokenProvider: () -> String? = { } + let isSubscriptionEnabled = false +#endif + self.init(keychainType: .default, + errorEvents: .networkProtectionAppDebugEvents, + isSubscriptionEnabled: isSubscriptionEnabled, + accessTokenProvider: accessTokenProvider) + } +} From aa64fe3d4b33122b07dcea8587df83ae50d95e3b Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:59:06 +0100 Subject: [PATCH 73/99] Fix locations fetching --- ...tworkProtection+ConvenienceInitializers.swift | 16 ++++++++++++++-- .../VPNLocation/VPNLocationViewModel.swift | 12 ------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift index bac507f752..3a49aca847 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift @@ -36,7 +36,7 @@ extension NetworkProtectionDeviceManager { tokenStore: tokenStore, keyStore: keyStore, errorEvents: .networkProtectionAppDebugEvents, - isSubscriptionEnabled: false) + isSubscriptionEnabled: DefaultSubscriptionFeatureAvailability().isFeatureAvailable()) } } @@ -46,7 +46,7 @@ extension NetworkProtectionCodeRedemptionCoordinator { self.init(environment: settings.selectedEnvironment, tokenStore: NetworkProtectionKeychainTokenStore(), errorEvents: .networkProtectionAppDebugEvents, - isSubscriptionEnabled: false) + isSubscriptionEnabled: DefaultSubscriptionFeatureAvailability().isFeatureAvailable()) } } @@ -71,4 +71,16 @@ extension NetworkProtectionKeychainKeyStore { } } +extension NetworkProtectionLocationListCompositeRepository { + convenience init() { + let settings = VPNSettings(defaults: .netP) + self.init( + environment: settings.selectedEnvironment, + tokenStore: NetworkProtectionKeychainTokenStore(), + errorEvents: .networkProtectionAppDebugEvents, + isSubscriptionEnabled: DefaultSubscriptionFeatureAvailability().isFeatureAvailable() + ) + } +} + #endif diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift index fb1b74c2ff..24dfd9c4ab 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift @@ -185,18 +185,6 @@ extension VPNCityItemModel { } } -extension NetworkProtectionLocationListCompositeRepository { - convenience init() { - let settings = VPNSettings(defaults: .netP) - self.init( - environment: settings.selectedEnvironment, - tokenStore: NetworkProtectionKeychainTokenStore(), - errorEvents: .networkProtectionAppDebugEvents, - isSubscriptionEnabled: false - ) - } -} - extension VPNLocationViewModel { convenience init() { let locationListRepository = NetworkProtectionLocationListCompositeRepository() From 9d87dab2df81111ae18b8b30191156fa8be84322 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:08:34 +0100 Subject: [PATCH 74/99] Fix non-sub access token provider --- .../NetworkProtection+ConvenienceInitializers.swift | 2 +- .../NetworkProtection+VPNAgentConvenienceInitializers.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift index 3a49aca847..8eed556fac 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift @@ -55,7 +55,7 @@ extension NetworkProtectionKeychainTokenStore { #if SUBSCRIPTION let accessTokenProvider: () -> String? = { AccountManager().accessToken } #else - let accessTokenProvider: () -> String? = { } + let accessTokenProvider: () -> String? = { return nil } #endif self.init(keychainType: .default, errorEvents: .networkProtectionAppDebugEvents, diff --git a/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift b/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift index 3e79d6297d..cc9105c40d 100644 --- a/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift +++ b/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift @@ -29,7 +29,7 @@ extension NetworkProtectionKeychainTokenStore { let accessTokenProvider: () -> String? = { AccountManager().accessToken } let isSubscriptionEnabled = true #else - let accessTokenProvider: () -> String? = { } + let accessTokenProvider: () -> String? = { return nil } let isSubscriptionEnabled = false #endif self.init(keychainType: .default, From 3d0a748ec8a30ac35e74db9c5c70c1a0d3a029fd Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:38:05 +0100 Subject: [PATCH 75/99] Revert to subs compiler flag for init of token store --- .../NetworkProtection+ConvenienceInitializers.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift index 8eed556fac..795b0c1666 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift @@ -53,13 +53,15 @@ extension NetworkProtectionCodeRedemptionCoordinator { extension NetworkProtectionKeychainTokenStore { convenience init() { #if SUBSCRIPTION + let isSubscriptionEnabled = true let accessTokenProvider: () -> String? = { AccountManager().accessToken } #else + let isSubscriptionEnabled = false let accessTokenProvider: () -> String? = { return nil } #endif self.init(keychainType: .default, errorEvents: .networkProtectionAppDebugEvents, - isSubscriptionEnabled: DefaultSubscriptionFeatureAvailability().isFeatureAvailable(), + isSubscriptionEnabled: isSubscriptionEnabled, accessTokenProvider: accessTokenProvider) } } From 0fcb50b3f4ee2439a7f9a2acb4d8444cd3e81da0 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:44:53 +0100 Subject: [PATCH 76/99] Revert "Revert to subs compiler flag for init of token store" This reverts commit 3d0a748ec8a30ac35e74db9c5c70c1a0d3a029fd. --- .../NetworkProtection+ConvenienceInitializers.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift index 795b0c1666..8eed556fac 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtection+ConvenienceInitializers.swift @@ -53,15 +53,13 @@ extension NetworkProtectionCodeRedemptionCoordinator { extension NetworkProtectionKeychainTokenStore { convenience init() { #if SUBSCRIPTION - let isSubscriptionEnabled = true let accessTokenProvider: () -> String? = { AccountManager().accessToken } #else - let isSubscriptionEnabled = false let accessTokenProvider: () -> String? = { return nil } #endif self.init(keychainType: .default, errorEvents: .networkProtectionAppDebugEvents, - isSubscriptionEnabled: isSubscriptionEnabled, + isSubscriptionEnabled: DefaultSubscriptionFeatureAvailability().isFeatureAvailable(), accessTokenProvider: accessTokenProvider) } } From 0f19b471fb732a7df5e7d5edf32a6ec3ed24b6e7 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:45:11 +0100 Subject: [PATCH 77/99] Make subs event handler lazy to prevent crash --- DuckDuckGo/Application/AppDelegate.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index d0aa5916c6..e4f938425a 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -82,7 +82,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel var privacyDashboardWindow: NSWindow? #if NETWORK_PROTECTION && SUBSCRIPTION - private let networkProtectionSubscriptionEventHandler = NetworkProtectionSubscriptionEventHandler() + // Needs to be lazy as indirectly depends on AppDelegate + private lazy var networkProtectionSubscriptionEventHandler = NetworkProtectionSubscriptionEventHandler() #endif #if DBP && SUBSCRIPTION From 944ddce63df8925221024f1ca35629e115bc7f70 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:03:16 +0100 Subject: [PATCH 78/99] Remove crashy stuff from subsfeatureavailaibility --- .../SubscriptionFeatureAvailability.swift | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift b/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift index 6599bd0ee9..9e0b2780d5 100644 --- a/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift +++ b/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift @@ -36,8 +36,8 @@ struct DefaultSubscriptionFeatureAvailability: SubscriptionFeatureAvailability { #if SUBSCRIPTION_OVERRIDE_ENABLED return true #elseif SUBSCRIPTION - print("isUserAuthenticated: [\(AccountManager().isUserAuthenticated)] | isSubscriptionInternalTestingEnabled: [\(isSubscriptionInternalTestingEnabled)] isInternalUser: [\(isInternalUser)] | isVPNActivated: [\(isVPNActivated)] | isDBPActivated: [\(isDBPActivated)]") - return AccountManager().isUserAuthenticated || (isSubscriptionInternalTestingEnabled && isInternalUser && !isVPNActivated && !isDBPActivated) + print("isUserAuthenticated: [\(AccountManager().isUserAuthenticated)] | isSubscriptionInternalTestingEnabled: [\(isSubscriptionInternalTestingEnabled)] isInternalUser: [\(isInternalUser)] | isDBPActivated: [\(isDBPActivated)]") + return AccountManager().isUserAuthenticated || (isSubscriptionInternalTestingEnabled && isInternalUser && !isDBPActivated) #else return false #endif @@ -51,14 +51,6 @@ struct DefaultSubscriptionFeatureAvailability: SubscriptionFeatureAvailability { NSApp.delegateTyped.internalUserDecider.isInternalUser } - private var isVPNActivated: Bool { -#if NETWORK_PROTECTION - return NetworkProtectionKeychainTokenStore().isFeatureActivated -#else - return false -#endif - } - private var isDBPActivated: Bool { #if DBP return DataBrokerProtectionManager.shared.dataManager.fetchProfile(ignoresCache: true) != nil From 898da73efaa812f90726e749b3c45dfcf9008656 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 15 Mar 2024 14:07:45 +0100 Subject: [PATCH 79/99] Also check waitlist token for expiry prompt --- .../NetworkProtectionNavBarPopoverManager.swift | 4 +++- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 3 ++- .../NetworkProtectionUI/Menu/StatusBarMenu.swift | 6 ++++-- .../NetworkProtectionUI/NetworkProtectionPopover.swift | 6 ++++-- .../StatusView/NetworkProtectionStatusViewModel.swift | 10 ++++++++-- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index 1849ec4e87..0a25d1a953 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -124,7 +124,9 @@ final class NetworkProtectionNavBarPopoverManager: NetPPopoverManager { Task { [weak self] in await self?.networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: true) } - }) + }, + featureActivation: NetworkProtectionKeychainTokenStore() + ) popover.delegate = delegate networkProtectionPopover = popover diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index c695f95e10..9e443666cd 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -264,7 +264,8 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { guard let self else { return } await self.vpnUninstaller.uninstall(includingSystemExtension: true) } - } + }, + featureActivation: NetworkProtectionKeychainTokenStore() ) } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift index 1833f8482e..4d2fe9eef9 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift @@ -58,7 +58,8 @@ public final class StatusBarMenu: NSObject { agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, userDefaults: UserDefaults, - uninstallHandler: @escaping () async -> Void) { + uninstallHandler: @escaping () async -> Void, + featureActivation: NetworkProtectionFeatureActivation) { self.model = model let statusItem = statusItem ?? NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) @@ -73,7 +74,8 @@ public final class StatusBarMenu: NSObject { agentLoginItem: agentLoginItem, isMenuBarStatusView: isMenuBarStatusView, userDefaults: userDefaults, - uninstallHandler: uninstallHandler) + uninstallHandler: uninstallHandler, + featureActivation: featureActivation) popover.behavior = .transient diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift index 0acbf84065..6ca4fc305d 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift @@ -58,7 +58,8 @@ public final class NetworkProtectionPopover: NSPopover { agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, userDefaults: UserDefaults, - uninstallHandler: @escaping () async -> Void) { + uninstallHandler: @escaping () async -> Void, + featureActivation: NetworkProtectionFeatureActivation) { self.statusReporter = statusReporter self.model = NetworkProtectionStatusView.Model(controller: controller, @@ -70,7 +71,8 @@ public final class NetworkProtectionPopover: NSPopover { agentLoginItem: agentLoginItem, isMenuBarStatusView: isMenuBarStatusView, userDefaults: userDefaults, - uninstallHandler: uninstallHandler) + uninstallHandler: uninstallHandler, + featureActivation: featureActivation) super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index d05370f897..336e44e538 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -98,6 +98,8 @@ extension NetworkProtectionStatusView { private let uninstallHandler: () async -> Void + private let featureActivation: NetworkProtectionFeatureActivation + private var cancellables = Set() // MARK: - Dispatch Queues @@ -119,7 +121,8 @@ extension NetworkProtectionStatusView { isMenuBarStatusView: Bool, runLoopMode: RunLoop.Mode? = nil, userDefaults: UserDefaults, - uninstallHandler: @escaping () async -> Void) { + uninstallHandler: @escaping () async -> Void, + featureActivation: NetworkProtectionFeatureActivation) { self.tunnelController = controller self.onboardingStatusPublisher = onboardingStatusPublisher @@ -131,6 +134,7 @@ extension NetworkProtectionStatusView { self.runLoopMode = runLoopMode self.appLauncher = appLauncher self.uninstallHandler = uninstallHandler + self.featureActivation = featureActivation tunnelControllerViewModel = TunnelControllerViewModel(controller: tunnelController, onboardingStatusPublisher: onboardingStatusPublisher, @@ -161,7 +165,9 @@ extension NetworkProtectionStatusView { userDefaults .publisher(for: \.networkProtectionEntitlementsValid) .receive(on: DispatchQueue.main) - .map { !$0 } + .map { entitlementsValid in + return !(entitlementsValid || featureActivation.isFeatureActivated) + } .assign(to: \.shouldShowSubscriptionExpired, onWeaklyHeld: self) .store(in: &cancellables) } From f5b2393ebcf508f54d72f84fdc4a959afe08ab30 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:36:40 +0100 Subject: [PATCH 80/99] Revert "Also check waitlist token for expiry prompt" This reverts commit 898da73efaa812f90726e749b3c45dfcf9008656. --- .../NetworkProtectionNavBarPopoverManager.swift | 4 +--- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 3 +-- .../NetworkProtectionUI/Menu/StatusBarMenu.swift | 6 ++---- .../NetworkProtectionUI/NetworkProtectionPopover.swift | 6 ++---- .../StatusView/NetworkProtectionStatusViewModel.swift | 10 ++-------- 5 files changed, 8 insertions(+), 21 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index 0a25d1a953..1849ec4e87 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -124,9 +124,7 @@ final class NetworkProtectionNavBarPopoverManager: NetPPopoverManager { Task { [weak self] in await self?.networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: true) } - }, - featureActivation: NetworkProtectionKeychainTokenStore() - ) + }) popover.delegate = delegate networkProtectionPopover = popover diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 9e443666cd..c695f95e10 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -264,8 +264,7 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { guard let self else { return } await self.vpnUninstaller.uninstall(includingSystemExtension: true) } - }, - featureActivation: NetworkProtectionKeychainTokenStore() + } ) } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift index 4d2fe9eef9..1833f8482e 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift @@ -58,8 +58,7 @@ public final class StatusBarMenu: NSObject { agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, userDefaults: UserDefaults, - uninstallHandler: @escaping () async -> Void, - featureActivation: NetworkProtectionFeatureActivation) { + uninstallHandler: @escaping () async -> Void) { self.model = model let statusItem = statusItem ?? NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) @@ -74,8 +73,7 @@ public final class StatusBarMenu: NSObject { agentLoginItem: agentLoginItem, isMenuBarStatusView: isMenuBarStatusView, userDefaults: userDefaults, - uninstallHandler: uninstallHandler, - featureActivation: featureActivation) + uninstallHandler: uninstallHandler) popover.behavior = .transient diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift index 6ca4fc305d..0acbf84065 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift @@ -58,8 +58,7 @@ public final class NetworkProtectionPopover: NSPopover { agentLoginItem: LoginItem?, isMenuBarStatusView: Bool, userDefaults: UserDefaults, - uninstallHandler: @escaping () async -> Void, - featureActivation: NetworkProtectionFeatureActivation) { + uninstallHandler: @escaping () async -> Void) { self.statusReporter = statusReporter self.model = NetworkProtectionStatusView.Model(controller: controller, @@ -71,8 +70,7 @@ public final class NetworkProtectionPopover: NSPopover { agentLoginItem: agentLoginItem, isMenuBarStatusView: isMenuBarStatusView, userDefaults: userDefaults, - uninstallHandler: uninstallHandler, - featureActivation: featureActivation) + uninstallHandler: uninstallHandler) super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 336e44e538..d05370f897 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -98,8 +98,6 @@ extension NetworkProtectionStatusView { private let uninstallHandler: () async -> Void - private let featureActivation: NetworkProtectionFeatureActivation - private var cancellables = Set() // MARK: - Dispatch Queues @@ -121,8 +119,7 @@ extension NetworkProtectionStatusView { isMenuBarStatusView: Bool, runLoopMode: RunLoop.Mode? = nil, userDefaults: UserDefaults, - uninstallHandler: @escaping () async -> Void, - featureActivation: NetworkProtectionFeatureActivation) { + uninstallHandler: @escaping () async -> Void) { self.tunnelController = controller self.onboardingStatusPublisher = onboardingStatusPublisher @@ -134,7 +131,6 @@ extension NetworkProtectionStatusView { self.runLoopMode = runLoopMode self.appLauncher = appLauncher self.uninstallHandler = uninstallHandler - self.featureActivation = featureActivation tunnelControllerViewModel = TunnelControllerViewModel(controller: tunnelController, onboardingStatusPublisher: onboardingStatusPublisher, @@ -165,9 +161,7 @@ extension NetworkProtectionStatusView { userDefaults .publisher(for: \.networkProtectionEntitlementsValid) .receive(on: DispatchQueue.main) - .map { entitlementsValid in - return !(entitlementsValid || featureActivation.isFeatureActivated) - } + .map { !$0 } .assign(to: \.shouldShowSubscriptionExpired, onWeaklyHeld: self) .store(in: &cancellables) } From bada414fd5368f3a53c4b574a395e441e795a07d Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Fri, 15 Mar 2024 17:00:22 +0100 Subject: [PATCH 81/99] Utilise yet another UserDefault for waitlist state --- .../NetworkProtectionAppEvents.swift | 2 + .../UserDefault+VPNEnabledViaWaitlist.swift | 44 +++++++++++++++++++ .../NetworkProtectionStatusViewModel.swift | 4 +- 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefault+VPNEnabledViaWaitlist.swift diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift index ce62ed2734..23d20a89d2 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift @@ -72,9 +72,11 @@ final class NetworkProtectionAppEvents { /// func applicationDidBecomeActive() { guard featureVisibility.isNetworkProtectionVisible() else { + UserDefaults.netP.networkProtectionVPNEnabledViaWaitlist = false featureVisibility.disableForAllUsers() return } + UserDefaults.netP.networkProtectionVPNEnabledViaWaitlist = true } private func restartNetworkProtectionIfVersionChanged(using loginItemsManager: LoginItemsManager) { diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefault+VPNEnabledViaWaitlist.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefault+VPNEnabledViaWaitlist.swift new file mode 100644 index 0000000000..397f67f6ac --- /dev/null +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefault+VPNEnabledViaWaitlist.swift @@ -0,0 +1,44 @@ +// +// UserDefault+VPNEnabledViaWaitlist.swift +// +// 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 + +public extension UserDefaults { + private enum Key { + static var networkProtectionVPNEnabledViaWaitlist = "networkProtectionVPNEnabledViaWaitlist" + } + + // Convenience declaration + private var networkProtectionVPNEnabledViaWaitlistRawValueKey: String { + Key.networkProtectionVPNEnabledViaWaitlist + } + + /// For KVO to work across processes (Menu App + Main App) we need to declare this dynamic var in a `UserDefaults` + /// extension, and the key for this property must match its name exactly. + /// + @objc + dynamic var networkProtectionVPNEnabledViaWaitlist: Bool { + get { + value(forKey: networkProtectionVPNEnabledViaWaitlistRawValueKey) as? Bool ?? false + } + + set { + set(newValue, forKey: networkProtectionVPNEnabledViaWaitlistRawValueKey) + } + } +} diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index d05370f897..6c65c96deb 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -161,7 +161,9 @@ extension NetworkProtectionStatusView { userDefaults .publisher(for: \.networkProtectionEntitlementsValid) .receive(on: DispatchQueue.main) - .map { !$0 } + .map { entitlementsAreValid in + !(entitlementsAreValid || userDefaults.networkProtectionVPNEnabledViaWaitlist) + } .assign(to: \.shouldShowSubscriptionExpired, onWeaklyHeld: self) .store(in: &cancellables) } From b45681d250a63359c990a1ae84b7c03c46be411f Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:00:44 +0100 Subject: [PATCH 82/99] Invert the UD validity bool to fix for waitlist --- .../NetworkProtectionSubscriptionEventHandler.swift | 9 +++++---- .../Preferences/Model/PreferencesSidebarModel.swift | 8 ++++---- .../NetworkProtectionFeatureVisibility.swift | 2 +- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 4 ++-- ...faults+NetworkProtectionExpiredEntitlements.swift | 12 ++++++------ .../NetworkProtectionStatusViewModel.swift | 5 +---- 6 files changed, 19 insertions(+), 21 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift index 67065cbb8a..6a2a8751cd 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift @@ -56,9 +56,9 @@ final class NetworkProtectionSubscriptionEventHandler { await entitlementMonitor.start(entitlementCheck: entitlementsCheck) { result in switch result { case .validEntitlement: - UserDefaults.netP.networkProtectionEntitlementsValid = true + UserDefaults.netP.networkProtectionEntitlementsExpired = false case .invalidEntitlement: - UserDefaults.netP.networkProtectionEntitlementsValid = false + UserDefaults.netP.networkProtectionEntitlementsExpired = true case .error: break } @@ -77,12 +77,13 @@ final class NetworkProtectionSubscriptionEventHandler { assertionFailure("[NetP Subscription] AccountManager signed in but token could not be retrieved") return } - userDefaults.networkProtectionEntitlementsValid = true + userDefaults.networkProtectionEntitlementsExpired = false + setUpEntitlementMonitoring() } @objc private func handleAccountDidSignOut() { print("[NetP Subscription] Deleted NetP auth token after signing out from Privacy Pro") - userDefaults.networkProtectionEntitlementsValid = false + userDefaults.networkProtectionEntitlementsExpired = true Task { await networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: false) diff --git a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift index 5efc478ed2..23d4ec919d 100644 --- a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift +++ b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift @@ -84,7 +84,7 @@ final class PreferencesSidebarModel: ObservableObject { ) { let loadSections = { #if SUBSCRIPTION - let includingVPN = userDefaults.networkProtectionEntitlementsValid && DefaultNetworkProtectionVisibility().isOnboarded + let includingVPN = !userDefaults.networkProtectionEntitlementsExpired && DefaultNetworkProtectionVisibility().isOnboarded #elseif NETWORK_PROTECTION let includingVPN = DefaultNetworkProtectionVisibility().isOnboarded #else @@ -121,11 +121,11 @@ final class PreferencesSidebarModel: ObservableObject { } .store(in: &cancellables) - UserDefaults.netP.publisher(for: \.networkProtectionEntitlementsValid) + UserDefaults.netP.publisher(for: \.networkProtectionEntitlementsExpired) .receive(on: DispatchQueue.main) - .sink { [weak self] entitlementsValid in + .sink { [weak self] entitlementsExpired in guard let self else { return } - if !entitlementsValid && self.selectedPane == .vpn { + if !entitlementsExpired && self.selectedPane == .vpn { self.selectedPane = .general } self.refreshSections() diff --git a/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift b/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift index 78ea5be429..08d52679a3 100644 --- a/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift +++ b/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift @@ -74,7 +74,7 @@ struct DefaultNetworkProtectionVisibility: NetworkProtectionFeatureVisibility { /// This is only true when the user is not an Easter Egg user, the waitlist test has ended, and the user is onboarded. func shouldUninstallAutomatically() -> Bool { #if SUBSCRIPTION - return !defaults.networkProtectionEntitlementsValid && LoginItem.vpnMenu.status.isInstalled + return defaults.networkProtectionEntitlementsExpired && LoginItem.vpnMenu.status.isInstalled #else let waitlistAccessEnded = isWaitlistUser && !waitlistIsOngoing let isNotEasterEggUser = !isEasterEggUser diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index c695f95e10..8a04fd0652 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -365,9 +365,9 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { await entitlementMonitor.start(entitlementCheck: entitlementsCheck) { [weak self] result in switch result { case .validEntitlement: - UserDefaults.netP.networkProtectionEntitlementsValid = true + UserDefaults.netP.networkProtectionEntitlementsExpired = false case .invalidEntitlement: - UserDefaults.netP.networkProtectionEntitlementsValid = false + UserDefaults.netP.networkProtectionEntitlementsExpired = true guard let self else { return } Task { let isConnected = await self.tunnelController.isConnected diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift index 6c8d82b740..0768592eff 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserDefaults+NetworkProtectionExpiredEntitlements.swift @@ -20,25 +20,25 @@ import Foundation public extension UserDefaults { private enum Key { - static var networkProtectionEntitlementsValid = "networkProtectionEntitlementsValid" + static var networkProtectionEntitlementsExpired = "networkProtectionEntitlementsExpired" } // Convenience declaration - private var networkProtectionEntitlementsValidRawValueKey: String { - Key.networkProtectionEntitlementsValid + private var networkProtectionEntitlementsExpiredRawValueKey: String { + Key.networkProtectionEntitlementsExpired } /// For KVO to work across processes (Menu App + Main App) we need to declare this dynamic var in a `UserDefaults` /// extension, and the key for this property must match its name exactly. /// @objc - dynamic var networkProtectionEntitlementsValid: Bool { + dynamic var networkProtectionEntitlementsExpired: Bool { get { - value(forKey: networkProtectionEntitlementsValidRawValueKey) as? Bool ?? false + value(forKey: networkProtectionEntitlementsExpiredRawValueKey) as? Bool ?? false } set { - set(newValue, forKey: networkProtectionEntitlementsValidRawValueKey) + set(newValue, forKey: networkProtectionEntitlementsExpiredRawValueKey) } } } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 6c65c96deb..7df51daf58 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -159,11 +159,8 @@ extension NetworkProtectionStatusView { .store(in: &cancellables) userDefaults - .publisher(for: \.networkProtectionEntitlementsValid) + .publisher(for: \.networkProtectionEntitlementsExpired) .receive(on: DispatchQueue.main) - .map { entitlementsAreValid in - !(entitlementsAreValid || userDefaults.networkProtectionVPNEnabledViaWaitlist) - } .assign(to: \.shouldShowSubscriptionExpired, onWeaklyHeld: self) .store(in: &cancellables) } From f20cbffab4d74dc952493552ceae55653efe9bbe Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:02:39 +0100 Subject: [PATCH 83/99] Don't run entitlements check if not authenticated --- .../NetworkProtectionSubscriptionEventHandler.swift | 2 +- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift index 6a2a8751cd..963c25c3ce 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift @@ -47,7 +47,7 @@ final class NetworkProtectionSubscriptionEventHandler { private func setUpEntitlementMonitoring() { SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging - + guard AccountManager().isUserAuthenticated else { return } let entitlementsCheck = { await AccountManager().hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) } diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 8a04fd0652..a2bd1e1521 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -357,6 +357,7 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { private func setUpSubscriptionMonitoring() { #if SUBSCRIPTION + guard AccountManager().isUserAuthenticated else { return } let entitlementsCheck = { await AccountManager().hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) } From 52a1d79b6fb7f78ebc8d2a991cc136fe44116486 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 13:09:22 +0100 Subject: [PATCH 84/99] Update Package.resolved after merge --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1785e7f697..631d43cca9 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -33,7 +33,7 @@ "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { "branch" : "graeme/expired-entitlements-stuff", - "revision" : "d48ecf18f71f6a265fbc00a19c1e444bd3af0db8" + "revision" : "0b65748909e192c6278290b0a340f03c6b53fcaa" } }, { From a3083f6b5e4c0400a5678d0f0f0d3d6e408abc45 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 13:51:25 +0100 Subject: [PATCH 85/99] Remove unused notification constant --- DuckDuckGoVPN/VPNUninstaller.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/DuckDuckGoVPN/VPNUninstaller.swift b/DuckDuckGoVPN/VPNUninstaller.swift index 00b983c3bc..52593d9faa 100644 --- a/DuckDuckGoVPN/VPNUninstaller.swift +++ b/DuckDuckGoVPN/VPNUninstaller.swift @@ -25,7 +25,6 @@ protocol VPNUninstalling { } final class VPNUninstaller: VPNUninstalling { - static let vpnUninstalledNotificationName = NSNotification.Name(rawValue: "com.duckduckgo.NetworkProtection.uninstalled") let networkExtensionController: NetworkExtensionController let vpnConfiguration: VPNConfigurationManager let defaults: UserDefaults From 5fe65e9382551017919f63065d0e7121de4d3699 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 14:07:15 +0100 Subject: [PATCH 86/99] Remove unnecessary Task dispatch --- .../NetworkProtectionNavBarPopoverManager.swift | 4 +--- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index 1849ec4e87..331892d0f5 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -121,9 +121,7 @@ final class NetworkProtectionNavBarPopoverManager: NetPPopoverManager { isMenuBarStatusView: false, userDefaults: .netP, uninstallHandler: { [weak self] in - Task { [weak self] in - await self?.networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: true) - } + _ = await self?.networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: true) }) popover.delegate = delegate diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index a2bd1e1521..07daf76c87 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -260,10 +260,8 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { isMenuBarStatusView: true, userDefaults: .netP, uninstallHandler: { [weak self] in - Task { [weak self] in - guard let self else { return } - await self.vpnUninstaller.uninstall(includingSystemExtension: true) - } + guard let self else { return } + await self.vpnUninstaller.uninstall(includingSystemExtension: true) } ) } From 650972995476545d7607c40240873b646977e7a8 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:05:25 +0100 Subject: [PATCH 87/99] Make the bouncer call block subsequent actions --- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 68 ++++++++++---------- DuckDuckGoVPN/NetworkProtectionBouncer.swift | 28 ++++---- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 07daf76c87..aa1e89c89a 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -274,59 +274,61 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { setupMenuVisibility() - bouncer.requireAuthenticationOrKillApp() + Task { @MainActor in + await bouncer.requireAuthenticationOrKillApp() - // Initialize lazy properties - _ = tunnelControllerIPCService - _ = vpnProxyLauncher + // Initialize lazy properties + _ = tunnelControllerIPCService + _ = vpnProxyLauncher - let dryRun: Bool + let dryRun: Bool #if DEBUG - dryRun = true + dryRun = true #else - dryRun = false + dryRun = false #endif - let pixelSource: String + let pixelSource: String #if NETP_SYSTEM_EXTENSION - pixelSource = "vpnAgent" + pixelSource = "vpnAgent" #else - pixelSource = "vpnAgentAppStore" + pixelSource = "vpnAgentAppStore" #endif - PixelKit.setUp(dryRun: dryRun, - appVersion: AppVersion.shared.versionNumber, - source: pixelSource, - defaultHeaders: [:], - log: .networkProtectionPixel, - defaults: .netP) { (pixelName: String, headers: [String: String], parameters: [String: String], _, _, onComplete: @escaping PixelKit.CompletionBlock) in + PixelKit.setUp(dryRun: dryRun, + appVersion: AppVersion.shared.versionNumber, + source: pixelSource, + defaultHeaders: [:], + log: .networkProtectionPixel, + defaults: .netP) { (pixelName: String, headers: [String: String], parameters: [String: String], _, _, onComplete: @escaping PixelKit.CompletionBlock) in - let url = URL.pixelUrl(forPixelNamed: pixelName) - let apiHeaders = APIRequest.Headers(additionalHeaders: headers) // workaround - Pixel class should really handle APIRequest.Headers by itself - let configuration = APIRequest.Configuration(url: url, method: .get, queryParameters: parameters, headers: apiHeaders) - let request = APIRequest(configuration: configuration) + let url = URL.pixelUrl(forPixelNamed: pixelName) + let apiHeaders = APIRequest.Headers(additionalHeaders: headers) // workaround - Pixel class should really handle APIRequest.Headers by itself + let configuration = APIRequest.Configuration(url: url, method: .get, queryParameters: parameters, headers: apiHeaders) + let request = APIRequest(configuration: configuration) - request.fetch { _, error in - onComplete(error == nil, error) + request.fetch { _, error in + onComplete(error == nil, error) + } } - } - vpnAppEventsHandler.appDidFinishLaunching() + vpnAppEventsHandler.appDidFinishLaunching() - let launchInformation = LoginItemLaunchInformation(agentBundleID: Bundle.main.bundleIdentifier!, defaults: .netP) - let launchedOnStartup = launchInformation.wasLaunchedByStartup - launchInformation.update() + let launchInformation = LoginItemLaunchInformation(agentBundleID: Bundle.main.bundleIdentifier!, defaults: .netP) + let launchedOnStartup = launchInformation.wasLaunchedByStartup + launchInformation.update() - setUpSubscriptionMonitoring() + setUpSubscriptionMonitoring() - if launchedOnStartup { - Task { - let isConnected = await tunnelController.isConnected + if launchedOnStartup { + Task { + let isConnected = await tunnelController.isConnected - if !isConnected && tunnelSettings.connectOnLogin { - await tunnelController.start() + if !isConnected && tunnelSettings.connectOnLogin { + await tunnelController.start() + } } } } diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index 4c3e6089c3..c56513e65c 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -33,23 +33,21 @@ final class NetworkProtectionBouncer { /// Simply verifies that the VPN feature is enabled and if not, takes care of killing the /// current app. /// - func requireAuthenticationOrKillApp() { + func requireAuthenticationOrKillApp() async { #if SUBSCRIPTION - Task { - let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) - let result = await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) - switch result { - case .success(true), .failure: - return - case .success(false): - os_log(.error, log: .networkProtection, "🔴 Stopping: VPN not authorized. Missing entitlement.") + let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) + let result = await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) + switch result { + case .success(true), .failure: + return + case .success(false): + os_log(.error, log: .networkProtection, "🔴 Stopping: VPN not authorized. Missing entitlement.") - // EXIT_SUCCESS ensures the login item won't relaunch - // Ref: https://developer.apple.com/documentation/servicemanagement/smappservice/register() - // See where it mentions: - // "If the helper crashes or exits with a non-zero status, the system relaunches it" - exit(EXIT_SUCCESS) - } + // EXIT_SUCCESS ensures the login item won't relaunch + // Ref: https://developer.apple.com/documentation/servicemanagement/smappservice/register() + // See where it mentions: + // "If the helper crashes or exits with a non-zero status, the system relaunches it" + exit(EXIT_SUCCESS) } #else let keychainStore = NetworkProtectionKeychainTokenStore(keychainType: .default, From fd394132fba620facd199d75a99ecc3c845d94bf Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:34:57 +0100 Subject: [PATCH 88/99] Remove subscription lib staging configuration --- .../NetworkProtectionSubscriptionEventHandler.swift | 1 - .../NetworkExtensionTargets/MacPacketTunnelProvider.swift | 1 - DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 3 --- 3 files changed, 5 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift index 963c25c3ce..4eae61057b 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift @@ -46,7 +46,6 @@ final class NetworkProtectionSubscriptionEventHandler { private lazy var entitlementMonitor = NetworkProtectionEntitlementMonitor() private func setUpEntitlementMonitoring() { - SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging guard AccountManager().isUserAuthenticated else { return } let entitlementsCheck = { await AccountManager().hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index a900a3327b..792f53fd6d 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -295,7 +295,6 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { accessTokenStorage: tokenStore, entitlementsCache: UserDefaultsCache<[Entitlement]>(key: UserDefaultsCacheKey.subscriptionEntitlements) ) - SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging let entitlementsCheck = { await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) } diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index aa1e89c89a..4ece31c7d4 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -47,9 +47,6 @@ final class DuckDuckGoVPNApplication: NSApplication { super.init() self.delegate = _delegate -#if SUBSCRIPTION - SubscriptionPurchaseEnvironment.currentServiceEnvironment = .staging -#endif #if DEBUG && SUBSCRIPTION let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) From 6a25ed4a35707cd3774ebbb785c188eb3930e357 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:38:38 +0100 Subject: [PATCH 89/99] replace NSnotification for VPN uninstalled --- .../View/NavigationBarViewController.swift | 4 ---- .../Waitlist/NetworkProtectionFeatureDisabler.swift | 13 ++++--------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift index 9f32b02194..fbe69492b5 100644 --- a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift +++ b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift @@ -438,10 +438,6 @@ final class NavigationBarViewController: NSViewController { object: nil) #if NETWORK_PROTECTION - NotificationCenter.default.addObserver(self, - selector: #selector(showVPNUninstalledFeedback), - name: NetworkProtectionFeatureDisabler.vpnUninstalledNotificationName, - object: nil) UserDefaults.netP .publisher(for: \.networkProtectionShouldShowVPNUninstalledMessage) .receive(on: DispatchQueue.main) diff --git a/DuckDuckGo/Waitlist/NetworkProtectionFeatureDisabler.swift b/DuckDuckGo/Waitlist/NetworkProtectionFeatureDisabler.swift index f33b15c8c7..dd5572e94c 100644 --- a/DuckDuckGo/Waitlist/NetworkProtectionFeatureDisabler.swift +++ b/DuckDuckGo/Waitlist/NetworkProtectionFeatureDisabler.swift @@ -33,8 +33,6 @@ protocol NetworkProtectionFeatureDisabling { } final class NetworkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling { - static let vpnUninstalledNotificationName = NSNotification.Name(rawValue: "com.duckduckgo.NetworkProtection.uninstalled") - private let log: OSLog private let loginItemsManager: LoginItemsManager private let pinningManager: LocalPinningManager @@ -91,7 +89,7 @@ final class NetworkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling } unpinNetworkProtection() - postVPNUninstalledNotification() + notifyVPNUninstalled() return true } @@ -126,14 +124,11 @@ final class NetworkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling settings.resetToDefaults() } - private func postVPNUninstalledNotification() { - Task { @MainActor in + private func notifyVPNUninstalled() { // Wait a bit since the NetP button is likely being hidden + Task { try? await Task.sleep(nanoseconds: 500 * NSEC_PER_MSEC) - - NotificationCenter.default.post( - name: Self.vpnUninstalledNotificationName, - object: nil) + userDefaults.networkProtectionShouldShowVPNUninstalledMessage = true } } } From 2e42598859cd812c418aaaf59f5742f84445b27e Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:51:35 +0100 Subject: [PATCH 90/99] Point to updated BSK branch --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8827764be0..1b5f69d7d3 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" : "7656e94efcf4eedf1c16152c63f57fb52b6ad079", - "version" : "126.0.0" + "branch" : "graeme/expired-entitlements-stuff", + "revision" : "ffd1b747847af4bd3156b2a0bff71513b83d1d22" } }, { From e33b7d128d2947faee64c61eab8e72bbaf4331f6 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 17:37:04 +0100 Subject: [PATCH 91/99] Remove warning --- .../NetworkProtectionSubscriptionEventHandler.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift index 4eae61057b..9f7287b8a7 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionSubscriptionEventHandler.swift @@ -72,7 +72,7 @@ final class NetworkProtectionSubscriptionEventHandler { } @objc private func handleAccountDidSignIn() { - guard let token = accountManager.accessToken else { + guard accountManager.accessToken != nil else { assertionFailure("[NetP Subscription] AccountManager signed in but token could not be retrieved") return } From 74f257d2324b6d6e3589908035a4f511ed7ddaba Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Mon, 18 Mar 2024 18:32:32 +0100 Subject: [PATCH 92/99] Set subs env based on VPN in agent and extension --- .../NetworkExtensionTargets/MacPacketTunnelProvider.swift | 1 + DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 792f53fd6d..64cd5cca5a 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -295,6 +295,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { accessTokenStorage: tokenStore, entitlementsCache: UserDefaultsCache<[Entitlement]>(key: UserDefaultsCacheKey.subscriptionEntitlements) ) + SubscriptionPurchaseEnvironment.currentServiceEnvironment = settings.selectedEnvironment == .production ? .production : .staging let entitlementsCheck = { await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) } diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index 4ece31c7d4..5d57d79cc3 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -317,6 +317,10 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { let launchedOnStartup = launchInformation.wasLaunchedByStartup launchInformation.update() +#if SUBSCRIPTION + SubscriptionPurchaseEnvironment.currentServiceEnvironment = tunnelSettings.selectedEnvironment == .production ? .production : .staging +#endif + setUpSubscriptionMonitoring() if launchedOnStartup { From 1d3f0815159a54112b56f373dd6c6f6ed434d495 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 19 Mar 2024 14:05:15 +0100 Subject: [PATCH 93/99] Update bouncer after main merge --- DuckDuckGoVPN/NetworkProtectionBouncer.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index ace7f7e2d7..884cb42224 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -39,9 +39,9 @@ final class NetworkProtectionBouncer { let result = await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) switch result { case .success(true), .failure: - return + break case .success(false): - os_log(.error, log: .networkProtection, "🔴 Stopping: VPN not authorized. Missing entitlement.") + os_log(.error, log: .networkProtection, "🔴 Stopping: DuckDuckGo VPN not authorized. Missing entitlement.") await controller.stop() // EXIT_SUCCESS ensures the login item won't relaunch @@ -50,7 +50,7 @@ final class NetworkProtectionBouncer { // "If the helper crashes or exits with a non-zero status, the system relaunches it" exit(EXIT_SUCCESS) } -#else +#endif let keychainStore = NetworkProtectionKeychainTokenStore(keychainType: .default, errorEvents: nil, isSubscriptionEnabled: false, @@ -66,6 +66,5 @@ final class NetworkProtectionBouncer { // "If the helper crashes or exits with a non-zero status, the system relaunches it" exit(EXIT_SUCCESS) } -#endif } } From fcb7a83d194935110d974493ad12bd7ffa18c283 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 19 Mar 2024 15:05:21 +0100 Subject: [PATCH 94/99] Adapt to token fetching changes --- .../NetworkProtectionTunnelController.swift | 2 +- .../MacPacketTunnelProvider.swift | 25 ++++++++++++++----- ...ore+SubscriptionTokenKeychainStorage.swift | 3 +-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index 2fc0add68a..c7ad5261f3 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -753,7 +753,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr #if SUBSCRIPTION if let accessToken = accountManager.accessToken { os_log(.error, log: .networkProtection, "🟢 TunnelController found token: %{public}d", accessToken) - return NetworkProtectionKeychainTokenStore().makeToken(from: accessToken) as NSString? + return accessToken as NSString? } #endif os_log(.error, log: .networkProtection, "🔴 TunnelController found no token :(") diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 64cd5cca5a..114e227733 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -284,22 +284,35 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { let tunnelHealthStore = NetworkProtectionTunnelHealthStore(notificationCenter: notificationCenter) let controllerErrorStore = NetworkProtectionTunnelErrorStore(notificationCenter: notificationCenter) let debugEvents = Self.networkProtectionDebugEvents(controllerErrorStore: controllerErrorStore) - let tokenStore = NetworkProtectionKeychainTokenStore(keychainType: Bundle.keychainType, - serviceName: Self.tokenServiceName, - errorEvents: debugEvents, - isSubscriptionEnabled: isSubscriptionEnabled, - accessTokenProvider: { nil }) let notificationsPresenter = NetworkProtectionNotificationsPresenterFactory().make(settings: settings, defaults: defaults) #if SUBSCRIPTION + let accountManagerTokenStore = NetworkProtectionKeychainTokenStore(keychainType: Bundle.keychainType, + serviceName: Self.tokenServiceName, + errorEvents: debugEvents, + isSubscriptionEnabled: isSubscriptionEnabled, + accessTokenProvider: { nil } + ) let accountManager = AccountManager( - accessTokenStorage: tokenStore, + accessTokenStorage: accountManagerTokenStore, entitlementsCache: UserDefaultsCache<[Entitlement]>(key: UserDefaultsCacheKey.subscriptionEntitlements) ) + let tokenStore = NetworkProtectionKeychainTokenStore(keychainType: Bundle.keychainType, + serviceName: Self.tokenServiceName, + errorEvents: debugEvents, + isSubscriptionEnabled: isSubscriptionEnabled, + accessTokenProvider: { accountManager.accessToken } + ) SubscriptionPurchaseEnvironment.currentServiceEnvironment = settings.selectedEnvironment == .production ? .production : .staging let entitlementsCheck = { await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) } #else + let tokenStore = NetworkProtectionKeychainTokenStore(keychainType: Bundle.keychainType, + serviceName: Self.tokenServiceName, + errorEvents: debugEvents, + isSubscriptionEnabled: isSubscriptionEnabled, + accessTokenProvider: { nil } + ) let entitlementsCheck: (() async -> Result)? = nil #endif diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift index dc0880743e..2987ab2ff9 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift @@ -25,8 +25,7 @@ import Common extension NetworkProtectionKeychainTokenStore: SubscriptionTokenStorage { public func store(accessToken: String) throws { - let tokenToStore = makeToken(from: accessToken) - try store(tokenToStore) + try store(accessToken) } public func getAccessToken() throws -> String? { From bedbfdf08fd3aeff9ac1ee1ba7bcd305f926e240 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 19 Mar 2024 17:46:38 +0100 Subject: [PATCH 95/99] Fixes after merging main --- .../NetworkProtectionTunnelController.swift | 6 ++++- .../MacPacketTunnelProvider.swift | 23 ++++--------------- DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift | 5 ++++ ...tion+VPNAgentConvenienceInitializers.swift | 11 ++------- DuckDuckGoVPN/NetworkProtectionBouncer.swift | 4 +++- 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index c7ad5261f3..8ecf83100d 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -753,12 +753,16 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr #if SUBSCRIPTION if let accessToken = accountManager.accessToken { os_log(.error, log: .networkProtection, "🟢 TunnelController found token: %{public}d", accessToken) - return accessToken as NSString? + return Self.adaptAccessTokenForVPN(accessToken) as NSString? } #endif os_log(.error, log: .networkProtection, "🔴 TunnelController found no token :(") return try tokenStore.fetchToken() as NSString? } + + private static func adaptAccessTokenForVPN(_ token: String) -> String { + "ddg:\(token)" + } } #endif diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 114e227733..acb06735b3 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -269,11 +269,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { // MARK: - Initialization @objc public init() { -#if SUBSCRIPTION - let isSubscriptionEnabled = true -#else let isSubscriptionEnabled = false -#endif #if NETP_SYSTEM_EXTENSION let defaults = UserDefaults.standard @@ -285,34 +281,23 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { let controllerErrorStore = NetworkProtectionTunnelErrorStore(notificationCenter: notificationCenter) let debugEvents = Self.networkProtectionDebugEvents(controllerErrorStore: controllerErrorStore) let notificationsPresenter = NetworkProtectionNotificationsPresenterFactory().make(settings: settings, defaults: defaults) -#if SUBSCRIPTION - let accountManagerTokenStore = NetworkProtectionKeychainTokenStore(keychainType: Bundle.keychainType, + let tokenStore = NetworkProtectionKeychainTokenStore(keychainType: Bundle.keychainType, serviceName: Self.tokenServiceName, errorEvents: debugEvents, isSubscriptionEnabled: isSubscriptionEnabled, accessTokenProvider: { nil } ) +#if SUBSCRIPTION + let accountManager = AccountManager( - accessTokenStorage: accountManagerTokenStore, + accessTokenStorage: tokenStore, entitlementsCache: UserDefaultsCache<[Entitlement]>(key: UserDefaultsCacheKey.subscriptionEntitlements) ) - let tokenStore = NetworkProtectionKeychainTokenStore(keychainType: Bundle.keychainType, - serviceName: Self.tokenServiceName, - errorEvents: debugEvents, - isSubscriptionEnabled: isSubscriptionEnabled, - accessTokenProvider: { accountManager.accessToken } - ) SubscriptionPurchaseEnvironment.currentServiceEnvironment = settings.selectedEnvironment == .production ? .production : .staging let entitlementsCheck = { await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) } #else - let tokenStore = NetworkProtectionKeychainTokenStore(keychainType: Bundle.keychainType, - serviceName: Self.tokenServiceName, - errorEvents: debugEvents, - isSubscriptionEnabled: isSubscriptionEnabled, - accessTokenProvider: { nil } - ) let entitlementsCheck: (() async -> Result)? = nil #endif diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index f02df24a39..c44f70bbd7 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -266,6 +266,9 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { @MainActor func applicationDidFinishLaunching(_ aNotification: Notification) { APIRequest.Headers.setUserAgent(UserAgent.duckDuckGoUserAgent()) +#if SUBSCRIPTION + SubscriptionPurchaseEnvironment.currentServiceEnvironment = tunnelSettings.selectedEnvironment == .production ? .production : .staging +#endif os_log("DuckDuckGoVPN started", log: .networkProtectionLoginItemLog, type: .info) @@ -319,6 +322,8 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { let launchedOnStartup = launchInformation.wasLaunchedByStartup launchInformation.update() + setUpSubscriptionMonitoring() + if launchedOnStartup { Task { let isConnected = await tunnelController.isConnected diff --git a/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift b/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift index cc9105c40d..b61f1779c1 100644 --- a/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift +++ b/DuckDuckGoVPN/NetworkProtection+VPNAgentConvenienceInitializers.swift @@ -25,16 +25,9 @@ import Subscription extension NetworkProtectionKeychainTokenStore { convenience init() { -#if SUBSCRIPTION - let accessTokenProvider: () -> String? = { AccountManager().accessToken } - let isSubscriptionEnabled = true -#else - let accessTokenProvider: () -> String? = { return nil } - let isSubscriptionEnabled = false -#endif self.init(keychainType: .default, errorEvents: .networkProtectionAppDebugEvents, - isSubscriptionEnabled: isSubscriptionEnabled, - accessTokenProvider: accessTokenProvider) + isSubscriptionEnabled: false, + accessTokenProvider: { return nil }) } } diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index 884cb42224..e34540d016 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -38,7 +38,9 @@ final class NetworkProtectionBouncer { let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) let result = await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) switch result { - case .success(true), .failure: + case .success(true): + return + case .failure: break case .success(false): os_log(.error, log: .networkProtection, "🔴 Stopping: DuckDuckGo VPN not authorized. Missing entitlement.") From f72d958faca2141d6836a45861bfa165cf49c963 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Tue, 19 Mar 2024 10:44:29 -0700 Subject: [PATCH 96/99] Print out the type of the delegate to see why the cast failed. --- DuckDuckGo/Common/Extensions/NSApplicationExtension.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/Common/Extensions/NSApplicationExtension.swift b/DuckDuckGo/Common/Extensions/NSApplicationExtension.swift index ec8c1cb750..7b20e15bf5 100644 --- a/DuckDuckGo/Common/Extensions/NSApplicationExtension.swift +++ b/DuckDuckGo/Common/Extensions/NSApplicationExtension.swift @@ -76,7 +76,11 @@ extension NSApplication { } var delegateTyped: AppDelegate { - return delegate as! AppDelegate // swiftlint:disable:this force_cast + if let delegate = delegate as? AppDelegate { + return delegate + } else { + fatalError("Failed to cast delegate: \(type(of: delegate))") + } } #endif From a6d68d35ced206f73fea19a7587c9a21bdb3a8d8 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Tue, 19 Mar 2024 10:53:47 -0700 Subject: [PATCH 97/99] Try another change to get CI working. --- DuckDuckGo/Common/Extensions/NSApplicationExtension.swift | 6 +----- .../Subscription/SubscriptionFeatureAvailability.swift | 3 ++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/DuckDuckGo/Common/Extensions/NSApplicationExtension.swift b/DuckDuckGo/Common/Extensions/NSApplicationExtension.swift index 7b20e15bf5..ec8c1cb750 100644 --- a/DuckDuckGo/Common/Extensions/NSApplicationExtension.swift +++ b/DuckDuckGo/Common/Extensions/NSApplicationExtension.swift @@ -76,11 +76,7 @@ extension NSApplication { } var delegateTyped: AppDelegate { - if let delegate = delegate as? AppDelegate { - return delegate - } else { - fatalError("Failed to cast delegate: \(type(of: delegate))") - } + return delegate as! AppDelegate // swiftlint:disable:this force_cast } #endif diff --git a/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift b/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift index 9e0b2780d5..05a6f1c770 100644 --- a/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift +++ b/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift @@ -48,7 +48,8 @@ struct DefaultSubscriptionFeatureAvailability: SubscriptionFeatureAvailability { } private var isInternalUser: Bool { - NSApp.delegateTyped.internalUserDecider.isInternalUser + return false + // NSApp.delegateTyped.internalUserDecider.isInternalUser } private var isDBPActivated: Bool { From 3c0dfe1a61d16f8c0bf9cb6e6dca0f2c952337e5 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:04:00 +0100 Subject: [PATCH 98/99] Point to BSK release --- DuckDuckGo.xcodeproj/project.pbxproj | 4 ++-- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 64eb8c448c..1596da5917 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -14090,8 +14090,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { - branch = "graeme/expired-entitlements-stuff"; - kind = branch; + kind = exactVersion; + version = 126.2.0; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 83e66567aa..7d241ed988 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -33,7 +33,7 @@ "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { "branch" : "graeme/expired-entitlements-stuff", - "revision" : "ffd1b747847af4bd3156b2a0bff71513b83d1d22" + "revision" : "925d0dd50e47f38c7fe922622002e8961569bc32" } }, { From 81ddbb8afdc37508742238eebb14240ecaed257d Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:43:29 +0100 Subject: [PATCH 99/99] Create internalUserDecider instance privately --- .../SubscriptionFeatureAvailability.swift | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift b/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift index 05a6f1c770..9090ffad02 100644 --- a/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift +++ b/DuckDuckGo/Subscription/SubscriptionFeatureAvailability.swift @@ -24,6 +24,7 @@ import Subscription #if NETWORK_PROTECTION import NetworkProtection +import BrowserServicesKit #endif protocol SubscriptionFeatureAvailability { @@ -48,8 +49,7 @@ struct DefaultSubscriptionFeatureAvailability: SubscriptionFeatureAvailability { } private var isInternalUser: Bool { - return false - // NSApp.delegateTyped.internalUserDecider.isInternalUser + Self.internalUserDecider.isInternalUser } private var isDBPActivated: Bool { @@ -59,4 +59,18 @@ struct DefaultSubscriptionFeatureAvailability: SubscriptionFeatureAvailability { return false #endif } + + private static var internalUserDecider: InternalUserDecider = { + let keyStore = EncryptionKeyStore() + let fileStore: FileStore + do { + let encryptionKey = NSApplication.runType.requiresEnvironment ? try keyStore.readKey() : nil + fileStore = EncryptedFileStore(encryptionKey: encryptionKey) + } catch { + fileStore = EncryptedFileStore() + } + + let internalUserDeciderStore = InternalUserDeciderStore(fileStore: fileStore) + return DefaultInternalUserDecider(store: internalUserDeciderStore) + }() }