Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit c9b0316

Browse files
authored
Add NetP subscription integration (#1710)
Task/Issue URL: https://app.asana.com/0/0/1205645389501251/f Tech Design URL: CC: Description: This PR integrates NetP with the subscription library.
1 parent 6925a02 commit c9b0316

File tree

22 files changed

+130
-29
lines changed

22 files changed

+130
-29
lines changed

DuckDuckGo.xcodeproj/project.pbxproj

+7-1
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,8 @@
10901090
4B2D067C2A13340900DE1F49 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4BEC322A11B509001D9AC5 /* Logging.swift */; };
10911091
4B2D067F2A1334D700DE1F49 /* NetworkProtectionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 4B2D067E2A1334D700DE1F49 /* NetworkProtectionUI */; };
10921092
4B2E7D6326FF9D6500D2DB17 /* PrintingUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E7D6226FF9D6500D2DB17 /* PrintingUserScript.swift */; };
1093+
4B2F565C2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2F565B2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift */; };
1094+
4B2F565D2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2F565B2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift */; };
10931095
4B379C1527BD91E3008A968E /* QuartzIdleStateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B379C1427BD91E3008A968E /* QuartzIdleStateProvider.swift */; };
10941096
4B379C1E27BDB7FF008A968E /* DeviceAuthenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B379C1D27BDB7FF008A968E /* DeviceAuthenticator.swift */; };
10951097
4B379C2227BDBA29008A968E /* LocalAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B379C2127BDBA29008A968E /* LocalAuthenticationService.swift */; };
@@ -3393,6 +3395,7 @@
33933395
4B2D06642A132F3A00DE1F49 /* NetworkProtectionAppExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NetworkProtectionAppExtension.entitlements; sourceTree = "<group>"; };
33943396
4B2D06692A13318400DE1F49 /* DuckDuckGo VPN App Store.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DuckDuckGo VPN App Store.app"; sourceTree = BUILT_PRODUCTS_DIR; };
33953397
4B2E7D6226FF9D6500D2DB17 /* PrintingUserScript.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrintingUserScript.swift; sourceTree = "<group>"; };
3398+
4B2F565B2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionSubscriptionEventHandler.swift; sourceTree = "<group>"; };
33963399
4B379C1427BD91E3008A968E /* QuartzIdleStateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuartzIdleStateProvider.swift; sourceTree = "<group>"; };
33973400
4B379C1D27BDB7FF008A968E /* DeviceAuthenticator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceAuthenticator.swift; sourceTree = "<group>"; };
33983401
4B379C2127BDBA29008A968E /* LocalAuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationService.swift; sourceTree = "<group>"; };
@@ -5213,6 +5216,7 @@
52135216
children = (
52145217
4BCF15D52ABB83D70083F6DF /* NetworkProtectionRemoteMessaging */,
52155218
7BA7CC4D2AD11F6F0042E5CE /* NetworkProtectionIPCTunnelController.swift */,
5219+
4B2F565B2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift */,
52165220
);
52175221
path = DeveloperIDTarget;
52185222
sourceTree = "<group>";
@@ -10830,6 +10834,7 @@
1083010834
4B957B052AC7AE700062CA31 /* FindInPageModel.swift in Sources */,
1083110835
4B957B062AC7AE700062CA31 /* PseudoFolder.swift in Sources */,
1083210836
4B957B072AC7AE700062CA31 /* Visit.swift in Sources */,
10837+
4B2F565D2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift in Sources */,
1083310838
4B957B082AC7AE700062CA31 /* PixelDataStore.swift in Sources */,
1083410839
4B957B092AC7AE700062CA31 /* WaitlistStorage.swift in Sources */,
1083510840
4B957B0A2AC7AE700062CA31 /* Pixel.swift in Sources */,
@@ -11243,6 +11248,7 @@
1124311248
1DFAB51D2A8982A600A0F7F6 /* SetExtension.swift in Sources */,
1124411249
315AA07028CA5CC800200030 /* YoutubePlayerNavigationHandler.swift in Sources */,
1124511250
37AFCE9227DB8CAD00471A10 /* PreferencesAboutView.swift in Sources */,
11251+
4B2F565C2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift in Sources */,
1124611252
9826B0A02747DF3D0092F683 /* ContentBlocking.swift in Sources */,
1124711253
4B379C2227BDBA29008A968E /* LocalAuthenticationService.swift in Sources */,
1124811254
37CEFCA92A6737A2001EF741 /* CredentialsCleanupErrorHandling.swift in Sources */,
@@ -13044,7 +13050,7 @@
1304413050
repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit";
1304513051
requirement = {
1304613052
kind = exactVersion;
13047-
version = 99.0.2;
13053+
version = 100.0.0;
1304813054
};
1304913055
};
1305013056
AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = {

DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
"kind" : "remoteSourceControl",
1515
"location" : "https://github.com/duckduckgo/BrowserServicesKit",
1616
"state" : {
17-
"revision" : "18043cbc24e5bb79aa1f44e01a367e0bccd2fa6e",
18-
"version" : "99.0.2"
17+
"revision" : "c3a482a4ca22d706207d08a68db8f23f0c262040",
18+
"version" : "100.0.0"
1919
}
2020
},
2121
{

DuckDuckGo/Application/AppDelegate.swift

+8
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel
7878
private var emailCancellables = Set<AnyCancellable>()
7979
let bookmarksManager = LocalBookmarkManager.shared
8080

81+
#if NETWORK_PROTECTION && SUBSCRIPTION
82+
private let networkProtectionSubscriptionEventHandler = NetworkProtectionSubscriptionEventHandler()
83+
#endif
84+
8185
#if DBP && SUBSCRIPTION
8286
private let dataBrokerProtectionSubscriptionEventHandler = DataBrokerProtectionSubscriptionEventHandler()
8387
#endif
@@ -247,6 +251,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel
247251

248252
UserDefaultsWrapper<Any>.clearRemovedKeys()
249253

254+
#if NETWORK_PROTECTION && SUBSCRIPTION
255+
networkProtectionSubscriptionEventHandler.registerForSubscriptionAccountManagerEvents()
256+
#endif
257+
250258
#if NETWORK_PROTECTION
251259
NetworkProtectionAppEvents().applicationDidFinishLaunching()
252260
UNUserNotificationCenter.current().delegate = self

DuckDuckGo/Bookmarks/Services/BookmarkStoreMock.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public final class BookmarkStoreMock: BookmarkStore {
122122
}
123123

124124
var moveObjectUUIDCalled = false
125-
func move(objectUUIDs: [String], toIndex: Int?, withinParentFolder: DuckDuckGo_Privacy_Browser.ParentFolderType, completion: @escaping (Error?) -> Void) {
125+
func move(objectUUIDs: [String], toIndex: Int?, withinParentFolder: ParentFolderType, completion: @escaping (Error?) -> Void) {
126126
moveObjectUUIDCalled = true
127127
}
128128

DuckDuckGo/MainWindow/MainViewController.swift

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import Carbon.HIToolbox
2121
import Combine
2222
import Common
2323

24+
#if NETWORK_PROTECTION
25+
import NetworkProtection
26+
#endif
27+
2428
final class MainViewController: NSViewController {
2529

2630
private let tabBarContainerView = NSView()

DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift

-12
Original file line numberDiff line numberDiff line change
@@ -356,18 +356,6 @@ final class MoreOptionsMenu: NSMenu {
356356

357357
#endif // DBP
358358

359-
#if SUBSCRIPTION
360-
let item1 = NSMenuItem(title: "Placeholder A", action: #selector(openPreferences(_:)), keyEquivalent: "")
361-
.targetting(self)
362-
.withImage(.image(for: .vpnIcon))
363-
items.append(item1)
364-
365-
let item2 = NSMenuItem(title: "Placeholder B", action: #selector(openPreferences(_:)), keyEquivalent: "")
366-
.targetting(self)
367-
.withImage(.image(for: .vpnIcon))
368-
items.append(item2)
369-
#endif
370-
371359
return items
372360
}
373361

DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift

+11
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import NetworkProtectionUI
2828
#endif
2929

3030
#if SUBSCRIPTION
31+
import Subscription
3132
import SubscriptionUI
3233
#endif
3334

@@ -331,6 +332,16 @@ final class NavigationBarViewController: NSViewController {
331332
return
332333
}
333334

335+
#if SUBSCRIPTION
336+
let accountManager = AccountManager()
337+
let networkProtectionTokenStorage = NetworkProtectionKeychainTokenStore()
338+
339+
if accountManager.accessToken != nil && (try? networkProtectionTokenStorage.fetchToken()) == nil {
340+
print("[NetP Subscription] Got access token but not auth token, meaning token exchange failed")
341+
return
342+
}
343+
#endif
344+
334345
// 1. If the user is on the waitlist but hasn't been invited or accepted terms and conditions, show the waitlist screen.
335346
// 2. If the user has no waitlist state but has an auth token, show the NetP popover.
336347
// 3. If the user has no state of any kind, show the waitlist screen.

DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/EventMapping+NetworkProtectionError.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ extension EventMapping where Event == NetworkProtectionError {
7070
.wireGuardDnsResolution,
7171
.wireGuardSetNetworkSettings,
7272
.startWireGuardBackend,
73-
// Needs Privacy triage for macOS Geoswitching pixels
73+
.failedToRetrieveAuthToken,
7474
.failedToFetchLocationList,
7575
.failedToParseLocationListResponse:
7676
domainEvent = .networkProtectionUnhandledError(function: #function, line: #line, error: event)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// NetworkProtectionSubscriptionEventHandler.swift
3+
//
4+
// Copyright © 2023 DuckDuckGo. All rights reserved.
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
19+
#if NETWORK_PROTECTION && SUBSCRIPTION
20+
21+
import Foundation
22+
import Subscription
23+
import NetworkProtection
24+
25+
final class NetworkProtectionSubscriptionEventHandler {
26+
27+
private let accountManager: AccountManaging
28+
private let networkProtectionRedemptionCoordinator: NetworkProtectionCodeRedeeming
29+
private let networkProtectionTokenStorage: NetworkProtectionTokenStore
30+
private let networkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling
31+
32+
init(accountManager: AccountManaging = AccountManager(),
33+
networkProtectionRedemptionCoordinator: NetworkProtectionCodeRedeeming = NetworkProtectionCodeRedemptionCoordinator(),
34+
networkProtectionTokenStorage: NetworkProtectionTokenStore = NetworkProtectionKeychainTokenStore(),
35+
networkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling = NetworkProtectionFeatureDisabler()) {
36+
self.accountManager = accountManager
37+
self.networkProtectionRedemptionCoordinator = networkProtectionRedemptionCoordinator
38+
self.networkProtectionTokenStorage = networkProtectionTokenStorage
39+
self.networkProtectionFeatureDisabler = networkProtectionFeatureDisabler
40+
}
41+
42+
func registerForSubscriptionAccountManagerEvents() {
43+
NotificationCenter.default.addObserver(self, selector: #selector(handleAccountDidSignIn), name: .accountDidSignIn, object: nil)
44+
NotificationCenter.default.addObserver(self, selector: #selector(handleAccountDidSignOut), name: .accountDidSignOut, object: nil)
45+
}
46+
47+
@objc private func handleAccountDidSignIn() {
48+
guard let token = accountManager.accessToken else {
49+
assertionFailure("[NetP Subscription] AccountManager signed in but token could not be retrieved")
50+
return
51+
}
52+
53+
Task {
54+
do {
55+
try await networkProtectionRedemptionCoordinator.exchange(accessToken: token)
56+
print("[NetP Subscription] Exchanged access token for auth token successfully")
57+
} catch {
58+
print("[NetP Subscription] Failed to exchange access token for auth token: \(error)")
59+
}
60+
}
61+
}
62+
63+
@objc private func handleAccountDidSignOut() {
64+
print("[NetP Subscription] Deleted NetP auth token after signing out from Privacy Pro")
65+
66+
Task {
67+
await networkProtectionFeatureDisabler.disable(keepAuthToken: false, uninstallSystemExtension: false)
68+
}
69+
}
70+
71+
}
72+
73+
#endif

DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
116116
domainEvent = .networkProtectionNoAuthTokenFoundError
117117
case .unhandledError(function: let function, line: let line, error: let error):
118118
domainEvent = .networkProtectionUnhandledError(function: function, line: line, error: error)
119-
case .failedToFetchLocationList,
119+
case .failedToRetrieveAuthToken,
120+
.failedToFetchLocationList,
120121
.failedToParseLocationListResponse:
121122
// Needs Privacy triage for macOS Geoswitching pixels
122123
return

DuckDuckGo/Preferences/View/PreferencesAboutView.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extension Preferences {
5252
Text(UserText.privacySimplified).font(.privacySimplified)
5353

5454
Text(UserText.versionLabel(version: model.appVersion.versionNumber, build: model.appVersion.buildNumber)).onTapGesture(count: 12) {
55-
#if NETWORK_PROTECTION
55+
#if NETWORK_PROTECTION && !SUBSCRIPTION
5656
model.displayNetPInvite()
5757
#endif
5858
}

LocalPackages/BuildToolPlugins/Plugins/InputFilesChecker/InputFilesChecker.swift

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ let nonSandboxedExtraInputFiles: Set<InputFile> = [
3232
.init("NetworkProtectionAppEvents.swift", .source),
3333
.init("NetworkProtectionIPCTunnelController.swift", .source),
3434
.init("NetworkProtectionNavBarPopoverManager.swift", .source),
35+
.init("NetworkProtectionSubscriptionEventHandler.swift", .source),
3536
.init("KeychainType+ClientDefault.swift", .source),
3637
.init("DBPHomeViewController.swift", .source),
3738
.init("DataBrokerProtectionManager.swift", .source),

LocalPackages/DataBrokerProtection/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ let package = Package(
2929
targets: ["DataBrokerProtection"])
3030
],
3131
dependencies: [
32-
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "99.0.2"),
32+
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"),
3333
.package(path: "../PixelKit"),
3434
.package(path: "../SwiftUIExtensions"),
3535
.package(path: "../XPCHelper")

LocalPackages/LoginItems/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ let package = Package(
1313
),
1414
],
1515
dependencies: [
16-
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "99.0.2"),
16+
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"),
1717
],
1818
targets: [
1919
.target(

LocalPackages/NetworkProtectionMac/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ let package = Package(
3030
.library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"])
3131
],
3232
dependencies: [
33-
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "99.0.2"),
33+
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"),
3434
.package(path: "../XPCHelper"),
3535
.package(path: "../SwiftUIExtensions")
3636
],

LocalPackages/PixelKit/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ let package = Package(
2020
)
2121
],
2222
dependencies: [
23-
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "99.0.2"),
23+
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"),
2424
],
2525
targets: [
2626
.target(

LocalPackages/Subscription/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ let package = Package(
1212
targets: ["Subscription"]),
1313
],
1414
dependencies: [
15-
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "99.0.2"),
15+
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"),
1616
],
1717
targets: [
1818
.target(

LocalPackages/SwiftUIExtensions/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ let package = Package(
1313
),
1414
],
1515
dependencies: [
16-
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "99.0.2"),
16+
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"),
1717
],
1818
targets: [
1919
.target(

LocalPackages/SyncUI/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ let package = Package(
1313
],
1414
dependencies: [
1515
.package(path: "../SwiftUIExtensions"),
16-
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "99.0.2"),
16+
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"),
1717
],
1818
targets: [
1919
.target(

LocalPackages/SystemExtensionManager/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ let package = Package(
1616
),
1717
],
1818
dependencies: [
19-
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "99.0.2"),
19+
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"),
2020
],
2121
targets: [
2222
// Targets are the basic building blocks of a package, defining a module or a test suite.

LocalPackages/XPCHelper/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ let package = Package(
3030
.library(name: "XPCHelper", targets: ["XPCHelper"]),
3131
],
3232
dependencies: [
33-
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "99.0.2"),
33+
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "100.0.0"),
3434
],
3535
targets: [
3636
// Targets are the basic building blocks of a package. A target can define a module or a test suite.

UnitTests/Waitlist/Mocks/MockNetworkProtectionCodeRedeemer.swift

+10-1
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ final class MockNetworkProtectionCodeRedeemer: NetworkProtectionCodeRedeeming {
2727
case error
2828
}
2929

30-
var redeemedCode: String?
3130
var throwError: Bool = false
3231

32+
var redeemedCode: String?
3333
func redeem(_ code: String) async throws {
3434
if throwError {
3535
throw MockNetworkProtectionCodeRedeemerError.error
@@ -38,6 +38,15 @@ final class MockNetworkProtectionCodeRedeemer: NetworkProtectionCodeRedeeming {
3838
}
3939
}
4040

41+
var redeemedAccessToken: String?
42+
func exchange(accessToken: String) async throws {
43+
if throwError {
44+
throw MockNetworkProtectionCodeRedeemerError.error
45+
} else {
46+
redeemedAccessToken = accessToken
47+
}
48+
}
49+
4150
}
4251

4352
#endif

0 commit comments

Comments
 (0)