E590 REGRESSION (252706@main): zillow.com shows a Recaptcha interstitial i… · WebKit/WebKit@5e4c680 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5e4c680

Browse files
committed
REGRESSION (252706@main): zillow.com shows a Recaptcha interstitial in private browsing mode
https://bugs.webkit.org/show_bug.cgi?id=250686 rdar://103905006 Reviewed by Youenn Fablet and Ben Nham. Currently, in private browsing mode (i.e. when using an ephemeral session) `Notification.permission` unconditionally returns `"denied"` (with `Notification.requestPermission` also unconditionally denying the request). However, the Permissions API (i.e. `navigator.permissions.query`) implements inconsistent behavior, and instead returns `"prompt"` in this scenario. On zillow.com, this causes a bot detection script to erroneously flag the UA as non-human in private browsing, and present interstitial Recaptcha UI to the user. Fix this by making the heuristics for "notifications" in `WebPageProxy::queryPermission` consistent with the Notifications API, such that in an ephemeral session, we return "default" or "prompt" unless the page has requested access (in which case we'll deny access, and then subsequently return "denied"). Test: http/tests/permissions/permission-state-for-notifications-in-ephemeral-session.html * LayoutTests/http/tests/permissions/permission-state-for-notifications-in-ephemeral-session-expected.txt: * LayoutTests/http/tests/permissions/permission-state-for-notifications-in-ephemeral-session.html: * LayoutTests/http/tests/push-api/permissions-ephemeral-expected.txt: * LayoutTests/http/tests/push-api/permissions-ephemeral.html: Rebaseline an existing layout test. * Source/WebKit/UIProcess/WebPageProxy.cpp: (WebKit::WebPageProxy::queryPermission): * Source/WebKit/WebProcess/WebCoreSupport/WebNotificationClient.cpp: (WebKit::WebNotificationClient::checkPermission): Canonical link: https://commits.webkit.org/259040@main
1 parent 7bee9f5 commit 5e4c680

File tree

6 files changed

+49
-8
lines changed

6 files changed

+49
-8
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
This test checks that Permissions::query() is consistent with Notification.permission in ephemeral sessions
2+
3+
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4+
5+
6+
PASS notificationState is "default"
7+
PASS permissionsState is "prompt"
8+
PASS successfullyParsed is true
9+
10+
TEST COMPLETE
11+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!-- webkit-test-runner [ useEphemeralSession=true ] -->
2+
<!DOCTYPE html>
3+
<html>
4+
<head>
5+
<script src="/resources/js-test-pre.js"></script>
6+
</head>
7+
<body>
8+
<script>
9+
description("This test checks that Permissions::query() is consistent with Notification.permission in ephemeral sessions");
10+
11+
jsTestIsAsync = true;
12+
13+
(async () => {
14+
notificationState = window?.Notification?.permission || "default";
15+
permissionsState = (await navigator.permissions.query({ name: "notifications" })).state;
16+
shouldBeEqualToString("notificationState", "default");
17+
shouldBeEqualToString("permissionsState", "prompt");
18+
finishJSTest();
19+
})();
20+
</script>
21+
<script src="/resources/js-test-post.js"></script>
22+
</body>
23+
</html>

LayoutTests/http/tests/push-api/permissions-ephemeral-expected.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
PASS: service worker permissionState was denied
2-
PASS: document permissionState was denied
1+
PASS: service worker permissionState was prompt
2+
PASS: document permissionState was prompt
33
PASS: service worker subscribe was error: NotAllowedError
44
PASS: document subscribe without user gesture was error: NotAllowedError
55
PASS: document subscribe with user gesture was error: NotAllowedError

LayoutTests/http/tests/push-api/permissions-ephemeral.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
navigator.serviceWorker.register("resources/subscribe-worker.js", { }).then(async (registration) => {
1515
try {
1616
await waitForState(registration.installing, "activated");
17-
await testServiceWorkerPermissionState(registration, 'denied');
18-
await testDocumentPermissionState(registration, 'denied');
17+
await testServiceWorkerPermissionState(registration, 'prompt');
18+
await testDocumentPermissionState(registration, 'prompt');
1919
await testServiceWorkerSubscribe(registration, 'NotAllowedError');
2020
await testDocumentSubscribeWithoutUserGesture(registration, 'NotAllowedError');
2121
await testDocumentSubscribeWithUserGesture(registration, 'NotAllowedError');

Source/WebKit/UIProcess/WebPageProxy.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9041,6 +9041,11 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi
90419041
// this topOrigin has requested permission to use the Notifications API previously.
90429042
if (m_notificationPermissionRequesters.contains(clientOrigin.topOrigin))
90439043
shouldChangeDeniedToPrompt = false;
9044+
9045+
if (sessionID().isEphemeral()) {
9046+
completionHandler(shouldChangeDeniedToPrompt ? PermissionState::Prompt : PermissionState::Denied);
9047+
return;
9048+
}
90449049
#endif
90459050
} else if (descriptor.name == PermissionName::ScreenWakeLock) {
90469051
name = "screen-wake-lock"_s;

Source/WebKit/WebProcess/WebCoreSupport/WebNotificationClient.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,23 +105,25 @@ void WebNotificationClient::requestPermission(ScriptExecutionContext& context, P
105105

106106
NotificationClient::Permission WebNotificationClient::checkPermission(ScriptExecutionContext* context)
107107
{
108-
if (!context
109-
|| (!context->isDocument() && !context->isServiceWorkerGlobalScope())
110-
|| WebProcess::singleton().sessionID().isEphemeral())
108+
if (!context || (!context->isDocument() && !context->isServiceWorkerGlobalScope()))
111109
return NotificationClient::Permission::Denied;
112110

113111
auto* origin = context->securityOrigin();
114112
if (!origin)
115113
return NotificationClient::Permission::Denied;
116114

115+
bool hasRequestedPermission = m_notificationPermissionRequesters.contains(origin->data());
116+
if (WebProcess::singleton().sessionID().isEphemeral())
117+
return hasRequestedPermission ? NotificationClient::Permission::Denied : NotificationClient::Permission::Default;
118+
117119
NotificationClient::Permission resultPermission;
118120
callOnMainRunLoopAndWait([&resultPermission, origin = origin->data().toString().isolatedCopy()] {
119121
resultPermission = WebProcess::singleton().supplement<WebNotificationManager>()->policyForOrigin(origin);
120122
});
121123

122124
// To reduce fingerprinting, if the origin has not requested permission to use the
123125
// Notifications API, and the permission state is "denied", return "default" instead.
124-
if (resultPermission == NotificationClient::Permission::Denied && !m_notificationPermissionRequesters.contains(context->securityOrigin()->data()))
126+
if (resultPermission == NotificationClient::Permission::Denied && !hasRequestedPermission)
125127
return NotificationClient::Permission::Default;
126128

127129
return resultPermission;

0 commit comments

Comments
 (0)
0