-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Subscription oauth api v2 #3580
base: main
Are you sure you want to change the base?
Conversation
# Conflicts: # DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
# Conflicts: # DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
# Conflicts: # DuckDuckGo/UnifiedFeedbackForm/UnifiedFeedbackFormViewController.swift
# Conflicts: # DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
# Conflicts: # DuckDuckGo.xcodeproj/project.pbxproj # DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
# Conflicts: # DuckDuckGo.xcodeproj/project.pbxproj # DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
# Conflicts: # DuckDuckGo.xcodeproj/project.pbxproj # DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved # DuckDuckGo/Application/AppDelegate.swift # DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift # DuckDuckGo/Subscription/SubscriptionManager+StandardConfiguration.swift # DuckDuckGo/UnifiedFeedbackForm/UnifiedFeedbackFormViewController.swift # DuckDuckGo/UnifiedFeedbackForm/UnifiedFeedbackFormViewModel.swift # LocalPackages/SubscriptionUI/Sources/SubscriptionUI/DebugMenu/SubscriptionDebugMenu.swift # LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift # UnitTests/Freemium/DBP/Experiment/FreemiumDBPPixelExperimentManagingTests.swift # UnitTests/Freemium/DBP/FreemiumDBPFeatureTests.swift # UnitTests/Menus/MoreOptionsMenuTests.swift # UnitTests/Subscription/SubscriptionAppStoreRestorerTests.swift # UnitTests/Subscription/SubscriptionPagesUseSubscriptionFeatureForStripeTests.swift # UnitTests/Subscription/SubscriptionPagesUseSubscriptionFeatureTests.swift # UnitTests/UnifiedFeedbackForm/UnifiedFeedbackFormViewModelTests.swift
Which environment and purchase platform are you using? App store subscriptions are renewing every 5 minutes until a max of (can't remember) times, so finding the VPN disconnected seems correct, are the settings showing an expired subscription? |
I'm using my pre-existing account from stripe + staging. |
Then it's not right, I'm investigating |
...Sources/DataBrokerProtection/Authentication/DataBrokerProtectionAuthenticationManaging.swift
Outdated
Show resolved
Hide resolved
let features = await subscriptionManager.currentSubscriptionFeatures(forceRefresh: false) | ||
let vpnFeature = features.first { $0.entitlement == .networkProtection } | ||
let dbpFeature = features.first { $0.entitlement == .dataBrokerProtection } | ||
let itrFeature = features.first { $0.entitlement == .identityTheftRestoration } | ||
let itrgFeature = features.first { $0.entitlement == .identityTheftRestorationGlobal } | ||
|
||
Task { @MainActor in | ||
self.networkProtectionItem.isEnabled = vpnFeature?.enabled ?? false | ||
self.dataBrokerProtectionItem.isEnabled = dbpFeature?.enabled ?? false | ||
let hasIdentityTheftRestoration = itrFeature?.enabled ?? false | ||
let hasIdentityTheftRestorationGlobal = itrgFeature?.enabled ?? false | ||
self.identityTheftRestorationItem.isEnabled = hasIdentityTheftRestoration || hasIdentityTheftRestorationGlobal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can migrate the whole block to the new simpler entitlement check with subscriptionManager.isFeatureActive(...)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
subscriptionManager.isFeatureActive(...)
is a bit too heavy for checking all entitlements because it is fetching (local) auth token and subscription every time, this is the same but just faster. We have two places where we use this approach, the code duplication is not super pretty but it's difficult to parametrise.
DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift
Outdated
Show resolved
Hide resolved
DuckDuckGo/Subscription/DefaultSubscriptionManager+StandardConfiguration.swift
Outdated
Show resolved
Hide resolved
DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionPagesUseSubscriptionFeature.swift
Show resolved
Hide resolved
DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionPagesUseSubscriptionFeature.swift
Show resolved
Hide resolved
@@ -397,13 +385,14 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { | |||
#if NETP_SYSTEM_EXTENSION | |||
"\(Bundle.main.bundleIdentifier!).authToken" | |||
#else | |||
NetworkProtectionKeychainTokenStore.Defaults.tokenStoreService | |||
"com.duckduckgo.networkprotection.authToken" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding a constant here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I transformed tokenServiceName in a let so that's now a constant, there was no need to be a var calculated at runtime.
I didn't move the string somewhere else (like in the previous implementation) because is only used there.
@@ -436,16 +417,60 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { | |||
case .staging: | |||
subscriptionEnvironment.serviceEnvironment = .staging | |||
} | |||
subscriptionEnvironment.purchasePlatform = .stripe // we don't care about the purchasePlatform |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've no idea why we don't care about the purchase platform. Could we document what this means, maybe providing a link with reference or a clearer explanation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment added: The SysExt doesn't care about the purchase platform because the only operations executed here are about the Auth token. No purchase or platforms-related operations are performed.
serviceName: Self.tokenServiceName, | ||
keychainType: Bundle.keychainType) | ||
let authClient = DefaultOAuthClient(tokensStorage: tokenStorage, | ||
legacyTokenStorage: nil, // Note: The VPN SysExt will stop at the first transition from auth v1 to v2, is up to the user to re-enable it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain this to me in a bit more detail? It's not clear to me what the "transition" is... is it the first time they manually start the VPN?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've confirmed with Thomas that it is actually possible to exchange a token v1 multiple times so this comment is not relevant anymore, I've updated the code so the SysExt can now perform a full migration from auth v1 to v2 and never stop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still looking but added several comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing and PIR seems to work now. I've just left one minor comment on the code
@@ -52,6 +53,7 @@ struct DataBrokerProtectionAppEvents { | |||
// In this case, let's disable the agent and delete any left-over data because there's nothing for it to do | |||
if let profileQueriesCount = try? DataBrokerProtectionManager.shared.dataManager.profileQueriesCount(), | |||
profileQueriesCount > 0 { | |||
Logger.dataBrokerProtection.log("Found \(profileQueriesCount) profile queries in DB. Disabling agent.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this comment is wrong (confused by the comment above no longer being accurate)
If there are profile queries, we don't disable it, we want the agent to be running. We restart it rather than disable it (to help with the flakeyness of login items)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, modified with "Restarting agent"
# Conflicts: # DuckDuckGo.xcodeproj/project.pbxproj # DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved # DuckDuckGo/Common/Extensions/WKWebViewExtension.swift # LocalPackages/NewTabPage/Sources/NewTabPage/Configuration/NewTabPageConfigurationClient.swift # LocalPackages/NewTabPage/Sources/NewTabPage/Favorites/NewTabPageFavoritesClient.swift
# Conflicts: # DuckDuckGo.xcodeproj/project.pbxproj # DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved # DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift
# Conflicts: # DuckDuckGo.xcodeproj/project.pbxproj # DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
# Conflicts: # DuckDuckGo.xcodeproj/project.pbxproj # DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
Task/Issue URL: https://app.asana.com/0/1205842942115003/1207991044706236/f
Tech Design URL: https://app.asana.com/0/1205842942115003/1207991044706232/f
CC: @miasma13
iOS PR: duckduckgo/iOS#3480
BSK PR: duckduckgo/BrowserServicesKit#1033
Description:
This PR introduces the use of OAuth V2 authentication in Privacy Pro Subscription.
The code changes are comprehensive due to the paradigm changes between the old access token lifecycle and the new JWT lifecycle.
The Subscription UI and UX should be unchanged.
Steps to test this PR:
Test all Privacy Pro Subscription features and UX, more details here
Internal references:
Pull Request Review Checklist
Software Engineering Expectations
Technical Design Template
Pull Request Documentation