summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaloyan Chehlarski <kaloyan.chehlarski@qt.io>2025-03-19 10:48:31 +0100
committerKaloyan Chehlarski <kaloyan.chehlarski@qt.io>2025-08-20 15:06:23 +0200
commitbbbe5014e51d2b2c7abce1e63cc971713f9b2540 (patch)
treec29ac36122e0e7528e0cebb80adcc0a6776dd83d
parent4dfc6e4598310641b94a9c16764d2561883f1046 (diff)
Associate permissions with frames
Previously, permisions were associated with the originating WebContents, as the PermissionManager API uses those in its function calls. This is insufficient, however, as it results in iframes not receiving the correct permissions (because they were instead granted to the root frame instead. This change modifies the internals of PermissionManagerQt to use GlobalRenderFrameHostTokens, and modifies relevant functions across the codebase to pass those around instead of WebContents. Media and mouse lock permissions now also query the permission manager before issuing a request, which avoids some cases of the same request being sent multiple times in a row. As a side effect, the behavior of non-persistent permissions (as well as the behavior of ALL permissions when running in AskEveryTime mode) is standardized so that a permission is remembered as long as the associated frame is alive. Fixes: QTBUG-134637 Fixes: QTBUG-135787 Pick-to: 6.10 6.9 Change-Id: I650e3328ef3830d06206acafc3305566d3a10d86 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--src/core/api/qwebenginepage.cpp79
-rw-r--r--src/core/api/qwebenginepage_p.h6
-rw-r--r--src/core/api/qwebenginepermission.cpp39
-rw-r--r--src/core/api/qwebenginepermission_p.h6
-rw-r--r--src/core/api/qwebengineprofile.cpp2
-rw-r--r--src/core/media_capture_devices_dispatcher.cpp30
-rw-r--r--src/core/permission_manager_qt.cpp435
-rw-r--r--src/core/permission_manager_qt.h37
-rw-r--r--src/core/profile_adapter.cpp24
-rw-r--r--src/core/profile_adapter.h5
-rw-r--r--src/core/web_contents_adapter.cpp158
-rw-r--r--src/core/web_contents_adapter.h12
-rw-r--r--src/core/web_contents_adapter_client.h7
-rw-r--r--src/core/web_contents_delegate_qt.cpp48
-rw-r--r--src/core/web_contents_delegate_qt.h3
-rw-r--r--src/webenginequick/api/qquickwebengineprofile.cpp2
-rw-r--r--src/webenginequick/api/qquickwebengineview.cpp82
-rw-r--r--src/webenginequick/api/qquickwebengineview_p_p.h6
18 files changed, 554 insertions, 427 deletions
diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp
index bfa184e5c..8d73723f6 100644
--- a/src/core/api/qwebenginepage.cpp
+++ b/src/core/api/qwebenginepage.cpp
@@ -590,49 +590,6 @@ void QWebEnginePagePrivate::showColorDialog(QSharedPointer<ColorChooserControlle
view->showColorDialog(controller);
}
-void QWebEnginePagePrivate::runMediaAccessPermissionRequest(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags requestFlags)
-{
- Q_Q(QWebEnginePage);
- QWebEnginePermission::PermissionType permissionType;
-
- if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)
- && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture))
- permissionType = QWebEnginePermission::PermissionType::MediaAudioVideoCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture))
- permissionType = QWebEnginePermission::PermissionType::MediaAudioCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture))
- permissionType = QWebEnginePermission::PermissionType::MediaVideoCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture)
- && requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture))
- permissionType = QWebEnginePermission::PermissionType::DesktopAudioVideoCapture;
- else // if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture))
- permissionType = QWebEnginePermission::PermissionType::DesktopVideoCapture;
-
- Q_EMIT q->permissionRequested(createFeaturePermissionObject(securityOrigin, permissionType));
-
-#if QT_DEPRECATED_SINCE(6, 8)
- QT_WARNING_PUSH
- QT_WARNING_DISABLE_DEPRECATED
- QWebEnginePage::Feature deprecatedFeature;
-
- if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)
- && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture))
- deprecatedFeature = QWebEnginePage::MediaAudioVideoCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture))
- deprecatedFeature = QWebEnginePage::MediaAudioCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture))
- deprecatedFeature = QWebEnginePage::MediaVideoCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture)
- && requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture))
- deprecatedFeature = QWebEnginePage::DesktopAudioVideoCapture;
- else // if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture))
- deprecatedFeature = QWebEnginePage::DesktopVideoCapture;
-
- Q_EMIT q->featurePermissionRequested(securityOrigin, deprecatedFeature);
- QT_WARNING_POP
-#endif // QT_DEPRECATED_SINCE(6, 8)
-}
-
#if QT_DEPRECATED_SINCE(6, 8)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
@@ -668,33 +625,19 @@ static QWebEnginePage::Feature toDeprecatedFeature(QWebEnginePermission::Permiss
QT_WARNING_POP
#endif // QT_DEPRECATED_SINCE(6, 8)
-void QWebEnginePagePrivate::runFeaturePermissionRequest(QWebEnginePermission::PermissionType permissionType, const QUrl &securityOrigin)
+void QWebEnginePagePrivate::runFeaturePermissionRequest(
+ QWebEnginePermission::PermissionType permissionType,
+ const QUrl &securityOrigin,
+ int childId, const std::string &serializedToken)
{
Q_Q(QWebEnginePage);
- if (QWebEnginePermission::isPersistent(permissionType)) {
- Q_EMIT q->permissionRequested(createFeaturePermissionObject(securityOrigin, permissionType));
-#if QT_DEPRECATED_SINCE(6, 8)
- QT_WARNING_PUSH
- QT_WARNING_DISABLE_DEPRECATED
- Q_EMIT q->featurePermissionRequested(securityOrigin, toDeprecatedFeature(permissionType));
- QT_WARNING_POP
-#endif // QT_DEPRECATED_SINCE(6, 8)
- return;
- }
-
- Q_UNREACHABLE();
-}
-
-void QWebEnginePagePrivate::runMouseLockPermissionRequest(const QUrl &securityOrigin)
-{
- Q_Q(QWebEnginePage);
- Q_EMIT q->permissionRequested(createFeaturePermissionObject(securityOrigin, QWebEnginePermission::PermissionType::MouseLock));
-
+ Q_EMIT q->permissionRequested(QWebEnginePermission(
+ new QWebEnginePermissionPrivate(securityOrigin, permissionType, profileAdapter(), childId, serializedToken)));
#if QT_DEPRECATED_SINCE(6, 8)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
- Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::MouseLock);
+ Q_EMIT q->featurePermissionRequested(securityOrigin, toDeprecatedFeature(permissionType));
QT_WARNING_POP
#endif // QT_DEPRECATED_SINCE(6, 8)
}
@@ -885,12 +828,6 @@ void QWebEnginePagePrivate::showWebAuthDialog(QWebEngineWebAuthUxRequest *reques
Q_EMIT q->webAuthUxRequested(request);
}
-QWebEnginePermission QWebEnginePagePrivate::createFeaturePermissionObject(const QUrl &securityOrigin, QWebEnginePermission::PermissionType feature)
-{
- auto *returnPrivate = new QWebEnginePermissionPrivate(securityOrigin, feature, adapter, profileAdapter());
- return QWebEnginePermission(returnPrivate);
-}
-
QWebEnginePage::QWebEnginePage(QObject* parent)
: QObject(parent)
, d_ptr(new QWebEnginePagePrivate())
@@ -1918,7 +1855,7 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine
Q_UNREACHABLE();
}
- d->adapter->setPermission(securityOrigin, f, s);
+ d->adapter->setPermission(securityOrigin, f, s, {});
}
QT_WARNING_POP
#endif // QT_DEPRECATED_SINCE(6, 8)
diff --git a/src/core/api/qwebenginepage_p.h b/src/core/api/qwebenginepage_p.h
index 76b4a4d9d..ba1fbc6d5 100644
--- a/src/core/api/qwebenginepage_p.h
+++ b/src/core/api/qwebenginepage_p.h
@@ -148,9 +148,8 @@ public:
void authenticationRequired(
QSharedPointer<QtWebEngineCore::AuthenticationDialogController>) override;
void releaseProfile() override;
- void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) override;
- void runFeaturePermissionRequest(QWebEnginePermission::PermissionType permissionType, const QUrl &securityOrigin) override;
- void runMouseLockPermissionRequest(const QUrl &securityOrigin) override;
+ void runFeaturePermissionRequest(QWebEnginePermission::PermissionType permissionType, const QUrl &securityOrigin,
+ int childId, const std::string &serializedToken) override;
void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) override;
void runFileSystemAccessRequest(QWebEngineFileSystemAccessRequest) override;
QObject *accessibilityParentObject() override;
@@ -181,7 +180,6 @@ public:
const QRect &bounds, bool autoselectFirstSuggestion) override;
void hideAutofillPopup() override;
void showWebAuthDialog(QWebEngineWebAuthUxRequest *controller) override;
- QWebEnginePermission createFeaturePermissionObject(const QUrl &securityOrigin, QWebEnginePermission::PermissionType permissionType) override;
QtWebEngineCore::ProfileAdapter *profileAdapter() override;
QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override;
diff --git a/src/core/api/qwebenginepermission.cpp b/src/core/api/qwebenginepermission.cpp
index ec62f0e4c..1d1b12b7e 100644
--- a/src/core/api/qwebenginepermission.cpp
+++ b/src/core/api/qwebenginepermission.cpp
@@ -20,11 +20,12 @@ QWebEnginePermissionPrivate::QWebEnginePermissionPrivate()
/*! \internal */
QWebEnginePermissionPrivate::QWebEnginePermissionPrivate(const QUrl &origin_, QWebEnginePermission::PermissionType permissionType_,
- QSharedPointer<QtWebEngineCore::WebContentsAdapter> webContentsAdapter_, QtWebEngineCore::ProfileAdapter *profileAdapter_)
+ QtWebEngineCore::ProfileAdapter *profileAdapter_, int childId_, const std::string &serializedToken_)
: QSharedData()
, origin(origin_)
, permissionType(permissionType_)
- , webContentsAdapter(webContentsAdapter_)
+ , childId(childId_)
+ , serializedToken(serializedToken_)
, profileAdapter(profileAdapter_)
{
}
@@ -114,15 +115,12 @@ bool QWebEnginePermission::equals(const QWebEnginePermission &other) const
return false;
if (!isPersistent(d_ptr->permissionType)) {
- if (d_ptr->webContentsAdapter != other.d_ptr->webContentsAdapter)
+ if (d_ptr->childId != other.d_ptr->childId
+ && d_ptr->serializedToken != other.d_ptr->serializedToken)
return false;
} else {
- QtWebEngineCore::ProfileAdapter *thisProfile = d_ptr->webContentsAdapter
- ? d_ptr->webContentsAdapter.toStrongRef()->profileAdapter()
- : d_ptr->profileAdapter.get();
- QtWebEngineCore::ProfileAdapter *otherProfile = d_ptr->webContentsAdapter
- ? other.d_ptr->webContentsAdapter.toStrongRef()->profileAdapter()
- : other.d_ptr->profileAdapter.get();
+ QtWebEngineCore::ProfileAdapter *thisProfile = d_ptr->profileAdapter.get();
+ QtWebEngineCore::ProfileAdapter *otherProfile = other.d_ptr->profileAdapter.get();
if (thisProfile != otherProfile)
return false;
@@ -201,11 +199,7 @@ QWebEnginePermission::State QWebEnginePermission::state() const
{
if (!isValid())
return State::Invalid;
- if (d_ptr->webContentsAdapter)
- return d_ptr->webContentsAdapter.toStrongRef()->getPermissionState(origin(), permissionType());
- if (d_ptr->profileAdapter)
- return d_ptr->profileAdapter->getPermissionState(origin(), permissionType());
- Q_UNREACHABLE_RETURN(State::Ask);
+ return d_ptr->profileAdapter->getPermissionState(origin(), permissionType(), d_ptr->childId, d_ptr->serializedToken);
}
/*!
@@ -227,7 +221,7 @@ bool QWebEnginePermission::isValid() const
return false;
if (permissionType() == PermissionType::Unsupported)
return false;
- if (!d_ptr->profileAdapter && !d_ptr->webContentsAdapter)
+ if (!d_ptr->profileAdapter)
return false;
if (!d_ptr->origin.isValid())
return false;
@@ -243,10 +237,7 @@ void QWebEnginePermission::grant() const
{
if (!isValid())
return;
- if (d_ptr->webContentsAdapter)
- d_ptr->webContentsAdapter.toStrongRef()->setPermission(origin(), permissionType(), State::Granted);
- else if (d_ptr->profileAdapter)
- d_ptr->profileAdapter->setPermission(origin(), permissionType(), State::Granted);
+ d_ptr->profileAdapter->setPermission(origin(), permissionType(), State::Granted, d_ptr->childId, d_ptr->serializedToken);
}
/*!
@@ -258,10 +249,7 @@ void QWebEnginePermission::deny() const
{
if (!isValid())
return;
- if (d_ptr->webContentsAdapter)
- d_ptr->webContentsAdapter.toStrongRef()->setPermission(origin(), permissionType(), State::Denied);
- else if (d_ptr->profileAdapter)
- d_ptr->profileAdapter->setPermission(origin(), permissionType(), State::Denied);
+ d_ptr->profileAdapter->setPermission(origin(), permissionType(), State::Denied, d_ptr->childId, d_ptr->serializedToken);
}
/*!
@@ -279,10 +267,7 @@ void QWebEnginePermission::reset() const
{
if (!isValid())
return;
- if (d_ptr->webContentsAdapter)
- d_ptr->webContentsAdapter.toStrongRef()->setPermission(origin(), permissionType(), State::Ask);
- else if (d_ptr->profileAdapter)
- d_ptr->profileAdapter->setPermission(origin(), permissionType(), State::Ask);
+ d_ptr->profileAdapter->setPermission(origin(), permissionType(), State::Ask, d_ptr->childId, d_ptr->serializedToken);
}
/*!
diff --git a/src/core/api/qwebenginepermission_p.h b/src/core/api/qwebenginepermission_p.h
index c6b525b31..aabb5c4b9 100644
--- a/src/core/api/qwebenginepermission_p.h
+++ b/src/core/api/qwebenginepermission_p.h
@@ -33,12 +33,14 @@ struct QWebEnginePermissionPrivate : public QSharedData
{
Q_WEBENGINECORE_EXPORT QWebEnginePermissionPrivate();
Q_WEBENGINECORE_EXPORT QWebEnginePermissionPrivate(const QUrl &, QWebEnginePermission::PermissionType,
- QSharedPointer<QtWebEngineCore::WebContentsAdapter>, QtWebEngineCore::ProfileAdapter *);
+ QtWebEngineCore::ProfileAdapter *, int = -1, const std::string & = std::string());
QUrl origin;
QWebEnginePermission::PermissionType permissionType;
- QWeakPointer<QtWebEngineCore::WebContentsAdapter> webContentsAdapter;
+ int childId = -1;
+ std::string serializedToken;
+
QPointer<QtWebEngineCore::ProfileAdapter> profileAdapter;
};
diff --git a/src/core/api/qwebengineprofile.cpp b/src/core/api/qwebengineprofile.cpp
index b6c308cf6..f7f6ab551 100644
--- a/src/core/api/qwebengineprofile.cpp
+++ b/src/core/api/qwebengineprofile.cpp
@@ -1018,7 +1018,7 @@ QWebEnginePermission QWebEngineProfile::queryPermission(const QUrl &securityOrig
return QWebEnginePermission(new QWebEnginePermissionPrivate());
}
- auto *pvt = new QWebEnginePermissionPrivate(securityOrigin, permissionType, nullptr, d->profileAdapter());
+ auto *pvt = new QWebEnginePermissionPrivate(securityOrigin, permissionType, d->profileAdapter());
return QWebEnginePermission(pvt);
}
diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp
index 848a92986..d691c65ea 100644
--- a/src/core/media_capture_devices_dispatcher.cpp
+++ b/src/core/media_capture_devices_dispatcher.cpp
@@ -11,6 +11,8 @@
#include "web_contents_delegate_qt.h"
#include "web_contents_view_qt.h"
#include "web_engine_settings.h"
+#include "permission_manager_qt.h"
+#include "type_conversion.h"
#include "base/strings/strcat.h"
#include "blink/public/common/page/page_zoom.h"
@@ -21,6 +23,8 @@
#include "content/public/browser/desktop_streams_registry.h"
#include "content/public/browser/host_zoom_map.h"
#include "content/public/browser/media_capture_devices.h"
+#include "content/public/browser/permission_controller_delegate.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "media/audio/audio_device_description.h"
#include "media/audio/audio_manager_base.h"
@@ -493,8 +497,17 @@ void MediaCaptureDevicesDispatcher::processMediaAccessRequest(
}
enqueueMediaAccessRequest(webContents, request, std::move(callback), id);
- // We might not require this approval for pepper requests.
- adapterClient->runMediaAccessPermissionRequest(toQt(request.security_origin), flags);
+
+ PermissionManagerQt *permissionManager = static_cast<PermissionManagerQt *>(
+ webContents->GetBrowserContext()->GetPermissionControllerDelegate());
+ permissionManager->requestMediaPermissions(
+ content::RenderFrameHost::FromID(request.render_process_id, request.render_frame_id),
+ flags,
+ base::BindOnce(
+ &MediaCaptureDevicesDispatcher::handleMediaAccessPermissionResponse,
+ base::Unretained(this),
+ webContents,
+ toQt(request.url_origin)));
}
void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content::WebContents *webContents, const content::MediaStreamRequest &request, content::MediaResponseCallback callback)
@@ -558,9 +571,18 @@ void MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest(content::WebConte
RequestsQueue &queue(it->second);
content::MediaStreamRequest &request = queue.front()->request;
+ WebContentsAdapterClient::MediaRequestFlags flags = mediaRequestFlagsForRequest(request);
- WebContentsAdapterClient *adapterClient = WebContentsViewQt::from(static_cast<content::WebContentsImpl *>(webContents)->GetView())->client();
- adapterClient->runMediaAccessPermissionRequest(toQt(request.security_origin), mediaRequestFlagsForRequest(request));
+ PermissionManagerQt *permissionManager = static_cast<PermissionManagerQt *>(
+ webContents->GetBrowserContext()->GetPermissionControllerDelegate());
+ permissionManager->requestMediaPermissions(
+ content::RenderFrameHost::FromID(request.render_process_id, request.render_frame_id),
+ flags,
+ base::BindOnce(
+ &MediaCaptureDevicesDispatcher::handleMediaAccessPermissionResponse,
+ base::Unretained(this),
+ webContents,
+ toQt(request.url_origin)));
}
void MediaCaptureDevicesDispatcher::getDefaultDevices(const std::string &audioDeviceId, const std::string &videoDeviceId,
diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp
index 5258f15cf..eae98b350 100644
--- a/src/core/permission_manager_qt.cpp
+++ b/src/core/permission_manager_qt.cpp
@@ -40,7 +40,7 @@ static QWebEnginePermission::PermissionType toQt(blink::PermissionType type)
case blink::PermissionType::VIDEO_CAPTURE:
return QWebEnginePermission::PermissionType::MediaVideoCapture;
case blink::PermissionType::DISPLAY_CAPTURE:
- return QWebEnginePermission::PermissionType::DesktopAudioVideoCapture;
+ return QWebEnginePermission::PermissionType::DesktopVideoCapture;
// We treat these both as read/write since we do not currently have a
// ClipboardSanitizedWrite permission type.
case blink::PermissionType::CLIPBOARD_READ_WRITE:
@@ -56,6 +56,8 @@ static QWebEnginePermission::PermissionType toQt(blink::PermissionType type)
case blink::PermissionType::WINDOW_MANAGEMENT:
case blink::PermissionType::BACKGROUND_SYNC:
case blink::PermissionType::NUM:
+ case blink::PermissionType::TOP_LEVEL_STORAGE_ACCESS:
+ case blink::PermissionType::SPEAKER_SELECTION:
return QWebEnginePermission::PermissionType::Unsupported;
case blink::PermissionType::MIDI_SYSEX:
case blink::PermissionType::PROTECTED_MEDIA_IDENTIFIER:
@@ -72,16 +74,13 @@ static QWebEnginePermission::PermissionType toQt(blink::PermissionType type)
case blink::PermissionType::AR:
case blink::PermissionType::VR:
case blink::PermissionType::STORAGE_ACCESS_GRANT:
- case blink::PermissionType::TOP_LEVEL_STORAGE_ACCESS:
case blink::PermissionType::CAPTURED_SURFACE_CONTROL:
case blink::PermissionType::SMART_CARD:
case blink::PermissionType::WEB_PRINTING:
- case blink::PermissionType::SPEAKER_SELECTION:
case blink::PermissionType::KEYBOARD_LOCK:
case blink::PermissionType::AUTOMATIC_FULLSCREEN:
case blink::PermissionType::HAND_TRACKING:
case blink::PermissionType::WEB_APP_INSTALLATION:
- LOG(INFO) << "Unexpected unsupported Blink permission type: " << static_cast<int>(type);
break;
}
return QWebEnginePermission::PermissionType::Unsupported;
@@ -107,16 +106,50 @@ static blink::PermissionType toBlink(QWebEnginePermission::PermissionType permis
return blink::PermissionType::LOCAL_FONTS;
case QWebEnginePermission::PermissionType::MouseLock:
return blink::PermissionType::POINTER_LOCK;
- case QWebEnginePermission::PermissionType::MediaAudioVideoCapture:
- LOG(INFO) << "Unexpected unsupported WebEngine permission type: " << static_cast<int>(permissionType);
- Q_FALLTHROUGH();
case QWebEnginePermission::PermissionType::Unsupported:
return blink::PermissionType::NUM;
+ case QWebEnginePermission::PermissionType::MediaAudioVideoCapture:
+ break;
}
Q_UNREACHABLE_RETURN(blink::PermissionType::NUM);
}
+static std::vector<QWebEnginePermission::PermissionType> toQt(
+ const std::vector<blink::PermissionType> &blinkPermissions)
+{
+ // This function handles the edge case differences between our permission types and Blink's;
+ // namely, MediaAudioVideoCapture and DesktopAudioVideoCapture
+ std::vector<QWebEnginePermission::PermissionType> permissions;
+ for (auto &p : blinkPermissions) {
+ permissions.push_back(toQt(p));
+ }
+
+ for (auto i1 = permissions.begin(); i1 != permissions.end(); ++i1) {
+ if (*i1 == QWebEnginePermission::PermissionType::MediaAudioCapture) {
+ for (auto i2 = permissions.begin(); i2 != permissions.end(); ++i2) {
+ if (*i2 == QWebEnginePermission::PermissionType::MediaVideoCapture) {
+ // Merge MediaAudioCapture and MediaVideoCapture into MediaAudioVideoCapture
+ *i1 = QWebEnginePermission::PermissionType::MediaAudioVideoCapture;
+ permissions.erase(i2);
+ break;
+ }
+ }
+ } else if (*i1 == QWebEnginePermission::PermissionType::DesktopVideoCapture) {
+ for (auto i2 = i1 + 1; i2 != permissions.end(); ++i2) {
+ if (*i2 == QWebEnginePermission::PermissionType::DesktopVideoCapture) {
+ // Double DesktopVideoCapture means we actually need DesktopAudioVideoCapture
+ *i2 = QWebEnginePermission::PermissionType::DesktopAudioVideoCapture;
+ i1 = permissions.erase(i1);
+ break;
+ }
+ }
+ }
+ }
+
+ return permissions;
+}
+
static QWebEnginePermission::State toQt(blink::mojom::PermissionStatus state)
{
switch (state) {
@@ -154,6 +187,8 @@ std::string permissionTypeString(QWebEnginePermission::PermissionType permission
return "MediaVideoCapture";
case QWebEnginePermission::PermissionType::DesktopAudioVideoCapture:
return "DesktopAudioVideoCapture";
+ case QWebEnginePermission::PermissionType::DesktopVideoCapture:
+ return "DesktopVideoCapture";
case QWebEnginePermission::PermissionType::MouseLock:
return "MouseLock";
case QWebEnginePermission::PermissionType::Notifications:
@@ -213,6 +248,8 @@ PermissionManagerQt::PermissionManagerQt(ProfileAdapter *profileAdapter)
m_permissionTypes.push_back(QWebEnginePermission::PermissionType::MediaAudioCapture);
m_permissionTypes.push_back(QWebEnginePermission::PermissionType::MediaVideoCapture);
+ m_permissionTypes.push_back(QWebEnginePermission::PermissionType::DesktopAudioVideoCapture);
+ m_permissionTypes.push_back(QWebEnginePermission::PermissionType::DesktopVideoCapture);
m_permissionTypes.push_back(QWebEnginePermission::PermissionType::MouseLock);
m_permissionTypes.push_back(QWebEnginePermission::PermissionType::Notifications);
m_permissionTypes.push_back(QWebEnginePermission::PermissionType::Geolocation);
@@ -239,38 +276,83 @@ PermissionManagerQt::~PermissionManagerQt()
commit();
}
+// static
+content::GlobalRenderFrameHostToken PermissionManagerQt::deserializeToken(int childId, const std::string &serializedToken)
+{
+ auto maybeToken = base::UnguessableToken::DeserializeFromString(serializedToken);
+ if (maybeToken)
+ return content::GlobalRenderFrameHostToken(childId, blink::LocalFrameToken(maybeToken.value()));
+
+ return content::GlobalRenderFrameHostToken();
+}
+
void PermissionManagerQt::setPermission(
const QUrl &url,
- QWebEnginePermission::PermissionType permissionType,
- QWebEnginePermission::State state,
- content::RenderFrameHost *rfh)
+ const QWebEnginePermission::PermissionType permissionType,
+ const QWebEnginePermission::State state,
+ const content::GlobalRenderFrameHostToken &token)
+{
+ if (permissionType == QWebEnginePermission::PermissionType::MediaAudioVideoCapture) {
+ setPermissionImpl(url, QWebEnginePermission::PermissionType::MediaAudioCapture, state, token);
+ setPermissionImpl(url, QWebEnginePermission::PermissionType::MediaVideoCapture, state, token);
+ return;
+ }
+
+ setPermissionImpl(url, permissionType, state, token);
+}
+
+void PermissionManagerQt::setPermission(
+ const QUrl &url,
+ const QWebEnginePermission::PermissionType permissionType,
+ const QWebEnginePermission::State state,
+ int childId, const std::string &serializedToken)
+{
+ content::GlobalRenderFrameHostToken token;
+ auto maybeToken = base::UnguessableToken::DeserializeFromString(serializedToken);
+ if (maybeToken)
+ token = content::GlobalRenderFrameHostToken(childId, blink::LocalFrameToken(maybeToken.value()));
+
+ setPermission(url, permissionType, state, token);
+}
+
+void PermissionManagerQt::setPermissionImpl(
+ const QUrl &url,
+ const QWebEnginePermission::PermissionType permissionTypeQt,
+ const QWebEnginePermission::State permissionStateQt,
+ const content::GlobalRenderFrameHostToken &frameToken)
{
+ const blink::PermissionType permissionTypeBlink = toBlink(permissionTypeQt);
+ const blink::mojom::PermissionStatus permissionStateBlink = toBlink(permissionStateQt);
+
// Normalize the QUrl to Chromium origin form.
const GURL gorigin = toGurl(url).DeprecatedGetOriginAsURL();
const QUrl origin = gorigin.is_empty() ? url : toQt(gorigin);
if (origin.isEmpty())
return;
- // Send eligible permissions with an associated rfh to the transient store. When pre-granting
+ // Send eligible permissions with an associated frameToken to the transient store. When pre-granting
// a non-persistent permission (or pre-granting any permission in AskEveryTime mode), it is allowed
// to pass through the persistent store. It will be moved to the transient store and associated
- // with a rfh the next time its status is requested.
- bool inTransientStore = rfh && (!QWebEnginePermission::isPersistent(permissionType) || !m_persistence);
+ // with a frameToken the next time its status is requested.
+ bool inTransientStore = frameToken.child_id != content::kInvalidChildProcessUniqueId
+ && (!QWebEnginePermission::isPersistent(permissionTypeQt) || !m_persistence);
- blink::mojom::PermissionStatus blinkStatus = toBlink(state);
- if (state == QWebEnginePermission::State::Ask) {
+ blink::mojom::PermissionStatus blinkStatus = permissionStateBlink;
+ if (permissionStateQt == QWebEnginePermission::State::Ask) {
if (inTransientStore)
- resetTransientPermission(toBlink(permissionType), gorigin, rfh->GetGlobalFrameToken());
+ resetTransientPermission(permissionTypeBlink, gorigin, frameToken);
else
- ResetPermission(toBlink(permissionType), gorigin, gorigin);
+ ResetPermission(permissionTypeBlink, gorigin, gorigin);
} else {
if (inTransientStore)
- setTransientPermission(toBlink(permissionType), gorigin, state == QWebEnginePermission::State::Granted, rfh->GetGlobalFrameToken());
+ setTransientPermission(permissionTypeBlink, gorigin,
+ permissionStateQt == QWebEnginePermission::State::Granted, frameToken);
else
- setPersistentPermission(toBlink(permissionType), gorigin, state == QWebEnginePermission::State::Granted);
+ setPersistentPermission(permissionTypeBlink,
+ gorigin, permissionStateQt == QWebEnginePermission::State::Granted);
auto it = m_requests.begin();
while (it != m_requests.end()) {
- if (it->origin == origin && it->type == permissionType) {
+ if (it->origin == origin && it->type == permissionTypeQt) {
std::move(it->callback).Run(blinkStatus);
it = m_requests.erase(it);
} else
@@ -292,10 +374,10 @@ void PermissionManagerQt::setPermission(
if (subscription->embedding_origin != gorigin)
continue;
- if (subscription->permission != toBlink(permissionType))
+ if (subscription->permission != permissionTypeBlink)
continue;
- if ((!QWebEnginePermission::isPersistent(permissionType) || !m_persistence)
- && targetRfh && targetRfh != rfh)
+ if ((!QWebEnginePermission::isPersistent(permissionTypeQt) || !m_persistence)
+ && targetRfh && targetRfh != content::RenderFrameHost::FromFrameToken(frameToken))
continue;
// Behavior in callbacks may differ depending on the denial reason. Until we have
@@ -312,7 +394,7 @@ void PermissionManagerQt::setPermission(
std::move(callback).Run();
}
- if (state == QWebEnginePermission::State::Ask)
+ if (permissionStateQt == QWebEnginePermission::State::Ask)
return;
auto it = m_multiRequests.begin();
@@ -321,32 +403,37 @@ void PermissionManagerQt::setPermission(
bool answerable = true;
std::vector<blink::mojom::PermissionStatus> result;
result.reserve(it->types.size());
- for (blink::PermissionType permission : it->types) {
- if (toQt(permission) == QWebEnginePermission::PermissionType::Unsupported) {
+ for (blink::PermissionType currentPermissionType : it->types) {
+ if (toQt(currentPermissionType) == QWebEnginePermission::PermissionType::Unsupported) {
result.push_back(blink::mojom::PermissionStatus::DENIED);
continue;
}
blink::mojom::PermissionStatus permissionStatus;
if (inTransientStore)
- permissionStatus = toBlink(getPermissionState(url, permissionType, rfh));
+ permissionStatus = toBlink(getPermissionState(url, toQt(currentPermissionType), frameToken));
else
- permissionStatus = GetPermissionStatus(permission, gorigin, GURL());
+ permissionStatus = GetPermissionStatus(currentPermissionType, gorigin, GURL());
- if (permissionStatus == toBlink(state)) {
+ if (permissionStatus == permissionStateBlink) {
if (permissionStatus == blink::mojom::PermissionStatus::ASK) {
answerable = false;
break;
}
result.push_back(permissionStatus);
- } else {
+ } else if (!m_persistence) {
// Reached when the PersistentPermissionsPolicy is set to AskEveryTime
- result.push_back(toBlink(state));
+ result.push_back(permissionStateBlink);
+ } else {
+ // Not all of the permissions in this request have been set yet, bail and wait for the next setPermission() call
+ answerable = false;
+ break;
}
}
if (answerable) {
- std::move(it->callback).Run(result);
+ if (!it->callback.is_null())
+ std::move(it->callback).Run(result);
it = m_multiRequests.erase(it);
continue;
}
@@ -355,23 +442,44 @@ void PermissionManagerQt::setPermission(
}
}
-QWebEnginePermission::State PermissionManagerQt::getPermissionState(const QUrl &origin, QWebEnginePermission::PermissionType permissionType,
- content::RenderFrameHost *rfh)
+QWebEnginePermission::State PermissionManagerQt::getPermissionState(
+ const QUrl &origin,
+ const QWebEnginePermission::PermissionType permissionType,
+ const content::GlobalRenderFrameHostToken &frameToken)
{
- if (rfh) {
- // Ignore the origin parameter
- return toQt(GetPermissionStatusForCurrentDocument(toBlink(permissionType), rfh, false));
+ std::vector<QWebEnginePermission::PermissionType> types;
+ if (permissionType == QWebEnginePermission::PermissionType::MediaAudioVideoCapture) {
+ types.push_back(QWebEnginePermission::PermissionType::MediaAudioCapture);
+ types.push_back(QWebEnginePermission::PermissionType::MediaVideoCapture);
+ } else {
+ types.push_back(permissionType);
+ }
+
+ auto *rfh = content::RenderFrameHost::FromFrameToken(frameToken);
+ QWebEnginePermission::State returnState = QWebEnginePermission::State::Invalid;
+ for (auto type : types) {
+ QWebEnginePermission::State state = rfh
+ ? toQt(GetPermissionStatusForCurrentDocument(toBlink(type), rfh, false))
+ : toQt(GetPermissionStatus(toBlink(type), toGurl(origin), GURL()));
+
+ if (returnState == QWebEnginePermission::State::Invalid)
+ returnState = state;
+ else if (returnState != state)
+ returnState = QWebEnginePermission::State::Ask;
}
- return toQt(GetPermissionStatus(toBlink(permissionType), toGurl(origin), GURL()));
+ return returnState;
}
-QList<QWebEnginePermission> PermissionManagerQt::listPermissions(const QUrl &origin, QWebEnginePermission::PermissionType permissionType)
+QList<QWebEnginePermission> PermissionManagerQt::listPermissions(
+ const QUrl &origin,
+ const QWebEnginePermission::PermissionType permissionType)
{
Q_ASSERT(origin.isEmpty() || permissionType == QWebEnginePermission::PermissionType::Unsupported);
+
QList<QWebEnginePermission> returnList;
- GURL gorigin = toGurl(origin).DeprecatedGetOriginAsURL();
- std::string originSpec = gorigin.spec();
+ const GURL gorigin = toGurl(origin).DeprecatedGetOriginAsURL();
+ const std::string originSpec = gorigin.spec();
if (!origin.isEmpty() && !gorigin.is_valid())
return returnList;
@@ -382,7 +490,7 @@ QList<QWebEnginePermission> PermissionManagerQt::listPermissions(const QUrl &ori
else
types.push_back(permissionType);
- for (auto &type : types) {
+ for (const auto &type : types) {
// Transient types may end up in the permission store as an implementation detail,
// but we do not want to expose them to callers.
if (!QWebEnginePermission::isPersistent(type))
@@ -399,7 +507,8 @@ QList<QWebEnginePermission> PermissionManagerQt::listPermissions(const QUrl &ori
if (!originSpec.empty() && entry.first != originSpec)
continue;
- auto *pvt = new QWebEnginePermissionPrivate(toQt(GURL(std::string_view(entry.first))), type, nullptr, m_profileAdapter.get());
+ auto *pvt = new QWebEnginePermissionPrivate(
+ toQt(GURL(std::string_view(entry.first))), type, m_profileAdapter.get());
returnList.push_back(QWebEnginePermission(pvt));
}
}
@@ -407,6 +516,78 @@ QList<QWebEnginePermission> PermissionManagerQt::listPermissions(const QUrl &ori
return returnList;
}
+void PermissionManagerQt::requestMediaPermissions(
+ content::RenderFrameHost *render_frame_host,
+ const WebContentsAdapterClient::MediaRequestFlags flags,
+ base::OnceCallback<void(WebContentsAdapterClient::MediaRequestFlags authorizationFlags)> callback)
+{
+ std::vector<blink::PermissionType> permissionTypesBlink;
+ if (flags.testFlag(WebContentsAdapterClient::MediaAudioCapture))
+ permissionTypesBlink.push_back(blink::PermissionType::AUDIO_CAPTURE);
+ if (flags.testFlag(WebContentsAdapterClient::MediaVideoCapture))
+ permissionTypesBlink.push_back(blink::PermissionType::VIDEO_CAPTURE);
+ if (flags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture)
+ || flags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) {
+ permissionTypesBlink.push_back(blink::PermissionType::DISPLAY_CAPTURE);
+ if (flags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture)) {
+ // Inject a second copy of the permission type into the request,
+ // so we can distinguish between DesktopVideoCapture and DesktopAudioVideoCapture.
+ permissionTypesBlink.push_back(blink::PermissionType::DISPLAY_CAPTURE);
+ }
+ }
+
+ content::PermissionRequestDescription description(permissionTypesBlink, false, render_frame_host->GetLastCommittedOrigin().GetURL());
+
+ RequestPermissions(render_frame_host, description, base::BindOnce([](
+ std::vector<blink::PermissionType> permissionTypesBlink,
+ base::OnceCallback<void(WebContentsAdapterClient::MediaRequestFlags authorizationFlags)> callback,
+ const std::vector<blink::mojom::PermissionStatus> &statuses)
+ {
+ // This callback converts the Blink permission types to MediaRequestFlags,
+ // and then runs the callback initially passed to requestMediaPermissions().
+ DCHECK(permissionTypesBlink.size() == statuses.size());
+ WebContentsAdapterClient::MediaRequestFlags flags = WebContentsAdapterClient::MediaRequestFlag::MediaNone;
+ for (uint i = 0; i < statuses.size(); ++i) {
+ if (statuses[i] == blink::mojom::PermissionStatus::GRANTED) {
+ switch (permissionTypesBlink[i]) {
+ case blink::PermissionType::AUDIO_CAPTURE:
+ flags.setFlag(WebContentsAdapterClient::MediaRequestFlag::MediaAudioCapture);
+ break;
+ case blink::PermissionType::VIDEO_CAPTURE:
+ flags.setFlag(WebContentsAdapterClient::MediaRequestFlag::MediaVideoCapture);
+ break;
+ case blink::PermissionType::DISPLAY_CAPTURE:
+ flags.setFlag(WebContentsAdapterClient::MediaRequestFlag::MediaDesktopAudioCapture);
+ flags.setFlag(WebContentsAdapterClient::MediaRequestFlag::MediaDesktopVideoCapture);
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+ }
+ }
+ std::move(callback).Run(flags);
+ }, permissionTypesBlink, std::move(callback)));
+}
+
+// Needed for the rare cases where a RenderFrameHost remains the same even after
+// a cross-origin navigation (e.g. inside an iframe). Needs to be called every
+// time transient permissions are accessed.
+void PermissionManagerQt::onCrossOriginNavigation(content::RenderFrameHost *render_frame_host)
+{
+ if (!render_frame_host)
+ return;
+
+ auto frameToken = render_frame_host->GetGlobalFrameToken();
+ auto &permissionsForToken = m_transientPermissions[frameToken];
+ if (!permissionsForToken.size())
+ return;
+
+ GURL savedOrigin = get<0>(permissionsForToken[0]);
+ if (render_frame_host->GetLastCommittedOrigin().GetURL() != savedOrigin)
+ m_transientPermissions.erase(frameToken);
+}
+
void PermissionManagerQt::commit()
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -414,15 +595,18 @@ void PermissionManagerQt::commit()
m_prefService->CommitPendingWrite();
}
-void PermissionManagerQt::RequestPermissions(content::RenderFrameHost *frameHost,
- const content::PermissionRequestDescription &requestDescription,
- base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> callback)
+void PermissionManagerQt::RequestPermissions(
+ content::RenderFrameHost *frameHost,
+ const content::PermissionRequestDescription &requestDescription,
+ base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> callback)
{
if (requestDescription.requesting_origin.is_empty()) {
- std::move(callback).Run(std::vector<content::PermissionStatus>(requestDescription.permissions.size(), blink::mojom::PermissionStatus::DENIED));
+ std::move(callback).Run(std::vector<content::PermissionStatus>(requestDescription.permissions.size(),
+ blink::mojom::PermissionStatus::DENIED));
return;
}
+ const auto frameToken = frameHost->GetGlobalFrameToken();
WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt *>(
content::WebContents::FromRenderFrameHost(frameHost)->GetDelegate());
Q_ASSERT(contentsDelegate);
@@ -430,53 +614,54 @@ void PermissionManagerQt::RequestPermissions(content::RenderFrameHost *frameHost
bool answerable = true;
std::vector<content::PermissionStatus> result;
result.reserve(requestDescription.permissions.size());
- for (blink::PermissionType permission : requestDescription.permissions) {
- const QWebEnginePermission::PermissionType permissionType = toQt(permission);
- if (permissionType == QWebEnginePermission::PermissionType::Unsupported) {
+ for (const blink::PermissionType permissionTypeBlink : requestDescription.permissions) {
+ const QWebEnginePermission::PermissionType permissionTypeQt = toQt(permissionTypeBlink);
+ if (permissionTypeQt == QWebEnginePermission::PermissionType::Unsupported) {
result.push_back(blink::mojom::PermissionStatus::DENIED);
continue;
}
- blink::mojom::PermissionStatus permissionStatus = getStatusFromSettings(permission, contentsDelegate->webEngineSettings());
- if (permissionStatus == blink::mojom::PermissionStatus::ASK) {
+ blink::mojom::PermissionStatus permissionStatusBlink = getStatusFromSettings(
+ permissionTypeBlink, contentsDelegate->webEngineSettings());
+ if (permissionStatusBlink == blink::mojom::PermissionStatus::ASK) {
const GURL &rorigin = requestDescription.requesting_origin;
+ bool maybePreGranted = false;
if (!m_persistence) {
- answerable = false;
- break;
+ maybePreGranted = true;
}
- bool inTransientStore = !QWebEnginePermission::isPersistent(toQt(permission));
+ bool inTransientStore = !QWebEnginePermission::isPersistent(permissionTypeQt) || maybePreGranted;
if (inTransientStore) {
- permissionStatus = getTransientPermissionStatus(permission, rorigin, frameHost->GetGlobalFrameToken());
+ permissionStatusBlink = getTransientPermissionStatus(permissionTypeBlink, rorigin, frameToken);
- if (permissionStatus != blink::mojom::PermissionStatus::ASK) {
- result.push_back(permissionStatus);
+ if (permissionStatusBlink != blink::mojom::PermissionStatus::ASK) {
+ result.push_back(permissionStatusBlink);
continue;
}
// Fall through to check if permission was pre-granted (and thus landed in the permanent store)
}
- permissionStatus = GetPermissionStatus(permission, rorigin, rorigin);
+ permissionStatusBlink = GetPermissionStatus(permissionTypeBlink, rorigin, rorigin);
- if (inTransientStore && permissionStatus != blink::mojom::PermissionStatus::ASK) {
- // Move the pre-granted permission to the transient store and associate it with the rfh
- ResetPermission(permission, rorigin, rorigin);
- setTransientPermission(permission, rorigin, permissionStatus == blink::mojom::PermissionStatus::GRANTED,
- frameHost->GetGlobalFrameToken());
+ if (inTransientStore && permissionStatusBlink != blink::mojom::PermissionStatus::ASK) {
+ // Move the pre-granted permission to the transient store and associate it with a frame token
+ ResetPermission(permissionTypeBlink, rorigin, rorigin);
+ setTransientPermission(permissionTypeBlink, rorigin,
+ permissionStatusBlink == blink::mojom::PermissionStatus::GRANTED, frameToken);
}
- if (permissionStatus != blink::mojom::PermissionStatus::ASK) {
+ if (permissionStatusBlink != blink::mojom::PermissionStatus::ASK) {
// Automatically grant/deny without prompt if already asked once
- result.push_back(permissionStatus);
+ result.push_back(permissionStatusBlink);
} else {
answerable = false;
break;
}
} else {
// Reached when clipboard settings have been set
- result.push_back(permissionStatus);
+ result.push_back(permissionStatusBlink);
}
}
@@ -486,80 +671,75 @@ void PermissionManagerQt::RequestPermissions(content::RenderFrameHost *frameHost
}
int request_id = ++m_requestIdCount;
- auto requestOrigin = toQt(requestDescription.requesting_origin);
+ const auto requestOrigin = toQt(requestDescription.requesting_origin);
m_multiRequests.push_back({ request_id, requestDescription.permissions, requestOrigin, std::move(callback) });
- for (blink::PermissionType permission : requestDescription.permissions) {
- const QWebEnginePermission::PermissionType permissionType = toQt(permission);
- if (QWebEnginePermission::isPersistent(permissionType))
- contentsDelegate->requestFeaturePermission(permissionType, requestOrigin);
+ auto qtPermissions = toQt(requestDescription.permissions);
+ for (const QWebEnginePermission::PermissionType permissionTypeQt : qtPermissions) {
+ contentsDelegate->requestFeaturePermission(permissionTypeQt, requestOrigin, frameToken);
}
}
-void PermissionManagerQt::RequestPermissionsFromCurrentDocument(content::RenderFrameHost *frameHost,
- const content::PermissionRequestDescription &requestDescription,
- base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> callback)
+void PermissionManagerQt::RequestPermissionsFromCurrentDocument(
+ content::RenderFrameHost *frameHost,
+ const content::PermissionRequestDescription &requestDescription,
+ base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> callback)
{
RequestPermissions(frameHost, requestDescription, std::move(callback));
}
blink::mojom::PermissionStatus PermissionManagerQt::GetPermissionStatus(
- blink::PermissionType permission,
+ blink::PermissionType permissionTypeBlink,
const GURL& requesting_origin,
const GURL& /*embedding_origin*/)
{
- const QWebEnginePermission::PermissionType permissionType = toQt(permission);
- if (permissionType == QWebEnginePermission::PermissionType::Unsupported)
+ const QWebEnginePermission::PermissionType permissionTypeQt = toQt(permissionTypeBlink);
+ if (permissionTypeQt == QWebEnginePermission::PermissionType::Unsupported)
return blink::mojom::PermissionStatus::DENIED;
- permission = toBlink(toQt(permission)); // Filter out merged/unsupported permissions (e.g. clipboard)
- auto *pref = m_prefService->FindPreference(permissionTypeString(toQt(permission)));
+ permissionTypeBlink = toBlink(toQt(permissionTypeBlink)); // Filter out merged/unsupported permissions (e.g. clipboard)
+ auto *pref = m_prefService->FindPreference(permissionTypeString(permissionTypeQt));
if (!pref)
return blink::mojom::PermissionStatus::ASK; // Permission type not in database
- const auto *permissions = pref->GetValue()->GetIfDict();
- Q_ASSERT(permissions);
+ const auto *permissionsDict = pref->GetValue()->GetIfDict();
+ Q_ASSERT(permissionsDict);
- auto requestedPermission = permissions->FindBool(requesting_origin.DeprecatedGetOriginAsURL().spec());
+ const auto requestedPermission = permissionsDict->FindBool(requesting_origin.DeprecatedGetOriginAsURL().spec());
if (!requestedPermission)
return blink::mojom::PermissionStatus::ASK; // Origin is not in the current permission type's database
- // Workaround: local fonts are entirely managed by Chromium, which only calls RequestPermission() _after_
- // it's checked whether the permission has been granted. By always returning ASK, we force the request to
- // come through every time.
- if (permission == blink::PermissionType::LOCAL_FONTS && !m_persistence)
- return blink::mojom::PermissionStatus::ASK;
-
if (requestedPermission.value())
return blink::mojom::PermissionStatus::GRANTED;
return blink::mojom::PermissionStatus::DENIED;
}
blink::mojom::PermissionStatus PermissionManagerQt::GetPermissionStatusForCurrentDocument(
- blink::PermissionType permission,
+ blink::PermissionType permissionTypeBlink,
content::RenderFrameHost *render_frame_host, bool)
{
Q_ASSERT(render_frame_host);
- if (permission == blink::PermissionType::CLIPBOARD_READ_WRITE ||
- permission == blink::PermissionType::CLIPBOARD_SANITIZED_WRITE) {
+ if (permissionTypeBlink == blink::PermissionType::CLIPBOARD_READ_WRITE ||
+ permissionTypeBlink == blink::PermissionType::CLIPBOARD_SANITIZED_WRITE) {
WebContentsDelegateQt *delegate = static_cast<WebContentsDelegateQt *>(
content::WebContents::FromRenderFrameHost(render_frame_host)->GetDelegate());
Q_ASSERT(delegate);
- auto status = getStatusFromSettings(permission, delegate->webEngineSettings());
+ auto status = getStatusFromSettings(permissionTypeBlink, delegate->webEngineSettings());
if (status != blink::mojom::PermissionStatus::ASK)
return status;
}
- permission = toBlink(toQt(permission)); // Filter out merged/unsupported permissions (e.g. clipboard)
- if (toQt(permission) == QWebEnginePermission::PermissionType::Unsupported)
+ permissionTypeBlink = toBlink(toQt(permissionTypeBlink)); // Filter out merged/unsupported permissions (e.g. clipboard)
+ QWebEnginePermission::PermissionType permissionTypeQt = toQt(permissionTypeBlink);
+ if (permissionTypeQt == QWebEnginePermission::PermissionType::Unsupported)
return blink::mojom::PermissionStatus::DENIED;
GURL origin = render_frame_host->GetLastCommittedOrigin().GetURL();
auto status = blink::mojom::PermissionStatus::ASK;
- bool inTransientStore = !QWebEnginePermission::isPersistent(toQt(permission)) || !m_persistence;
+ const bool inTransientStore = !QWebEnginePermission::isPersistent(permissionTypeQt) || !m_persistence;
if (inTransientStore) {
- status = getTransientPermissionStatus(permission, origin, render_frame_host->GetGlobalFrameToken());
+ status = getTransientPermissionStatus(permissionTypeBlink, origin, render_frame_host->GetGlobalFrameToken());
if (status != blink::mojom::PermissionStatus::ASK) {
return status;
@@ -568,12 +748,12 @@ blink::mojom::PermissionStatus PermissionManagerQt::GetPermissionStatusForCurren
// Fall through to check if permission was pre-granted (and thus landed in the permanent store)
}
- status = GetPermissionStatus(permission, origin, origin);
+ status = GetPermissionStatus(permissionTypeBlink, origin, origin);
if (inTransientStore && status != blink::mojom::PermissionStatus::ASK) {
// Move the pre-granted permission to the transient store and associate it with the rfh
- ResetPermission(permission, origin, origin);
- setTransientPermission(permission, origin, status == blink::mojom::PermissionStatus::GRANTED,
+ ResetPermission(permissionTypeBlink, origin, origin);
+ setTransientPermission(permissionTypeBlink, origin, status == blink::mojom::PermissionStatus::GRANTED,
render_frame_host->GetGlobalFrameToken());
}
@@ -610,9 +790,9 @@ content::PermissionResult PermissionManagerQt::GetPermissionResultForOriginWitho
}
void PermissionManagerQt::ResetPermission(
- blink::PermissionType permission,
- const GURL& requesting_origin,
- const GURL& /*embedding_origin*/)
+ blink::PermissionType permission,
+ const GURL& requesting_origin,
+ const GURL& /*embedding_origin*/)
{
const QWebEnginePermission::PermissionType permissionType = toQt(permission);
if (permissionType == QWebEnginePermission::PermissionType::Unsupported)
@@ -622,12 +802,12 @@ void PermissionManagerQt::ResetPermission(
updater.Get().Remove(requesting_origin.spec());
}
-blink::mojom::PermissionStatus PermissionManagerQt::getTransientPermissionStatus(blink::PermissionType permission,
+blink::mojom::PermissionStatus PermissionManagerQt::getTransientPermissionStatus(
+ blink::PermissionType permissionTypeBlink,
const GURL& requesting_origin,
content::GlobalRenderFrameHostToken token)
{
- const QWebEnginePermission::PermissionType permissionType = toQt(permission);
- if (permissionType == QWebEnginePermission::PermissionType::Unsupported)
+ if (toQt(permissionTypeBlink) == QWebEnginePermission::PermissionType::Unsupported)
return blink::mojom::PermissionStatus::DENIED;
if (!m_transientPermissions.contains(token))
@@ -635,8 +815,10 @@ blink::mojom::PermissionStatus PermissionManagerQt::getTransientPermissionStatus
auto &permissionsForToken = m_transientPermissions[token];
for (auto p = permissionsForToken.begin(); p != permissionsForToken.end(); ++p) {
- if (get<0>(*p) == requesting_origin && get<1>(*p) == permission) {
- return get<2>(*p) ? blink::mojom::PermissionStatus::GRANTED : blink::mojom::PermissionStatus::DENIED;
+ if (get<0>(*p) == requesting_origin && get<1>(*p) == permissionTypeBlink) {
+ return get<2>(*p)
+ ? blink::mojom::PermissionStatus::GRANTED
+ : blink::mojom::PermissionStatus::DENIED;
}
}
@@ -644,47 +826,49 @@ blink::mojom::PermissionStatus PermissionManagerQt::getTransientPermissionStatus
}
void PermissionManagerQt::setPersistentPermission(
- blink::PermissionType permission,
- const GURL& requesting_origin,
- bool granted)
+ blink::PermissionType permissionTypeBlink,
+ const GURL& requesting_origin,
+ bool granted)
{
- const QWebEnginePermission::PermissionType permissionType = toQt(permission);
- if (permissionType == QWebEnginePermission::PermissionType::Unsupported)
+ const QWebEnginePermission::PermissionType permissionTypeQt = toQt(permissionTypeBlink);
+ if (permissionTypeQt == QWebEnginePermission::PermissionType::Unsupported)
return;
- if (!m_prefService->FindPreference(permissionTypeString(permissionType)))
+ if (!m_prefService->FindPreference(permissionTypeString(permissionTypeQt)))
return;
- ScopedDictPrefUpdate updater(m_prefService.get(), permissionTypeString(permissionType));
+ ScopedDictPrefUpdate updater(m_prefService.get(), permissionTypeString(permissionTypeQt));
updater.Get().Set(requesting_origin.spec(), granted);
m_prefService->SchedulePendingLossyWrites();
}
-void PermissionManagerQt::setTransientPermission(blink::PermissionType permission,
+void PermissionManagerQt::setTransientPermission(
+ blink::PermissionType permissionTypeBlink,
const GURL& requesting_origin,
bool granted,
content::GlobalRenderFrameHostToken token)
{
- const QWebEnginePermission::PermissionType permissionType = toQt(permission);
- if (permissionType == QWebEnginePermission::PermissionType::Unsupported)
+ const QWebEnginePermission::PermissionType permissionTypeQt = toQt(permissionTypeBlink);
+ if (permissionTypeQt == QWebEnginePermission::PermissionType::Unsupported)
return;
auto &permissionsForToken = m_transientPermissions[token];
for (auto &p : permissionsForToken) {
- if (get<0>(p) == requesting_origin && get<1>(p) == permission) {
+ if (get<0>(p) == requesting_origin && get<1>(p) == permissionTypeBlink) {
get<2>(p) = granted;
return;
}
}
- permissionsForToken.push_back({requesting_origin, permission, granted});
+ permissionsForToken.push_back({requesting_origin, permissionTypeBlink, granted});
// Render frame hosts get discarded often, so the map will eventualy fill up with junk unless
// periodically cleaned. The number 25 was chosen arbitrarily.
if (++m_transientWriteCount > 25) {
content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
- base::BindOnce([](PermissionManagerQt *p){
+ base::BindOnce([](PermissionManagerQt *p)
+ {
for (auto i = p->m_transientPermissions.begin(); i != p->m_transientPermissions.end(); ++i) {
if (content::RenderFrameHost::FromFrameToken(i->first) == nullptr) {
i = p->m_transientPermissions.erase(i);
@@ -695,17 +879,18 @@ void PermissionManagerQt::setTransientPermission(blink::PermissionType permissio
}
}
-void PermissionManagerQt::resetTransientPermission(blink::PermissionType permission,
+void PermissionManagerQt::resetTransientPermission(
+ blink::PermissionType permissionTypeBlink,
const GURL& requesting_origin,
content::GlobalRenderFrameHostToken token)
{
- const QWebEnginePermission::PermissionType permissionType = toQt(permission);
- if (permissionType == QWebEnginePermission::PermissionType::Unsupported)
+ const QWebEnginePermission::PermissionType permissionTypeQt = toQt(permissionTypeBlink);
+ if (permissionTypeQt == QWebEnginePermission::PermissionType::Unsupported)
return;
auto &permissionsForToken = m_transientPermissions[token];
for (auto i = permissionsForToken.begin(); i != permissionsForToken.end(); ++i) {
- if (get<0>(*i) == requesting_origin && get<1>(*i) == permission) {
+ if (get<0>(*i) == requesting_origin && get<1>(*i) == permissionTypeBlink) {
permissionsForToken.erase(i);
return;
}
diff --git a/src/core/permission_manager_qt.h b/src/core/permission_manager_qt.h
index 7468e9861..d8474d1e1 100644
--- a/src/core/permission_manager_qt.h
+++ b/src/core/permission_manager_qt.h
@@ -6,11 +6,13 @@
#include "base/functional/callback.h"
#include "content/public/browser/global_routing_id.h"
+#include "content/public/browser/media_stream_request.h"
#include "content/public/browser/permission_controller_delegate.h"
#include "content/public/browser/render_frame_host.h"
#include <QtWebEngineCore/qwebenginepermission.h>
#include "profile_adapter.h"
+#include "web_contents_adapter_client.h"
#include <map>
#include <tuple>
@@ -25,14 +27,30 @@ public:
PermissionManagerQt(ProfileAdapter *adapter);
~PermissionManagerQt();
+ static content::GlobalRenderFrameHostToken deserializeToken(int childId, const std::string &serializedToken);
+
+ void setPermission(
+ const QUrl &origin,
+ const QWebEnginePermission::PermissionType permissionType,
+ const QWebEnginePermission::State state,
+ const content::GlobalRenderFrameHostToken &frameToken);
+
void setPermission(
const QUrl &origin,
- QWebEnginePermission::PermissionType permissionType,
- QWebEnginePermission::State state,
- content::RenderFrameHost *rfh = nullptr);
- QWebEnginePermission::State getPermissionState(const QUrl &origin, QWebEnginePermission::PermissionType permissionType,
- content::RenderFrameHost *rfh = nullptr);
- QList<QWebEnginePermission> listPermissions(const QUrl &origin, QWebEnginePermission::PermissionType permissionType);
+ const QWebEnginePermission::PermissionType permissionType,
+ const QWebEnginePermission::State state,
+ int childId, const std::string &serializedToken);
+
+ QWebEnginePermission::State getPermissionState(const QUrl &origin, const QWebEnginePermission::PermissionType permissionType,
+ const content::GlobalRenderFrameHostToken &frameToken);
+ QList<QWebEnginePermission> listPermissions(const QUrl &origin, const QWebEnginePermission::PermissionType permissionType);
+
+ void requestMediaPermissions(
+ content::RenderFrameHost *render_frame_host,
+ const WebContentsAdapterClient::MediaRequestFlags flags,
+ base::OnceCallback<void(WebContentsAdapterClient::MediaRequestFlags authorizationFlags)> callback);
+
+ void onCrossOriginNavigation(content::RenderFrameHost *render_frame_host);
void commit();
@@ -42,7 +60,6 @@ public:
const GURL& requesting_origin,
const GURL& embedding_origin) override;
-
content::PermissionStatus GetPermissionStatusForCurrentDocument(blink::PermissionType, content::RenderFrameHost*, bool) override;
blink::mojom::PermissionStatus GetPermissionStatusForWorker(blink::PermissionType, content::RenderProcessHost *, const GURL &) override;
@@ -85,6 +102,12 @@ private:
base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback;
};
+ void setPermissionImpl(
+ const QUrl &origin,
+ const QWebEnginePermission::PermissionType permissionType,
+ const QWebEnginePermission::State state,
+ const content::GlobalRenderFrameHostToken &frameToken);
+
blink::mojom::PermissionStatus getTransientPermissionStatus(blink::PermissionType permission,
const GURL& requesting_origin,
content::GlobalRenderFrameHostToken token);
diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp
index f0cabc088..1e07f95f3 100644
--- a/src/core/profile_adapter.cpp
+++ b/src/core/profile_adapter.cpp
@@ -33,7 +33,9 @@
#include "renderer_host/user_resource_controller_host.h"
#include "type_conversion.h"
#include "visited_links_manager_qt.h"
+#include "web_contents_adapter.h"
#include "web_contents_adapter_client.h"
+#include "web_contents_delegate_qt.h"
#include "web_engine_context.h"
#include <QCoreApplication>
@@ -627,15 +629,29 @@ UserResourceControllerHost *ProfileAdapter::userResourceController()
}
void ProfileAdapter::setPermission(const QUrl &origin, QWebEnginePermission::PermissionType permissionType,
- QWebEnginePermission::State state, content::RenderFrameHost *rfh)
+ QWebEnginePermission::State state, int childId, const std::string &serializedToken)
{
- static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->setPermission(origin, permissionType, state, rfh);
+ auto token = PermissionManagerQt::deserializeToken(childId, serializedToken);
+
+ // Check if the frame token is valid, and defer to WebContentsAdapter if so
+ auto *rfh = content::RenderFrameHost::FromFrameToken(token);
+ if (rfh) {
+ static_cast<WebContentsDelegateQt *>(content::WebContents::FromRenderFrameHost(rfh)->GetDelegate())
+ ->webContentsAdapter()
+ ->setPermission(origin, permissionType, state, childId, serializedToken);
+ return;
+ }
+
+ // Otherwise, set the permission directly
+ static_cast<PermissionManagerQt *>(profile()->GetPermissionControllerDelegate())
+ ->setPermission(origin, permissionType, state, token);
}
QWebEnginePermission::State ProfileAdapter::getPermissionState(const QUrl &origin, QWebEnginePermission::PermissionType permissionType,
- content::RenderFrameHost *rfh)
+ int childId, const std::string &serializedToken)
{
- return static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->getPermissionState(origin, permissionType, rfh);
+ return static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())
+ ->getPermissionState(origin, permissionType, PermissionManagerQt::deserializeToken(childId, serializedToken));
}
QList<QWebEnginePermission> ProfileAdapter::listPermissions(const QUrl &origin, QWebEnginePermission::PermissionType permissionType)
diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h
index 36d286851..22dd65973 100644
--- a/src/core/profile_adapter.h
+++ b/src/core/profile_adapter.h
@@ -16,6 +16,7 @@
#define PROFILE_ADAPTER_H
#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
+#include <QtWebEngineCore/private/qwebenginepermission_p.h>
#include <QHash>
#include <QList>
@@ -187,9 +188,9 @@ public:
UserResourceControllerHost *userResourceController();
void setPermission(const QUrl &origin, QWebEnginePermission::PermissionType permissionType,
- QWebEnginePermission::State state, content::RenderFrameHost *rfh = nullptr);
+ QWebEnginePermission::State state, int childId = -1, const std::string &serializedToken = std::string());
QWebEnginePermission::State getPermissionState(const QUrl &origin, QWebEnginePermission::PermissionType permissionType,
- content::RenderFrameHost *rfh = nullptr);
+ int childId = -1, const std::string &serializedToken = std::string());
QList<QWebEnginePermission> listPermissions(const QUrl &origin = QUrl(),
QWebEnginePermission::PermissionType permissionType = QWebEnginePermission::PermissionType::Unsupported);
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index 8c4d01e58..685b2acfe 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -16,6 +16,7 @@
#include "find_text_helper.h"
#include "media_capture_devices_dispatcher.h"
#include "pdf_util_qt.h"
+#include "permission_manager_qt.h"
#include "profile_adapter.h"
#include "profile_qt.h"
#include "qwebengineloadinginfo.h"
@@ -1417,17 +1418,18 @@ QSizeF WebContentsAdapter::lastContentsSize() const
return QSizeF();
}
-void WebContentsAdapter::setPermission(const QUrl &origin, QWebEnginePermission::PermissionType permissionType, QWebEnginePermission::State state)
+void WebContentsAdapter::setPermission(
+ const QUrl &origin,
+ QWebEnginePermission::PermissionType permissionType,
+ QWebEnginePermission::State state,
+ int childId, const std::string &serializedToken)
{
+ auto *manager = static_cast<PermissionManagerQt*>(m_profileAdapter->profile()->GetPermissionControllerDelegate());
+
if (QWebEnginePermission::isPersistent(permissionType)) {
// Do not check for initialization in this path so permissions can be set before first navigation
Q_ASSERT(m_profileAdapter);
- if (!isInitialized()) {
- m_profileAdapter->setPermission(origin, permissionType, state);
- } else {
- m_profileAdapter->setPermission(origin, permissionType, state, m_webContents.get()->GetPrimaryMainFrame());
- }
-
+ manager->setPermission(origin, permissionType, state, childId, serializedToken);
return;
}
@@ -1440,115 +1442,87 @@ void WebContentsAdapter::setPermission(const QUrl &origin, QWebEnginePermission:
// Do nothing
break;
case QWebEnginePermission::State::Denied:
- grantMouseLockPermission(origin, false);
+ grantMouseLockPermission(origin, childId, serializedToken, false);
break;
case QWebEnginePermission::State::Granted:
- grantMouseLockPermission(origin, true);
+ grantMouseLockPermission(origin, childId, serializedToken, true);
break;
}
return;
}
- const WebContentsAdapterClient::MediaRequestFlags audioVideoCaptureFlags(
- WebContentsAdapterClient::MediaVideoCapture |
- WebContentsAdapterClient::MediaAudioCapture);
- const WebContentsAdapterClient::MediaRequestFlags desktopAudioVideoCaptureFlags(
- WebContentsAdapterClient::MediaDesktopVideoCapture |
- WebContentsAdapterClient::MediaDesktopAudioCapture);
-
- switch (state) {
- case QWebEnginePermission::State::Invalid:
- case QWebEnginePermission::State::Ask:
- // Do nothing
- return;
- case QWebEnginePermission::State::Denied:
- // Deny all media access
- grantMediaAccessPermission(origin, WebContentsAdapterClient::MediaNone);
- return;
- case QWebEnginePermission::State::Granted:
- // Enable only the requested capture type
- break;
- }
+ // If we reach this, we must be handling media access permissions
+ manager->setPermission(origin, permissionType, state, childId, serializedToken);
- switch (permissionType) {
- case QWebEnginePermission::PermissionType::MediaAudioVideoCapture:
- grantMediaAccessPermission(origin, audioVideoCaptureFlags);
- break;
- case QWebEnginePermission::PermissionType::MediaAudioCapture:
- grantMediaAccessPermission(origin, WebContentsAdapterClient::MediaAudioCapture);
- break;
- case QWebEnginePermission::PermissionType::MediaVideoCapture:
- grantMediaAccessPermission(origin, WebContentsAdapterClient::MediaVideoCapture);
- break;
- case QWebEnginePermission::PermissionType::DesktopAudioVideoCapture:
- grantMediaAccessPermission(origin, desktopAudioVideoCaptureFlags);
- break;
- case QWebEnginePermission::PermissionType::DesktopVideoCapture:
- grantMediaAccessPermission(origin, WebContentsAdapterClient::MediaDesktopVideoCapture);
- break;
- default:
- Q_UNREACHABLE();
- break;
+ WebContentsAdapterClient::MediaRequestFlags flags = WebContentsAdapterClient::MediaNone;
+ if (state == QWebEnginePermission::State::Granted) {
+ switch (permissionType) {
+ case QWebEnginePermission::PermissionType::MediaAudioCapture:
+ flags.setFlag(WebContentsAdapterClient::MediaAudioCapture);
+ break;
+ case QWebEnginePermission::PermissionType::MediaVideoCapture:
+ flags.setFlag(WebContentsAdapterClient::MediaVideoCapture);
+ break;
+ case QWebEnginePermission::PermissionType::MediaAudioVideoCapture:
+ flags.setFlag(WebContentsAdapterClient::MediaAudioCapture);
+ flags.setFlag(WebContentsAdapterClient::MediaVideoCapture);
+ break;
+ case QWebEnginePermission::PermissionType::DesktopVideoCapture:
+ flags.setFlag(WebContentsAdapterClient::MediaDesktopVideoCapture);
+ break;
+ case QWebEnginePermission::PermissionType::DesktopAudioVideoCapture:
+ flags.setFlag(WebContentsAdapterClient::MediaDesktopAudioCapture);
+ flags.setFlag(WebContentsAdapterClient::MediaDesktopVideoCapture);
+ break;
+ default:
+ break;
+ }
}
-}
-QWebEnginePermission::State WebContentsAdapter::getPermissionState(const QUrl &origin, QWebEnginePermission::PermissionType permissionType)
-{
- return m_profileAdapter->getPermissionState(origin, permissionType, m_webContents.get()->GetPrimaryMainFrame());
-}
-
-void WebContentsAdapter::grantMediaAccessPermission(const QUrl &origin, WebContentsAdapterClient::MediaRequestFlags flags)
-{
- CHECK_INITIALIZED();
- // Let the permission manager remember the reply.
- if (flags & WebContentsAdapterClient::MediaAudioCapture)
- m_profileAdapter->setPermission(origin,
- QWebEnginePermission::PermissionType::MediaAudioCapture,
- QWebEnginePermission::State::Granted,
- m_webContents.get()->GetPrimaryMainFrame());
- if (flags & WebContentsAdapterClient::MediaVideoCapture)
- m_profileAdapter->setPermission(origin,
- QWebEnginePermission::PermissionType::MediaVideoCapture,
- QWebEnginePermission::State::Granted,
- m_webContents.get()->GetPrimaryMainFrame());
MediaCaptureDevicesDispatcher::GetInstance()->handleMediaAccessPermissionResponse(m_webContents.get(), origin, flags);
}
-void WebContentsAdapter::grantMouseLockPermission(const QUrl &securityOrigin, bool granted)
+void WebContentsAdapter::grantMouseLockPermission(const QUrl &securityOrigin, int childId,
+ const std::string &serializedToken, bool granted)
{
CHECK_INITIALIZED();
- if (securityOrigin != toQt(m_webContents->GetLastCommittedURL().DeprecatedGetOriginAsURL()))
- return;
- if (granted) {
- if (RenderWidgetHostViewQt *rwhv = static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())) {
- rwhv->Focus();
- if (!rwhv->HasFocus()) {
- // We tried to activate our RWHVQtDelegate, but we failed. This probably means that
- // the permission was granted from a modal dialog and the windowing system is not ready
- // to set focus on the originating view. Since pointer lock strongly requires it, we just
- // wait until the next FocusIn event.
- m_pendingMouseLockPermissions.insert(securityOrigin, granted);
- return;
- }
- } else
- granted = false;
+ bool focused = false;
+ if (RenderWidgetHostViewQt *rwhv = static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())) {
+ rwhv->Focus();
+ if (rwhv->HasFocus()) {
+ focused = true;
+ }
+ } else {
+ granted = false;
}
- m_webContents->GotResponseToPointerLockRequest(granted ? blink::mojom::PointerLockResult::kSuccess
- : blink::mojom::PointerLockResult::kPermissionDenied);
+ m_pendingMouseLockPermissions.enqueue({ securityOrigin, granted, childId, serializedToken });
+
+ if (focused) {
+ handlePendingMouseLockPermission();
+ }
}
void WebContentsAdapter::handlePendingMouseLockPermission()
{
CHECK_INITIALIZED();
- auto it = m_pendingMouseLockPermissions.find(toQt(m_webContents->GetLastCommittedURL().DeprecatedGetOriginAsURL()));
- if (it != m_pendingMouseLockPermissions.end()) {
- m_webContents->GotResponseToPointerLockRequest(it.value() ? blink::mojom::PointerLockResult::kSuccess
- : blink::mojom::PointerLockResult::kPermissionDenied);
- m_pendingMouseLockPermissions.erase(it);
- }
+ if (!m_pendingMouseLockPermissions.size())
+ return;
+
+ auto pending = m_pendingMouseLockPermissions.dequeue();
+
+ // Simply set the permission in the manager. The callback from WebContentsDelegateQt::RequestPointerLock()
+ // will ensure WebContents receives the response
+ auto *manager = static_cast<PermissionManagerQt*>(m_profileAdapter->profile()->GetPermissionControllerDelegate());
+ manager->setPermission(
+ get<0>(pending), // origin
+ QWebEnginePermission::PermissionType::MouseLock,
+ get<1>(pending) // granted
+ ? QWebEnginePermission::State::Granted : QWebEnginePermission::State::Denied,
+ get<2>(pending), // childId
+ get<3>(pending)); // serializedToken
}
void WebContentsAdapter::setBackgroundColor(const QColor &color)
diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h
index 3bb639b1b..212411109 100644
--- a/src/core/web_contents_adapter.h
+++ b/src/core/web_contents_adapter.h
@@ -21,6 +21,7 @@
#include <QtCore/QUrl>
#include <QtCore/QVariant>
#include <QtCore/QPointer>
+#include <QtCore/QQueue>
#include <QtGui/qtgui-config.h>
#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
#include <QtWebEngineCore/qwebenginecontextmenurequest.h>
@@ -48,6 +49,7 @@ namespace content {
class WebContents;
class SiteInstance;
class RenderFrameHost;
+struct GlobalRenderFrameHostToken;
}
QT_BEGIN_NAMESPACE
@@ -179,11 +181,9 @@ public:
void devToolsFrontendDestroyed(DevToolsFrontendQt *frontend);
QString devToolsId();
- void setPermission(const QUrl &origin, QWebEnginePermission::PermissionType permissionType, QWebEnginePermission::State state);
- QWebEnginePermission::State getPermissionState(const QUrl &origin, QWebEnginePermission::PermissionType permissionType);
-
- void grantMediaAccessPermission(const QUrl &origin, WebContentsAdapterClient::MediaRequestFlags flags);
- void grantMouseLockPermission(const QUrl &origin, bool granted);
+ void setPermission(const QUrl &origin, QWebEnginePermission::PermissionType permissionType,
+ QWebEnginePermission::State state, int childId = -1, const std::string &serializedToken = std::string());
+ void grantMouseLockPermission(const QUrl &origin, int childId, const std::string &serializedToken, bool granted);
void handlePendingMouseLockPermission();
void setBackgroundColor(const QColor &color);
@@ -272,7 +272,7 @@ private:
#endif
WebContentsAdapterClient *m_adapterClient;
quint64 m_nextRequestId;
- QMap<QUrl, bool> m_pendingMouseLockPermissions;
+ QQueue<std::tuple<QUrl, bool, int, std::string>> m_pendingMouseLockPermissions;
QMap<quint64, std::function<void(const QVariant &)>> m_javaScriptCallbacks;
std::map<quint64, std::function<void(QSharedPointer<QByteArray>)>> m_printCallbacks;
std::unique_ptr<content::DropData> m_currentDropData;
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index 9ce5bebfc..2f93d4783 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -16,6 +16,7 @@
#define WEB_CONTENTS_ADAPTER_CLIENT_H
#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
+#include <QtWebEngineCore/private/qwebenginepermission_p.h>
#include <QtWebEngineCore/qwebenginepermission.h>
#include "profile_adapter.h"
@@ -195,9 +196,8 @@ public:
virtual QObject *accessibilityParentObject() = 0;
virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) = 0;
virtual void authenticationRequired(QSharedPointer<AuthenticationDialogController>) = 0;
- virtual void runFeaturePermissionRequest(QWebEnginePermission::PermissionType, const QUrl &securityOrigin) = 0;
- virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) = 0;
- virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0;
+ virtual void runFeaturePermissionRequest(QWebEnginePermission::PermissionType, const QUrl &securityOrigin,
+ int childId, const std::string &serializedToken) = 0;
virtual void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) = 0;
virtual void runFileSystemAccessRequest(QWebEngineFileSystemAccessRequest) = 0;
virtual QWebEngineSettings *webEngineSettings() const = 0;
@@ -229,7 +229,6 @@ public:
virtual WebContentsAdapter* webContentsAdapter() = 0;
virtual void releaseProfile() = 0;
virtual void showWebAuthDialog(QWebEngineWebAuthUxRequest *request) = 0;
- virtual QWebEnginePermission createFeaturePermissionObject(const QUrl &securityOrigin, QWebEnginePermission::PermissionType permissionType) = 0;
};
} // namespace QtWebEngineCore
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 89a0a6582..77ba5ec91 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -19,6 +19,7 @@
#include "javascript_dialog_manager_qt.h"
#include "media_capture_devices_dispatcher.h"
#include "native_web_keyboard_event_qt.h"
+#include "permission_manager_qt.h"
#include "profile_adapter.h"
#include "profile_qt.h"
#include "qwebengineloadinginfo.h"
@@ -418,6 +419,12 @@ void WebContentsDelegateQt::emitLoadCommitted()
void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navigation_handle)
{
+ if (navigation_handle->HasCommitted() && !navigation_handle->IsSameOrigin()) {
+ PermissionManagerQt *permissionManager = static_cast<PermissionManagerQt *>(
+ navigation_handle->GetWebContents()->GetBrowserContext()->GetPermissionControllerDelegate());
+ permissionManager->onCrossOriginNavigation(navigation_handle->GetRenderFrameHost());
+ }
+
if (!navigation_handle->IsInMainFrame())
return;
@@ -731,14 +738,32 @@ void WebContentsDelegateQt::ActivateContents(content::WebContents* contents)
void WebContentsDelegateQt::RequestPointerLock(content::WebContents *web_contents, bool user_gesture, bool last_unlocked_by_target)
{
- Q_UNUSED(user_gesture);
-
if (last_unlocked_by_target)
web_contents->GotResponseToPointerLockRequest(blink::mojom::PointerLockResult::kSuccess);
- else
- m_viewClient->runMouseLockPermissionRequest(toQt(web_contents->GetLastCommittedURL().DeprecatedGetOriginAsURL()));
+ else {
+ PermissionManagerQt *permissionManager = static_cast<PermissionManagerQt *>(
+ web_contents->GetBrowserContext()->GetPermissionControllerDelegate());
+
+ auto *rfh = web_contents->GetFocusedFrame();
+ if (!rfh)
+ rfh = web_contents->GetPrimaryMainFrame();
+
+ permissionManager->RequestPermissions(
+ rfh,
+ content::PermissionRequestDescription(blink::PermissionType::POINTER_LOCK, user_gesture, rfh->GetLastCommittedOrigin().GetURL()),
+ base::BindOnce([](content::WebContents *web_contents, PermissionManagerQt *manager, const std::vector<blink::mojom::PermissionStatus> &status)
+ {
+ Q_ASSERT(status.size() == 1);
+
+ web_contents->GotResponseToPointerLockRequest(status[0] == blink::mojom::PermissionStatus::GRANTED
+ ? blink::mojom::PointerLockResult::kSuccess
+ : blink::mojom::PointerLockResult::kPermissionDenied);
+ }, web_contents, permissionManager)
+ );
+ }
}
+
void WebContentsDelegateQt::overrideWebPreferences(content::WebContents *webContents, blink::web_pref::WebPreferences *webPreferences)
{
WebEngineSettings::get(m_viewClient->webEngineSettings())->overrideWebPreferences(webContents, webPreferences);
@@ -773,9 +798,12 @@ void WebContentsDelegateQt::selectClientCert(const QSharedPointer<ClientCertSele
m_viewClient->selectClientCert(selectController);
}
-void WebContentsDelegateQt::requestFeaturePermission(QWebEnginePermission::PermissionType permissionType, const QUrl &requestingOrigin)
+void WebContentsDelegateQt::requestFeaturePermission(
+ QWebEnginePermission::PermissionType permissionType,
+ const QUrl &requestingOrigin,
+ const content::GlobalRenderFrameHostToken &frameToken)
{
- m_viewClient->runFeaturePermissionRequest(permissionType, requestingOrigin);
+ m_viewClient->runFeaturePermissionRequest(permissionType, requestingOrigin, frameToken.child_id, frameToken.frame_token.ToString());
}
extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition);
@@ -834,18 +862,22 @@ bool WebContentsDelegateQt::CheckMediaAccessPermission(content::RenderFrameHost
blink::mojom::MediaStreamType type)
{
Q_ASSERT(rfh);
+
+ auto token = rfh->GetGlobalFrameToken();
+ std::string serializedToken = token.frame_token.ToString();
+
switch (type) {
case blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE:
return m_viewClient->profileAdapter()->getPermissionState(
toQt(security_origin),
QWebEnginePermission::PermissionType::MediaAudioCapture,
- rfh)
+ token.child_id, serializedToken)
== QWebEnginePermission::State::Granted;
case blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE:
return m_viewClient->profileAdapter()->getPermissionState(
toQt(security_origin),
QWebEnginePermission::PermissionType::MediaVideoCapture,
- rfh)
+ token.child_id, serializedToken)
== QWebEnginePermission::State::Granted;
default:
LOG(INFO) << "WebContentsDelegateQt::CheckMediaAccessPermission: "
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index 099d8280b..383803c4d 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -25,6 +25,7 @@ class ColorChooser;
class JavaScriptDialogManager;
class WebContents;
struct MediaStreamRequest;
+struct GlobalRenderFrameHostToken;
}
namespace QtWebEngineCore {
@@ -144,7 +145,7 @@ public:
void overrideWebPreferences(content::WebContents *, blink::web_pref::WebPreferences*);
void allowCertificateError(const QSharedPointer<CertificateErrorController> &);
void selectClientCert(const QSharedPointer<ClientCertSelectController> &);
- void requestFeaturePermission(QWebEnginePermission::PermissionType permissionType, const QUrl &requestingOrigin);
+ void requestFeaturePermission(QWebEnginePermission::PermissionType permissionType, const QUrl &requestingOrigin, const content::GlobalRenderFrameHostToken &frameToken);
void launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture);
FindTextHelper *findTextHelper();
diff --git a/src/webenginequick/api/qquickwebengineprofile.cpp b/src/webenginequick/api/qquickwebengineprofile.cpp
index dce3c8822..80e4ec5ac 100644
--- a/src/webenginequick/api/qquickwebengineprofile.cpp
+++ b/src/webenginequick/api/qquickwebengineprofile.cpp
@@ -1229,7 +1229,7 @@ QWebEnginePermission QQuickWebEngineProfile::queryPermission(const QUrl &securit
return QWebEnginePermission(new QWebEnginePermissionPrivate());
}
- auto *pvt = new QWebEnginePermissionPrivate(securityOrigin, permissionType, nullptr, d->profileAdapter());
+ auto *pvt = new QWebEnginePermissionPrivate(securityOrigin, permissionType, d->profileAdapter());
return QWebEnginePermission(pvt);
}
diff --git a/src/webenginequick/api/qquickwebengineview.cpp b/src/webenginequick/api/qquickwebengineview.cpp
index ade8b451c..619cbaef6 100644
--- a/src/webenginequick/api/qquickwebengineview.cpp
+++ b/src/webenginequick/api/qquickwebengineview.cpp
@@ -521,22 +521,30 @@ static QQuickWebEngineView::Feature toDeprecatedFeature(QWebEnginePermission::Pe
QT_WARNING_POP
#endif // QT_DEPRECATED_SINCE(6, 8)
-void QQuickWebEngineViewPrivate::runFeaturePermissionRequest(QWebEnginePermission::PermissionType permissionType, const QUrl &securityOrigin)
+void QQuickWebEngineViewPrivate::runFeaturePermissionRequest(
+ QWebEnginePermission::PermissionType permissionType,
+ const QUrl &securityOrigin,
+ int childId, const std::string &serializedToken)
{
Q_Q(QQuickWebEngineView);
- if (QWebEnginePermission::isPersistent(permissionType)) {
- Q_EMIT q->permissionRequested(createFeaturePermissionObject(securityOrigin, permissionType));
-#if QT_DEPRECATED_SINCE(6, 8)
- QT_WARNING_PUSH
- QT_WARNING_DISABLE_DEPRECATED
- Q_EMIT q->featurePermissionRequested(securityOrigin, toDeprecatedFeature(permissionType));
- QT_WARNING_POP
-#endif // QT_DEPRECATED_SINCE(6, 8)
+ if (permissionType == QWebEnginePermission::PermissionType::MouseLock) {
+ // Not supported in Qt Quick
+ auto permission = QWebEnginePermission(
+ new QWebEnginePermissionPrivate(securityOrigin, permissionType, profileAdapter(), childId, serializedToken));
+ permission.deny();
return;
}
- Q_UNREACHABLE();
+ Q_EMIT q->permissionRequested(QWebEnginePermission(
+ new QWebEnginePermissionPrivate(securityOrigin, permissionType, profileAdapter(), childId, serializedToken)));
+#if QT_DEPRECATED_SINCE(6, 8)
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+ Q_EMIT q->featurePermissionRequested(securityOrigin, toDeprecatedFeature(permissionType));
+ QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 8)
+ return;
}
void QQuickWebEngineViewPrivate::showColorDialog(QSharedPointer<ColorChooserController> controller)
@@ -809,54 +817,6 @@ void QQuickWebEngineViewPrivate::authenticationRequired(QSharedPointer<Authentic
ui()->showDialog(controller);
}
-void QQuickWebEngineViewPrivate::runMediaAccessPermissionRequest(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags requestFlags)
-{
- Q_Q(QQuickWebEngineView);
- if (!requestFlags)
- return;
- QWebEnginePermission::PermissionType permissionType;
- if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture))
- permissionType = QWebEnginePermission::PermissionType::MediaAudioVideoCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture))
- permissionType = QWebEnginePermission::PermissionType::MediaAudioCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture))
- permissionType = QWebEnginePermission::PermissionType::MediaVideoCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture) &&
- requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture))
- permissionType = QWebEnginePermission::PermissionType::DesktopAudioVideoCapture;
- else // if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture))
- permissionType = QWebEnginePermission::PermissionType::DesktopVideoCapture;
- Q_EMIT q->permissionRequested(createFeaturePermissionObject(securityOrigin, permissionType));
-
-#if QT_DEPRECATED_SINCE(6, 8)
- QT_WARNING_PUSH
- QT_WARNING_DISABLE_DEPRECATED
- QQuickWebEngineView::Feature deprecatedFeature;
-
- if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)
- && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture))
- deprecatedFeature = QQuickWebEngineView::MediaAudioVideoCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture))
- deprecatedFeature = QQuickWebEngineView::MediaAudioCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture))
- deprecatedFeature = QQuickWebEngineView::MediaVideoCapture;
- else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture)
- && requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture))
- deprecatedFeature = QQuickWebEngineView::DesktopAudioVideoCapture;
- else // if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture))
- deprecatedFeature = QQuickWebEngineView::DesktopVideoCapture;
-
- Q_EMIT q->featurePermissionRequested(securityOrigin, deprecatedFeature);
- QT_WARNING_POP
-#endif // QT_DEPRECATED_SINCE(6, 8)
-}
-
-void QQuickWebEngineViewPrivate::runMouseLockPermissionRequest(const QUrl &securityOrigin)
-{
- // TODO: Add mouse lock support
- adapter->grantMouseLockPermission(securityOrigin, false);
-}
-
void QQuickWebEngineViewPrivate::runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest request)
{
Q_Q(QQuickWebEngineView);
@@ -1523,12 +1483,6 @@ void QQuickWebEngineViewPrivate::showWebAuthDialog(QWebEngineWebAuthUxRequest *r
Q_EMIT q->webAuthUxRequested(request);
}
-QWebEnginePermission QQuickWebEngineViewPrivate::createFeaturePermissionObject(const QUrl &securityOrigin, QWebEnginePermission::PermissionType permissionType)
-{
- auto *returnPrivate = new QWebEnginePermissionPrivate(securityOrigin, permissionType, adapter, profileAdapter());
- return QWebEnginePermission(returnPrivate);
-}
-
bool QQuickWebEngineView::isLoading() const
{
Q_D(const QQuickWebEngineView);
diff --git a/src/webenginequick/api/qquickwebengineview_p_p.h b/src/webenginequick/api/qquickwebengineview_p_p.h
index d78157597..8fe98145b 100644
--- a/src/webenginequick/api/qquickwebengineview_p_p.h
+++ b/src/webenginequick/api/qquickwebengineview_p_p.h
@@ -105,8 +105,6 @@ public:
bool passOnFocus(bool reverse) override;
void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) override;
void authenticationRequired(QSharedPointer<QtWebEngineCore::AuthenticationDialogController>) override;
- void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) override;
- void runMouseLockPermissionRequest(const QUrl &securityOrigin) override;
void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) override;
void runFileSystemAccessRequest(QWebEngineFileSystemAccessRequest) override;
QObject *accessibilityParentObject() override;
@@ -114,7 +112,8 @@ public:
void allowCertificateError(const QWebEngineCertificateError &error) override;
void selectClientCert(const QSharedPointer<QtWebEngineCore::ClientCertSelectController>
&selectController) override;
- void runFeaturePermissionRequest(QWebEnginePermission::PermissionType permissionType, const QUrl &securityOrigin) override;
+ void runFeaturePermissionRequest(QWebEnginePermission::PermissionType permissionType, const QUrl &securityOrigin,
+ int childId, const std::string &serializedToken) override;
void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) override;
void requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) override;
void updateScrollPosition(const QPointF &position) override;
@@ -139,7 +138,6 @@ public:
const QRect &bounds, bool autoselectFirstSuggestion) override;
void hideAutofillPopup() override;
void showWebAuthDialog(QWebEngineWebAuthUxRequest *request) override;
- QWebEnginePermission createFeaturePermissionObject(const QUrl &securityOrigin, QWebEnginePermission::PermissionType permissionType) override;
void updateAction(QQuickWebEngineView::WebAction) const;
bool adoptWebContents(QtWebEngineCore::WebContentsAdapter *webContents);