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

     1  package config
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"net/url"
     8  	"reflect"
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/golang/glog"
    14  	"github.com/prebid/go-gdpr/consentconstants"
    15  	"github.com/prebid/openrtb/v19/openrtb2"
    16  	"github.com/prebid/prebid-server/errortypes"
    17  	"github.com/prebid/prebid-server/openrtb_ext"
    18  	"github.com/prebid/prebid-server/util/ptrutil"
    19  	"github.com/spf13/viper"
    20  )
    21  
    22  // Configuration specifies the static application config.
    23  type Configuration struct {
    24  	ExternalURL      string      `mapstructure:"external_url"`
    25  	Host             string      `mapstructure:"host"`
    26  	Port             int         `mapstructure:"port"`
    27  	UnixSocketEnable bool        `mapstructure:"unix_socket_enable"`
    28  	UnixSocketName   string      `mapstructure:"unix_socket_name"`
    29  	Client           HTTPClient  `mapstructure:"http_client"`
    30  	CacheClient      HTTPClient  `mapstructure:"http_client_cache"`
    31  	AdminPort        int         `mapstructure:"admin_port"`
    32  	EnableGzip       bool        `mapstructure:"enable_gzip"`
    33  	Compression      Compression `mapstructure:"compression"`
    34  	// GarbageCollectorThreshold allocates virtual memory (in bytes) which is not used by PBS but
    35  	// serves as a hack to trigger the garbage collector only when the heap reaches at least this size.
    36  	// More info: https://github.com/golang/go/issues/48409
    37  	GarbageCollectorThreshold int `mapstructure:"garbage_collector_threshold"`
    38  	// StatusResponse is the string which will be returned by the /status endpoint when things are OK.
    39  	// If empty, it will return a 204 with no content.
    40  	StatusResponse    string          `mapstructure:"status_response"`
    41  	AuctionTimeouts   AuctionTimeouts `mapstructure:"auction_timeouts_ms"`
    42  	TmaxAdjustments   TmaxAdjustments `mapstructure:"tmax_adjustments"`
    43  	CacheURL          Cache           `mapstructure:"cache"`
    44  	ExtCacheURL       ExternalCache   `mapstructure:"external_cache"`
    45  	RecaptchaSecret   string          `mapstructure:"recaptcha_secret"`
    46  	HostCookie        HostCookie      `mapstructure:"host_cookie"`
    47  	Metrics           Metrics         `mapstructure:"metrics"`
    48  	StoredRequests    StoredRequests  `mapstructure:"stored_requests"`
    49  	StoredRequestsAMP StoredRequests  `mapstructure:"stored_amp_req"`
    50  	CategoryMapping   StoredRequests  `mapstructure:"category_mapping"`
    51  	VTrack            VTrack          `mapstructure:"vtrack"`
    52  	Event             Event           `mapstructure:"event"`
    53  	Accounts          StoredRequests  `mapstructure:"accounts"`
    54  	UserSync          UserSync        `mapstructure:"user_sync"`
    55  	// Note that StoredVideo refers to stored video requests, and has nothing to do with caching video creatives.
    56  	StoredVideo     StoredRequests `mapstructure:"stored_video_req"`
    57  	StoredResponses StoredRequests `mapstructure:"stored_responses"`
    58  
    59  	MaxRequestSize       int64             `mapstructure:"max_request_size"`
    60  	Analytics            Analytics         `mapstructure:"analytics"`
    61  	AMPTimeoutAdjustment int64             `mapstructure:"amp_timeout_adjustment_ms"`
    62  	GDPR                 GDPR              `mapstructure:"gdpr"`
    63  	CCPA                 CCPA              `mapstructure:"ccpa"`
    64  	LMT                  LMT               `mapstructure:"lmt"`
    65  	CurrencyConverter    CurrencyConverter `mapstructure:"currency_converter"`
    66  	DefReqConfig         DefReqConfig      `mapstructure:"default_request"`
    67  
    68  	VideoStoredRequestRequired bool `mapstructure:"video_stored_request_required"`
    69  
    70  	// Array of blacklisted apps that is used to create the hash table BlacklistedAppMap so App.ID's can be instantly accessed.
    71  	BlacklistedApps   []string `mapstructure:"blacklisted_apps,flow"`
    72  	BlacklistedAppMap map[string]bool
    73  	// Array of blacklisted accounts that is used to create the hash table BlacklistedAcctMap so Account.ID's can be instantly accessed.
    74  	BlacklistedAccts   []string `mapstructure:"blacklisted_accts,flow"`
    75  	BlacklistedAcctMap map[string]bool
    76  	// Is publisher/account ID required to be submitted in the OpenRTB2 request
    77  	AccountRequired bool `mapstructure:"account_required"`
    78  	// AccountDefaults defines default settings for valid accounts that are partially defined
    79  	// and provides a way to set global settings that can be overridden at account level.
    80  	AccountDefaults Account `mapstructure:"account_defaults"`
    81  	// accountDefaultsJSON is the internal serialized form of AccountDefaults used for json merge
    82  	accountDefaultsJSON json.RawMessage
    83  	// Local private file containing SSL certificates
    84  	PemCertsFile string `mapstructure:"certificates_file"`
    85  	// Custom headers to handle request timeouts from queueing infrastructure
    86  	RequestTimeoutHeaders RequestTimeoutHeaders `mapstructure:"request_timeout_headers"`
    87  	// Debug/logging flags go here
    88  	Debug Debug `mapstructure:"debug"`
    89  	// RequestValidation specifies the request validation options.
    90  	RequestValidation RequestValidation `mapstructure:"request_validation"`
    91  	// When true, PBS will assign a randomly generated UUID to req.Source.TID if it is empty
    92  	AutoGenSourceTID bool `mapstructure:"auto_gen_source_tid"`
    93  	//When true, new bid id will be generated in seatbid[].bid[].ext.prebid.bidid and used in event urls instead
    94  	GenerateBidID bool `mapstructure:"generate_bid_id"`
    95  	// GenerateRequestID overrides the bidrequest.id in an AMP Request or an App Stored Request with a generated UUID if set to true. The default is false.
    96  	GenerateRequestID bool                      `mapstructure:"generate_request_id"`
    97  	HostSChainNode    *openrtb2.SupplyChainNode `mapstructure:"host_schain_node"`
    98  	// Experiment configures non-production ready features.
    99  	Experiment Experiment `mapstructure:"experiment"`
   100  	DataCenter string     `mapstructure:"datacenter"`
   101  	// BidderInfos supports adapter overrides in extra configs like pbs.json, pbs.yaml, etc.
   102  	// Refers to main.go `configFileName` constant
   103  	BidderInfos BidderInfos `mapstructure:"adapters"`
   104  	// Hooks provides a way to specify hook execution plan for specific endpoints and stages
   105  	Hooks       Hooks       `mapstructure:"hooks"`
   106  	Validations Validations `mapstructure:"validations"`
   107  	PriceFloors PriceFloors `mapstructure:"price_floors"`
   108  }
   109  
   110  type PriceFloors struct {
   111  	Enabled bool `mapstructure:"enabled"`
   112  }
   113  
   114  const MIN_COOKIE_SIZE_BYTES = 500
   115  
   116  type HTTPClient struct {
   117  	MaxConnsPerHost     int `mapstructure:"max_connections_per_host"`
   118  	MaxIdleConns        int `mapstructure:"max_idle_connections"`
   119  	MaxIdleConnsPerHost int `mapstructure:"max_idle_connections_per_host"`
   120  	IdleConnTimeout     int `mapstructure:"idle_connection_timeout_seconds"`
   121  }
   122  
   123  func (cfg *Configuration) validate(v *viper.Viper) []error {
   124  	var errs []error
   125  	errs = cfg.AuctionTimeouts.validate(errs)
   126  	errs = cfg.StoredRequests.validate(errs)
   127  	errs = cfg.StoredRequestsAMP.validate(errs)
   128  	errs = cfg.Accounts.validate(errs)
   129  	errs = cfg.CategoryMapping.validate(errs)
   130  	errs = cfg.StoredVideo.validate(errs)
   131  	errs = cfg.Metrics.validate(errs)
   132  	if cfg.MaxRequestSize < 0 {
   133  		errs = append(errs, fmt.Errorf("cfg.max_request_size must be >= 0. Got %d", cfg.MaxRequestSize))
   134  	}
   135  	errs = cfg.GDPR.validate(v, errs)
   136  	errs = cfg.CurrencyConverter.validate(errs)
   137  	errs = cfg.Debug.validate(errs)
   138  	errs = cfg.ExtCacheURL.validate(errs)
   139  	errs = cfg.AccountDefaults.PriceFloors.validate(errs)
   140  	if cfg.AccountDefaults.Disabled {
   141  		glog.Warning(`With account_defaults.disabled=true, host-defined accounts must exist and have "disabled":false. All other requests will be rejected.`)
   142  	}
   143  
   144  	if cfg.PriceFloors.Enabled {
   145  		glog.Warning(`cfg.PriceFloors.Enabled will currently not do anything as price floors feature is still under development.`)
   146  	}
   147  
   148  	if len(cfg.AccountDefaults.Events.VASTEvents) > 0 {
   149  		errs = append(errs, errors.New("account_defaults.Events.VASTEvents has no effect as the feature is under development."))
   150  	}
   151  
   152  	errs = cfg.Experiment.validate(errs)
   153  	errs = cfg.BidderInfos.validate(errs)
   154  	errs = cfg.AccountDefaults.Privacy.IPv6Config.Validate(errs)
   155  	errs = cfg.AccountDefaults.Privacy.IPv4Config.Validate(errs)
   156  
   157  	return errs
   158  }
   159  
   160  type AuctionTimeouts struct {
   161  	// The default timeout is used if the user's request didn't define one. Use 0 if there's no default.
   162  	Default uint64 `mapstructure:"default"`
   163  	// The max timeout is used as an absolute cap, to prevent excessively long ones. Use 0 for no cap
   164  	Max uint64 `mapstructure:"max"`
   165  }
   166  
   167  func (cfg *AuctionTimeouts) validate(errs []error) []error {
   168  	if cfg.Max < cfg.Default {
   169  		errs = append(errs, fmt.Errorf("auction_timeouts_ms.max cannot be less than auction_timeouts_ms.default. max=%d, default=%d", cfg.Max, cfg.Default))
   170  	}
   171  	return errs
   172  }
   173  
   174  func (data *ExternalCache) validate(errs []error) []error {
   175  	if data.Host == "" && data.Path == "" {
   176  		// Both host and path can be blank. No further validation needed
   177  		return errs
   178  	}
   179  
   180  	if data.Scheme != "" && data.Scheme != "http" && data.Scheme != "https" {
   181  		return append(errs, errors.New("External cache Scheme must be http or https if specified"))
   182  	}
   183  
   184  	// Either host or path or both not empty, validate.
   185  	if data.Host == "" && data.Path != "" || data.Host != "" && data.Path == "" {
   186  		return append(errs, errors.New("External cache Host and Path must both be specified"))
   187  	}
   188  	if strings.HasSuffix(data.Host, "/") {
   189  		return append(errs, errors.New(fmt.Sprintf("External cache Host '%s' must not end with a path separator", data.Host)))
   190  	}
   191  	if strings.Contains(data.Host, "://") {
   192  		return append(errs, errors.New(fmt.Sprintf("External cache Host must not specify a protocol. '%s'", data.Host)))
   193  	}
   194  	if !strings.HasPrefix(data.Path, "/") {
   195  		return append(errs, errors.New(fmt.Sprintf("External cache Path '%s' must begin with a path separator", data.Path)))
   196  	}
   197  
   198  	urlObj, err := url.Parse("https://" + data.Host + data.Path)
   199  	if err != nil {
   200  		return append(errs, errors.New(fmt.Sprintf("External cache Path validation error: %s ", err.Error())))
   201  	}
   202  	if urlObj.Host != data.Host {
   203  		return append(errs, errors.New(fmt.Sprintf("External cache Host '%s' is invalid", data.Host)))
   204  	}
   205  	if urlObj.Path != data.Path {
   206  		return append(errs, errors.New("External cache Path is invalid"))
   207  	}
   208  
   209  	return errs
   210  }
   211  
   212  // LimitAuctionTimeout returns the min of requested or cfg.MaxAuctionTimeout.
   213  // Both values treat "0" as "infinite".
   214  func (cfg *AuctionTimeouts) LimitAuctionTimeout(requested time.Duration) time.Duration {
   215  	if requested == 0 && cfg.Default != 0 {
   216  		return time.Duration(cfg.Default) * time.Millisecond
   217  	}
   218  	if cfg.Max > 0 {
   219  		maxTimeout := time.Duration(cfg.Max) * time.Millisecond
   220  		if requested == 0 || requested > maxTimeout {
   221  			return maxTimeout
   222  		}
   223  	}
   224  	return requested
   225  }
   226  
   227  // Privacy is a grouping of privacy related configs to assist in dependency injection.
   228  type Privacy struct {
   229  	CCPA CCPA
   230  	GDPR GDPR
   231  	LMT  LMT
   232  }
   233  
   234  type GDPR struct {
   235  	Enabled                 bool         `mapstructure:"enabled"`
   236  	HostVendorID            int          `mapstructure:"host_vendor_id"`
   237  	DefaultValue            string       `mapstructure:"default_value"`
   238  	Timeouts                GDPRTimeouts `mapstructure:"timeouts_ms"`
   239  	NonStandardPublishers   []string     `mapstructure:"non_standard_publishers,flow"`
   240  	NonStandardPublisherMap map[string]struct{}
   241  	TCF2                    TCF2 `mapstructure:"tcf2"`
   242  	AMPException            bool `mapstructure:"amp_exception"` // Deprecated: Use account-level GDPR settings (gdpr.integration_enabled.amp) instead
   243  	// EEACountries (EEA = European Economic Area) are a list of countries where we should assume GDPR applies.
   244  	// If the gdpr flag is unset in a request, but geo.country is set, we will assume GDPR applies if and only
   245  	// if the country matches one on this list. If both the GDPR flag and country are not set, we default
   246  	// to DefaultValue
   247  	EEACountries    []string `mapstructure:"eea_countries"`
   248  	EEACountriesMap map[string]struct{}
   249  }
   250  
   251  func (cfg *GDPR) validate(v *viper.Viper, errs []error) []error {
   252  	if !v.IsSet("gdpr.default_value") {
   253  		errs = append(errs, fmt.Errorf("gdpr.default_value is required and must be specified"))
   254  	} else if cfg.DefaultValue != "0" && cfg.DefaultValue != "1" {
   255  		errs = append(errs, fmt.Errorf("gdpr.default_value must be 0 or 1"))
   256  	}
   257  	if cfg.HostVendorID < 0 || cfg.HostVendorID > 0xffff {
   258  		errs = append(errs, fmt.Errorf("gdpr.host_vendor_id must be in the range [0, %d]. Got %d", 0xffff, cfg.HostVendorID))
   259  	}
   260  	if cfg.HostVendorID == 0 {
   261  		glog.Warning("gdpr.host_vendor_id was not specified. Host company GDPR checks will be skipped.")
   262  	}
   263  	if cfg.AMPException == true {
   264  		errs = append(errs, fmt.Errorf("gdpr.amp_exception has been discontinued and must be removed from your config. If you need to disable GDPR for AMP, you may do so per-account (gdpr.integration_enabled.amp) or at the host level for the default account (account_defaults.gdpr.integration_enabled.amp)"))
   265  	}
   266  	return cfg.validatePurposes(errs)
   267  }
   268  
   269  func (cfg *GDPR) validatePurposes(errs []error) []error {
   270  	purposeConfigs := []TCF2Purpose{
   271  		cfg.TCF2.Purpose1,
   272  		cfg.TCF2.Purpose2,
   273  		cfg.TCF2.Purpose3,
   274  		cfg.TCF2.Purpose4,
   275  		cfg.TCF2.Purpose5,
   276  		cfg.TCF2.Purpose6,
   277  		cfg.TCF2.Purpose7,
   278  		cfg.TCF2.Purpose8,
   279  		cfg.TCF2.Purpose9,
   280  		cfg.TCF2.Purpose10,
   281  	}
   282  
   283  	for i := 0; i < len(purposeConfigs); i++ {
   284  		enforceAlgoValue := purposeConfigs[i].EnforceAlgo
   285  		enforceAlgoField := fmt.Sprintf("gdpr.tcf2.purpose%d.enforce_algo", (i + 1))
   286  
   287  		if enforceAlgoValue != TCF2EnforceAlgoFull && enforceAlgoValue != TCF2EnforceAlgoBasic {
   288  			errs = append(errs, fmt.Errorf("%s must be \"basic\" or \"full\". Got %s", enforceAlgoField, enforceAlgoValue))
   289  		}
   290  	}
   291  	return errs
   292  }
   293  
   294  type GDPRTimeouts struct {
   295  	InitVendorlistFetch   int `mapstructure:"init_vendorlist_fetches"`
   296  	ActiveVendorlistFetch int `mapstructure:"active_vendorlist_fetch"`
   297  }
   298  
   299  func (t *GDPRTimeouts) InitTimeout() time.Duration {
   300  	return time.Duration(t.InitVendorlistFetch) * time.Millisecond
   301  }
   302  
   303  func (t *GDPRTimeouts) ActiveTimeout() time.Duration {
   304  	return time.Duration(t.ActiveVendorlistFetch) * time.Millisecond
   305  }
   306  
   307  const (
   308  	TCF2EnforceAlgoBasic = "basic"
   309  	TCF2EnforceAlgoFull  = "full"
   310  )
   311  
   312  type TCF2EnforcementAlgo int
   313  
   314  const (
   315  	TCF2UndefinedEnforcement TCF2EnforcementAlgo = iota
   316  	TCF2BasicEnforcement
   317  	TCF2FullEnforcement
   318  )
   319  
   320  // TCF2 defines the TCF2 specific configurations for GDPR
   321  type TCF2 struct {
   322  	Enabled   bool        `mapstructure:"enabled"`
   323  	Purpose1  TCF2Purpose `mapstructure:"purpose1"`
   324  	Purpose2  TCF2Purpose `mapstructure:"purpose2"`
   325  	Purpose3  TCF2Purpose `mapstructure:"purpose3"`
   326  	Purpose4  TCF2Purpose `mapstructure:"purpose4"`
   327  	Purpose5  TCF2Purpose `mapstructure:"purpose5"`
   328  	Purpose6  TCF2Purpose `mapstructure:"purpose6"`
   329  	Purpose7  TCF2Purpose `mapstructure:"purpose7"`
   330  	Purpose8  TCF2Purpose `mapstructure:"purpose8"`
   331  	Purpose9  TCF2Purpose `mapstructure:"purpose9"`
   332  	Purpose10 TCF2Purpose `mapstructure:"purpose10"`
   333  	// Map of purpose configs for easy purpose lookup
   334  	PurposeConfigs      map[consentconstants.Purpose]*TCF2Purpose
   335  	SpecialFeature1     TCF2SpecialFeature      `mapstructure:"special_feature1"`
   336  	PurposeOneTreatment TCF2PurposeOneTreatment `mapstructure:"purpose_one_treatment"`
   337  }
   338  
   339  // ChannelEnabled checks if a given channel type is enabled. All channel types are considered either
   340  // enabled or disabled based on the Enabled flag.
   341  func (t *TCF2) ChannelEnabled(channelType ChannelType) bool {
   342  	return t.Enabled
   343  }
   344  
   345  // IsEnabled indicates if TCF2 is enabled
   346  func (t *TCF2) IsEnabled() bool {
   347  	return t.Enabled
   348  }
   349  
   350  // PurposeEnforced checks if full enforcement is turned on for a given purpose. With full enforcement enabled, the
   351  // GDPR full enforcement algorithm will execute for that purpose determining legal basis; otherwise it's skipped.
   352  func (t *TCF2) PurposeEnforced(purpose consentconstants.Purpose) (enforce bool) {
   353  	if t.PurposeConfigs[purpose] == nil {
   354  		return false
   355  	}
   356  	return t.PurposeConfigs[purpose].EnforcePurpose
   357  }
   358  
   359  // PurposeEnforcementAlgo returns the default enforcement algorithm for a given purpose
   360  func (t *TCF2) PurposeEnforcementAlgo(purpose consentconstants.Purpose) (enforcement TCF2EnforcementAlgo) {
   361  	if c, exists := t.PurposeConfigs[purpose]; exists {
   362  		return c.EnforceAlgoID
   363  	}
   364  	return TCF2FullEnforcement
   365  }
   366  
   367  // PurposeEnforcingVendors checks if enforcing vendors is turned on for a given purpose. With enforcing vendors
   368  // enabled, the GDPR full enforcement algorithm considers the GVL when determining legal basis; otherwise it's skipped.
   369  func (t *TCF2) PurposeEnforcingVendors(purpose consentconstants.Purpose) (enforce bool) {
   370  	if t.PurposeConfigs[purpose] == nil {
   371  		return false
   372  	}
   373  	return t.PurposeConfigs[purpose].EnforceVendors
   374  }
   375  
   376  // PurposeVendorExceptions returns the vendor exception map for a given purpose if it exists, otherwise it returns
   377  // an empty map of vendor exceptions
   378  func (t *TCF2) PurposeVendorExceptions(purpose consentconstants.Purpose) (vendorExceptions map[openrtb_ext.BidderName]struct{}) {
   379  	c, exists := t.PurposeConfigs[purpose]
   380  
   381  	if exists && c.VendorExceptionMap != nil {
   382  		return c.VendorExceptionMap
   383  	}
   384  	return make(map[openrtb_ext.BidderName]struct{}, 0)
   385  }
   386  
   387  // FeatureOneEnforced checks if special feature one is enforced. If it is enforced, PBS will determine whether geo
   388  // information may be passed through in the bid request.
   389  func (t *TCF2) FeatureOneEnforced() bool {
   390  	return t.SpecialFeature1.Enforce
   391  }
   392  
   393  // FeatureOneVendorException checks if the specified bidder is considered a vendor exception for special feature one.
   394  // If a bidder is a vendor exception, PBS will bypass the pass geo calculation passing the geo information in the bid request.
   395  func (t *TCF2) FeatureOneVendorException(bidder openrtb_ext.BidderName) bool {
   396  	if _, ok := t.SpecialFeature1.VendorExceptionMap[bidder]; ok {
   397  		return true
   398  	}
   399  	return false
   400  }
   401  
   402  // PurposeOneTreatmentEnabled checks if purpose one treatment is enabled.
   403  func (t *TCF2) PurposeOneTreatmentEnabled() bool {
   404  	return t.PurposeOneTreatment.Enabled
   405  }
   406  
   407  // PurposeOneTreatmentAccessAllowed checks if purpose one treatment access is allowed.
   408  func (t *TCF2) PurposeOneTreatmentAccessAllowed() bool {
   409  	return t.PurposeOneTreatment.AccessAllowed
   410  }
   411  
   412  // Making a purpose struct so purpose specific details can be added later.
   413  type TCF2Purpose struct {
   414  	Enabled     bool   `mapstructure:"enabled"` // Deprecated: Use enforce_purpose instead
   415  	EnforceAlgo string `mapstructure:"enforce_algo"`
   416  	// Integer representation of enforcement algo for performance improvement on compares
   417  	EnforceAlgoID  TCF2EnforcementAlgo
   418  	EnforcePurpose bool `mapstructure:"enforce_purpose"`
   419  	EnforceVendors bool `mapstructure:"enforce_vendors"`
   420  	// Array of vendor exceptions that is used to create the hash table VendorExceptionMap so vendor names can be instantly accessed
   421  	VendorExceptions   []openrtb_ext.BidderName `mapstructure:"vendor_exceptions"`
   422  	VendorExceptionMap map[openrtb_ext.BidderName]struct{}
   423  }
   424  
   425  type TCF2SpecialFeature struct {
   426  	Enforce bool `mapstructure:"enforce"`
   427  	// Array of vendor exceptions that is used to create the hash table VendorExceptionMap so vendor names can be instantly accessed
   428  	VendorExceptions   []openrtb_ext.BidderName `mapstructure:"vendor_exceptions"`
   429  	VendorExceptionMap map[openrtb_ext.BidderName]struct{}
   430  }
   431  
   432  type TCF2PurposeOneTreatment struct {
   433  	Enabled       bool `mapstructure:"enabled"`
   434  	AccessAllowed bool `mapstructure:"access_allowed"`
   435  }
   436  
   437  type CCPA struct {
   438  	Enforce bool `mapstructure:"enforce"`
   439  }
   440  
   441  type LMT struct {
   442  	Enforce bool `mapstructure:"enforce"`
   443  }
   444  
   445  type Analytics struct {
   446  	File     FileLogs `mapstructure:"file"`
   447  	Pubstack Pubstack `mapstructure:"pubstack"`
   448  }
   449  
   450  type CurrencyConverter struct {
   451  	FetchURL             string `mapstructure:"fetch_url"`
   452  	FetchIntervalSeconds int    `mapstructure:"fetch_interval_seconds"`
   453  	StaleRatesSeconds    int    `mapstructure:"stale_rates_seconds"`
   454  }
   455  
   456  func (cfg *CurrencyConverter) validate(errs []error) []error {
   457  	if cfg.FetchIntervalSeconds < 0 {
   458  		errs = append(errs, fmt.Errorf("currency_converter.fetch_interval_seconds must be in the range [0, %d]. Got %d", 0xffff, cfg.FetchIntervalSeconds))
   459  	}
   460  	return errs
   461  }
   462  
   463  // FileLogs Corresponding config for FileLogger as a PBS Analytics Module
   464  type FileLogs struct {
   465  	Filename string `mapstructure:"filename"`
   466  }
   467  
   468  type Pubstack struct {
   469  	Enabled     bool           `mapstructure:"enabled"`
   470  	ScopeId     string         `mapstructure:"scopeid"`
   471  	IntakeUrl   string         `mapstructure:"endpoint"`
   472  	Buffers     PubstackBuffer `mapstructure:"buffers"`
   473  	ConfRefresh string         `mapstructure:"configuration_refresh_delay"`
   474  }
   475  
   476  type PubstackBuffer struct {
   477  	BufferSize string `mapstructure:"size"`
   478  	EventCount int    `mapstructure:"count"`
   479  	Timeout    string `mapstructure:"timeout"`
   480  }
   481  
   482  type VTrack struct {
   483  	TimeoutMS          int64 `mapstructure:"timeout_ms"`
   484  	AllowUnknownBidder bool  `mapstructure:"allow_unknown_bidder"`
   485  	Enabled            bool  `mapstructure:"enabled"`
   486  }
   487  
   488  type Event struct {
   489  	TimeoutMS int64 `mapstructure:"timeout_ms"`
   490  }
   491  
   492  type HostCookie struct {
   493  	Domain             string `mapstructure:"domain"`
   494  	Family             string `mapstructure:"family"`
   495  	CookieName         string `mapstructure:"cookie_name"`
   496  	OptOutURL          string `mapstructure:"opt_out_url"`
   497  	OptInURL           string `mapstructure:"opt_in_url"`
   498  	MaxCookieSizeBytes int    `mapstructure:"max_cookie_size_bytes"`
   499  	OptOutCookie       Cookie `mapstructure:"optout_cookie"`
   500  	// Cookie timeout in days
   501  	TTL int64 `mapstructure:"ttl_days"`
   502  }
   503  
   504  func (cfg *HostCookie) TTLDuration() time.Duration {
   505  	return time.Duration(cfg.TTL) * time.Hour * 24
   506  }
   507  
   508  type RequestTimeoutHeaders struct {
   509  	RequestTimeInQueue    string `mapstructure:"request_time_in_queue"`
   510  	RequestTimeoutInQueue string `mapstructure:"request_timeout_in_queue"`
   511  }
   512  
   513  type Metrics struct {
   514  	Influxdb   InfluxMetrics     `mapstructure:"influxdb"`
   515  	Prometheus PrometheusMetrics `mapstructure:"prometheus"`
   516  	Disabled   DisabledMetrics   `mapstructure:"disabled_metrics"`
   517  }
   518  
   519  type DisabledMetrics struct {
   520  	// True if we want to stop collecting account-to-adapter metrics
   521  	AccountAdapterDetails bool `mapstructure:"account_adapter_details"`
   522  
   523  	// True if we want to stop collecting account debug request metrics
   524  	AccountDebug bool `mapstructure:"account_debug"`
   525  
   526  	// True if we want to stop collecting account stored respponses metrics
   527  	AccountStoredResponses bool `mapstructure:"account_stored_responses"`
   528  
   529  	// True if we don't want to collect metrics about the connections prebid
   530  	// server establishes with bidder servers such as the number of connections
   531  	// that were created or reused.
   532  	AdapterConnectionMetrics bool `mapstructure:"adapter_connections_metrics"`
   533  
   534  	// True if we don't want to collect the per adapter GDPR request blocked metric
   535  	AdapterGDPRRequestBlocked bool `mapstructure:"adapter_gdpr_request_blocked"`
   536  
   537  	// True if we want to stop collecting account modules metrics
   538  	AccountModulesMetrics bool `mapstructure:"account_modules_metrics"`
   539  }
   540  
   541  func (cfg *Metrics) validate(errs []error) []error {
   542  	return cfg.Prometheus.validate(errs)
   543  }
   544  
   545  type InfluxMetrics struct {
   546  	Host               string `mapstructure:"host"`
   547  	Database           string `mapstructure:"database"`
   548  	Measurement        string `mapstructure:"measurement"`
   549  	Username           string `mapstructure:"username"`
   550  	Password           string `mapstructure:"password"`
   551  	AlignTimestamps    bool   `mapstructure:"align_timestamps"`
   552  	MetricSendInterval int    `mapstructure:"metric_send_interval"`
   553  }
   554  
   555  type PrometheusMetrics struct {
   556  	Port             int    `mapstructure:"port"`
   557  	Namespace        string `mapstructure:"namespace"`
   558  	Subsystem        string `mapstructure:"subsystem"`
   559  	TimeoutMillisRaw int    `mapstructure:"timeout_ms"`
   560  }
   561  
   562  func (cfg *PrometheusMetrics) validate(errs []error) []error {
   563  	if cfg.Port > 0 && cfg.TimeoutMillisRaw <= 0 {
   564  		errs = append(errs, fmt.Errorf("metrics.prometheus.timeout_ms must be positive if metrics.prometheus.port is defined. Got timeout=%d and port=%d", cfg.TimeoutMillisRaw, cfg.Port))
   565  	}
   566  	return errs
   567  }
   568  
   569  func (m *PrometheusMetrics) Timeout() time.Duration {
   570  	return time.Duration(m.TimeoutMillisRaw) * time.Millisecond
   571  }
   572  
   573  // ExternalCache configures the externally accessible cache url.
   574  type ExternalCache struct {
   575  	Scheme string `mapstructure:"scheme"`
   576  	Host   string `mapstructure:"host"`
   577  	Path   string `mapstructure:"path"`
   578  }
   579  
   580  // Cache configures the url used internally by Prebid Server to communicate with Prebid Cache.
   581  type Cache struct {
   582  	Scheme string `mapstructure:"scheme"`
   583  	Host   string `mapstructure:"host"`
   584  	Query  string `mapstructure:"query"`
   585  
   586  	// A static timeout here is not ideal. This is a hack because we have some aggressive timelines for OpenRTB support.
   587  	// This value specifies how much time the prebid server host expects a call to prebid cache to take.
   588  	//
   589  	// OpenRTB allows the caller to specify the auction timeout. Prebid Server will subtract _this_ amount of time
   590  	// from the timeout it gives demand sources to respond.
   591  	//
   592  	// In reality, the cache response time will probably fluctuate with the traffic over time. Someday,
   593  	// this should be replaced by code which tracks the response time of recent cache calls and
   594  	// adjusts the time dynamically.
   595  	ExpectedTimeMillis int `mapstructure:"expected_millis"`
   596  
   597  	DefaultTTLs DefaultTTLs `mapstructure:"default_ttl_seconds"`
   598  }
   599  
   600  // Default TTLs to use to cache bids for different types of imps.
   601  type DefaultTTLs struct {
   602  	Banner int `mapstructure:"banner"`
   603  	Video  int `mapstructure:"video"`
   604  	Native int `mapstructure:"native"`
   605  	Audio  int `mapstructure:"audio"`
   606  }
   607  
   608  type Cookie struct {
   609  	Name  string `mapstructure:"name"`
   610  	Value string `mapstructure:"value"`
   611  }
   612  
   613  // AliasConfig will define the various source(s) or the default aliases
   614  // Currently only filesystem is supported, but keeping the config structure
   615  type DefReqConfig struct {
   616  	Type       string      `mapstructure:"type"`
   617  	FileSystem DefReqFiles `mapstructure:"file"`
   618  	AliasInfo  bool        `mapstructure:"alias_info"`
   619  }
   620  
   621  type DefReqFiles struct {
   622  	FileName string `mapstructure:"name"`
   623  }
   624  
   625  type Debug struct {
   626  	TimeoutNotification TimeoutNotification `mapstructure:"timeout_notification"`
   627  	OverrideToken       string              `mapstructure:"override_token"`
   628  }
   629  
   630  type Server struct {
   631  	ExternalUrl string
   632  	GvlID       int
   633  	DataCenter  string
   634  }
   635  
   636  func (server *Server) Empty() bool {
   637  	return server == nil || (server.DataCenter == "" && server.ExternalUrl == "" && server.GvlID == 0)
   638  }
   639  
   640  func (cfg *Debug) validate(errs []error) []error {
   641  	return cfg.TimeoutNotification.validate(errs)
   642  }
   643  
   644  type TimeoutNotification struct {
   645  	// Log timeout notifications in the application log
   646  	Log bool `mapstructure:"log"`
   647  	// Fraction of notifications to log
   648  	SamplingRate float32 `mapstructure:"sampling_rate"`
   649  	// Only log failures
   650  	FailOnly bool `mapstructure:"fail_only"`
   651  }
   652  
   653  type Validations struct {
   654  	BannerCreativeMaxSize string `mapstructure:"banner_creative_max_size" json:"banner_creative_max_size"`
   655  	SecureMarkup          string `mapstructure:"secure_markup" json:"secure_markup"`
   656  	MaxCreativeWidth      int64  `mapstructure:"max_creative_width" json:"max_creative_width"`
   657  	MaxCreativeHeight     int64  `mapstructure:"max_creative_height" json:"max_creative_height"`
   658  }
   659  
   660  const (
   661  	ValidationEnforce string = "enforce"
   662  	ValidationWarn    string = "warn"
   663  	ValidationSkip    string = "skip"
   664  )
   665  
   666  func (host *Validations) SetBannerCreativeMaxSize(account Validations) {
   667  	if len(account.BannerCreativeMaxSize) > 0 {
   668  		host.BannerCreativeMaxSize = account.BannerCreativeMaxSize
   669  	}
   670  }
   671  
   672  func (cfg *TimeoutNotification) validate(errs []error) []error {
   673  	if cfg.SamplingRate < 0.0 || cfg.SamplingRate > 1.0 {
   674  		errs = append(errs, fmt.Errorf("debug.timeout_notification.sampling_rate must be positive and not greater than 1.0. Got %f", cfg.SamplingRate))
   675  	}
   676  	return errs
   677  }
   678  
   679  // New uses viper to get our server configurations.
   680  func New(v *viper.Viper, bidderInfos BidderInfos, normalizeBidderName func(string) (openrtb_ext.BidderName, bool)) (*Configuration, error) {
   681  	var c Configuration
   682  	if err := v.Unmarshal(&c); err != nil {
   683  		return nil, fmt.Errorf("viper failed to unmarshal app config: %v", err)
   684  	}
   685  
   686  	if err := c.RequestValidation.Parse(); err != nil {
   687  		return nil, err
   688  	}
   689  
   690  	if err := isValidCookieSize(c.HostCookie.MaxCookieSizeBytes); err != nil {
   691  		glog.Fatal(fmt.Printf("Max cookie size %d cannot be less than %d \n", c.HostCookie.MaxCookieSizeBytes, MIN_COOKIE_SIZE_BYTES))
   692  		return nil, err
   693  	}
   694  
   695  	// Update account defaults and generate base json for patch
   696  	c.AccountDefaults.CacheTTL = c.CacheURL.DefaultTTLs // comment this out to set explicitly in config
   697  
   698  	// Update the deprecated and new events enabled values for account defaults.
   699  	c.AccountDefaults.EventsEnabled, c.AccountDefaults.Events.Enabled = migrateConfigEventsEnabled(c.AccountDefaults.EventsEnabled, c.AccountDefaults.Events.Enabled)
   700  
   701  	if err := c.MarshalAccountDefaults(); err != nil {
   702  		return nil, err
   703  	}
   704  
   705  	// To look for a request's publisher_id in the NonStandardPublishers list in
   706  	// O(1) time, we fill this hash table located in the NonStandardPublisherMap field of GDPR
   707  	var s struct{}
   708  	c.GDPR.NonStandardPublisherMap = make(map[string]struct{})
   709  	for i := 0; i < len(c.GDPR.NonStandardPublishers); i++ {
   710  		c.GDPR.NonStandardPublisherMap[c.GDPR.NonStandardPublishers[i]] = s
   711  	}
   712  
   713  	c.GDPR.EEACountriesMap = make(map[string]struct{}, len(c.GDPR.EEACountries))
   714  	for _, v := range c.GDPR.EEACountries {
   715  		c.GDPR.EEACountriesMap[v] = s
   716  	}
   717  
   718  	// for each purpose we capture a reference to the purpose config in a map for easy purpose config lookup
   719  	c.GDPR.TCF2.PurposeConfigs = map[consentconstants.Purpose]*TCF2Purpose{
   720  		1:  &c.GDPR.TCF2.Purpose1,
   721  		2:  &c.GDPR.TCF2.Purpose2,
   722  		3:  &c.GDPR.TCF2.Purpose3,
   723  		4:  &c.GDPR.TCF2.Purpose4,
   724  		5:  &c.GDPR.TCF2.Purpose5,
   725  		6:  &c.GDPR.TCF2.Purpose6,
   726  		7:  &c.GDPR.TCF2.Purpose7,
   727  		8:  &c.GDPR.TCF2.Purpose8,
   728  		9:  &c.GDPR.TCF2.Purpose9,
   729  		10: &c.GDPR.TCF2.Purpose10,
   730  	}
   731  
   732  	// As an alternative to performing several string compares per request, we set the integer representation of
   733  	// the enforcement algorithm on each purpose config
   734  	for _, pc := range c.GDPR.TCF2.PurposeConfigs {
   735  		if pc.EnforceAlgo == TCF2EnforceAlgoBasic {
   736  			pc.EnforceAlgoID = TCF2BasicEnforcement
   737  		} else {
   738  			pc.EnforceAlgoID = TCF2FullEnforcement
   739  		}
   740  	}
   741  
   742  	// To look for a purpose's vendor exceptions in O(1) time, for each purpose we fill this hash table with bidders
   743  	// located in the VendorExceptions field of the GDPR.TCF2.PurposeX struct defined in this file
   744  	for _, pc := range c.GDPR.TCF2.PurposeConfigs {
   745  		pc.VendorExceptionMap = make(map[openrtb_ext.BidderName]struct{})
   746  		for v := 0; v < len(pc.VendorExceptions); v++ {
   747  			bidderName := pc.VendorExceptions[v]
   748  			pc.VendorExceptionMap[bidderName] = struct{}{}
   749  		}
   750  	}
   751  
   752  	// To look for a special feature's vendor exceptions in O(1) time, we fill this hash table with bidders located in the
   753  	// VendorExceptions field of the GDPR.TCF2.SpecialFeature1 struct defined in this file
   754  	c.GDPR.TCF2.SpecialFeature1.VendorExceptionMap = make(map[openrtb_ext.BidderName]struct{})
   755  	for v := 0; v < len(c.GDPR.TCF2.SpecialFeature1.VendorExceptions); v++ {
   756  		bidderName := c.GDPR.TCF2.SpecialFeature1.VendorExceptions[v]
   757  		c.GDPR.TCF2.SpecialFeature1.VendorExceptionMap[bidderName] = struct{}{}
   758  	}
   759  
   760  	// To look for a request's app_id in O(1) time, we fill this hash table located in the
   761  	// the BlacklistedApps field of the Configuration struct defined in this file
   762  	c.BlacklistedAppMap = make(map[string]bool)
   763  	for i := 0; i < len(c.BlacklistedApps); i++ {
   764  		c.BlacklistedAppMap[c.BlacklistedApps[i]] = true
   765  	}
   766  
   767  	// To look for a request's account id in O(1) time, we fill this hash table located in the
   768  	// the BlacklistedAccts field of the Configuration struct defined in this file
   769  	c.BlacklistedAcctMap = make(map[string]bool)
   770  	for i := 0; i < len(c.BlacklistedAccts); i++ {
   771  		c.BlacklistedAcctMap[c.BlacklistedAccts[i]] = true
   772  	}
   773  
   774  	// Migrate combo stored request config to separate stored_reqs and amp stored_reqs configs.
   775  	resolvedStoredRequestsConfig(&c)
   776  
   777  	mergedBidderInfos, err := applyBidderInfoConfigOverrides(c.BidderInfos, bidderInfos, normalizeBidderName)
   778  	if err != nil {
   779  		return nil, err
   780  	}
   781  	c.BidderInfos = mergedBidderInfos
   782  
   783  	glog.Info("Logging the resolved configuration:")
   784  	logGeneral(reflect.ValueOf(c), "  \t")
   785  	if errs := c.validate(v); len(errs) > 0 {
   786  		return &c, errortypes.NewAggregateError("validation errors", errs)
   787  	}
   788  
   789  	return &c, nil
   790  }
   791  
   792  // MarshalAccountDefaults compiles AccountDefaults into the JSON format used for merge patch
   793  func (cfg *Configuration) MarshalAccountDefaults() error {
   794  	var err error
   795  	if cfg.accountDefaultsJSON, err = json.Marshal(cfg.AccountDefaults); err != nil {
   796  		glog.Warningf("converting %+v to json: %v", cfg.AccountDefaults, err)
   797  	}
   798  	return err
   799  }
   800  
   801  // AccountDefaultsJSON returns the precompiled JSON form of account_defaults
   802  func (cfg *Configuration) AccountDefaultsJSON() json.RawMessage {
   803  	return cfg.accountDefaultsJSON
   804  }
   805  
   806  // GetBaseURL allows for protocol relative URL if scheme is empty
   807  func (cfg *Cache) GetBaseURL() string {
   808  	cfg.Scheme = strings.ToLower(cfg.Scheme)
   809  	if strings.Contains(cfg.Scheme, "https") {
   810  		return fmt.Sprintf("https://%s", cfg.Host)
   811  	}
   812  	if strings.Contains(cfg.Scheme, "http") {
   813  		return fmt.Sprintf("http://%s", cfg.Host)
   814  	}
   815  	return fmt.Sprintf("//%s", cfg.Host)
   816  }
   817  
   818  func (cfg *Configuration) GetCachedAssetURL(uuid string) string {
   819  	return fmt.Sprintf("%s/cache?%s", cfg.CacheURL.GetBaseURL(), strings.Replace(cfg.CacheURL.Query, "%PBS_CACHE_UUID%", uuid, 1))
   820  }
   821  
   822  // Set the default config values for the viper object we are using.
   823  func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) {
   824  	if filename != "" {
   825  		v.SetConfigName(filename)
   826  		v.AddConfigPath(".")
   827  		v.AddConfigPath("/etc/config")
   828  	}
   829  
   830  	// Fixes #475: Some defaults will be set just so they are accessible via environment variables
   831  	// (basically so viper knows they exist)
   832  	v.SetDefault("external_url", "http://localhost:8000")
   833  	v.SetDefault("host", "")
   834  	v.SetDefault("port", 8000)
   835  	v.SetDefault("unix_socket_enable", false)              // boolean which decide if the socket-server will be started.
   836  	v.SetDefault("unix_socket_name", "prebid-server.sock") // path of the socket's file which must be listened.
   837  	v.SetDefault("admin_port", 6060)
   838  	v.SetDefault("garbage_collector_threshold", 0)
   839  	v.SetDefault("status_response", "")
   840  	v.SetDefault("datacenter", "")
   841  	v.SetDefault("auction_timeouts_ms.default", 0)
   842  	v.SetDefault("auction_timeouts_ms.max", 0)
   843  	v.SetDefault("cache.scheme", "")
   844  	v.SetDefault("cache.host", "")
   845  	v.SetDefault("cache.query", "")
   846  	v.SetDefault("cache.expected_millis", 10)
   847  	v.SetDefault("cache.default_ttl_seconds.banner", 0)
   848  	v.SetDefault("cache.default_ttl_seconds.video", 0)
   849  	v.SetDefault("cache.default_ttl_seconds.native", 0)
   850  	v.SetDefault("cache.default_ttl_seconds.audio", 0)
   851  	v.SetDefault("external_cache.scheme", "")
   852  	v.SetDefault("external_cache.host", "")
   853  	v.SetDefault("external_cache.path", "")
   854  	v.SetDefault("recaptcha_secret", "")
   855  	v.SetDefault("host_cookie.domain", "")
   856  	v.SetDefault("host_cookie.family", "")
   857  	v.SetDefault("host_cookie.cookie_name", "")
   858  	v.SetDefault("host_cookie.opt_out_url", "")
   859  	v.SetDefault("host_cookie.opt_in_url", "")
   860  	v.SetDefault("host_cookie.optout_cookie.name", "")
   861  	v.SetDefault("host_cookie.value", "")
   862  	v.SetDefault("host_cookie.ttl_days", 90)
   863  	v.SetDefault("host_cookie.max_cookie_size_bytes", 0)
   864  	v.SetDefault("host_schain_node", nil)
   865  	v.SetDefault("validations.banner_creative_max_size", ValidationSkip)
   866  	v.SetDefault("validations.secure_markup", ValidationSkip)
   867  	v.SetDefault("validations.max_creative_size.height", 0)
   868  	v.SetDefault("validations.max_creative_size.width", 0)
   869  	v.SetDefault("http_client.max_connections_per_host", 0) // unlimited
   870  	v.SetDefault("http_client.max_idle_connections", 400)
   871  	v.SetDefault("http_client.max_idle_connections_per_host", 10)
   872  	v.SetDefault("http_client.idle_connection_timeout_seconds", 60)
   873  	v.SetDefault("http_client_cache.max_connections_per_host", 0) // unlimited
   874  	v.SetDefault("http_client_cache.max_idle_connections", 10)
   875  	v.SetDefault("http_client_cache.max_idle_connections_per_host", 2)
   876  	v.SetDefault("http_client_cache.idle_connection_timeout_seconds", 60)
   877  	// no metrics configured by default (metrics{host|database|username|password})
   878  	v.SetDefault("metrics.disabled_metrics.account_adapter_details", false)
   879  	v.SetDefault("metrics.disabled_metrics.account_debug", true)
   880  	v.SetDefault("metrics.disabled_metrics.account_stored_responses", true)
   881  	v.SetDefault("metrics.disabled_metrics.adapter_connections_metrics", true)
   882  	v.SetDefault("metrics.disabled_metrics.adapter_gdpr_request_blocked", false)
   883  	v.SetDefault("metrics.influxdb.host", "")
   884  	v.SetDefault("metrics.influxdb.database", "")
   885  	v.SetDefault("metrics.influxdb.measurement", "")
   886  	v.SetDefault("metrics.influxdb.username", "")
   887  	v.SetDefault("metrics.influxdb.password", "")
   888  	v.SetDefault("metrics.influxdb.align_timestamps", false)
   889  	v.SetDefault("metrics.influxdb.metric_send_interval", 20)
   890  	v.SetDefault("metrics.prometheus.port", 0)
   891  	v.SetDefault("metrics.prometheus.namespace", "")
   892  	v.SetDefault("metrics.prometheus.subsystem", "")
   893  	v.SetDefault("metrics.prometheus.timeout_ms", 10000)
   894  	v.SetDefault("category_mapping.filesystem.enabled", true)
   895  	v.SetDefault("category_mapping.filesystem.directorypath", "./static/category-mapping")
   896  	v.SetDefault("category_mapping.http.endpoint", "")
   897  	v.SetDefault("stored_requests.filesystem.enabled", false)
   898  	v.SetDefault("stored_requests.filesystem.directorypath", "./stored_requests/data/by_id")
   899  	v.SetDefault("stored_requests.directorypath", "./stored_requests/data/by_id")
   900  	v.SetDefault("stored_requests.http.endpoint", "")
   901  	v.SetDefault("stored_requests.http.amp_endpoint", "")
   902  	v.SetDefault("stored_requests.in_memory_cache.type", "none")
   903  	v.SetDefault("stored_requests.in_memory_cache.ttl_seconds", 0)
   904  	v.SetDefault("stored_requests.in_memory_cache.request_cache_size_bytes", 0)
   905  	v.SetDefault("stored_requests.in_memory_cache.imp_cache_size_bytes", 0)
   906  	v.SetDefault("stored_requests.in_memory_cache.resp_cache_size_bytes", 0)
   907  	v.SetDefault("stored_requests.cache_events_api", false)
   908  	v.SetDefault("stored_requests.http_events.endpoint", "")
   909  	v.SetDefault("stored_requests.http_events.amp_endpoint", "")
   910  	v.SetDefault("stored_requests.http_events.refresh_rate_seconds", 0)
   911  	v.SetDefault("stored_requests.http_events.timeout_ms", 0)
   912  	// stored_video is short for stored_video_requests.
   913  	// PBS is not in the business of storing video content beyond the normal prebid cache system.
   914  	v.SetDefault("stored_video_req.filesystem.enabled", false)
   915  	v.SetDefault("stored_video_req.filesystem.directorypath", "")
   916  	v.SetDefault("stored_video_req.http.endpoint", "")
   917  	v.SetDefault("stored_video_req.in_memory_cache.type", "none")
   918  	v.SetDefault("stored_video_req.in_memory_cache.ttl_seconds", 0)
   919  	v.SetDefault("stored_video_req.in_memory_cache.request_cache_size_bytes", 0)
   920  	v.SetDefault("stored_video_req.in_memory_cache.imp_cache_size_bytes", 0)
   921  	v.SetDefault("stored_video_req.in_memory_cache.resp_cache_size_bytes", 0)
   922  	v.SetDefault("stored_video_req.cache_events.enabled", false)
   923  	v.SetDefault("stored_video_req.cache_events.endpoint", "")
   924  	v.SetDefault("stored_video_req.http_events.endpoint", "")
   925  	v.SetDefault("stored_video_req.http_events.refresh_rate_seconds", 0)
   926  	v.SetDefault("stored_video_req.http_events.timeout_ms", 0)
   927  	v.SetDefault("stored_responses.filesystem.enabled", false)
   928  	v.SetDefault("stored_responses.filesystem.directorypath", "")
   929  	v.SetDefault("stored_responses.http.endpoint", "")
   930  	v.SetDefault("stored_responses.in_memory_cache.type", "none")
   931  	v.SetDefault("stored_responses.in_memory_cache.ttl_seconds", 0)
   932  	v.SetDefault("stored_responses.in_memory_cache.request_cache_size_bytes", 0)
   933  	v.SetDefault("stored_responses.in_memory_cache.imp_cache_size_bytes", 0)
   934  	v.SetDefault("stored_responses.in_memory_cache.resp_cache_size_bytes", 0)
   935  	v.SetDefault("stored_responses.cache_events.enabled", false)
   936  	v.SetDefault("stored_responses.cache_events.endpoint", "")
   937  	v.SetDefault("stored_responses.http_events.endpoint", "")
   938  	v.SetDefault("stored_responses.http_events.refresh_rate_seconds", 0)
   939  	v.SetDefault("stored_responses.http_events.timeout_ms", 0)
   940  
   941  	v.SetDefault("vtrack.timeout_ms", 2000)
   942  	v.SetDefault("vtrack.allow_unknown_bidder", true)
   943  	v.SetDefault("vtrack.enabled", true)
   944  
   945  	v.SetDefault("event.timeout_ms", 1000)
   946  
   947  	v.SetDefault("user_sync.priority_groups", [][]string{})
   948  
   949  	v.SetDefault("accounts.filesystem.enabled", false)
   950  	v.SetDefault("accounts.filesystem.directorypath", "./stored_requests/data/by_id")
   951  	v.SetDefault("accounts.in_memory_cache.type", "none")
   952  
   953  	v.BindEnv("user_sync.external_url")
   954  	v.BindEnv("user_sync.coop_sync.default")
   955  
   956  	// some adapters append the user id to the end of the redirect url instead of using
   957  	// macro substitution. it is important for the uid to be the last query parameter.
   958  	v.SetDefault("user_sync.redirect_url", "{{.ExternalURL}}/setuid?bidder={{.SyncerKey}}&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&f={{.SyncType}}&uid={{.UserMacro}}")
   959  
   960  	v.SetDefault("max_request_size", 1024*256)
   961  	v.SetDefault("analytics.file.filename", "")
   962  	v.SetDefault("analytics.pubstack.endpoint", "https://s2s.pbstck.com/v1")
   963  	v.SetDefault("analytics.pubstack.scopeid", "change-me")
   964  	v.SetDefault("analytics.pubstack.enabled", false)
   965  	v.SetDefault("analytics.pubstack.configuration_refresh_delay", "2h")
   966  	v.SetDefault("analytics.pubstack.buffers.size", "2MB")
   967  	v.SetDefault("analytics.pubstack.buffers.count", 100)
   968  	v.SetDefault("analytics.pubstack.buffers.timeout", "900s")
   969  	v.SetDefault("amp_timeout_adjustment_ms", 0)
   970  	v.BindEnv("gdpr.default_value")
   971  	v.SetDefault("gdpr.enabled", true)
   972  	v.SetDefault("gdpr.host_vendor_id", 0)
   973  	v.SetDefault("gdpr.timeouts_ms.init_vendorlist_fetches", 0)
   974  	v.SetDefault("gdpr.timeouts_ms.active_vendorlist_fetch", 0)
   975  	v.SetDefault("gdpr.non_standard_publishers", []string{""})
   976  	v.SetDefault("gdpr.tcf2.enabled", true)
   977  	v.SetDefault("gdpr.tcf2.purpose1.enforce_vendors", true)
   978  	v.SetDefault("gdpr.tcf2.purpose2.enforce_vendors", true)
   979  	v.SetDefault("gdpr.tcf2.purpose3.enforce_vendors", true)
   980  	v.SetDefault("gdpr.tcf2.purpose4.enforce_vendors", true)
   981  	v.SetDefault("gdpr.tcf2.purpose5.enforce_vendors", true)
   982  	v.SetDefault("gdpr.tcf2.purpose6.enforce_vendors", true)
   983  	v.SetDefault("gdpr.tcf2.purpose7.enforce_vendors", true)
   984  	v.SetDefault("gdpr.tcf2.purpose8.enforce_vendors", true)
   985  	v.SetDefault("gdpr.tcf2.purpose9.enforce_vendors", true)
   986  	v.SetDefault("gdpr.tcf2.purpose10.enforce_vendors", true)
   987  	v.SetDefault("gdpr.tcf2.purpose1.vendor_exceptions", []openrtb_ext.BidderName{})
   988  	v.SetDefault("gdpr.tcf2.purpose2.vendor_exceptions", []openrtb_ext.BidderName{})
   989  	v.SetDefault("gdpr.tcf2.purpose3.vendor_exceptions", []openrtb_ext.BidderName{})
   990  	v.SetDefault("gdpr.tcf2.purpose4.vendor_exceptions", []openrtb_ext.BidderName{})
   991  	v.SetDefault("gdpr.tcf2.purpose5.vendor_exceptions", []openrtb_ext.BidderName{})
   992  	v.SetDefault("gdpr.tcf2.purpose6.vendor_exceptions", []openrtb_ext.BidderName{})
   993  	v.SetDefault("gdpr.tcf2.purpose7.vendor_exceptions", []openrtb_ext.BidderName{})
   994  	v.SetDefault("gdpr.tcf2.purpose8.vendor_exceptions", []openrtb_ext.BidderName{})
   995  	v.SetDefault("gdpr.tcf2.purpose9.vendor_exceptions", []openrtb_ext.BidderName{})
   996  	v.SetDefault("gdpr.tcf2.purpose10.vendor_exceptions", []openrtb_ext.BidderName{})
   997  	v.SetDefault("gdpr.amp_exception", false)
   998  	v.SetDefault("gdpr.eea_countries", []string{"ALA", "AUT", "BEL", "BGR", "HRV", "CYP", "CZE", "DNK", "EST",
   999  		"FIN", "FRA", "GUF", "DEU", "GIB", "GRC", "GLP", "GGY", "HUN", "ISL", "IRL", "IMN", "ITA", "JEY", "LVA",
  1000  		"LIE", "LTU", "LUX", "MLT", "MTQ", "MYT", "NLD", "NOR", "POL", "PRT", "REU", "ROU", "BLM", "MAF", "SPM",
  1001  		"SVK", "SVN", "ESP", "SWE", "GBR"})
  1002  	v.SetDefault("ccpa.enforce", false)
  1003  	v.SetDefault("lmt.enforce", true)
  1004  	v.SetDefault("currency_converter.fetch_url", "https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json")
  1005  	v.SetDefault("currency_converter.fetch_interval_seconds", 1800) // fetch currency rates every 30 minutes
  1006  	v.SetDefault("currency_converter.stale_rates_seconds", 0)
  1007  	v.SetDefault("default_request.type", "")
  1008  	v.SetDefault("default_request.file.name", "")
  1009  	v.SetDefault("default_request.alias_info", false)
  1010  	v.SetDefault("blacklisted_apps", []string{""})
  1011  	v.SetDefault("blacklisted_accts", []string{""})
  1012  	v.SetDefault("account_required", false)
  1013  	v.SetDefault("account_defaults.disabled", false)
  1014  	v.SetDefault("account_defaults.debug_allow", true)
  1015  	v.SetDefault("account_defaults.price_floors.enabled", false)
  1016  	v.SetDefault("account_defaults.price_floors.enforce_floors_rate", 100)
  1017  	v.SetDefault("account_defaults.price_floors.adjust_for_bid_adjustment", true)
  1018  	v.SetDefault("account_defaults.price_floors.enforce_deal_floors", false)
  1019  	v.SetDefault("account_defaults.price_floors.use_dynamic_data", false)
  1020  	v.SetDefault("account_defaults.price_floors.max_rules", 100)
  1021  	v.SetDefault("account_defaults.price_floors.max_schema_dims", 3)
  1022  	v.SetDefault("account_defaults.events_enabled", false)
  1023  	v.SetDefault("account_defaults.privacy.ipv6.anon_keep_bits", 56)
  1024  	v.SetDefault("account_defaults.privacy.ipv4.anon_keep_bits", 24)
  1025  
  1026  	v.SetDefault("compression.response.enable_gzip", false)
  1027  	v.SetDefault("compression.request.enable_gzip", false)
  1028  
  1029  	v.SetDefault("certificates_file", "")
  1030  	v.SetDefault("auto_gen_source_tid", true)
  1031  	v.SetDefault("generate_bid_id", false)
  1032  	v.SetDefault("generate_request_id", false)
  1033  
  1034  	v.SetDefault("request_timeout_headers.request_time_in_queue", "")
  1035  	v.SetDefault("request_timeout_headers.request_timeout_in_queue", "")
  1036  
  1037  	v.SetDefault("debug.timeout_notification.log", false)
  1038  	v.SetDefault("debug.timeout_notification.sampling_rate", 0.0)
  1039  	v.SetDefault("debug.timeout_notification.fail_only", false)
  1040  	v.SetDefault("debug.override_token", "")
  1041  
  1042  	v.SetDefault("tmax_adjustments.enabled", false)
  1043  	v.SetDefault("tmax_adjustments.bidder_response_duration_min_ms", 0)
  1044  	v.SetDefault("tmax_adjustments.bidder_network_latency_buffer_ms", 0)
  1045  	v.SetDefault("tmax_adjustments.pbs_response_preparation_duration_ms", 0)
  1046  
  1047  	/* IPv4
  1048  	/*  Site Local: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
  1049  	/*  Link Local: 169.254.0.0/16
  1050  	/*  Loopback:   127.0.0.0/8
  1051  	/*
  1052  	/* IPv6
  1053  	/*  Loopback:      ::1/128
  1054  	/*  Documentation: 2001:db8::/32
  1055  	/*  Unique Local:  fc00::/7
  1056  	/*  Link Local:    fe80::/10
  1057  	/*  Multicast:     ff00::/8
  1058  	*/
  1059  	v.SetDefault("request_validation.ipv4_private_networks", []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "169.254.0.0/16", "127.0.0.0/8"})
  1060  	v.SetDefault("request_validation.ipv6_private_networks", []string{"::1/128", "fc00::/7", "fe80::/10", "ff00::/8", "2001:db8::/32"})
  1061  
  1062  	bindDatabaseEnvVars(v)
  1063  
  1064  	// Set environment variable support:
  1065  	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
  1066  	v.SetTypeByDefaultValue(true)
  1067  	v.SetEnvPrefix("PBS")
  1068  	v.AutomaticEnv()
  1069  	v.ReadInConfig()
  1070  
  1071  	// Migrate config settings to maintain compatibility with old configs
  1072  	migrateConfig(v)
  1073  	migrateConfigPurposeOneTreatment(v)
  1074  	migrateConfigSpecialFeature1(v)
  1075  	migrateConfigTCF2PurposeFlags(v)
  1076  	migrateConfigDatabaseConnection(v)
  1077  	migrateConfigCompression(v)
  1078  
  1079  	// These defaults must be set after the migrate functions because those functions look for the presence of these
  1080  	// config fields and there isn't a way to detect presence of a config field using the viper package if a default
  1081  	// is set. Viper IsSet and Get functions consider default values.
  1082  	v.SetDefault("gdpr.tcf2.purpose1.enabled", true)
  1083  	v.SetDefault("gdpr.tcf2.purpose2.enabled", true)
  1084  	v.SetDefault("gdpr.tcf2.purpose3.enabled", true)
  1085  	v.SetDefault("gdpr.tcf2.purpose4.enabled", true)
  1086  	v.SetDefault("gdpr.tcf2.purpose5.enabled", true)
  1087  	v.SetDefault("gdpr.tcf2.purpose6.enabled", true)
  1088  	v.SetDefault("gdpr.tcf2.purpose7.enabled", true)
  1089  	v.SetDefault("gdpr.tcf2.purpose8.enabled", true)
  1090  	v.SetDefault("gdpr.tcf2.purpose9.enabled", true)
  1091  	v.SetDefault("gdpr.tcf2.purpose10.enabled", true)
  1092  	v.SetDefault("gdpr.tcf2.purpose1.enforce_algo", TCF2EnforceAlgoFull)
  1093  	v.SetDefault("gdpr.tcf2.purpose2.enforce_algo", TCF2EnforceAlgoFull)
  1094  	v.SetDefault("gdpr.tcf2.purpose3.enforce_algo", TCF2EnforceAlgoFull)
  1095  	v.SetDefault("gdpr.tcf2.purpose4.enforce_algo", TCF2EnforceAlgoFull)
  1096  	v.SetDefault("gdpr.tcf2.purpose5.enforce_algo", TCF2EnforceAlgoFull)
  1097  	v.SetDefault("gdpr.tcf2.purpose6.enforce_algo", TCF2EnforceAlgoFull)
  1098  	v.SetDefault("gdpr.tcf2.purpose7.enforce_algo", TCF2EnforceAlgoFull)
  1099  	v.SetDefault("gdpr.tcf2.purpose8.enforce_algo", TCF2EnforceAlgoFull)
  1100  	v.SetDefault("gdpr.tcf2.purpose9.enforce_algo", TCF2EnforceAlgoFull)
  1101  	v.SetDefault("gdpr.tcf2.purpose10.enforce_algo", TCF2EnforceAlgoFull)
  1102  	v.SetDefault("gdpr.tcf2.purpose1.enforce_purpose", true)
  1103  	v.SetDefault("gdpr.tcf2.purpose2.enforce_purpose", true)
  1104  	v.SetDefault("gdpr.tcf2.purpose3.enforce_purpose", true)
  1105  	v.SetDefault("gdpr.tcf2.purpose4.enforce_purpose", true)
  1106  	v.SetDefault("gdpr.tcf2.purpose5.enforce_purpose", true)
  1107  	v.SetDefault("gdpr.tcf2.purpose6.enforce_purpose", true)
  1108  	v.SetDefault("gdpr.tcf2.purpose7.enforce_purpose", true)
  1109  	v.SetDefault("gdpr.tcf2.purpose8.enforce_purpose", true)
  1110  	v.SetDefault("gdpr.tcf2.purpose9.enforce_purpose", true)
  1111  	v.SetDefault("gdpr.tcf2.purpose10.enforce_purpose", true)
  1112  	v.SetDefault("gdpr.tcf2.purpose_one_treatment.enabled", true)
  1113  	v.SetDefault("gdpr.tcf2.purpose_one_treatment.access_allowed", true)
  1114  	v.SetDefault("gdpr.tcf2.special_feature1.enforce", true)
  1115  	v.SetDefault("gdpr.tcf2.special_feature1.vendor_exceptions", []openrtb_ext.BidderName{})
  1116  	v.SetDefault("price_floors.enabled", false)
  1117  
  1118  	v.SetDefault("enable_gzip", false)
  1119  
  1120  	// Defaults for account_defaults.events.default_url
  1121  	v.SetDefault("account_defaults.events.default_url", "https://PBS_HOST/event?t=##PBS-EVENTTYPE##&vtype=##PBS-VASTEVENT##&b=##PBS-BIDID##&f=i&a=##PBS-ACCOUNTID##&ts=##PBS-TIMESTAMP##&bidder=##PBS-BIDDER##&int=##PBS-INTEGRATION##&mt=##PBS-MEDIATYPE##&ch=##PBS-CHANNEL##&aid=##PBS-AUCTIONID##&l=##PBS-LINEID##")
  1122  
  1123  	v.SetDefault("experiment.adscert.mode", "off")
  1124  	v.SetDefault("experiment.adscert.inprocess.origin", "")
  1125  	v.SetDefault("experiment.adscert.inprocess.key", "")
  1126  	v.SetDefault("experiment.adscert.inprocess.domain_check_interval_seconds", 30)
  1127  	v.SetDefault("experiment.adscert.inprocess.domain_renewal_interval_seconds", 30)
  1128  	v.SetDefault("experiment.adscert.remote.url", "")
  1129  	v.SetDefault("experiment.adscert.remote.signing_timeout_ms", 5)
  1130  
  1131  	v.SetDefault("hooks.enabled", false)
  1132  
  1133  	for bidderName := range bidderInfos {
  1134  		setBidderDefaults(v, strings.ToLower(bidderName))
  1135  	}
  1136  }
  1137  
  1138  func migrateConfig(v *viper.Viper) {
  1139  	// if stored_requests.filesystem is not a map in conf file as expected from defaults,
  1140  	// means we have old-style settings; migrate them to new filesystem map to avoid breaking viper
  1141  	if _, ok := v.Get("stored_requests.filesystem").(map[string]interface{}); !ok {
  1142  		glog.Warning("stored_requests.filesystem should be changed to stored_requests.filesystem.enabled")
  1143  		glog.Warning("stored_requests.directorypath should be changed to stored_requests.filesystem.directorypath")
  1144  		m := v.GetStringMap("stored_requests.filesystem")
  1145  		m["enabled"] = v.GetBool("stored_requests.filesystem")
  1146  		m["directorypath"] = v.GetString("stored_requests.directorypath")
  1147  		v.Set("stored_requests.filesystem", m)
  1148  	}
  1149  }
  1150  
  1151  func migrateConfigCompression(v *viper.Viper) {
  1152  	oldField := "enable_gzip"
  1153  	newField := "compression.response.enable_gzip"
  1154  	if v.IsSet(oldField) {
  1155  		oldConfig := v.GetBool(oldField)
  1156  		if v.IsSet(newField) {
  1157  			glog.Warningf("using %s and ignoring deprecated %s", newField, oldField)
  1158  		} else {
  1159  			glog.Warningf("%s is deprecated and should be changed to %s", oldField, newField)
  1160  			v.Set(newField, oldConfig)
  1161  		}
  1162  	}
  1163  }
  1164  
  1165  func migrateConfigPurposeOneTreatment(v *viper.Viper) {
  1166  	if oldConfig, ok := v.Get("gdpr.tcf2.purpose_one_treatement").(map[string]interface{}); ok {
  1167  		if v.IsSet("gdpr.tcf2.purpose_one_treatment") {
  1168  			glog.Warning("using gdpr.tcf2.purpose_one_treatment and ignoring deprecated gdpr.tcf2.purpose_one_treatement")
  1169  		} else {
  1170  			glog.Warning("gdpr.tcf2.purpose_one_treatement.enabled should be changed to gdpr.tcf2.purpose_one_treatment.enabled")
  1171  			glog.Warning("gdpr.tcf2.purpose_one_treatement.access_allowed should be changed to gdpr.tcf2.purpose_one_treatment.access_allowed")
  1172  			v.Set("gdpr.tcf2.purpose_one_treatment", oldConfig)
  1173  		}
  1174  	}
  1175  }
  1176  
  1177  func migrateConfigSpecialFeature1(v *viper.Viper) {
  1178  	if oldConfig, ok := v.Get("gdpr.tcf2.special_purpose1").(map[string]interface{}); ok {
  1179  		if v.IsSet("gdpr.tcf2.special_feature1") {
  1180  			glog.Warning("using gdpr.tcf2.special_feature1 and ignoring deprecated gdpr.tcf2.special_purpose1")
  1181  		} else {
  1182  			glog.Warning("gdpr.tcf2.special_purpose1.enabled is deprecated and should be changed to gdpr.tcf2.special_feature1.enforce")
  1183  			glog.Warning("gdpr.tcf2.special_purpose1.vendor_exceptions is deprecated and should be changed to gdpr.tcf2.special_feature1.vendor_exceptions")
  1184  			v.Set("gdpr.tcf2.special_feature1.enforce", oldConfig["enabled"])
  1185  			v.Set("gdpr.tcf2.special_feature1.vendor_exceptions", oldConfig["vendor_exceptions"])
  1186  		}
  1187  	}
  1188  }
  1189  
  1190  func migrateConfigTCF2PurposeFlags(v *viper.Viper) {
  1191  	migrateConfigTCF2EnforcePurposeFlags(v)
  1192  	migrateConfigTCF2PurposeEnabledFlags(v)
  1193  }
  1194  
  1195  func migrateConfigTCF2EnforcePurposeFlags(v *viper.Viper) {
  1196  	for i := 1; i <= 10; i++ {
  1197  		algoField := fmt.Sprintf("gdpr.tcf2.purpose%d.enforce_algo", i)
  1198  		purposeField := fmt.Sprintf("gdpr.tcf2.purpose%d.enforce_purpose", i)
  1199  
  1200  		if !v.IsSet(purposeField) {
  1201  			continue
  1202  		}
  1203  		if _, ok := v.Get(purposeField).(string); !ok {
  1204  			continue
  1205  		}
  1206  		if v.IsSet(algoField) {
  1207  			glog.Warningf("using %s and ignoring deprecated %s string type", algoField, purposeField)
  1208  		} else {
  1209  			v.Set(algoField, TCF2EnforceAlgoFull)
  1210  
  1211  			glog.Warningf("setting %s to \"%s\" based on deprecated %s string type \"%s\"", algoField, TCF2EnforceAlgoFull, purposeField, v.GetString(purposeField))
  1212  		}
  1213  
  1214  		oldPurposeFieldValue := v.GetString(purposeField)
  1215  		newPurposeFieldValue := "false"
  1216  		if oldPurposeFieldValue == TCF2EnforceAlgoFull {
  1217  			newPurposeFieldValue = "true"
  1218  		}
  1219  
  1220  		glog.Warningf("converting %s from string \"%s\" to bool \"%s\"; string type is deprecated", purposeField, oldPurposeFieldValue, newPurposeFieldValue)
  1221  		v.Set(purposeField, newPurposeFieldValue)
  1222  	}
  1223  }
  1224  
  1225  func migrateConfigTCF2PurposeEnabledFlags(v *viper.Viper) {
  1226  	for i := 1; i <= 10; i++ {
  1227  		oldField := fmt.Sprintf("gdpr.tcf2.purpose%d.enabled", i)
  1228  		newField := fmt.Sprintf("gdpr.tcf2.purpose%d.enforce_purpose", i)
  1229  
  1230  		if v.IsSet(oldField) {
  1231  			oldConfig := v.GetBool(oldField)
  1232  			if v.IsSet(newField) {
  1233  				glog.Warningf("using %s and ignoring deprecated %s", newField, oldField)
  1234  			} else {
  1235  				glog.Warningf("%s is deprecated and should be changed to %s", oldField, newField)
  1236  				v.Set(newField, oldConfig)
  1237  			}
  1238  		}
  1239  
  1240  		if v.IsSet(newField) {
  1241  			v.Set(oldField, strconv.FormatBool(v.GetBool(newField)))
  1242  		}
  1243  	}
  1244  }
  1245  
  1246  func migrateConfigDatabaseConnection(v *viper.Viper) {
  1247  
  1248  	type QueryParamMigration struct {
  1249  		old string
  1250  		new string
  1251  	}
  1252  
  1253  	type QueryMigration struct {
  1254  		name   string
  1255  		params []QueryParamMigration
  1256  	}
  1257  
  1258  	type Migration struct {
  1259  		old             string
  1260  		new             string
  1261  		fields          []string
  1262  		queryMigrations []QueryMigration
  1263  	}
  1264  
  1265  	queryParamMigrations := struct {
  1266  		RequestIdList QueryParamMigration
  1267  		ImpIdList     QueryParamMigration
  1268  		IdList        QueryParamMigration
  1269  		LastUpdated   QueryParamMigration
  1270  	}{
  1271  		RequestIdList: QueryParamMigration{
  1272  			old: "%REQUEST_ID_LIST%",
  1273  			new: "$REQUEST_ID_LIST",
  1274  		},
  1275  		ImpIdList: QueryParamMigration{
  1276  			old: "%IMP_ID_LIST%",
  1277  			new: "$IMP_ID_LIST",
  1278  		},
  1279  		IdList: QueryParamMigration{
  1280  			old: "%ID_LIST%",
  1281  			new: "$ID_LIST",
  1282  		},
  1283  		LastUpdated: QueryParamMigration{
  1284  			old: "$1",
  1285  			new: "$LAST_UPDATED",
  1286  		},
  1287  	}
  1288  
  1289  	queryMigrations := []QueryMigration{
  1290  		{
  1291  			name:   "fetcher.query",
  1292  			params: []QueryParamMigration{queryParamMigrations.RequestIdList, queryParamMigrations.ImpIdList, queryParamMigrations.IdList},
  1293  		},
  1294  		{
  1295  			name:   "fetcher.amp_query",
  1296  			params: []QueryParamMigration{queryParamMigrations.RequestIdList, queryParamMigrations.ImpIdList, queryParamMigrations.IdList},
  1297  		},
  1298  		{
  1299  			name:   "poll_for_updates.query",
  1300  			params: []QueryParamMigration{queryParamMigrations.LastUpdated},
  1301  		},
  1302  		{
  1303  			name:   "poll_for_updates.amp_query",
  1304  			params: []QueryParamMigration{queryParamMigrations.LastUpdated},
  1305  		},
  1306  	}
  1307  
  1308  	migrations := []Migration{
  1309  		{
  1310  			old: "stored_requests.postgres",
  1311  			new: "stored_requests.database",
  1312  			fields: []string{
  1313  				"connection.dbname",
  1314  				"connection.host",
  1315  				"connection.port",
  1316  				"connection.user",
  1317  				"connection.password",
  1318  				"fetcher.query",
  1319  				"fetcher.amp_query",
  1320  				"initialize_caches.timeout_ms",
  1321  				"initialize_caches.query",
  1322  				"initialize_caches.amp_query",
  1323  				"poll_for_updates.refresh_rate_seconds",
  1324  				"poll_for_updates.timeout_ms",
  1325  				"poll_for_updates.query",
  1326  				"poll_for_updates.amp_query",
  1327  			},
  1328  			queryMigrations: queryMigrations,
  1329  		},
  1330  		{
  1331  			old: "stored_video_req.postgres",
  1332  			new: "stored_video_req.database",
  1333  			fields: []string{
  1334  				"connection.dbname",
  1335  				"connection.host",
  1336  				"connection.port",
  1337  				"connection.user",
  1338  				"connection.password",
  1339  				"fetcher.query",
  1340  				"initialize_caches.timeout_ms",
  1341  				"initialize_caches.query",
  1342  				"poll_for_updates.refresh_rate_seconds",
  1343  				"poll_for_updates.timeout_ms",
  1344  				"poll_for_updates.query",
  1345  			},
  1346  			queryMigrations: queryMigrations,
  1347  		},
  1348  		{
  1349  			old: "stored_responses.postgres",
  1350  			new: "stored_responses.database",
  1351  			fields: []string{
  1352  				"connection.dbname",
  1353  				"connection.host",
  1354  				"connection.port",
  1355  				"connection.user",
  1356  				"connection.password",
  1357  				"fetcher.query",
  1358  				"initialize_caches.timeout_ms",
  1359  				"initialize_caches.query",
  1360  				"poll_for_updates.refresh_rate_seconds",
  1361  				"poll_for_updates.timeout_ms",
  1362  				"poll_for_updates.query",
  1363  			},
  1364  			queryMigrations: queryMigrations,
  1365  		},
  1366  	}
  1367  
  1368  	for _, migration := range migrations {
  1369  		driverField := migration.new + ".connection.driver"
  1370  		newConfigInfoPresent := isConfigInfoPresent(v, migration.new, migration.fields)
  1371  		oldConfigInfoPresent := isConfigInfoPresent(v, migration.old, migration.fields)
  1372  
  1373  		if !newConfigInfoPresent && oldConfigInfoPresent {
  1374  			glog.Warning(fmt.Sprintf("%s is deprecated and should be changed to %s", migration.old, migration.new))
  1375  			glog.Warning(fmt.Sprintf("%s is not set, using default (postgres)", driverField))
  1376  			v.Set(driverField, "postgres")
  1377  
  1378  			for _, field := range migration.fields {
  1379  				oldField := migration.old + "." + field
  1380  				newField := migration.new + "." + field
  1381  				if v.IsSet(oldField) {
  1382  					glog.Warning(fmt.Sprintf("%s is deprecated and should be changed to %s", oldField, newField))
  1383  					v.Set(newField, v.Get(oldField))
  1384  				}
  1385  			}
  1386  
  1387  			for _, queryMigration := range migration.queryMigrations {
  1388  				oldQueryField := migration.old + "." + queryMigration.name
  1389  				newQueryField := migration.new + "." + queryMigration.name
  1390  				queryString := v.GetString(oldQueryField)
  1391  				for _, queryParam := range queryMigration.params {
  1392  					if strings.Contains(queryString, queryParam.old) {
  1393  						glog.Warning(fmt.Sprintf("Query param %s for %s is deprecated and should be changed to %s", queryParam.old, oldQueryField, queryParam.new))
  1394  						queryString = strings.ReplaceAll(queryString, queryParam.old, queryParam.new)
  1395  						v.Set(newQueryField, queryString)
  1396  					}
  1397  				}
  1398  			}
  1399  		} else if newConfigInfoPresent && oldConfigInfoPresent {
  1400  			glog.Warning(fmt.Sprintf("using %s and ignoring deprecated %s", migration.new, migration.old))
  1401  
  1402  			for _, field := range migration.fields {
  1403  				oldField := migration.old + "." + field
  1404  				newField := migration.new + "." + field
  1405  				if v.IsSet(oldField) {
  1406  					glog.Warning(fmt.Sprintf("using %s and ignoring deprecated %s", newField, oldField))
  1407  				}
  1408  			}
  1409  		}
  1410  	}
  1411  }
  1412  
  1413  // migrateConfigEventsEnabled is responsible for ensuring backward compatibility of events_enabled field.
  1414  // This function copies the value of newField "events.enabled" and set it to the oldField "events_enabled".
  1415  // This is necessary to achieve the desired order of precedence favoring the account values over the host values
  1416  // given the account fetcher JSON merge mechanics.
  1417  func migrateConfigEventsEnabled(oldFieldValue *bool, newFieldValue *bool) (updatedOldFieldValue, updatedNewFieldValue *bool) {
  1418  	newField := "account_defaults.events.enabled"
  1419  	oldField := "account_defaults.events_enabled"
  1420  
  1421  	updatedOldFieldValue = oldFieldValue
  1422  	if oldFieldValue != nil {
  1423  		glog.Warningf("%s is deprecated and should be changed to %s", oldField, newField)
  1424  	}
  1425  	if newFieldValue != nil {
  1426  		if oldFieldValue != nil {
  1427  			glog.Warningf("using %s and ignoring deprecated %s", newField, oldField)
  1428  		}
  1429  		updatedOldFieldValue = ptrutil.ToPtr(*newFieldValue)
  1430  	}
  1431  
  1432  	return updatedOldFieldValue, nil
  1433  }
  1434  
  1435  func isConfigInfoPresent(v *viper.Viper, prefix string, fields []string) bool {
  1436  	prefix = prefix + "."
  1437  	for _, field := range fields {
  1438  		fieldName := prefix + field
  1439  		if v.IsSet(fieldName) {
  1440  			return true
  1441  		}
  1442  	}
  1443  	return false
  1444  }
  1445  
  1446  func bindDatabaseEnvVars(v *viper.Viper) {
  1447  	v.BindEnv("stored_requests.database.connection.driver")
  1448  	v.BindEnv("stored_requests.database.connection.dbname")
  1449  	v.BindEnv("stored_requests.database.connection.host")
  1450  	v.BindEnv("stored_requests.database.connection.port")
  1451  	v.BindEnv("stored_requests.database.connection.user")
  1452  	v.BindEnv("stored_requests.database.connection.password")
  1453  	v.BindEnv("stored_requests.database.connection.query_string")
  1454  	v.BindEnv("stored_requests.database.connection.tls.root_cert")
  1455  	v.BindEnv("stored_requests.database.connection.tls.client_cert")
  1456  	v.BindEnv("stored_requests.database.connection.tls.client_key")
  1457  	v.BindEnv("stored_requests.database.fetcher.query")
  1458  	v.BindEnv("stored_requests.database.fetcher.amp_query")
  1459  	v.BindEnv("stored_requests.database.initialize_caches.timeout_ms")
  1460  	v.BindEnv("stored_requests.database.initialize_caches.query")
  1461  	v.BindEnv("stored_requests.database.initialize_caches.amp_query")
  1462  	v.BindEnv("stored_requests.database.poll_for_updates.refresh_rate_seconds")
  1463  	v.BindEnv("stored_requests.database.poll_for_updates.timeout_ms")
  1464  	v.BindEnv("stored_requests.database.poll_for_updates.query")
  1465  	v.BindEnv("stored_requests.database.poll_for_updates.amp_query")
  1466  	v.BindEnv("stored_video_req.database.connection.driver")
  1467  	v.BindEnv("stored_video_req.database.connection.dbname")
  1468  	v.BindEnv("stored_video_req.database.connection.host")
  1469  	v.BindEnv("stored_video_req.database.connection.port")
  1470  	v.BindEnv("stored_video_req.database.connection.user")
  1471  	v.BindEnv("stored_video_req.database.connection.password")
  1472  	v.BindEnv("stored_video_req.database.connection.query_string")
  1473  	v.BindEnv("stored_video_req.database.connection.tls.root_cert")
  1474  	v.BindEnv("stored_video_req.database.connection.tls.client_cert")
  1475  	v.BindEnv("stored_video_req.database.connection.tls.client_key")
  1476  	v.BindEnv("stored_video_req.database.fetcher.query")
  1477  	v.BindEnv("stored_video_req.database.initialize_caches.timeout_ms")
  1478  	v.BindEnv("stored_video_req.database.initialize_caches.query")
  1479  	v.BindEnv("stored_video_req.database.poll_for_updates.refresh_rate_seconds")
  1480  	v.BindEnv("stored_video_req.database.poll_for_updates.timeout_ms")
  1481  	v.BindEnv("stored_video_req.database.poll_for_updates.query")
  1482  	v.BindEnv("stored_responses.database.connection.driver")
  1483  	v.BindEnv("stored_responses.database.connection.dbname")
  1484  	v.BindEnv("stored_responses.database.connection.host")
  1485  	v.BindEnv("stored_responses.database.connection.port")
  1486  	v.BindEnv("stored_responses.database.connection.user")
  1487  	v.BindEnv("stored_responses.database.connection.password")
  1488  	v.BindEnv("stored_responses.database.connection.query_string")
  1489  	v.BindEnv("stored_responses.database.connection.tls.root_cert")
  1490  	v.BindEnv("stored_responses.database.connection.tls.client_cert")
  1491  	v.BindEnv("stored_responses.database.connection.tls.client_key")
  1492  	v.BindEnv("stored_responses.database.fetcher.query")
  1493  	v.BindEnv("stored_responses.database.initialize_caches.timeout_ms")
  1494  	v.BindEnv("stored_responses.database.initialize_caches.query")
  1495  	v.BindEnv("stored_responses.database.poll_for_updates.refresh_rate_seconds")
  1496  	v.BindEnv("stored_responses.database.poll_for_updates.timeout_ms")
  1497  	v.BindEnv("stored_responses.database.poll_for_updates.query")
  1498  }
  1499  
  1500  func setBidderDefaults(v *viper.Viper, bidder string) {
  1501  	adapterCfgPrefix := "adapters." + bidder
  1502  	v.BindEnv(adapterCfgPrefix + ".disabled")
  1503  	v.BindEnv(adapterCfgPrefix + ".endpoint")
  1504  	v.BindEnv(adapterCfgPrefix + ".extra_info")
  1505  	v.BindEnv(adapterCfgPrefix + ".modifyingVastXmlAllowed")
  1506  	v.BindEnv(adapterCfgPrefix + ".debug.allow")
  1507  	v.BindEnv(adapterCfgPrefix + ".gvlVendorID")
  1508  	v.BindEnv(adapterCfgPrefix + ".usersync_url")
  1509  	v.BindEnv(adapterCfgPrefix + ".experiment.adsCert.enabled")
  1510  	v.BindEnv(adapterCfgPrefix + ".platform_id")
  1511  	v.BindEnv(adapterCfgPrefix + ".app_secret")
  1512  	v.BindEnv(adapterCfgPrefix + ".xapi.username")
  1513  	v.BindEnv(adapterCfgPrefix + ".xapi.password")
  1514  	v.BindEnv(adapterCfgPrefix + ".xapi.tracker")
  1515  	v.BindEnv(adapterCfgPrefix + ".endpointCompression")
  1516  	v.BindEnv(adapterCfgPrefix + ".openrtb.version")
  1517  	v.BindEnv(adapterCfgPrefix + ".openrtb.gpp-supported")
  1518  
  1519  	v.BindEnv(adapterCfgPrefix + ".usersync.key")
  1520  	v.BindEnv(adapterCfgPrefix + ".usersync.default")
  1521  	v.BindEnv(adapterCfgPrefix + ".usersync.iframe.url")
  1522  	v.BindEnv(adapterCfgPrefix + ".usersync.iframe.redirect_url")
  1523  	v.BindEnv(adapterCfgPrefix + ".usersync.iframe.external_url")
  1524  	v.BindEnv(adapterCfgPrefix + ".usersync.iframe.user_macro")
  1525  	v.BindEnv(adapterCfgPrefix + ".usersync.redirect.url")
  1526  	v.BindEnv(adapterCfgPrefix + ".usersync.redirect.redirect_url")
  1527  	v.BindEnv(adapterCfgPrefix + ".usersync.redirect.external_url")
  1528  	v.BindEnv(adapterCfgPrefix + ".usersync.redirect.user_macro")
  1529  	v.BindEnv(adapterCfgPrefix + ".usersync.external_url")
  1530  	v.BindEnv(adapterCfgPrefix + ".usersync.support_cors")
  1531  }
  1532  
  1533  func isValidCookieSize(maxCookieSize int) error {
  1534  	// If a non-zero-less-than-500-byte "host_cookie.max_cookie_size_bytes" value was specified in the
  1535  	// environment configuration of prebid-server, default to 500 bytes
  1536  	if maxCookieSize != 0 && maxCookieSize < MIN_COOKIE_SIZE_BYTES {
  1537  		return fmt.Errorf("Configured cookie size is less than allowed minimum size of %d \n", MIN_COOKIE_SIZE_BYTES)
  1538  	}
  1539  	return nil
  1540  }
  1541  
  1542  // Tmax Adjustments enables PBS to estimate the tmax value for bidders, indicating the allotted time for them to respond to a request.
  1543  // It's important to note that the calculated tmax is just an estimate and will not be entirely precise.
  1544  // PBS will calculate the bidder tmax as follows:
  1545  // bidderTmax = request.tmax - reqProcessingTime - BidderNetworkLatencyBuffer - PBSResponsePreparationDuration
  1546  // Note that reqProcessingTime is time taken by PBS to process a given request before it is sent to bid adapters and is computed at run time.
  1547  type TmaxAdjustments struct {
  1548  	// Enabled indicates whether bidder tmax should be calculated and passed on to bid adapters
  1549  	Enabled bool `mapstructure:"enabled"`
  1550  	// BidderNetworkLatencyBuffer accounts for network delays between PBS and bidder servers.
  1551  	// A value of 0 indicates no network latency buffer should be accounted for when calculating the bidder tmax.
  1552  	BidderNetworkLatencyBuffer uint `mapstructure:"bidder_network_latency_buffer_ms"`
  1553  	// PBSResponsePreparationDuration accounts for amount of time required for PBS to process all bidder responses and generate final response for a request.
  1554  	// A value of 0 indicates PBS response preparation time shouldn't be accounted for when calculating bidder tmax.
  1555  	PBSResponsePreparationDuration uint `mapstructure:"pbs_response_preparation_duration_ms"`
  1556  	// BidderResponseDurationMin is the minimum amount of time expected to get a response from a bidder request.
  1557  	// PBS won't send a request to the bidder if the bidder tmax calculated is less than the BidderResponseDurationMin value
  1558  	BidderResponseDurationMin uint `mapstructure:"bidder_response_duration_min_ms"`
  1559  }