247 lines
10 KiB
HTML
247 lines
10 KiB
HTML
<!DOCTYPE HTML>
|
|
<html>
|
|
<!--
|
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1363508
|
|
-->
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Test for Pointer Events spoofing</title>
|
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
|
</head>
|
|
<body>
|
|
<div id="target0" style="width: 50px; height: 50px; background: green"></div>
|
|
<div id="target1" style="width: 50px; height: 50px; background: black"></div>
|
|
<script type="application/javascript">
|
|
/** Test for Bug 1363508 */
|
|
SimpleTest.waitForExplicitFinish();
|
|
|
|
const { AppConstants } = SpecialPowers.ChromeUtils.importESModule(
|
|
"resource://gre/modules/AppConstants.sys.mjs"
|
|
);
|
|
|
|
var target0 = window.document.getElementById("target0");
|
|
var target1 = window.document.getElementById("target1");
|
|
var utils = SpecialPowers.Ci.nsIDOMWindowUtils;
|
|
|
|
// A helper function to check that whether the pointer is spoofed correctly.
|
|
function checkPointerEvent(aEvent) {
|
|
is(aEvent.width, 1, "The spoofed pointer event should always have width as 1.");
|
|
is(aEvent.height, 1, "The spoofed pointer event should always have width as 1.");
|
|
if (aEvent.buttons === 0) {
|
|
is(aEvent.pressure, 0.0,
|
|
"The spoofed pointer event should have pressure as 0.0 if it is not in a active buttons state.");
|
|
} else {
|
|
is(aEvent.pressure, 0.5,
|
|
"The spoofed pointer event should have pressure as 0.5 if it is in a active buttons state.");
|
|
}
|
|
is(aEvent.tangentialPressure, 0, "The spoofed pointer event should always have tangentialPressure as 0.");
|
|
is(aEvent.tiltX, 0, "The spoofed pointer event should always have tiltX as 0.");
|
|
is(aEvent.tiltY, 0, "The spoofed pointer event should always have tiltY as 0.");
|
|
is(aEvent.twist, 0, "The spoofed pointer event should always have twist as 0.");
|
|
if (AppConstants.platform == "macosx") {
|
|
is(aEvent.pointerId, utils.DEFAULT_MOUSE_POINTER_ID,
|
|
"The spoofed pointer event should always have the mouse pointer id.");
|
|
is(aEvent.pointerType, "mouse", "The spoofed pointer event should always has mouse pointerType.");
|
|
is(aEvent.isPrimary, true, "The spoofed pointer event should only receive primary pointer events.");
|
|
}
|
|
}
|
|
|
|
// A helper function to create a promise for waiting the event.
|
|
function promiseForEvent(aEventType, aCheckFunc) {
|
|
return new Promise(resolve => {
|
|
target0.addEventListener(aEventType, (event) => {
|
|
is(event.type, aEventType, "receive " + event.type + " on target0");
|
|
aCheckFunc(event);
|
|
resolve();
|
|
}, { once: true });
|
|
});
|
|
}
|
|
|
|
// A test for pointer events from touch interface.
|
|
async function doTestForTouchPointerEvent() {
|
|
let eventPromises = [
|
|
promiseForEvent("pointerover", checkPointerEvent),
|
|
promiseForEvent("pointerenter", checkPointerEvent),
|
|
promiseForEvent("pointerdown", checkPointerEvent),
|
|
promiseForEvent("pointermove", checkPointerEvent),
|
|
promiseForEvent("pointerup", checkPointerEvent),
|
|
promiseForEvent("pointerout", checkPointerEvent),
|
|
promiseForEvent("pointerleave", checkPointerEvent),
|
|
];
|
|
|
|
synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 });
|
|
synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 });
|
|
synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 });
|
|
|
|
await Promise.all(eventPromises);
|
|
}
|
|
|
|
// A test for pointercancel event.
|
|
async function doTestForTouchPointerCancelEvent() {
|
|
let eventPromises = [
|
|
promiseForEvent("pointerover", checkPointerEvent),
|
|
promiseForEvent("pointerenter", checkPointerEvent),
|
|
promiseForEvent("pointerdown", checkPointerEvent),
|
|
promiseForEvent("pointermove", checkPointerEvent),
|
|
promiseForEvent("pointercancel", checkPointerEvent),
|
|
promiseForEvent("pointerout", checkPointerEvent),
|
|
promiseForEvent("pointerleave", checkPointerEvent),
|
|
];
|
|
|
|
synthesizeTouch(target0, 5, 5, { type: "touchstart" });
|
|
synthesizeTouch(target0, 6, 6, { type: "touchmove" });
|
|
synthesizeTouch(target0, 6, 6, { type: "touchcancel" });
|
|
|
|
await Promise.all(eventPromises);
|
|
}
|
|
|
|
// A test for pointer events from pen interface.
|
|
async function doTestForPenPointerEvent() {
|
|
let eventPromises = [
|
|
promiseForEvent("pointerover", checkPointerEvent),
|
|
promiseForEvent("pointerenter", checkPointerEvent),
|
|
promiseForEvent("pointerdown", checkPointerEvent),
|
|
promiseForEvent("pointermove", checkPointerEvent),
|
|
promiseForEvent("pointerup", checkPointerEvent),
|
|
promiseForEvent("pointerout", checkPointerEvent),
|
|
promiseForEvent("pointerleave", checkPointerEvent),
|
|
];
|
|
|
|
synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_PEN });
|
|
synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_PEN });
|
|
synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_PEN });
|
|
synthesizeMouse(target1, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_PEN });
|
|
|
|
await Promise.all(eventPromises);
|
|
}
|
|
|
|
// A test for gotpointercapture and lostpointercapture events.
|
|
// We would also test releasePointerCapture for only accepting spoofed pointer
|
|
// Id here.
|
|
async function doTestForPointerCapture() {
|
|
// We test for both mouse and touch to see whether the capture events are
|
|
// filed properly. We don't check pen here since it won't file capture
|
|
// events.
|
|
let inputSources = [ MouseEvent.MOZ_SOURCE_MOUSE,
|
|
MouseEvent.MOZ_SOURCE_TOUCH ];
|
|
|
|
for (let inputSource of inputSources) {
|
|
function eventHandler(event) {
|
|
checkPointerEvent(event);
|
|
if (event.type === "pointerdown") {
|
|
target0.setPointerCapture(event.pointerId);
|
|
} else if (event.type === "pointermove") {
|
|
if (inputSource === MouseEvent.MOZ_SOURCE_TOUCH) {
|
|
try {
|
|
target0.releasePointerCapture(utils.DEFAULT_TOUCH_POINTER_ID);
|
|
ok(false, "The releasePointerCapture should fail here, but it is not.");
|
|
} catch (e) {
|
|
ok(true, "The releasePointerCapture fails properly.");
|
|
}
|
|
}
|
|
target0.releasePointerCapture(event.pointerId);
|
|
}
|
|
}
|
|
|
|
let eventPromises = [
|
|
promiseForEvent("pointerover", eventHandler),
|
|
promiseForEvent("pointerenter", eventHandler),
|
|
promiseForEvent("pointerdown", eventHandler),
|
|
promiseForEvent("gotpointercapture", eventHandler),
|
|
promiseForEvent("pointermove", eventHandler),
|
|
promiseForEvent("lostpointercapture", eventHandler),
|
|
promiseForEvent("pointerup", eventHandler),
|
|
promiseForEvent("pointerout", eventHandler),
|
|
promiseForEvent("pointerleave", eventHandler),
|
|
];
|
|
|
|
synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource });
|
|
synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource });
|
|
synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource });
|
|
synthesizeMouse(target1, 5, 5, { type: "mousemove", inputSource });
|
|
|
|
await Promise.all(eventPromises);
|
|
}
|
|
}
|
|
|
|
// A test for setPointerCapture() for only accepting spoofed pointer id.
|
|
async function doTestForSetPointerCapture() {
|
|
function eventHandler(event) {
|
|
checkPointerEvent(event);
|
|
if (event.type === "pointerdown") {
|
|
try {
|
|
target0.setPointerCapture(utils.DEFAULT_TOUCH_POINTER_ID);
|
|
ok(false, "The setPointerCapture should fail here, but it is not.");
|
|
} catch (e) {
|
|
ok(true, "The setPointerCapture fails properly.");
|
|
}
|
|
}
|
|
}
|
|
|
|
let eventPromises = [
|
|
promiseForEvent("pointerover", eventHandler),
|
|
promiseForEvent("pointerenter", eventHandler),
|
|
promiseForEvent("pointerdown", eventHandler),
|
|
promiseForEvent("pointermove", eventHandler),
|
|
promiseForEvent("pointerup", eventHandler),
|
|
promiseForEvent("pointerout", eventHandler),
|
|
promiseForEvent("pointerleave", eventHandler),
|
|
];
|
|
|
|
synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_TOUCH });
|
|
synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_TOUCH });
|
|
synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_TOUCH });
|
|
|
|
await Promise.all(eventPromises);
|
|
}
|
|
|
|
// A test for assuring that script generated events won't be spoofed.
|
|
function doTestNoSpoofingForScriptGeneratedEvent() {
|
|
return new Promise(resolve => {
|
|
// Generate a custom pointer event by script.
|
|
let pointerEventCustom = new PointerEvent("pointerover", {
|
|
pointerId: utils.DEFAULT_TOUCH_POINTER_ID,
|
|
pointerType: "touch",
|
|
width: 5,
|
|
height: 5,
|
|
pressure: 0.75,
|
|
tangentialPressure: 0.5,
|
|
isPrimary: false,
|
|
});
|
|
|
|
target0.addEventListener("pointerover", (event) => {
|
|
// Check that script generated event is not spoofed.
|
|
is(event.pointerType, "touch", "The pointerEvent.pointerType is not spoofed.");
|
|
is(event.width, 5, "The pointerEvent.width is not spoofed.");
|
|
is(event.height, 5, "The pointerEvent.height is not spoofed.");
|
|
is(event.pressure, 0.75, "The pointerEvent.pressure is not spoofed.");
|
|
is(event.tangentialPressure, 0.5, "The pointerEvent.tangentialPressure is not spoofed.");
|
|
is(event.isPrimary, false, "The pointerEvent.isPrimary is not spoofed.");
|
|
resolve();
|
|
}, { once: true });
|
|
|
|
target0.dispatchEvent(pointerEventCustom);
|
|
});
|
|
}
|
|
|
|
async function doTests() {
|
|
await doTestForTouchPointerEvent();
|
|
await doTestForTouchPointerCancelEvent();
|
|
await doTestForPenPointerEvent();
|
|
await doTestForPointerCapture();
|
|
await doTestForSetPointerCapture();
|
|
await doTestNoSpoofingForScriptGeneratedEvent();
|
|
|
|
SimpleTest.finish();
|
|
}
|
|
|
|
SimpleTest.waitForFocus(() => {
|
|
SpecialPowers.pushPrefEnv({"set": [["privacy.resistFingerprinting", true]]},
|
|
doTests);
|
|
});
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|