[Feature Policy] Introduce 'focus-without-user-activation'
The new policy can be used to disable automatic focus inside a frame; this would
include scripting such as element/window.focus() as well as 'autofocus'
attribute on editable elements.
TBR=rbyers@chromium.org
Bug: 954349
Change-Id: Ib2db7de78e1eefb2aa3174deeaf691d9f0c55c4d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1586103
Commit-Queue: Ehsan Karamad <ekaramad@chromium.org>
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Reviewed-by: Dave Tapuska <dtapuska@chromium.org>
Reviewed-by: Mustaq Ahmed <mustaq@chromium.org>
Reviewed-by: Ian Clelland <iclelland@chromium.org>
Reviewed-by: Ken Buchanan <kenrb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659105}
diff --git a/feature-policy/experimental-features/focus-without-user-activation-tentative.sub.html b/feature-policy/experimental-features/focus-without-user-activation-tentative.sub.html
new file mode 100644
index 0000000..ad90864
--- /dev/null
+++ b/feature-policy/experimental-features/focus-without-user-activation-tentative.sub.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/common.js"></script>
+<title> 'focus-without-user-activation' Policy : Correctly block automatic focus when policy disabled
+</title>
+<body>
+ <input onblur="did_blur();" autofocus/>
+<script>
+ "use strict"
+
+ const url = "http://{{hosts[alt][www1]}}:{{ports[http][0]}}/feature-policy/experimental-features/resources/focus_steal.html";
+
+ let did_blur_ = false;
+ function did_blur() {
+ did_blur_ = true;
+ }
+
+ function short_delay(test_instance) {
+ // Long enough to allow focus to propagate correctly.
+ const SHORT_DELAY = 400;
+ return new Promise( (r) => test_instance.step_timeout(r, SHORT_DELAY));
+ }
+
+ function reset_focus() {
+ did_blur_ = false;
+ document.querySelector("input").focus();
+ }
+
+ promise_test( async (instance) => {
+ const frame = createIframe(document.body, {
+ sandbox: "allow-scripts allow-same-origin",
+ allow: "focus-without-user-activation 'none'",
+ src: url
+ });
+ await wait_for_load(frame);
+
+ await short_delay(instance);
+ assert_false(did_blur_, "'autofocus' should not work.");
+
+ frame.contentWindow.postMessage("focus-input", "*");
+ await short_delay(instance);
+ assert_false(did_blur_, "'element.focus' should not work.");
+
+ frame.contentWindow.postMessage("focus-window", "*");
+ await short_delay(instance);
+ assert_false(did_blur_, "'window.focus' should not work.");
+ }, "When the policy is disabled, 'autofocus' and scripted focus do not focus " +
+ "the document.");
+
+
+ promise_test( async (instance) => {
+ const frame = createIframe(document.body, {
+ sandbox: "allow-scripts allow-same-origin",
+ allow: "focus-without-user-activation *",
+ src: url
+ });
+ await wait_for_load(frame);
+ await short_delay(instance);
+
+ reset_focus();
+ frame.contentWindow.postMessage("focus-input", "*");
+ await short_delay(instance);
+ assert_true(did_blur_, "'element.focus' should work.");
+ did_blur_ = false;
+
+ reset_focus();
+ frame.contentWindow.postMessage("focus-window", "*");
+ await short_delay(instance);
+ assert_true(did_blur_, "'window.focus' should work.");
+ }, "When the policy is enabled, 'autofocus' and scripted focus do focus " +
+ "the document.");
+</script>
+</body>
diff --git a/feature-policy/experimental-features/resources/focus_steal.html b/feature-policy/experimental-features/resources/focus_steal.html
new file mode 100644
index 0000000..43e8688
--- /dev/null
+++ b/feature-policy/experimental-features/resources/focus_steal.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<input autofocus/>
+<script>
+ window.addEventListener("message", (e) => {
+ if (e.data === "focus-window") {
+ window.focus();
+ }
+ else if (e.data === "focus-input") {
+ document.querySelector("input").focus();
+ }
+});
+</script>