Skip to content
Permalink
Browse files
Permissions.query should return 'prompt' for unique origins
https://bugs.webkit.org/show_bug.cgi?id=244246
rdar://98990618

Reviewed by Chris Dumez.

Unique origins do not have a host so it is not useful to call the UI delegate to get the permission.
Instead, we do as if the delegate returns prompt.

Coverdd by added API test.

* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::isOriginUnique):
(WebKit::WebPageProxy::queryPermission):
* Tools/TestWebKitAPI/SourcesCocoa.txt:
* Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* Tools/TestWebKitAPI/Tests/WebKitCocoa/PermissionsAPI.mm: Added.
(-[PermissionsAPIMessageHandler userContentController:didReceiveScriptMessage:]):
(-[PermissionsAPIUIDelegate _webView:queryPermission:forOrigin:completionHandler:]):
(TestWebKitAPI::urlEncodeIfNeeded):
(TestWebKitAPI::TEST):
* Tools/TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm:

Canonical link: https://commits.webkit.org/253785@main
  • Loading branch information
youennf committed Aug 25, 2022
1 parent 07200d6 commit fde28e0775507976c3191182e0d854282e449538
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 3 deletions.
@@ -8840,6 +8840,12 @@ void WebPageProxy::revokeGeolocationAuthorizationToken(const String& authorizati
m_geolocationPermissionRequestManager.revokeAuthorizationToken(authorizationToken);
}

static bool isOriginUnique(const SecurityOriginData& origin)
{
ASSERT(!origin.isEmpty());
return origin.protocol == emptyString() && origin.host == emptyString() && !origin.port;
}

void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const PermissionDescriptor& descriptor, CompletionHandler<void(std::optional<PermissionState>, bool shouldCache)>&& completionHandler)
{
bool canAPISucceed = true;
@@ -8885,8 +8891,7 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi
return;
}

auto origin = API::SecurityOrigin::create(clientOrigin.topOrigin);
m_uiClient->queryPermission(name, origin, [clientOrigin, shouldChangeDeniedToPrompt, shouldChangePromptToGrant, completionHandler = WTFMove(completionHandler)](auto result) mutable {
CompletionHandler<void(std::optional<WebCore::PermissionState>)> callback = [clientOrigin, shouldChangeDeniedToPrompt, shouldChangePromptToGrant, completionHandler = WTFMove(completionHandler)](auto result) mutable {
if (!result) {
completionHandler({ }, false);
return;
@@ -8896,7 +8901,15 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi
else if (*result == PermissionState::Prompt && shouldChangePromptToGrant)
result = PermissionState::Granted;
completionHandler(*result, false);
});
};

if (isOriginUnique(clientOrigin.topOrigin)) {
callback(PermissionState::Prompt);
return;
}

auto origin = API::SecurityOrigin::create(clientOrigin.topOrigin);
m_uiClient->queryPermission(name, origin, WTFMove(callback));
}

#if ENABLE(MEDIA_STREAM)
@@ -189,6 +189,7 @@ Tests/WebKitCocoa/PasteImage.mm
Tests/WebKitCocoa/PasteMixedContent.mm
Tests/WebKitCocoa/PasteRTFD.mm
Tests/WebKitCocoa/PasteWebArchive.mm
Tests/WebKitCocoa/PermissionsAPI.mm
Tests/WebKitCocoa/PictureInPictureDelegate.mm
Tests/WebKitCocoa/Preconnect.mm
Tests/WebKitCocoa/Preferences.mm
@@ -2131,6 +2131,7 @@
4198524F27AD7B70005477B7 /* getUserMediaPermission.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = getUserMediaPermission.html; sourceTree = "<group>"; };
41BAF4E225AC9DB800D82F32 /* getUserMedia2.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = getUserMedia2.html; sourceTree = "<group>"; };
41E67A8425D16E83007B0A4C /* STUNMessageParsingTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = STUNMessageParsingTest.cpp; sourceTree = "<group>"; };
41E9EE1A28B4DBF8006A2298 /* PermissionsAPI.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PermissionsAPI.mm; sourceTree = "<group>"; };
41EBA9F128ABA06500953013 /* ImageRotationSessionVT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageRotationSessionVT.cpp; sourceTree = "<group>"; };
44077BB0231449D200179E2D /* DataDetectorsTestIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DataDetectorsTestIOS.mm; sourceTree = "<group>"; };
442BBF681C91CAD90017087F /* RefLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RefLogger.cpp; sourceTree = "<group>"; };
@@ -3777,6 +3778,7 @@
9B2346411F943A2400DB1D23 /* PasteWebArchive.mm */,
51D8C18F2267B26700797E40 /* PDFLinkReferrer.mm */,
516281262325C19100BB7E42 /* PDFSnapshot.mm */,
41E9EE1A28B4DBF8006A2298 /* PermissionsAPI.mm */,
3FCC4FE41EC4E8520076E37C /* PictureInPictureDelegate.mm */,
DFB8FF312492F51A00F00B0D /* Preconnect.mm */,
C95501BE19AD2FAF0049BE3E /* Preferences.mm */,
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

