Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Source/Core/EdgeAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,9 @@ extension EdgeAPI {
])
}

// The CMP's section IDs are only used with the CMP's GPP string, never with one set in config.
var gppSid = config.gppSid

if let gpp = config.gpp {
components.queryItems?.append(
.init(name: "gpp", value: gpp)
Expand All @@ -269,9 +272,10 @@ extension EdgeAPI {
components.queryItems?.append(
.init(name: "gpp", value: globalGPP)
)
gppSid = gppSid ?? IABConsent.gppSid
}

if let gppSid = config.gppSid {
if let gppSid {
components.queryItems?.append(
.init(name: "gpp_sid", value: gppSid)
)
Expand Down
12 changes: 11 additions & 1 deletion Source/Misc/IABConsent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ enum IABConsent {
enum Keys {
static let IABTCF_TCString = "IABTCF_TCString"
static let IABTCF_gdprApplies = "IABTCF_gdprApplies"
static let IABGPP_HDR_GppString = "IABGPP_HDR_GppString"
static let IABGPP_GppSID = "IABGPP_GppSID"
/// Not an IAB key, read before `IABGPP_HDR_GppString` was. Kept as a fallback for apps that write it.
static let IABGPP_2_TCString = "IABGPP_2_TCString"
}

Expand All @@ -31,6 +34,13 @@ enum IABConsent {
}

static var gppTC: String? {
UserDefaults.standard.string(forKey: Keys.IABGPP_2_TCString)
UserDefaults.standard.string(forKey: Keys.IABGPP_HDR_GppString)
?? UserDefaults.standard.string(forKey: Keys.IABGPP_2_TCString)
}

/// The CMP stores section IDs separated by underscores ("2_7"); the Edge API takes them comma-separated ("2,7").
static var gppSid: String? {
UserDefaults.standard.string(forKey: Keys.IABGPP_GppSID)?
.replacingOccurrences(of: "_", with: ",")
}
}
4 changes: 3 additions & 1 deletion Source/Public/OptableConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public final class OptableConfig: NSObject, Sendable {
/**
GPP privacy string.

> If not set, SDK will try to fetch data from UserDefaults => `IABGPP_2_TCString`, as stated in [](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details)
> If not set, SDK will try to fetch data from UserDefaults => `IABGPP_HDR_GppString`, as stated in [](https://github.com/InteractiveAdvertisingBureau/Global-Privacy-Platform/blob/main/Core/CMP%20API%20Specification.md)
*/
@objc
public var gpp: String? {
Expand All @@ -159,6 +159,8 @@ public final class OptableConfig: NSObject, Sendable {

/**
A comma-separated list of up to two sections applicable in a given GPP privacy string. This value is required when gpp is present.

> If not set and `gpp` is read from UserDefaults, SDK will also read `IABGPP_GppSID` from UserDefaults, as stated in [](https://github.com/InteractiveAdvertisingBureau/Global-Privacy-Platform/blob/main/Core/CMP%20API%20Specification.md)
*/
@objc
public var gppSid: String? {
Expand Down
41 changes: 40 additions & 1 deletion Tests/Unit/EdgeAPITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class EdgeAPITests: XCTestCase {
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABTCF_gdprApplies)
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABTCF_TCString)
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_2_TCString)
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_HDR_GppString)
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_GppSID)

let config = OptableConfig(tenant: T.api.tenant.prebidtest, originSlug: T.api.slug.iosSDK)
let generatedURL = OptableSDK(config: config).api.buildEdgeAPIURL(endpoint: T.api.endpoint.identify)
Expand All @@ -100,7 +102,9 @@ class EdgeAPITests: XCTestCase {
func test_url_generation_privacy_regulations_global() throws {
UserDefaults.standard.set("0", forKey: IABConsent.Keys.IABTCF_gdprApplies)
UserDefaults.standard.set("globalGDPRConsent", forKey: IABConsent.Keys.IABTCF_TCString)
UserDefaults.standard.set("globalGPP", forKey: IABConsent.Keys.IABGPP_2_TCString)
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_2_TCString)
UserDefaults.standard.set("globalGPP", forKey: IABConsent.Keys.IABGPP_HDR_GppString)
UserDefaults.standard.set("2_7", forKey: IABConsent.Keys.IABGPP_GppSID)

let config = OptableConfig(tenant: T.api.tenant.prebidtest, originSlug: T.api.slug.iosSDK)
let generatedURL = OptableSDK(config: config).api.buildEdgeAPIURL(endpoint: T.api.endpoint.identify)
Expand All @@ -113,7 +117,40 @@ class EdgeAPITests: XCTestCase {
XCTAssertEqual(generatedURLComponents.queryItems!.first(where: { $0.name == "gdpr" })!.value, "0")
XCTAssertNotNil(generatedURLComponents.queryItems?.first(where: { $0.name == "gpp" }))
XCTAssertEqual(generatedURLComponents.queryItems!.first(where: { $0.name == "gpp" })!.value, "globalGPP")
XCTAssertNotNil(generatedURLComponents.queryItems?.first(where: { $0.name == "gpp_sid" }))
XCTAssertEqual(generatedURLComponents.queryItems!.first(where: { $0.name == "gpp_sid" })!.value, "2,7")
}

func test_url_generation_privacy_regulations_global_legacyGPPKey() throws {
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_HDR_GppString)
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_GppSID)
UserDefaults.standard.set("legacyGPP", forKey: IABConsent.Keys.IABGPP_2_TCString)

let config = OptableConfig(tenant: T.api.tenant.prebidtest, originSlug: T.api.slug.iosSDK)
let generatedURL = OptableSDK(config: config).api.buildEdgeAPIURL(endpoint: T.api.endpoint.identify)
let generatedURLComponents = URLComponents(url: generatedURL!, resolvingAgainstBaseURL: false)!

XCTAssertEqual(generatedURLComponents.queryItems?.first(where: { $0.name == "gpp" })?.value, "legacyGPP")
XCTAssertNil(generatedURLComponents.queryItems?.first(where: { $0.name == "gpp_sid" }))

UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_2_TCString)
}

func test_url_generation_privacy_regulations_explicitGPP_ignoresGlobalGPPSid() throws {
UserDefaults.standard.set("globalGPP", forKey: IABConsent.Keys.IABGPP_HDR_GppString)
UserDefaults.standard.set("2_7", forKey: IABConsent.Keys.IABGPP_GppSID)

let config = OptableConfig(tenant: T.api.tenant.prebidtest, originSlug: T.api.slug.iosSDK)
config.gpp = "gpp"

let generatedURL = OptableSDK(config: config).api.buildEdgeAPIURL(endpoint: T.api.endpoint.identify)
let generatedURLComponents = URLComponents(url: generatedURL!, resolvingAgainstBaseURL: false)!

XCTAssertEqual(generatedURLComponents.queryItems?.first(where: { $0.name == "gpp" })?.value, "gpp")
XCTAssertNil(generatedURLComponents.queryItems?.first(where: { $0.name == "gpp_sid" }))

UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_HDR_GppString)
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_GppSID)
}

/**
Expand All @@ -123,6 +160,8 @@ class EdgeAPITests: XCTestCase {
UserDefaults.standard.set("0", forKey: IABConsent.Keys.IABTCF_gdprApplies)
UserDefaults.standard.set("globalGDPRConsent", forKey: IABConsent.Keys.IABTCF_TCString)
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_2_TCString)
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_HDR_GppString)
UserDefaults.standard.set(nil, forKey: IABConsent.Keys.IABGPP_GppSID)

let config = OptableConfig(tenant: T.api.tenant.prebidtest, originSlug: T.api.slug.iosSDK)
config.reg = "reg"
Expand Down
Loading