use a QWebEngineProfile request interceptor for auth in HTTP header

This commit is contained in:
Stephen Birarda 2016-10-17 11:29:09 -07:00
parent 89a4bc8434
commit b4b5c648c2
9 changed files with 80 additions and 56 deletions

View file

@ -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 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"
}

View file

@ -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<EntityScriptingInterface>();
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity,
@ -1681,6 +1677,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

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

View file

@ -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 <QtWebEngine/QQuickWebEngineProfile>
class HFWebEngineProfile : public QQuickWebEngineProfile {
public:
HFWebEngineProfile(QObject* parent = Q_NULLPTR);
};
#endif // hifi_HFWebEngineProfile_h

View file

@ -13,6 +13,26 @@
#include <QtCore/QDebug>
void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
qDebug() << "==================== We have a request we can intercept! COOL!";
#include <AccountManager.h>
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<AccountManager>();
static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization";
QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token;
info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit());
}
}

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

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