#import "config.h"

#import "TestWKWebView.h"
#import <wtf/text/StringBuilder.h>

static unsigned clientPermissionRequestCount;
static bool didReceiveMessage;
static bool didReceiveQueryPermission;
static bool isDone;

@interface PermissionsAPIMessageHandler : NSObject <WKScriptMessageHandler>
@end

@implementation PermissionsAPIMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
EXPECT_WK_STREQ([message body], @"prompt");
didReceiveMessage = true;
}
@end


@interface PermissionsAPIUIDelegate : NSObject<WKUIDelegate>
- (void)_webView:(WKWebView *)webView queryPermission:(NSString*) name forOrigin:(WKSecurityOrigin *)origin completionHandler:(void (^)(WKPermissionDecision state))completionHandler;
@end

@implementation PermissionsAPIUIDelegate
- (void)_webView:(WKWebView *)webView queryPermission:(NSString*) name forOrigin:(WKSecurityOrigin *)origin completionHandler:(void (^)(WKPermissionDecision state))completionHandler {
didReceiveQueryPermission = true;
completionHandler(WKPermissionDecisionDeny);
}
@end

namespace TestWebKitAPI {

static void urlEncodeIfNeeded(uint8_t byte, StringBuilder& buffer)
{
if (byte < '0' || (byte > '9' && byte < 'A') || (byte > 'Z' && byte < 'a') || byte > 'z') {
buffer.append('%');
buffer.append(upperNibbleToASCIIHexDigit(byte));
buffer.append(lowerNibbleToASCIIHexDigit(byte));
return;
}
buffer.append(byte);
}

TEST(PermissionsAPI, DataURL)
{
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
configuration.get()._allowTopNavigationToDataURLs = YES;
auto messageHandler = adoptNS([[PermissionsAPIMessageHandler alloc] init]);
[[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"msg"];

auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration.get()]);
auto delegate = adoptNS([[PermissionsAPIUIDelegate alloc] init]);
[webView setUIDelegate:delegate.get()];

isDone = false;
didReceiveMessage = false;
didReceiveQueryPermission = false;
char script[] = "<script>\
navigator.permissions.query({ name : 'geolocation' }).then((result) => { \
window.webkit.messageHandlers.msg.postMessage(result.state);\
}, () => { \
window.webkit.messageHandlers.msg.postMessage('FAIL');\
});\
</script>";

StringBuilder buffer;
buffer.append("data:text/html,");
for (size_t cptr = 0; cptr < sizeof(script) - 1; ++cptr)
urlEncodeIfNeeded(script[cptr], buffer);

auto request = [NSURLRequest requestWithURL:[NSURL URLWithString:buffer.toString()]];
[webView loadRequest:request];
TestWebKitAPI::Util::run(&didReceiveMessage);
EXPECT_FALSE(didReceiveQueryPermission);
}

} // namespace TestWebKitAPI
@@ -31,6 +31,7 @@
#import "TestNavigationDelegate.h"
#import "TestUIDelegate.h"
#import "TestWKWebView.h"
#import "WKWebViewConfigurationExtras.h"
#import <WebKit/WKContentWorld.h>
#import <WebKit/WKProcessPoolPrivate.h>
#import <WebKit/WKScriptMessage.h>

0 comments on commit fde28e0

Please sign in to comment.