Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed TCF2 Geo Only Enforcement #1492

Merged
merged 1 commit into from
Sep 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions exchange/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,10 @@ func cleanOpenRTBRequests(ctx context.Context,
coreBidder := resolveBidder(bidder.String(), aliases)

var publisherID = labels.PubID
ok, geo, id, err := gDPR.PersonalInfoAllowed(ctx, coreBidder, publisherID, consent)
privacyEnforcement.GDPR = !ok && err == nil
_, geo, id, err := gDPR.PersonalInfoAllowed(ctx, coreBidder, publisherID, consent)
privacyEnforcement.GDPRGeo = !geo && err == nil
privacyEnforcement.GDPRID = !id && err == nil
} else {
privacyEnforcement.GDPR = false
privacyEnforcement.GDPRGeo = false
privacyEnforcement.GDPRID = false
}
Expand Down
30 changes: 22 additions & 8 deletions privacy/enforcement.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ import (
type Enforcement struct {
CCPA bool
COPPA bool
GDPR bool
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bool no longer causes an effect. Removed.

GDPRGeo bool
GDPRID bool
LMT bool
}

// Any returns true if at least one privacy policy requires enforcement.
func (e Enforcement) Any() bool {
return e.CCPA || e.COPPA || e.GDPR || e.GDPRGeo || e.GDPRID || e.LMT
return e.CCPA || e.COPPA || e.GDPRGeo || e.GDPRID || e.LMT
}

// Apply cleans personally identifiable information from an OpenRTB bid request.
Expand All @@ -26,17 +25,33 @@ func (e Enforcement) Apply(bidRequest *openrtb.BidRequest, ampGDPRException bool

func (e Enforcement) apply(bidRequest *openrtb.BidRequest, ampGDPRException bool, scrubber Scrubber) {
if bidRequest != nil && e.Any() {
bidRequest.Device = scrubber.ScrubDevice(bidRequest.Device, e.getIPv6ScrubStrategy(), e.getGeoScrubStrategy())
bidRequest.Device = scrubber.ScrubDevice(bidRequest.Device, e.getDeviceIDScrubStrategy(), e.getIPv4ScrubStrategy(), e.getIPv6ScrubStrategy(), e.getGeoScrubStrategy())
bidRequest.User = scrubber.ScrubUser(bidRequest.User, e.getUserScrubStrategy(ampGDPRException), e.getGeoScrubStrategy())
}
}

func (e Enforcement) getDeviceIDScrubStrategy() ScrubStrategyDeviceID {
if e.COPPA || e.GDPRID || e.CCPA || e.LMT {
return ScrubStrategyDeviceIDAll
}

return ScrubStrategyDeviceIDNone
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was always set to ScrubStrategyDeviceIDAll before. Now it resolves to None for GDPR if only Geo is being enforced.


func (e Enforcement) getIPv4ScrubStrategy() ScrubStrategyIPV4 {
if e.COPPA || e.GDPRGeo || e.CCPA || e.LMT {
return ScrubStrategyIPV4Lowest8
}

return ScrubStrategyIPV4None
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was always set to ScrubStrategyIPV4Lowest8 before. Now it resolves to None for GDPR if only ID is being enforced. IP rounding is considered Geo enforcement.

}

func (e Enforcement) getIPv6ScrubStrategy() ScrubStrategyIPV6 {
if e.COPPA {
return ScrubStrategyIPV6Lowest32
}

if e.GDPR || e.CCPA || e.LMT {
if e.GDPRGeo || e.CCPA || e.LMT {
return ScrubStrategyIPV6Lowest16
}

Expand All @@ -60,12 +75,11 @@ func (e Enforcement) getUserScrubStrategy(ampGDPRException bool) ScrubStrategyUs
return ScrubStrategyUserIDAndDemographic
}

if e.GDPR && ampGDPRException {
return ScrubStrategyUserNone
if e.CCPA || e.LMT {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a bug too? If CCPA is enforced along with GDPR for a AMP request, the user would not be scrubbed. Now the AMP exception applies only to the GDPR enforcement aspect.

return ScrubStrategyUserID
}

// If no user scrubbing is needed, then return none, else scrub ID (COPPA checked above)
if e.CCPA || e.GDPRID || e.LMT {
if e.GDPRID && !ampGDPRException {
return ScrubStrategyUserID
}

Expand Down
131 changes: 60 additions & 71 deletions privacy/enforcement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ func TestAny(t *testing.T) {
enforcement: Enforcement{
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the most important part of the PR to review to ensure policy enforcement makes sense.

CCPA: false,
COPPA: false,
GDPR: false,
GDPRGeo: false,
GDPRID: false,
LMT: false,
Expand All @@ -31,7 +30,6 @@ func TestAny(t *testing.T) {
enforcement: Enforcement{
CCPA: true,
COPPA: true,
GDPR: true,
GDPRGeo: true,
GDPRID: true,
LMT: true,
Expand All @@ -43,7 +41,6 @@ func TestAny(t *testing.T) {
enforcement: Enforcement{
CCPA: false,
COPPA: true,
GDPR: false,
GDPRGeo: false,
GDPRID: false,
LMT: true,
Expand All @@ -63,6 +60,8 @@ func TestApply(t *testing.T) {
description string
enforcement Enforcement
ampGDPRException bool
expectedDeviceID ScrubStrategyDeviceID
expectedDeviceIPv4 ScrubStrategyIPV4
expectedDeviceIPv6 ScrubStrategyIPV6
expectedDeviceGeo ScrubStrategyGeo
expectedUser ScrubStrategyUser
Expand All @@ -73,12 +72,12 @@ func TestApply(t *testing.T) {
enforcement: Enforcement{
CCPA: true,
COPPA: true,
GDPR: true,
GDPRGeo: true,
GDPRID: true,
LMT: true,
},
ampGDPRException: false,
expectedDeviceID: ScrubStrategyDeviceIDAll,
expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
expectedDeviceGeo: ScrubStrategyGeoFull,
expectedUser: ScrubStrategyUserIDAndDemographic,
Expand All @@ -89,12 +88,12 @@ func TestApply(t *testing.T) {
enforcement: Enforcement{
CCPA: true,
COPPA: false,
GDPR: false,
GDPRGeo: false,
GDPRID: false,
LMT: false,
},
ampGDPRException: false,
expectedDeviceID: ScrubStrategyDeviceIDAll,
expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
expectedUser: ScrubStrategyUserID,
Expand All @@ -105,124 +104,97 @@ func TestApply(t *testing.T) {
enforcement: Enforcement{
CCPA: false,
COPPA: true,
GDPR: false,
GDPRGeo: false,
GDPRID: false,
LMT: false,
},
ampGDPRException: false,
expectedDeviceID: ScrubStrategyDeviceIDAll,
expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
expectedDeviceGeo: ScrubStrategyGeoFull,
expectedUser: ScrubStrategyUserIDAndDemographic,
expectedUserGeo: ScrubStrategyGeoFull,
},
{
description: "GDPR Only",
description: "GDPR Only - Full",
enforcement: Enforcement{
CCPA: false,
COPPA: false,
GDPR: true,
GDPRGeo: true,
GDPRID: true,
LMT: false,
},
ampGDPRException: false,
expectedDeviceID: ScrubStrategyDeviceIDAll,
expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
expectedUser: ScrubStrategyUserID,
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
},
{
description: "GDPR Only, ampGDPRException",
description: "GDPR Only - Full - AMP Exception",
enforcement: Enforcement{
CCPA: false,
COPPA: false,
GDPR: true,
GDPRGeo: true,
GDPRID: true,
LMT: false,
},
ampGDPRException: true,
expectedDeviceID: ScrubStrategyDeviceIDAll,
expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
expectedUser: ScrubStrategyUserNone,
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
},
{
description: "CCPA Only, ampGDPRException",
enforcement: Enforcement{
CCPA: true,
COPPA: false,
GDPR: false,
GDPRGeo: false,
GDPRID: false,
LMT: false,
},
ampGDPRException: true,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
expectedUser: ScrubStrategyUserID,
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
},
{
description: "COPPA and GDPR, ampGDPRException",
enforcement: Enforcement{
CCPA: false,
COPPA: true,
GDPR: true,
GDPRGeo: true,
GDPRID: true,
LMT: false,
},
ampGDPRException: true,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
expectedDeviceGeo: ScrubStrategyGeoFull,
expectedUser: ScrubStrategyUserIDAndDemographic,
expectedUserGeo: ScrubStrategyGeoFull,
},
{
description: "GDPR Only, no Geo",
description: "GDPR Only - ID Only",
enforcement: Enforcement{
CCPA: false,
COPPA: false,
GDPR: true,
GDPRGeo: false,
GDPRID: true,
LMT: false,
},
ampGDPRException: false,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
expectedDeviceID: ScrubStrategyDeviceIDAll,
expectedDeviceIPv4: ScrubStrategyIPV4None,
expectedDeviceIPv6: ScrubStrategyIPV6None,
expectedDeviceGeo: ScrubStrategyGeoNone,
expectedUser: ScrubStrategyUserID,
expectedUserGeo: ScrubStrategyGeoNone,
},
{
description: "GDPR Only, Geo only",
description: "GDPR Only - ID Only - AMP Exception",
enforcement: Enforcement{
CCPA: false,
COPPA: false,
GDPR: false,
GDPRGeo: true,
GDPRID: false,
GDPRGeo: false,
GDPRID: true,
LMT: false,
},
ampGDPRException: false,
ampGDPRException: true,
expectedDeviceID: ScrubStrategyDeviceIDAll,
expectedDeviceIPv4: ScrubStrategyIPV4None,
expectedDeviceIPv6: ScrubStrategyIPV6None,
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
expectedDeviceGeo: ScrubStrategyGeoNone,
expectedUser: ScrubStrategyUserNone,
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
expectedUserGeo: ScrubStrategyGeoNone,
},
{
description: "GDPR Only, ID exception",
description: "GDPR Only - Geo Only",
enforcement: Enforcement{
CCPA: false,
COPPA: false,
GDPR: true,
GDPRGeo: true,
GDPRID: false,
LMT: false,
},
ampGDPRException: false,
expectedDeviceID: ScrubStrategyDeviceIDNone,
expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
expectedUser: ScrubStrategyUserNone,
Expand All @@ -233,32 +205,50 @@ func TestApply(t *testing.T) {
enforcement: Enforcement{
CCPA: false,
COPPA: false,
GDPR: false,
GDPRGeo: false,
GDPRID: false,
LMT: true,
},
ampGDPRException: false,
expectedDeviceID: ScrubStrategyDeviceIDAll,
expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
expectedUser: ScrubStrategyUserID,
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
},
{
description: "LMT Only, ampGDPRException",
description: "Interactions: COPPA Only + AMP Exception",
enforcement: Enforcement{
CCPA: false,
COPPA: false,
GDPR: false,
COPPA: true,
GDPRGeo: false,
GDPRID: false,
LMT: true,
LMT: false,
},
ampGDPRException: true,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
expectedDeviceGeo: ScrubStrategyGeoReducedPrecision,
expectedUser: ScrubStrategyUserID,
expectedUserGeo: ScrubStrategyGeoReducedPrecision,
expectedDeviceID: ScrubStrategyDeviceIDAll,
expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
expectedDeviceGeo: ScrubStrategyGeoFull,
expectedUser: ScrubStrategyUserIDAndDemographic,
expectedUserGeo: ScrubStrategyGeoFull,
},
{
description: "Interactions: COPPA + GDPR Full + AMP Exception",
enforcement: Enforcement{
CCPA: false,
COPPA: true,
GDPRGeo: true,
GDPRID: true,
LMT: false,
},
ampGDPRException: true,
expectedDeviceID: ScrubStrategyDeviceIDAll,
expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
expectedDeviceGeo: ScrubStrategyGeoFull,
expectedUser: ScrubStrategyUserIDAndDemographic,
expectedUserGeo: ScrubStrategyGeoFull,
},
}

Expand All @@ -271,7 +261,7 @@ func TestApply(t *testing.T) {
replacedUser := &openrtb.User{}

m := &mockScrubber{}
m.On("ScrubDevice", req.Device, test.expectedDeviceIPv6, test.expectedDeviceGeo).Return(replacedDevice).Once()
m.On("ScrubDevice", req.Device, test.expectedDeviceID, test.expectedDeviceIPv4, test.expectedDeviceIPv6, test.expectedDeviceGeo).Return(replacedDevice).Once()
m.On("ScrubUser", req.User, test.expectedUser, test.expectedUserGeo).Return(replacedUser).Once()

test.enforcement.apply(req, test.ampGDPRException, m)
Expand All @@ -290,7 +280,6 @@ func TestApplyNoneApplicable(t *testing.T) {
enforcement := Enforcement{
CCPA: false,
COPPA: false,
GDPR: false,
GDPRGeo: false,
GDPRID: false,
LMT: false,
Expand All @@ -315,8 +304,8 @@ type mockScrubber struct {
mock.Mock
}

func (m *mockScrubber) ScrubDevice(device *openrtb.Device, ipv6 ScrubStrategyIPV6, geo ScrubStrategyGeo) *openrtb.Device {
args := m.Called(device, ipv6, geo)
func (m *mockScrubber) ScrubDevice(device *openrtb.Device, id ScrubStrategyDeviceID, ipv4 ScrubStrategyIPV4, ipv6 ScrubStrategyIPV6, geo ScrubStrategyGeo) *openrtb.Device {
args := m.Called(device, id, ipv4, ipv6, geo)
return args.Get(0).(*openrtb.Device)
}

Expand Down
Loading