Merge pull request #8828 from birarda/web-engine-interceptor

move HF access token to authorization header
This commit is contained in:
Stephen Birarda 2016-10-18 17:24:58 -07:00 committed by GitHub
commit 9f2627d31d
15 changed files with 145 additions and 82 deletions

View file

@ -41,8 +41,10 @@ endif ()
if (ANDROID)
set(PLATFORM_QT_COMPONENTS AndroidExtras)
set(PLATFORM_QT_LIBRARIES Qt5::AndroidExtras)
else ()
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
set(PLATFORM_QT_LIBRARIES Qt5::WebEngine Qt5::WebEngineWidgets)
endif ()
find_package(
@ -244,7 +246,8 @@ target_link_libraries(
${TARGET_NAME}
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL
Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
Qt5::WebChannel Qt5::WebEngine
Qt5::WebChannel Qt5::WebEngine
${PLATFORM_QT_LIBRARIES}
)
if (UNIX)

View file

@ -10,10 +10,10 @@
import QtQuick 2.5
import QtWebEngine 1.2
import HFWebEngineProfile 1.0
WebEngineView {
id: root
property var newUrl;
profile: desktop.browserProfile
@ -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) {

View file

@ -2,6 +2,7 @@ import QtQuick 2.5
import QtWebEngine 1.1
import QtWebChannel 1.0
import "../controls-uit" as HiFiControls
import HFWebEngineProfile 1.0
Item {
property alias url: root.url
@ -31,6 +32,11 @@ Item {
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFWebEngineProfile {
id: webviewProfile
storageName: "qmlWebEngine"
}
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
@ -62,28 +68,6 @@ Item {
root.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)";
}
// 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 = root.newUrl;
}
onUrlChanged: {
var originalUrl = url.toString();
root.newUrl = urlHandler.fixupUrl(originalUrl).toString();
if (root.newUrl !== originalUrl) {
root.stop();
if (urlReplacementTimer.running) {
console.warn("Replacement timer already running");
return;
}
urlReplacementTimer.start();
}
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}

View file

@ -33,7 +33,7 @@ FocusScope {
}
}
onHeightChanged: d.handleSizeChanged();
onWidthChanged: d.handleSizeChanged();

View file

@ -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"
}
@ -127,5 +125,3 @@ OriginalDesktop.Desktop {
return result;
}
}

View file

@ -34,6 +34,8 @@
#include <QtQml/QQmlEngine>
#include <QtQuick/QQuickWindow>
#include <QtWebEngineWidgets/QWebEngineProfile>
#include <QtWidgets/QDesktopWidget>
#include <QtWidgets/QMessageBox>
@ -65,6 +67,7 @@
#include <gpu/gl/GLBackend.h>
#include <HFActionEvent.h>
#include <HFBackEvent.h>
#include <HFWebEngineProfile.h>
#include <InfoView.h>
#include <input-plugins/InputPlugin.h>
#include <controllers/UserInputMapper.h>
@ -126,6 +129,7 @@
#include "InterfaceLogging.h"
#include "LODManager.h"
#include "ModelPackager.h"
#include "scripting/AccountScriptingInterface.h"
#include "scripting/AssetMappingsScriptingInterface.h"
#include "scripting/AudioDeviceScriptingInterface.h"
@ -1698,6 +1702,7 @@ void Application::initializeUi() {
UpdateDialog::registerType();
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference");
qmlRegisterType<HFWebEngineProfile>("HFWebEngineProfile", 1, 0, "HFWebEngineProfile");
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create(_glWidget->qglContext());

View file

@ -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<AccountManager>();
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<AbstractUriHandler*>(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

View file

@ -143,13 +143,13 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) {
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->hasValidAccessToken()) {
QUrlQuery urlQuery(_url.query());
urlQuery.addQueryItem("access_token", accountManager->getAccountInfo().getAccessToken().token);
_url.setQuery(urlQuery);
if (_url.scheme() == "https" && accountManager->hasValidAccessToken()) {
static const QString HTTP_AUTHORIZATION_HEADER = "Authorization";
QString bearerString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token;
_request.setRawHeader(HTTP_AUTHORIZATION_HEADER.toLocal8Bit(), bearerString.toLocal8Bit());
}
}
if (!username.isEmpty()) {
_url.setUserName(username);
}

View file

@ -1,3 +1,3 @@
set(TARGET_NAME ui)
setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebSockets XmlPatterns)
setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebEngine WebSockets XmlPatterns)
link_hifi_libraries(shared networking gl)

View file

@ -0,0 +1,27 @@
//
// HFWebEngineProfile.cpp
// interface/src/networking
//
// 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);
}

View file

@ -0,0 +1,25 @@
//
// HFWebEngineProfile.h
// interface/src/networking
//
// 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 <QtWebEngine/QQuickWebEngineProfile>
class HFWebEngineProfile : public QQuickWebEngineProfile {
public:
HFWebEngineProfile(QObject* parent = Q_NULLPTR);
};
#endif // hifi_HFWebEngineProfile_h

View file

@ -0,0 +1,40 @@
//
// HFWebEngineRequestInterceptor.cpp
// interface/src/networking
//
// Created by Stephen Birarda on 2016-10-14.
// 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 "HFWebEngineRequestInterceptor.h"
#include <QtCore/QDebug>
#include <AccountManager.h>
bool isAuthableHighFidelityURL(const QUrl& url) {
static const QStringList HF_HOSTS = {
"highfidelity.com", "highfidelity.io",
"metaverse.highfidelity.com", "metaverse.highfidelity.io"
};
return url.scheme() == "https" && HF_HOSTS.contains(url.host());
}
void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
// check if this is a request to a highfidelity URL
if (isAuthableHighFidelityURL(info.requestUrl())) {
// if we have an access token, add it to the right HTTP header for authorization
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->hasValidAccessToken()) {
static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization";
QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token;
info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit());
}
}
}

View file

@ -0,0 +1,26 @@
//
// HFWebEngineRequestInterceptor.h
// interface/src/networking
//
// Created by Stephen Birarda on 2016-10-14.
// 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_HFWebEngineRequestInterceptor_h
#define hifi_HFWebEngineRequestInterceptor_h
#include <QWebEngineUrlRequestInterceptor>
class HFWebEngineRequestInterceptor : public QWebEngineUrlRequestInterceptor {
public:
HFWebEngineRequestInterceptor(QObject* parent) : QWebEngineUrlRequestInterceptor(parent) {};
virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
};
#endif // hifi_HFWebEngineRequestInterceptor_h

View file

@ -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<OffscreenUi>()->executeOnUiThread([=] {
if (!_qmlWindow.isNull()) {
_qmlWindow->setProperty(URL_PROPERTY, fixupHifiUrl(urlString));
_qmlWindow->setProperty(URL_PROPERTY, urlString);
}
});
}

View file

@ -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);