Skip to content

Commit

Permalink
Use TransmitUserFPD and TransmitPreciseGeo activities in analytics (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
VeronikaSolovei9 authored Jan 25, 2024
1 parent 106f22d commit 8bd778c
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 22 deletions.
49 changes: 43 additions & 6 deletions analytics/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/prebid/prebid-server/v2/analytics/filesystem"
"github.com/prebid/prebid-server/v2/analytics/pubstack"
"github.com/prebid/prebid-server/v2/config"
"github.com/prebid/prebid-server/v2/openrtb_ext"
"github.com/prebid/prebid-server/v2/ortb"
"github.com/prebid/prebid-server/v2/privacy"
)

Expand Down Expand Up @@ -46,19 +48,24 @@ type enabledAnalytics map[string]analytics.Module

func (ea enabledAnalytics) LogAuctionObject(ao *analytics.AuctionObject, ac privacy.ActivityControl) {
for name, module := range ea {
component := privacy.Component{Type: privacy.ComponentTypeAnalytics, Name: name}
if ac.Allow(privacy.ActivityReportAnalytics, component, privacy.ActivityRequest{}) {
if isAllowed, cloneBidderReq := evaluateActivities(ao.RequestWrapper, ac, name); isAllowed {
if cloneBidderReq != nil {
ao.RequestWrapper = cloneBidderReq
}
module.LogAuctionObject(ao)
}
}
}

func (ea enabledAnalytics) LogVideoObject(vo *analytics.VideoObject, ac privacy.ActivityControl) {
for name, module := range ea {
component := privacy.Component{Type: privacy.ComponentTypeAnalytics, Name: name}
if ac.Allow(privacy.ActivityReportAnalytics, component, privacy.ActivityRequest{}) {
if isAllowed, cloneBidderReq := evaluateActivities(vo.RequestWrapper, ac, name); isAllowed {
if cloneBidderReq != nil {
vo.RequestWrapper = cloneBidderReq
}
module.LogVideoObject(vo)
}

}
}

Expand All @@ -76,8 +83,10 @@ func (ea enabledAnalytics) LogSetUIDObject(so *analytics.SetUIDObject) {

func (ea enabledAnalytics) LogAmpObject(ao *analytics.AmpObject, ac privacy.ActivityControl) {
for name, module := range ea {
component := privacy.Component{Type: privacy.ComponentTypeAnalytics, Name: name}
if ac.Allow(privacy.ActivityReportAnalytics, component, privacy.ActivityRequest{}) {
if isAllowed, cloneBidderReq := evaluateActivities(ao.RequestWrapper, ac, name); isAllowed {
if cloneBidderReq != nil {
ao.RequestWrapper = cloneBidderReq
}
module.LogAmpObject(ao)
}
}
Expand All @@ -91,3 +100,31 @@ func (ea enabledAnalytics) LogNotificationEventObject(ne *analytics.Notification
}
}
}

func evaluateActivities(rw *openrtb_ext.RequestWrapper, ac privacy.ActivityControl, componentName string) (bool, *openrtb_ext.RequestWrapper) {
// returned nil request wrapper means that request wrapper was not modified by activities and doesn't have to be changed in analytics object
// it is needed in order to use one function for all analytics objects with RequestWrapper
component := privacy.Component{Type: privacy.ComponentTypeAnalytics, Name: componentName}
if !ac.Allow(privacy.ActivityReportAnalytics, component, privacy.ActivityRequest{}) {
return false, nil
}
blockUserFPD := !ac.Allow(privacy.ActivityTransmitUserFPD, component, privacy.ActivityRequest{})
blockPreciseGeo := !ac.Allow(privacy.ActivityTransmitPreciseGeo, component, privacy.ActivityRequest{})

if !blockUserFPD && !blockPreciseGeo {
return true, nil
}

cloneReq := ortb.CloneBidderReq(rw.BidRequest)

if blockUserFPD {
privacy.ScrubUserFPD(cloneReq)
}
if blockPreciseGeo {
ipConf := privacy.IPConf{IPV6: ac.IPv6Config, IPV4: ac.IPv4Config}
privacy.ScrubGeoAndDeviceIP(cloneReq, ipConf)
}

cloneReq.RebuildRequest()
return true, cloneReq
}
140 changes: 136 additions & 4 deletions analytics/build/build_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package build

import (
"github.com/prebid/prebid-server/v2/openrtb_ext"
"github.com/prebid/prebid-server/v2/util/iputil"

"net/http"
"os"
"testing"
Expand Down Expand Up @@ -143,7 +146,7 @@ func TestSampleModuleActivitiesAllowed(t *testing.T) {
var count int
am := initAnalytics(&count)

acAllowed := privacy.NewActivityControl(getDefaultActivityConfig("sampleModule", true))
acAllowed := privacy.NewActivityControl(getActivityConfig("sampleModule", true, true, true))

ao := &analytics.AuctionObject{
Status: http.StatusOK,
Expand Down Expand Up @@ -172,11 +175,46 @@ func TestSampleModuleActivitiesAllowed(t *testing.T) {
}
}

func TestSampleModuleActivitiesAllowedAndDenied(t *testing.T) {
var count int
am := initAnalytics(&count)

acAllowed := privacy.NewActivityControl(getActivityConfig("sampleModule", true, false, true))

rw := &openrtb_ext.RequestWrapper{BidRequest: getDefaultBidRequest()}
ao := &analytics.AuctionObject{
RequestWrapper: rw,
Status: http.StatusOK,
Errors: nil,
Response: &openrtb2.BidResponse{},
}

am.LogAuctionObject(ao, acAllowed)
if count != 1 {
t.Errorf("PBSAnalyticsModule failed at LogAuctionObject")
}

am.LogAmpObject(&analytics.AmpObject{RequestWrapper: rw}, acAllowed)
if count != 2 {
t.Errorf("PBSAnalyticsModule failed at LogAmpObject")
}

am.LogVideoObject(&analytics.VideoObject{RequestWrapper: rw}, acAllowed)
if count != 3 {
t.Errorf("PBSAnalyticsModule failed at LogVideoObject")
}

am.LogNotificationEventObject(&analytics.NotificationEvent{}, acAllowed)
if count != 4 {
t.Errorf("PBSAnalyticsModule failed at LogNotificationEventObject")
}
}

func TestSampleModuleActivitiesDenied(t *testing.T) {
var count int
am := initAnalytics(&count)

acDenied := privacy.NewActivityControl(getDefaultActivityConfig("sampleModule", false))
acDenied := privacy.NewActivityControl(getActivityConfig("sampleModule", false, true, true))

ao := &analytics.AuctionObject{
Status: http.StatusOK,
Expand Down Expand Up @@ -205,14 +243,102 @@ func TestSampleModuleActivitiesDenied(t *testing.T) {
}
}

func getDefaultActivityConfig(componentName string, allow bool) *config.AccountPrivacy {
func TestEvaluateActivities(t *testing.T) {
testCases := []struct {
description string
givenActivityControl privacy.ActivityControl
expectedRequest *openrtb_ext.RequestWrapper
expectedAllowActivities bool
}{
{
description: "all blocked",
givenActivityControl: privacy.NewActivityControl(getActivityConfig("sampleModule", false, false, false)),
expectedRequest: nil,
expectedAllowActivities: false,
},
{
description: "all allowed",
givenActivityControl: privacy.NewActivityControl(getActivityConfig("sampleModule", true, true, true)),
expectedRequest: nil,
expectedAllowActivities: true,
},

{
description: "ActivityTransmitUserFPD and ActivityTransmitPreciseGeo disabled",
givenActivityControl: privacy.NewActivityControl(getActivityConfig("sampleModule", true, false, false)),
expectedRequest: &openrtb_ext.RequestWrapper{
BidRequest: &openrtb2.BidRequest{ID: "test_request", User: &openrtb2.User{ID: ""}, Device: &openrtb2.Device{IFA: "", IP: "127.0.0.0"}},
},
expectedAllowActivities: true,
},
{
description: "ActivityTransmitUserFPD enabled, ActivityTransmitPreciseGeo disabled",
givenActivityControl: privacy.NewActivityControl(getActivityConfig("sampleModule", true, true, false)),
expectedRequest: &openrtb_ext.RequestWrapper{
BidRequest: &openrtb2.BidRequest{ID: "test_request", User: &openrtb2.User{ID: "user-id"}, Device: &openrtb2.Device{IFA: "device-ifa", IP: "127.0.0.0"}},
},
expectedAllowActivities: true,
},
}

for _, test := range testCases {
t.Run(test.description, func(t *testing.T) {
rw := &openrtb_ext.RequestWrapper{BidRequest: getDefaultBidRequest()}
resActivityAllowed, resRequest := evaluateActivities(rw, test.givenActivityControl, "sampleModule")
assert.Equal(t, test.expectedAllowActivities, resActivityAllowed)
if test.expectedRequest != nil {
assert.Equal(t, test.expectedRequest.User.ID, resRequest.User.ID)
assert.Equal(t, test.expectedRequest.Device.IFA, resRequest.Device.IFA)
assert.Equal(t, test.expectedRequest.Device.IP, resRequest.Device.IP)
} else {
assert.Nil(t, resRequest)
}

})
}

}

func getDefaultBidRequest() *openrtb2.BidRequest {
return &openrtb2.BidRequest{
ID: "test_request",
User: &openrtb2.User{ID: "user-id"},
Device: &openrtb2.Device{IFA: "device-ifa", IP: "127.0.0.1"}}

}

func getActivityConfig(componentName string, allowReportAnalytics, allowTransmitUserFPD, allowTransmitPreciseGeo bool) *config.AccountPrivacy {
return &config.AccountPrivacy{
AllowActivities: &config.AllowActivities{
ReportAnalytics: config.Activity{
Default: ptrutil.ToPtr(true),
Rules: []config.ActivityRule{
{
Allow: allow,
Allow: allowReportAnalytics,
Condition: config.ActivityCondition{
ComponentName: []string{componentName},
ComponentType: []string{"analytics"},
},
},
},
},
TransmitUserFPD: config.Activity{
Default: ptrutil.ToPtr(true),
Rules: []config.ActivityRule{
{
Allow: allowTransmitUserFPD,
Condition: config.ActivityCondition{
ComponentName: []string{componentName},
ComponentType: []string{"analytics"},
},
},
},
},
TransmitPreciseGeo: config.Activity{
Default: ptrutil.ToPtr(true),
Rules: []config.ActivityRule{
{
Allow: allowTransmitPreciseGeo,
Condition: config.ActivityCondition{
ComponentName: []string{componentName},
ComponentType: []string{"analytics"},
Expand All @@ -221,5 +347,11 @@ func getDefaultActivityConfig(componentName string, allow bool) *config.AccountP
},
},
},
IPv4Config: config.IPv4{
AnonKeepBits: iputil.IPv4DefaultMaskingBitSize,
},
IPv6Config: config.IPv6{
AnonKeepBits: iputil.IPv6DefaultMaskingBitSize,
},
}
}
3 changes: 2 additions & 1 deletion endpoints/openrtb2/video_auction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1250,7 +1250,8 @@ func (m *mockAnalyticsModule) LogCookieSyncObject(cso *analytics.CookieSyncObjec

func (m *mockAnalyticsModule) LogSetUIDObject(so *analytics.SetUIDObject) {}

func (m *mockAnalyticsModule) LogAmpObject(ao *analytics.AmpObject, _ privacy.ActivityControl) {}
func (m *mockAnalyticsModule) LogAmpObject(ao *analytics.AmpObject, _ privacy.ActivityControl) {
}

func (m *mockAnalyticsModule) LogNotificationEventObject(ne *analytics.NotificationEvent, _ privacy.ActivityControl) {
}
Expand Down
7 changes: 6 additions & 1 deletion privacy/activitycontrol.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ func (r ActivityRequest) IsBidRequest() bool {
}

type ActivityControl struct {
plans map[Activity]ActivityPlan
plans map[Activity]ActivityPlan
IPv6Config config.IPv6
IPv4Config config.IPv4
}

func NewActivityControl(cfg *config.AccountPrivacy) ActivityControl {
Expand All @@ -58,6 +60,9 @@ func NewActivityControl(cfg *config.AccountPrivacy) ActivityControl {
plans[ActivityTransmitTIDs] = buildPlan(cfg.AllowActivities.TransmitTids)
ac.plans = plans

ac.IPv4Config = cfg.IPv4Config
ac.IPv6Config = cfg.IPv6Config

return ac
}

Expand Down
26 changes: 16 additions & 10 deletions privacy/activitycontrol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,23 @@ func TestNewActivityControl(t *testing.T) {
TransmitUniqueRequestIds: getTestActivityConfig(true),
TransmitTids: getTestActivityConfig(true),
},
IPv6Config: config.IPv6{AnonKeepBits: 32},
IPv4Config: config.IPv4{AnonKeepBits: 16},
},
activityControl: ActivityControl{
plans: map[Activity]ActivityPlan{
ActivitySyncUser: getTestActivityPlan(ActivityAllow),
ActivityFetchBids: getTestActivityPlan(ActivityAllow),
ActivityEnrichUserFPD: getTestActivityPlan(ActivityAllow),
ActivityReportAnalytics: getTestActivityPlan(ActivityAllow),
ActivityTransmitUserFPD: getTestActivityPlan(ActivityAllow),
ActivityTransmitPreciseGeo: getTestActivityPlan(ActivityDeny),
ActivityTransmitUniqueRequestIDs: getTestActivityPlan(ActivityAllow),
ActivityTransmitTIDs: getTestActivityPlan(ActivityAllow),
},
IPv6Config: config.IPv6{AnonKeepBits: 32},
IPv4Config: config.IPv4{AnonKeepBits: 16},
},
activityControl: ActivityControl{plans: map[Activity]ActivityPlan{
ActivitySyncUser: getTestActivityPlan(ActivityAllow),
ActivityFetchBids: getTestActivityPlan(ActivityAllow),
ActivityEnrichUserFPD: getTestActivityPlan(ActivityAllow),
ActivityReportAnalytics: getTestActivityPlan(ActivityAllow),
ActivityTransmitUserFPD: getTestActivityPlan(ActivityAllow),
ActivityTransmitPreciseGeo: getTestActivityPlan(ActivityDeny),
ActivityTransmitUniqueRequestIDs: getTestActivityPlan(ActivityAllow),
ActivityTransmitTIDs: getTestActivityPlan(ActivityAllow),
}},
},
}

Expand Down

0 comments on commit 8bd778c

Please sign in to comment.