github.com/prebid/prebid-server/v2@v2.18.0/openrtb_ext/device.go (about)

     1  package openrtb_ext
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"strconv"
     7  
     8  	"github.com/buger/jsonparser"
     9  	"github.com/prebid/prebid-server/v2/errortypes"
    10  )
    11  
    12  // PrebidExtKey represents the prebid extension key used in requests
    13  const PrebidExtKey = "prebid"
    14  
    15  // PrebidExtBidderKey represents the field name within request.imp.ext.prebid reserved for bidder params.
    16  const PrebidExtBidderKey = "bidder"
    17  
    18  // ExtDevice defines the contract for bidrequest.device.ext
    19  type ExtDevice struct {
    20  	// Attribute:
    21  	//   atts
    22  	// Type:
    23  	//   integer; optional - iOS Only
    24  	// Description:
    25  	//   iOS app tracking authorization status.
    26  	// Extension Spec:
    27  	//   https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/extensions/community_extensions/skadnetwork.md
    28  	ATTS *IOSAppTrackingStatus `json:"atts"`
    29  
    30  	// Attribute:
    31  	//   prebid
    32  	// Type:
    33  	//   object; optional
    34  	// Description:
    35  	//   Prebid extensions for the Device object.
    36  	Prebid ExtDevicePrebid `json:"prebid"`
    37  }
    38  
    39  // IOSAppTrackingStatus describes the values for iOS app tracking authorization status.
    40  type IOSAppTrackingStatus int
    41  
    42  // Values of the IOSAppTrackingStatus enumeration.
    43  const (
    44  	IOSAppTrackingStatusNotDetermined IOSAppTrackingStatus = 0
    45  	IOSAppTrackingStatusRestricted    IOSAppTrackingStatus = 1
    46  	IOSAppTrackingStatusDenied        IOSAppTrackingStatus = 2
    47  	IOSAppTrackingStatusAuthorized    IOSAppTrackingStatus = 3
    48  )
    49  
    50  // IsKnownIOSAppTrackingStatus returns true if the value is a known iOS app tracking authorization status.
    51  func IsKnownIOSAppTrackingStatus(v int64) bool {
    52  	switch IOSAppTrackingStatus(v) {
    53  	case IOSAppTrackingStatusNotDetermined:
    54  		return true
    55  	case IOSAppTrackingStatusRestricted:
    56  		return true
    57  	case IOSAppTrackingStatusDenied:
    58  		return true
    59  	case IOSAppTrackingStatusAuthorized:
    60  		return true
    61  	default:
    62  		return false
    63  	}
    64  }
    65  
    66  // ExtDevicePrebid defines the contract for bidrequest.device.ext.prebid
    67  type ExtDevicePrebid struct {
    68  	Interstitial *ExtDeviceInt `json:"interstitial"`
    69  }
    70  
    71  // ExtDeviceInt defines the contract for bidrequest.device.ext.prebid.interstitial
    72  type ExtDeviceInt struct {
    73  	MinWidthPerc  int64 `json:"minwidthperc"`
    74  	MinHeightPerc int64 `json:"minheightperc"`
    75  }
    76  
    77  func (edi *ExtDeviceInt) UnmarshalJSON(b []byte) error {
    78  	if len(b) == 0 {
    79  		return &errortypes.BadInput{Message: "request.device.ext.prebid.interstitial must have some data in it"}
    80  	}
    81  	if value, dataType, _, _ := jsonparser.Get(b, "minwidthperc"); dataType != jsonparser.Number {
    82  		return &errortypes.BadInput{Message: "request.device.ext.prebid.interstitial.minwidthperc must be a number between 0 and 100"}
    83  	} else {
    84  		perc, err := strconv.Atoi(string(value))
    85  		if err != nil || perc < 0 || perc > 100 {
    86  			return &errortypes.BadInput{Message: "request.device.ext.prebid.interstitial.minwidthperc must be a number between 0 and 100"}
    87  		}
    88  		edi.MinWidthPerc = int64(perc)
    89  	}
    90  	if value, dataType, _, _ := jsonparser.Get(b, "minheightperc"); dataType != jsonparser.Number {
    91  		return &errortypes.BadInput{Message: "request.device.ext.prebid.interstitial.minheightperc must be a number between 0 and 100"}
    92  	} else {
    93  		perc, err := strconv.Atoi(string(value))
    94  		if err != nil || perc < 0 || perc > 100 {
    95  			return &errortypes.BadInput{Message: "request.device.ext.prebid.interstitial.minheightperc must be a number between 0 and 100"}
    96  		}
    97  		edi.MinHeightPerc = int64(perc)
    98  	}
    99  	return nil
   100  }
   101  
   102  // ParseDeviceExtATTS parses the ATTS value from the request.device.ext OpenRTB field.
   103  func ParseDeviceExtATTS(deviceExt json.RawMessage) (*IOSAppTrackingStatus, error) {
   104  	v, err := jsonparser.GetInt(deviceExt, "atts")
   105  
   106  	// node not found error
   107  	if err == jsonparser.KeyPathNotFoundError {
   108  		return nil, nil
   109  	}
   110  
   111  	// unexpected parse error
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	// invalid value error
   117  	if !IsKnownIOSAppTrackingStatus(v) {
   118  		return nil, errors.New("invalid status")
   119  	}
   120  
   121  	status := IOSAppTrackingStatus(v)
   122  	return &status, nil
   123  }