Commit 3adbed21 authored by Mikhail Pozdnyakov's avatar Mikhail Pozdnyakov Committed by Commit Bot

[DeviceOrientation]Blink-side Feature Policy check

DeviceSingleWindowEventController::DidAddEventListener() is not
called if {deviceorientation|deviceorientationabsolute|devicemotion}
events are blocked by feature policy.

A console message referencing to
https://github.com/WICG/feature-policy/blob/gh-pages/features.md
is send to warn the user.

Bug: 796894
Change-Id: I350ff75ca55766b7ebb42944d66470ecd2b8a4c1
Reviewed-on: https://chromium-review.googlesource.com/870510Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarTim Volodine <timvolodine@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Commit-Queue: Mikhail Pozdnyakov <mikhail.pozdnyakov@intel.com>
Cr-Commit-Position: refs/heads/master@{#532384}
parent 4c7ec5bf
...@@ -472,8 +472,8 @@ IN_PROC_BROWSER_TEST_F(DeviceSensorBrowserTest, ...@@ -472,8 +472,8 @@ IN_PROC_BROWSER_TEST_F(DeviceSensorBrowserTest,
// Main frame is on a.com, iframe is on b.com. // Main frame is on a.com, iframe is on b.com.
GURL main_frame_url = GURL main_frame_url =
https_embedded_test_server_->GetURL("a.com", "/cross_origin_iframe.html"); https_embedded_test_server_->GetURL("a.com", "/cross_origin_iframe.html");
GURL iframe_url = GURL iframe_url = https_embedded_test_server_->GetURL(
https_embedded_test_server_->GetURL("b.com", "/device_motion_test.html"); "b.com", "/device_motion_test.html?failure_timeout=100");
// Wait for the main frame, subframe, and the #pass/#fail commits. // Wait for the main frame, subframe, and the #pass/#fail commits.
TestNavigationObserver navigation_observer(shell()->web_contents(), 3); TestNavigationObserver navigation_observer(shell()->web_contents(), 3);
...@@ -523,7 +523,7 @@ IN_PROC_BROWSER_TEST_F(DeviceSensorBrowserTest, ...@@ -523,7 +523,7 @@ IN_PROC_BROWSER_TEST_F(DeviceSensorBrowserTest,
GURL main_frame_url = GURL main_frame_url =
https_embedded_test_server_->GetURL("a.com", "/cross_origin_iframe.html"); https_embedded_test_server_->GetURL("a.com", "/cross_origin_iframe.html");
GURL iframe_url = https_embedded_test_server_->GetURL( GURL iframe_url = https_embedded_test_server_->GetURL(
"b.com", "/device_orientation_test.html"); "b.com", "/device_orientation_test.html?failure_timeout=100");
// Wait for the main frame, subframe, and the #pass/#fail commits. // Wait for the main frame, subframe, and the #pass/#fail commits.
TestNavigationObserver navigation_observer(shell()->web_contents(), 3); TestNavigationObserver navigation_observer(shell()->web_contents(), 3);
...@@ -567,6 +567,32 @@ IN_PROC_BROWSER_TEST_F(DeviceSensorBrowserTest, ...@@ -567,6 +567,32 @@ IN_PROC_BROWSER_TEST_F(DeviceSensorBrowserTest,
EXPECT_EQ("pass", iframe->GetLastCommittedURL().ref()); EXPECT_EQ("pass", iframe->GetLastCommittedURL().ref());
} }
IN_PROC_BROWSER_TEST_F(DeviceSensorBrowserTest,
DeviceOrientationFeaturePolicyWarning) {
// Main frame is on a.com, iframe is on b.com.
GURL main_frame_url =
https_embedded_test_server_->GetURL("a.com", "/cross_origin_iframe.html");
GURL iframe_url = https_embedded_test_server_->GetURL(
"b.com", "/device_orientation_absolute_test.html");
const char kWarningMessage[] =
"The deviceorientationabsolute events are blocked by "
"feature policy. See "
"https://github.com/WICG/feature-policy/blob/"
"gh-pages/features.md#sensor-features";
auto console_delegate = std::make_unique<ConsoleObserverDelegate>(
shell()->web_contents(), kWarningMessage);
shell()->web_contents()->SetDelegate(console_delegate.get());
EXPECT_TRUE(NavigateToURL(shell(), main_frame_url));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(),
"cross_origin_iframe", iframe_url));
console_delegate->Wait();
EXPECT_EQ(kWarningMessage, console_delegate->message());
}
} // namespace } // namespace
} // namespace content } // namespace content
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
<head> <head>
<title>DeviceMotion test</title> <title>DeviceMotion test</title>
<script type="text/javascript"> <script type="text/javascript">
let expectedInterval = Math.floor(1000 / 60); const expectedInterval = Math.floor(1000 / 60);
let kRadiansToDegrees = 180 / Math.PI; const kRadiansToDegrees = 180 / Math.PI;
let eventTimeoutId; // To be set in start().
function checkMotionEvent(event) { function checkMotionEvent(event) {
return event.acceleration.x == 1 && return event.acceleration.x == 1 &&
event.acceleration.y == 2 && event.acceleration.y == 2 &&
...@@ -20,6 +22,7 @@ ...@@ -20,6 +22,7 @@
function onMotion(event) { function onMotion(event) {
if (checkMotionEvent(event)) { if (checkMotionEvent(event)) {
window.removeEventListener('devicemotion', onMotion); window.removeEventListener('devicemotion', onMotion);
window.clearTimeout(eventTimeoutId);
pass(); pass();
} else { } else {
fail(); fail();
...@@ -34,9 +37,21 @@ ...@@ -34,9 +37,21 @@
function fail() { function fail() {
document.location = '#fail'; document.location = '#fail';
} }
function failOnTimeoutIfNeeded() {
let params = new URLSearchParams(location.search);
let timeout = Number(params.get("failure_timeout"));
if (timeout > 0)
eventTimeoutId = window.setTimeout(fail, timeout);
}
function start() {
window.addEventListener('devicemotion', onMotion);
failOnTimeoutIfNeeded();
}
</script> </script>
</head> </head>
<body onLoad="window.addEventListener('devicemotion', onMotion)"> <body onLoad="start()">
<div id="status">FAIL</div> <div id="status">FAIL</div>
</body> </body>
</html> </html>
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
<head> <head>
<title>DeviceOrientation test</title> <title>DeviceOrientation test</title>
<script type="text/javascript"> <script type="text/javascript">
let eventTimeoutId; // To be set in start().
function checkOrientationEvent(event) { function checkOrientationEvent(event) {
// Return true iff the orientation is close enough to (1, 2, 3). // Return true iff the orientation is close enough to (1, 2, 3).
return Math.abs(event.alpha - 1) < 0.01 && return Math.abs(event.alpha - 1) < 0.01 &&
...@@ -13,6 +15,7 @@ ...@@ -13,6 +15,7 @@
function onOrientation(event) { function onOrientation(event) {
if (checkOrientationEvent(event)) { if (checkOrientationEvent(event)) {
window.removeEventListener('deviceorientation', onOrientation); window.removeEventListener('deviceorientation', onOrientation);
window.clearTimeout(eventTimeoutId);
pass(); pass();
} else { } else {
fail(); fail();
...@@ -27,9 +30,21 @@ ...@@ -27,9 +30,21 @@
function fail() { function fail() {
document.location = '#fail'; document.location = '#fail';
} }
function failOnTimeoutIfNeeded() {
let params = new URLSearchParams(location.search);
let timeout = Number(params.get("failure_timeout"));
if (timeout > 0)
eventTimeoutId = window.setTimeout(fail, timeout);
}
function start() {
window.addEventListener('deviceorientation', onOrientation);
failOnTimeoutIfNeeded();
}
</script> </script>
</head> </head>
<body onLoad="window.addEventListener('deviceorientation', onOrientation)"> <body onLoad="start()">
<div id="status">FAIL</div> <div id="status">FAIL</div>
</body> </body>
</html> </html>
...@@ -90,6 +90,17 @@ bool DeviceSingleWindowEventController::IsSameSecurityOriginAsMainFrame() ...@@ -90,6 +90,17 @@ bool DeviceSingleWindowEventController::IsSameSecurityOriginAsMainFrame()
return false; return false;
} }
bool DeviceSingleWindowEventController::CheckPolicyFeatures(
const Vector<FeaturePolicyFeature>& features) const {
LocalFrame* frame = GetDocument().GetFrame();
if (!frame)
return false;
return std::all_of(features.begin(), features.end(),
[frame](FeaturePolicyFeature feature) {
return frame->IsFeatureEnabled(feature);
});
}
void DeviceSingleWindowEventController::Trace(blink::Visitor* visitor) { void DeviceSingleWindowEventController::Trace(blink::Visitor* visitor) {
visitor->Trace(document_); visitor->Trace(document_);
PlatformEventController::Trace(visitor); PlatformEventController::Trace(visitor);
......
...@@ -36,6 +36,7 @@ class CORE_EXPORT DeviceSingleWindowEventController ...@@ -36,6 +36,7 @@ class CORE_EXPORT DeviceSingleWindowEventController
Document& GetDocument() const { return *document_; } Document& GetDocument() const { return *document_; }
bool IsSameSecurityOriginAsMainFrame() const; bool IsSameSecurityOriginAsMainFrame() const;
bool CheckPolicyFeatures(const Vector<FeaturePolicyFeature>& features) const;
void DispatchDeviceEvent(Event*); void DispatchDeviceEvent(Event*);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "modules/device_orientation/DeviceMotionData.h" #include "modules/device_orientation/DeviceMotionData.h"
#include "modules/device_orientation/DeviceMotionDispatcher.h" #include "modules/device_orientation/DeviceMotionDispatcher.h"
#include "modules/device_orientation/DeviceMotionEvent.h" #include "modules/device_orientation/DeviceMotionEvent.h"
#include "modules/device_orientation/DeviceOrientationController.h"
#include "platform/weborigin/SecurityOrigin.h" #include "platform/weborigin/SecurityOrigin.h"
#include "public/platform/Platform.h" #include "public/platform/Platform.h"
...@@ -42,20 +43,17 @@ void DeviceMotionController::DidAddEventListener( ...@@ -42,20 +43,17 @@ void DeviceMotionController::DidAddEventListener(
if (event_type != EventTypeName()) if (event_type != EventTypeName())
return; return;
if (GetDocument().GetFrame()) { LocalFrame* frame = GetDocument().GetFrame();
if (frame) {
if (GetDocument().IsSecureContext()) { if (GetDocument().IsSecureContext()) {
UseCounter::Count(GetDocument().GetFrame(), UseCounter::Count(frame, WebFeature::kDeviceMotionSecureOrigin);
WebFeature::kDeviceMotionSecureOrigin);
} else { } else {
Deprecation::CountDeprecation(GetDocument().GetFrame(), Deprecation::CountDeprecation(frame,
WebFeature::kDeviceMotionInsecureOrigin); WebFeature::kDeviceMotionInsecureOrigin);
HostsUsingFeatures::CountAnyWorld( HostsUsingFeatures::CountAnyWorld(
GetDocument(), GetDocument(),
HostsUsingFeatures::Feature::kDeviceMotionInsecureHost); HostsUsingFeatures::Feature::kDeviceMotionInsecureHost);
if (GetDocument() if (frame->GetSettings()->GetStrictPowerfulFeatureRestrictions())
.GetFrame()
->GetSettings()
->GetStrictPowerfulFeatureRestrictions())
return; return;
} }
} }
...@@ -68,6 +66,13 @@ void DeviceMotionController::DidAddEventListener( ...@@ -68,6 +66,13 @@ void DeviceMotionController::DidAddEventListener(
Platform::Current()->RecordRapporURL( Platform::Current()->RecordRapporURL(
"DeviceSensors.DeviceMotionCrossOrigin", WebURL(GetDocument().Url())); "DeviceSensors.DeviceMotionCrossOrigin", WebURL(GetDocument().Url()));
} }
if (!CheckPolicyFeatures({FeaturePolicyFeature::kAccelerometer,
FeaturePolicyFeature::kGyroscope})) {
DeviceOrientationController::LogToConsolePolicyFeaturesDisabled(
frame, EventTypeName());
return;
}
} }
DeviceSingleWindowEventController::DidAddEventListener(window, event_type); DeviceSingleWindowEventController::DidAddEventListener(window, event_type);
......
...@@ -41,25 +41,31 @@ void DeviceOrientationAbsoluteController::DidAddEventListener( ...@@ -41,25 +41,31 @@ void DeviceOrientationAbsoluteController::DidAddEventListener(
if (event_type != EventTypeName()) if (event_type != EventTypeName())
return; return;
if (GetDocument().GetFrame()) { LocalFrame* frame = GetDocument().GetFrame();
if (frame) {
if (GetDocument().IsSecureContext()) { if (GetDocument().IsSecureContext()) {
UseCounter::Count(GetDocument().GetFrame(), UseCounter::Count(frame,
WebFeature::kDeviceOrientationAbsoluteSecureOrigin); WebFeature::kDeviceOrientationAbsoluteSecureOrigin);
} else { } else {
Deprecation::CountDeprecation( Deprecation::CountDeprecation(
GetDocument().GetFrame(), frame, WebFeature::kDeviceOrientationAbsoluteInsecureOrigin);
WebFeature::kDeviceOrientationAbsoluteInsecureOrigin);
// TODO: add rappor logging of insecure origins as in // TODO: add rappor logging of insecure origins as in
// DeviceOrientationController. // DeviceOrientationController.
if (GetDocument() if (frame->GetSettings()->GetStrictPowerfulFeatureRestrictions())
.GetFrame()
->GetSettings()
->GetStrictPowerfulFeatureRestrictions())
return; return;
} }
} }
// TODO: add rappor url logging as in DeviceOrientationController. if (!has_event_listener_) {
// TODO: add rappor url logging as in DeviceOrientationController.
if (!CheckPolicyFeatures({FeaturePolicyFeature::kAccelerometer,
FeaturePolicyFeature::kGyroscope,
FeaturePolicyFeature::kMagnetometer})) {
LogToConsolePolicyFeaturesDisabled(frame, EventTypeName());
return;
}
}
DeviceSingleWindowEventController::DidAddEventListener(window, event_type); DeviceSingleWindowEventController::DidAddEventListener(window, event_type);
} }
......
...@@ -5,12 +5,15 @@ ...@@ -5,12 +5,15 @@
#include "modules/device_orientation/DeviceOrientationController.h" #include "modules/device_orientation/DeviceOrientationController.h"
#include "core/frame/Deprecation.h" #include "core/frame/Deprecation.h"
#include "core/frame/FrameConsole.h"
#include "core/frame/HostsUsingFeatures.h" #include "core/frame/HostsUsingFeatures.h"
#include "core/frame/Settings.h" #include "core/frame/Settings.h"
#include "core/inspector/ConsoleMessage.h"
#include "modules/EventModules.h" #include "modules/EventModules.h"
#include "modules/device_orientation/DeviceOrientationData.h" #include "modules/device_orientation/DeviceOrientationData.h"
#include "modules/device_orientation/DeviceOrientationDispatcher.h" #include "modules/device_orientation/DeviceOrientationDispatcher.h"
#include "modules/device_orientation/DeviceOrientationEvent.h" #include "modules/device_orientation/DeviceOrientationEvent.h"
#include "platform/feature_policy/FeaturePolicy.h"
#include "platform/weborigin/SecurityOrigin.h" #include "platform/weborigin/SecurityOrigin.h"
#include "platform/wtf/Assertions.h" #include "platform/wtf/Assertions.h"
#include "public/platform/Platform.h" #include "public/platform/Platform.h"
...@@ -51,14 +54,13 @@ void DeviceOrientationController::DidAddEventListener( ...@@ -51,14 +54,13 @@ void DeviceOrientationController::DidAddEventListener(
if (event_type != EventTypeName()) if (event_type != EventTypeName())
return; return;
if (GetDocument().GetFrame()) { LocalFrame* frame = GetDocument().GetFrame();
if (frame) {
if (GetDocument().IsSecureContext()) { if (GetDocument().IsSecureContext()) {
UseCounter::Count(GetDocument().GetFrame(), UseCounter::Count(frame, WebFeature::kDeviceOrientationSecureOrigin);
WebFeature::kDeviceOrientationSecureOrigin);
} else { } else {
Deprecation::CountDeprecation( Deprecation::CountDeprecation(
GetDocument().GetFrame(), frame, WebFeature::kDeviceOrientationInsecureOrigin);
WebFeature::kDeviceOrientationInsecureOrigin);
HostsUsingFeatures::CountAnyWorld( HostsUsingFeatures::CountAnyWorld(
GetDocument(), GetDocument(),
HostsUsingFeatures::Feature::kDeviceOrientationInsecureHost); HostsUsingFeatures::Feature::kDeviceOrientationInsecureHost);
...@@ -79,6 +81,12 @@ void DeviceOrientationController::DidAddEventListener( ...@@ -79,6 +81,12 @@ void DeviceOrientationController::DidAddEventListener(
"DeviceSensors.DeviceOrientationCrossOrigin", "DeviceSensors.DeviceOrientationCrossOrigin",
WebURL(GetDocument().Url())); WebURL(GetDocument().Url()));
} }
if (!CheckPolicyFeatures({FeaturePolicyFeature::kAccelerometer,
FeaturePolicyFeature::kGyroscope})) {
LogToConsolePolicyFeaturesDisabled(frame, EventTypeName());
return;
}
} }
DeviceSingleWindowEventController::DidAddEventListener(window, event_type); DeviceSingleWindowEventController::DidAddEventListener(window, event_type);
...@@ -141,4 +149,21 @@ void DeviceOrientationController::Trace(blink::Visitor* visitor) { ...@@ -141,4 +149,21 @@ void DeviceOrientationController::Trace(blink::Visitor* visitor) {
Supplement<Document>::Trace(visitor); Supplement<Document>::Trace(visitor);
} }
// static
void DeviceOrientationController::LogToConsolePolicyFeaturesDisabled(
LocalFrame* frame,
const AtomicString& event_name) {
if (!frame)
return;
const String& message = String::Format(
"The %s events are blocked by feature policy. "
"See "
"https://github.com/WICG/feature-policy/blob/gh-pages/"
"features.md#sensor-features",
event_name.Ascii().data());
ConsoleMessage* console_message = ConsoleMessage::Create(
kJSMessageSource, kWarningMessageLevel, std::move(message));
frame->Console().AddMessage(console_message);
}
} // namespace blink } // namespace blink
...@@ -35,6 +35,10 @@ class MODULES_EXPORT DeviceOrientationController ...@@ -35,6 +35,10 @@ class MODULES_EXPORT DeviceOrientationController
virtual void Trace(blink::Visitor*); virtual void Trace(blink::Visitor*);
static void LogToConsolePolicyFeaturesDisabled(
LocalFrame*,
const AtomicString& event_name);
protected: protected:
explicit DeviceOrientationController(Document&); explicit DeviceOrientationController(Document&);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment