Fix TcfCaV1 (Canada) OptimizedRange + base64 encoding, with backwards-compatible decoding#107
Open
chuff wants to merge 4 commits into
Open
Fix TcfCaV1 (Canada) OptimizedRange + base64 encoding, with backwards-compatible decoding#107chuff wants to merge 4 commits into
chuff wants to merge 4 commits into
Conversation
Two Canada (TcfCaV1) encoding bugs: 1. VendorExpressConsent, VendorImpliedConsent, and DisclosedVendors are OptimizedRange per the spec (Fibonacci-coded in GPP), but used EncodableOptimizedFixedRange. Switch to EncodableOptimizedFibonacciRange. 2. The disclosed-vendors segment used TraditionalBase64UrlEncoder; the core and publisher-purposes segments use CompressedBase64UrlEncoder. Switch it to CompressedBase64UrlEncoder. With both fixes the ES output is now byte-identical to iabgpp-java for the same inputs (verified the disclosed segment goes from ...IAGO5wAA to ...IAGO5w, matching Java). Regenerate the affected test vectors and add a round-trip test exercising the Fibonacci range path with sparse vendor IDs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per the GPP spec, PubRestrictions is N-ArrayOfRanges(6,2) where each record's ids are an OptimizedRange (Fibonacci coded). It was using EncodableArrayOfFixedIntegerRanges, which encodes ids as fixed-integer ranges (the legacy ArrayOfRanges form shared with TCF EU). Add EncodableArrayOfOptimizedFibonacciRanges, which reuses the existing EncodableOptimizedFibonacciRange for each record's ids, export it, and point TcfCaV1's PUB_RESTRICTIONS field at it. The fixed variant is left untouched for TCF EU. Regenerate the affected TcfCaV1 test vectors and extend the round-trip test to cover PubRestrictions with sparse ids (Fibonacci range path). The PubRestrictions string now matches iabgpp-java byte-for-byte. Note: verified by Java/ES cross-implementation agreement and round-trip, not yet against an external reference string. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Strings produced by the pre-fix encoder used fixed-integer ranges for the
OptimizedRange / N-ArrayOfRanges fields (VendorExpressConsent,
VendorImpliedConsent, DisclosedVendors, PubRestrictions), and a
traditional-base64 disclosed-vendors segment. Decoding those with the new
Fibonacci datatypes would misread the data.
The TcfCaV1 core and disclosed-vendors segments now decode by trying the
spec-compliant (Fibonacci) interpretation first and, if it does not
round-trip back to the input bitstring, falling back to the legacy
(fixed-range) interpretation. Whichever re-encodes to the original bits
is the one that produced the string. Decoded values are copied into the
current (Fibonacci) fields. (base64 decode is padding-agnostic, so the
traditional-vs-compressed difference does not affect decoding.)
Also fixes an incorrect decode error message in the disclosed-vendors
segment ("HeaderV1CoreSegment" -> "TcfCaV1DisclosedVendorsSegment").
Tests: decode real pre-fix strings (vendors, PubRestrictions, and the
traditional-base64 disclosed segment) and assert correct values.
Note: unlike iabgpp-java, re-encoding a decoded section here returns the
original string unchanged because AbstractLazilyEncodableSection.setFieldValue
does not mark the section dirty (pre-existing behavior); decoding is
unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…iant Adds a regression test using a real pre-fix (fixed-range) TcfCaV1 string: verifies it decodes correctly (CmpId, language, 14 express + 46 implied vendors) and that re-encoding (after marking the section dirty, the way GppModel does) emits the spec-compliant Fibonacci form. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Per the GPP Consent String Specification, the Canada (
TcfCaV1) section encodes several fields asOptimizedRange/N-ArrayOfRanges(Fibonacci coded), and its disclosed-vendors segment should use the compressed base64 encoder. This corrects both and keeps existing strings decodable.Fixes:
VendorExpressConsent,VendorImpliedConsent,DisclosedVendors(OptimizedRange) —EncodableOptimizedFixedRange→EncodableOptimizedFibonacciRange.PubRestrictions(N-ArrayOfRanges(6,2), whoseidsare anOptimizedRange) — newEncodableArrayOfOptimizedFibonacciRangesreusing the existing FibonacciOptimizedRangefor each record's ids. The fixed variant is left untouched for TCF EU.TraditionalBase64UrlEncoder→CompressedBase64UrlEncoder(the core and publisher-purposes segments already used compressed).With all three, the output is now byte-identical to iabgpp-java for the same inputs (e.g. the disclosed segment goes from
…IAGO5wAAto…IAGO5w).Backwards compatibility
The
TcfCaV1core and disclosed-vendors segments decode by trying the spec-compliant (Fibonacci) interpretation first and, if it doesn't round-trip back to the input bitstring, falling back to the legacy (fixed-range) interpretation. base64 decode is padding-agnostic, so the traditional-vs-compressed change doesn't affect decoding. Strings produced by the previous encoder still decode correctly.Note: backwards compatible on read; the encoder now emits Fibonacci/compressed output, so consumers still running the previous code will not read the new range-form strings — a deliberate wire-format correction.
Also fixes an incorrect decode error message in the disclosed-vendors segment (
HeaderV1CoreSegment→TcfCaV1DisclosedVendorsSegment).Test plan
tsc-compiled classes and match iabgpp-java byte-for-byte)🤖 Generated with Claude Code