tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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>