github.com/prebid/prebid-server/v2@v2.18.0/gdpr/purpose_enforcer.go (about)

     1  package gdpr
     2  
     3  import (
     4  	"github.com/prebid/go-gdpr/api"
     5  	"github.com/prebid/go-gdpr/consentconstants"
     6  	tcf2 "github.com/prebid/go-gdpr/vendorconsent/tcf2"
     7  	"github.com/prebid/prebid-server/v2/config"
     8  	"github.com/prebid/prebid-server/v2/openrtb_ext"
     9  )
    10  
    11  // PurposeEnforcer represents the enforcement strategy for determining if legal basis is achieved for a purpose
    12  type PurposeEnforcer interface {
    13  	LegalBasis(vendorInfo VendorInfo, name string, consent tcf2.ConsentMetadata, overrides Overrides) bool
    14  }
    15  
    16  // PurposeEnforcerBuilder generates an instance of PurposeEnforcer for a given purpose and bidder
    17  type PurposeEnforcerBuilder func(p consentconstants.Purpose, name string) PurposeEnforcer
    18  
    19  // Overrides specifies enforcement algorithm rule adjustments
    20  type Overrides struct {
    21  	allowLITransparency   bool
    22  	blockVendorExceptions bool
    23  	enforcePurpose        bool
    24  	enforceVendors        bool
    25  }
    26  
    27  type BidderInfo struct {
    28  	bidderCoreName openrtb_ext.BidderName
    29  	bidder         openrtb_ext.BidderName
    30  }
    31  type VendorInfo struct {
    32  	vendorID uint16
    33  	vendor   api.Vendor
    34  }
    35  
    36  // PurposeEnforcers holds the full and basic enforcers for a purpose
    37  type PurposeEnforcers struct {
    38  	Full  PurposeEnforcer
    39  	Basic PurposeEnforcer
    40  }
    41  
    42  // NewPurposeEnforcerBuilder creates a new instance of PurposeEnforcerBuilder. This function uses
    43  // closures so that any enforcer generated by the returned builder may use the config and also be
    44  // cached and reused within a request context
    45  func NewPurposeEnforcerBuilder(cfg TCF2ConfigReader) PurposeEnforcerBuilder {
    46  	cachedEnforcers := make([]PurposeEnforcers, 10)
    47  
    48  	return func(purpose consentconstants.Purpose, name string) PurposeEnforcer {
    49  		index := purpose - 1
    50  
    51  		var basicEnforcementVendor bool
    52  		if purpose == consentconstants.Purpose(1) {
    53  			basicEnforcementVendor = false
    54  		} else {
    55  			basicEnforcementVendors := cfg.BasicEnforcementVendors()
    56  			_, basicEnforcementVendor = basicEnforcementVendors[name]
    57  		}
    58  
    59  		enforceAlgo := cfg.PurposeEnforcementAlgo(purpose)
    60  		downgraded := isDowngraded(enforceAlgo, basicEnforcementVendor)
    61  
    62  		if enforceAlgo == config.TCF2BasicEnforcement || downgraded {
    63  			if cachedEnforcers[index].Basic != nil {
    64  				return cachedEnforcers[index].Basic
    65  			}
    66  
    67  			purposeCfg := purposeConfig{
    68  				PurposeID:                  purpose,
    69  				EnforceAlgo:                enforceAlgo,
    70  				EnforcePurpose:             cfg.PurposeEnforced(purpose),
    71  				EnforceVendors:             cfg.PurposeEnforcingVendors(purpose),
    72  				VendorExceptionMap:         cfg.PurposeVendorExceptions(purpose),
    73  				BasicEnforcementVendorsMap: cfg.BasicEnforcementVendors(),
    74  			}
    75  
    76  			enforcer := &BasicEnforcement{
    77  				cfg: purposeCfg,
    78  			}
    79  			cachedEnforcers[index].Basic = enforcer
    80  			return enforcer
    81  		} else {
    82  			if cachedEnforcers[index].Full != nil {
    83  				return cachedEnforcers[index].Full
    84  			}
    85  
    86  			purposeCfg := purposeConfig{
    87  				PurposeID:                  purpose,
    88  				EnforceAlgo:                enforceAlgo,
    89  				EnforcePurpose:             cfg.PurposeEnforced(purpose),
    90  				EnforceVendors:             cfg.PurposeEnforcingVendors(purpose),
    91  				VendorExceptionMap:         cfg.PurposeVendorExceptions(purpose),
    92  				BasicEnforcementVendorsMap: cfg.BasicEnforcementVendors(),
    93  			}
    94  
    95  			enforcer := &FullEnforcement{
    96  				cfg: purposeCfg,
    97  			}
    98  			cachedEnforcers[index].Full = enforcer
    99  			return enforcer
   100  		}
   101  	}
   102  }
   103  
   104  // isDowngraded determines if the enforcement algorithm used to determine legal basis for a
   105  // purpose should be downgraded from full enforcement to basic
   106  func isDowngraded(enforceAlgo config.TCF2EnforcementAlgo, basicEnforcementVendor bool) bool {
   107  	if enforceAlgo == config.TCF2FullEnforcement && basicEnforcementVendor {
   108  		return true
   109  	}
   110  	return false
   111  }