Diff
Modified: trunk/LayoutTests/ChangeLog (251638 => 251639)
--- trunk/LayoutTests/ChangeLog 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/LayoutTests/ChangeLog 2019-10-26 20:50:40 UTC (rev 251639)
@@ -1,3 +1,15 @@
+2019-10-26 youenn fablet <[email protected]>
+
+ Enforce user gesture for getUserMedia in case a previous getUserMedia call was denied
+ https://bugs.webkit.org/show_bug.cgi?id=203362
+
+ Reviewed by Eric Carlson.
+
+ * fast/mediastream/getUserMedia-deny-persistency5-expected.txt:
+ * fast/mediastream/getUserMedia-deny-persistency5.html:
+ * fast/mediastream/screencapture-user-gesture-expected.txt:
+ * fast/mediastream/screencapture-user-gesture.html:
+
2019-10-26 Rob Buis <[email protected]>
Main implementation for lazy image loading
Added: trunk/LayoutTests/fast/mediastream/getUserMedia-deny-persistency5-expected.txt (0 => 251639)
--- trunk/LayoutTests/fast/mediastream/getUserMedia-deny-persistency5-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/mediastream/getUserMedia-deny-persistency5-expected.txt 2019-10-26 20:50:40 UTC (rev 251639)
@@ -0,0 +1,3 @@
+
+PASS Testing getUserMedia with and without user gesture after user denied access
+
Added: trunk/LayoutTests/fast/mediastream/getUserMedia-deny-persistency5.html (0 => 251639)
--- trunk/LayoutTests/fast/mediastream/getUserMedia-deny-persistency5.html (rev 0)
+++ trunk/LayoutTests/fast/mediastream/getUserMedia-deny-persistency5.html 2019-10-26 20:50:40 UTC (rev 251639)
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <script src=""
+ <script src=""
+ </head>
+ <body>
+ <script>
+promise_test(async (test) => {
+ if (window.testRunner)
+ testRunner.setUserMediaPermission(false);
+
+ await navigator.mediaDevices.getUserMedia({audio:false, video:true}).then(assert_unreached, (e) => { });
+ await navigator.mediaDevices.getUserMedia({audio:true, video:false}).then(assert_unreached, (e) => { });
+ await navigator.mediaDevices.getUserMedia({audio:true, video:true}).then(assert_unreached, (e) => { });
+
+ if (window.testRunner)
+ testRunner.setUserMediaPermission(true);
+
+ await navigator.mediaDevices.getUserMedia({audio:false, video:true}).then(assert_unreached, (e) => {
+ assert_equals(e.name, "NotAllowedError");
+ });
+
+ let promise;
+ internals.withUserGesture(() => {
+ promise = navigator.mediaDevices.getUserMedia({audio:false, video:true});
+ });
+ await promise;
+ internals.withUserGesture(() => {
+ promise = navigator.mediaDevices.getUserMedia({audio:true, video:false});
+ });
+ await promise;
+
+ internals.withUserGesture(() => {
+ promise = navigator.mediaDevices.getUserMedia({audio:true, video:true});
+ });
+ await promise;
+
+ await navigator.mediaDevices.getUserMedia({audio:false, video:true}).then(assert_unreached, (e) => { });
+ await navigator.mediaDevices.getUserMedia({audio:true, video:false}).then(assert_unreached, (e) => { });
+ await navigator.mediaDevices.getUserMedia({audio:true, video:true}).then(assert_unreached, (e) => { });
+}, "Testing getUserMedia with and without user gesture after user denied access");
+ </script>
+ </body>
+</html>
Modified: trunk/LayoutTests/fast/mediastream/screencapture-user-gesture-expected.txt (251638 => 251639)
--- trunk/LayoutTests/fast/mediastream/screencapture-user-gesture-expected.txt 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/LayoutTests/fast/mediastream/screencapture-user-gesture-expected.txt 2019-10-26 20:50:40 UTC (rev 251639)
@@ -1,4 +1,5 @@
PASS Allow getDisplayMedia call in case of user gesture
+PASS Disallow getDisplayMedia calls in case of user gesture if not the first call
PASS Deny getDisplayMedia call if no user gesture
Modified: trunk/LayoutTests/fast/mediastream/screencapture-user-gesture.html (251638 => 251639)
--- trunk/LayoutTests/fast/mediastream/screencapture-user-gesture.html 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/LayoutTests/fast/mediastream/screencapture-user-gesture.html 2019-10-26 20:50:40 UTC (rev 251639)
@@ -12,6 +12,21 @@
return promise;
}, "Allow getDisplayMedia call in case of user gesture");
+promise_test(() => {
+ let promise;
+ internals.withUserGesture(() => {
+ const promise1 = navigator.mediaDevices.getDisplayMedia({video : true});
+ const promise2 = navigator.mediaDevices.getDisplayMedia({video : true}).then(() => {
+ return Promise.reject("Second promise should reject");
+ }, () => {
+ return "Second promise rejected";
+ });
+ promise = Promise.all([promise1, promise2]);
+ });
+ return promise;
+}, "Disallow getDisplayMedia calls in case of user gesture if not the first call");
+
+
promise_test((test) => {
return promise_rejects(test, "InvalidAccessError", navigator.mediaDevices.getDisplayMedia({video : true}));
}, "Deny getDisplayMedia call if no user gesture");
Modified: trunk/Source/WebCore/ChangeLog (251638 => 251639)
--- trunk/Source/WebCore/ChangeLog 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/Source/WebCore/ChangeLog 2019-10-26 20:50:40 UTC (rev 251639)
@@ -1,3 +1,28 @@
+2019-10-26 youenn fablet <[email protected]>
+
+ Enforce user gesture for getUserMedia in case a previous getUserMedia call was denied
+ https://bugs.webkit.org/show_bug.cgi?id=203362
+
+ Reviewed by Eric Carlson.
+
+ Compute whether a media request is user priviledged or not.
+ It is priviledged if it is created as part of a user gesture and no request of the same type
+ has been previously created for the same user gesture.
+ If getDisplayMedia is called twice as part of a single user gesture, getDisplaMedia will reject for the second call.
+
+ Test: fast/mediastream/getUserMedia-deny-persistency5.html and updated test.
+
+ * Modules/mediastream/MediaDevices.cpp:
+ (WebCore::MediaDevices::computeUserGesturePriviledge):
+ (WebCore::MediaDevices::getUserMedia):
+ (WebCore::MediaDevices::getDisplayMedia):
+ (WebCore::MediaDevices::getUserMedia const): Deleted.
+ (WebCore::MediaDevices::getDisplayMedia const): Deleted.
+ * Modules/mediastream/MediaDevices.h:
+ * platform/mediastream/MediaStreamRequest.h:
+ (WebCore::MediaStreamRequest::encode const):
+ (WebCore::MediaStreamRequest::decode):
+
2019-10-26 Zalan Bujtas <[email protected]>
[LFC] Do not layout on every paint frame.
Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp (251638 => 251639)
--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp 2019-10-26 20:50:40 UTC (rev 251639)
@@ -41,6 +41,7 @@
#include "JSMediaDeviceInfo.h"
#include "MediaTrackSupportedConstraints.h"
#include "RealtimeMediaSourceSettings.h"
+#include "UserGestureIndicator.h"
#include "UserMediaController.h"
#include "UserMediaRequest.h"
#include <wtf/IsoMallocInlines.h>
@@ -104,8 +105,21 @@
);
}
-void MediaDevices::getUserMedia(const StreamConstraints& constraints, Promise&& promise) const
+bool MediaDevices::computeUserGesturePriviledge(GestureAllowedRequest requestType)
{
+ auto* currentGestureToken = UserGestureIndicator::currentUserGesture().get();
+ if (m_currentGestureToken != currentGestureToken) {
+ m_currentGestureToken = currentGestureToken;
+ m_requestTypesForCurrentGesture = { };
+ }
+
+ bool isUserGesturePriviledged = m_currentGestureToken && !m_requestTypesForCurrentGesture.contains(requestType);
+ m_requestTypesForCurrentGesture.add(requestType);
+ return isUserGesturePriviledged;
+}
+
+void MediaDevices::getUserMedia(const StreamConstraints& constraints, Promise&& promise)
+{
auto* document = this->document();
if (!document)
return;
@@ -112,25 +126,34 @@
auto audioConstraints = createMediaConstraints(constraints.audio);
auto videoConstraints = createMediaConstraints(constraints.video);
- if (videoConstraints.isValid)
+
+ bool isUserGesturePriviledged = false;
+
+ if (audioConstraints.isValid)
+ isUserGesturePriviledged |= computeUserGesturePriviledge(GestureAllowedRequest::Microphone);
+
+ if (videoConstraints.isValid) {
+ isUserGesturePriviledged |= computeUserGesturePriviledge(GestureAllowedRequest::Camera);
videoConstraints.setDefaultVideoConstraints();
+ }
- auto request = UserMediaRequest::create(*document, { MediaStreamRequest::Type::UserMedia, WTFMove(audioConstraints), WTFMove(videoConstraints) }, WTFMove(promise));
+ auto request = UserMediaRequest::create(*document, { MediaStreamRequest::Type::UserMedia, WTFMove(audioConstraints), WTFMove(videoConstraints), isUserGesturePriviledged }, WTFMove(promise));
request->start();
}
-void MediaDevices::getDisplayMedia(const StreamConstraints& constraints, Promise&& promise) const
+void MediaDevices::getDisplayMedia(const StreamConstraints& constraints, Promise&& promise)
{
auto* document = this->document();
if (!document)
return;
- if (!m_disableGetDisplayMediaUserGestureConstraint && !UserGestureIndicator::processingUserGesture()) {
+ bool isUserGesturePriviledged = computeUserGesturePriviledge(GestureAllowedRequest::Display);
+ if (!m_disableGetDisplayMediaUserGestureConstraint && !isUserGesturePriviledged) {
promise.reject(Exception { InvalidAccessError, "getDisplayMedia must be called from a user gesture handler."_s });
return;
}
- auto request = UserMediaRequest::create(*document, { MediaStreamRequest::Type::DisplayMedia, { }, createMediaConstraints(constraints.video) }, WTFMove(promise));
+ auto request = UserMediaRequest::create(*document, { MediaStreamRequest::Type::DisplayMedia, { }, createMediaConstraints(constraints.video), isUserGesturePriviledged }, WTFMove(promise));
request->start();
}
Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.h (251638 => 251639)
--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.h 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.h 2019-10-26 20:50:40 UTC (rev 251639)
@@ -49,6 +49,7 @@
class Document;
class MediaDeviceInfo;
class MediaStream;
+class UserGestureToken;
struct MediaTrackSupportedConstraints;
@@ -77,8 +78,8 @@
Variant<bool, MediaTrackConstraints> video;
Variant<bool, MediaTrackConstraints> audio;
};
- void getUserMedia(const StreamConstraints&, Promise&&) const;
- void getDisplayMedia(const StreamConstraints&, Promise&&) const;
+ void getUserMedia(const StreamConstraints&, Promise&&);
+ void getDisplayMedia(const StreamConstraints&, Promise&&);
void enumerateDevices(EnumerateDevicesPromise&&);
MediaTrackSupportedConstraints getSupportedConstraints();
@@ -109,6 +110,13 @@
void refEventTarget() final { ref(); }
void derefEventTarget() final { deref(); }
+ enum class GestureAllowedRequest {
+ Microphone = 1 << 0,
+ Camera = 1 << 1,
+ Display = 1 << 2,
+ };
+ bool computeUserGesturePriviledge(GestureAllowedRequest);
+
Timer m_scheduledEventTimer;
UserMediaClient::DeviceChangeObserverToken m_deviceChangeToken;
const EventNames& m_eventNames; // Need to cache this so we can use it from GC threads.
@@ -118,6 +126,9 @@
Vector<Ref<MediaDeviceInfo>> m_devices;
bool m_canAccessCamera { false };
bool m_canAccessMicrophone { false };
+
+ OptionSet<GestureAllowedRequest> m_requestTypesForCurrentGesture;
+ UserGestureToken* m_currentGestureToken { nullptr };
};
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/mediastream/MediaStreamRequest.h (251638 => 251639)
--- trunk/Source/WebCore/platform/mediastream/MediaStreamRequest.h 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/Source/WebCore/platform/mediastream/MediaStreamRequest.h 2019-10-26 20:50:40 UTC (rev 251639)
@@ -33,9 +33,10 @@
struct MediaStreamRequest {
enum class Type { UserMedia, DisplayMedia };
- Type type;
+ Type type { Type::UserMedia };
MediaConstraints audioConstraints;
MediaConstraints videoConstraints;
+ bool isUserGesturePriviledged { false };
template<class Encoder>
void encode(Encoder& encoder) const
@@ -43,12 +44,13 @@
encoder.encodeEnum(type);
encoder << audioConstraints;
encoder << videoConstraints;
+ encoder << isUserGesturePriviledged;
}
template <class Decoder> static Optional<MediaStreamRequest> decode(Decoder& decoder)
{
MediaStreamRequest request;
- if (decoder.decodeEnum(request.type) && decoder.decode(request.audioConstraints) && decoder.decode(request.videoConstraints))
+ if (decoder.decodeEnum(request.type) && decoder.decode(request.audioConstraints) && decoder.decode(request.videoConstraints) && decoder.decode(request.isUserGesturePriviledged))
return request;
return WTF::nullopt;
Modified: trunk/Source/WebKit/ChangeLog (251638 => 251639)
--- trunk/Source/WebKit/ChangeLog 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/Source/WebKit/ChangeLog 2019-10-26 20:50:40 UTC (rev 251639)
@@ -1,3 +1,17 @@
+2019-10-26 youenn fablet <[email protected]>
+
+ Enforce user gesture for getUserMedia in case a previous getUserMedia call was denied
+ https://bugs.webkit.org/show_bug.cgi?id=203362
+
+ Reviewed by Eric Carlson.
+
+ In case the request has user gesture priviledge, do not look at denied request history.
+
+ * UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
+ (WebKit::UserMediaPermissionRequestManagerProxy::getRequestAction):
+ * UIProcess/UserMediaPermissionRequestProxy.h:
+ (WebKit::UserMediaPermissionRequestProxy::isUserGesturePriviledged const):
+
2019-10-26 Chris Lord <[email protected]>
Put OffscreenCanvas behind a build flag
Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp (251638 => 251639)
--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp 2019-10-26 20:50:40 UTC (rev 251639)
@@ -345,7 +345,7 @@
ASSERT(!(requestingScreenCapture && !request.hasVideoDevice()));
ASSERT(!(requestingScreenCapture && requestingMicrophone));
- if (wasRequestDenied(request.frameID(), request.userMediaDocumentSecurityOrigin(), request.topLevelDocumentSecurityOrigin(), requestingMicrophone, requestingCamera, requestingScreenCapture))
+ if (!request.isUserGesturePriviledged() && wasRequestDenied(request.frameID(), request.userMediaDocumentSecurityOrigin(), request.topLevelDocumentSecurityOrigin(), requestingMicrophone, requestingCamera, requestingScreenCapture))
return RequestAction::Deny;
if (request.requestType() == MediaStreamRequest::Type::DisplayMedia)
Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h (251638 => 251639)
--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h 2019-10-26 20:50:40 UTC (rev 251639)
@@ -84,6 +84,8 @@
WebCore::CaptureDevice audioDevice() const { return m_eligibleAudioDevices.isEmpty() ? WebCore::CaptureDevice { } : m_eligibleAudioDevices[0]; }
WebCore::CaptureDevice videoDevice() const { return m_eligibleVideoDevices.isEmpty() ? WebCore::CaptureDevice { } : m_eligibleVideoDevices[0]; }
+ bool isUserGesturePriviledged() const { return m_request.isUserGesturePriviledged; }
+
private:
UserMediaPermissionRequestProxy(UserMediaPermissionRequestManagerProxy&, uint64_t userMediaID, WebCore::FrameIdentifier mainFrameID, WebCore::FrameIdentifier, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, WebCore::MediaStreamRequest&&);
Modified: trunk/Tools/ChangeLog (251638 => 251639)
--- trunk/Tools/ChangeLog 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/Tools/ChangeLog 2019-10-26 20:50:40 UTC (rev 251639)
@@ -1,3 +1,14 @@
+2019-10-26 youenn fablet <[email protected]>
+
+ Enforce user gesture for getUserMedia in case a previous getUserMedia call was denied
+ https://bugs.webkit.org/show_bug.cgi?id=203362
+
+ Reviewed by Eric Carlson.
+
+ Update test to take into account the ability to reask permission.
+ * TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMedia.mm:
+ (TestWebKitAPI::TEST_F):
+
2019-10-26 Chris Lord <[email protected]>
Put OffscreenCanvas behind a build flag
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMedia.mm (251638 => 251639)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMedia.mm 2019-10-26 19:16:18 UTC (rev 251638)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMedia.mm 2019-10-26 20:50:40 UTC (rev 251639)
@@ -180,8 +180,7 @@
shouldDeny = true;
promptForCapture(@"{ video: true }", false);
shouldDeny = false;
- promptForCapture(@"{ video: true }", false);
- promptForCapture(@"{ video: true }", false);
+ promptForCapture(@"{ video: true }", true);
}
} // namespace TestWebKitAPI