Skip to content

Commit ef5f299

Browse files
sunnywucursoragent
andauthored
Remove SF1 (precise geolocation) consent validation for EUID (#2338)
* Remove SF1 (precise geolocation) consent validation for EUID The Special Feature 1 validation was a legacy requirement that is no longer needed. This change allows EUID token generation for users who have the required TCF purpose consents but don't have SF1 (precise geolocation) enabled. Resolves: UID2-6532 Co-authored-by: Cursor <cursoragent@cursor.com> * Add test to verify consent passes when PreciseGeolocation special feature is missing Ensures TCF consent validation does not require SF1 (PreciseGeolocationData) opt-in. Co-authored-by: Cursor <cursoragent@cursor.com> * Removed TransparentConsentSpecialFeature.java --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 196b99d commit ef5f299

4 files changed

Lines changed: 54 additions & 19 deletions

File tree

src/main/java/com/uid2/operator/privacy/tcf/TransparentConsent.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,4 @@ public boolean hasConsent(int vendorId, TransparentConsentPurpose ... purposes)
3939
.reduce(0, (f, x) -> (f | (1 << x)))
4040
& requiredBits) == requiredBits;
4141
}
42-
43-
public boolean hasSpecialFeature(TransparentConsentSpecialFeature feature) {
44-
return this.tcString.getSpecialFeatureOptIns().contains(feature.value);
45-
}
4642
}

src/main/java/com/uid2/operator/privacy/tcf/TransparentConsentSpecialFeature.java

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import com.uid2.operator.privacy.tcf.TransparentConsent;
1313
import com.uid2.operator.privacy.tcf.TransparentConsentParseResult;
1414
import com.uid2.operator.privacy.tcf.TransparentConsentPurpose;
15-
import com.uid2.operator.privacy.tcf.TransparentConsentSpecialFeature;
1615
import com.uid2.operator.service.*;
1716
import com.uid2.operator.store.*;
1817
import com.uid2.operator.store.IConfigStore;
@@ -1632,9 +1631,7 @@ private UserConsentStatus validateUserConsent(JsonObject req, String apiContact)
16321631
TransparentConsentPurpose.MEASURE_AD_PERFORMANCE, // 7
16331632
TransparentConsentPurpose.DEVELOP_AND_IMPROVE_PRODUCTS // 10
16341633
);
1635-
final boolean allowPreciseGeo = tcResult.getTCString().hasSpecialFeature(TransparentConsentSpecialFeature.PreciseGeolocationData);
1636-
1637-
if (!userConsent || !allowPreciseGeo) {
1634+
if (!userConsent) {
16381635
return UserConsentStatus.INSUFFICIENT;
16391636
}
16401637
}

src/test/java/com/uid2/operator/EUIDOperatorVerticleTest.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
import org.junit.jupiter.api.Test;
44

5+
import com.iabtcf.encoder.TCStringEncoder;
6+
import com.iabtcf.utils.BitSetIntIterable;
57
import com.uid2.operator.model.IdentityScope;
68
import com.uid2.shared.auth.Role;
79

810
import io.vertx.core.Vertx;
911
import io.vertx.core.json.JsonObject;
1012
import io.vertx.junit5.VertxTestContext;
1113

14+
import java.time.Instant;
15+
1216
import static org.junit.jupiter.api.Assertions.*;
1317

1418
class EUIDOperatorVerticleTest extends UIDOperatorVerticleTest {
@@ -75,5 +79,54 @@ void noContentOnInsufficientTcfConsent(Vertx vertx, VertxTestContext testContext
7579
testContext.completeNow();
7680
});
7781
}
82+
83+
@Test
84+
void consentPassesWhenPreciseGeolocationSpecialFeatureIsMissing(Vertx vertx, VertxTestContext testContext) {
85+
final int clientSiteId = 201;
86+
fakeAuth(clientSiteId, Role.GENERATOR);
87+
setupSalts();
88+
setupKeys();
89+
90+
final String emailAddress = "test@uid2.com";
91+
final JsonObject v2Payload = new JsonObject();
92+
v2Payload.put("email", emailAddress);
93+
// TCF string with all required purposes but WITHOUT PreciseGeolocation special feature (feature 1)
94+
String tcfStringWithoutPreciseGeolocation = createTcfConsentString(
95+
new int[] { 21 }, // vendor consent
96+
new int[] { 21 }, // vendor LI
97+
new int[] { 1, 3, 4 }, // purpose consents (1, 3, 4)
98+
new int[] { 2, 7, 10 }, // purpose LI (2, 7, 10)
99+
new int[] {} // NO special features - PreciseGeolocation (1) is missing
100+
);
101+
v2Payload.put("tcf_consent_string", tcfStringWithoutPreciseGeolocation);
102+
sendTokenGenerate(vertx, v2Payload, 200, json -> {
103+
assertTrue(json.containsKey("body"));
104+
assertEquals("success", json.getString("status"));
105+
testContext.completeNow();
106+
});
107+
}
108+
109+
private String createTcfConsentString(int[] vendorConsent, int[] vendorLI, int[] purposesConsent, int[] purposesLI, int[] specialFeatureOptIns) {
110+
return TCStringEncoder.newBuilder()
111+
.version(2)
112+
.created(Instant.now())
113+
.lastUpdated(Instant.now())
114+
.cmpId(1)
115+
.cmpVersion(12)
116+
.consentScreen(1)
117+
.consentLanguage("FR")
118+
.vendorListVersion(2)
119+
.tcfPolicyVersion(1)
120+
.isServiceSpecific(true)
121+
.useNonStandardStacks(false)
122+
.addSpecialFeatureOptIns(BitSetIntIterable.from(specialFeatureOptIns))
123+
.publisherCC("DE")
124+
.addVendorConsent(BitSetIntIterable.from(vendorConsent))
125+
.addVendorLegitimateInterest(BitSetIntIterable.from(vendorLI))
126+
.purposeOneTreatment(true)
127+
.addPurposesConsent(BitSetIntIterable.from(purposesConsent))
128+
.addPurposesLITransparency(BitSetIntIterable.from(purposesLI))
129+
.encode();
130+
}
78131
}
79132

0 commit comments

Comments
 (0)