tor-browser

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

AllJavascriptTypes.mjs (10812B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 /* eslint-disable object-shorthand */
      5 
      6 // eslint-disable-next-line mozilla/reject-import-system-module-from-non-system
      7 import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
      8 
      9 // Try replicating real world environment, by using
     10 // * a true HTML document
     11 // * served from http (https isn't yet supported by nsHttpServer)
     12 // * with a regular domain name (example.com)
     13 export const TEST_PAGE_HTML = String.raw`<!DOCTYPE html>
     14 <html lang="en">
     15 <head>
     16  <meta charset="UTF-8">
     17  <title></title>
     18 </head>
     19 <body>
     20  <span id="span">Hello there.</span>
     21  <script>
     22    globalThis.myPolicy = trustedTypes.createPolicy("myPolicy", {
     23      createHTML: s => "<my-policy>" + s + "</my-policy>",
     24      createScript: s => "/* myPolicy */ " + s,
     25      createScriptURL: s => s + "?myPolicy",
     26    });
     27  </script>
     28 </body>
     29 </html>`;
     30 
     31 export const CONTEXTS = {
     32   JS: "js",
     33   PAGE: "page",
     34   CHROME: "chrome"
     35 };
     36 
     37 /**
     38 * Manifest covering all the possible JavaScript value types that gecko may create.
     39 * This consist in JavaScript code instantiating one of more example values for all of these types.
     40 *
     41 * See README.md
     42 */
     43 const BasicPrimitives = [
     44  {
     45    context: CONTEXTS.JS,
     46    expression: "undefined",
     47  },
     48  {
     49    context: CONTEXTS.JS,
     50    expression: "null",
     51  },
     52  {
     53    context: CONTEXTS.JS,
     54    expression: "true",
     55  },
     56  {
     57    context: CONTEXTS.JS,
     58    expression: "false",
     59  },
     60  {
     61    context: CONTEXTS.JS,
     62    expression: "NaN",
     63  },
     64 ];
     65 
     66 const Strings = [
     67  {
     68    context: CONTEXTS.JS,
     69    expression: `"abc"`,
     70  },
     71  {
     72    context: CONTEXTS.JS,
     73    expression: `"\u9f2c\xFA"`,
     74  },
     75 ];
     76 
     77 const Numbers = [
     78  {
     79    context: CONTEXTS.JS,
     80    expression: "42",
     81  },
     82  {
     83    context: CONTEXTS.JS,
     84    expression: "-42",
     85  },
     86  {
     87    context: CONTEXTS.JS,
     88    expression: "-0",
     89  },
     90  {
     91    context: CONTEXTS.JS,
     92    expression: "Infinity",
     93  },
     94  {
     95    context: CONTEXTS.JS,
     96    expression: "BigInt(1000000000000000000)",
     97  },
     98  {
     99    context: CONTEXTS.JS,
    100    expression: "1n",
    101  },
    102  {
    103    context: CONTEXTS.JS,
    104    expression: "-2n",
    105  },
    106  {
    107    context: CONTEXTS.JS,
    108    expression: "0n",
    109  },
    110 ];
    111 
    112 const Primitives = [...BasicPrimitives, ...Strings, ...Numbers];
    113 
    114 const PlainObjects = [
    115  {
    116    context: CONTEXTS.JS,
    117    expression: "({})"
    118  },
    119  {
    120    context: CONTEXTS.JS,
    121    expression: `({ foo: "bar"})`
    122  }
    123 ];
    124 
    125 const Arrays = [
    126  {
    127    context: CONTEXTS.JS,
    128    expression: "[]"
    129  },
    130  {
    131    context: CONTEXTS.JS,
    132    expression: "[1]"
    133  },
    134  {
    135    context: CONTEXTS.JS,
    136    expression: '["foo"]'
    137  }
    138 ];
    139 
    140 const TypedArrays = [
    141  {
    142    context: CONTEXTS.JS,
    143    expression: "new BigInt64Array()"
    144  },
    145  {
    146    context: CONTEXTS.JS,
    147    expression: `
    148      const a = new BigInt64Array(1);
    149      a[0] = BigInt(42);
    150      a;
    151    `,
    152  },
    153 ];
    154 
    155 const Maps = [
    156  {
    157    context: CONTEXTS.JS,
    158    expression: `new Map(
    159          Array.from({ length: 2 }).map((el, i) => [
    160            { key: i },
    161            { object: 42 },
    162          ])
    163        )`,
    164  },
    165  {
    166    context: CONTEXTS.JS,
    167    expression: `new Map(Array.from({ length: 20 }).map((el, i) => [Symbol(i), i]))`,
    168  },
    169  {
    170    context: CONTEXTS.JS,
    171    expression: `new Map(Array.from({ length: 331 }).map((el, i) => [Symbol(i), i]))`,
    172  },
    173 ];
    174 
    175 const Sets = [
    176  {
    177    context: CONTEXTS.JS,
    178    expression: `new Set(Array.from({ length: 2 }).map((el, i) => ({ value: i })))`,
    179  },
    180  {
    181    context: CONTEXTS.JS,
    182    expression: `new Set(Array.from({ length: 20 }).map((el, i) => i))`
    183  },
    184  {
    185    context: CONTEXTS.JS,
    186    expression: `new Set(Array.from({ length: 222 }).map((el, i) => i))`
    187  },
    188 ];
    189 
    190 const Temporals = [
    191  {
    192    context: CONTEXTS.JS,
    193    expression: `new Temporal.Instant(355924804000000000n)`
    194  },
    195  {
    196    context: CONTEXTS.JS,
    197    expression: `new Temporal.PlainDate(2021, 7, 1, "coptic")`
    198  },
    199  {
    200    context: CONTEXTS.JS,
    201    expression: `new Temporal.PlainDateTime(2021, 7, 1, 0, 0, 0, 0, 0, 0, "gregory")`,
    202  },
    203  {
    204    context: CONTEXTS.JS,
    205    expression: `new Temporal.PlainMonthDay(7, 1, "chinese")`
    206  },
    207  {
    208    context: CONTEXTS.JS,
    209    expression: `new Temporal.PlainTime(4, 20)`
    210  },
    211  {
    212    context: CONTEXTS.JS,
    213    expression: `new Temporal.PlainYearMonth(2021, 7, "indian")`
    214  },
    215  {
    216    context: CONTEXTS.JS,
    217    expression: `new Temporal.ZonedDateTime(0n, "America/New_York")`
    218  },
    219  {
    220    context: CONTEXTS.JS,
    221    expression: `Temporal.Duration.from({ years: 1 })`
    222  },
    223 ];
    224 
    225 const DOMAPIs = [
    226  {
    227    context: CONTEXTS.PAGE,
    228    expression: `myPolicy.createHTML("hello")`,
    229    prefs: [["dom.security.trusted_types.enabled", true]],
    230  },
    231  {
    232    context: CONTEXTS.PAGE,
    233    expression: `myPolicy.createScript("const hello = 'world'")`
    234  },
    235  {
    236    context: CONTEXTS.PAGE,
    237    expression: `myPolicy.createScriptURL("https://example.com/trusted")`
    238  },
    239 
    240  {
    241    context: CONTEXTS.PAGE,
    242    expression: `
    243      const formData = new FormData();
    244      formData.append("a", 1);
    245      formData.append("a", 2);
    246      formData.append("b", 3);
    247      formData;
    248    `,
    249  },
    250  /* midi API requires https (See Bug 1967917)
    251  {
    252    context: CONTEXTS.PAGE,
    253    expression: `
    254      const midiAccess = await navigator.requestMIDIAccess();
    255      midiAccess.inputs;
    256    `,
    257    prefs: [
    258      // This will make it so we'll have stable MIDI devices reported
    259      ["midi.testing", true],
    260      ["dom.webmidi.enabled", true],
    261      ["midi.prompt.testing", true],
    262      ["media.navigator.permission.disabled", true],
    263    ],
    264  },
    265  */
    266  {
    267    context: CONTEXTS.PAGE,
    268    expression: `
    269      customElements.define("fx-test", class extends HTMLElement {});
    270      const { states } = document.createElement("fx-test").attachInternals();
    271      states.add("custom-state");
    272      states.add("another-custom-state");
    273      states;
    274    `,
    275  },
    276 
    277  {
    278    context: CONTEXTS.PAGE,
    279    expression: `
    280      CSS.highlights.set("search", new Highlight());
    281      CSS.highlights.set("glow", new Highlight());
    282      CSS.highlights.set("anchor", new Highlight());
    283      CSS.highlights;
    284    `,
    285    prefs: [["dom.customHighlightAPI.enabled", true]],
    286  },
    287  {
    288    context: CONTEXTS.PAGE,
    289    expression: `new URLSearchParams([
    290      ["a", 1],
    291      ["a", 2],
    292      ["b", 3],
    293      ["b", 3],
    294      ["b", 5],
    295      ["c", "this is 6"],
    296      ["d", 7],
    297      ["e", 8],
    298      ["f", 9],
    299      ["g", 10],
    300      ["h", 11],
    301    ])`,
    302  },
    303 ];
    304 
    305 const Errors = [
    306  {
    307    context: CONTEXTS.JS,
    308    expression: `new Error("foo")`
    309  },
    310  {
    311    context: CONTEXTS.JS,
    312    expression: `throw new Error("Long error ".repeat(10000));`,
    313  },
    314  {
    315    context: CONTEXTS.JS,
    316    expression: `
    317      throw \`“https://evil.com/?${"a".repeat(
    318        200
    319      )}“ is evil and “https://not-so-evil.com/?${"b".repeat(
    320        200
    321      )}“ is not good either\`;
    322    `,
    323  },
    324  {
    325    context: CONTEXTS.JS,
    326    expression: `Error("bar")`
    327  },
    328  {
    329    context: CONTEXTS.JS,
    330    expression: `
    331      function bar() {
    332        asdf();
    333      }
    334      function foo() {
    335        bar();
    336      }
    337 
    338      foo();
    339    `,
    340  },
    341 
    342  {
    343    context: CONTEXTS.JS,
    344    // Use nested `eval()` as syntax error would make the test framework throw on its own eval call
    345    expression: `eval("let a, a")`,
    346  },
    347 
    348  {
    349    context: CONTEXTS.JS,
    350    expression: `throw "";`
    351  },
    352  {
    353    context: CONTEXTS.JS,
    354    expression: `throw false;`
    355  },
    356  {
    357    context: CONTEXTS.JS,
    358    expression: `throw undefined;`
    359  },
    360  {
    361    context: CONTEXTS.JS,
    362    expression: `throw 0;`
    363  },
    364  {
    365    context: CONTEXTS.JS,
    366    expression: `throw { vegetable: "cucumber" };`
    367  },
    368  {
    369    context: CONTEXTS.JS,
    370    expression: `throw Symbol("potato");`
    371  },
    372 
    373  {
    374    context: CONTEXTS.JS,
    375    expression: `
    376      var err = new Error("pineapple");
    377      err.name = "JuicyError";
    378      err.flavor = "delicious";
    379      throw err;
    380    `,
    381  },
    382  {
    383    context: CONTEXTS.JS,
    384    expression: `
    385      var originalError = new SyntaxError("original error");
    386      var err = new Error("something went wrong", {
    387        cause: originalError,
    388      });
    389      throw err;
    390    `,
    391  },
    392 
    393  {
    394    context: CONTEXTS.JS,
    395    expression: `
    396      var a = new Error("err-a");
    397      var b = new Error("err-b", { cause: a });
    398      var c = new Error("err-c", { cause: b });
    399      var d = new Error("err-d", { cause: c });
    400      throw d;
    401    `,
    402  },
    403  {
    404    context: CONTEXTS.JS,
    405    expression: `
    406      var a = new Error("err-a", { cause: b });
    407      var b = new Error("err-b", { cause: a });
    408      throw b;
    409    `,
    410  },
    411  {
    412    context: CONTEXTS.JS,
    413    expression: `throw new Error("null cause", { cause: null });`
    414  },
    415  {
    416    context: CONTEXTS.JS,
    417    expression: `throw new Error("number cause", { cause: 0 });`
    418  },
    419  {
    420    context: CONTEXTS.JS,
    421    expression: `throw new Error("string cause", { cause: "cause message" });`
    422  },
    423  {
    424    context: CONTEXTS.JS,
    425    expression: `
    426      throw new Error("object cause", {
    427        cause: { code: 234, message: "ERR_234" },
    428      });
    429    `,
    430  },
    431 
    432  {
    433    context: CONTEXTS.JS,
    434    expression: `Promise.reject("")`
    435  },
    436  {
    437    context: CONTEXTS.JS,
    438    expression: `Promise.reject("tomato")`
    439  },
    440  {
    441    context: CONTEXTS.JS,
    442    expression: `Promise.reject(false)`
    443  },
    444  {
    445    context: CONTEXTS.JS,
    446    expression: `Promise.reject(0)`
    447  },
    448  {
    449    context: CONTEXTS.JS,
    450    expression: `Promise.reject(null)`
    451  },
    452  {
    453    context: CONTEXTS.JS,
    454    expression: `Promise.reject(undefined)`
    455  },
    456  {
    457    context: CONTEXTS.JS,
    458    expression: `Promise.reject(Symbol("potato"))`
    459  },
    460  {
    461    context: CONTEXTS.JS,
    462    expression: `Promise.reject({vegetable: "cucumber"})`
    463  },
    464  {
    465    context: CONTEXTS.JS,
    466    expression: `Promise.reject(new Error("pumpkin"))`
    467  },
    468  {
    469    context: CONTEXTS.JS,
    470    expression: `
    471      var err = new Error("pineapple");
    472      err.name = "JuicyError";
    473      err.flavor = "delicious";
    474      Promise.reject(err);
    475    `,
    476  },
    477  {
    478    context: CONTEXTS.JS,
    479    expression: `Promise.resolve().then(() => {
    480        try {
    481          unknownFunc();
    482        } catch(e) {
    483          throw new Error("something went wrong", { cause: e })
    484        }
    485      })`,
    486  },
    487  {
    488    context: CONTEXTS.JS,
    489    expression: `
    490      throw new SuppressedError(
    491        new Error("foo"),
    492        new Error("bar"),
    493        "the suppressed error message"
    494      );
    495    `,
    496    prefs: [
    497      ["javascript.options.experimental.explicit_resource_management", true],
    498    ],
    499    // eslint-disable-next-line no-constant-binary-expression
    500    disabled: true || !AppConstants.ENABLE_EXPLICIT_RESOURCE_MANAGEMENT,
    501  },
    502 ];
    503 
    504 const Privileged = [
    505  {
    506    context: CONTEXTS.CHROME,
    507    expression: `Components.Exception("foo")`
    508  }
    509 ];
    510 
    511 
    512 export const AllObjects = [
    513  ...Primitives,
    514  ...PlainObjects,
    515  ...Arrays,
    516  ...TypedArrays,
    517  ...Maps,
    518  ...Sets,
    519  ...Temporals,
    520  ...DOMAPIs,
    521  ...Errors,
    522  ...Privileged,
    523 ];