fledge-bidding-logic.py (3860B)
1 # These functions are used by FLEDGE to determine the logic for the ad buyer. 2 # For our testing purposes, we only need the minimal amount of boilerplate 3 # code in place to allow them to be invoked properly and move the FLEDGE 4 # process along. The tests generally do usually not deal with reporting results, 5 # so we leave `reportWin` empty unless we need to call registerAdBeacon(). See 6 # `generateURNFromFledge` in "utils.js" to see how this file is used. 7 8 from wptserve.utils import isomorphic_decode 9 10 def main(request, response): 11 # Set up response headers. 12 headers = [ 13 ('Content-Type', 'Application/Javascript'), 14 ('Ad-Auction-Allowed', 'true') 15 ] 16 17 # Parse URL params. 18 requested_size = request.GET.first(b"requested-size", None) 19 ad_with_size = request.GET.first(b"ad-with-size", None) 20 beacon = request.GET.first(b"beacon", None) 21 22 # Use URL params to modify Javascript. 23 requested_size_check = '' 24 if requested_size is not None: 25 # request.GET stores URL keys and values in iso-8859-1 binary encoding. We 26 # have to decode the values back to a string to parse width/height. Don't 27 # bother sanitizing the size, because it is sanitized before auction logic 28 # runs already. 29 width, height = isomorphic_decode(requested_size).split('-') 30 31 requested_size_check = ( 32 f''' 33 if (!(browserSignals.requestedSize.width === '{width}') && 34 (browserSignals.requestedSize.height === '{height}')) {{ 35 throw new Error('requestedSize missing/incorrect in browserSignals'); 36 }} 37 ''' 38 ) 39 40 render_obj = 'ad.renderURL' 41 if ad_with_size is not None: 42 render_obj = '{ url: ad.renderURL, width: "100px", height: "50px" }' 43 44 component_render_obj = 'component.renderURL' 45 if ad_with_size is not None: 46 component_render_obj = ( 47 '''{ 48 url: component.renderURL, 49 width: "100px", 50 height: "50px" 51 } 52 ''' 53 ) 54 55 register_ad_beacon = '' 56 if beacon is not None: 57 register_ad_beacon = ( 58 '''registerAdBeacon({ 59 'reserved.top_navigation_start': 60 browserSignals.interestGroupOwner + 61 '/fenced-frame/resources/beacon-store.py?type=reserved.top_navigation_start', 62 'reserved.top_navigation_commit': 63 browserSignals.interestGroupOwner + 64 '/fenced-frame/resources/beacon-store.py?type=reserved.top_navigation_commit', 65 'click': 66 browserSignals.interestGroupOwner + 67 '/fenced-frame/resources/beacon-store.py?type=click', 68 }); 69 ''' 70 ) 71 72 # Generate Javascript. 73 # Note: Python fstrings use double-brackets ( {{, }} ) to insert bracket 74 # literals instead of substitution sequences. 75 generate_bid = ( 76 f'''function generateBid( 77 interestGroup, 78 auctionSignals, 79 perBuyerSignals, 80 trustedBiddingSignals, 81 browserSignals) {{ 82 {requested_size_check} 83 const ad = interestGroup.ads[0]; 84 85 // `auctionSignals` controls whether or not component auctions are 86 // allowed. 87 let allowComponentAuction = (typeof auctionSignals === 'string' && 88 auctionSignals.includes('bidderAllowsComponentAuction')); 89 90 let result = {{ 91 'ad': ad, 92 'bid': 1, 93 'render': {render_obj}, 94 'allowComponentAuction': allowComponentAuction 95 }}; 96 if (interestGroup.adComponents && interestGroup.adComponents.length > 0) 97 result.adComponents = interestGroup.adComponents.map((component) => {{ 98 return {component_render_obj}; 99 }}); 100 return result; 101 }} 102 ''' 103 ) 104 105 report_win = ( 106 f'''function reportWin( 107 auctionSignals, 108 perBuyerSignals, 109 sellerSignals, 110 browserSignals) {{ 111 {register_ad_beacon} 112 return; 113 }} 114 ''' 115 ) 116 117 content = f'{generate_bid}\n{report_win}' 118 119 return (headers, content)