github.com/prebid/prebid-server/v2@v2.18.0/dsa/validate.go (about)

     1  package dsa
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/prebid/prebid-server/v2/exchange/entities"
     7  	"github.com/prebid/prebid-server/v2/openrtb_ext"
     8  	"github.com/prebid/prebid-server/v2/util/jsonutil"
     9  )
    10  
    11  // Required values representing whether a DSA object is required
    12  const (
    13  	Required               int8 = 2 // bid responses without DSA object will not be accepted
    14  	RequiredOnlinePlatform int8 = 3 // bid responses without DSA object will not be accepted, Publisher is Online Platform
    15  )
    16  
    17  // PubRender values representing publisher rendering intentions
    18  const (
    19  	PubRenderCannotRender int8 = 0 // publisher can't render
    20  	PubRenderWillRender   int8 = 2 // publisher will render
    21  )
    22  
    23  // AdRender values representing buyer/advertiser rendering intentions
    24  const (
    25  	AdRenderWillRender int8 = 1 // buyer/advertiser will render
    26  )
    27  
    28  var (
    29  	ErrDsaMissing        = errors.New("DSA object missing when required")
    30  	ErrBehalfTooLong     = errors.New("DSA behalf exceeds limit of 100 chars")
    31  	ErrPaidTooLong       = errors.New("DSA paid exceeds limit of 100 chars")
    32  	ErrNeitherWillRender = errors.New("DSA publisher and buyer both signal will not render")
    33  	ErrBothWillRender    = errors.New("DSA publisher and buyer both signal will render")
    34  )
    35  
    36  const (
    37  	behalfMaxLength = 100
    38  	paidMaxLength   = 100
    39  )
    40  
    41  // Validate determines whether a given bid is valid from a DSA perspective.
    42  // A bid is considered valid unless the bid request indicates that a DSA object is required
    43  // in bid responses and the object happens to be missing from the specified bid, or if the bid
    44  // DSA object contents are invalid
    45  func Validate(req *openrtb_ext.RequestWrapper, bid *entities.PbsOrtbBid) error {
    46  	reqDSA := getReqDSA(req)
    47  	bidDSA := getBidDSA(bid)
    48  
    49  	if dsaRequired(reqDSA) && bidDSA == nil {
    50  		return ErrDsaMissing
    51  	}
    52  	if bidDSA == nil {
    53  		return nil
    54  	}
    55  	if len(bidDSA.Behalf) > behalfMaxLength {
    56  		return ErrBehalfTooLong
    57  	}
    58  	if len(bidDSA.Paid) > paidMaxLength {
    59  		return ErrPaidTooLong
    60  	}
    61  	if reqDSA != nil && reqDSA.PubRender != nil && bidDSA.AdRender != nil {
    62  		if *reqDSA.PubRender == PubRenderCannotRender && *bidDSA.AdRender != AdRenderWillRender {
    63  			return ErrNeitherWillRender
    64  		}
    65  		if *reqDSA.PubRender == PubRenderWillRender && *bidDSA.AdRender == AdRenderWillRender {
    66  			return ErrBothWillRender
    67  		}
    68  	}
    69  	return nil
    70  }
    71  
    72  // dsaRequired examines the bid request to determine if the dsarequired field indicates
    73  // that bid responses include a dsa object
    74  func dsaRequired(dsa *openrtb_ext.ExtRegsDSA) bool {
    75  	if dsa == nil || dsa.Required == nil {
    76  		return false
    77  	}
    78  	return *dsa.Required == Required || *dsa.Required == RequiredOnlinePlatform
    79  }
    80  
    81  // getReqDSA retrieves the DSA object from the request
    82  func getReqDSA(req *openrtb_ext.RequestWrapper) *openrtb_ext.ExtRegsDSA {
    83  	if req == nil {
    84  		return nil
    85  	}
    86  	regExt, err := req.GetRegExt()
    87  	if regExt == nil || err != nil {
    88  		return nil
    89  	}
    90  	return regExt.GetDSA()
    91  }
    92  
    93  // getBidDSA retrieves the DSA object from the bid
    94  func getBidDSA(bid *entities.PbsOrtbBid) *openrtb_ext.ExtBidDSA {
    95  	if bid == nil || bid.Bid == nil {
    96  		return nil
    97  	}
    98  	var bidExt openrtb_ext.ExtBid
    99  	if err := jsonutil.Unmarshal(bid.Bid.Ext, &bidExt); err != nil {
   100  		return nil
   101  	}
   102  	return bidExt.DSA
   103  }