payment-request-constructor-thcrash.https.html (7357B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <meta name="timeout" content="long"> 4 <title>Crash tests PaymentRequest Constructor</title> 5 <link rel="help" href="https://w3c.github.io/browser-payment-api/#constructor"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <script> 9 10 "use strict"; 11 const ABUSIVE_AMOUNT = 100000; 12 13 const applePay = { 14 supportedMethods: "https://apple.com/apple-pay", 15 data: { 16 version: 3, 17 merchantIdentifier: "merchant.com.example", 18 countryCode: "US", 19 merchantCapabilities: ["supports3DS"], 20 supportedNetworks: ["visa"], 21 } 22 }; 23 24 const basicCard = Object.freeze({ 25 supportedMethods: "basic-card", 26 }); 27 28 const defaultAmount = Object.freeze({ 29 currency: "USD", 30 value: "1.00", 31 }); 32 33 const evilAmount = Object.freeze({ 34 currency: "USD", 35 value: "1".repeat(ABUSIVE_AMOUNT), 36 }); 37 38 const defaultMethods = Object.freeze([basicCard, applePay]); 39 40 const defaultTotal = Object.freeze({ 41 label: "label", 42 amount: defaultAmount, 43 }); 44 45 const evilTotal = Object.freeze({ 46 label: "a".repeat(ABUSIVE_AMOUNT), 47 amount: evilAmount, 48 }); 49 50 const defaultDetails = Object.freeze({ 51 total: defaultTotal, 52 get id() { 53 return Math.random(); 54 }, 55 }); 56 57 const defaultPaymentItem = Object.freeze({ 58 label: "label", 59 amount: defaultAmount, 60 }); 61 62 const defaultShippingOption = { 63 get id() { 64 return "shipping option " + Math.random(); 65 }, 66 amount: defaultAmount, 67 label: "shipping option label", 68 }; 69 70 // First argument is sequence<PaymentMethodData> methodData 71 test(() => { 72 let evilMethods = [Object.assign({}, basicCard)]; 73 // smoke test 74 try { 75 new PaymentRequest(evilMethods, defaultDetails); 76 } catch (err) { 77 assert_unreached("failed smoke test: " + err.stack); 78 } 79 // Now, let's add an abusive amount of methods. 80 while (evilMethods.length < ABUSIVE_AMOUNT) { 81 evilMethods.push({supportedMethods: "evil-method" + evilMethods.length}); 82 } 83 try { 84 new PaymentRequest(evilMethods, defaultDetails); 85 } catch (err) { 86 assert_equals(err.name, "TypeError", "must be a TypeError"); 87 } 88 }, "Don't crash if there is an abusive number of payment methods in the methodData sequence"); 89 90 // PaymentMethodData.supportedMethods 91 test(() => { 92 const supportedMethods = "basic-card"; 93 // Smoke test 94 try { 95 new PaymentRequest([{ supportedMethods }], defaultDetails); 96 } catch (err) { 97 assert_unreached("failed smoke test: " + err.stack); 98 } 99 // Now, we make supportedMethods super large 100 const evilMethodData = [ 101 { 102 supportedMethods: supportedMethods.repeat(ABUSIVE_AMOUNT), 103 }, 104 ]; 105 try { 106 new PaymentRequest(evilMethodData, defaultDetails); 107 } catch (err) { 108 assert_equals(err.name, "TypeError", "must be a TypeError"); 109 } 110 }, "Don't crash if PaymentMethodData.supportedMethods is an abusive length"); 111 112 // PaymentDetailsInit.id 113 test(() => { 114 const id = "abc"; 115 // Smoke Test 116 try { 117 new PaymentRequest( 118 defaultMethods, 119 Object.assign({}, defaultDetails, { id }) 120 ); 121 } catch (err) { 122 assert_unreached("failed smoke test: " + err.stack); 123 } 124 // Now, we make the id super large; 125 const evilDetails = Object.assign({}, defaultDetails, { 126 id: id.repeat(ABUSIVE_AMOUNT), 127 }); 128 try { 129 new PaymentRequest(defaultMethods, evilDetails); 130 } catch (err) { 131 assert_equals(err.name, "TypeError", "must be a TypeError"); 132 } 133 }, "Don't crash if the request id has an abusive length"); 134 135 // PaymentDetailsInit.total.label 136 test(() => { 137 const evilDetails = Object.assign({}, defaultDetails); 138 // Smoke Test 139 try { 140 new PaymentRequest(defaultMethods, evilDetails); 141 } catch (err) { 142 assert_unreached("failed smoke test: " + err.stack); 143 } 144 // Now, we make the label super large; 145 evilDetails.total = { 146 label: "l".repeat(ABUSIVE_AMOUNT), 147 amount: defaultAmount, 148 }; 149 try { 150 new PaymentRequest(defaultMethods, evilDetails); 151 } catch (err) { 152 assert_equals(err.name, "TypeError", "must be a TypeError"); 153 } 154 }, "Don't crash if PaymentDetailsInit.total.label is an abusive length"); 155 156 test(() => { 157 const evilDetails = Object.assign({}, defaultDetails); 158 // Smoke Test 159 try { 160 new PaymentRequest(defaultMethods, evilDetails); 161 } catch (err) { 162 assert_unreached("failed smoke test: " + err.stack); 163 } 164 // Now, we can use evilAmount 165 evilDetails.total = evilAmount; 166 try { 167 new PaymentRequest(defaultMethods, evilDetails); 168 } catch (err) { 169 assert_equals(err.name, "TypeError", "must be a TypeError"); 170 } 171 }, "Don't crash if total.amount.value is an abusive length"); 172 173 for (const [prop, defaultValue] of [ 174 ["displayItems", defaultPaymentItem], 175 ["shippingOptions", defaultShippingOption], 176 ]) { 177 test(() => { 178 const evilDetails = Object.assign({}, defaultDetails); 179 evilDetails[prop] = [defaultValue]; 180 // Smoke Test 181 try { 182 new PaymentRequest(defaultMethods, evilDetails); 183 } catch (err) { 184 assert_unreached("failed smoke test: " + err.stack); 185 } 186 while (evilDetails[prop].length < ABUSIVE_AMOUNT) { 187 evilDetails[prop] = evilDetails[prop].concat(evilDetails[prop]); 188 } 189 // Now, construct with evil items! 190 try { 191 new PaymentRequest(defaultMethods, evilDetails); 192 } catch (err) { 193 assert_equals(err.name, "TypeError", "must be a TypeError"); 194 } 195 }, `Don't crash if details.${prop} has an abusive number of items`); 196 } 197 198 test(() => { 199 const evilDetails = Object.assign({}, defaultDetails); 200 const evilShippingOption = Object.assign({}, defaultShippingOption); 201 evilDetails.shippingOptions = [evilShippingOption]; 202 // Smoke Test 203 try { 204 new PaymentRequest(defaultMethods, evilDetails); 205 } catch (err) { 206 assert_unreached("failed smoke test: " + err.stack); 207 } 208 // Now, we make the label super large; 209 evilShippingOption.label = "l".repeat(ABUSIVE_AMOUNT); 210 try { 211 new PaymentRequest(defaultMethods, evilDetails); 212 } catch (err) { 213 assert_equals(err.name, "TypeError", "must be a TypeError"); 214 } 215 }, "Don't crash if PaymentShippingOptions.label is an abusive length"); 216 217 test(() => { 218 const evilDetails = Object.assign({}, defaultDetails); 219 const evilShippingOption = Object.assign({}, defaultShippingOption); 220 evilDetails.shippingOptions = [evilShippingOption]; 221 // Smoke Test 222 try { 223 new PaymentRequest(defaultMethods, evilDetails); 224 } catch (err) { 225 assert_unreached("failed smoke test: " + err.stack); 226 } 227 // Now, we make use of evilAmount; 228 evilShippingOption.amount = evilAmount; 229 try { 230 new PaymentRequest(defaultMethods, evilDetails); 231 } catch (err) { 232 assert_equals(err.name, "TypeError", "must be a TypeError"); 233 } 234 }, "Don't crash if the PaymentShippingOptions.amount.value is an abusive length"); 235 236 test(() => { 237 const evilDetails = Object.assign({}, defaultDetails); 238 const evilDisplayItem = Object.assign({}, defaultPaymentItem); 239 evilDetails.displayItems = [evilDisplayItem]; 240 // Smoke Test 241 try { 242 new PaymentRequest(defaultMethods, evilDetails); 243 } catch (err) { 244 assert_unreached("failed smoke test: " + err.stack); 245 } 246 // Now, we make the label super large; 247 evilDisplayItem.label = "l".repeat(ABUSIVE_AMOUNT); 248 try { 249 new PaymentRequest(defaultMethods, evilDetails); 250 } catch (err) { 251 assert_equals(err.name, "TypeError", "must be a TypeError"); 252 } 253 }, "Don't crash if PaymentItem.label is an abusive length"); 254 </script>