Skip to content
This repository was archived by the owner on Dec 22, 2022. It is now read-only.

Commit 72b980b

Browse files
authored
Restore the AMP privacy exception as an option. (prebid#1311)
* Restore the AMP privacy exception as an option. * Adds missing test case * More PR feedback * Remove unused constant * Comment tweak
1 parent 8509ca0 commit 72b980b

12 files changed

+167
-66
lines changed

config/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ type GDPR struct {
142142
Timeouts GDPRTimeouts `mapstructure:"timeouts_ms"`
143143
NonStandardPublishers []string `mapstructure:"non_standard_publishers,flow"`
144144
NonStandardPublisherMap map[string]int
145+
AMPException bool `mapstructure:"amp_exception"`
145146
}
146147

147148
func (cfg *GDPR) validate(errs configErrors) configErrors {
@@ -768,6 +769,7 @@ func SetupViper(v *viper.Viper, filename string) {
768769
v.SetDefault("gdpr.timeouts_ms.init_vendorlist_fetches", 0)
769770
v.SetDefault("gdpr.timeouts_ms.active_vendorlist_fetch", 0)
770771
v.SetDefault("gdpr.non_standard_publishers", []string{""})
772+
v.SetDefault("gdpr.amp_exception", false)
771773
v.SetDefault("ccpa.enforce", false)
772774
v.SetDefault("currency_converter.fetch_url", "https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json")
773775
v.SetDefault("currency_converter.fetch_interval_seconds", 1800) // fetch currency rates every 30 minutes

endpoints/auction_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,10 @@ func (m *auctionMockPermissions) PersonalInfoAllowed(ctx context.Context, bidder
421421
return m.allowPI, nil
422422
}
423423

424+
func (m *auctionMockPermissions) AMPException() bool {
425+
return false
426+
}
427+
424428
func TestBidSizeValidate(t *testing.T) {
425429
bids := make(pbs.PBSBidSlice, 0)
426430
// bid1 will be rejected due to undefined size when adunit has multiple sizes

endpoints/cookie_sync_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,7 @@ func (g *gdprPerms) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.Bi
257257
func (g *gdprPerms) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, error) {
258258
return true, nil
259259
}
260+
261+
func (g *gdprPerms) AMPException() bool {
262+
return false
263+
}

endpoints/setuid_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,10 @@ func (g *mockPermsSetUID) PersonalInfoAllowed(ctx context.Context, bidder openrt
441441
return g.allowPI, nil
442442
}
443443

444+
func (g *mockPermsSetUID) AMPException() bool {
445+
return false
446+
}
447+
444448
func newFakeSyncer(familyName string) usersync.Usersyncer {
445449
return fakeSyncer{
446450
familyName: familyName,

exchange/utils.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func cleanOpenRTBRequests(ctx context.Context,
4343

4444
gdpr := extractGDPR(orig, usersyncIfAmbiguous)
4545
consent := extractConsent(orig)
46+
ampGDPRException := (labels.RType == pbsmetrics.ReqTypeAMP) && gDPR.AMPException()
4647

4748
privacyEnforcement := privacy.Enforcement{
4849
COPPA: orig.Regs != nil && orig.Regs.COPPA == 1,
@@ -65,7 +66,7 @@ func cleanOpenRTBRequests(ctx context.Context,
6566
privacyEnforcement.GDPR = false
6667
}
6768

68-
privacyEnforcement.Apply(bidReq)
69+
privacyEnforcement.Apply(bidReq, ampGDPRException)
6970
}
7071

7172
return

exchange/utils_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ func (p *permissionsMock) PersonalInfoAllowed(ctx context.Context, bidder openrt
3131
return false, nil
3232
}
3333

34+
func (p *permissionsMock) AMPException() bool {
35+
return false
36+
}
37+
3438
func assertReq(t *testing.T, reqByBidders map[openrtb_ext.BidderName]*openrtb.BidRequest,
3539
applyCOPPA bool, consentedVendors map[string]bool) {
3640
// assert individual bidder requests

gdpr/gdpr.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ type Permissions interface {
2424
//
2525
// If the consent string was nonsensical, the returned error will be an ErrorMalformedConsent.
2626
PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, error)
27+
28+
// Exposes the AMP execption flag
29+
AMPException() bool
2730
}
2831

2932
const (

gdpr/impl.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ func (p *permissionsImpl) PersonalInfoAllowed(ctx context.Context, bidder openrt
5858
return false, nil
5959
}
6060

61+
func (p *permissionsImpl) AMPException() bool {
62+
return p.cfg.AMPException
63+
}
64+
6165
func (p *permissionsImpl) allowSync(ctx context.Context, vendorID uint16, consent string) (bool, error) {
6266
// If we're not given a consent string, respect the preferences in the app config.
6367
if consent == "" {
@@ -145,3 +149,7 @@ func (a AlwaysAllow) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.B
145149
func (a AlwaysAllow) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, error) {
146150
return true, nil
147151
}
152+
153+
func (a AlwaysAllow) AMPException() bool {
154+
return false
155+
}

privacy/enforcement.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ func (e Enforcement) Any() bool {
1717
}
1818

1919
// Apply cleans personally identifiable information from an OpenRTB bid request.
20-
func (e Enforcement) Apply(bidRequest *openrtb.BidRequest) {
21-
e.apply(bidRequest, NewScrubber())
20+
func (e Enforcement) Apply(bidRequest *openrtb.BidRequest, ampGDPRException bool) {
21+
e.apply(bidRequest, ampGDPRException, NewScrubber())
2222
}
2323

24-
func (e Enforcement) apply(bidRequest *openrtb.BidRequest, scrubber Scrubber) {
24+
func (e Enforcement) apply(bidRequest *openrtb.BidRequest, ampGDPRException bool, scrubber Scrubber) {
2525
if bidRequest != nil && e.Any() {
2626
bidRequest.Device = scrubber.ScrubDevice(bidRequest.Device, e.getIPv6ScrubStrategy(), e.getGeoScrubStrategy())
27-
bidRequest.User = scrubber.ScrubUser(bidRequest.User, e.getDemographicScrubStrategy(), e.getGeoScrubStrategy())
27+
bidRequest.User = scrubber.ScrubUser(bidRequest.User, e.getUserScrubStrategy(ampGDPRException), e.getGeoScrubStrategy())
2828
}
2929
}
3030

@@ -52,10 +52,13 @@ func (e Enforcement) getGeoScrubStrategy() ScrubStrategyGeo {
5252
return ScrubStrategyGeoNone
5353
}
5454

55-
func (e Enforcement) getDemographicScrubStrategy() ScrubStrategyDemographic {
55+
func (e Enforcement) getUserScrubStrategy(ampGDPRException bool) ScrubStrategyUser {
5656
if e.COPPA {
57-
return ScrubStrategyDemographicAgeAndGender
57+
return ScrubStrategyUserIDAndDemographic
5858
}
5959

60-
return ScrubStrategyDemographicNone
60+
if e.GDPR && ampGDPRException {
61+
return ScrubStrategyUserNone
62+
}
63+
return ScrubStrategyUserID
6164
}

privacy/enforcement_test.go

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,13 @@ func TestAny(t *testing.T) {
5151

5252
func TestApply(t *testing.T) {
5353
testCases := []struct {
54-
description string
55-
enforcement Enforcement
56-
expectedDeviceIPv6 ScrubStrategyIPV6
57-
expectedDeviceGeo ScrubStrategyGeo
58-
expectedUserDemographic ScrubStrategyDemographic
59-
expectedUserGeo ScrubStrategyGeo
54+
description string
55+
enforcement Enforcement
56+
ampGDPRException bool
57+
expectedDeviceIPv6 ScrubStrategyIPV6
58+
expectedDeviceGeo ScrubStrategyGeo
59+
expectedUser ScrubStrategyUser
60+
expectedUserGeo ScrubStrategyGeo
6061
}{
6162
{
6263
description: "All Enforced",
@@ -65,10 +66,11 @@ func TestApply(t *testing.T) {
6566
COPPA: true,
6667
GDPR: true,
6768
},
68-
expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
69-
expectedDeviceGeo: ScrubStrategyGeoFull,
70-
expectedUserDemographic: ScrubStrategyDemographicAgeAndGender,
71-
expectedUserGeo: ScrubStrategyGeoFull,
69+
ampGDPRException: false,
70+
expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
71+
expectedDeviceGeo: ScrubStrategyGeoFull,
72+
expectedUser: ScrubStrategyUserIDAndDemographic,
73+
expectedUserGeo: ScrubStrategyGeoFull,
7274
},
7375
{
7476
description: "CCPA Only",
@@ -77,10 +79,11 @@ func TestApply(t *testing.T) {
7779
COPPA: false,
7880
GDPR: false,
7981
},
80-
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
81-
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
82-
expectedUserDemographic: ScrubStrategyDemographicNone,
83-
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
82+
ampGDPRException: false,
83+
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
84+
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
85+
expectedUser: ScrubStrategyUserID,
86+
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
8487
},
8588
{
8689
description: "COPPA Only",
@@ -89,10 +92,11 @@ func TestApply(t *testing.T) {
8992
COPPA: true,
9093
GDPR: false,
9194
},
92-
expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
93-
expectedDeviceGeo: ScrubStrategyGeoFull,
94-
expectedUserDemographic: ScrubStrategyDemographicAgeAndGender,
95-
expectedUserGeo: ScrubStrategyGeoFull,
95+
ampGDPRException: false,
96+
expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
97+
expectedDeviceGeo: ScrubStrategyGeoFull,
98+
expectedUser: ScrubStrategyUserIDAndDemographic,
99+
expectedUserGeo: ScrubStrategyGeoFull,
96100
},
97101
{
98102
description: "GDPR Only",
@@ -101,10 +105,50 @@ func TestApply(t *testing.T) {
101105
COPPA: false,
102106
GDPR: true,
103107
},
104-
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
105-
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
106-
expectedUserDemographic: ScrubStrategyDemographicNone,
107-
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
108+
ampGDPRException: false,
109+
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
110+
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
111+
expectedUser: ScrubStrategyUserID,
112+
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
113+
},
114+
{
115+
description: "GDPR Only, ampGDPRException",
116+
enforcement: Enforcement{
117+
CCPA: false,
118+
COPPA: false,
119+
GDPR: true,
120+
},
121+
ampGDPRException: true,
122+
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
123+
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
124+
expectedUser: ScrubStrategyUserNone,
125+
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
126+
},
127+
{
128+
description: "CCPA Only, ampGDPRException",
129+
enforcement: Enforcement{
130+
CCPA: true,
131+
COPPA: false,
132+
GDPR: false,
133+
},
134+
ampGDPRException: true,
135+
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
136+
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
137+
expectedUser: ScrubStrategyUserID,
138+
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
139+
},
140+
{
141+
description: "COPPA and GDPR, ampGDPRException",
142+
enforcement: Enforcement{
143+
CCPA: false,
144+
COPPA: true,
145+
GDPR: true,
146+
},
147+
ampGDPRException: true,
148+
expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
149+
expectedDeviceGeo: ScrubStrategyGeoFull,
150+
expectedUser: ScrubStrategyUserIDAndDemographic,
151+
expectedUserGeo: ScrubStrategyGeoFull,
108152
},
109153
}
110154

@@ -118,9 +162,9 @@ func TestApply(t *testing.T) {
118162

119163
m := &mockScrubber{}
120164
m.On("ScrubDevice", req.Device, test.expectedDeviceIPv6, test.expectedDeviceGeo).Return(replacedDevice).Once()
121-
m.On("ScrubUser", req.User, test.expectedUserDemographic, test.expectedUserGeo).Return(replacedUser).Once()
165+
m.On("ScrubUser", req.User, test.expectedUser, test.expectedUserGeo).Return(replacedUser).Once()
122166

123-
test.enforcement.apply(req, m)
167+
test.enforcement.apply(req, test.ampGDPRException, m)
124168

125169
m.AssertExpectations(t)
126170
assert.Same(t, replacedDevice, req.Device, "Device")
@@ -138,7 +182,7 @@ func TestApplyNoneApplicable(t *testing.T) {
138182
COPPA: false,
139183
GDPR: false,
140184
}
141-
enforcement.apply(req, m)
185+
enforcement.apply(req, false, m)
142186

143187
m.AssertNotCalled(t, "ScrubDevice")
144188
m.AssertNotCalled(t, "ScrubUser")
@@ -148,7 +192,7 @@ func TestApplyNil(t *testing.T) {
148192
m := &mockScrubber{}
149193

150194
enforcement := Enforcement{}
151-
enforcement.apply(nil, m)
195+
enforcement.apply(nil, false, m)
152196

153197
m.AssertNotCalled(t, "ScrubDevice")
154198
m.AssertNotCalled(t, "ScrubUser")
@@ -163,7 +207,7 @@ func (m *mockScrubber) ScrubDevice(device *openrtb.Device, ipv6 ScrubStrategyIPV
163207
return args.Get(0).(*openrtb.Device)
164208
}
165209

166-
func (m *mockScrubber) ScrubUser(user *openrtb.User, demographic ScrubStrategyDemographic, geo ScrubStrategyGeo) *openrtb.User {
167-
args := m.Called(user, demographic, geo)
210+
func (m *mockScrubber) ScrubUser(user *openrtb.User, strategy ScrubStrategyUser, geo ScrubStrategyGeo) *openrtb.User {
211+
args := m.Called(user, strategy, geo)
168212
return args.Get(0).(*openrtb.User)
169213
}

privacy/scrubber.go

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,24 @@ const (
3434
ScrubStrategyGeoReducedPrecision
3535
)
3636

37-
// ScrubStrategyDemographic defines the approach to non-location demographic data.
38-
type ScrubStrategyDemographic int
37+
// ScrubStrategyUser defines the approach to scrub PII from user data.
38+
type ScrubStrategyUser int
3939

4040
const (
41-
// ScrubStrategyDemographicNone does not remove non-location demographic data.
42-
ScrubStrategyDemographicNone ScrubStrategyDemographic = iota
41+
// ScrubStrategyUserNone does not remove non-location data.
42+
ScrubStrategyUserNone ScrubStrategyUser = iota
4343

44-
// ScrubStrategyDemographicAgeAndGender removes age and gender data.
45-
ScrubStrategyDemographicAgeAndGender
44+
// ScrubStrategyUserIDAndDemographic removes the user's buyer id, exchange id year of birth, and gender.
45+
ScrubStrategyUserIDAndDemographic
46+
47+
// ScrubStrategyUserID removes the user's buyer id.
48+
ScrubStrategyUserID
4649
)
4750

4851
// Scrubber removes PII from parts of an OpenRTB request.
4952
type Scrubber interface {
5053
ScrubDevice(device *openrtb.Device, ipv6 ScrubStrategyIPV6, geo ScrubStrategyGeo) *openrtb.Device
51-
ScrubUser(user *openrtb.User, demographic ScrubStrategyDemographic, geo ScrubStrategyGeo) *openrtb.User
54+
ScrubUser(user *openrtb.User, strategy ScrubStrategyUser, geo ScrubStrategyGeo) *openrtb.User
5255
}
5356

5457
type scrubber struct{}
@@ -90,19 +93,22 @@ func (scrubber) ScrubDevice(device *openrtb.Device, ipv6 ScrubStrategyIPV6, geo
9093
return &deviceCopy
9194
}
9295

93-
func (scrubber) ScrubUser(user *openrtb.User, demographic ScrubStrategyDemographic, geo ScrubStrategyGeo) *openrtb.User {
96+
func (scrubber) ScrubUser(user *openrtb.User, strategy ScrubStrategyUser, geo ScrubStrategyGeo) *openrtb.User {
9497
if user == nil {
9598
return nil
9699
}
97100

98101
userCopy := *user
99-
userCopy.BuyerUID = ""
100-
userCopy.ID = ""
101102

102-
switch demographic {
103-
case ScrubStrategyDemographicAgeAndGender:
103+
switch strategy {
104+
case ScrubStrategyUserIDAndDemographic:
105+
userCopy.BuyerUID = ""
106+
userCopy.ID = ""
104107
userCopy.Yob = 0
105108
userCopy.Gender = ""
109+
case ScrubStrategyUserID:
110+
userCopy.BuyerUID = ""
111+
userCopy.ID = ""
106112
}
107113

108114
switch geo {

0 commit comments

Comments
 (0)