Skip to content

Commit

Permalink
Add function to get TCF policy version from consent string (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
bsardo authored Jun 14, 2023
1 parent 29f4610 commit ca19899
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 0 deletions.
3 changes: 3 additions & 0 deletions api/consent.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ type VendorConsents interface {
// The latest version can always be found at https://vendorlist.consensu.org/vendorlist.json
VendorListVersion() uint16

// TCFPolicyVersion indicates the TCF policy version needed to interpret this consent string.
TCFPolicyVersion() uint8

// MaxVendorID describes how many vendors are encoded into the string.
// This is the upper bound (inclusive) on valid inputs for HasConsent(id).
MaxVendorID() uint16
Expand Down
5 changes: 5 additions & 0 deletions vendorconsent/tcf1/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ func (c consentMetadata) VendorListVersion() uint16 {
return binary.BigEndian.Uint16([]byte{leftByte, rightByte})
}

// TCFPolicyVersion is not implemented in TCF1
func (c consentMetadata) TCFPolicyVersion() uint8 {
return 0
}

func (c consentMetadata) MaxVendorID() uint16 {
// The max vendor ID is stored in bits 156 - 171
leftByte := byte((c[19]&0x0f)<<4 + (c[20]&0xf0)>>4)
Expand Down
6 changes: 6 additions & 0 deletions vendorconsent/tcf2/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ func (c ConsentMetadata) VendorListVersion() uint16 {
return binary.BigEndian.Uint16([]byte{leftByte, rightByte})
}

// TCFPolicyVersion returns the TCF policy version stored in bits 133 to 138
func (c ConsentMetadata) TCFPolicyVersion() uint8 {
// Stored in bits 133-138.. which is [0000xxxx xx00000000] starting at the 17th byte
return uint8(((c.data[16] & 0x0f) << 2) | (c.data[17] & 0xc0) >> 6)
}

// MaxVendorID returns the maximum value for vendor identifier in bits 214 to 229
func (c ConsentMetadata) MaxVendorID() uint16 {
// The max vendor ID is stored in bits 214 - 229
Expand Down
59 changes: 59 additions & 0 deletions vendorconsent/tcf2/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,65 @@ func TestLanguageExtremes(t *testing.T) {
assertStringsEqual(t, "SV", consent.ConsentLanguage())
}

func TestTCFPolicyVersion(t *testing.T) {
baseConsent := "CPtGDMAPtGDMALMAAAENA_C_AAAAAAAAACiQAAAAAAAA"
index := 22 // policy version is at the 23rd 6-bit base64 position
tests := []struct{
name string
base64Char string
expected uint8
}{
{
name: "char_A_bits_000000_is_version_0",
base64Char: "A",
expected: 0,
},
{
name: "char_B_bits_000001_is_version_1",
base64Char: "B",
expected: 1,
},
{
name: "char_C_bits_000010_is_version_2",
base64Char: "C",
expected: 2,
},
{
name: "char_E_bits_000100_is_version_4",
base64Char: "E",
expected: 4,
},
{
name: "char_I_bits_001000_is_version_8",
base64Char: "I",
expected: 8,
},
{
name: "char_Q_bits_010000_is_version_16",
base64Char: "Q",
expected: 16,
},
{
name: "char_g_bits_100000_is_version_32",
base64Char: "g",
expected: 32,
},
{
name: "char_underscore_bits_111111_is_version_63",
base64Char: "_",
expected: 63,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
updatedConsent := baseConsent[:index] + tt.base64Char + baseConsent[index+1:]
consent, err := Parse(decode(t, updatedConsent))
assertNilError(t, err)
assertUInt8sEqual(t, tt.expected, consent.TCFPolicyVersion())
})
}
}

func TestTCF2Fields(t *testing.T) {
baseConsent, err := Parse(decode(t, "COx3XOeOx3XOeLkAAAENAfCIAAAAAHgAAIAAAAAAAAAA"))
assertNilError(t, err)
Expand Down

0 comments on commit ca19899

Please sign in to comment.