Skip to content

Commit

Permalink
Update to subscription cookie (#3512)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1108686900785972/1208264562025859/f

**Description**:
Initial PR -> #3488
Update to how the subscription cookie operates:
- constraint the cookie to `subscriptions.duckduckgo.com`
- on sign out do not fully remove the cookie - just clear the value
- gate the feature behind the
`setAccessTokenCookieForSubscriptionDomains` privacy config feature flag
  • Loading branch information
miasma13 authored Nov 1, 2024
1 parent c5aab0c commit cc7929e
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 25 deletions.
8 changes: 4 additions & 4 deletions Core/PixelEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -710,8 +710,8 @@ extension Pixel {
case privacyProKeychainAccessError
case privacyProSubscriptionCookieMissingTokenOnSignIn
case privacyProSubscriptionCookieMissingCookieOnSignOut
case privacyProSubscriptionCookieRefreshedWithUpdate
case privacyProSubscriptionCookieRefreshedWithDelete
case privacyProSubscriptionCookieRefreshedWithAccessToken
case privacyProSubscriptionCookieRefreshedWithEmptyValue
case privacyProSubscriptionCookieFailedToSetSubscriptionCookie

// MARK: Pixel Experiment
Expand Down Expand Up @@ -1527,8 +1527,8 @@ extension Pixel.Event {
case .privacyProKeychainAccessError: return "m_privacy-pro_keychain_access_error"
case .privacyProSubscriptionCookieMissingTokenOnSignIn: return "m_privacy-pro_subscription-cookie-missing_token_on_sign_in"
case .privacyProSubscriptionCookieMissingCookieOnSignOut: return "m_privacy-pro_subscription-cookie-missing_cookie_on_sign_out"
case .privacyProSubscriptionCookieRefreshedWithUpdate: return "m_privacy-pro_subscription-cookie-refreshed_with_update"
case .privacyProSubscriptionCookieRefreshedWithDelete: return "m_privacy-pro_subscription-cookie-refreshed_with_delete"
case .privacyProSubscriptionCookieRefreshedWithAccessToken: return "m_privacy-pro_subscription-cookie-refreshed_with_access_token"
case .privacyProSubscriptionCookieRefreshedWithEmptyValue: return "m_privacy-pro_subscription-cookie-refreshed_with_empty_value"
case .privacyProSubscriptionCookieFailedToSetSubscriptionCookie: return "m_privacy-pro_subscription-cookie-failed_to_set_subscription_cookie"

// MARK: Pixel Experiment
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11010,7 +11010,7 @@
repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 201.0.0;
version = "201.0.0-1";
};
};
9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/DuckDuckGo/BrowserServicesKit",
"state" : {
"revision" : "e5946eee6af859690cc1cc5e51daef3c8368981b",
"version" : "201.0.0"
"revision" : "9506581ae99273681073f9993fc6d881d3edaa7f",
"version" : "201.0.0-1"
}
},
{
Expand Down
56 changes: 44 additions & 12 deletions DuckDuckGo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import os.log

private(set) var subscriptionFeatureAvailability: SubscriptionFeatureAvailability!
private var subscriptionCookieManager: SubscriptionCookieManaging!
private var subscriptionCookieManagerFeatureFlagCancellable: AnyCancellable?
var privacyProDataReporter: PrivacyProDataReporting!

// MARK: - Feature specific app event handlers
Expand Down Expand Up @@ -123,7 +124,7 @@ import os.log
}
}

// swiftlint:disable:next function_body_length cyclomatic_complexity
// swiftlint:disable:next function_body_length
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

#if targetEnvironment(simulator)
Expand Down Expand Up @@ -313,17 +314,8 @@ import os.log
subscriptionFeatureAvailability = DefaultSubscriptionFeatureAvailability(
privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager,
purchasePlatform: .appStore)

subscriptionCookieManager = SubscriptionCookieManager(subscriptionManager: AppDependencyProvider.shared.subscriptionManager,
currentCookieStore: { [weak self] in
guard self?.mainViewController?.tabManager.model.hasActiveTabs ?? false else {
// We shouldn't interact with WebKit's cookie store unless we have a WebView,
// eventually the subscription cookie will be refreshed on opening the first tab
return nil
}

return WKWebsiteDataStore.current().httpCookieStore
}, eventMapping: SubscriptionCookieManageEventPixelMapping())

subscriptionCookieManager = makeSubscriptionCookieManager()

homePageConfiguration = HomePageConfiguration(variantManager: AppDependencyProvider.shared.variantManager,
remoteMessagingClient: remoteMessagingClient,
Expand Down Expand Up @@ -416,6 +408,46 @@ import os.log
return true
}

private func makeSubscriptionCookieManager() -> SubscriptionCookieManaging {
let subscriptionCookieManager = SubscriptionCookieManager(subscriptionManager: AppDependencyProvider.shared.subscriptionManager,
currentCookieStore: { [weak self] in
guard self?.mainViewController?.tabManager.model.hasActiveTabs ?? false else {
// We shouldn't interact with WebKit's cookie store unless we have a WebView,
// eventually the subscription cookie will be refreshed on opening the first tab
return nil
}

return WKWebsiteDataStore.current().httpCookieStore
}, eventMapping: SubscriptionCookieManageEventPixelMapping())


let privacyConfigurationManager = ContentBlocking.shared.privacyConfigurationManager

// Enable subscriptionCookieManager if feature flag is present
if privacyConfigurationManager.privacyConfig.isSubfeatureEnabled(PrivacyProSubfeature.setAccessTokenCookieForSubscriptionDomains) {
subscriptionCookieManager.enableSettingSubscriptionCookie()
}

// Keep track of feature flag changes
subscriptionCookieManagerFeatureFlagCancellable = privacyConfigurationManager.updatesPublisher
.sink { [weak self, weak privacyConfigurationManager] in
guard let self, let privacyConfigurationManager else { return }

let isEnabled = privacyConfigurationManager.privacyConfig.isSubfeatureEnabled(PrivacyProSubfeature.setAccessTokenCookieForSubscriptionDomains)

Task { [weak self] in
if isEnabled {
self?.subscriptionCookieManager.enableSettingSubscriptionCookie()
await self?.subscriptionCookieManager.refreshSubscriptionCookie()
} else {
await self?.subscriptionCookieManager.disableSettingSubscriptionCookie()
}
}
}

return subscriptionCookieManager
}

private func makeHistoryManager() -> HistoryManaging {

let provider = AppDependencyProvider.shared
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ public final class SubscriptionCookieManageEventPixelMapping: EventMapping<Subsc
switch event {
case .errorHandlingAccountDidSignInTokenIsMissing:
return .privacyProSubscriptionCookieMissingTokenOnSignIn
case .errorHandlingAccountDidSignOutCookieIsMissing:
return .privacyProSubscriptionCookieMissingCookieOnSignOut
case .subscriptionCookieRefreshedWithUpdate:
return .privacyProSubscriptionCookieRefreshedWithUpdate
case .subscriptionCookieRefreshedWithDelete:
return .privacyProSubscriptionCookieRefreshedWithDelete
case .subscriptionCookieRefreshedWithAccessToken:
return .privacyProSubscriptionCookieRefreshedWithAccessToken
case .subscriptionCookieRefreshedWithEmptyValue:
return .privacyProSubscriptionCookieRefreshedWithEmptyValue
case .failedToSetSubscriptionCookie:
return .privacyProSubscriptionCookieFailedToSetSubscriptionCookie
}
Expand Down

0 comments on commit cc7929e

Please sign in to comment.