github.com/prebid/prebid-server@v0.275.0/config/account.go (about)

     1  package config
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"math"
     7  	"strings"
     8  
     9  	"github.com/prebid/go-gdpr/consentconstants"
    10  	"github.com/prebid/prebid-server/openrtb_ext"
    11  	"github.com/prebid/prebid-server/util/iputil"
    12  )
    13  
    14  // ChannelType enumerates the values of integrations Prebid Server can configure for an account
    15  type ChannelType string
    16  
    17  // Possible values of channel types Prebid Server can configure for an account
    18  const (
    19  	ChannelAMP   ChannelType = "amp"
    20  	ChannelApp   ChannelType = "app"
    21  	ChannelVideo ChannelType = "video"
    22  	ChannelWeb   ChannelType = "web"
    23  )
    24  
    25  // Account represents a publisher account configuration
    26  type Account struct {
    27  	ID                      string                                      `mapstructure:"id" json:"id"`
    28  	Disabled                bool                                        `mapstructure:"disabled" json:"disabled"`
    29  	CacheTTL                DefaultTTLs                                 `mapstructure:"cache_ttl" json:"cache_ttl"`
    30  	EventsEnabled           *bool                                       `mapstructure:"events_enabled" json:"events_enabled"` // Deprecated: Use events.enabled instead.
    31  	CCPA                    AccountCCPA                                 `mapstructure:"ccpa" json:"ccpa"`
    32  	GDPR                    AccountGDPR                                 `mapstructure:"gdpr" json:"gdpr"`
    33  	DebugAllow              bool                                        `mapstructure:"debug_allow" json:"debug_allow"`
    34  	DefaultIntegration      string                                      `mapstructure:"default_integration" json:"default_integration"`
    35  	CookieSync              CookieSync                                  `mapstructure:"cookie_sync" json:"cookie_sync"`
    36  	Events                  Events                                      `mapstructure:"events" json:"events"` // Don't enable this feature. It is still under developmment - https://github.com/prebid/prebid-server/issues/1725
    37  	TruncateTargetAttribute *int                                        `mapstructure:"truncate_target_attr" json:"truncate_target_attr"`
    38  	AlternateBidderCodes    *openrtb_ext.ExtAlternateBidderCodes        `mapstructure:"alternatebiddercodes" json:"alternatebiddercodes"`
    39  	Hooks                   AccountHooks                                `mapstructure:"hooks" json:"hooks"`
    40  	PriceFloors             AccountPriceFloors                          `mapstructure:"price_floors" json:"price_floors"`
    41  	Validations             Validations                                 `mapstructure:"validations" json:"validations"`
    42  	DefaultBidLimit         int                                         `mapstructure:"default_bid_limit" json:"default_bid_limit"`
    43  	BidAdjustments          *openrtb_ext.ExtRequestPrebidBidAdjustments `mapstructure:"bidadjustments" json:"bidadjustments"`
    44  	Privacy                 AccountPrivacy                              `mapstructure:"privacy" json:"privacy"`
    45  }
    46  
    47  // CookieSync represents the account-level defaults for the cookie sync endpoint.
    48  type CookieSync struct {
    49  	DefaultLimit    *int  `mapstructure:"default_limit" json:"default_limit"`
    50  	MaxLimit        *int  `mapstructure:"max_limit" json:"max_limit"`
    51  	DefaultCoopSync *bool `mapstructure:"default_coop_sync" json:"default_coop_sync"`
    52  }
    53  
    54  // AccountCCPA represents account-specific CCPA configuration
    55  type AccountCCPA struct {
    56  	Enabled            *bool          `mapstructure:"enabled" json:"enabled,omitempty"`
    57  	IntegrationEnabled AccountChannel `mapstructure:"integration_enabled" json:"integration_enabled"`
    58  	ChannelEnabled     AccountChannel `mapstructure:"channel_enabled" json:"channel_enabled"`
    59  }
    60  
    61  type AccountPriceFloors struct {
    62  	Enabled                bool `mapstructure:"enabled" json:"enabled"`
    63  	EnforceFloorsRate      int  `mapstructure:"enforce_floors_rate" json:"enforce_floors_rate"`
    64  	AdjustForBidAdjustment bool `mapstructure:"adjust_for_bid_adjustment" json:"adjust_for_bid_adjustment"`
    65  	EnforceDealFloors      bool `mapstructure:"enforce_deal_floors" json:"enforce_deal_floors"`
    66  	UseDynamicData         bool `mapstructure:"use_dynamic_data" json:"use_dynamic_data"`
    67  	MaxRule                int  `mapstructure:"max_rules" json:"max_rules"`
    68  	MaxSchemaDims          int  `mapstructure:"max_schema_dims" json:"max_schema_dims"`
    69  }
    70  
    71  func (pf *AccountPriceFloors) validate(errs []error) []error {
    72  
    73  	if pf.EnforceFloorsRate < 0 || pf.EnforceFloorsRate > 100 {
    74  		errs = append(errs, fmt.Errorf(`account_defaults.price_floors.enforce_floors_rate should be between 0 and 100`))
    75  	}
    76  
    77  	if pf.MaxRule < 0 || pf.MaxRule > math.MaxInt32 {
    78  		errs = append(errs, fmt.Errorf(`account_defaults.price_floors.max_rules should be between 0 and %v`, math.MaxInt32))
    79  	}
    80  
    81  	if pf.MaxSchemaDims < 0 || pf.MaxSchemaDims > 20 {
    82  		errs = append(errs, fmt.Errorf(`account_defaults.price_floors.max_schema_dims should be between 0 and 20`))
    83  	}
    84  
    85  	return errs
    86  }
    87  
    88  func (pf *AccountPriceFloors) IsAdjustForBidAdjustmentEnabled() bool {
    89  	return pf.AdjustForBidAdjustment
    90  }
    91  
    92  // EnabledForChannelType indicates whether CCPA is turned on at the account level for the specified channel type
    93  // by using the channel type setting if defined or the general CCPA setting if defined; otherwise it returns nil
    94  func (a *AccountCCPA) EnabledForChannelType(channelType ChannelType) *bool {
    95  	if channelEnabled := a.ChannelEnabled.GetByChannelType(channelType); channelEnabled != nil {
    96  		return channelEnabled
    97  	} else if integrationEnabled := a.IntegrationEnabled.GetByChannelType(channelType); integrationEnabled != nil {
    98  		return integrationEnabled
    99  	}
   100  	return a.Enabled
   101  }
   102  
   103  // AccountGDPR represents account-specific GDPR configuration
   104  type AccountGDPR struct {
   105  	Enabled            *bool          `mapstructure:"enabled" json:"enabled,omitempty"`
   106  	IntegrationEnabled AccountChannel `mapstructure:"integration_enabled" json:"integration_enabled"`
   107  	ChannelEnabled     AccountChannel `mapstructure:"channel_enabled" json:"channel_enabled"`
   108  	// Array of basic enforcement vendors that is used to create the hash table so vendor names can be instantly accessed
   109  	BasicEnforcementVendors    []string `mapstructure:"basic_enforcement_vendors" json:"basic_enforcement_vendors"`
   110  	BasicEnforcementVendorsMap map[string]struct{}
   111  	Purpose1                   AccountGDPRPurpose `mapstructure:"purpose1" json:"purpose1"`
   112  	Purpose2                   AccountGDPRPurpose `mapstructure:"purpose2" json:"purpose2"`
   113  	Purpose3                   AccountGDPRPurpose `mapstructure:"purpose3" json:"purpose3"`
   114  	Purpose4                   AccountGDPRPurpose `mapstructure:"purpose4" json:"purpose4"`
   115  	Purpose5                   AccountGDPRPurpose `mapstructure:"purpose5" json:"purpose5"`
   116  	Purpose6                   AccountGDPRPurpose `mapstructure:"purpose6" json:"purpose6"`
   117  	Purpose7                   AccountGDPRPurpose `mapstructure:"purpose7" json:"purpose7"`
   118  	Purpose8                   AccountGDPRPurpose `mapstructure:"purpose8" json:"purpose8"`
   119  	Purpose9                   AccountGDPRPurpose `mapstructure:"purpose9" json:"purpose9"`
   120  	Purpose10                  AccountGDPRPurpose `mapstructure:"purpose10" json:"purpose10"`
   121  	// Hash table of purpose configs for convenient purpose config lookup
   122  	PurposeConfigs      map[consentconstants.Purpose]*AccountGDPRPurpose
   123  	PurposeOneTreatment AccountGDPRPurposeOneTreatment `mapstructure:"purpose_one_treatment" json:"purpose_one_treatment"`
   124  	SpecialFeature1     AccountGDPRSpecialFeature      `mapstructure:"special_feature1" json:"special_feature1"`
   125  }
   126  
   127  // EnabledForChannelType indicates whether GDPR is turned on at the account level for the specified channel type
   128  // by using the channel type setting if defined or the general GDPR setting if defined; otherwise it returns nil.
   129  func (a *AccountGDPR) EnabledForChannelType(channelType ChannelType) *bool {
   130  	if channelEnabled := a.ChannelEnabled.GetByChannelType(channelType); channelEnabled != nil {
   131  		return channelEnabled
   132  	} else if integrationEnabled := a.IntegrationEnabled.GetByChannelType(channelType); integrationEnabled != nil {
   133  		return integrationEnabled
   134  	}
   135  	return a.Enabled
   136  }
   137  
   138  // FeatureOneEnforced gets the account level feature one enforced setting returning the value and whether or not it
   139  // was set. If not set, a default value of true is returned matching host default behavior.
   140  func (a *AccountGDPR) FeatureOneEnforced() (value, exists bool) {
   141  	if a.SpecialFeature1.Enforce == nil {
   142  		return true, false
   143  	}
   144  	return *a.SpecialFeature1.Enforce, true
   145  }
   146  
   147  // FeatureOneVendorException checks if the given bidder is a vendor exception.
   148  func (a *AccountGDPR) FeatureOneVendorException(bidder openrtb_ext.BidderName) (value, exists bool) {
   149  	if a.SpecialFeature1.VendorExceptionMap == nil {
   150  		return false, false
   151  	}
   152  	_, found := a.SpecialFeature1.VendorExceptionMap[bidder]
   153  
   154  	return found, true
   155  }
   156  
   157  // PurposeEnforced checks if full enforcement is turned on for a given purpose at the account level. It returns the
   158  // enforcement strategy type and whether or not it is set on the account. If not set, a default value of true is
   159  // returned matching host default behavior.
   160  func (a *AccountGDPR) PurposeEnforced(purpose consentconstants.Purpose) (value, exists bool) {
   161  	if a.PurposeConfigs[purpose] == nil {
   162  		return true, false
   163  	}
   164  	if a.PurposeConfigs[purpose].EnforcePurpose == nil {
   165  		return true, false
   166  	}
   167  	return *a.PurposeConfigs[purpose].EnforcePurpose, true
   168  }
   169  
   170  // PurposeEnforcementAlgo checks the purpose enforcement algo for a given purpose by first
   171  // looking at the account settings, and if not set there, defaulting to the host configuration.
   172  func (a *AccountGDPR) PurposeEnforcementAlgo(purpose consentconstants.Purpose) (value TCF2EnforcementAlgo, exists bool) {
   173  	var c *AccountGDPRPurpose
   174  	c, exists = a.PurposeConfigs[purpose]
   175  
   176  	if exists && (c.EnforceAlgoID == TCF2BasicEnforcement || c.EnforceAlgoID == TCF2FullEnforcement) {
   177  		return c.EnforceAlgoID, true
   178  	}
   179  	return TCF2UndefinedEnforcement, false
   180  }
   181  
   182  // PurposeEnforcingVendors gets the account level enforce vendors setting for a given purpose returning the value and
   183  // whether or not it is set. If not set, a default value of true is returned matching host default behavior.
   184  func (a *AccountGDPR) PurposeEnforcingVendors(purpose consentconstants.Purpose) (value, exists bool) {
   185  	if a.PurposeConfigs[purpose] == nil {
   186  		return true, false
   187  	}
   188  	if a.PurposeConfigs[purpose].EnforceVendors == nil {
   189  		return true, false
   190  	}
   191  	return *a.PurposeConfigs[purpose].EnforceVendors, true
   192  }
   193  
   194  // PurposeVendorExceptions returns the vendor exception map for a given purpose.
   195  func (a *AccountGDPR) PurposeVendorExceptions(purpose consentconstants.Purpose) (value map[openrtb_ext.BidderName]struct{}, exists bool) {
   196  	c, exists := a.PurposeConfigs[purpose]
   197  
   198  	if exists && c.VendorExceptionMap != nil {
   199  		return c.VendorExceptionMap, true
   200  	}
   201  	return nil, false
   202  }
   203  
   204  // PurposeOneTreatmentEnabled gets the account level purpose one treatment enabled setting returning the value and
   205  // whether or not it is set. If not set, a default value of true is returned matching host default behavior.
   206  func (a *AccountGDPR) PurposeOneTreatmentEnabled() (value, exists bool) {
   207  	if a.PurposeOneTreatment.Enabled == nil {
   208  		return true, false
   209  	}
   210  	return *a.PurposeOneTreatment.Enabled, true
   211  }
   212  
   213  // PurposeOneTreatmentAccessAllowed gets the account level purpose one treatment access allowed setting returning the
   214  // value and whether or not it is set. If not set, a default value of true is returned matching host default behavior.
   215  func (a *AccountGDPR) PurposeOneTreatmentAccessAllowed() (value, exists bool) {
   216  	if a.PurposeOneTreatment.AccessAllowed == nil {
   217  		return true, false
   218  	}
   219  	return *a.PurposeOneTreatment.AccessAllowed, true
   220  }
   221  
   222  // AccountGDPRPurpose represents account-specific GDPR purpose configuration
   223  type AccountGDPRPurpose struct {
   224  	EnforceAlgo string `mapstructure:"enforce_algo" json:"enforce_algo,omitempty"`
   225  	// Integer representation of enforcement algo for performance improvement on compares
   226  	EnforceAlgoID  TCF2EnforcementAlgo
   227  	EnforcePurpose *bool `mapstructure:"enforce_purpose" json:"enforce_purpose,omitempty"`
   228  	EnforceVendors *bool `mapstructure:"enforce_vendors" json:"enforce_vendors,omitempty"`
   229  	// Array of vendor exceptions that is used to create the hash table VendorExceptionMap so vendor names can be instantly accessed
   230  	VendorExceptions   []openrtb_ext.BidderName `mapstructure:"vendor_exceptions" json:"vendor_exceptions"`
   231  	VendorExceptionMap map[openrtb_ext.BidderName]struct{}
   232  }
   233  
   234  // AccountGDPRSpecialFeature represents account-specific GDPR special feature configuration
   235  type AccountGDPRSpecialFeature struct {
   236  	Enforce *bool `mapstructure:"enforce" json:"enforce"`
   237  	// Array of vendor exceptions that is used to create the hash table VendorExceptionMap so vendor names can be instantly accessed
   238  	VendorExceptions   []openrtb_ext.BidderName `mapstructure:"vendor_exceptions" json:"vendor_exceptions"`
   239  	VendorExceptionMap map[openrtb_ext.BidderName]struct{}
   240  }
   241  
   242  // AccountGDPRPurposeOneTreatment represents account-specific GDPR purpose one treatment configuration
   243  type AccountGDPRPurposeOneTreatment struct {
   244  	Enabled       *bool `mapstructure:"enabled"`
   245  	AccessAllowed *bool `mapstructure:"access_allowed"`
   246  }
   247  
   248  // AccountChannel indicates whether a particular privacy policy (GDPR, CCPA) is enabled for each channel type
   249  type AccountChannel struct {
   250  	AMP   *bool `mapstructure:"amp" json:"amp,omitempty"`
   251  	App   *bool `mapstructure:"app" json:"app,omitempty"`
   252  	Video *bool `mapstructure:"video" json:"video,omitempty"`
   253  	Web   *bool `mapstructure:"web" json:"web,omitempty"`
   254  }
   255  
   256  // GetByChannelType looks up the account integration enabled setting for the specified channel type
   257  func (a *AccountChannel) GetByChannelType(channelType ChannelType) *bool {
   258  	var channelEnabled *bool
   259  
   260  	switch channelType {
   261  	case ChannelAMP:
   262  		channelEnabled = a.AMP
   263  	case ChannelApp:
   264  		channelEnabled = a.App
   265  	case ChannelVideo:
   266  		channelEnabled = a.Video
   267  	case ChannelWeb:
   268  		channelEnabled = a.Web
   269  	}
   270  
   271  	return channelEnabled
   272  }
   273  
   274  // AccountHooks represents account-specific hooks configuration
   275  type AccountHooks struct {
   276  	Modules       AccountModules    `mapstructure:"modules" json:"modules"`
   277  	ExecutionPlan HookExecutionPlan `mapstructure:"execution_plan" json:"execution_plan"`
   278  }
   279  
   280  // AccountModules mapping provides account-level module configuration
   281  // format: map[vendor_name]map[module_name]json.RawMessage
   282  type AccountModules map[string]map[string]json.RawMessage
   283  
   284  // ModuleConfig returns the account-level module config.
   285  // The id argument must be passed in the form "vendor.module_name",
   286  // otherwise an error is returned.
   287  func (m AccountModules) ModuleConfig(id string) (json.RawMessage, error) {
   288  	ns := strings.SplitN(id, ".", 2)
   289  	if len(ns) < 2 {
   290  		return nil, fmt.Errorf("ID must consist of vendor and module names separated by dot, got: %s", id)
   291  	}
   292  
   293  	vendor := ns[0]
   294  	module := ns[1]
   295  	return m[vendor][module], nil
   296  }
   297  
   298  func (a *AccountChannel) IsSet() bool {
   299  	return a.AMP != nil || a.App != nil || a.Video != nil || a.Web != nil
   300  }
   301  
   302  type AccountPrivacy struct {
   303  	AllowActivities *AllowActivities `mapstructure:"allowactivities" json:"allowactivities"`
   304  	IPv6Config      IPv6             `mapstructure:"ipv6" json:"ipv6"`
   305  	IPv4Config      IPv4             `mapstructure:"ipv4" json:"ipv4"`
   306  }
   307  
   308  type IPv6 struct {
   309  	AnonKeepBits int `mapstructure:"anon_keep_bits" json:"anon_keep_bits"`
   310  }
   311  
   312  type IPv4 struct {
   313  	AnonKeepBits int `mapstructure:"anon_keep_bits" json:"anon_keep_bits"`
   314  }
   315  
   316  func (ip *IPv6) Validate(errs []error) []error {
   317  	if ip.AnonKeepBits > iputil.IPv6BitSize || ip.AnonKeepBits < 0 {
   318  		err := fmt.Errorf("bits cannot exceed %d in ipv6 address, or be less than 0", iputil.IPv6BitSize)
   319  		errs = append(errs, err)
   320  	}
   321  	return errs
   322  }
   323  
   324  func (ip *IPv4) Validate(errs []error) []error {
   325  	if ip.AnonKeepBits > iputil.IPv4BitSize || ip.AnonKeepBits < 0 {
   326  		err := fmt.Errorf("bits cannot exceed %d in ipv4 address, or be less than 0", iputil.IPv4BitSize)
   327  		errs = append(errs, err)
   328  	}
   329  	return errs
   330  }