From 716af801dfceff30a3646d4c5454de61e502f732 Mon Sep 17 00:00:00 2001 From: James Yuzawa Date: Mon, 16 Jun 2025 10:17:17 -0400 Subject: [PATCH 01/22] Fix javadoc build issues (#78) * make jdk's consistent * force javadoc check in CI build --- .github/workflows/main.yml | 2 +- .github/workflows/tests.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0a6ad10c..2d032488 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,8 +22,8 @@ jobs: - name: Set up Java uses: actions/setup-java@v2 with: - java-version: '11' distribution: 'adopt' + java-version: '21' # Import GPG secret key for signing - name: Import GPG key diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9b99b412..03923b3d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: - distribution: 'temurin' + distribution: 'adopt' java-version: '21' cache: 'maven' - name: Initialize CodeQL @@ -28,7 +28,7 @@ jobs: languages: java - name: Build with Maven timeout-minutes: 15 - run: mvn -B clean package --file pom.xml + run: mvn -B clean javadoc:javadoc package --file pom.xml - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: From 21736636477f39cdf1c66689e4b76c10fcb3e470 Mon Sep 17 00:00:00 2001 From: aitsxhxl <111370634+aitsxhxl@users.noreply.github.com> Date: Mon, 16 Jun 2025 19:57:30 +0530 Subject: [PATCH 02/22] modified build script to delete gpg key after import & removed javadoc skip flag --- .github/workflows/main.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2d032488..971fbd50 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,7 +30,8 @@ jobs: run: | echo "${{ secrets.GPG_SECRET_KEY }}" > secret_key.asc gpg --import --no-tty --batch secret_key.asc || { echo "GPG import failed"; cat secret_key.asc; exit 1; } - gpg --list-secret-keys + rm -f secret_key.asc + # gpg --list-secret-keys # Generate settings.xml with Maven repository credentials - name: Create settings.xml @@ -56,7 +57,8 @@ jobs: echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf echo "use-agent" >> ~/.gnupg/gpg.conf export GPG_TTY=$(tty || echo /dev/tty) - mvn clean deploy --settings ~/.m2/settings.xml -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" -Prelease -Dmaven.javadoc.skip=true + mvn clean deploy --settings ~/.m2/settings.xml -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" -Prelease + # mvn clean deploy --settings ~/.m2/settings.xml -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" -Prelease -Dmaven.javadoc.skip=true # Commit the release version and create a tag - name: Commit and tag release From 351c5e0368e0cfe1787c44ef122508370b8746d6 Mon Sep 17 00:00:00 2001 From: aitsxhxl <111370634+aitsxhxl@users.noreply.github.com> Date: Wed, 18 Jun 2025 14:26:07 +0530 Subject: [PATCH 03/22] Update workflow file to commit the next snapshot version in message --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 971fbd50..c30d3dc4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -76,8 +76,10 @@ jobs: # Commit the snapshot version - name: Commit snapshot version run: | + NEW_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) git add . - git commit -m "${{ github.event.inputs.version }}-SNAPSHOT" + git commit -m "$NEW_VERSION" + # git commit -m "${{ github.event.inputs.version }}-SNAPSHOT" # Push commits and tags to GitHub - name: Push changes From 2f1c52ec08bceee81e513e69ff3fd39992459f1b Mon Sep 17 00:00:00 2001 From: chuff Date: Wed, 25 Jun 2025 03:25:59 -0600 Subject: [PATCH 04/22] Fail if gpp string doesnt start with DB (#76) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial multi state implementation * multi state * unit tests * exposing id based methods in GppModel * personal data consents fix, reduce multi state subsection id (#10) Co-authored-by: chad * 3.0.0 (#11) * personal data consents fix, reduce multi state subsection id * scm * [maven-release-plugin] prepare release iabgpp-core-3.0.0 * scm * scm * scm * scm * 3.0.0 * 3.0.1-SNAPSHOT Co-authored-by: chad * fix multi state name, add unit tests (#13) * personal data consents fix, reduce multi state subsection id * scm * [maven-release-plugin] prepare release iabgpp-core-3.0.0 * scm * scm * scm * scm * 3.0.0 * 3.0.1-SNAPSHOT * fix section names and add unit tests Co-authored-by: chad * 3.0.1 (#14) * personal data consents fix, reduce multi state subsection id * scm * [maven-release-plugin] prepare release iabgpp-core-3.0.0 * scm * scm * scm * scm * 3.0.0 * 3.0.1-SNAPSHOT * fix section names and add unit tests * 3.0.1 * 3.1.0-SNAPSHOT * cleanup * fix groupId in README * fix groupId in README * fix groupId in README Co-authored-by: chad * Convenience Methods (#15) * personal data consents fix, reduce multi state subsection id * scm * [maven-release-plugin] prepare release iabgpp-core-3.0.0 * scm * scm * scm * scm * 3.0.0 * 3.0.1-SNAPSHOT * fix section names and add unit tests * 3.0.1 * 3.1.0-SNAPSHOT * cleanup * fix groupId in README * fix groupId in README * fix groupId in README * convenience methods * 3.0.2 * 3.1.0-SNAPSHOT Co-authored-by: chad * full list of fields to readme (#16) * personal data consents fix, reduce multi state subsection id * scm * [maven-release-plugin] prepare release iabgpp-core-3.0.0 * scm * scm * scm * scm * 3.0.0 * 3.0.1-SNAPSHOT * fix section names and add unit tests * 3.0.1 * 3.1.0-SNAPSHOT * cleanup * fix groupId in README * fix groupId in README * fix groupId in README * convenience methods * 3.0.2 * 3.1.0-SNAPSHOT * full list of fields to readme * rename array to list in readme Co-authored-by: chad * tcfeuv2 backwards compatible (#19) * Exception handling * compressed base64urlencoder for all non-tcfeuv2 segments * Revert uspv1 to original encoding * Rename tcfcav2 to tcfcav1 * update readme for tcfcav2 -> tcfcav1 and uspv1 changes * optional gpc segments * update readme with GpcSegmentIncluded fields * fix vendor list encoding / decoding * formatting * 3.0.3 * version bump Co-authored-by: chad * Update dependencies. Fix bitfield cast. (#20) * Exception handling * compressed base64urlencoder for all non-tcfeuv2 segments * Revert uspv1 to original encoding * Rename tcfcav2 to tcfcav1 * update readme for tcfcav2 -> tcfcav1 and uspv1 changes * optional gpc segments * update readme with GpcSegmentIncluded fields * fix vendor list encoding / decoding * formatting * 3.0.3 * version bump * fix bitfield data type * update jackson version * update junit * 3.0.4 * 3.0.5-SNAPSHOT * 3.0.5 * 3.0.6-SNAPSHOT * 3.0.6 * 3.0.7-SNAPSHOT * 3.0.7 * 3.0.8-SNAPSHOT Co-authored-by: chad * Dedupe and sort lists. Added InvalidFieldError. (#24) * fix optimized fix range decoder * fix optimized fibonacci fix range decoder * 3.0.8 * 3.0.9-SNAPSHOT * 3.0.9 * 3.0.10-SNAPSHOT * dedup and sort lists * formatting * 3.0.10 * 3.0.11-SNAPSHOT * 3.0.12-SNAPSHOT * 3.0.11-SNAPSHOT * 3.0.10 * 3.0.11-SNAPSHOT * 3.0.10 * 3.0.11-SNAPSHOT * cleanup Co-authored-by: chad * issue 26: wrong version number for TcfCaV1 (#27) Co-authored-by: Guofang Li * Removes duplicate section in the GppModel.decodeSection if tree as UspV1 was in the list twice. (#30) * Updating GVL code as V3 and adding some comments (#32) * https://github.com/IABTechLab/iabgpp-java/issues/29 https://github.com/IABTechLab/iabgpp-java/issues/26 * Removes duplicate section in the GppModel.decodeSection * Rename multistate usp* to us* * fix tcfcav1 policy version * vendor list 2.2 * lazy decoding * cleanup lazy decoding * Updating GVL code as V3 and adding some comments; also removing GPPModel LazyDecoding feature; also keeping the TCF policy version as 2 for Canada. * 3.1.0 * 3.1.1-SNAPSHOT --------- Co-authored-by: chad Co-authored-by: srini81 * rename missed multistate usp* methods to us* (#35) Co-authored-by: chad * Adding a new field in Vendor for "impConsPurposes" as the GVL for Canada has changed to include this field in the place of "legIntPurposes". (#37) Both these fields will be set to Optional in order to handle both Canada and EU use cases. Co-authored-by: srini81 * 3.1.1 * 3.1.2-SNAPSHOT * Version Bump (#38) * 3.1.1 * 3.1.2-SNAPSHOT --------- Co-authored-by: chad * lazy decoding (#34) * lazy decoding * java 8 compatible gppmodel tests * rename missed multistate usp* methods to us* * lazier decoding * lazier decoding * tests for null and empty string constructor arguments * deprecate multi-state usp* methods * remove deprecated usp methods * encodeSection lazy fix * optimize bitstring padding --------- Co-authored-by: chad * Update README.md (#46) Fix incorrect client-side API prefixes. https://github.com/InteractiveAdvertisingBureau/Global-Privacy-Platform/blob/main/Sections/Section%20Information.md is the authority. * Validation (#36) * lazy decoding * java 8 compatible gppmodel tests * rename missed multistate usp* methods to us* * lazier decoding * lazier decoding * tests for null and empty string constructor arguments * validation * fix typo * remove redundant validate call * default validate * remove empty validate method from header core segment * fix usct validator * deprecate multi-state usp* methods * remove deprecated usp methods * cleanup validators * encodeSection lazy fix --------- Co-authored-by: chad * tcfca pub restrictions and disclosed vendors (#39) * rename missed multistate usp* methods to us* * 3.1.1 * 3.1.2-SNAPSHOT * tcfca publisher restrictions and disclosed vendors * deprecate multi-state usp* methods * substring error handling * remove deprecated usp methods * Update README * tcfeu pub restrictions fix * pub restrictions getters * tcfeu pub restirctions fix * cleanup * pub restrictions fix --------- Co-authored-by: chad * 3.2.0 * 3.2.1-SNAPSHOT * Versioning (#47) * 3.1.1 * 3.1.2-SNAPSHOT * 3.2.0 * 3.2.1-SNAPSHOT --------- Co-authored-by: chad * Remove multistate version (#60) * lazy decoding * java 8 compatible gppmodel tests * rename missed multistate usp* methods to us* * lazier decoding * lazier decoding * tests for null and empty string constructor arguments * validation * fix typo * remove redundant validate call * default validate * remove empty validate method from header core segment * fix usct validator * 3.1.1 * 3.1.2-SNAPSHOT * tcfca publisher restrictions and disclosed vendors * deprecate multi-state usp* methods * substring error handling * remove deprecated usp methods * remove deprecated usp methods * remove deprecated usp methods * cleanup validators * Better decoding exception messaging * remove unused classes * Update README * add support for the old headerless tcfeuv2 strings * encodeSection fix * encodeSection lazy fix * tcfeu pub restrictions fix * pub restrictions getters * tcfeu pub restirctions fix * cleanup * pub restrictions fix * optimize bitstring padding * 3.2.0 * 3.2.1-SNAPSHOT * fl mt or tx * remove version from multistate resources --------- Co-authored-by: chad * Post release version bump (#64) * 3.2.1 * 3.2.2-SNAPSHOT --------- Co-authored-by: Chad Huff * 3.2.2 * 3.2.3-SNAPSHOT * Tx fl or mt (#57) * lazy decoding * java 8 compatible gppmodel tests * rename missed multistate usp* methods to us* * lazier decoding * lazier decoding * tests for null and empty string constructor arguments * validation * fix typo * remove redundant validate call * default validate * remove empty validate method from header core segment * fix usct validator * 3.1.1 * 3.1.2-SNAPSHOT * tcfca publisher restrictions and disclosed vendors * deprecate multi-state usp* methods * substring error handling * remove deprecated usp methods * remove deprecated usp methods * remove deprecated usp methods * cleanup validators * Better decoding exception messaging * remove unused classes * Update README * add support for the old headerless tcfeuv2 strings * encodeSection fix * encodeSection lazy fix * tcfeu pub restrictions fix * pub restrictions getters * tcfeu pub restirctions fix * cleanup * pub restrictions fix * optimize bitstring padding * 3.2.0 * 3.2.1-SNAPSHOT * fl mt or tx --------- Co-authored-by: chad * Update AbstractLazilyEncodableSection.java (#61) * DE IA NE NH NJ TN MSPA USNAT (#65) * DE IA NE NH NJ TN * remove validation * usnat backwards compatibility --------- Co-authored-by: Chad Huff * remove validation (#66) * remove validation * fix lazy decoding in decodeSection --------- Co-authored-by: Chad Huff * 3.2.3 * 3.2.4-SNAPSHOT * Added GitHub Actions workflow file for iabgpp-java version release * Fail if gpp string doesnt start with DB * fix merge conflict --------- Co-authored-by: Mayank Mishra Co-authored-by: chad Co-authored-by: Guofang Li Co-authored-by: Guofang Li Co-authored-by: Bryan DeLong Co-authored-by: srini81 Co-authored-by: Srinivas Bhagavatula Co-authored-by: DaniĆ«l Hoeksema <37441336+danielsao@users.noreply.github.com> Co-authored-by: iabsxhxl Co-authored-by: naveenjr7 Co-authored-by: aitsxhxl <111370634+aitsxhxl@users.noreply.github.com> --- .github/workflows/main.yml | 1 + README.md | 1 + .../java/com/iab/gpp/encoder/GppModel.java | 2 +- .../com/iab/gpp/encoder/GppModelTest.java | 43 +++++++++++-------- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c30d3dc4..3b0cdcf3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -33,6 +33,7 @@ jobs: rm -f secret_key.asc # gpg --list-secret-keys + # Generate settings.xml with Maven repository credentials - name: Create settings.xml run: | diff --git a/README.md b/README.md index a6a2a2db..b4c3ee2b 100644 --- a/README.md +++ b/README.md @@ -263,3 +263,4 @@ CmpList cmpList = loader.cmpList(cmpListContent); ## Contributing Here you can find the [contributing guide](CONTRIBUTING.md) to help maintain and update the library. This library is managed by the Code Libraries Subgroup of the Global Privacy Working Group at the IAB Tech Lab. To join the group, please reach out to support@iabtechlab.com. + diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java index a85a5e25..b4f8cba3 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java @@ -359,7 +359,7 @@ protected String encodeModel(Map sections) { } protected Map decodeModel(String str) { - if (str == null || str.isEmpty() || str.startsWith("D")) { + if (str == null || str.isEmpty() || str.startsWith("DB")) { Map sections = new HashMap<>(); if (str != null && !str.isEmpty()) { diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index 9a6e9609..d1890a59 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -69,20 +69,6 @@ public void testEncodeDefault() { } - @Test - public void testDecodingException() { - Assertions.assertThrows(DecodingException.class, () -> { - new GppModel("invalid gpp string").getHeader(); - }); - } - - @Test() - public void testDecodeGarbage() { - Assertions.assertThrows(DecodingException.class, () -> { - new GppModel("z").getUsCtSection(); - }); - } - @Test public void testEncodeDefaultAll() { GppModel gppModel = new GppModel(); @@ -132,7 +118,6 @@ public void testEncodeDefaultAll() { gppModel.setFieldValue(UsTn.NAME, UsTxField.VERSION, UsTx.VERSION); - Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(true, gppModel.hasSection(TcfCaV1.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UspV1.NAME)); @@ -155,9 +140,22 @@ public void testEncodeDefaultAll() { String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOdM~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA", - gppString); + "DBACOdM~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA", + gppString); + } + @Test + public void testDecodingException() { + Assertions.assertThrows(DecodingException.class, () -> { + new GppModel("invalid gpp string").getHeader(); + }); + } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new GppModel("z").getUsCtSection(); + }); } @Test @@ -821,6 +819,17 @@ public void testDecodingEmptyString() { gppModel.setFieldValue("uspv1", UspV1Field.NOTICE, 'Y'); Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); } + + @Test + public void testDecodingExceptionValidStringButNotGPP() { + try { + GppModel gppModel = new GppModel("DP48G0AP48G0AEsACCPLAkEgAAAAAEPgAB5YAAAQaQD2F2K2kKFkPCmQWYAQBCijYEAhQAAAAkCBIAAgAUgQAgFIIAgAIFAAAAAAAAAQEgCQAAQABAAAIACgAAAAAAIAAAAAAAQQAAAAAIAAAAAAAAEAAAAAAAQAAAAIAABEhCAAQQAEAAAAAAAQAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAgAA"); + gppModel.getHeader().getName(); + Assertions.fail("Expected LazyDecodingException"); + } catch (DecodingException e) { + + } + } } From 7459ecfb768fbbe77ac262f8a62610870029b971 Mon Sep 17 00:00:00 2001 From: Mayank Mishra Date: Wed, 25 Jun 2025 09:32:40 +0000 Subject: [PATCH 05/22] 3.2.4 --- iabgpp-encoder/pom.xml | 2 +- iabgpp-extras-jackson/pom.xml | 4 ++-- iabgpp-extras/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iabgpp-encoder/pom.xml b/iabgpp-encoder/pom.xml index e8d49a10..8da7a2a3 100644 --- a/iabgpp-encoder/pom.xml +++ b/iabgpp-encoder/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.2.4-SNAPSHOT + 3.2.4 iabgpp-encoder diff --git a/iabgpp-extras-jackson/pom.xml b/iabgpp-extras-jackson/pom.xml index 1924b0f5..e149d7df 100644 --- a/iabgpp-extras-jackson/pom.xml +++ b/iabgpp-extras-jackson/pom.xml @@ -7,7 +7,7 @@ iabgpp-core com.iabgpp - 3.2.4-SNAPSHOT + 3.2.4 iabgpp-extras-jackson @@ -24,7 +24,7 @@ com.iabgpp iabgpp-extras - 3.2.4-SNAPSHOT + 3.2.4 diff --git a/iabgpp-extras/pom.xml b/iabgpp-extras/pom.xml index ffa646af..fe2ad020 100644 --- a/iabgpp-extras/pom.xml +++ b/iabgpp-extras/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.2.4-SNAPSHOT + 3.2.4 iabgpp-extras diff --git a/pom.xml b/pom.xml index aa2b158a..f844d95a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iabgpp iabgpp-core - 3.2.4-SNAPSHOT + 3.2.4 IAB GPP Core Library https://github.com/IABTechLabs/iabtcf-java Encode and decode consent information with the IAB GPP v3.0. From 17d738b26e1816445fe5eba234120c8fb56463de Mon Sep 17 00:00:00 2001 From: Mayank Mishra Date: Wed, 25 Jun 2025 09:32:45 +0000 Subject: [PATCH 06/22] 3.2.5-SNAPSHOT --- iabgpp-encoder/pom.xml | 2 +- iabgpp-extras-jackson/pom.xml | 4 ++-- iabgpp-extras/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iabgpp-encoder/pom.xml b/iabgpp-encoder/pom.xml index 8da7a2a3..03e794e5 100644 --- a/iabgpp-encoder/pom.xml +++ b/iabgpp-encoder/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.2.4 + 3.2.5-SNAPSHOT iabgpp-encoder diff --git a/iabgpp-extras-jackson/pom.xml b/iabgpp-extras-jackson/pom.xml index e149d7df..99819c6e 100644 --- a/iabgpp-extras-jackson/pom.xml +++ b/iabgpp-extras-jackson/pom.xml @@ -7,7 +7,7 @@ iabgpp-core com.iabgpp - 3.2.4 + 3.2.5-SNAPSHOT iabgpp-extras-jackson @@ -24,7 +24,7 @@ com.iabgpp iabgpp-extras - 3.2.4 + 3.2.5-SNAPSHOT diff --git a/iabgpp-extras/pom.xml b/iabgpp-extras/pom.xml index fe2ad020..592a99ad 100644 --- a/iabgpp-extras/pom.xml +++ b/iabgpp-extras/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.2.4 + 3.2.5-SNAPSHOT iabgpp-extras diff --git a/pom.xml b/pom.xml index f844d95a..892005fc 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iabgpp iabgpp-core - 3.2.4 + 3.2.5-SNAPSHOT IAB GPP Core Library https://github.com/IABTechLabs/iabtcf-java Encode and decode consent information with the IAB GPP v3.0. From b18fdce1ae7d43e57fbc4e8175da10fa7ba9b906 Mon Sep 17 00:00:00 2001 From: chuff Date: Tue, 10 Feb 2026 12:02:36 -0700 Subject: [PATCH 07/22] usnat backwards compatibility for compressed padding (#82) Co-authored-by: Chad Huff --- .../gpp/encoder/segment/UsNatCoreSegment.java | 6 ++++- .../iab/gpp/encoder/section/UsNatTest.java | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatCoreSegment.java index 6c7a7945..0c4769ad 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatCoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatCoreSegment.java @@ -99,7 +99,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel // Necessary to maintain backwards compatibility when sensitive data processing changed from a // length of 12 to 16 and known child sensitive data consents changed from a length of 2 to 3 in the // DE, IA, NE, NH, NJ, TN release - if (bitString.length() == 66) { + if (bitString.length() == 60) { + bitString = + bitString.substring(0, 48) + "00000000" + bitString.substring(48, 52) + "00" + bitString.substring(52, 60) + "00"; + } + else if (bitString.length() == 66) { bitString = bitString.substring(0, 48) + "00000000" + bitString.substring(48, 52) + "00" + bitString.substring(52, 62); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatTest.java index 67029545..4d32c057 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatTest.java @@ -228,6 +228,28 @@ public void testDecodeWithGpcSegmentExcluded() throws DecodingException { Assertions.assertEquals(2, usNat.getMspaServiceProviderMode()); Assertions.assertEquals(false, usNat.getGpcSegmentIncluded()); } + + @Test + public void testDecodeBackwardsCompatibility() throws DecodingException { + UsNat usNat = new UsNat("BVQqAAAACg"); + + Assertions.assertEquals(1, usNat.getSharingNotice()); + Assertions.assertEquals(1, usNat.getSaleOptOutNotice()); + Assertions.assertEquals(1, usNat.getSharingOptOutNotice()); + Assertions.assertEquals(1, usNat.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(0, usNat.getSensitiveDataProcessingOptOutNotice()); + Assertions.assertEquals(0, usNat.getSensitiveDataLimitUseNotice()); + Assertions.assertEquals(2, usNat.getSaleOptOut()); + Assertions.assertEquals(2, usNat.getSharingOptOut()); + Assertions.assertEquals(2, usNat.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), usNat.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(0, 0, 0), usNat.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(2, usNat.getPersonalDataConsents()); + Assertions.assertEquals(2, usNat.getMspaCoveredTransaction()); + Assertions.assertEquals(0, usNat.getMspaOptOutOptionMode()); + Assertions.assertEquals(0, usNat.getMspaServiceProviderMode()); + Assertions.assertEquals(false, usNat.getGpc()); + } @Test() public void testDecodeGarbage() { From 8f46511217d929582e138e6f12b87a16f975313b Mon Sep 17 00:00:00 2001 From: chuff Date: Tue, 10 Feb 2026 12:02:44 -0700 Subject: [PATCH 08/22] Minnesota (#85) * Minnesota * Fix section references * Fix MN datatypes --------- Co-authored-by: Chad Huff --- README.md | 451 ++++++++++++------ .../java/com/iab/gpp/encoder/GppModel.java | 36 +- .../com/iab/gpp/encoder/field/UsMnField.java | 48 ++ .../com/iab/gpp/encoder/section/Sections.java | 1 + .../com/iab/gpp/encoder/section/UsMn.java | 141 ++++++ .../gpp/encoder/segment/UsDeCoreSegment.java | 3 +- .../gpp/encoder/segment/UsIaCoreSegment.java | 3 +- .../gpp/encoder/segment/UsMnCoreSegment.java | 97 ++++ .../gpp/encoder/segment/UsMnGpcSegment.java | 61 +++ .../gpp/encoder/segment/UsNeCoreSegment.java | 3 +- .../gpp/encoder/segment/UsTxCoreSegment.java | 3 +- .../com/iab/gpp/encoder/GppModelTest.java | 36 +- .../FibonacciIntegerRangeEncoderTest.java | 2 +- .../encoder/FixedIntegerRangeEncoderTest.java | 2 +- .../gpp/encoder/section/.UsNatV1Test.java.swp | Bin 16384 -> 0 bytes .../com/iab/gpp/encoder/section/UsMnTest.java | 171 +++++++ 16 files changed, 860 insertions(+), 198 deletions(-) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMnField.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsMn.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMnCoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMnGpcSegment.java delete mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/.UsNatV1Test.java.swp create mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsMnTest.java diff --git a/README.md b/README.md index b4c3ee2b..fa9345d3 100644 --- a/README.md +++ b/README.md @@ -115,151 +115,312 @@ CmpList cmpList = loader.cmpList(cmpListContent); ### Fields -|Section Name|Section ID|Field|Data Type/Value| -|------------|----------|-----|---------------| -|tcfeuv2|2|Version|6 bit int. Value is 2.| -|tcfeuv2|2|Created|Datetime. Updated when fields are set| -|tcfeuv2|2|LastUpdated|Datetime. Updated when fields are set| -|tcfeuv2|2|CmpId|12 bit int| -|tcfeuv2|2|CmpVersion|12 bit int| -|tcfeuv2|2|ConsentScreen|6 bit int| -|tcfeuv2|2|ConsentLanguage|2 character country code| -|tcfeuv2|2|VendorListVersion|12 bit int| -|tcfeuv2|2|PolicyVersion|6 bit int. Value is 2| -|tcfeuv2|2|IsServiceSpecific|Boolean| -|tcfeuv2|2|UseNonStandardStacks|Boolean| -|tcfeuv2|2|SpecialFeatureOptins|Boolean list of size 12| -|tcfeuv2|2|PurposeConsents|Boolean list of size 24| -|tcfeuv2|2|PurposeLegitimateInterests|Boolean list of size 24| -|tcfeuv2|2|PurposeOneTreatment|Boolean| -|tcfeuv2|2|PublisherCountryCode|2 character country code| -|tcfeuv2|2|VendorConsents|Integer list of variable size| -|tcfeuv2|2|VendorLegitimateInterests|Integer list of variable size| -|tcfeuv2|2|PublisherRestrictions|Integer list of variable size| -|tcfeuv2|2|PublisherPurposesSegmentType|3 bit int. Value is 3| -|tcfeuv2|2|PublisherConsents|Boolean list of size 24| -|tcfeuv2|2|PublisherLegitimateInterests|Boolean list of size 24| -|tcfeuv2|2|NumCustomPurposes|6 bit int| -|tcfeuv2|2|PublisherCustomConsents|Boolean list where size is set by the NumCustomPurposes field| -|tcfeuv2|2|PublisherCustomLegitimateInterests|Boolean list where size is set by the NumCustomPurposes field| -|tcfeuv2|2|VendorsAllowedSegmentType|3 bit int. Value is 2| -|tcfeuv2|2|VendorsAllowed|Integer list of variable size| -|tcfeuv2|2|VendorsDisclosedSegmentType|3 bit int. Value is 1| -|tcfeuv2|2|VendorsDisclosed|Integer list of variable size| -|tcfcav1|5|Version|6 bit int. Value is 2.| -|tcfcav1|5|Created|Datetime. Updated when any fields are set| -|tcfcav1|5|LastUpdated|Datetime. Updated when any fields are set| -|tcfcav1|5|CmpId|12 bit int| -|tcfcav1|5|CmpVersion|12 bit int| -|tcfcav1|5|ConsentScreen|6 bit int| -|tcfcav1|5|ConsentLanguage|2 character country code| -|tcfcav1|5|VendorListVersion|12 bit int| -|tcfcav1|5|TcfPolicyVersion|6 bit int. Value is 2.| -|tcfcav1|5|UseNonStandardStacks|Boolean| -|tcfcav1|5|SpecialFeatureExpressConsent|Boolean list of size 12| -|tcfcav1|5|PurposesExpressConsent|Boolean list of size 24| -|tcfcav1|5|PurposesImpliedConsent|Boolean list of size 24| -|tcfcav1|5|VendorExpressConsent|Integer list of variable size| -|tcfcav1|5|VendorImpliedConsent|Integer list of variable size| -|tcfcav1|5|PubRestrictions|RangeEntry list of variable size| -|tcfcav1|5|PubPurposesSegmentType|3 bit int. Value is 3| -|tcfcav1|5|PubPurposesExpressConsent|Boolean list of size 24| -|tcfcav1|5|PubPurposesImpliedConsent|Boolean list of size 24| -|tcfcav1|5|NumCustomPurposes|6 bit int| -|tcfcav1|5|CustomPurposesExpressConsent|Boolean list where size is set by the NumCustomPurposes field| -|tcfcav1|5|CustomPurposesImpliedConsent|Boolean list where size is set by the NumCustomPurposes field| -|tcfcav1|5|DisclosedVendorsSegmentType|3 bit int. Value is 1| -|tcfcav1|5|DisclosedVendors|Integer list of variable size| -|uspv1|6|Version|6 bit int. Value is 1| -|uspv1|6|Notice|2 bit int| -|uspv1|6|OptOutSale|2 bit int| -|uspv1|6|LspaCovered|2 bit int| -|usnat|7|Version|6 bit int. Value is 1| -|usnat|7|SharingNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|SaleOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|SharingOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|TargetedAdvertisingOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|SensitiveDataProcessingOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|SensitiveDataLimitUseNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|SaleOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|SharingOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|TargetedAdvertisingOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|SensitiveDataProcessing|2 bit int list of size 12. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|KnownChildSensitiveDataConsents|2 bit int list of size 2. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|PersonalDataConsents|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|MspaCoveredTransaction|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|MspaOptOutOptionMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|MspaServiceProviderMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usnat|7|GpcSegmentType|2 bit int. Value is 1| -|usnat|7|GpcSegmentIncluded|Boolean. Default value is true| -|usnat|7|Gpc|Boolean| -|usca|8|Version|6 bit int. Value is 1| -|usca|8|SaleOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usca|8|SharingOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usca|8|SensitiveDataLimitUseNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usca|8|SaleOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usca|8|SharingOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usca|8|SensitiveDataProcessing|2 bit int list of size 9. 0=Not applicable, 1=Yes, 2=No| -|usca|8|KnownChildSensitiveDataConsents|2 bit int list of size 2. 0=Not applicable, 1=Yes, 2=No| -|usca|8|PersonalDataConsents|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usca|8|MspaCoveredTransaction|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usca|8|MspaOptOutOptionMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usca|8|MspaServiceProviderMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usca|8|GpcSegmentType|2 bit int. Value is 1| -|usca|8|GpcSegmentIncluded|Boolean. Default value is true| -|usca|8|Gpc|Boolean| -|usva|9|Version|6 bit int. Value is 1| -|usva|9|SharingNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usva|9|SaleOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usva|9|TargetedAdvertisingOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usva|9|SaleOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usva|9|TargetedAdvertisingOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usva|9|SensitiveDataProcessing|2 bit int list of size 8. 0=Not applicable, 1=Yes, 2=No| -|usva|9|KnownChildSensitiveDataConsents|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usva|9|MspaCoveredTransaction|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usva|9|MspaOptOutOptionMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usva|9|MspaServiceProviderMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usco|10|Version|6 bit int. Value is 1| -|usco|10|SharingNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usco|10|SaleOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usco|10|TargetedAdvertisingOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usco|10|SaleOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usco|10|TargetedAdvertisingOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usco|10|SensitiveDataProcessing|2 bit int list of size 7. 0=Not applicable, 1=Yes, 2=No| -|usco|10|KnownChildSensitiveDataConsents|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usco|10|MspaCoveredTransaction|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usco|10|MspaOptOutOptionMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usco|10|MspaServiceProviderMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usco|10|GpcSegmentType|2 bit int. Value is 1| -|usco|10|GpcSegmentIncluded|Boolean. Default value is true| -|usco|10|Gpc|Boolean| -|usut|11|Version|6 bit int. Value is 1| -|usut|11|SharingNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usut|11|SaleOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usut|11|TargetedAdvertisingOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usut|11|SensitiveDataProcessingOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usut|11|SaleOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usut|11|TargetedAdvertisingOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usut|11|SensitiveDataProcessing|2 bit int list of size 8. 0=Not applicable, 1=Yes, 2=No| -|usut|11|KnownChildSensitiveDataConsents|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usut|11|MspaCoveredTransaction|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usut|11|MspaOptOutOptionMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usut|11|MspaServiceProviderMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usct|12|Version|6 bit int. Value is 1| -|usct|12|SharingNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usct|12|SaleOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usct|12|TargetedAdvertisingOptOutNotice|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usct|12|SaleOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usct|12|TargetedAdvertisingOptOut|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usct|12|SensitiveDataProcessing|2 bit int list of size 8. 0=Not applicable, 1=Yes, 2=No| -|usct|12|KnownChildSensitiveDataConsents|2 bit int list of size 3. 0=Not applicable, 1=Yes, 2=No| -|usct|12|MspaCoveredTransaction|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usct|12|MspaOptOutOptionMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usct|12|MspaServiceProviderMode|2 bit int. 0=Not applicable, 1=Yes, 2=No| -|usct|12|GpcSegmentType|2 bit int. Value is 1| -|usct|12|GpcSegmentIncluded|Boolean. Default value is true| -|usct|12|Gpc|Boolean| - +| Section Name | Section ID | Field | Data Type/Value | +| ------------ | ---------- | ----------------------------------- | -------------------------------------------------------------- | +| tcfeuv2 | 2 | Version | 6 bit int. Value is 2. | +| tcfeuv2 | 2 | Created | Datetime. Updated when fields are set | +| tcfeuv2 | 2 | LastUpdated | Datetime. Updated when fields are set | +| tcfeuv2 | 2 | CmpId | 12 bit int | +| tcfeuv2 | 2 | CmpVersion | 12 bit int | +| tcfeuv2 | 2 | ConsentScreen | 6 bit int | +| tcfeuv2 | 2 | ConsentLanguage | 2 character country code | +| tcfeuv2 | 2 | VendorListVersion | 12 bit int | +| tcfeuv2 | 2 | PolicyVersion | 6 bit int. Value is 2 | +| tcfeuv2 | 2 | IsServiceSpecific | Boolean | +| tcfeuv2 | 2 | UseNonStandardStacks | Boolean | +| tcfeuv2 | 2 | SpecialFeatureOptins | Boolean array of size 12 | +| tcfeuv2 | 2 | PurposeConsents | Boolean array of size 24 | +| tcfeuv2 | 2 | PurposeLegitimateInterests | Boolean array of size 24 | +| tcfeuv2 | 2 | PurposeOneTreatment | Boolean | +| tcfeuv2 | 2 | PublisherCountryCode | 2 character country code | +| tcfeuv2 | 2 | VendorConsents | Integer array of variable size | +| tcfeuv2 | 2 | VendorLegitimateInterests | Integer array of variable size | +| tcfeuv2 | 2 | PublisherRestrictions | Integer array of variable size | +| tcfeuv2 | 2 | PublisherPurposesSegmentType | 3 bit int. Value is 3 | +| tcfeuv2 | 2 | PublisherConsents | Boolean array of size 24 | +| tcfeuv2 | 2 | PublisherLegitimateInterests | Boolean array of size 24 | +| tcfeuv2 | 2 | NumCustomPurposes | 6 bit int | +| tcfeuv2 | 2 | PublisherCustomConsents | Boolean array where size is set by the NumCustomPurposes field | +| tcfeuv2 | 2 | PublisherCustomLegitimateInterests | Boolean array where size is set by the NumCustomPurposes field | +| tcfeuv2 | 2 | VendorsAllowedSegmentType | 3 bit int. Value is 2 | +| tcfeuv2 | 2 | VendorsAllowed | Integer array of variable size | +| tcfeuv2 | 2 | VendorsDisclosedSegmentType | 3 bit int. Value is 1 | +| tcfeuv2 | 2 | VendorsDisclosed | Integer array of variable size | +| tcfcav1 | 5 | Version | 6 bit int. Value is 2. | +| tcfcav1 | 5 | Created | Datetime. Updated when any fields are set | +| tcfcav1 | 5 | LastUpdated | Datetime. Updated when any fields are set | +| tcfcav1 | 5 | CmpId | 12 bit int | +| tcfcav1 | 5 | CmpVersion | 12 bit int | +| tcfcav1 | 5 | ConsentScreen | 6 bit int | +| tcfcav1 | 5 | ConsentLanguage | 2 character country code | +| tcfcav1 | 5 | VendorListVersion | 12 bit int | +| tcfcav1 | 5 | TcfPolicyVersion | 6 bit int. Value is 2. | +| tcfcav1 | 5 | UseNonStandardStacks | Boolean | +| tcfcav1 | 5 | SpecialFeatureExpressConsent | Boolean array of size 12 | +| tcfcav1 | 5 | PurposesExpressConsent | Boolean array of size 24 | +| tcfcav1 | 5 | PurposesImpliedConsent | Boolean array of size 24 | +| tcfcav1 | 5 | VendorExpressConsent | Integer array of variable size | +| tcfcav1 | 5 | VendorImpliedConsent | Integer array of variable size | +| tcfcav1 | 5 | PubRestrictions | RangeEntry list of variable size | +| tcfcav1 | 5 | PubPurposesSegmentType | 3 bit int. Value is 3 | +| tcfcav1 | 5 | PubPurposesExpressConsent | Boolean array of size 24 | +| tcfcav1 | 5 | PubPurposesImpliedConsent | Boolean array of size 24 | +| tcfcav1 | 5 | NumCustomPurposes | 6 bit int | +| tcfcav1 | 5 | CustomPurposesExpressConsent | Boolean array where size is set by the NumCustomPurposes field | +| tcfcav1 | 5 | CustomPurposesImpliedConsent | Boolean array where size is set by the NumCustomPurposes field | +| tcfcav1 | 5 | DisclosedVendorsSegmentType | 3 bit int. Value is 1 | +| tcfcav1 | 5 | DisclosedVendors | Integer list of variable size | +| uspv1 | 6 | Version | 6 bit int. Value is 1 | +| uspv1 | 6 | Notice | 2 bit int | +| uspv1 | 6 | OptOutSale | 2 bit int | +| uspv1 | 6 | LspaCovered | 2 bit int | +| usnat | 7 | Version | 6 bit int. Value is 1 | +| usnat | 7 | SharingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | SharingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | SensitiveDataProcessingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | SensitiveDataLimitUseNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | SharingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | SensitiveDataProcessing | 2 bit int array of size 16. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | KnownChildSensitiveDataConsents | 2 bit int array of size 3. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | PersonalDataConsents | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnat | 7 | GpcSegmentType | 2 bit int. Value is 1 | +| usnat | 7 | GpcSegmentIncluded | Boolean. Default is true | +| usnat | 7 | Gpc | Boolean | +| usca | 8 | Version | 6 bit int. Value is 1 | +| usca | 8 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | SharingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | SensitiveDataLimitUseNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | SharingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | SensitiveDataProcessing | 2 bit int array of size 9. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | KnownChildSensitiveDataConsents | 2 bit int array of size 2. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | PersonalDataConsents | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usca | 8 | GpcSegmentType | 2 bit int. Value is 1 | +| usca | 8 | GpcSegmentIncluded | Boolean. Default is true | +| usca | 8 | Gpc | Boolean | +| usva | 9 | Version | 6 bit int. Value is 1 | +| usva | 9 | SharingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usva | 9 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usva | 9 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usva | 9 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usva | 9 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usva | 9 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| usva | 9 | KnownChildSensitiveDataConsents | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usva | 9 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usva | 9 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usva | 9 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | Version | 6 bit int. Value is 1 | +| usco | 10 | SharingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | SensitiveDataProcessing | 2 bit int array of size 7. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | KnownChildSensitiveDataConsents | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usco | 10 | GpcSegmentType | 2 bit int. Value is 1 | +| usco | 10 | GpcSegmentIncluded | Boolean. Deafult is true | +| usco | 10 | Gpc | Boolean | +| usut | 11 | Version | 6 bit int. Value is 1 | +| usut | 11 | SharingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usut | 11 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usut | 11 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usut | 11 | SensitiveDataProcessingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usut | 11 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usut | 11 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usut | 11 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| usut | 11 | KnownChildSensitiveDataConsents | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usut | 11 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usut | 11 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usut | 11 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | Version | 6 bit int. Value is 1 | +| usct | 12 | SharingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | KnownChildSensitiveDataConsents | 2 bit int array of size 3. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usct | 12 | GpcSegmentType | 2 bit int. Value is 1 | +| usct | 12 | GpcSegmentIncluded | Boolean. Default is true | +| usct | 12 | Gpc | Boolean | +| usfl | 13 | Version | 6 bit int. Value is 1 | +| usfl | 13 | ProcessingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usfl | 13 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usfl | 13 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usfl | 13 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usfl | 13 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usfl | 13 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| usfl | 13 | KnownChildSensitiveDataConsents | 2 bit int array of size 3. 0=Not applicable, 1=Yes, 2=No | +| usfl | 13 | AdditionalDataProcessingConsent | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usfl | 13 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usfl | 13 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usfl | 13 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | Version | 6 bit int. Value is 1 | +| usmt | 14 | SharingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | KnownChildSensitiveDataConsents | 2 bit int array of size 3. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | AdditionalDataProcessingConsent | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmt | 14 | GpcSegmentType | 2 bit int. Value is 1 | +| usmt | 14 | GpcSegmentIncluded | Boolean. Default is true | +| usmt | 14 | Gpc | Boolean | +| usor | 15 | Version | 6 bit int. Value is 1 | +| usor | 15 | ProcessingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | SensitiveDataProcessing | 2 bit int array of size 11. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | KnownChildSensitiveDataConsents | 2 bit int array of size 3. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | AdditionalDataProcessingConsent | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usor | 15 | GpcSegmentType | 2 bit int. Value is 1 | +| usor | 15 | GpcSegmentIncluded | Boolean. Default is true | +| usor | 15 | Gpc | Boolean | +| ustx | 16 | Version | 6 bit int. Value is 1 | +| ustx | 16 | ProcessingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | KnownChildSensitiveDataConsents | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | AdditionalDataProcessingConsent | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustx | 16 | GpcSegmentType | 2 bit int. Value is 1 | +| ustx | 16 | GpcSegmentIncluded | Boolean. Default is true | +| ustx | 16 | Gpc | Boolean | +| usde | 17 | Version | 6 bit int. Value is 1 | +| usde | 17 | ProcessingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | SensitiveDataProcessing | 2 bit int array of size 9. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | KnownChildSensitiveDataConsents | 2 bit int array of size 5. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | AdditionalDataProcessingConsent | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usde | 17 | GpcSegmentType | 2 bit int. Value is 1 | +| usde | 17 | GpcSegmentIncluded | Boolean. Default is true | +| usde | 17 | Gpc | Boolean | +| usia | 18 | Version | 6 bit int. Value is 1 | +| usia | 18 | ProcessingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | SensitiveDataOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | KnownChildSensitiveDataConsents | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usia | 18 | GpcSegmentType | 2 bit int. Value is 1 | +| usia | 18 | GpcSegmentIncluded | Boolean. Default is true | +| usia | 18 | Gpc | Boolean | +| usne | 19 | Version | 6 bit int. Value is 1 | +| usne | 19 | ProcessingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | KnownChildSensitiveDataConsents | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | AdditionalDataProcessingConsent | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usne | 19 | GpcSegmentType | 2 bit int. Value is 1 | +| usne | 19 | GpcSegmentIncluded | Boolean. Default is true | +| usne | 19 | Gpc | Boolean | +| usnh | 20 | Version | 6 bit int. Value is 1 | +| usnh | 20 | ProcessingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | KnownChildSensitiveDataConsents | 2 bit int array of size 3. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | AdditionalDataProcessingConsent | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnh | 20 | GpcSegmentType | 2 bit int. Value is 1 | +| usnh | 20 | GpcSegmentIncluded | Boolean. Default is true | +| usnh | 20 | Gpc | Boolean | +| usnj | 21 | Version | 6 bit int. Value is 1 | +| usnj | 21 | ProcessingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | SensitiveDataProcessing | 2 bit int array of size 10. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | KnownChildSensitiveDataConsents | 2 bit int array of size 5. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | AdditionalDataProcessingConsent | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usnj | 21 | GpcSegmentType | 2 bit int. Value is 1 | +| usnj | 21 | GpcSegmentIncluded | Boolean. Default is true | +| usnj | 21 | Gpc | Boolean | +| ustn | 22 | Version | 6 bit int. Value is 1 | +| ustn | 22 | ProcessingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | KnownChildSensitiveDataConsents | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | AdditionalDataProcessingConsent | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| ustn | 22 | GpcSegmentType | 2 bit int. Value is 1 | +| ustn | 22 | GpcSegmentIncluded | Boolean. Default is true | +| ustn | 22 | Gpc | Boolean | +| usmn | 23 | Version | 6 bit int. Value is 1 | +| usmn | 23 | ProcessingNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | SaleOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | TargetedAdvertisingOptOutNotice | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | SaleOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | TargetedAdvertisingOptOut | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | SensitiveDataProcessing | 2 bit int array of size 8. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | KnownChildSensitiveDataConsents | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | AdditionalDataProcessingConsent | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | MspaCoveredTransaction | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | MspaOptOutOptionMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | MspaServiceProviderMode | 2 bit int. 0=Not applicable, 1=Yes, 2=No | +| usmn | 23 | GpcSegmentType | 2 bit int. Value is 1 | +| usmn | 23 | GpcSegmentIncluded | Boolean. Default is true | +| usmn | 23 | Gpc | Boolean | ## Contributing Here you can find the [contributing guide](CONTRIBUTING.md) to help maintain and update the library. This library is managed by the Code Libraries Subgroup of the Global Privacy Working Group at the IAB Tech Lab. To join the group, please reach out to support@iabtechlab.com. diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java index b4f8cba3..2eef8aa5 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java @@ -10,28 +10,7 @@ import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.HeaderV1Field; -import com.iab.gpp.encoder.section.EncodableSection; -import com.iab.gpp.encoder.section.HeaderV1; -import com.iab.gpp.encoder.section.Sections; -import com.iab.gpp.encoder.section.TcfCaV1; -import com.iab.gpp.encoder.section.TcfEuV2; -import com.iab.gpp.encoder.section.UsCa; -import com.iab.gpp.encoder.section.UsCo; -import com.iab.gpp.encoder.section.UsCt; -import com.iab.gpp.encoder.section.UsDe; -import com.iab.gpp.encoder.section.UsFl; -import com.iab.gpp.encoder.section.UsIa; -import com.iab.gpp.encoder.section.UsMt; -import com.iab.gpp.encoder.section.UsNat; -import com.iab.gpp.encoder.section.UsNe; -import com.iab.gpp.encoder.section.UsNh; -import com.iab.gpp.encoder.section.UsNj; -import com.iab.gpp.encoder.section.UsOr; -import com.iab.gpp.encoder.section.UsTn; -import com.iab.gpp.encoder.section.UsTx; -import com.iab.gpp.encoder.section.UsUt; -import com.iab.gpp.encoder.section.UsVa; -import com.iab.gpp.encoder.section.UspV1; +import com.iab.gpp.encoder.section.*; public class GppModel { private Map sections = new HashMap<>(); @@ -119,6 +98,9 @@ public void setFieldValue(String sectionName, String fieldName, Object value) { } else if (sectionName.equals(UsTn.NAME)) { section = new UsTn(); this.sections.put(UsTn.NAME, section); + } else if (sectionName.equals(UsMn.NAME)) { + section = new UsMn(); + this.sections.put(UsMn.NAME, section); } } else { section = this.sections.get(sectionName); @@ -316,6 +298,10 @@ public UsTn getUsTnSection() { return (UsTn) getSection(UsTn.NAME); } + public UsMn getUsMnSection() { + return (UsMn) getSection(UsMn.NAME); + } + public List getSectionIds() { if (!this.decoded) { this.sections = this.decodeModel(this.encodedString); @@ -427,6 +413,9 @@ protected Map decodeModel(String str) { } else if (sectionIds.get(i).equals(UsTn.ID)) { UsTn section = new UsTn(encodedSections[i + 1]); sections.put(UsTn.NAME, section); + } else if (sectionIds.get(i).equals(UsMn.ID)) { + UsMn section = new UsMn(encodedSections[i + 1]); + sections.put(UsMn.NAME, section); } } } @@ -537,6 +526,9 @@ public void decodeSection(String sectionName, String encodedString) { }else if (sectionName.equals(UsTn.NAME)) { section = new UsTn(); this.sections.put(UsTn.NAME, section); + }else if (sectionName.equals(UsMn.NAME)) { + section = new UsMn(); + this.sections.put(UsMn.NAME, section); } } else { section = this.sections.get(sectionName); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMnField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMnField.java new file mode 100644 index 00000000..c86f828f --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMnField.java @@ -0,0 +1,48 @@ +package com.iab.gpp.encoder.field; + +import java.util.Arrays; +import java.util.List; + +public class UsMnField { + + public static String VERSION = "Version"; + public static String PROCESSING_NOTICE = "ProcessingNotice"; + public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice"; + public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice"; + public static String SALE_OPT_OUT = "SaleOptOut"; + public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut"; + public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing"; + public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents"; + public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent"; + public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction"; + public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode"; + public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode"; + + public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; + public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; + public static String GPC = "Gpc"; + + //@formatter:off + public static List USMN_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsMnField.VERSION, + UsMnField.PROCESSING_NOTICE, + UsMnField.SALE_OPT_OUT_NOTICE, + UsMnField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsMnField.SALE_OPT_OUT, + UsMnField.TARGETED_ADVERTISING_OPT_OUT, + UsMnField.SENSITIVE_DATA_PROCESSING, + UsMnField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsMnField.ADDITIONAL_DATA_PROCESSING_CONSENT, + UsMnField.MSPA_COVERED_TRANSACTION, + UsMnField.MSPA_OPT_OUT_OPTION_MODE, + UsMnField.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on + + //@formatter:off + public static List USMN_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsMnField.GPC_SEGMENT_TYPE, + UsMnField.GPC + }); + //@formatter:on +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java index 976805d3..fb69587c 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java @@ -34,6 +34,7 @@ public class Sections { SECTION_ID_NAME_MAP.put(UsNh.ID, UsNh.NAME); SECTION_ID_NAME_MAP.put(UsNj.ID, UsNj.NAME); SECTION_ID_NAME_MAP.put(UsTn.ID, UsTn.NAME); + SECTION_ID_NAME_MAP.put(UsMn.ID, UsMn.NAME); SECTION_ORDER = new ArrayList(SECTION_ID_NAME_MAP.keySet()).stream().sorted() .map(id -> SECTION_ID_NAME_MAP.get(id)).collect(Collectors.toList()); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsMn.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsMn.java new file mode 100644 index 00000000..961f4a91 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsMn.java @@ -0,0 +1,141 @@ +package com.iab.gpp.encoder.section; + +import com.iab.gpp.encoder.field.UsMnField; +import com.iab.gpp.encoder.segment.*; + +import java.util.ArrayList; +import java.util.List; + +public class UsMn extends AbstractLazilyEncodableSection { + + public static int ID = 23; + public static int VERSION = 1; + public static String NAME = "usmn"; + + public UsMn() { + super(); + } + + public UsMn(String encodedString) { + super(); + decode(encodedString); + } + + @Override + public int getId() { + return UsMn.ID; + } + + @Override + public String getName() { + return UsMn.NAME; + } + + @Override + public int getVersion() { + return UsMn.VERSION; + } + + @Override + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsMnCoreSegment()); + segments.add(new UsMnGpcSegment()); + return segments; + } + + @Override + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if (encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if (encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if (encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsMnField.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsMnField.GPC_SEGMENT_INCLUDED, false); + } + } + + return segments; + } + + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if (!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if (segments.size() >= 2 && segments.get(1).getFieldValue(UsMnField.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); + } + + + public Integer getProcessingNotice() { + return (Integer) this.getFieldValue(UsMnField.PROCESSING_NOTICE); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.getFieldValue(UsMnField.SALE_OPT_OUT_NOTICE); + } + + public Integer getTargetedAdvertisingOptOutNotice() { + return (Integer) this.getFieldValue(UsMnField.TARGETED_ADVERTISING_OPT_OUT_NOTICE); + } + + public Integer getSaleOptOut() { + return (Integer) this.getFieldValue(UsMnField.SALE_OPT_OUT); + } + + public Integer getTargetedAdvertisingOptOut() { + return (Integer) this.getFieldValue(UsMnField.TARGETED_ADVERTISING_OPT_OUT); + } + + @SuppressWarnings("unchecked") + public List getSensitiveDataProcessing() { + return (List) this.getFieldValue(UsMnField.SENSITIVE_DATA_PROCESSING); + } + + @SuppressWarnings("unchecked") + public Integer getKnownChildSensitiveDataConsents() { + return (Integer) this.getFieldValue(UsMnField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); + } + + public Integer getAdditionalDataProcessingConsent() { + return (Integer) this.getFieldValue(UsMnField.ADDITIONAL_DATA_PROCESSING_CONSENT); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.getFieldValue(UsMnField.MSPA_COVERED_TRANSACTION); + } + + public Integer getMspaOptOutOptionMode() { + return (Integer) this.getFieldValue(UsMnField.MSPA_OPT_OUT_OPTION_MODE); + } + + public Integer getMspaServiceProviderMode() { + return (Integer) this.getFieldValue(UsMnField.MSPA_SERVICE_PROVIDER_MODE); + } + + public Integer getGpcSegmentType() { + return (Integer) this.getFieldValue(UsMnField.GPC_SEGMENT_TYPE); + } + + public Boolean getGpcSegmentIncluded() { + return (Boolean) this.getFieldValue(UsMnField.GPC_SEGMENT_INCLUDED); + } + + public Boolean getGpc() { + return (Boolean) this.getFieldValue(UsMnField.GPC); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsDeCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsDeCoreSegment.java index a011faa0..72953219 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsDeCoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsDeCoreSegment.java @@ -11,7 +11,6 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsDeField; -import com.iab.gpp.encoder.field.UsVaField; import com.iab.gpp.encoder.section.UsDe; public class UsDeCoreSegment extends AbstractLazilyEncodableSegment { @@ -61,7 +60,7 @@ protected EncodableBitStringFields initializeFields() { fields.put(UsDeField.SENSITIVE_DATA_PROCESSING, new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0)) .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); - fields.put(UsVaField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + fields.put(UsDeField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0)) .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); fields.put(UsDeField.ADDITIONAL_DATA_PROCESSING_CONSENT, diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsIaCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsIaCoreSegment.java index 9cd9a917..aa3bd706 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsIaCoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsIaCoreSegment.java @@ -11,7 +11,6 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsIaField; -import com.iab.gpp.encoder.field.UsVaField; import com.iab.gpp.encoder.section.UsIa; public class UsIaCoreSegment extends AbstractLazilyEncodableSegment { @@ -63,7 +62,7 @@ protected EncodableBitStringFields initializeFields() { fields.put(UsIaField.SENSITIVE_DATA_PROCESSING, new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); - fields.put(UsVaField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + fields.put(UsIaField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsIaField.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMnCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMnCoreSegment.java new file mode 100644 index 00000000..1d48ea10 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMnCoreSegment.java @@ -0,0 +1,97 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsMnField; +import com.iab.gpp.encoder.section.UsMn; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +public class UsMnCoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsMnCoreSegment() { + super(); + } + + public UsMnCoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsMnField.USMN_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsMnField.VERSION, new EncodableFixedInteger(6, UsMn.VERSION)); + fields.put(UsMnField.PROCESSING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMnField.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMnField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMnField.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMnField.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMnField.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsMnField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMnField.ADDITIONAL_DATA_PROCESSING_CONSENT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMnField.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMnField.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMnField.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsMnCoreSegment '" + encodedString + "'", e); + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMnGpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMnGpcSegment.java new file mode 100644 index 00000000..fbeb9df0 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMnGpcSegment.java @@ -0,0 +1,61 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsMnField; + +import java.util.List; + +public class UsMnGpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsMnGpcSegment() { + super(); + } + + public UsMnGpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsMnField.USMN_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsMnField.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsMnField.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsMnField.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsMnGpcSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNeCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNeCoreSegment.java index 7a98c30f..626b9c93 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNeCoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNeCoreSegment.java @@ -11,7 +11,6 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsNeField; -import com.iab.gpp.encoder.field.UsVaField; import com.iab.gpp.encoder.section.UsNe; public class UsNeCoreSegment extends AbstractLazilyEncodableSegment { @@ -61,7 +60,7 @@ protected EncodableBitStringFields initializeFields() { fields.put(UsNeField.SENSITIVE_DATA_PROCESSING, new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); - fields.put(UsVaField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + fields.put(UsNeField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsNeField.ADDITIONAL_DATA_PROCESSING_CONSENT, new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsTxCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsTxCoreSegment.java index 53463d20..a983a2ce 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsTxCoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsTxCoreSegment.java @@ -11,7 +11,6 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsTxField; -import com.iab.gpp.encoder.field.UsVaField; import com.iab.gpp.encoder.section.UsTx; public class UsTxCoreSegment extends AbstractLazilyEncodableSegment { @@ -61,7 +60,7 @@ protected EncodableBitStringFields initializeFields() { fields.put(UsTxField.SENSITIVE_DATA_PROCESSING, new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); - fields.put(UsVaField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + fields.put(UsTxField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsTxField.ADDITIONAL_DATA_PROCESSING_CONSENT, new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index d1890a59..bb5f2336 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -4,22 +4,11 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; + +import com.iab.gpp.encoder.field.*; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.field.TcfCaV1Field; -import com.iab.gpp.encoder.field.TcfEuV2Field; -import com.iab.gpp.encoder.field.UsCaField; -import com.iab.gpp.encoder.field.UsCoField; -import com.iab.gpp.encoder.field.UsCtField; -import com.iab.gpp.encoder.field.UsFlField; -import com.iab.gpp.encoder.field.UsMtField; -import com.iab.gpp.encoder.field.UsNatField; -import com.iab.gpp.encoder.field.UsOrField; -import com.iab.gpp.encoder.field.UsTxField; -import com.iab.gpp.encoder.field.UsUtField; -import com.iab.gpp.encoder.field.UsVaField; -import com.iab.gpp.encoder.field.UspV1Field; import com.iab.gpp.encoder.section.TcfCaV1; import com.iab.gpp.encoder.section.TcfEuV2; import com.iab.gpp.encoder.section.UsCa; @@ -28,6 +17,7 @@ import com.iab.gpp.encoder.section.UsDe; import com.iab.gpp.encoder.section.UsFl; import com.iab.gpp.encoder.section.UsIa; +import com.iab.gpp.encoder.section.UsMn; import com.iab.gpp.encoder.section.UsMt; import com.iab.gpp.encoder.section.UsNat; import com.iab.gpp.encoder.section.UsNe; @@ -92,6 +82,7 @@ public void testEncodeDefaultAll() { Assertions.assertEquals(false, gppModel.hasSection(UsNh.NAME)); Assertions.assertEquals(false, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(false, gppModel.hasSection(UsTn.NAME)); + Assertions.assertEquals(false, gppModel.hasSection(UsMn.NAME)); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VERSION, TcfEuV2.VERSION); gppModel.setFieldValue(TcfEuV2.NAME, TcfCaV1Field.CREATED, utcDateTime); @@ -110,12 +101,13 @@ public void testEncodeDefaultAll() { gppModel.setFieldValue(UsMt.NAME, UsMtField.VERSION, UsMt.VERSION); gppModel.setFieldValue(UsOr.NAME, UsOrField.VERSION, UsOr.VERSION); gppModel.setFieldValue(UsTx.NAME, UsTxField.VERSION, UsTx.VERSION); - gppModel.setFieldValue(UsDe.NAME, UsTxField.VERSION, UsTx.VERSION); - gppModel.setFieldValue(UsIa.NAME, UsTxField.VERSION, UsTx.VERSION); - gppModel.setFieldValue(UsNe.NAME, UsTxField.VERSION, UsTx.VERSION); - gppModel.setFieldValue(UsNh.NAME, UsTxField.VERSION, UsTx.VERSION); - gppModel.setFieldValue(UsNj.NAME, UsTxField.VERSION, UsTx.VERSION); - gppModel.setFieldValue(UsTn.NAME, UsTxField.VERSION, UsTx.VERSION); + gppModel.setFieldValue(UsDe.NAME, UsDeField.VERSION, UsDe.VERSION); + gppModel.setFieldValue(UsIa.NAME, UsIaField.VERSION, UsIa.VERSION); + gppModel.setFieldValue(UsNe.NAME, UsNeField.VERSION, UsNe.VERSION); + gppModel.setFieldValue(UsNh.NAME, UsNhField.VERSION, UsNh.VERSION); + gppModel.setFieldValue(UsNj.NAME, UsNjField.VERSION, UsNj.VERSION); + gppModel.setFieldValue(UsTn.NAME, UsTnField.VERSION, UsTn.VERSION); + gppModel.setFieldValue(UsMn.NAME, UsMnField.VERSION, UsMn.VERSION); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -137,10 +129,11 @@ public void testEncodeDefaultAll() { Assertions.assertEquals(true, gppModel.hasSection(UsNh.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsTn.NAME)); + Assertions.assertEquals(true, gppModel.hasSection(UsMn.NAME)); String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOdM~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA", + "DBACOYs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA", gppString); } @@ -413,7 +406,7 @@ public void testDecodeDefaults() { @Test public void testDecodeDefaultsAll() { String gppString = - "DBACOdM~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA"; + "DBACOYs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAABAA.QA"; GppModel gppModel = new GppModel(gppString); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -435,6 +428,7 @@ public void testDecodeDefaultsAll() { Assertions.assertEquals(true, gppModel.hasSection(UsNh.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsTn.NAME)); + Assertions.assertEquals(true, gppModel.hasSection(UsMn.NAME)); } @Test diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerRangeEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerRangeEncoderTest.java index f0cb813f..1cae6e34 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerRangeEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerRangeEncoderTest.java @@ -102,6 +102,6 @@ public void testDecode8() { @Test public void testGiantRange() { String max = FibonacciIntegerEncoder.encode(FibonacciIntegerRangeEncoder.MAX_SIZE + 1); - Assertions.assertEquals(List.of(), FibonacciIntegerRangeEncoder.decode("000000000001111" + max)); + Assertions.assertEquals(new ArrayList<>(), FibonacciIntegerRangeEncoder.decode("000000000001111" + max)); } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerRangeEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerRangeEncoderTest.java index 769763ea..b781cd4c 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerRangeEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerRangeEncoderTest.java @@ -132,6 +132,6 @@ public void testDecode10() { @Test public void testGiantRange() { String max = FibonacciIntegerEncoder.encode(FibonacciIntegerRangeEncoder.MAX_SIZE + 1); - Assertions.assertEquals(List.of(), FixedIntegerRangeEncoder.decode("00000000000110000000000000001" + max)); + Assertions.assertEquals(new ArrayList<>(), FixedIntegerRangeEncoder.decode("00000000000110000000000000001" + max)); } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/.UsNatV1Test.java.swp b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/.UsNatV1Test.java.swp deleted file mode 100644 index 686ae751e38ab4870c28793ce259a9eb4aa5eaa3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI3UyKt)9LI;hry!v4pz+1E@X(re%N<4{M8nc9N5l0G-MylQr0#9!?w0Fy*WK+M z|4Dez7@v$WknrLQ2@fR3m|%19M8uaAy;=NC9qd!@9K z$ZGm-)0{{YY*Vb7x>oHdb<#JOoHp$V$I^6~G_(O@sMP|{<+)*_@!4=>Nkac9+K)-*fZ;m`GY}z=? zHQ@?y1-JrS0j>a7fGfZi;0kaB9wG%?tB;&Qf0wg9o9umA+xr7{)Y*BfE&Xqn9+dy3 zE&V=A56Y>mf}oyzEd6y>?pj;=Uo3ryrEg&k4$9wU=})nAt1X?K=5Jg9t^iknE5H@t z3UCFu0$c&E09Sx3z!i8X70@b#Jc*v)@)pu~{vWL0uWumaNALr<3eEr*>;h}R_4P;x zSHNX(37iFIfDQUV0>r@+YGcqBUK=587hwl$-FaKqAc zZe19iPu^bawW-{bi59VYD&OWbJvDmul(N4Edm!W>7vUZycI=nL{d2fS0S9x^f%oim z-KeVFcQ;zpA8rxLq*vjl1FN1h$6|#Tla^__0``rI*kmqZ-#GKqwm9l7Kt$FGf9h+gX#$TBlKH8Xmf z-o?6WRKLu~A|0Jb-dE*zMgPJ{pd-m2vPBexVHXAu}?~h=H_Z)^rrbZE-qBG$r zGW)#VZ~f^=KkxPEngyR9mY#n*XEUF56L{wqw?`YFcx(6rNo{7li-Vkk2JZ zXLu(T>fFAXIbBPQ8`X+JYmVU>Q}kcjpEYXK3@C+b57mhw(y8O%E4pB>!ULpgHU^tk zqzV*v4bMVjyt=f*E|A{JYE{}>!B*Laj7h^Cc4%;oE-<)Z8RihP(W;&-&M9n9) { + new UsMn("z").getProcessingNotice(); + }); + } +} From 394f4226efbb4310e02604f25c89c9aac12ff075 Mon Sep 17 00:00:00 2001 From: xdevanshux Date: Fri, 13 Feb 2026 19:11:16 +0530 Subject: [PATCH 09/22] changes --- .github/workflows/main.yml | 44 +++++++++++++++++++++++++++----------- pom.xml | 17 ++++++++++----- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3b0cdcf3..f40adc9e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,3 +1,13 @@ +# Release to Maven Central via Central Publisher Portal +# https://central.sonatype.org/publish/publish-portal-guide/ +# +# Required GitHub secrets (Settings → Secrets and variables → Actions): +# CENTRAL_TOKEN_USERNAME - Portal token username (from https://central.sonatype.com/usertoken) +# CENTRAL_TOKEN_PASSWORD - Portal token password (from same page; save on first view, cannot be retrieved later) +# GPG_SECRET_KEY - Armored GPG private key for signing +# GPG_PASSPHRASE - Passphrase for the GPG key +# PAT - Personal access token with repo scope (for pushing commits/tags) +# name: IABGPP-Java Release on: @@ -14,15 +24,15 @@ jobs: steps: # Checkout the repository with full history for tagging - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - # Set up Java (assuming Java 11, adjust if different) + # Set up Java - name: Set up Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: - distribution: 'adopt' + distribution: 'temurin' java-version: '21' # Import GPG secret key for signing @@ -31,16 +41,26 @@ jobs: echo "${{ secrets.GPG_SECRET_KEY }}" > secret_key.asc gpg --import --no-tty --batch secret_key.asc || { echo "GPG import failed"; cat secret_key.asc; exit 1; } rm -f secret_key.asc - # gpg --list-secret-keys - - # Generate settings.xml with Maven repository credentials + # Generate settings.xml with Central Publisher Portal token credentials + # Token from: https://central.sonatype.com/usertoken - name: Create settings.xml + env: + CENTRAL_TOKEN_USERNAME: ${{ secrets.CENTRAL_TOKEN_USERNAME }} + CENTRAL_TOKEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN_PASSWORD }} run: | mkdir -p ~/.m2 cat > ~/.m2/settings.xml << EOF - - ~/.m2 false false org.sonatype.plugins sonatype-nexus-snapshots TiW/t45q ${{ secrets.SONATYPE_PWD }} sonatype-nexus-staging TiW/t45q ${{ secrets.SONATYPE_PWD_STAGING }} + + + + central + ${CENTRAL_TOKEN_USERNAME} + ${CENTRAL_TOKEN_PASSWORD} + + EOF @@ -52,14 +72,13 @@ jobs: - name: Set release version run: mvn versions:set -DnewVersion=${{ github.event.inputs.version }} -DgenerateBackupPoms=false - # Build and deploy the release + # Build and deploy to Central Publisher Portal (mvn deploy uploads bundle and publishes) - name: Deploy release run: | echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf echo "use-agent" >> ~/.gnupg/gpg.conf export GPG_TTY=$(tty || echo /dev/tty) mvn clean deploy --settings ~/.m2/settings.xml -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" -Prelease - # mvn clean deploy --settings ~/.m2/settings.xml -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" -Prelease -Dmaven.javadoc.skip=true # Commit the release version and create a tag - name: Commit and tag release @@ -80,7 +99,6 @@ jobs: NEW_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) git add . git commit -m "$NEW_VERSION" - # git commit -m "${{ github.event.inputs.version }}-SNAPSHOT" # Push commits and tags to GitHub - name: Push changes @@ -88,4 +106,4 @@ jobs: git status git push; git push --tags env: - GITHUB_TOKEN: ${{secrets.PAT}} + GITHUB_TOKEN: ${{ secrets.PAT }} diff --git a/pom.xml b/pom.xml index 892005fc..9b5db157 100644 --- a/pom.xml +++ b/pom.xml @@ -40,11 +40,7 @@ Sonatype Nexus Snapshots https://s01.oss.sonatype.org/content/repositories/snapshots/ - - sonatype-nexus-staging - Nexus Release Repository - https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ - + @@ -113,6 +109,17 @@ release + + org.sonatype.central + central-publishing-maven-plugin + 0.10.0 + true + + central + true + published + + org.apache.maven.plugins maven-source-plugin From e86498dde48197eb40ecc0c4fcdafc6e9d198c30 Mon Sep 17 00:00:00 2001 From: xdevanshux Date: Fri, 13 Feb 2026 19:24:08 +0530 Subject: [PATCH 10/22] name added --- iabgpp-encoder/pom.xml | 1 + iabgpp-extras-jackson/pom.xml | 1 + iabgpp-extras/pom.xml | 1 + 3 files changed, 3 insertions(+) diff --git a/iabgpp-encoder/pom.xml b/iabgpp-encoder/pom.xml index 03e794e5..15b510da 100644 --- a/iabgpp-encoder/pom.xml +++ b/iabgpp-encoder/pom.xml @@ -11,6 +11,7 @@ iabgpp-encoder + IAB GPP Encoder jar diff --git a/iabgpp-extras-jackson/pom.xml b/iabgpp-extras-jackson/pom.xml index 99819c6e..a36e8163 100644 --- a/iabgpp-extras-jackson/pom.xml +++ b/iabgpp-extras-jackson/pom.xml @@ -11,6 +11,7 @@ iabgpp-extras-jackson + IAB GPP Extras Jackson jar diff --git a/iabgpp-extras/pom.xml b/iabgpp-extras/pom.xml index 592a99ad..50e163f9 100644 --- a/iabgpp-extras/pom.xml +++ b/iabgpp-extras/pom.xml @@ -11,6 +11,7 @@ iabgpp-extras + IAB GPP Extras jar From 7d56a34e813e7113340510aecd6b9c1e1db8cf6c Mon Sep 17 00:00:00 2001 From: Mayank Mishra Date: Fri, 13 Feb 2026 15:19:19 +0000 Subject: [PATCH 11/22] 3.2.5 --- iabgpp-encoder/pom.xml | 2 +- iabgpp-extras-jackson/pom.xml | 4 ++-- iabgpp-extras/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iabgpp-encoder/pom.xml b/iabgpp-encoder/pom.xml index 15b510da..d5a68287 100644 --- a/iabgpp-encoder/pom.xml +++ b/iabgpp-encoder/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.2.5-SNAPSHOT + 3.2.5 iabgpp-encoder diff --git a/iabgpp-extras-jackson/pom.xml b/iabgpp-extras-jackson/pom.xml index a36e8163..fd69d00c 100644 --- a/iabgpp-extras-jackson/pom.xml +++ b/iabgpp-extras-jackson/pom.xml @@ -7,7 +7,7 @@ iabgpp-core com.iabgpp - 3.2.5-SNAPSHOT + 3.2.5 iabgpp-extras-jackson @@ -25,7 +25,7 @@ com.iabgpp iabgpp-extras - 3.2.5-SNAPSHOT + 3.2.5 diff --git a/iabgpp-extras/pom.xml b/iabgpp-extras/pom.xml index 50e163f9..eeb0eaf9 100644 --- a/iabgpp-extras/pom.xml +++ b/iabgpp-extras/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.2.5-SNAPSHOT + 3.2.5 iabgpp-extras diff --git a/pom.xml b/pom.xml index 9b5db157..ee00d703 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iabgpp iabgpp-core - 3.2.5-SNAPSHOT + 3.2.5 IAB GPP Core Library https://github.com/IABTechLabs/iabtcf-java Encode and decode consent information with the IAB GPP v3.0. From ab49f071619896480fe0ca287521c40b8381e4cc Mon Sep 17 00:00:00 2001 From: Mayank Mishra Date: Fri, 13 Feb 2026 15:19:25 +0000 Subject: [PATCH 12/22] 3.2.6-SNAPSHOT --- iabgpp-encoder/pom.xml | 2 +- iabgpp-extras-jackson/pom.xml | 4 ++-- iabgpp-extras/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iabgpp-encoder/pom.xml b/iabgpp-encoder/pom.xml index d5a68287..bf84bbbc 100644 --- a/iabgpp-encoder/pom.xml +++ b/iabgpp-encoder/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.2.5 + 3.2.6-SNAPSHOT iabgpp-encoder diff --git a/iabgpp-extras-jackson/pom.xml b/iabgpp-extras-jackson/pom.xml index fd69d00c..bd0d839c 100644 --- a/iabgpp-extras-jackson/pom.xml +++ b/iabgpp-extras-jackson/pom.xml @@ -7,7 +7,7 @@ iabgpp-core com.iabgpp - 3.2.5 + 3.2.6-SNAPSHOT iabgpp-extras-jackson @@ -25,7 +25,7 @@ com.iabgpp iabgpp-extras - 3.2.5 + 3.2.6-SNAPSHOT diff --git a/iabgpp-extras/pom.xml b/iabgpp-extras/pom.xml index eeb0eaf9..61879021 100644 --- a/iabgpp-extras/pom.xml +++ b/iabgpp-extras/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.2.5 + 3.2.6-SNAPSHOT iabgpp-extras diff --git a/pom.xml b/pom.xml index ee00d703..5d5bd6a7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iabgpp iabgpp-core - 3.2.5 + 3.2.6-SNAPSHOT IAB GPP Core Library https://github.com/IABTechLabs/iabtcf-java Encode and decode consent information with the IAB GPP v3.0. From a71f98f6f95902709511cb9b27eab167376e76f6 Mon Sep 17 00:00:00 2001 From: xdevanshux Date: Sat, 18 Apr 2026 21:55:59 +0530 Subject: [PATCH 13/22] Create 4.x-release.yml --- .github/workflows/4.x-release.yml | 109 ++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 .github/workflows/4.x-release.yml diff --git a/.github/workflows/4.x-release.yml b/.github/workflows/4.x-release.yml new file mode 100644 index 00000000..95820f3d --- /dev/null +++ b/.github/workflows/4.x-release.yml @@ -0,0 +1,109 @@ +# Release to Maven Central via Central Publisher Portal +# https://central.sonatype.org/publish/publish-portal-guide/ +# +# Required GitHub secrets (Settings → Secrets and variables → Actions): +# CENTRAL_TOKEN_USERNAME - Portal token username (from https://central.sonatype.com/usertoken) +# CENTRAL_TOKEN_PASSWORD - Portal token password (from same page; save on first view, cannot be retrieved later) +# GPG_SECRET_KEY - Armored GPG private key for signing +# GPG_PASSPHRASE - Passphrase for the GPG key +# PAT - Personal access token with repo scope (for pushing commits/tags) +# +name: IABGPP-Java 4.X Release + +on: + workflow_dispatch: + inputs: + version: + description: 'The release version (e.g., 4.x.x)' + required: true + default: '' + +jobs: + release: + runs-on: ubuntu-latest + steps: + # Checkout the repository with full history for tagging + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Set up Java + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + + # Import GPG secret key for signing + - name: Import GPG key + run: | + echo "${{ secrets.GPG_SECRET_KEY }}" > secret_key.asc + gpg --import --no-tty --batch secret_key.asc || { echo "GPG import failed"; cat secret_key.asc; exit 1; } + rm -f secret_key.asc + + # Generate settings.xml with Central Publisher Portal token credentials + # Token from: https://central.sonatype.com/usertoken + - name: Create settings.xml + env: + CENTRAL_TOKEN_USERNAME: ${{ secrets.CENTRAL_TOKEN_USERNAME }} + CENTRAL_TOKEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN_PASSWORD }} + run: | + mkdir -p ~/.m2 + cat > ~/.m2/settings.xml << EOF + + + + central + ${CENTRAL_TOKEN_USERNAME} + ${CENTRAL_TOKEN_PASSWORD} + + + + EOF + + # Pull latest changes from master + - name: Pull latest changes + run: git pull origin 4.X + + # Set the release version in pom.xml + - name: Set release version + run: mvn versions:set -DnewVersion=${{ github.event.inputs.version }} -DgenerateBackupPoms=false + + # Build and deploy to Central Publisher Portal (mvn deploy uploads bundle and publishes) + - name: Deploy release + run: | + echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf + echo "use-agent" >> ~/.gnupg/gpg.conf + export GPG_TTY=$(tty || echo /dev/tty) + mvn clean deploy --settings ~/.m2/settings.xml -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" -Prelease + + # Commit the release version and create a tag + - name: Commit and tag release + run: | + git config user.email "mayank@iabtechlab.com" + git config user.name "Mayank Mishra" + git add . + git commit -m "${{ github.event.inputs.version }}" + git tag "${{ github.event.inputs.version }}" + + # Set the next snapshot version + - name: Set next snapshot version + run: mvn versions:set -DnextSnapshot=true -DgenerateBackupPoms=false + + # Commit the snapshot version + - name: Commit snapshot version + run: | + NEW_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + git add . + git commit -m "$NEW_VERSION" + + # Push commits and tags to GitHub + - name: Push changes + run: | + git status + git push; git push --tags + env: + GITHUB_TOKEN: ${{ secrets.PAT }} From 1bde2abd677ab47ed5c3201323f0ec9aafd36a1a Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Fri, 5 Jun 2026 15:29:08 -0600 Subject: [PATCH 14/22] Add UsMd section (Maryland, Section ID 24) Implements the Maryland Online Data Privacy Act section per the GPP spec, following the existing UsMn pattern. Core + GPC segments, 9 core fields (MspaVersion, MspaCoveredTransaction, MspaMode, ProcessingNotice, SaleOptOutNotice, TargetedAdvertisingOptOutNotice, SaleOptOut, TargetedAdvertisingOptOut, AdditionalDataProcessingConsent), no SensitiveDataProcessing / KnownChildSensitiveDataConsents per spec. --- .../java/com/iab/gpp/encoder/GppModel.java | 13 ++ .../com/iab/gpp/encoder/field/UsMdField.java | 42 ++++++ .../com/iab/gpp/encoder/section/Sections.java | 1 + .../com/iab/gpp/encoder/section/UsMd.java | 131 ++++++++++++++++++ .../gpp/encoder/segment/UsMdCoreSegment.java | 80 +++++++++++ .../gpp/encoder/segment/UsMdGpcSegment.java | 61 ++++++++ .../com/iab/gpp/encoder/section/UsMdTest.java | 124 +++++++++++++++++ 7 files changed, 452 insertions(+) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMdField.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsMd.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMdCoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMdGpcSegment.java create mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsMdTest.java diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java index 2eef8aa5..7656bd2a 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java @@ -101,6 +101,9 @@ public void setFieldValue(String sectionName, String fieldName, Object value) { } else if (sectionName.equals(UsMn.NAME)) { section = new UsMn(); this.sections.put(UsMn.NAME, section); + } else if (sectionName.equals(UsMd.NAME)) { + section = new UsMd(); + this.sections.put(UsMd.NAME, section); } } else { section = this.sections.get(sectionName); @@ -302,6 +305,10 @@ public UsMn getUsMnSection() { return (UsMn) getSection(UsMn.NAME); } + public UsMd getUsMdSection() { + return (UsMd) getSection(UsMd.NAME); + } + public List getSectionIds() { if (!this.decoded) { this.sections = this.decodeModel(this.encodedString); @@ -416,6 +423,9 @@ protected Map decodeModel(String str) { } else if (sectionIds.get(i).equals(UsMn.ID)) { UsMn section = new UsMn(encodedSections[i + 1]); sections.put(UsMn.NAME, section); + } else if (sectionIds.get(i).equals(UsMd.ID)) { + UsMd section = new UsMd(encodedSections[i + 1]); + sections.put(UsMd.NAME, section); } } } @@ -529,6 +539,9 @@ public void decodeSection(String sectionName, String encodedString) { }else if (sectionName.equals(UsMn.NAME)) { section = new UsMn(); this.sections.put(UsMn.NAME, section); + }else if (sectionName.equals(UsMd.NAME)) { + section = new UsMd(); + this.sections.put(UsMd.NAME, section); } } else { section = this.sections.get(sectionName); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMdField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMdField.java new file mode 100644 index 00000000..5b61810d --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMdField.java @@ -0,0 +1,42 @@ +package com.iab.gpp.encoder.field; + +import java.util.Arrays; +import java.util.List; + +public class UsMdField { + + public static String MSPA_VERSION = "MspaVersion"; + public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction"; + public static String MSPA_MODE = "MspaMode"; + public static String PROCESSING_NOTICE = "ProcessingNotice"; + public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice"; + public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice"; + public static String SALE_OPT_OUT = "SaleOptOut"; + public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut"; + public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent"; + + public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; + public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; + public static String GPC = "Gpc"; + + //@formatter:off + public static List USMD_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsMdField.MSPA_VERSION, + UsMdField.MSPA_COVERED_TRANSACTION, + UsMdField.MSPA_MODE, + UsMdField.PROCESSING_NOTICE, + UsMdField.SALE_OPT_OUT_NOTICE, + UsMdField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsMdField.SALE_OPT_OUT, + UsMdField.TARGETED_ADVERTISING_OPT_OUT, + UsMdField.ADDITIONAL_DATA_PROCESSING_CONSENT + }); + //@formatter:on + + //@formatter:off + public static List USMD_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsMdField.GPC_SEGMENT_TYPE, + UsMdField.GPC + }); + //@formatter:on +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java index fb69587c..d9cad1a1 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java @@ -35,6 +35,7 @@ public class Sections { SECTION_ID_NAME_MAP.put(UsNj.ID, UsNj.NAME); SECTION_ID_NAME_MAP.put(UsTn.ID, UsTn.NAME); SECTION_ID_NAME_MAP.put(UsMn.ID, UsMn.NAME); + SECTION_ID_NAME_MAP.put(UsMd.ID, UsMd.NAME); SECTION_ORDER = new ArrayList(SECTION_ID_NAME_MAP.keySet()).stream().sorted() .map(id -> SECTION_ID_NAME_MAP.get(id)).collect(Collectors.toList()); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsMd.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsMd.java new file mode 100644 index 00000000..dbcb8ece --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsMd.java @@ -0,0 +1,131 @@ +package com.iab.gpp.encoder.section; + +import com.iab.gpp.encoder.field.UsMdField; +import com.iab.gpp.encoder.segment.*; + +import java.util.ArrayList; +import java.util.List; + +public class UsMd extends AbstractLazilyEncodableSection { + + public static int ID = 24; + public static int VERSION = 1; + public static String NAME = "usmd"; + + public UsMd() { + super(); + } + + public UsMd(String encodedString) { + super(); + decode(encodedString); + } + + @Override + public int getId() { + return UsMd.ID; + } + + @Override + public String getName() { + return UsMd.NAME; + } + + @Override + public int getVersion() { + return UsMd.VERSION; + } + + @Override + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsMdCoreSegment()); + segments.add(new UsMdGpcSegment()); + return segments; + } + + @Override + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if (encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if (encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if (encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsMdField.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsMdField.GPC_SEGMENT_INCLUDED, false); + } + } + + return segments; + } + + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if (!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if (segments.size() >= 2 && segments.get(1).getFieldValue(UsMdField.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); + } + + + public Integer getMspaVersion() { + return (Integer) this.getFieldValue(UsMdField.MSPA_VERSION); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.getFieldValue(UsMdField.MSPA_COVERED_TRANSACTION); + } + + public Integer getMspaMode() { + return (Integer) this.getFieldValue(UsMdField.MSPA_MODE); + } + + public Integer getProcessingNotice() { + return (Integer) this.getFieldValue(UsMdField.PROCESSING_NOTICE); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.getFieldValue(UsMdField.SALE_OPT_OUT_NOTICE); + } + + public Integer getTargetedAdvertisingOptOutNotice() { + return (Integer) this.getFieldValue(UsMdField.TARGETED_ADVERTISING_OPT_OUT_NOTICE); + } + + public Integer getSaleOptOut() { + return (Integer) this.getFieldValue(UsMdField.SALE_OPT_OUT); + } + + public Integer getTargetedAdvertisingOptOut() { + return (Integer) this.getFieldValue(UsMdField.TARGETED_ADVERTISING_OPT_OUT); + } + + public Integer getAdditionalDataProcessingConsent() { + return (Integer) this.getFieldValue(UsMdField.ADDITIONAL_DATA_PROCESSING_CONSENT); + } + + public Integer getGpcSegmentType() { + return (Integer) this.getFieldValue(UsMdField.GPC_SEGMENT_TYPE); + } + + public Boolean getGpcSegmentIncluded() { + return (Boolean) this.getFieldValue(UsMdField.GPC_SEGMENT_INCLUDED); + } + + public Boolean getGpc() { + return (Boolean) this.getFieldValue(UsMdField.GPC); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMdCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMdCoreSegment.java new file mode 100644 index 00000000..ae8d1253 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMdCoreSegment.java @@ -0,0 +1,80 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsMdField; +import com.iab.gpp.encoder.section.UsMd; + +import java.util.List; +import java.util.function.Predicate; + +public class UsMdCoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsMdCoreSegment() { + super(); + } + + public UsMdCoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsMdField.USMD_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsMdField.MSPA_VERSION, new EncodableFixedInteger(6, UsMd.VERSION)); + fields.put(UsMdField.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMdField.MSPA_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMdField.PROCESSING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMdField.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMdField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMdField.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMdField.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsMdField.ADDITIONAL_DATA_PROCESSING_CONSENT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsMdCoreSegment '" + encodedString + "'", e); + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMdGpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMdGpcSegment.java new file mode 100644 index 00000000..4f10ae95 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsMdGpcSegment.java @@ -0,0 +1,61 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsMdField; + +import java.util.List; + +public class UsMdGpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsMdGpcSegment() { + super(); + } + + public UsMdGpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsMdField.USMD_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsMdField.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsMdField.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsMdField.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsMdGpcSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsMdTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsMdTest.java new file mode 100644 index 00000000..b44b045f --- /dev/null +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsMdTest.java @@ -0,0 +1,124 @@ +package com.iab.gpp.encoder.section; + + +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; +import com.iab.gpp.encoder.field.UsMdField; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class UsMdTest { + + @Test + public void testEncode1() { + UsMd usMd = new UsMd(); + Assertions.assertEquals("BQAA.QA", usMd.encode()); + } + + @Test + public void testEncode2() { + UsMd usMd = new UsMd(); + + usMd.setFieldValue(UsMdField.MSPA_COVERED_TRANSACTION, 1); + usMd.setFieldValue(UsMdField.MSPA_MODE, 1); + usMd.setFieldValue(UsMdField.PROCESSING_NOTICE, 1); + usMd.setFieldValue(UsMdField.SALE_OPT_OUT_NOTICE, 1); + usMd.setFieldValue(UsMdField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usMd.setFieldValue(UsMdField.SALE_OPT_OUT, 1); + usMd.setFieldValue(UsMdField.TARGETED_ADVERTISING_OPT_OUT, 1); + usMd.setFieldValue(UsMdField.ADDITIONAL_DATA_PROCESSING_CONSENT, 1); + usMd.setFieldValue(UsMdField.GPC, true); + + Assertions.assertEquals("BVVU.YA", usMd.encode()); + } + + @Test + public void testSetInvalidValues() { + UsMd usMd = new UsMd(); + + try { + usMd.setFieldValue(UsMdField.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usMd.setFieldValue(UsMdField.MSPA_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usMd.setFieldValue(UsMdField.PROCESSING_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usMd.setFieldValue(UsMdField.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usMd.setFieldValue(UsMdField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usMd.setFieldValue(UsMdField.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usMd.setFieldValue(UsMdField.TARGETED_ADVERTISING_OPT_OUT, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usMd.setFieldValue(UsMdField.ADDITIONAL_DATA_PROCESSING_CONSENT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + } + + @Test + public void testEncodeWithGpcSegmentExcluded() { + UsMd usMd = new UsMd(); + usMd.setFieldValue(UsMdField.GPC_SEGMENT_INCLUDED, false); + Assertions.assertEquals("BQAA", usMd.encode()); + } + + @Test + public void testDecode1() throws DecodingException { + UsMd usMd = new UsMd("BVVU.YA"); + + Assertions.assertEquals(1, usMd.getMspaCoveredTransaction()); + Assertions.assertEquals(1, usMd.getMspaMode()); + Assertions.assertEquals(1, usMd.getProcessingNotice()); + Assertions.assertEquals(1, usMd.getSaleOptOutNotice()); + Assertions.assertEquals(1, usMd.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usMd.getSaleOptOut()); + Assertions.assertEquals(1, usMd.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(1, usMd.getAdditionalDataProcessingConsent()); + Assertions.assertEquals(true, usMd.getGpc()); + } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsMd("z").getProcessingNotice(); + }); + } +} From 1852478a83b091fa3fcf94865ee8ccab05af1169 Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Fri, 5 Jun 2026 15:31:34 -0600 Subject: [PATCH 15/22] Add UsIn section (Indiana, Section ID 25) Implements the Indiana Consumer Data Protection Act section per the GPP spec, following the UsMn pattern. Core + GPC segments, 11 core fields including SensitiveDataProcessing (8-element N-Bitfield) and KnownChildSensitiveDataConsents. --- .../java/com/iab/gpp/encoder/GppModel.java | 13 ++ .../com/iab/gpp/encoder/field/UsInField.java | 46 ++++++ .../com/iab/gpp/encoder/section/Sections.java | 1 + .../com/iab/gpp/encoder/section/UsIn.java | 140 ++++++++++++++++++ .../gpp/encoder/segment/UsInCoreSegment.java | 95 ++++++++++++ .../gpp/encoder/segment/UsInGpcSegment.java | 61 ++++++++ .../com/iab/gpp/encoder/section/UsInTest.java | 104 +++++++++++++ 7 files changed, 460 insertions(+) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsInField.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsIn.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInCoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInGpcSegment.java create mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsInTest.java diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java index 2eef8aa5..d9d78a95 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java @@ -101,6 +101,9 @@ public void setFieldValue(String sectionName, String fieldName, Object value) { } else if (sectionName.equals(UsMn.NAME)) { section = new UsMn(); this.sections.put(UsMn.NAME, section); + } else if (sectionName.equals(UsIn.NAME)) { + section = new UsIn(); + this.sections.put(UsIn.NAME, section); } } else { section = this.sections.get(sectionName); @@ -302,6 +305,10 @@ public UsMn getUsMnSection() { return (UsMn) getSection(UsMn.NAME); } + public UsIn getUsInSection() { + return (UsIn) getSection(UsIn.NAME); + } + public List getSectionIds() { if (!this.decoded) { this.sections = this.decodeModel(this.encodedString); @@ -416,6 +423,9 @@ protected Map decodeModel(String str) { } else if (sectionIds.get(i).equals(UsMn.ID)) { UsMn section = new UsMn(encodedSections[i + 1]); sections.put(UsMn.NAME, section); + } else if (sectionIds.get(i).equals(UsIn.ID)) { + UsIn section = new UsIn(encodedSections[i + 1]); + sections.put(UsIn.NAME, section); } } } @@ -529,6 +539,9 @@ public void decodeSection(String sectionName, String encodedString) { }else if (sectionName.equals(UsMn.NAME)) { section = new UsMn(); this.sections.put(UsMn.NAME, section); + }else if (sectionName.equals(UsIn.NAME)) { + section = new UsIn(); + this.sections.put(UsIn.NAME, section); } } else { section = this.sections.get(sectionName); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsInField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsInField.java new file mode 100644 index 00000000..287579f0 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsInField.java @@ -0,0 +1,46 @@ +package com.iab.gpp.encoder.field; + +import java.util.Arrays; +import java.util.List; + +public class UsInField { + + public static String MSPA_VERSION = "MspaVersion"; + public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction"; + public static String MSPA_MODE = "MspaMode"; + public static String PROCESSING_NOTICE = "ProcessingNotice"; + public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice"; + public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice"; + public static String SALE_OPT_OUT = "SaleOptOut"; + public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut"; + public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents"; + public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent"; + public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing"; + + public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; + public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; + public static String GPC = "Gpc"; + + //@formatter:off + public static List USIN_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsInField.MSPA_VERSION, + UsInField.MSPA_COVERED_TRANSACTION, + UsInField.MSPA_MODE, + UsInField.PROCESSING_NOTICE, + UsInField.SALE_OPT_OUT_NOTICE, + UsInField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsInField.SALE_OPT_OUT, + UsInField.TARGETED_ADVERTISING_OPT_OUT, + UsInField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsInField.ADDITIONAL_DATA_PROCESSING_CONSENT, + UsInField.SENSITIVE_DATA_PROCESSING + }); + //@formatter:on + + //@formatter:off + public static List USIN_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsInField.GPC_SEGMENT_TYPE, + UsInField.GPC + }); + //@formatter:on +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java index fb69587c..9a5c544b 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java @@ -35,6 +35,7 @@ public class Sections { SECTION_ID_NAME_MAP.put(UsNj.ID, UsNj.NAME); SECTION_ID_NAME_MAP.put(UsTn.ID, UsTn.NAME); SECTION_ID_NAME_MAP.put(UsMn.ID, UsMn.NAME); + SECTION_ID_NAME_MAP.put(UsIn.ID, UsIn.NAME); SECTION_ORDER = new ArrayList(SECTION_ID_NAME_MAP.keySet()).stream().sorted() .map(id -> SECTION_ID_NAME_MAP.get(id)).collect(Collectors.toList()); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsIn.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsIn.java new file mode 100644 index 00000000..594b7bb1 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsIn.java @@ -0,0 +1,140 @@ +package com.iab.gpp.encoder.section; + +import com.iab.gpp.encoder.field.UsInField; +import com.iab.gpp.encoder.segment.*; + +import java.util.ArrayList; +import java.util.List; + +public class UsIn extends AbstractLazilyEncodableSection { + + public static int ID = 25; + public static int VERSION = 1; + public static String NAME = "usin"; + + public UsIn() { + super(); + } + + public UsIn(String encodedString) { + super(); + decode(encodedString); + } + + @Override + public int getId() { + return UsIn.ID; + } + + @Override + public String getName() { + return UsIn.NAME; + } + + @Override + public int getVersion() { + return UsIn.VERSION; + } + + @Override + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsInCoreSegment()); + segments.add(new UsInGpcSegment()); + return segments; + } + + @Override + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if (encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if (encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if (encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsInField.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsInField.GPC_SEGMENT_INCLUDED, false); + } + } + + return segments; + } + + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if (!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if (segments.size() >= 2 && segments.get(1).getFieldValue(UsInField.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); + } + + + public Integer getMspaVersion() { + return (Integer) this.getFieldValue(UsInField.MSPA_VERSION); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.getFieldValue(UsInField.MSPA_COVERED_TRANSACTION); + } + + public Integer getMspaMode() { + return (Integer) this.getFieldValue(UsInField.MSPA_MODE); + } + + public Integer getProcessingNotice() { + return (Integer) this.getFieldValue(UsInField.PROCESSING_NOTICE); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.getFieldValue(UsInField.SALE_OPT_OUT_NOTICE); + } + + public Integer getTargetedAdvertisingOptOutNotice() { + return (Integer) this.getFieldValue(UsInField.TARGETED_ADVERTISING_OPT_OUT_NOTICE); + } + + public Integer getSaleOptOut() { + return (Integer) this.getFieldValue(UsInField.SALE_OPT_OUT); + } + + public Integer getTargetedAdvertisingOptOut() { + return (Integer) this.getFieldValue(UsInField.TARGETED_ADVERTISING_OPT_OUT); + } + + public Integer getKnownChildSensitiveDataConsents() { + return (Integer) this.getFieldValue(UsInField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); + } + + public Integer getAdditionalDataProcessingConsent() { + return (Integer) this.getFieldValue(UsInField.ADDITIONAL_DATA_PROCESSING_CONSENT); + } + + @SuppressWarnings("unchecked") + public List getSensitiveDataProcessing() { + return (List) this.getFieldValue(UsInField.SENSITIVE_DATA_PROCESSING); + } + + public Integer getGpcSegmentType() { + return (Integer) this.getFieldValue(UsInField.GPC_SEGMENT_TYPE); + } + + public Boolean getGpcSegmentIncluded() { + return (Boolean) this.getFieldValue(UsInField.GPC_SEGMENT_INCLUDED); + } + + public Boolean getGpc() { + return (Boolean) this.getFieldValue(UsInField.GPC); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInCoreSegment.java new file mode 100644 index 00000000..f00a41d6 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInCoreSegment.java @@ -0,0 +1,95 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsInField; +import com.iab.gpp.encoder.section.UsIn; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +public class UsInCoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsInCoreSegment() { + super(); + } + + public UsInCoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsInField.USIN_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsInField.MSPA_VERSION, new EncodableFixedInteger(6, UsIn.VERSION)); + fields.put(UsInField.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsInField.MSPA_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsInField.PROCESSING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsInField.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsInField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsInField.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsInField.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsInField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsInField.ADDITIONAL_DATA_PROCESSING_CONSENT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsInField.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsInCoreSegment '" + encodedString + "'", e); + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInGpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInGpcSegment.java new file mode 100644 index 00000000..5166694f --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInGpcSegment.java @@ -0,0 +1,61 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsInField; + +import java.util.List; + +public class UsInGpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsInGpcSegment() { + super(); + } + + public UsInGpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsInField.USIN_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsInField.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsInField.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsInField.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsInGpcSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsInTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsInTest.java new file mode 100644 index 00000000..193840c4 --- /dev/null +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsInTest.java @@ -0,0 +1,104 @@ +package com.iab.gpp.encoder.section; + + +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; +import com.iab.gpp.encoder.field.UsInField; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +public class UsInTest { + + @Test + public void testEncode1() { + UsIn usIn = new UsIn(); + Assertions.assertEquals("BQAAAAA.QA", usIn.encode()); + } + + @Test + public void testEncode2() { + UsIn usIn = new UsIn(); + + usIn.setFieldValue(UsInField.MSPA_COVERED_TRANSACTION, 1); + usIn.setFieldValue(UsInField.MSPA_MODE, 1); + usIn.setFieldValue(UsInField.PROCESSING_NOTICE, 1); + usIn.setFieldValue(UsInField.SALE_OPT_OUT_NOTICE, 1); + usIn.setFieldValue(UsInField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usIn.setFieldValue(UsInField.SALE_OPT_OUT, 1); + usIn.setFieldValue(UsInField.TARGETED_ADVERTISING_OPT_OUT, 1); + usIn.setFieldValue(UsInField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); + usIn.setFieldValue(UsInField.ADDITIONAL_DATA_PROCESSING_CONSENT, 1); + usIn.setFieldValue(UsInField.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); + usIn.setFieldValue(UsInField.GPC, true); + + Assertions.assertEquals("BVVVkkk.YA", usIn.encode()); + } + + @Test + public void testSetInvalidValues() { + UsIn usIn = new UsIn(); + + try { + usIn.setFieldValue(UsInField.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usIn.setFieldValue(UsInField.MSPA_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usIn.setFieldValue(UsInField.PROCESSING_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usIn.setFieldValue(UsInField.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 1, 2, 0, 1)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usIn.setFieldValue(UsInField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + } + + @Test + public void testEncodeWithGpcSegmentExcluded() { + UsIn usIn = new UsIn(); + usIn.setFieldValue(UsInField.GPC_SEGMENT_INCLUDED, false); + Assertions.assertEquals("BQAAAAA", usIn.encode()); + } + + @Test + public void testDecode1() throws DecodingException { + UsIn usIn = new UsIn("BVVVkkk.YA"); + + Assertions.assertEquals(1, usIn.getMspaCoveredTransaction()); + Assertions.assertEquals(1, usIn.getMspaMode()); + Assertions.assertEquals(1, usIn.getProcessingNotice()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usIn.getSensitiveDataProcessing()); + Assertions.assertEquals(1, usIn.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(true, usIn.getGpc()); + } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsIn("z").getProcessingNotice(); + }); + } +} From d4f0c7abef4cf8949351b4589536e7b2371ac7a8 Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Fri, 5 Jun 2026 15:33:15 -0600 Subject: [PATCH 16/22] Add UsKy section (Kentucky, Section ID 26) --- .../java/com/iab/gpp/encoder/GppModel.java | 13 ++ .../com/iab/gpp/encoder/field/UsKyField.java | 46 ++++++ .../com/iab/gpp/encoder/section/Sections.java | 1 + .../com/iab/gpp/encoder/section/UsKy.java | 140 ++++++++++++++++++ .../gpp/encoder/segment/UsKyCoreSegment.java | 95 ++++++++++++ .../gpp/encoder/segment/UsKyGpcSegment.java | 61 ++++++++ .../com/iab/gpp/encoder/section/UsKyTest.java | 88 +++++++++++ 7 files changed, 444 insertions(+) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsKyField.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsKy.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyCoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyGpcSegment.java create mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsKyTest.java diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java index 2eef8aa5..a5a597ec 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java @@ -101,6 +101,9 @@ public void setFieldValue(String sectionName, String fieldName, Object value) { } else if (sectionName.equals(UsMn.NAME)) { section = new UsMn(); this.sections.put(UsMn.NAME, section); + } else if (sectionName.equals(UsKy.NAME)) { + section = new UsKy(); + this.sections.put(UsKy.NAME, section); } } else { section = this.sections.get(sectionName); @@ -302,6 +305,10 @@ public UsMn getUsMnSection() { return (UsMn) getSection(UsMn.NAME); } + public UsKy getUsKySection() { + return (UsKy) getSection(UsKy.NAME); + } + public List getSectionIds() { if (!this.decoded) { this.sections = this.decodeModel(this.encodedString); @@ -416,6 +423,9 @@ protected Map decodeModel(String str) { } else if (sectionIds.get(i).equals(UsMn.ID)) { UsMn section = new UsMn(encodedSections[i + 1]); sections.put(UsMn.NAME, section); + } else if (sectionIds.get(i).equals(UsKy.ID)) { + UsKy section = new UsKy(encodedSections[i + 1]); + sections.put(UsKy.NAME, section); } } } @@ -529,6 +539,9 @@ public void decodeSection(String sectionName, String encodedString) { }else if (sectionName.equals(UsMn.NAME)) { section = new UsMn(); this.sections.put(UsMn.NAME, section); + }else if (sectionName.equals(UsKy.NAME)) { + section = new UsKy(); + this.sections.put(UsKy.NAME, section); } } else { section = this.sections.get(sectionName); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsKyField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsKyField.java new file mode 100644 index 00000000..12be3966 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsKyField.java @@ -0,0 +1,46 @@ +package com.iab.gpp.encoder.field; + +import java.util.Arrays; +import java.util.List; + +public class UsKyField { + + public static String MSPA_VERSION = "MspaVersion"; + public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction"; + public static String MSPA_MODE = "MspaMode"; + public static String PROCESSING_NOTICE = "ProcessingNotice"; + public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice"; + public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice"; + public static String SALE_OPT_OUT = "SaleOptOut"; + public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut"; + public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents"; + public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent"; + public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing"; + + public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; + public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; + public static String GPC = "Gpc"; + + //@formatter:off + public static List USKY_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsKyField.MSPA_VERSION, + UsKyField.MSPA_COVERED_TRANSACTION, + UsKyField.MSPA_MODE, + UsKyField.PROCESSING_NOTICE, + UsKyField.SALE_OPT_OUT_NOTICE, + UsKyField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsKyField.SALE_OPT_OUT, + UsKyField.TARGETED_ADVERTISING_OPT_OUT, + UsKyField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsKyField.ADDITIONAL_DATA_PROCESSING_CONSENT, + UsKyField.SENSITIVE_DATA_PROCESSING + }); + //@formatter:on + + //@formatter:off + public static List USKY_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsKyField.GPC_SEGMENT_TYPE, + UsKyField.GPC + }); + //@formatter:on +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java index fb69587c..21daa2c1 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java @@ -35,6 +35,7 @@ public class Sections { SECTION_ID_NAME_MAP.put(UsNj.ID, UsNj.NAME); SECTION_ID_NAME_MAP.put(UsTn.ID, UsTn.NAME); SECTION_ID_NAME_MAP.put(UsMn.ID, UsMn.NAME); + SECTION_ID_NAME_MAP.put(UsKy.ID, UsKy.NAME); SECTION_ORDER = new ArrayList(SECTION_ID_NAME_MAP.keySet()).stream().sorted() .map(id -> SECTION_ID_NAME_MAP.get(id)).collect(Collectors.toList()); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsKy.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsKy.java new file mode 100644 index 00000000..0e12f3a1 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsKy.java @@ -0,0 +1,140 @@ +package com.iab.gpp.encoder.section; + +import com.iab.gpp.encoder.field.UsKyField; +import com.iab.gpp.encoder.segment.*; + +import java.util.ArrayList; +import java.util.List; + +public class UsKy extends AbstractLazilyEncodableSection { + + public static int ID = 26; + public static int VERSION = 1; + public static String NAME = "usky"; + + public UsKy() { + super(); + } + + public UsKy(String encodedString) { + super(); + decode(encodedString); + } + + @Override + public int getId() { + return UsKy.ID; + } + + @Override + public String getName() { + return UsKy.NAME; + } + + @Override + public int getVersion() { + return UsKy.VERSION; + } + + @Override + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsKyCoreSegment()); + segments.add(new UsKyGpcSegment()); + return segments; + } + + @Override + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if (encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if (encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if (encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsKyField.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsKyField.GPC_SEGMENT_INCLUDED, false); + } + } + + return segments; + } + + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if (!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if (segments.size() >= 2 && segments.get(1).getFieldValue(UsKyField.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); + } + + + public Integer getMspaVersion() { + return (Integer) this.getFieldValue(UsKyField.MSPA_VERSION); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.getFieldValue(UsKyField.MSPA_COVERED_TRANSACTION); + } + + public Integer getMspaMode() { + return (Integer) this.getFieldValue(UsKyField.MSPA_MODE); + } + + public Integer getProcessingNotice() { + return (Integer) this.getFieldValue(UsKyField.PROCESSING_NOTICE); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.getFieldValue(UsKyField.SALE_OPT_OUT_NOTICE); + } + + public Integer getTargetedAdvertisingOptOutNotice() { + return (Integer) this.getFieldValue(UsKyField.TARGETED_ADVERTISING_OPT_OUT_NOTICE); + } + + public Integer getSaleOptOut() { + return (Integer) this.getFieldValue(UsKyField.SALE_OPT_OUT); + } + + public Integer getTargetedAdvertisingOptOut() { + return (Integer) this.getFieldValue(UsKyField.TARGETED_ADVERTISING_OPT_OUT); + } + + public Integer getKnownChildSensitiveDataConsents() { + return (Integer) this.getFieldValue(UsKyField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); + } + + public Integer getAdditionalDataProcessingConsent() { + return (Integer) this.getFieldValue(UsKyField.ADDITIONAL_DATA_PROCESSING_CONSENT); + } + + @SuppressWarnings("unchecked") + public List getSensitiveDataProcessing() { + return (List) this.getFieldValue(UsKyField.SENSITIVE_DATA_PROCESSING); + } + + public Integer getGpcSegmentType() { + return (Integer) this.getFieldValue(UsKyField.GPC_SEGMENT_TYPE); + } + + public Boolean getGpcSegmentIncluded() { + return (Boolean) this.getFieldValue(UsKyField.GPC_SEGMENT_INCLUDED); + } + + public Boolean getGpc() { + return (Boolean) this.getFieldValue(UsKyField.GPC); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyCoreSegment.java new file mode 100644 index 00000000..0f67e504 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyCoreSegment.java @@ -0,0 +1,95 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsKyField; +import com.iab.gpp.encoder.section.UsKy; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +public class UsKyCoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsKyCoreSegment() { + super(); + } + + public UsKyCoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsKyField.USKY_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsKyField.MSPA_VERSION, new EncodableFixedInteger(6, UsKy.VERSION)); + fields.put(UsKyField.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsKyField.MSPA_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsKyField.PROCESSING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsKyField.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsKyField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsKyField.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsKyField.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsKyField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsKyField.ADDITIONAL_DATA_PROCESSING_CONSENT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsKyField.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsKyCoreSegment '" + encodedString + "'", e); + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyGpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyGpcSegment.java new file mode 100644 index 00000000..af095930 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyGpcSegment.java @@ -0,0 +1,61 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsKyField; + +import java.util.List; + +public class UsKyGpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsKyGpcSegment() { + super(); + } + + public UsKyGpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsKyField.USKY_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsKyField.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsKyField.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsKyField.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsKyGpcSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsKyTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsKyTest.java new file mode 100644 index 00000000..4f2904a9 --- /dev/null +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsKyTest.java @@ -0,0 +1,88 @@ +package com.iab.gpp.encoder.section; + + +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; +import com.iab.gpp.encoder.field.UsKyField; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +public class UsKyTest { + + @Test + public void testEncode1() { + UsKy usKy = new UsKy(); + Assertions.assertEquals("BQAAAAA.QA", usKy.encode()); + } + + @Test + public void testEncode2() { + UsKy usKy = new UsKy(); + + usKy.setFieldValue(UsKyField.MSPA_COVERED_TRANSACTION, 1); + usKy.setFieldValue(UsKyField.MSPA_MODE, 1); + usKy.setFieldValue(UsKyField.PROCESSING_NOTICE, 1); + usKy.setFieldValue(UsKyField.SALE_OPT_OUT_NOTICE, 1); + usKy.setFieldValue(UsKyField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usKy.setFieldValue(UsKyField.SALE_OPT_OUT, 1); + usKy.setFieldValue(UsKyField.TARGETED_ADVERTISING_OPT_OUT, 1); + usKy.setFieldValue(UsKyField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); + usKy.setFieldValue(UsKyField.ADDITIONAL_DATA_PROCESSING_CONSENT, 1); + usKy.setFieldValue(UsKyField.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); + usKy.setFieldValue(UsKyField.GPC, true); + + Assertions.assertEquals("BVVVkkk.YA", usKy.encode()); + } + + @Test + public void testSetInvalidValues() { + UsKy usKy = new UsKy(); + + try { + usKy.setFieldValue(UsKyField.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usKy.setFieldValue(UsKyField.MSPA_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usKy.setFieldValue(UsKyField.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 1, 2, 0, 1)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + } + + @Test + public void testEncodeWithGpcSegmentExcluded() { + UsKy usKy = new UsKy(); + usKy.setFieldValue(UsKyField.GPC_SEGMENT_INCLUDED, false); + Assertions.assertEquals("BQAAAAA", usKy.encode()); + } + + @Test + public void testDecode1() throws DecodingException { + UsKy usKy = new UsKy("BVVVkkk.YA"); + + Assertions.assertEquals(1, usKy.getMspaCoveredTransaction()); + Assertions.assertEquals(1, usKy.getMspaMode()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usKy.getSensitiveDataProcessing()); + Assertions.assertEquals(true, usKy.getGpc()); + } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsKy("z").getProcessingNotice(); + }); + } +} From 8e2f27ae7b7baa153227bcf1fa6f2fea8080d580 Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Fri, 5 Jun 2026 22:18:26 -0600 Subject: [PATCH 17/22] Add UsRi section (Rhode Island, Section ID 27) --- .../java/com/iab/gpp/encoder/GppModel.java | 13 ++ .../com/iab/gpp/encoder/field/UsRiField.java | 46 ++++++ .../com/iab/gpp/encoder/section/Sections.java | 1 + .../com/iab/gpp/encoder/section/UsRi.java | 140 ++++++++++++++++++ .../gpp/encoder/segment/UsRiCoreSegment.java | 95 ++++++++++++ .../gpp/encoder/segment/UsRiGpcSegment.java | 61 ++++++++ .../com/iab/gpp/encoder/section/UsRiTest.java | 88 +++++++++++ 7 files changed, 444 insertions(+) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsRiField.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsRi.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiCoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiGpcSegment.java create mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsRiTest.java diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java index 2eef8aa5..eb28c5ba 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java @@ -101,6 +101,9 @@ public void setFieldValue(String sectionName, String fieldName, Object value) { } else if (sectionName.equals(UsMn.NAME)) { section = new UsMn(); this.sections.put(UsMn.NAME, section); + } else if (sectionName.equals(UsRi.NAME)) { + section = new UsRi(); + this.sections.put(UsRi.NAME, section); } } else { section = this.sections.get(sectionName); @@ -302,6 +305,10 @@ public UsMn getUsMnSection() { return (UsMn) getSection(UsMn.NAME); } + public UsRi getUsRiSection() { + return (UsRi) getSection(UsRi.NAME); + } + public List getSectionIds() { if (!this.decoded) { this.sections = this.decodeModel(this.encodedString); @@ -416,6 +423,9 @@ protected Map decodeModel(String str) { } else if (sectionIds.get(i).equals(UsMn.ID)) { UsMn section = new UsMn(encodedSections[i + 1]); sections.put(UsMn.NAME, section); + } else if (sectionIds.get(i).equals(UsRi.ID)) { + UsRi section = new UsRi(encodedSections[i + 1]); + sections.put(UsRi.NAME, section); } } } @@ -529,6 +539,9 @@ public void decodeSection(String sectionName, String encodedString) { }else if (sectionName.equals(UsMn.NAME)) { section = new UsMn(); this.sections.put(UsMn.NAME, section); + }else if (sectionName.equals(UsRi.NAME)) { + section = new UsRi(); + this.sections.put(UsRi.NAME, section); } } else { section = this.sections.get(sectionName); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsRiField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsRiField.java new file mode 100644 index 00000000..b3b0d3f3 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsRiField.java @@ -0,0 +1,46 @@ +package com.iab.gpp.encoder.field; + +import java.util.Arrays; +import java.util.List; + +public class UsRiField { + + public static String MSPA_VERSION = "MspaVersion"; + public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction"; + public static String MSPA_MODE = "MspaMode"; + public static String PROCESSING_NOTICE = "ProcessingNotice"; + public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice"; + public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice"; + public static String SALE_OPT_OUT = "SaleOptOut"; + public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut"; + public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents"; + public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent"; + public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing"; + + public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; + public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; + public static String GPC = "Gpc"; + + //@formatter:off + public static List USRI_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsRiField.MSPA_VERSION, + UsRiField.MSPA_COVERED_TRANSACTION, + UsRiField.MSPA_MODE, + UsRiField.PROCESSING_NOTICE, + UsRiField.SALE_OPT_OUT_NOTICE, + UsRiField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsRiField.SALE_OPT_OUT, + UsRiField.TARGETED_ADVERTISING_OPT_OUT, + UsRiField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsRiField.ADDITIONAL_DATA_PROCESSING_CONSENT, + UsRiField.SENSITIVE_DATA_PROCESSING + }); + //@formatter:on + + //@formatter:off + public static List USRI_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsRiField.GPC_SEGMENT_TYPE, + UsRiField.GPC + }); + //@formatter:on +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java index fb69587c..a9b5a9d2 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java @@ -35,6 +35,7 @@ public class Sections { SECTION_ID_NAME_MAP.put(UsNj.ID, UsNj.NAME); SECTION_ID_NAME_MAP.put(UsTn.ID, UsTn.NAME); SECTION_ID_NAME_MAP.put(UsMn.ID, UsMn.NAME); + SECTION_ID_NAME_MAP.put(UsRi.ID, UsRi.NAME); SECTION_ORDER = new ArrayList(SECTION_ID_NAME_MAP.keySet()).stream().sorted() .map(id -> SECTION_ID_NAME_MAP.get(id)).collect(Collectors.toList()); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsRi.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsRi.java new file mode 100644 index 00000000..da1f1d83 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsRi.java @@ -0,0 +1,140 @@ +package com.iab.gpp.encoder.section; + +import com.iab.gpp.encoder.field.UsRiField; +import com.iab.gpp.encoder.segment.*; + +import java.util.ArrayList; +import java.util.List; + +public class UsRi extends AbstractLazilyEncodableSection { + + public static int ID = 27; + public static int VERSION = 1; + public static String NAME = "usri"; + + public UsRi() { + super(); + } + + public UsRi(String encodedString) { + super(); + decode(encodedString); + } + + @Override + public int getId() { + return UsRi.ID; + } + + @Override + public String getName() { + return UsRi.NAME; + } + + @Override + public int getVersion() { + return UsRi.VERSION; + } + + @Override + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsRiCoreSegment()); + segments.add(new UsRiGpcSegment()); + return segments; + } + + @Override + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if (encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if (encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if (encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsRiField.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsRiField.GPC_SEGMENT_INCLUDED, false); + } + } + + return segments; + } + + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if (!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if (segments.size() >= 2 && segments.get(1).getFieldValue(UsRiField.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); + } + + + public Integer getMspaVersion() { + return (Integer) this.getFieldValue(UsRiField.MSPA_VERSION); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.getFieldValue(UsRiField.MSPA_COVERED_TRANSACTION); + } + + public Integer getMspaMode() { + return (Integer) this.getFieldValue(UsRiField.MSPA_MODE); + } + + public Integer getProcessingNotice() { + return (Integer) this.getFieldValue(UsRiField.PROCESSING_NOTICE); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.getFieldValue(UsRiField.SALE_OPT_OUT_NOTICE); + } + + public Integer getTargetedAdvertisingOptOutNotice() { + return (Integer) this.getFieldValue(UsRiField.TARGETED_ADVERTISING_OPT_OUT_NOTICE); + } + + public Integer getSaleOptOut() { + return (Integer) this.getFieldValue(UsRiField.SALE_OPT_OUT); + } + + public Integer getTargetedAdvertisingOptOut() { + return (Integer) this.getFieldValue(UsRiField.TARGETED_ADVERTISING_OPT_OUT); + } + + public Integer getKnownChildSensitiveDataConsents() { + return (Integer) this.getFieldValue(UsRiField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); + } + + public Integer getAdditionalDataProcessingConsent() { + return (Integer) this.getFieldValue(UsRiField.ADDITIONAL_DATA_PROCESSING_CONSENT); + } + + @SuppressWarnings("unchecked") + public List getSensitiveDataProcessing() { + return (List) this.getFieldValue(UsRiField.SENSITIVE_DATA_PROCESSING); + } + + public Integer getGpcSegmentType() { + return (Integer) this.getFieldValue(UsRiField.GPC_SEGMENT_TYPE); + } + + public Boolean getGpcSegmentIncluded() { + return (Boolean) this.getFieldValue(UsRiField.GPC_SEGMENT_INCLUDED); + } + + public Boolean getGpc() { + return (Boolean) this.getFieldValue(UsRiField.GPC); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiCoreSegment.java new file mode 100644 index 00000000..a4791d44 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiCoreSegment.java @@ -0,0 +1,95 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsRiField; +import com.iab.gpp.encoder.section.UsRi; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +public class UsRiCoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsRiCoreSegment() { + super(); + } + + public UsRiCoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsRiField.USRI_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsRiField.MSPA_VERSION, new EncodableFixedInteger(6, UsRi.VERSION)); + fields.put(UsRiField.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsRiField.MSPA_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsRiField.PROCESSING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsRiField.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsRiField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsRiField.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsRiField.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsRiField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsRiField.ADDITIONAL_DATA_PROCESSING_CONSENT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsRiField.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsRiCoreSegment '" + encodedString + "'", e); + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiGpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiGpcSegment.java new file mode 100644 index 00000000..3d47370c --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiGpcSegment.java @@ -0,0 +1,61 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsRiField; + +import java.util.List; + +public class UsRiGpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsRiGpcSegment() { + super(); + } + + public UsRiGpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsRiField.USRI_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsRiField.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsRiField.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsRiField.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsRiGpcSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsRiTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsRiTest.java new file mode 100644 index 00000000..eae8bbd0 --- /dev/null +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsRiTest.java @@ -0,0 +1,88 @@ +package com.iab.gpp.encoder.section; + + +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; +import com.iab.gpp.encoder.field.UsRiField; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +public class UsRiTest { + + @Test + public void testEncode1() { + UsRi usRi = new UsRi(); + Assertions.assertEquals("BQAAAAA.QA", usRi.encode()); + } + + @Test + public void testEncode2() { + UsRi usRi = new UsRi(); + + usRi.setFieldValue(UsRiField.MSPA_COVERED_TRANSACTION, 1); + usRi.setFieldValue(UsRiField.MSPA_MODE, 1); + usRi.setFieldValue(UsRiField.PROCESSING_NOTICE, 1); + usRi.setFieldValue(UsRiField.SALE_OPT_OUT_NOTICE, 1); + usRi.setFieldValue(UsRiField.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usRi.setFieldValue(UsRiField.SALE_OPT_OUT, 1); + usRi.setFieldValue(UsRiField.TARGETED_ADVERTISING_OPT_OUT, 1); + usRi.setFieldValue(UsRiField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); + usRi.setFieldValue(UsRiField.ADDITIONAL_DATA_PROCESSING_CONSENT, 1); + usRi.setFieldValue(UsRiField.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); + usRi.setFieldValue(UsRiField.GPC, true); + + Assertions.assertEquals("BVVVkkk.YA", usRi.encode()); + } + + @Test + public void testSetInvalidValues() { + UsRi usRi = new UsRi(); + + try { + usRi.setFieldValue(UsRiField.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usRi.setFieldValue(UsRiField.MSPA_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usRi.setFieldValue(UsRiField.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 1, 2, 0, 1)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + } + + @Test + public void testEncodeWithGpcSegmentExcluded() { + UsRi usRi = new UsRi(); + usRi.setFieldValue(UsRiField.GPC_SEGMENT_INCLUDED, false); + Assertions.assertEquals("BQAAAAA", usRi.encode()); + } + + @Test + public void testDecode1() throws DecodingException { + UsRi usRi = new UsRi("BVVVkkk.YA"); + + Assertions.assertEquals(1, usRi.getMspaCoveredTransaction()); + Assertions.assertEquals(1, usRi.getMspaMode()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usRi.getSensitiveDataProcessing()); + Assertions.assertEquals(true, usRi.getGpc()); + } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsRi("z").getProcessingNotice(); + }); + } +} From 12243517587f92a4971eb4d999afb63c84eb4b44 Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Sat, 6 Jun 2026 15:38:03 -0600 Subject: [PATCH 18/22] Add UsMd to GppModelTest all-sections tests --- .../src/test/java/com/iab/gpp/encoder/GppModelTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index bb5f2336..129a28b4 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -17,6 +17,7 @@ import com.iab.gpp.encoder.section.UsDe; import com.iab.gpp.encoder.section.UsFl; import com.iab.gpp.encoder.section.UsIa; +import com.iab.gpp.encoder.section.UsMd; import com.iab.gpp.encoder.section.UsMn; import com.iab.gpp.encoder.section.UsMt; import com.iab.gpp.encoder.section.UsNat; @@ -83,6 +84,7 @@ public void testEncodeDefaultAll() { Assertions.assertEquals(false, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(false, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(false, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(false, gppModel.hasSection(UsMd.NAME)); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VERSION, TcfEuV2.VERSION); gppModel.setFieldValue(TcfEuV2.NAME, TcfCaV1Field.CREATED, utcDateTime); @@ -108,6 +110,7 @@ public void testEncodeDefaultAll() { gppModel.setFieldValue(UsNj.NAME, UsNjField.VERSION, UsNj.VERSION); gppModel.setFieldValue(UsTn.NAME, UsTnField.VERSION, UsTn.VERSION); gppModel.setFieldValue(UsMn.NAME, UsMnField.VERSION, UsMn.VERSION); + gppModel.setFieldValue(UsMd.NAME, UsMdField.MSPA_VERSION, UsMd.VERSION); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -130,10 +133,11 @@ public void testEncodeDefaultAll() { Assertions.assertEquals(true, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(true, gppModel.hasSection(UsMd.NAME)); String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOYs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA", + "DBACOcs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAA.QA", gppString); } @@ -406,7 +410,7 @@ public void testDecodeDefaults() { @Test public void testDecodeDefaultsAll() { String gppString = - "DBACOYs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAABAA.QA"; + "DBACOcs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAA.QA"; GppModel gppModel = new GppModel(gppString); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -429,6 +433,7 @@ public void testDecodeDefaultsAll() { Assertions.assertEquals(true, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(true, gppModel.hasSection(UsMd.NAME)); } @Test From 301d0c9107e634b1c69a2b10c379469cccf78b5f Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Sat, 6 Jun 2026 15:38:59 -0600 Subject: [PATCH 19/22] Add UsIn to GppModelTest all-sections tests --- .../src/test/java/com/iab/gpp/encoder/GppModelTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index bb5f2336..a1f80d15 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -17,6 +17,7 @@ import com.iab.gpp.encoder.section.UsDe; import com.iab.gpp.encoder.section.UsFl; import com.iab.gpp.encoder.section.UsIa; +import com.iab.gpp.encoder.section.UsIn; import com.iab.gpp.encoder.section.UsMn; import com.iab.gpp.encoder.section.UsMt; import com.iab.gpp.encoder.section.UsNat; @@ -83,6 +84,7 @@ public void testEncodeDefaultAll() { Assertions.assertEquals(false, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(false, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(false, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(false, gppModel.hasSection(UsIn.NAME)); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VERSION, TcfEuV2.VERSION); gppModel.setFieldValue(TcfEuV2.NAME, TcfCaV1Field.CREATED, utcDateTime); @@ -108,6 +110,7 @@ public void testEncodeDefaultAll() { gppModel.setFieldValue(UsNj.NAME, UsNjField.VERSION, UsNj.VERSION); gppModel.setFieldValue(UsTn.NAME, UsTnField.VERSION, UsTn.VERSION); gppModel.setFieldValue(UsMn.NAME, UsMnField.VERSION, UsMn.VERSION); + gppModel.setFieldValue(UsIn.NAME, UsInField.MSPA_VERSION, UsIn.VERSION); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -130,10 +133,11 @@ public void testEncodeDefaultAll() { Assertions.assertEquals(true, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(true, gppModel.hasSection(UsIn.NAME)); String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOYs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA", + "DBADOYsw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAAAAA.QA", gppString); } @@ -406,7 +410,7 @@ public void testDecodeDefaults() { @Test public void testDecodeDefaultsAll() { String gppString = - "DBACOYs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAABAA.QA"; + "DBADOYsw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAAAAA.QA"; GppModel gppModel = new GppModel(gppString); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -429,6 +433,7 @@ public void testDecodeDefaultsAll() { Assertions.assertEquals(true, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(true, gppModel.hasSection(UsIn.NAME)); } @Test From b6e71a1b71ec8ad284dc3e51e5f76de9d14fa3a6 Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Sat, 6 Jun 2026 15:39:52 -0600 Subject: [PATCH 20/22] Add UsKy to GppModelTest all-sections tests --- .../src/test/java/com/iab/gpp/encoder/GppModelTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index bb5f2336..16744446 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -17,6 +17,7 @@ import com.iab.gpp.encoder.section.UsDe; import com.iab.gpp.encoder.section.UsFl; import com.iab.gpp.encoder.section.UsIa; +import com.iab.gpp.encoder.section.UsKy; import com.iab.gpp.encoder.section.UsMn; import com.iab.gpp.encoder.section.UsMt; import com.iab.gpp.encoder.section.UsNat; @@ -83,6 +84,7 @@ public void testEncodeDefaultAll() { Assertions.assertEquals(false, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(false, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(false, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(false, gppModel.hasSection(UsKy.NAME)); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VERSION, TcfEuV2.VERSION); gppModel.setFieldValue(TcfEuV2.NAME, TcfCaV1Field.CREATED, utcDateTime); @@ -108,6 +110,7 @@ public void testEncodeDefaultAll() { gppModel.setFieldValue(UsNj.NAME, UsNjField.VERSION, UsNj.VERSION); gppModel.setFieldValue(UsTn.NAME, UsTnField.VERSION, UsTn.VERSION); gppModel.setFieldValue(UsMn.NAME, UsMnField.VERSION, UsMn.VERSION); + gppModel.setFieldValue(UsKy.NAME, UsKyField.MSPA_VERSION, UsKy.VERSION); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -130,10 +133,11 @@ public void testEncodeDefaultAll() { Assertions.assertEquals(true, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(true, gppModel.hasSection(UsKy.NAME)); String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOYs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA", + "DBADOYsY~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAAAAA.QA", gppString); } @@ -406,7 +410,7 @@ public void testDecodeDefaults() { @Test public void testDecodeDefaultsAll() { String gppString = - "DBACOYs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAABAA.QA"; + "DBADOYsY~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAAAAA.QA"; GppModel gppModel = new GppModel(gppString); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -429,6 +433,7 @@ public void testDecodeDefaultsAll() { Assertions.assertEquals(true, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(true, gppModel.hasSection(UsKy.NAME)); } @Test From 8f18c93c1f3ea63705a43a99ecddf3d653f95943 Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Sat, 6 Jun 2026 15:40:47 -0600 Subject: [PATCH 21/22] Add UsRi to GppModelTest all-sections tests --- .../src/test/java/com/iab/gpp/encoder/GppModelTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index bb5f2336..2265cd7f 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -24,6 +24,7 @@ import com.iab.gpp.encoder.section.UsNh; import com.iab.gpp.encoder.section.UsNj; import com.iab.gpp.encoder.section.UsOr; +import com.iab.gpp.encoder.section.UsRi; import com.iab.gpp.encoder.section.UsTn; import com.iab.gpp.encoder.section.UsTx; import com.iab.gpp.encoder.section.UsUt; @@ -83,6 +84,7 @@ public void testEncodeDefaultAll() { Assertions.assertEquals(false, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(false, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(false, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(false, gppModel.hasSection(UsRi.NAME)); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VERSION, TcfEuV2.VERSION); gppModel.setFieldValue(TcfEuV2.NAME, TcfCaV1Field.CREATED, utcDateTime); @@ -108,6 +110,7 @@ public void testEncodeDefaultAll() { gppModel.setFieldValue(UsNj.NAME, UsNjField.VERSION, UsNj.VERSION); gppModel.setFieldValue(UsTn.NAME, UsTnField.VERSION, UsTn.VERSION); gppModel.setFieldValue(UsMn.NAME, UsMnField.VERSION, UsMn.VERSION); + gppModel.setFieldValue(UsRi.NAME, UsRiField.MSPA_VERSION, UsRi.VERSION); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -130,10 +133,11 @@ public void testEncodeDefaultAll() { Assertions.assertEquals(true, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(true, gppModel.hasSection(UsRi.NAME)); String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOYs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA", + "DBADOYtY~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAAAAA.QA", gppString); } @@ -406,7 +410,7 @@ public void testDecodeDefaults() { @Test public void testDecodeDefaultsAll() { String gppString = - "DBACOYs~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAABAA.QA"; + "DBADOYtY~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAAAAA.QA"; GppModel gppModel = new GppModel(gppString); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -429,6 +433,7 @@ public void testDecodeDefaultsAll() { Assertions.assertEquals(true, gppModel.hasSection(UsNj.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsTn.NAME)); Assertions.assertEquals(true, gppModel.hasSection(UsMn.NAME)); + Assertions.assertEquals(true, gppModel.hasSection(UsRi.NAME)); } @Test From 906334bde882cdbf00b5b5b853dff32d0be471a9 Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Mon, 8 Jun 2026 07:36:23 -0600 Subject: [PATCH 22/22] fix: replace GPC segment with SensitiveDataConsent segment for IN/KY/RI Per the IAB GPP MSPA spec, Indiana (25), Kentucky (26), and Rhode Island (27) have a Sensitive Data Consents optional segment (not GPC). Move SensitiveDataProcessing out of the core segment and into the new UsIn/Ky/RiSensitiveDataConsentSegment, and remove the incorrectly added GPC fields and segment files. Co-Authored-By: Claude Sonnet 4.6 --- .../com/iab/gpp/encoder/field/UsInField.java | 12 +++---- .../com/iab/gpp/encoder/field/UsKyField.java | 12 +++---- .../com/iab/gpp/encoder/field/UsRiField.java | 12 +++---- .../com/iab/gpp/encoder/section/UsIn.java | 24 +++++--------- .../com/iab/gpp/encoder/section/UsKy.java | 24 +++++--------- .../com/iab/gpp/encoder/section/UsRi.java | 24 +++++--------- .../gpp/encoder/segment/UsInCoreSegment.java | 13 -------- ...a => UsInSensitiveDataConsentSegment.java} | 32 +++++++++++++------ .../gpp/encoder/segment/UsKyCoreSegment.java | 13 -------- ...a => UsKySensitiveDataConsentSegment.java} | 32 +++++++++++++------ .../gpp/encoder/segment/UsRiCoreSegment.java | 13 -------- ...a => UsRiSensitiveDataConsentSegment.java} | 32 +++++++++++++------ .../com/iab/gpp/encoder/GppModelTest.java | 4 +-- .../com/iab/gpp/encoder/section/UsInTest.java | 21 ++++++------ .../com/iab/gpp/encoder/section/UsKyTest.java | 21 +++++++----- .../com/iab/gpp/encoder/section/UsRiTest.java | 21 +++++++----- 16 files changed, 142 insertions(+), 168 deletions(-) rename iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/{UsInGpcSegment.java => UsInSensitiveDataConsentSegment.java} (57%) rename iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/{UsKyGpcSegment.java => UsKySensitiveDataConsentSegment.java} (57%) rename iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/{UsRiGpcSegment.java => UsRiSensitiveDataConsentSegment.java} (57%) diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsInField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsInField.java index 287579f0..f3c5f61c 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsInField.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsInField.java @@ -17,9 +17,7 @@ public class UsInField { public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent"; public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing"; - public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; - public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; - public static String GPC = "Gpc"; + public static String SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED = "SensitiveDataConsentSegmentIncluded"; //@formatter:off public static List USIN_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { @@ -32,15 +30,13 @@ public class UsInField { UsInField.SALE_OPT_OUT, UsInField.TARGETED_ADVERTISING_OPT_OUT, UsInField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsInField.ADDITIONAL_DATA_PROCESSING_CONSENT, - UsInField.SENSITIVE_DATA_PROCESSING + UsInField.ADDITIONAL_DATA_PROCESSING_CONSENT }); //@formatter:on //@formatter:off - public static List USIN_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { - UsInField.GPC_SEGMENT_TYPE, - UsInField.GPC + public static List USIN_SENSITIVE_DATA_CONSENT_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsInField.SENSITIVE_DATA_PROCESSING }); //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsKyField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsKyField.java index 12be3966..7fdcd542 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsKyField.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsKyField.java @@ -17,9 +17,7 @@ public class UsKyField { public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent"; public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing"; - public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; - public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; - public static String GPC = "Gpc"; + public static String SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED = "SensitiveDataConsentSegmentIncluded"; //@formatter:off public static List USKY_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { @@ -32,15 +30,13 @@ public class UsKyField { UsKyField.SALE_OPT_OUT, UsKyField.TARGETED_ADVERTISING_OPT_OUT, UsKyField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsKyField.ADDITIONAL_DATA_PROCESSING_CONSENT, - UsKyField.SENSITIVE_DATA_PROCESSING + UsKyField.ADDITIONAL_DATA_PROCESSING_CONSENT }); //@formatter:on //@formatter:off - public static List USKY_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { - UsKyField.GPC_SEGMENT_TYPE, - UsKyField.GPC + public static List USKY_SENSITIVE_DATA_CONSENT_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsKyField.SENSITIVE_DATA_PROCESSING }); //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsRiField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsRiField.java index b3b0d3f3..26be8c26 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsRiField.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsRiField.java @@ -17,9 +17,7 @@ public class UsRiField { public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent"; public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing"; - public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; - public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; - public static String GPC = "Gpc"; + public static String SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED = "SensitiveDataConsentSegmentIncluded"; //@formatter:off public static List USRI_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { @@ -32,15 +30,13 @@ public class UsRiField { UsRiField.SALE_OPT_OUT, UsRiField.TARGETED_ADVERTISING_OPT_OUT, UsRiField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsRiField.ADDITIONAL_DATA_PROCESSING_CONSENT, - UsRiField.SENSITIVE_DATA_PROCESSING + UsRiField.ADDITIONAL_DATA_PROCESSING_CONSENT }); //@formatter:on //@formatter:off - public static List USRI_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { - UsRiField.GPC_SEGMENT_TYPE, - UsRiField.GPC + public static List USRI_SENSITIVE_DATA_CONSENT_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsRiField.SENSITIVE_DATA_PROCESSING }); //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsIn.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsIn.java index 594b7bb1..ed7dec6a 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsIn.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsIn.java @@ -40,7 +40,7 @@ public int getVersion() { protected List initializeSegments() { List segments = new ArrayList<>(); segments.add(new UsInCoreSegment()); - segments.add(new UsInGpcSegment()); + segments.add(new UsInSensitiveDataConsentSegment()); return segments; } @@ -56,10 +56,10 @@ protected List decodeSection(String encodedString) { } if (encodedSegments.length > 1) { - segments.get(1).setFieldValue(UsInField.GPC_SEGMENT_INCLUDED, true); + segments.get(1).setFieldValue(UsInField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, true); segments.get(1).decode(encodedSegments[1]); } else { - segments.get(1).setFieldValue(UsInField.GPC_SEGMENT_INCLUDED, false); + segments.get(1).setFieldValue(UsInField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, false); } } @@ -72,7 +72,7 @@ protected String encodeSection(List segments) { if (!segments.isEmpty()) { encodedSegments.add(segments.get(0).encode()); - if (segments.size() >= 2 && segments.get(1).getFieldValue(UsInField.GPC_SEGMENT_INCLUDED).equals(true)) { + if (segments.size() >= 2 && segments.get(1).getFieldValue(UsInField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED).equals(true)) { encodedSegments.add(segments.get(1).encode()); } } @@ -121,20 +121,12 @@ public Integer getAdditionalDataProcessingConsent() { return (Integer) this.getFieldValue(UsInField.ADDITIONAL_DATA_PROCESSING_CONSENT); } + public Boolean getSensitiveDataConsentSegmentIncluded() { + return (Boolean) this.getFieldValue(UsInField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED); + } + @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { return (List) this.getFieldValue(UsInField.SENSITIVE_DATA_PROCESSING); } - - public Integer getGpcSegmentType() { - return (Integer) this.getFieldValue(UsInField.GPC_SEGMENT_TYPE); - } - - public Boolean getGpcSegmentIncluded() { - return (Boolean) this.getFieldValue(UsInField.GPC_SEGMENT_INCLUDED); - } - - public Boolean getGpc() { - return (Boolean) this.getFieldValue(UsInField.GPC); - } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsKy.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsKy.java index 0e12f3a1..6985cec4 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsKy.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsKy.java @@ -40,7 +40,7 @@ public int getVersion() { protected List initializeSegments() { List segments = new ArrayList<>(); segments.add(new UsKyCoreSegment()); - segments.add(new UsKyGpcSegment()); + segments.add(new UsKySensitiveDataConsentSegment()); return segments; } @@ -56,10 +56,10 @@ protected List decodeSection(String encodedString) { } if (encodedSegments.length > 1) { - segments.get(1).setFieldValue(UsKyField.GPC_SEGMENT_INCLUDED, true); + segments.get(1).setFieldValue(UsKyField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, true); segments.get(1).decode(encodedSegments[1]); } else { - segments.get(1).setFieldValue(UsKyField.GPC_SEGMENT_INCLUDED, false); + segments.get(1).setFieldValue(UsKyField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, false); } } @@ -72,7 +72,7 @@ protected String encodeSection(List segments) { if (!segments.isEmpty()) { encodedSegments.add(segments.get(0).encode()); - if (segments.size() >= 2 && segments.get(1).getFieldValue(UsKyField.GPC_SEGMENT_INCLUDED).equals(true)) { + if (segments.size() >= 2 && segments.get(1).getFieldValue(UsKyField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED).equals(true)) { encodedSegments.add(segments.get(1).encode()); } } @@ -121,20 +121,12 @@ public Integer getAdditionalDataProcessingConsent() { return (Integer) this.getFieldValue(UsKyField.ADDITIONAL_DATA_PROCESSING_CONSENT); } + public Boolean getSensitiveDataConsentSegmentIncluded() { + return (Boolean) this.getFieldValue(UsKyField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED); + } + @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { return (List) this.getFieldValue(UsKyField.SENSITIVE_DATA_PROCESSING); } - - public Integer getGpcSegmentType() { - return (Integer) this.getFieldValue(UsKyField.GPC_SEGMENT_TYPE); - } - - public Boolean getGpcSegmentIncluded() { - return (Boolean) this.getFieldValue(UsKyField.GPC_SEGMENT_INCLUDED); - } - - public Boolean getGpc() { - return (Boolean) this.getFieldValue(UsKyField.GPC); - } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsRi.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsRi.java index da1f1d83..fb9f4ea0 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsRi.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsRi.java @@ -40,7 +40,7 @@ public int getVersion() { protected List initializeSegments() { List segments = new ArrayList<>(); segments.add(new UsRiCoreSegment()); - segments.add(new UsRiGpcSegment()); + segments.add(new UsRiSensitiveDataConsentSegment()); return segments; } @@ -56,10 +56,10 @@ protected List decodeSection(String encodedString) { } if (encodedSegments.length > 1) { - segments.get(1).setFieldValue(UsRiField.GPC_SEGMENT_INCLUDED, true); + segments.get(1).setFieldValue(UsRiField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, true); segments.get(1).decode(encodedSegments[1]); } else { - segments.get(1).setFieldValue(UsRiField.GPC_SEGMENT_INCLUDED, false); + segments.get(1).setFieldValue(UsRiField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, false); } } @@ -72,7 +72,7 @@ protected String encodeSection(List segments) { if (!segments.isEmpty()) { encodedSegments.add(segments.get(0).encode()); - if (segments.size() >= 2 && segments.get(1).getFieldValue(UsRiField.GPC_SEGMENT_INCLUDED).equals(true)) { + if (segments.size() >= 2 && segments.get(1).getFieldValue(UsRiField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED).equals(true)) { encodedSegments.add(segments.get(1).encode()); } } @@ -121,20 +121,12 @@ public Integer getAdditionalDataProcessingConsent() { return (Integer) this.getFieldValue(UsRiField.ADDITIONAL_DATA_PROCESSING_CONSENT); } + public Boolean getSensitiveDataConsentSegmentIncluded() { + return (Boolean) this.getFieldValue(UsRiField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED); + } + @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { return (List) this.getFieldValue(UsRiField.SENSITIVE_DATA_PROCESSING); } - - public Integer getGpcSegmentType() { - return (Integer) this.getFieldValue(UsRiField.GPC_SEGMENT_TYPE); - } - - public Boolean getGpcSegmentIncluded() { - return (Boolean) this.getFieldValue(UsRiField.GPC_SEGMENT_INCLUDED); - } - - public Boolean getGpc() { - return (Boolean) this.getFieldValue(UsRiField.GPC); - } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInCoreSegment.java index f00a41d6..2369ee3b 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInCoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInCoreSegment.java @@ -4,13 +4,11 @@ import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsInField; import com.iab.gpp.encoder.section.UsIn; -import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -37,14 +35,6 @@ public List getFieldNames() { protected EncodableBitStringFields initializeFields() { Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); - Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { - for (int n : l) { - if (n < 0 || n > 2) { - return false; - } - } - return true; - }); EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsInField.MSPA_VERSION, new EncodableFixedInteger(6, UsIn.VERSION)); @@ -66,9 +56,6 @@ protected EncodableBitStringFields initializeFields() { new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsInField.ADDITIONAL_DATA_PROCESSING_CONSENT, new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); - fields.put(UsInField.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) - .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); return fields; } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInGpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInSensitiveDataConsentSegment.java similarity index 57% rename from iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInGpcSegment.java rename to iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInSensitiveDataConsentSegment.java index 5166694f..a73d6e10 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInGpcSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsInSensitiveDataConsentSegment.java @@ -4,38 +4,50 @@ import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsInField; +import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; -public class UsInGpcSegment extends AbstractLazilyEncodableSegment { +public class UsInSensitiveDataConsentSegment extends AbstractLazilyEncodableSegment { private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); - public UsInGpcSegment() { + public UsInSensitiveDataConsentSegment() { super(); } - public UsInGpcSegment(String encodedString) { + public UsInSensitiveDataConsentSegment(String encodedString) { super(); this.decode(encodedString); } @Override public List getFieldNames() { - return UsInField.USIN_GPC_SEGMENT_FIELD_NAMES; + return UsInField.USIN_SENSITIVE_DATA_CONSENT_SEGMENT_FIELD_NAMES; } @Override protected EncodableBitStringFields initializeFields() { + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + EncodableBitStringFields fields = new EncodableBitStringFields(); - fields.put(UsInField.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsInField.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsInField.GPC, new EncodableBoolean(false)); + fields.put(UsInField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsInField.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); return fields; } @@ -48,14 +60,14 @@ protected String encodeSegment(EncodableBitStringFields fields) { @Override protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { - if(encodedString == null || encodedString.isEmpty()) { + if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } try { String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } catch (Exception e) { - throw new DecodingException("Unable to decode UsInGpcSegment '" + encodedString + "'", e); + throw new DecodingException("Unable to decode UsInSensitiveDataConsentSegment '" + encodedString + "'", e); } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyCoreSegment.java index 0f67e504..88b11def 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyCoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyCoreSegment.java @@ -4,13 +4,11 @@ import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsKyField; import com.iab.gpp.encoder.section.UsKy; -import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -37,14 +35,6 @@ public List getFieldNames() { protected EncodableBitStringFields initializeFields() { Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); - Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { - for (int n : l) { - if (n < 0 || n > 2) { - return false; - } - } - return true; - }); EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsKyField.MSPA_VERSION, new EncodableFixedInteger(6, UsKy.VERSION)); @@ -66,9 +56,6 @@ protected EncodableBitStringFields initializeFields() { new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsKyField.ADDITIONAL_DATA_PROCESSING_CONSENT, new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); - fields.put(UsKyField.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) - .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); return fields; } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyGpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKySensitiveDataConsentSegment.java similarity index 57% rename from iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyGpcSegment.java rename to iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKySensitiveDataConsentSegment.java index af095930..5dc04aec 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKyGpcSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsKySensitiveDataConsentSegment.java @@ -4,38 +4,50 @@ import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsKyField; +import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; -public class UsKyGpcSegment extends AbstractLazilyEncodableSegment { +public class UsKySensitiveDataConsentSegment extends AbstractLazilyEncodableSegment { private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); - public UsKyGpcSegment() { + public UsKySensitiveDataConsentSegment() { super(); } - public UsKyGpcSegment(String encodedString) { + public UsKySensitiveDataConsentSegment(String encodedString) { super(); this.decode(encodedString); } @Override public List getFieldNames() { - return UsKyField.USKY_GPC_SEGMENT_FIELD_NAMES; + return UsKyField.USKY_SENSITIVE_DATA_CONSENT_SEGMENT_FIELD_NAMES; } @Override protected EncodableBitStringFields initializeFields() { + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + EncodableBitStringFields fields = new EncodableBitStringFields(); - fields.put(UsKyField.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsKyField.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsKyField.GPC, new EncodableBoolean(false)); + fields.put(UsKyField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsKyField.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); return fields; } @@ -48,14 +60,14 @@ protected String encodeSegment(EncodableBitStringFields fields) { @Override protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { - if(encodedString == null || encodedString.isEmpty()) { + if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } try { String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } catch (Exception e) { - throw new DecodingException("Unable to decode UsKyGpcSegment '" + encodedString + "'", e); + throw new DecodingException("Unable to decode UsKySensitiveDataConsentSegment '" + encodedString + "'", e); } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiCoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiCoreSegment.java index a4791d44..c8a0960a 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiCoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiCoreSegment.java @@ -4,13 +4,11 @@ import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsRiField; import com.iab.gpp.encoder.section.UsRi; -import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -37,14 +35,6 @@ public List getFieldNames() { protected EncodableBitStringFields initializeFields() { Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); - Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { - for (int n : l) { - if (n < 0 || n > 2) { - return false; - } - } - return true; - }); EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsRiField.MSPA_VERSION, new EncodableFixedInteger(6, UsRi.VERSION)); @@ -66,9 +56,6 @@ protected EncodableBitStringFields initializeFields() { new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsRiField.ADDITIONAL_DATA_PROCESSING_CONSENT, new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); - fields.put(UsRiField.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) - .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); return fields; } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiGpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiSensitiveDataConsentSegment.java similarity index 57% rename from iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiGpcSegment.java rename to iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiSensitiveDataConsentSegment.java index 3d47370c..127a37e9 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiGpcSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsRiSensitiveDataConsentSegment.java @@ -4,38 +4,50 @@ import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsRiField; +import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; -public class UsRiGpcSegment extends AbstractLazilyEncodableSegment { +public class UsRiSensitiveDataConsentSegment extends AbstractLazilyEncodableSegment { private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); - public UsRiGpcSegment() { + public UsRiSensitiveDataConsentSegment() { super(); } - public UsRiGpcSegment(String encodedString) { + public UsRiSensitiveDataConsentSegment(String encodedString) { super(); this.decode(encodedString); } @Override public List getFieldNames() { - return UsRiField.USRI_GPC_SEGMENT_FIELD_NAMES; + return UsRiField.USRI_SENSITIVE_DATA_CONSENT_SEGMENT_FIELD_NAMES; } @Override protected EncodableBitStringFields initializeFields() { + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + EncodableBitStringFields fields = new EncodableBitStringFields(); - fields.put(UsRiField.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsRiField.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsRiField.GPC, new EncodableBoolean(false)); + fields.put(UsRiField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsRiField.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); return fields; } @@ -48,14 +60,14 @@ protected String encodeSegment(EncodableBitStringFields fields) { @Override protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { - if(encodedString == null || encodedString.isEmpty()) { + if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } try { String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } catch (Exception e) { - throw new DecodingException("Unable to decode UsRiGpcSegment '" + encodedString + "'", e); + throw new DecodingException("Unable to decode UsRiSensitiveDataConsentSegment '" + encodedString + "'", e); } } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index 12d83aff..ce4f5625 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -149,7 +149,7 @@ public void testEncodeDefaultAll() { String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOcGA~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAA.QA~BQAAAAA.QA~BQAAAAA.QA~BQAAAAA.QA", + "DBACOcGA~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAA.QA~BQAA.AAA~BQAA.AAA~BQAA.AAA", gppString); } @@ -422,7 +422,7 @@ public void testDecodeDefaults() { @Test public void testDecodeDefaultsAll() { String gppString = - "DBACOcGA~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAA.QA~BQAAAAA.QA~BQAAAAA.QA~BQAAAAA.QA"; + "DBACOcGA~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAABA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA~BAAAAABA~BAAAAABA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAABAA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BAAAAABA.QA~BAAAAAAAQA.QA~BAAAAAQA.QA~BAAAAAQA.QA~BQAA.QA~BQAA.AAA~BQAA.AAA~BQAA.AAA"; GppModel gppModel = new GppModel(gppString); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsInTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsInTest.java index 193840c4..8b015c67 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsInTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsInTest.java @@ -14,7 +14,7 @@ public class UsInTest { @Test public void testEncode1() { UsIn usIn = new UsIn(); - Assertions.assertEquals("BQAAAAA.QA", usIn.encode()); + Assertions.assertEquals("BQAA.AAA", usIn.encode()); } @Test @@ -31,9 +31,8 @@ public void testEncode2() { usIn.setFieldValue(UsInField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); usIn.setFieldValue(UsInField.ADDITIONAL_DATA_PROCESSING_CONSENT, 1); usIn.setFieldValue(UsInField.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); - usIn.setFieldValue(UsInField.GPC, true); - Assertions.assertEquals("BVVVkkk.YA", usIn.encode()); + Assertions.assertEquals("BVVV.kkk", usIn.encode()); } @Test @@ -77,22 +76,26 @@ public void testSetInvalidValues() { } @Test - public void testEncodeWithGpcSegmentExcluded() { + public void testEncodeWithSensitiveDataConsentSegmentExcluded() { UsIn usIn = new UsIn(); - usIn.setFieldValue(UsInField.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BQAAAAA", usIn.encode()); + usIn.setFieldValue(UsInField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, false); + Assertions.assertEquals("BQAA", usIn.encode()); } @Test public void testDecode1() throws DecodingException { - UsIn usIn = new UsIn("BVVVkkk.YA"); + UsIn usIn = new UsIn("BVVV.kkk"); Assertions.assertEquals(1, usIn.getMspaCoveredTransaction()); Assertions.assertEquals(1, usIn.getMspaMode()); Assertions.assertEquals(1, usIn.getProcessingNotice()); - Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usIn.getSensitiveDataProcessing()); + Assertions.assertEquals(1, usIn.getSaleOptOutNotice()); + Assertions.assertEquals(1, usIn.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usIn.getSaleOptOut()); + Assertions.assertEquals(1, usIn.getTargetedAdvertisingOptOut()); Assertions.assertEquals(1, usIn.getKnownChildSensitiveDataConsents()); - Assertions.assertEquals(true, usIn.getGpc()); + Assertions.assertEquals(1, usIn.getAdditionalDataProcessingConsent()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usIn.getSensitiveDataProcessing()); } @Test() diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsKyTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsKyTest.java index 4f2904a9..d045a4cb 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsKyTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsKyTest.java @@ -14,7 +14,7 @@ public class UsKyTest { @Test public void testEncode1() { UsKy usKy = new UsKy(); - Assertions.assertEquals("BQAAAAA.QA", usKy.encode()); + Assertions.assertEquals("BQAA.AAA", usKy.encode()); } @Test @@ -31,9 +31,8 @@ public void testEncode2() { usKy.setFieldValue(UsKyField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); usKy.setFieldValue(UsKyField.ADDITIONAL_DATA_PROCESSING_CONSENT, 1); usKy.setFieldValue(UsKyField.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); - usKy.setFieldValue(UsKyField.GPC, true); - Assertions.assertEquals("BVVVkkk.YA", usKy.encode()); + Assertions.assertEquals("BVVV.kkk", usKy.encode()); } @Test @@ -63,20 +62,26 @@ public void testSetInvalidValues() { } @Test - public void testEncodeWithGpcSegmentExcluded() { + public void testEncodeWithSensitiveDataConsentSegmentExcluded() { UsKy usKy = new UsKy(); - usKy.setFieldValue(UsKyField.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BQAAAAA", usKy.encode()); + usKy.setFieldValue(UsKyField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, false); + Assertions.assertEquals("BQAA", usKy.encode()); } @Test public void testDecode1() throws DecodingException { - UsKy usKy = new UsKy("BVVVkkk.YA"); + UsKy usKy = new UsKy("BVVV.kkk"); Assertions.assertEquals(1, usKy.getMspaCoveredTransaction()); Assertions.assertEquals(1, usKy.getMspaMode()); + Assertions.assertEquals(1, usKy.getProcessingNotice()); + Assertions.assertEquals(1, usKy.getSaleOptOutNotice()); + Assertions.assertEquals(1, usKy.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usKy.getSaleOptOut()); + Assertions.assertEquals(1, usKy.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(1, usKy.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usKy.getAdditionalDataProcessingConsent()); Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usKy.getSensitiveDataProcessing()); - Assertions.assertEquals(true, usKy.getGpc()); } @Test() diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsRiTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsRiTest.java index eae8bbd0..2246f341 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsRiTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsRiTest.java @@ -14,7 +14,7 @@ public class UsRiTest { @Test public void testEncode1() { UsRi usRi = new UsRi(); - Assertions.assertEquals("BQAAAAA.QA", usRi.encode()); + Assertions.assertEquals("BQAA.AAA", usRi.encode()); } @Test @@ -31,9 +31,8 @@ public void testEncode2() { usRi.setFieldValue(UsRiField.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); usRi.setFieldValue(UsRiField.ADDITIONAL_DATA_PROCESSING_CONSENT, 1); usRi.setFieldValue(UsRiField.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); - usRi.setFieldValue(UsRiField.GPC, true); - Assertions.assertEquals("BVVVkkk.YA", usRi.encode()); + Assertions.assertEquals("BVVV.kkk", usRi.encode()); } @Test @@ -63,20 +62,26 @@ public void testSetInvalidValues() { } @Test - public void testEncodeWithGpcSegmentExcluded() { + public void testEncodeWithSensitiveDataConsentSegmentExcluded() { UsRi usRi = new UsRi(); - usRi.setFieldValue(UsRiField.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BQAAAAA", usRi.encode()); + usRi.setFieldValue(UsRiField.SENSITIVE_DATA_CONSENT_SEGMENT_INCLUDED, false); + Assertions.assertEquals("BQAA", usRi.encode()); } @Test public void testDecode1() throws DecodingException { - UsRi usRi = new UsRi("BVVVkkk.YA"); + UsRi usRi = new UsRi("BVVV.kkk"); Assertions.assertEquals(1, usRi.getMspaCoveredTransaction()); Assertions.assertEquals(1, usRi.getMspaMode()); + Assertions.assertEquals(1, usRi.getProcessingNotice()); + Assertions.assertEquals(1, usRi.getSaleOptOutNotice()); + Assertions.assertEquals(1, usRi.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usRi.getSaleOptOut()); + Assertions.assertEquals(1, usRi.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(1, usRi.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usRi.getAdditionalDataProcessingConsent()); Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usRi.getSensitiveDataProcessing()); - Assertions.assertEquals(true, usRi.getGpc()); } @Test()