Title: [251639] trunk
Revision
251639
Author
[email protected]
Date
2019-10-26 13:50:40 -0700 (Sat, 26 Oct 2019)

Log Message

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.

Source/WebCore:

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):

Source/WebKit:

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):

Tools:

Update test to take into account the ability to reask permission.
* TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMedia.mm:
(TestWebKitAPI::TEST_F):

LayoutTests:

* 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:

Modified Paths

Added Paths

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
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to