From df5c65b6b068bb24e456da7a7473916dc16a938e Mon Sep 17 00:00:00 2001 From: Andreas Wunderlich Date: Thu, 6 Aug 2020 02:27:32 +0200 Subject: [PATCH 1/4] vendorconsent.tcf2: parseRangeSection: Fixed hardcoded values being used instead of parameter startbit --- vendorconsent/tcf2/rangesection.go | 8 +++++--- vendorconsent/tcf2/rangesection_test.go | 23 ++++++++++++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/vendorconsent/tcf2/rangesection.go b/vendorconsent/tcf2/rangesection.go index 85d5381..c5116b1 100644 --- a/vendorconsent/tcf2/rangesection.go +++ b/vendorconsent/tcf2/rangesection.go @@ -9,17 +9,19 @@ import ( func parseRangeSection(metadata ConsentMetadata, maxVendorID uint16, startbit uint) (*rangeSection, uint, error) { data := metadata.data - // This makes an int from bits 230-241 + if len(data) < 31 { return nil, 0, fmt.Errorf("vendor consent strings using RangeSections require at least 31 bytes. Got %d", len(data)) } - numEntries, err := bitutils.ParseUInt12(data, 230) + + // This makes an int from bits [startBit, startBit + 12) + numEntries, err := bitutils.ParseUInt12(data, startbit) if err != nil { return nil, 0, err } // Parse out the "exceptions" here. - currentOffset := uint(242) + currentOffset := startbit + 12 consents := make([]rangeConsent, numEntries) for i := uint16(0); i < numEntries; i++ { thisConsent, bitsConsumed, err := parseRangeConsent(data, currentOffset, maxVendorID) diff --git a/vendorconsent/tcf2/rangesection_test.go b/vendorconsent/tcf2/rangesection_test.go index 14aecf4..4428b90 100644 --- a/vendorconsent/tcf2/rangesection_test.go +++ b/vendorconsent/tcf2/rangesection_test.go @@ -8,14 +8,14 @@ import ( func TestRangeSectionConsent(t *testing.T) { // String built using http://iabtcf.com/#/encode // This sample encodes a mix of Single- and Range-typed consent exceptions. - consent, err := Parse(decode(t, "COyiILmOyiILmADACHENAPCAAAAAAAAAAAAAE5QBgALgAqgD8AQACSwEygJyAAAAAA")) + consent, err := Parse(decode(t, "COyfVVoOyfVVoADACHENAwCAAAAAAAAAAAAAE5QBgALgAqgD8AQACSwEygJyAnSAMABgAFkAgQCDASeAmYBOgAA")) assertNilError(t, err) assertUInt8sEqual(t, 2, consent.Version()) assertUInt16sEqual(t, 3, consent.CmpID()) assertUInt16sEqual(t, 2, consent.CmpVersion()) assertUInt8sEqual(t, 7, consent.ConsentScreen()) assertStringsEqual(t, "EN", consent.ConsentLanguage()) - assertUInt16sEqual(t, 15, consent.VendorListVersion()) + assertUInt16sEqual(t, 48, consent.VendorListVersion()) assertUInt16sEqual(t, 626, consent.MaxVendorID()) // The above encoder doesn't support setting purposes. @@ -27,11 +27,24 @@ func TestRangeSectionConsent(t *testing.T) { vendorsWithConsent := buildMap(23, 42, 126, 127, 128, 587, 613, 626) for i := uint16(1); i <= consent.MaxVendorID(); i++ { - _, ok := vendorsWithConsent[uint(i)] - if ok != consent.VendorConsent(i) { + _, expected := vendorsWithConsent[uint(i)] + actual := consent.VendorConsent(i) + if expected != actual { fmt.Printf("Vendor: %d failed\n", i) } - assertBoolsEqual(t, ok, consent.VendorConsent(i)) + assertBoolsEqual(t, expected, actual) + } + + // TODO func VendorLegitInterest() should be added to api.VendorConsents + consentMetadata := consent.(ConsentMetadata) + vendorsLegitimateInterestWithConsent := buildMap(24, 44, 129, 130, 131, 591, 614, 628) + for i := uint16(1); i <= consent.MaxVendorID(); i++ { + _, expected := vendorsLegitimateInterestWithConsent[uint(i)] + actual := consentMetadata.VendorLegitInterest(i) + if expected != actual { + fmt.Printf("VendorLegitInterest: %d failed\n", i) + } + assertBoolsEqual(t, expected, actual) } } From 14f7fbde59433d3473e0904bc9f55a3805201f3f Mon Sep 17 00:00:00 2001 From: Andreas Wunderlich Date: Thu, 6 Aug 2020 03:19:37 +0200 Subject: [PATCH 2/4] vendorconsent.tcf2: vendorConsentsResolver: Added func MaxVendorID(), implemented it on structs consentBitField and rangeSection --- vendorconsent/tcf2/bitfield.go | 8 ++++++++ vendorconsent/tcf2/metadata.go | 1 + vendorconsent/tcf2/rangesection.go | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/vendorconsent/tcf2/bitfield.go b/vendorconsent/tcf2/bitfield.go index 8842d49..d76a96c 100644 --- a/vendorconsent/tcf2/bitfield.go +++ b/vendorconsent/tcf2/bitfield.go @@ -26,6 +26,14 @@ type consentBitField struct { maxVendorID uint16 } +func (f *consentBitField) MaxVendorID() uint16 { + if f == nil { + return 0 + } + + return f.maxVendorID +} + func (f *consentBitField) VendorConsent(id uint16) bool { if id < 1 || id > f.maxVendorID { return false diff --git a/vendorconsent/tcf2/metadata.go b/vendorconsent/tcf2/metadata.go index 087c336..f237c6f 100644 --- a/vendorconsent/tcf2/metadata.go +++ b/vendorconsent/tcf2/metadata.go @@ -44,6 +44,7 @@ type ConsentMetadata struct { } type vendorConsentsResolver interface { + MaxVendorID() uint16 VendorConsent(id uint16) bool } diff --git a/vendorconsent/tcf2/rangesection.go b/vendorconsent/tcf2/rangesection.go index c5116b1..8bd4676 100644 --- a/vendorconsent/tcf2/rangesection.go +++ b/vendorconsent/tcf2/rangesection.go @@ -100,6 +100,14 @@ type rangeSection struct { maxVendorID uint16 } +func (p *rangeSection) MaxVendorID() uint16 { + if p == nil { + return 0 + } + + return p.maxVendorID +} + // VendorConsents implementation func (p rangeSection) VendorConsent(id uint16) bool { if id < 1 || id > p.maxVendorID { From 74ffa6775bf43bd2151a8de50ef7efb78120fde3 Mon Sep 17 00:00:00 2001 From: Andreas Wunderlich Date: Thu, 6 Aug 2020 03:21:38 +0200 Subject: [PATCH 3/4] vendorconsent.tcf2: ConsentMetadata: Added and integrated func MaxLegitimateInterestVendorID() The max vendor ID may differ between the vendor consent and vendor legitimate interest sections. Therefore, this commit adds a new func MaxLegitimateInterestVendorID() to ConsentMetadata. --- vendorconsent/tcf2/metadata.go | 4 ++++ vendorconsent/tcf2/rangesection_test.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/vendorconsent/tcf2/metadata.go b/vendorconsent/tcf2/metadata.go index f237c6f..30cf722 100644 --- a/vendorconsent/tcf2/metadata.go +++ b/vendorconsent/tcf2/metadata.go @@ -126,6 +126,10 @@ func (c ConsentMetadata) VendorListVersion() uint16 { return binary.BigEndian.Uint16([]byte{leftByte, rightByte}) } +func (c ConsentMetadata) MaxLegitimateInterestVendorID() uint16 { + return c.vendorLegitimateInterests.MaxVendorID() +} + func (c ConsentMetadata) MaxVendorID() uint16 { // The max vendor ID is stored in bits 213 - 228 [00000xxx xxxxxxxx xxxxx000] leftByte := ((c.data[26] & 0x07) << 5) | ((c.data[27] & 0xf8) >> 3) diff --git a/vendorconsent/tcf2/rangesection_test.go b/vendorconsent/tcf2/rangesection_test.go index 4428b90..3af6ba0 100644 --- a/vendorconsent/tcf2/rangesection_test.go +++ b/vendorconsent/tcf2/rangesection_test.go @@ -38,7 +38,7 @@ func TestRangeSectionConsent(t *testing.T) { // TODO func VendorLegitInterest() should be added to api.VendorConsents consentMetadata := consent.(ConsentMetadata) vendorsLegitimateInterestWithConsent := buildMap(24, 44, 129, 130, 131, 591, 614, 628) - for i := uint16(1); i <= consent.MaxVendorID(); i++ { + for i := uint16(1); i <= consentMetadata.MaxLegitimateInterestVendorID(); i++ { _, expected := vendorsLegitimateInterestWithConsent[uint(i)] actual := consentMetadata.VendorLegitInterest(i) if expected != actual { From 6cd748cc061f20410528b528ee27ff3234c86b72 Mon Sep 17 00:00:00 2001 From: Andreas Wunderlich Date: Mon, 10 Aug 2020 23:05:08 +0200 Subject: [PATCH 4/4] vendorconsent.tcf2: ConsentMetadata: Renamed func MaxLegitimateInterestVendorID() to VendorLegitInterestMaxID() --- vendorconsent/tcf2/metadata.go | 8 ++++---- vendorconsent/tcf2/rangesection_test.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/vendorconsent/tcf2/metadata.go b/vendorconsent/tcf2/metadata.go index 30cf722..ebe1435 100644 --- a/vendorconsent/tcf2/metadata.go +++ b/vendorconsent/tcf2/metadata.go @@ -119,6 +119,10 @@ func (c ConsentMetadata) ConsentLanguage() string { return string([]byte{leftChar + 65, rightChar + 65}) // Unicode A-Z is 65-90 } +func (c ConsentMetadata) VendorLegitInterestMaxID() uint16 { + return c.vendorLegitimateInterests.MaxVendorID() +} + func (c ConsentMetadata) VendorListVersion() uint16 { // The vendor list version is stored in bits 120 - 131 rightByte := ((c.data[16] & 0xf0) >> 4) | ((c.data[15] & 0x0f) << 4) @@ -126,10 +130,6 @@ func (c ConsentMetadata) VendorListVersion() uint16 { return binary.BigEndian.Uint16([]byte{leftByte, rightByte}) } -func (c ConsentMetadata) MaxLegitimateInterestVendorID() uint16 { - return c.vendorLegitimateInterests.MaxVendorID() -} - func (c ConsentMetadata) MaxVendorID() uint16 { // The max vendor ID is stored in bits 213 - 228 [00000xxx xxxxxxxx xxxxx000] leftByte := ((c.data[26] & 0x07) << 5) | ((c.data[27] & 0xf8) >> 3) diff --git a/vendorconsent/tcf2/rangesection_test.go b/vendorconsent/tcf2/rangesection_test.go index 3af6ba0..85216ac 100644 --- a/vendorconsent/tcf2/rangesection_test.go +++ b/vendorconsent/tcf2/rangesection_test.go @@ -38,7 +38,7 @@ func TestRangeSectionConsent(t *testing.T) { // TODO func VendorLegitInterest() should be added to api.VendorConsents consentMetadata := consent.(ConsentMetadata) vendorsLegitimateInterestWithConsent := buildMap(24, 44, 129, 130, 131, 591, 614, 628) - for i := uint16(1); i <= consentMetadata.MaxLegitimateInterestVendorID(); i++ { + for i := uint16(1); i <= consentMetadata.VendorLegitInterestMaxID(); i++ { _, expected := vendorsLegitimateInterestWithConsent[uint(i)] actual := consentMetadata.VendorLegitInterest(i) if expected != actual {