diff --git a/src/main/java/com/uid2/operator/privacy/tcf/TransparentConsent.java b/src/main/java/com/uid2/operator/privacy/tcf/TransparentConsent.java index 08640305c..c6aaf17c5 100644 --- a/src/main/java/com/uid2/operator/privacy/tcf/TransparentConsent.java +++ b/src/main/java/com/uid2/operator/privacy/tcf/TransparentConsent.java @@ -39,8 +39,4 @@ public boolean hasConsent(int vendorId, TransparentConsentPurpose ... purposes) .reduce(0, (f, x) -> (f | (1 << x))) & requiredBits) == requiredBits; } - - public boolean hasSpecialFeature(TransparentConsentSpecialFeature feature) { - return this.tcString.getSpecialFeatureOptIns().contains(feature.value); - } } diff --git a/src/main/java/com/uid2/operator/privacy/tcf/TransparentConsentSpecialFeature.java b/src/main/java/com/uid2/operator/privacy/tcf/TransparentConsentSpecialFeature.java deleted file mode 100644 index 3c1d1efbc..000000000 --- a/src/main/java/com/uid2/operator/privacy/tcf/TransparentConsentSpecialFeature.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.uid2.operator.privacy.tcf; - -public enum TransparentConsentSpecialFeature { - PreciseGeolocationData (1), - ActiveScanDeviceCharacteristics (2); - - public final int value; - private TransparentConsentSpecialFeature(int value) { - this.value = value; - } -} diff --git a/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java b/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java index 7b36e8eea..5f879d768 100644 --- a/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java +++ b/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java @@ -12,7 +12,6 @@ import com.uid2.operator.privacy.tcf.TransparentConsent; import com.uid2.operator.privacy.tcf.TransparentConsentParseResult; import com.uid2.operator.privacy.tcf.TransparentConsentPurpose; -import com.uid2.operator.privacy.tcf.TransparentConsentSpecialFeature; import com.uid2.operator.service.*; import com.uid2.operator.store.*; import com.uid2.operator.store.IConfigStore; @@ -1632,9 +1631,7 @@ private UserConsentStatus validateUserConsent(JsonObject req, String apiContact) TransparentConsentPurpose.MEASURE_AD_PERFORMANCE, // 7 TransparentConsentPurpose.DEVELOP_AND_IMPROVE_PRODUCTS // 10 ); - final boolean allowPreciseGeo = tcResult.getTCString().hasSpecialFeature(TransparentConsentSpecialFeature.PreciseGeolocationData); - - if (!userConsent || !allowPreciseGeo) { + if (!userConsent) { return UserConsentStatus.INSUFFICIENT; } } diff --git a/src/test/java/com/uid2/operator/EUIDOperatorVerticleTest.java b/src/test/java/com/uid2/operator/EUIDOperatorVerticleTest.java index d9a4ef419..3d6cbc692 100644 --- a/src/test/java/com/uid2/operator/EUIDOperatorVerticleTest.java +++ b/src/test/java/com/uid2/operator/EUIDOperatorVerticleTest.java @@ -2,6 +2,8 @@ import org.junit.jupiter.api.Test; +import com.iabtcf.encoder.TCStringEncoder; +import com.iabtcf.utils.BitSetIntIterable; import com.uid2.operator.model.IdentityScope; import com.uid2.shared.auth.Role; @@ -9,6 +11,8 @@ import io.vertx.core.json.JsonObject; import io.vertx.junit5.VertxTestContext; +import java.time.Instant; + import static org.junit.jupiter.api.Assertions.*; class EUIDOperatorVerticleTest extends UIDOperatorVerticleTest { @@ -75,5 +79,54 @@ void noContentOnInsufficientTcfConsent(Vertx vertx, VertxTestContext testContext testContext.completeNow(); }); } + + @Test + void consentPassesWhenPreciseGeolocationSpecialFeatureIsMissing(Vertx vertx, VertxTestContext testContext) { + final int clientSiteId = 201; + fakeAuth(clientSiteId, Role.GENERATOR); + setupSalts(); + setupKeys(); + + final String emailAddress = "test@uid2.com"; + final JsonObject v2Payload = new JsonObject(); + v2Payload.put("email", emailAddress); + // TCF string with all required purposes but WITHOUT PreciseGeolocation special feature (feature 1) + String tcfStringWithoutPreciseGeolocation = createTcfConsentString( + new int[] { 21 }, // vendor consent + new int[] { 21 }, // vendor LI + new int[] { 1, 3, 4 }, // purpose consents (1, 3, 4) + new int[] { 2, 7, 10 }, // purpose LI (2, 7, 10) + new int[] {} // NO special features - PreciseGeolocation (1) is missing + ); + v2Payload.put("tcf_consent_string", tcfStringWithoutPreciseGeolocation); + sendTokenGenerate(vertx, v2Payload, 200, json -> { + assertTrue(json.containsKey("body")); + assertEquals("success", json.getString("status")); + testContext.completeNow(); + }); + } + + private String createTcfConsentString(int[] vendorConsent, int[] vendorLI, int[] purposesConsent, int[] purposesLI, int[] specialFeatureOptIns) { + return TCStringEncoder.newBuilder() + .version(2) + .created(Instant.now()) + .lastUpdated(Instant.now()) + .cmpId(1) + .cmpVersion(12) + .consentScreen(1) + .consentLanguage("FR") + .vendorListVersion(2) + .tcfPolicyVersion(1) + .isServiceSpecific(true) + .useNonStandardStacks(false) + .addSpecialFeatureOptIns(BitSetIntIterable.from(specialFeatureOptIns)) + .publisherCC("DE") + .addVendorConsent(BitSetIntIterable.from(vendorConsent)) + .addVendorLegitimateInterest(BitSetIntIterable.from(vendorLI)) + .purposeOneTreatment(true) + .addPurposesConsent(BitSetIntIterable.from(purposesConsent)) + .addPurposesLITransparency(BitSetIntIterable.from(purposesLI)) + .encode(); + } }