tor-browser

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

test_pointer_event.html (10359B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <!--
      4 https://bugzilla.mozilla.org/show_bug.cgi?id=1363508
      5 -->
      6 <head>
      7  <meta charset="utf-8">
      8  <title>Test for Pointer Events spoofing</title>
      9  <script src="/tests/SimpleTest/SimpleTest.js"></script>
     10  <script src="/tests/SimpleTest/EventUtils.js"></script>
     11  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     12 </head>
     13 <body>
     14 <div id="target0" style="width: 50px; height: 50px; background: green"></div>
     15 <div id="target1" style="width: 50px; height: 50px; background: black"></div>
     16 <script type="application/javascript">
     17  /** Test for Bug 1363508 */
     18  SimpleTest.waitForExplicitFinish();
     19 
     20  const { AppConstants } = SpecialPowers.ChromeUtils.importESModule(
     21    "resource://gre/modules/AppConstants.sys.mjs"
     22  );
     23 
     24  var target0 = window.document.getElementById("target0");
     25  var target1 = window.document.getElementById("target1");
     26  var utils = SpecialPowers.Ci.nsIDOMWindowUtils;
     27 
     28  // A helper function to check that whether the pointer is spoofed correctly.
     29  function checkPointerEvent(aEvent) {
     30    is(aEvent.width, 1, "The spoofed pointer event should always have width as 1.");
     31    is(aEvent.height, 1, "The spoofed pointer event should always have width as 1.");
     32    if (aEvent.buttons === 0) {
     33      is(aEvent.pressure, 0.0,
     34         "The spoofed pointer event should have pressure as 0.0 if it is not in a active buttons state.");
     35    } else {
     36      is(aEvent.pressure, 0.5,
     37         "The spoofed pointer event should have pressure as 0.5 if it is in a active buttons state.");
     38    }
     39    is(aEvent.tangentialPressure, 0, "The spoofed pointer event should always have tangentialPressure as 0.");
     40    is(aEvent.tiltX, 0, "The spoofed pointer event should always have tiltX as 0.");
     41    is(aEvent.tiltY, 0, "The spoofed pointer event should always have tiltY as 0.");
     42    is(aEvent.twist, 0, "The spoofed pointer event should always have twist as 0.");
     43    if (AppConstants.platform == "macosx") {
     44      is(aEvent.pointerId, utils.DEFAULT_MOUSE_POINTER_ID,
     45       "The spoofed pointer event should always have the mouse pointer id.");
     46      is(aEvent.pointerType, "mouse", "The spoofed pointer event should always has mouse pointerType.");
     47      is(aEvent.isPrimary, true, "The spoofed pointer event should only receive primary pointer events.");
     48    }
     49  }
     50 
     51  // A helper function to create a promise for waiting the event.
     52  function promiseForEvent(aEventType, aCheckFunc) {
     53    return new Promise(resolve => {
     54      target0.addEventListener(aEventType, (event) => {
     55        is(event.type, aEventType, "receive " + event.type + " on target0");
     56        aCheckFunc(event);
     57        resolve();
     58      }, { once: true });
     59    });
     60  }
     61 
     62  // A test for pointer events from touch interface.
     63  async function doTestForTouchPointerEvent() {
     64    let eventPromises = [
     65      promiseForEvent("pointerover", checkPointerEvent),
     66      promiseForEvent("pointerenter", checkPointerEvent),
     67      promiseForEvent("pointerdown", checkPointerEvent),
     68      promiseForEvent("pointermove", checkPointerEvent),
     69      promiseForEvent("pointerup", checkPointerEvent),
     70      promiseForEvent("pointerout", checkPointerEvent),
     71      promiseForEvent("pointerleave", checkPointerEvent),
     72    ];
     73 
     74    synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 });
     75    synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 });
     76    synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 });
     77 
     78    await Promise.all(eventPromises);
     79  }
     80 
     81  // A test for pointercancel event.
     82  async function doTestForTouchPointerCancelEvent() {
     83    let eventPromises = [
     84      promiseForEvent("pointerover", checkPointerEvent),
     85      promiseForEvent("pointerenter", checkPointerEvent),
     86      promiseForEvent("pointerdown", checkPointerEvent),
     87      promiseForEvent("pointermove", checkPointerEvent),
     88      promiseForEvent("pointercancel", checkPointerEvent),
     89      promiseForEvent("pointerout", checkPointerEvent),
     90      promiseForEvent("pointerleave", checkPointerEvent),
     91    ];
     92 
     93    synthesizeTouch(target0, 5, 5, { type: "touchstart" });
     94    synthesizeTouch(target0, 6, 6, { type: "touchmove" });
     95    synthesizeTouch(target0, 6, 6, { type: "touchcancel" });
     96 
     97    await Promise.all(eventPromises);
     98  }
     99 
    100  // A test for pointer events from pen interface.
    101  async function doTestForPenPointerEvent() {
    102    let eventPromises = [
    103      promiseForEvent("pointerover", checkPointerEvent),
    104      promiseForEvent("pointerenter", checkPointerEvent),
    105      promiseForEvent("pointerdown", checkPointerEvent),
    106      promiseForEvent("pointermove", checkPointerEvent),
    107      promiseForEvent("pointerup", checkPointerEvent),
    108      promiseForEvent("pointerout", checkPointerEvent),
    109      promiseForEvent("pointerleave", checkPointerEvent),
    110    ];
    111 
    112    synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_PEN });
    113    synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_PEN });
    114    synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_PEN });
    115    synthesizeMouse(target1, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_PEN });
    116 
    117    await Promise.all(eventPromises);
    118  }
    119 
    120  // A test for gotpointercapture and lostpointercapture events.
    121  // We would also test releasePointerCapture for only accepting spoofed pointer
    122  // Id here.
    123  async function doTestForPointerCapture() {
    124    // We test for both mouse and touch to see whether the capture events are
    125    // filed properly. We don't check pen here since it won't file capture
    126    // events.
    127    let inputSources = [ MouseEvent.MOZ_SOURCE_MOUSE,
    128                         MouseEvent.MOZ_SOURCE_TOUCH ];
    129 
    130    for (let inputSource of inputSources) {
    131      function eventHandler(event) {
    132        checkPointerEvent(event);
    133        if (event.type === "pointerdown") {
    134          target0.setPointerCapture(event.pointerId);
    135        } else if (event.type === "pointermove") {
    136          if (inputSource === MouseEvent.MOZ_SOURCE_TOUCH) {
    137            try {
    138              target0.releasePointerCapture(utils.DEFAULT_TOUCH_POINTER_ID);
    139              ok(false, "The releasePointerCapture should fail here, but it is not.");
    140            } catch (e) {
    141              ok(true, "The releasePointerCapture fails properly.");
    142            }
    143          }
    144          target0.releasePointerCapture(event.pointerId);
    145        }
    146      }
    147 
    148      let eventPromises = [
    149        promiseForEvent("pointerover", eventHandler),
    150        promiseForEvent("pointerenter", eventHandler),
    151        promiseForEvent("pointerdown", eventHandler),
    152        promiseForEvent("gotpointercapture", eventHandler),
    153        promiseForEvent("pointermove", eventHandler),
    154        promiseForEvent("lostpointercapture", eventHandler),
    155        promiseForEvent("pointerup", eventHandler),
    156        promiseForEvent("pointerout", eventHandler),
    157        promiseForEvent("pointerleave", eventHandler),
    158      ];
    159 
    160      synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource });
    161      synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource });
    162      synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource });
    163      synthesizeMouse(target1, 5, 5, { type: "mousemove", inputSource });
    164 
    165      await Promise.all(eventPromises);
    166    }
    167  }
    168 
    169  // A test for setPointerCapture() for only accepting spoofed pointer id.
    170  async function doTestForSetPointerCapture() {
    171    function eventHandler(event) {
    172      checkPointerEvent(event);
    173      if (event.type === "pointerdown") {
    174        try {
    175          target0.setPointerCapture(utils.DEFAULT_TOUCH_POINTER_ID);
    176          ok(false, "The setPointerCapture should fail here, but it is not.");
    177        } catch (e) {
    178          ok(true, "The setPointerCapture fails properly.");
    179        }
    180      }
    181    }
    182 
    183    let eventPromises = [
    184      promiseForEvent("pointerover", eventHandler),
    185      promiseForEvent("pointerenter", eventHandler),
    186      promiseForEvent("pointerdown", eventHandler),
    187      promiseForEvent("pointermove", eventHandler),
    188      promiseForEvent("pointerup", eventHandler),
    189      promiseForEvent("pointerout", eventHandler),
    190      promiseForEvent("pointerleave", eventHandler),
    191    ];
    192 
    193    synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_TOUCH });
    194    synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_TOUCH });
    195    synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_TOUCH });
    196 
    197    await Promise.all(eventPromises);
    198  }
    199 
    200  // A test for assuring that script generated events won't be spoofed.
    201  function doTestNoSpoofingForScriptGeneratedEvent() {
    202    return new Promise(resolve => {
    203      // Generate a custom pointer event by script.
    204      let pointerEventCustom = new PointerEvent("pointerover", {
    205        pointerId: utils.DEFAULT_TOUCH_POINTER_ID,
    206        pointerType: "touch",
    207        width: 5,
    208        height: 5,
    209        pressure: 0.75,
    210        tangentialPressure: 0.5,
    211        isPrimary: false,
    212      });
    213 
    214      target0.addEventListener("pointerover", (event) => {
    215        // Check that script generated event is not spoofed.
    216        is(event.pointerType, "touch", "The pointerEvent.pointerType is not spoofed.");
    217        is(event.width, 5, "The pointerEvent.width is not spoofed.");
    218        is(event.height, 5, "The pointerEvent.height is not spoofed.");
    219        is(event.pressure, 0.75, "The pointerEvent.pressure is not spoofed.");
    220        is(event.tangentialPressure, 0.5, "The pointerEvent.tangentialPressure is not spoofed.");
    221        is(event.isPrimary, false, "The pointerEvent.isPrimary is not spoofed.");
    222        resolve();
    223      }, { once: true });
    224 
    225      target0.dispatchEvent(pointerEventCustom);
    226    });
    227  }
    228 
    229  async function doTests() {
    230    await doTestForTouchPointerEvent();
    231    await doTestForTouchPointerCancelEvent();
    232    await doTestForPenPointerEvent();
    233    await doTestForPointerCapture();
    234    await doTestForSetPointerCapture();
    235    await doTestNoSpoofingForScriptGeneratedEvent();
    236 
    237    SimpleTest.finish();
    238  }
    239 
    240  SimpleTest.waitForFocus(() => {
    241    SpecialPowers.pushPrefEnv({"set": [["privacy.resistFingerprinting", true]]},
    242                              doTests);
    243  });
    244 
    245 </script>
    246 </body>
    247 </html>