summaryrefslogtreecommitdiffstats
path: root/toolkit/components/satchel/test/test_bug_511615.html
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/satchel/test/test_bug_511615.html')
-rw-r--r--toolkit/components/satchel/test/test_bug_511615.html194
1 files changed, 194 insertions, 0 deletions
diff --git a/toolkit/components/satchel/test/test_bug_511615.html b/toolkit/components/satchel/test/test_bug_511615.html
new file mode 100644
index 000000000..66972d9b3
--- /dev/null
+++ b/toolkit/components/satchel/test/test_bug_511615.html
@@ -0,0 +1,194 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Form History Autocomplete Untrusted Events: Bug 511615</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="satchel_common.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+Test for Form History Autocomplete Untrusted Events: Bug 511615
+<p id="display"></p>
+
+<!-- we presumably can't hide the content for this test. -->
+<div id="content">
+ <!-- normal, basic form -->
+ <form id="form1" onsubmit="return false;">
+ <input type="text" name="field1">
+ <button type="submit">Submit</button>
+ </form>
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var resolvePopupShownListener;
+registerPopupShownListener(() => resolvePopupShownListener());
+
+function waitForNextPopup() {
+ return new Promise(resolve => { resolvePopupShownListener = resolve; });
+}
+
+/**
+ * Indicates the time to wait before checking that the state of the autocomplete
+ * popup, including whether it is open, has not changed in response to events.
+ *
+ * Manual testing on a fast machine revealed that 80ms was still unreliable,
+ * while 100ms detected a simulated failure reliably. Unfortunately, this means
+ * that to take into account slower machines we should use a larger value.
+ *
+ * Note that if a machine takes more than this time to show the popup, this
+ * would not cause a failure, conversely the machine would not be able to detect
+ * whether the test should have failed. In other words, this use of timeouts is
+ * never expected to cause intermittent failures with test automation.
+ */
+const POPUP_RESPONSE_WAIT_TIME_MS = 200;
+
+SimpleTest.requestFlakyTimeout("Must ensure that an event does not happen.");
+
+/**
+ * Checks that the popup does not open in response to the given function.
+ */
+function expectPopupDoesNotOpen(triggerFn) {
+ let popupShown = waitForNextPopup();
+ triggerFn();
+ return Promise.race([
+ popupShown.then(() => Promise.reject("Popup opened unexpectedly.")),
+ new Promise(resolve => setTimeout(resolve, POPUP_RESPONSE_WAIT_TIME_MS)),
+ ]);
+}
+
+/**
+ * Checks that the selected index in the popup still matches the given value.
+ */
+function checkSelectedIndexAfterResponseTime(expectedIndex) {
+ return new Promise(resolve => {
+ setTimeout(() => getPopupState(resolve), POPUP_RESPONSE_WAIT_TIME_MS);
+ }).then(popupState => {
+ is(popupState.open, true, "Popup should still be open.");
+ is(popupState.selectedIndex, expectedIndex, "Selected index should match.");
+ });
+}
+
+function doKeyUnprivileged(key) {
+ let keyName = "DOM_VK_" + key.toUpperCase();
+ let keycode, charcode;
+
+ if (key.length == 1) {
+ keycode = 0;
+ charcode = key.charCodeAt(0);
+ alwaysval = charcode;
+ } else {
+ keycode = KeyEvent[keyName];
+ if (!keycode)
+ throw "invalid keyname in test";
+ charcode = 0;
+ alwaysval = keycode;
+ }
+
+ let dnEvent = document.createEvent('KeyboardEvent');
+ let prEvent = document.createEvent('KeyboardEvent');
+ let upEvent = document.createEvent('KeyboardEvent');
+
+ dnEvent.initKeyEvent("keydown", true, true, null, false, false, false, false, alwaysval, 0);
+ prEvent.initKeyEvent("keypress", true, true, null, false, false, false, false, keycode, charcode);
+ upEvent.initKeyEvent("keyup", true, true, null, false, false, false, false, alwaysval, 0);
+
+ input.dispatchEvent(dnEvent);
+ input.dispatchEvent(prEvent);
+ input.dispatchEvent(upEvent);
+}
+
+function doClickWithMouseEventUnprivileged() {
+ let dnEvent = document.createEvent('MouseEvent');
+ let upEvent = document.createEvent('MouseEvent');
+ let ckEvent = document.createEvent('MouseEvent');
+
+ dnEvent.initMouseEvent("mousedown", true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
+ upEvent.initMouseEvent("mouseup", true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
+ ckEvent.initMouseEvent("mouseclick", true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
+
+ input.dispatchEvent(dnEvent);
+ input.dispatchEvent(upEvent);
+ input.dispatchEvent(ckEvent);
+}
+
+let input = $_(1, "field1");
+
+add_task(function* test_initialize() {
+ yield new Promise(resolve => updateFormHistory([
+ { op : "remove" },
+ { op : "add", fieldname : "field1", value : "value1" },
+ { op : "add", fieldname : "field1", value : "value2" },
+ { op : "add", fieldname : "field1", value : "value3" },
+ { op : "add", fieldname : "field1", value : "value4" },
+ { op : "add", fieldname : "field1", value : "value5" },
+ { op : "add", fieldname : "field1", value : "value6" },
+ { op : "add", fieldname : "field1", value : "value7" },
+ { op : "add", fieldname : "field1", value : "value8" },
+ { op : "add", fieldname : "field1", value : "value9" },
+ ], resolve));
+});
+
+add_task(function* test_untrusted_events_ignored() {
+ // The autocomplete popup should not open from untrusted events.
+ for (let triggerFn of [
+ () => input.focus(),
+ () => input.click(),
+ () => doClickWithMouseEventUnprivileged(),
+ () => doKeyUnprivileged("down"),
+ () => doKeyUnprivileged("page_down"),
+ () => doKeyUnprivileged("return"),
+ () => doKeyUnprivileged("v"),
+ () => doKeyUnprivileged(" "),
+ () => doKeyUnprivileged("back_space"),
+ ]) {
+ // We must wait for the entire timeout for each individual test, because the
+ // next event in the list might prevent the popup from opening.
+ yield expectPopupDoesNotOpen(triggerFn);
+ }
+
+ // A privileged key press will actually open the popup.
+ let popupShown = waitForNextPopup();
+ doKey("down");
+ yield popupShown;
+
+ // The selected autocomplete item should not change from untrusted events.
+ for (let triggerFn of [
+ () => doKeyUnprivileged("down"),
+ () => doKeyUnprivileged("page_down"),
+ ]) {
+ triggerFn();
+ yield checkSelectedIndexAfterResponseTime(-1);
+ }
+
+ // A privileged key press will actually change the selected index.
+ let indexChanged = new Promise(resolve => notifySelectedIndex(0, resolve));
+ doKey("down");
+ yield indexChanged;
+
+ // The selected autocomplete item should not change and it should not be
+ // possible to use it from untrusted events.
+ for (let triggerFn of [
+ () => doKeyUnprivileged("down"),
+ () => doKeyUnprivileged("page_down"),
+ () => doKeyUnprivileged("right"),
+ () => doKeyUnprivileged(" "),
+ () => doKeyUnprivileged("back_space"),
+ () => doKeyUnprivileged("back_space"),
+ () => doKeyUnprivileged("return"),
+ ]) {
+ triggerFn();
+ yield checkSelectedIndexAfterResponseTime(0);
+ is(input.value, "", "The selected item should not have been used.");
+ }
+
+ // Close the popup.
+ input.blur();
+});
+</script>
+</pre>
+</body>
+</html>