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

Activities refactoring #2989

Merged
merged 2 commits into from
Aug 3, 2023
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
2 changes: 1 addition & 1 deletion endpoints/cookie_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ func (p usersyncPrivacy) CCPAAllowsBidderSync(bidder string) bool {
}

func (p usersyncPrivacy) ActivityAllowsUserSync(bidder string) bool {
activityResult := p.activityControl.Allow(privacy.ActivitySyncUser,
activityResult := p.activityControl.Evaluate(privacy.ActivitySyncUser,
privacy.ScopedName{Scope: privacy.ScopeTypeBidder, Name: bidder})
return activityResult == privacy.ActivityAllow
}
2 changes: 1 addition & 1 deletion endpoints/setuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func NewSetUIDEndpoint(cfg *config.Configuration, syncersByBidder map[string]use
}
}

userSyncActivityAllowed := activities.Allow(privacy.ActivitySyncUser,
userSyncActivityAllowed := activities.Evaluate(privacy.ActivitySyncUser,
privacy.ScopedName{Scope: privacy.ScopeTypeBidder, Name: bidderName})
if userSyncActivityAllowed == privacy.ActivityDeny {
w.WriteHeader(http.StatusUnavailableForLegalReasons)
Expand Down
6 changes: 3 additions & 3 deletions exchange/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context,

// fetchBids activity
scopedName := privacy.ScopedName{Scope: privacy.ScopeTypeBidder, Name: bidderRequest.BidderName.String()}
fetchBidsActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityFetchBids, scopedName)
fetchBidsActivityAllowed := auctionReq.Activities.Evaluate(privacy.ActivityFetchBids, scopedName)
if fetchBidsActivityAllowed == privacy.ActivityDeny {
// skip the call to a bidder if fetchBids activity is not allowed
// do not add this bidder to allowedBidderRequests
Expand All @@ -173,7 +173,7 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context,
}
}

passIDActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitUserFPD, scopedName)
passIDActivityAllowed := auctionReq.Activities.Evaluate(privacy.ActivityTransmitUserFPD, scopedName)
if passIDActivityAllowed == privacy.ActivityDeny {
privacyEnforcement.UFPD = true
} else {
Expand All @@ -190,7 +190,7 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context,
privacyEnforcement.CCPA = ccpaEnforcer.ShouldEnforce(bidderRequest.BidderName.String())
}

passGeoActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitPreciseGeo, scopedName)
passGeoActivityAllowed := auctionReq.Activities.Evaluate(privacy.ActivityTransmitPreciseGeo, scopedName)
if passGeoActivityAllowed == privacy.ActivityDeny {
privacyEnforcement.PreciseGeo = true
} else {
Expand Down
92 changes: 54 additions & 38 deletions privacy/enforcer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package privacy

import (
"fmt"
"github.com/prebid/prebid-server/config"
"strings"

"github.com/prebid/prebid-server/config"
)

type ActivityResult int
Expand Down Expand Up @@ -86,23 +87,32 @@ func buildEnforcementPlan(activity config.Activity) (ActivityPlan, error) {
}

func activityRulesToEnforcementRules(rules []config.ActivityRule) ([]ActivityRule, error) {
enfRules := make([]ActivityRule, 0)
var enfRules []ActivityRule

for _, r := range rules {
cmpName, err := conditionToRuleComponentName(r.Condition.ComponentName)
var result ActivityResult
if r.Allow {
result = ActivityAllow
} else {
result = ActivityDeny
}

componentName, err := conditionToRuleComponentNames(r.Condition.ComponentName)
if err != nil {
return nil, err
}

er := ComponentEnforcementRule{
allowed: r.Allow,
componentName: cmpName,
result: result,
componentName: componentName,
componentType: r.Condition.ComponentType,
}
enfRules = append(enfRules, er)
}
return enfRules, nil
}

func conditionToRuleComponentName(conditions []string) ([]ScopedName, error) {
func conditionToRuleComponentNames(conditions []string) ([]ScopedName, error) {
sn := make([]ScopedName, 0)
for _, condition := range conditions {
scope, err := NewScopedName(condition)
Expand All @@ -124,24 +134,24 @@ func activityDefaultToDefaultResult(activityDefault *bool) ActivityResult {
return ActivityDeny
}

func (e ActivityControl) Allow(activity Activity, target ScopedName) ActivityResult {
func (e ActivityControl) Evaluate(activity Activity, target ScopedName) ActivityResult {
plan, planDefined := e.plans[activity]

if !planDefined {
return ActivityAbstain
}

return plan.Allow(target)
return plan.Evaluate(target)
}

type ActivityPlan struct {
defaultResult ActivityResult
rules []ActivityRule
}

func (p ActivityPlan) Allow(target ScopedName) ActivityResult {
func (p ActivityPlan) Evaluate(target ScopedName) ActivityResult {
for _, rule := range p.rules {
result := rule.Allow(target)
result := rule.Evaluate(target)
if result == ActivityDeny || result == ActivityAllow {
return result
}
Expand All @@ -150,51 +160,57 @@ func (p ActivityPlan) Allow(target ScopedName) ActivityResult {
}

type ActivityRule interface {
Allow(target ScopedName) ActivityResult
Evaluate(target ScopedName) ActivityResult
}

type ComponentEnforcementRule struct {
result ActivityResult
componentName []ScopedName
componentType []string
// include gppSectionId from 3.5
// include geo from 3.5
allowed bool
}

func (r ComponentEnforcementRule) Allow(target ScopedName) ActivityResult {
if len(r.componentName) == 0 && len(r.componentType) == 0 {
func (r ComponentEnforcementRule) Evaluate(target ScopedName) ActivityResult {
if matched := evaluateComponentName(target, r.componentName); !matched {
return ActivityAbstain
}

if matched := evaluateComponentType(target, r.componentType); !matched {
return ActivityAbstain
}

nameClauseExists := len(r.componentName) > 0
typeClauseExists := len(r.componentType) > 0
return r.result
}

componentNameFound := false
for _, scope := range r.componentName {
if strings.EqualFold(scope.Scope, target.Scope) &&
(scope.Name == "*" || strings.EqualFold(scope.Name, target.Name)) {
componentNameFound = true
break
}
func evaluateComponentName(target ScopedName, componentNames []ScopedName) bool {
// no clauses are considered a match
if len(componentNames) == 0 {
return true
}

componentTypeFound := false
for _, componentType := range r.componentType {
if strings.EqualFold(componentType, target.Scope) {
componentTypeFound = true
break
// if there are clauses, at least one needs to match
for _, n := range componentNames {
if strings.EqualFold(n.Scope, target.Scope) && (n.Name == "*" || strings.EqualFold(n.Name, target.Name)) {
return true
}
}
// behavior if rule matches: can be either true=allow or false=deny. result is abstain if the rule doesn't match
matchFound := (componentNameFound || !nameClauseExists) && (componentTypeFound || !typeClauseExists)
if matchFound {
if r.allowed {
return ActivityAllow
} else {
return ActivityDeny

return false
}

func evaluateComponentType(target ScopedName, componentTypes []string) bool {
// no clauses are considered a match
if len(componentTypes) == 0 {
return true
}

// if there are clauses, at least one needs to match
for _, s := range componentTypes {
if strings.EqualFold(s, target.Scope) {
return true
}
}
return ActivityAbstain

return false
}

type ScopedName struct {
Expand Down
Loading