forked from LiveRamp/iabconsent
-
Notifications
You must be signed in to change notification settings - Fork 1
/
v2_parsed_consent.go
478 lines (437 loc) · 21.8 KB
/
v2_parsed_consent.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
package iabconsent
import (
"time"
"github.com/pkg/errors"
)
// V2ParsedConsent represents data extracted from an v2 TCF Consent String.
type V2ParsedConsent struct {
// Version number of the encoding format.
Version int
// Epoch deciseconds when this TC String was first created (should not be changed
// unless a new TCString is created from scratch).
Created time.Time
// Epoch deciseconds when TC String was last updated (Must be updated any time a
// value is changed).
LastUpdated time.Time
// Consent Management Platform ID that last updated the TC String.
// A unique ID will be assigned to each Consent Management Platform.
CMPID int
// Consent Management Platform version of the CMP that last updated this TC String.
// Each change to a CMP should increment their internally assigned version number as
// a record of which version the user gave consent and transparency was established.
CMPVersion int
// CMP Screen number at which consent was given for a user with the CMP that last
// updated this TC String. The number is a CMP internal designation and is CMPVersion
// specific. The number is used for identifying on which screen a user gave consent
// as a record.
ConsentScreen int
// Two-letter ISO 639-1 language code in which the CMP UI was presented.
ConsentLanguage string
// Number corresponds to the Global Vendor List (GVL) vendorListVersion.
VendorListVersion int
// Version of policy used within GVL.
TCFPolicyVersion int
// Whether the signals encoded in this TC String were from service-specific storage
// (true) versus ‘global’ consensu.org shared storage (false).
IsServiceSpecific bool
// Setting this to 1 means that a publisher-run CMP – that is still IAB Europe
// registered – is using customized Stack descriptions and not the standard stack
// descriptions defined in the Policies. A CMP that services multiple publishers sets
// this value to 0.
UseNonStandardStacks bool
// The TCF Policies designates certain Features as “special” which means a CMP must
// afford the user a means to opt in to their use. These “Special Features” are
// published and numerically identified in the Global Vendor List separately from
// normal Features.
SpecialFeaturesOptIn map[int]bool
// The user’s consent value for each Purpose established on the legal basis of consent.
// The Purposes are numerically identified and published in the Global Vendor List.
// From left to right, Purpose 1 maps to the 0th bit, purpose 24 maps to the bit at
// index 23. Special Purposes are a different ID space and not included in this field.
PurposesConsent map[int]bool
// The Purpose’s transparency requirements are met for each Purpose on the legal basis
// of legitimate interest and the user has not exercised their “Right to Object” to that
// Purpose. By default or if the user has exercised their “Right to Object” to a Purpose,
// the corresponding bit for that Purpose is set to 0. From left to right, Purpose 1 maps
// to the 0th bit, purpose 24 maps to the bit at index 23. Special Purposes are a
// different ID space and not included in this field.
PurposesLITransparency map[int]bool
// CMPs can use the PublisherCC field to indicate the legal jurisdiction the publisher is
// under to help vendors determine whether the vendor needs consent for Purpose 1. In a
// globally-scoped TC string, this field must always have a value of 0. When a CMP
// encounters a globally-scoped TC String with PurposeOneTreatment=1 then it is considered
// invalid and the CMP must discard it and re-establish transparency and consent.
PurposeOneTreatment bool
// The country code of the country that determines legislation of reference. Commonly,
// this corresponds to the country in which the publisher’s business entity is established.
PublisherCC string
// The maximum Vendor ID that is represented in the following bit field or range encoding.
MaxConsentVendorID int
// The encoding scheme used to encode the IDs in the section – Either a BitField Section or
// Range Section follows. Encoding logic should choose the encoding scheme that results in
// the smaller output size for a given set.
IsConsentRangeEncoding bool
// The consent value for each Vendor ID.
ConsentedVendors map[int]bool
// Number of RangeEntry sections to follow.
NumConsentEntries int
// A single or range of Vendor ID(s) who have received consent. If a Vendor ID is not within
// the bounds of the ranges then the vendor is assumed to have “No Consent”.
ConsentedVendorsRange []*RangeEntry
// The maximum Vendor ID that is represented in the following bit field or range encoding.
MaxInterestsVendorID int
// The encoding scheme used to encode the IDs in the section – Either a BitField Section or
// Range Section follows. Encoding logic should encode with the encoding scheme that results
// in the smaller output size for a given set.
IsInterestsRangeEncoding bool
// The legitimate interest value for each Vendor ID from 1 to MaxVendorId. Set the bit
// corresponding to a given vendor to 1 if the CMP has established transparency for a vendor's
// legitimate interest disclosures. If a user exercises their “Right To Object” to a vendor’s
// processing based on a legitimate interest, then that vendor’s bit must be set to 0.
InterestsVendors map[int]bool
// Number of RangeEntry sections to follow.
NumInterestsEntries int
// A single or range of Vendor ID(s) who have established transparency for their legitimate
// interest disclosures with the user. If a Vendor ID is not within the bounds of the ranges
// then they have not established that transparency.
InterestsVendorsRange []*RangeEntry
// Number of restriction records to follow.
NumPubRestrictions int
// Each Publisher Restriction Entry is made up of three parts: Purpose ID, Restriction Type and,
// List of Vendor IDs under that Purpose restriction.
PubRestrictionEntries []*PubRestrictionEntry
// The DisclosedVendors is a TC String segment that signals which vendors have been disclosed
// to a given user by a CMP.
OOBDisclosedVendors *OOBVendorList
// Signals which vendors the publisher permits to use OOB legal bases.
OOBAllowedVendors *OOBVendorList
// Publishers may need to establish transparency and consent for a set of personal data processing
// purposes for their own use. For example, a publisher that wants to set a frequency-capping
// first-party cookie should request user consent for Purpose 1 "Store and/or access information on
// a device" in jurisdictions where it is required.
//
// The Publisher TC segment in the TC string represents publisher purposes transparency & consent
// signals which is different than the other TC String segments; they are used to collect consumer
// purposes transparency & consent for vendors. This segment supports the standard list of purposes
// defined by the TCF as well as Custom Purposes defined by the publisher if they so choose.
*PublisherTCEntry
}
// V2CAParsedConsent represents data extracted from an v2 CA TCF Consent String.
type V2CAParsedConsent struct {
// Version number of the encoding format.
Version int
// Epoch deciseconds when this TC String was first created (should not be changed
// unless a new TCString is created from scratch).
Created time.Time
// Epoch deciseconds when TC String was last updated (Must be updated any time a
// value is changed).
LastUpdated time.Time
// Consent Management Platform ID that last updated the TC String.
// A unique ID will be assigned to each Consent Management Platform.
CMPID int
// Consent Management Platform version of the CMP that last updated this TC String.
// Each change to a CMP should increment their internally assigned version number as
// a record of which version the user gave consent and transparency was established.
CMPVersion int
// CMP Screen number at which consent was given for a user with the CMP that last
// updated this TC String. The number is a CMP internal designation and is CMPVersion
// specific. The number is used for identifying on which screen a user gave consent
// as a record.
ConsentScreen int
// Two-letter ISO 639-1 language code in which the CMP UI was presented.
ConsentLanguage string
// Number corresponds to the Global Vendor List (GVL) vendorListVersion.
VendorListVersion int
// Version of policy used within GVL.
TCFPolicyVersion int
// Setting this to 1 means that a publisher-run CMP – that is still IAB Europe
// registered – is using customized Stack descriptions and not the standard stack
// descriptions defined in the Policies. A CMP that services multiple publishers sets
// this value to 0.
UseNonStandardStacks bool
// The TCF Policies designates certain Features as “special” which means a CMP must
// afford the user a means to opt in to their use. These “Special Features” are
// published and numerically identified in the Global Vendor List separately from
// normal Features.
SpecialFeatureExpressConsent map[int]bool
// The user’s consent value for each Purpose established on the legal basis of consent.
// The Purposes are numerically identified and published in the Global Vendor List.
// From left to right, Purpose 1 maps to the 0th bit, purpose 24 maps to the bit at
// index 23. Special Purposes are a different ID space and not included in this field.
PurposesExpressConsent map[int]bool
// The Purpose’s transparency requirements are met for each Purpose on the legal basis
// of legitimate interest and the user has not exercised their “Right to Object” to that
// Purpose. By default or if the user has exercised their “Right to Object” to a Purpose,
// the corresponding bit for that Purpose is set to 0. From left to right, Purpose 1 maps
// to the 0th bit, purpose 24 maps to the bit at index 23. Special Purposes are a
// different ID space and not included in this field.
PurposesImpliedConsent map[int]bool
MaxExpressConsentVendorID int
IsExpressConsentRangeEncoding bool
// The consent value for each Vendor ID.
ExpressConsentedVendors map[int]bool
// Number of RangeEntry sections to follow.
NumExpressConsentEntries int
// A single or range of Vendor ID(s) who have received consent. If a Vendor ID is not within
// the bounds of the ranges then the vendor is assumed to have “No Consent”.
VendorExpressConsent []*RangeEntry
MaxImpliedConsentVendorID int
IsImpliedConsentRangeEncoding bool
// The consent value for each Vendor ID.
ImpliedConsentedVendors map[int]bool
// Number of RangeEntry sections to follow.
NumImpliedConsentEntries int
// A single or range of Vendor ID(s) who have received consent. If a Vendor ID is not within
// the bounds of the ranges then the vendor is assumed to have “No Consent”.
VendorImpliedConsent []*RangeEntry
*PublisherTCEntry
}
// RestrictionType is an enum type of publisher restriction types.
type RestrictionType int
const (
// Purpose Flatly Not Allowed by Publisher (regardless of Vendor declarations).
PurposeFlatlyNotAllowed RestrictionType = iota
// Require Consent (if Vendor has declared the Purpose IDs legal basis as Legitimate
// Interest and flexible)
RequireConsent
// Require Legitimate Interest (if Vendor has declared the Purpose IDs legal basis as Consent and flexible).
RequireLegitimateInterest
// Undefined (not used).
Undefined
)
// PubRestrictionEntry is made up of three parts: Purpose ID, Restriction Type and, List
// of Vendor IDs under that Purpose restriction.
type PubRestrictionEntry struct {
// The Vendor’s declared Purpose ID that the publisher has indicated that they are overriding.
PurposeID int
// The restriction type.
RestrictionType RestrictionType
// Number of RangeEntry sections to follow.
NumEntries int
// A single or range of Vendor ID(s) who the publisher has designated as restricted under the
// Purpose ID in this PubRestrictionsEntry.
RestrictionsRange []*RangeEntry
}
// PublisherTCEntry represents Publisher Purposes Transparency and Consent.
type PublisherTCEntry struct {
// Enum type
SegmentType SegmentType
// The user's consent value for each Purpose established on the legal basis of consent, for the publisher.
// The Purposes are numerically identified and published in the Global Vendor List.
PubPurposesConsent map[int]bool
// The Purpose’s transparency requirements are met for each Purpose established on the legal basis of legitimate
// interest and the user has not exercised their “Right to Object” to that Purpose. By default or if the user has
// exercised their “Right to Object to a Purpose, the corresponding bit for that purpose is set to 0.
PubPurposesLITransparency map[int]bool
// The number of Custom Purposes.
NumCustomPurposes int
// The consent value for each CustomPurposeId from 1 to NumberCustomPurposes,
CustomPurposesConsent map[int]bool
// The legitimate Interest disclosure establishment value for each CustomPurposeId from 1 to NumberCustomPurposes.
CustomPurposesLITransparency map[int]bool
}
// SegmentType is an enum type of possible Out-of-Band (OOB) legal bases.
type SegmentType int
const (
// The core string.
CoreString SegmentType = iota
// The DisclosedVendors is a TC String segment that signals which vendors have been disclosed to a given user
// by a CMP. This segment is required when saving a global-context TC String. When a CMP updates a globally-scoped
// TC String, the CMP MUST retain the existing values and only add new disclosed Vendor IDs that had not been added
// by other CMPs in prior interactions with this user.
DisclosedVendors
// Signals which vendors the publisher permits to use OOB legal bases.
AllowedVendors
// Publishers may need to establish transparency and consent for a set of personal data processing
// purposes for their own use. For example, a publisher that wants to set a frequency-capping first-party
// cookie should request user consent for Purpose 1 "Store and/or access information on a device" in
// jurisdictions where it is required.
//
// The Publisher TC segment in the TC string represents publisher purposes transparency & consent signals
// which is different than the other TC String segments; they are used to collect consumer purposes transparency
// & consent for vendors. This segment supports the standard list of purposes defined by the TCF as well as
// Custom Purposes defined by the publisher if they so choose.
PublisherTC
)
// OOBVendorList is represents either a DisclosedVendors or AllowedVendors list.
type OOBVendorList struct {
// Enum type.
SegmentType SegmentType
// The maximum Vendor ID that is included.
MaxVendorID int
// The encoding scheme used to encode the IDs in the section – Either a BitField Section or Range Section follows.
// Encoding logic should choose the encoding scheme that results in the smaller output size for a given set.
IsRangeEncoding bool
// The value for each Vendor ID from 1 to MaxVendorId. Set the bit corresponding to a given Vendor ID to 1 if the
// Publisher permits the vendor to use OOB legal bases.
Vendors map[int]bool
// Number of RangeEntry sections to follow.
NumEntries int
// A single or range of Vendor ID(s) of Vendor(s) who are allowed to use OOB legal bases on the given publisher’s
// digital property. If a Vendor ID is not within the bounds of the ranges then they are not allowed to use OOB
// legal bases on the given publisher's digital property.
VendorEntries []*RangeEntry
}
// SpecialFeature is an enum type for special features. The TCF Policies designates certain Features as “special” which
// means a CMP must afford the user a means to opt in to their use. These “Special Features” are published and
// numerically identified in the Global Vendor List separately from normal Features.
type SpecialFeature int
const (
InvalidSpecialFeature SpecialFeature = iota
// Vendors can:
// - Collect and process precise geolocation data in support of one or more purposes.
// - N.B. Precise geolocation means that there are no restrictions on the precision of a user’s location;
// this can be accurate to within several meters.
UsePreciseGeolocation
// Vendors can:
// - Create an identifier using data collected via actively scanning a device for specific characteristics, e.g.
// installed fonts or screen resolution.
// - Use such an identifier to re-identify a device.
ActivelyScanDevice
)
// SpecialPurpose is an enum type for special purposes.
type SpecialPurpose int
const (
InvalidSpecialPurpose SpecialPurpose = iota
// To ensure security, prevent fraud and debug vendors can:
// - Ensure data are securely transmitted
// - Detect and prevent malicious, fraudulent, invalid, or illegal activity.
// - Ensure correct and efficient operation of systems and processes, including to monitor and enhance the
// performance of systems and processes engaged in permitted purposes.
// Vendors cannot:
// - Conduct any other data processing operation allowed under a different purpose under this purpose
EnsureSecurity
// To deliver information and respond to technical requests vendors can:
// - Use a user’s IP address to deliver an ad over the internet
// - Respond to a user’s interaction with an ad by sending the user to a landing page
// - Use a user’s IP address to deliver content over the internet
// - Respond to a user’s interaction with content by sending the user to a landing page
// - Use information about the device type and capabilities for delivering ads or content, for example, to deliver
// the right size ad creative or video file in a format supported by the device
// Vendors cannot:
// - Conduct any other data processing operation allowed under a different purpose under this purpose
TechnicallyDeliverAds
)
// EveryPurposeAllowed returns true iff every purpose number in ps exists in
// the V2ParsedConsent, otherwise false. This explicitly checks that
// the vendor has opted in, and does not cover legitimate interest.
// This is vendor agnostic, and should not be used without checking if
// there are any Publisher Restrictions for a given vendor or vendors
// (which can be done with a call of p.PublisherRestricted).
func (p *V2ParsedConsent) EveryPurposeAllowed(ps []int) bool {
for _, rp := range ps {
if !p.PurposesConsent[rp] {
return false
}
}
return true
}
// PurposeAllowed returns true if the passed purpose number exists in
// the V2ParsedConsent, otherwise false.
// Deprecated and replaced by PurposeAllowedForConsent
func (p *V2ParsedConsent) PurposeAllowed(ps int) bool {
if !p.PurposesConsent[ps] {
return false
}
return true
}
// VendorAllowed returns true if the ParsedConsent contains affirmative consent
// for VendorID |v|.
// Deprecated and replaced by VendorAllowedForConsent
func (p *V2ParsedConsent) VendorAllowed(v int) bool {
if p.IsConsentRangeEncoding {
return inRangeEntries(v, p.ConsentedVendorsRange)
}
return p.ConsentedVendors[v]
}
// VendorAllowedForConsent returns true if the ParsedConsent contains affirmative consent
// for VendorID |v|.
func (p *V2ParsedConsent) VendorAllowedForConsent(v int) bool {
if p.IsConsentRangeEncoding {
return inRangeEntries(v, p.ConsentedVendorsRange)
}
return p.ConsentedVendors[v]
}
func (p *V2ParsedConsent) PurposeAllowedForConsent(ps int) bool {
if !p.PurposesConsent[ps] {
return false
}
return true
}
// VendorAllowedForConsent returns true if the ParsedConsent contains affirmative legitimate interest
// for VendorID |v|.
func (p *V2ParsedConsent) VendorAllowedForLI(v int) bool {
if p.IsInterestsRangeEncoding {
return inRangeEntries(v, p.InterestsVendorsRange)
}
return p.InterestsVendors[v]
}
func (p *V2ParsedConsent) PurposeAllowedForLI(ps int) bool {
if !p.PurposesLITransparency[ps] {
return false
}
return true
}
// PublisherRestricted returns true if any purpose in |ps| is
// Flatly Not Allowed and |v| is covered by that restriction.
func (p *V2ParsedConsent) PublisherRestricted(ps []int, v int) bool {
// Map-ify ps for use in checking pub restrictions.
var pm = make(map[int]bool)
for _, p := range ps {
pm[p] = true
}
if p.NumPubRestrictions > 0 {
for _, re := range p.PubRestrictionEntries {
if pm[re.PurposeID] &&
re.RestrictionType == PurposeFlatlyNotAllowed &&
inRangeEntries(v, re.RestrictionsRange) {
return true
}
}
}
return false
}
// inRangeEntries returns whether |v| is found within |entries|.
func inRangeEntries(v int, entries []*RangeEntry) bool {
for _, re := range entries {
if re.StartVendorID <= v && v <= re.EndVendorID {
return true
}
}
return false
}
// SuitableToProcess evaluates if its suitable for a vendor (with a set of
// required purposes allowed on the basis of consent) to process a given request.
func (p *V2ParsedConsent) SuitableToProcess(ps []int, v int) bool {
return p.VendorAllowed(v) &&
p.EveryPurposeAllowed(ps) &&
!p.PublisherRestricted(ps, v)
}
// MinorVersion of the V2 TCF string is not explicitly set as a value, so we return the
// minor version of the string based on specific values set. If there is a TCFPolicyVersion
// that is higher than what is currently known, we will return an error message, and a very
// high value. This allows callers to error on the unsupported TCFPolicyVersions, and/or use
// their highest supported minor version when handling strings. More specifically, we will
// apply the highest supported minor version when parsing, but the user as the ability to call
// MinorVersion() on its own to decide what to do if TCF Policy Version is higher.
func (p *V2ParsedConsent) MinorVersion() (int, error) {
switch p.TCFPolicyVersion {
case 0, 1, 2:
return 0, nil
// Any TCF v2 string with TCFPolicyVersion of 3 indicates v2.1.
case 3:
return 1, nil
// Any TCF v2 string that has TCFPolicyVersion of 4 indicates v2.2.
case 4:
return 2, nil
default:
return 100, errors.Errorf("Unsupported TCFPolicyVersion %d", p.TCFPolicyVersion)
}
}
// IsVendorRestricted returns true if the vendor is restricted by PubRestrictionEntry
func (p *PubRestrictionEntry) IsVendorRestricted(v int) bool {
if inRangeEntries(v, p.RestrictionsRange) {
return true
}
return false
}