From b4b5c648c23be398770ad5bc0643318ce5ffdeb8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Oct 2016 11:29:09 -0700 Subject: [PATCH] use a QWebEngineProfile request interceptor for auth in HTTP header --- .../qml/controls-uit/BaseWebView.qml | 22 --------------- interface/resources/qml/hifi/Desktop.qml | 6 ++--- interface/src/Application.cpp | 7 ++--- interface/src/HFWebEngineProfile.cpp | 27 +++++++++++++++++++ interface/src/HFWebEngineProfile.h | 25 +++++++++++++++++ .../src/HFWebEngineRequestInterceptor.cpp | 24 +++++++++++++++-- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 18 ------------- libraries/ui/src/QmlWebWindowClass.cpp | 5 +--- libraries/ui/src/QmlWebWindowClass.h | 2 +- 9 files changed, 80 insertions(+), 56 deletions(-) create mode 100644 interface/src/HFWebEngineProfile.cpp create mode 100644 interface/src/HFWebEngineProfile.h diff --git a/interface/resources/qml/controls-uit/BaseWebView.qml b/interface/resources/qml/controls-uit/BaseWebView.qml index a5b724f113..6c351a1ed0 100644 --- a/interface/resources/qml/controls-uit/BaseWebView.qml +++ b/interface/resources/qml/controls-uit/BaseWebView.qml @@ -25,28 +25,6 @@ WebEngineView { }); } - // FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6 - Timer { - id: urlReplacementTimer - running: false - repeat: false - interval: 50 - onTriggered: url = newUrl; - } - - onUrlChanged: { - var originalUrl = url.toString(); - newUrl = urlHandler.fixupUrl(originalUrl).toString(); - if (newUrl !== originalUrl) { - root.stop(); - if (urlReplacementTimer.running) { - console.warn("Replacement timer already running"); - return; - } - urlReplacementTimer.start(); - } - } - onLoadingChanged: { // Required to support clicking on "hifi://" links if (WebEngineView.LoadStartedStatus == loadRequest.status) { diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index 7e523bbb70..6581d6761c 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -2,6 +2,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtWebEngine 1.1; import Qt.labs.settings 1.0 +import HFWebEngineProfile 1.0 import "../desktop" as OriginalDesktop import ".." @@ -20,17 +21,14 @@ OriginalDesktop.Desktop { onEntered: ApplicationCompositor.reticleOverDesktop = true onExited: ApplicationCompositor.reticleOverDesktop = false acceptedButtons: Qt.NoButton - - } // The tool window, one instance property alias toolWindow: toolWindow ToolWindow { id: toolWindow } - property var browserProfile: WebEngineProfile { + property var browserProfile: HFWebEngineProfile { id: webviewProfile - httpUserAgent: "Chrome/48.0 (HighFidelityInterface)" storageName: "qmlWebEngine" } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5b4c76f3bc..41287746a0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -123,7 +123,7 @@ #include "devices/Leapmotion.h" #include "DiscoverabilityManager.h" #include "GLCanvas.h" -#include "HFWebEngineRequestInterceptor.h" +#include "HFWebEngineProfile.h" #include "InterfaceActionFactory.h" #include "InterfaceLogging.h" #include "LODManager.h" @@ -1097,10 +1097,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : SpacemouseManager::getInstance().init(); #endif - // we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user - auto requestInterceptor = new HFWebEngineRequestInterceptor(this); - QWebEngineProfile::defaultProfile()->setRequestInterceptor(requestInterceptor); - // If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it auto entityScriptingInterface = DependencyManager::get(); connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, @@ -1681,6 +1677,7 @@ void Application::initializeUi() { UpdateDialog::registerType(); qmlRegisterType("Hifi", 1, 0, "Preference"); + qmlRegisterType("HFWebEngineProfile", 1, 0, "HFWebEngineProfile"); auto offscreenUi = DependencyManager::get(); offscreenUi->create(_glWidget->qglContext()); diff --git a/interface/src/HFWebEngineProfile.cpp b/interface/src/HFWebEngineProfile.cpp new file mode 100644 index 0000000000..2e76ebfcf2 --- /dev/null +++ b/interface/src/HFWebEngineProfile.cpp @@ -0,0 +1,27 @@ +// +// HFWebEngineProfile.cpp +// interface/src +// +// Created by Stephen Birarda on 2016-10-17. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "HFWebEngineProfile.h" + +#include "HFWebEngineRequestInterceptor.h" + +static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine"; + +HFWebEngineProfile::HFWebEngineProfile(QObject* parent) : + QQuickWebEngineProfile(parent) +{ + static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)"; + setHttpUserAgent(WEB_ENGINE_USER_AGENT); + + // we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user + auto requestInterceptor = new HFWebEngineRequestInterceptor(this); + setRequestInterceptor(requestInterceptor); +} diff --git a/interface/src/HFWebEngineProfile.h b/interface/src/HFWebEngineProfile.h new file mode 100644 index 0000000000..68d1fcc934 --- /dev/null +++ b/interface/src/HFWebEngineProfile.h @@ -0,0 +1,25 @@ +// +// HFWebEngineProfile.h +// interface/src +// +// Created by Stephen Birarda on 2016-10-17. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once + +#ifndef hifi_HFWebEngineProfile_h +#define hifi_HFWebEngineProfile_h + +#include + +class HFWebEngineProfile : public QQuickWebEngineProfile { +public: + HFWebEngineProfile(QObject* parent = Q_NULLPTR); +}; + + +#endif // hifi_HFWebEngineProfile_h diff --git a/interface/src/HFWebEngineRequestInterceptor.cpp b/interface/src/HFWebEngineRequestInterceptor.cpp index 9a710a7551..0fd7ff029c 100644 --- a/interface/src/HFWebEngineRequestInterceptor.cpp +++ b/interface/src/HFWebEngineRequestInterceptor.cpp @@ -13,6 +13,26 @@ #include -void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) { - qDebug() << "==================== We have a request we can intercept! COOL!"; +#include + +bool isHighFidelityURL(const QUrl& url) { + static const QStringList HF_HOSTS = { + "highfidelity.com", "highfidelity.io", + "metaverse.highfidelity.com", "metaverse.highfidelity.io" + }; + + return HF_HOSTS.contains(url.host()); +} + +void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) { + // check if this is a request to a highfidelity URL + if (isHighFidelityURL(info.requestUrl())) { + // if we have an access token, add it to the right HTTP header for authorization + auto accountManager = DependencyManager::get(); + + static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization"; + + QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token; + info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit()); + } } diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index d16968f370..8bf510bb2a 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -40,19 +40,6 @@ #include "TextureRecycler.h" #include "Context.h" -QString fixupHifiUrl(const QString& urlString) { - static const QString ACCESS_TOKEN_PARAMETER = "access_token"; - static const QString ALLOWED_HOST = "metaverse.highfidelity.com"; - QUrl url(urlString); - QUrlQuery query(url); - if (url.host() == ALLOWED_HOST && query.allQueryItemValues(ACCESS_TOKEN_PARAMETER).empty()) { - auto accountManager = DependencyManager::get(); - query.addQueryItem(ACCESS_TOKEN_PARAMETER, accountManager->getAccountInfo().getAccessToken().token); - url.setQuery(query.query()); - return url.toString(); - } - return urlString; -} class UrlHandler : public QObject { Q_OBJECT @@ -66,11 +53,6 @@ public: static auto handler = dynamic_cast(qApp); return handler->acceptURL(url); } - - // FIXME hack for authentication, remove when we migrate to Qt 5.6 - Q_INVOKABLE QString fixupUrl(const QString& originalUrl) { - return fixupHifiUrl(originalUrl); - } }; // Time between receiving a request to render the offscreen UI actually triggering diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 84d0aa0489..2130e84220 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -86,13 +86,10 @@ QString QmlWebWindowClass::getURL() const { return result.toString(); } -// HACK find a good place to declare and store this -extern QString fixupHifiUrl(const QString& urlString); - void QmlWebWindowClass::setURL(const QString& urlString) { DependencyManager::get()->executeOnUiThread([=] { if (!_qmlWindow.isNull()) { - _qmlWindow->setProperty(URL_PROPERTY, fixupHifiUrl(urlString)); + _qmlWindow->setProperty(URL_PROPERTY, urlString); } }); } diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h index e32c6d5a04..731afb3acb 100644 --- a/libraries/ui/src/QmlWebWindowClass.h +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -19,7 +19,7 @@ class QmlWebWindowClass : public QmlWindowClass { public: static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); - public slots: +public slots: QString getURL() const; void setURL(const QString& url);