mirror of
https://github.com/lubosz/overte.git
synced 2025-04-09 13:12:57 +02:00
Don't allow Web surfaces created by non-client scripts to access files
This commit is contained in:
parent
e321ee0cb6
commit
4b317a84d8
26 changed files with 275 additions and 234 deletions
|
@ -62,6 +62,7 @@ Windows.ScrollingWindow {
|
|||
url: "about:blank"
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
profile: HFWebEngineProfile;
|
||||
|
||||
property string userScriptUrl: ""
|
||||
|
||||
|
|
|
@ -6603,11 +6603,12 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
LocationScriptingInterface::locationSetter);
|
||||
|
||||
bool clientScript = scriptEngine->isClientScript();
|
||||
scriptEngine->registerFunction("OverlayWindow", clientScript ? QmlWindowClass::constructor : QmlWindowClass::restricted_constructor);
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
|
||||
scriptEngine->registerFunction("OverlayWebWindow", clientScript ? QmlWebWindowClass::constructor : QmlWebWindowClass::restricted_constructor);
|
||||
#endif
|
||||
scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor);
|
||||
scriptEngine->registerFunction("QmlFragment", QmlFragmentClass::constructor);
|
||||
scriptEngine->registerFunction("QmlFragment", clientScript ? QmlFragmentClass::constructor : QmlFragmentClass::restricted_constructor);
|
||||
|
||||
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get<DesktopPreviewProvider>().data());
|
||||
|
|
|
@ -40,7 +40,8 @@ static QSize clampSize(const QSize& qsize, uint32_t maxDimension) {
|
|||
return fromGlm(clampSize(toGlm(qsize), maxDimension));
|
||||
}
|
||||
|
||||
const QmlContextObjectCallback OffscreenSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QQuickItem*) {};
|
||||
const QmlContextObjectCallback OffscreenSurface::DEFAULT_CONTEXT_OBJECT_CALLBACK = [](QQmlContext*, QQuickItem*) {};
|
||||
const QmlContextCallback OffscreenSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*) {};
|
||||
|
||||
void OffscreenSurface::initializeEngine(QQmlEngine* engine) {
|
||||
}
|
||||
|
@ -266,8 +267,8 @@ void OffscreenSurface::load(const QUrl& qmlSource, bool createNewContext, const
|
|||
loadInternal(qmlSource, createNewContext, nullptr, callback);
|
||||
}
|
||||
|
||||
void OffscreenSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback) {
|
||||
load(qmlSource, true, callback);
|
||||
void OffscreenSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback, const QmlContextCallback& contextCallback) {
|
||||
loadInternal(qmlSource, true, nullptr, callback, contextCallback);
|
||||
}
|
||||
|
||||
void OffscreenSurface::load(const QUrl& qmlSource, const QmlContextObjectCallback& callback) {
|
||||
|
@ -281,7 +282,8 @@ void OffscreenSurface::load(const QString& qmlSourceFile, const QmlContextObject
|
|||
void OffscreenSurface::loadInternal(const QUrl& qmlSource,
|
||||
bool createNewContext,
|
||||
QQuickItem* parent,
|
||||
const QmlContextObjectCallback& callback) {
|
||||
const QmlContextObjectCallback& callback,
|
||||
const QmlContextCallback& contextCallback) {
|
||||
PROFILE_RANGE_EX(app, "OffscreenSurface::loadInternal", 0xffff00ff, 0, { std::make_pair("url", qmlSource.toDisplayString()) });
|
||||
if (QThread::currentThread() != thread()) {
|
||||
qFatal("Called load on a non-surface thread");
|
||||
|
@ -310,6 +312,7 @@ void OffscreenSurface::loadInternal(const QUrl& qmlSource,
|
|||
}
|
||||
|
||||
auto targetContext = contextForUrl(finalQmlSource, parent, createNewContext);
|
||||
contextCallback(targetContext);
|
||||
QQmlComponent* qmlComponent;
|
||||
{
|
||||
PROFILE_RANGE(app, "new QQmlComponent");
|
||||
|
|
|
@ -37,13 +37,15 @@ namespace impl {
|
|||
class SharedObject;
|
||||
}
|
||||
|
||||
using QmlContextCallback = ::std::function<void(QQmlContext*)>;
|
||||
using QmlContextObjectCallback = ::std::function<void(QQmlContext*, QQuickItem*)>;
|
||||
|
||||
class OffscreenSurface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static const QmlContextObjectCallback DEFAULT_CONTEXT_CALLBACK;
|
||||
static const QmlContextObjectCallback DEFAULT_CONTEXT_OBJECT_CALLBACK;
|
||||
static const QmlContextCallback DEFAULT_CONTEXT_CALLBACK;
|
||||
|
||||
using TextureAndFence = std::pair<uint32_t, void*>;
|
||||
using MouseTranslator = std::function<QPoint(const QPointF&)>;
|
||||
|
@ -85,10 +87,15 @@ public:
|
|||
Q_INVOKABLE void load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback);
|
||||
|
||||
// For use from C++
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QString& qmlSourceFile, const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_OBJECT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource,
|
||||
bool createNewContext,
|
||||
const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_OBJECT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QString& qmlSourceFile,
|
||||
const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_OBJECT_CALLBACK);
|
||||
Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource,
|
||||
const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_OBJECT_CALLBACK,
|
||||
const QmlContextCallback& contextCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
|
||||
public slots:
|
||||
virtual void onFocusObjectChanged(QObject* newFocus) {}
|
||||
|
@ -103,19 +110,21 @@ protected:
|
|||
|
||||
virtual void initializeEngine(QQmlEngine* engine);
|
||||
virtual void loadInternal(const QUrl& qmlSource,
|
||||
bool createNewContext,
|
||||
QQuickItem* parent,
|
||||
const QmlContextObjectCallback& callback) final;
|
||||
bool createNewContext,
|
||||
QQuickItem* parent,
|
||||
const QmlContextObjectCallback& callback,
|
||||
const QmlContextCallback& contextCallback = DEFAULT_CONTEXT_CALLBACK) final;
|
||||
virtual void finishQmlLoad(QQmlComponent* qmlComponent,
|
||||
QQmlContext* qmlContext,
|
||||
QQuickItem* parent,
|
||||
const QmlContextObjectCallback& onQmlLoadedCallback) final;
|
||||
QQmlContext* qmlContext,
|
||||
QQuickItem* parent,
|
||||
const QmlContextObjectCallback& onQmlLoadedCallback) final;
|
||||
|
||||
virtual void onRootCreated() {}
|
||||
virtual void onItemCreated(QQmlContext* context, QQuickItem* newItem) {}
|
||||
virtual void onRootContextCreated(QQmlContext* qmlContext) {}
|
||||
|
||||
virtual QQmlContext* contextForUrl(const QUrl& qmlSource, QQuickItem* parent, bool forceNewContext);
|
||||
|
||||
private:
|
||||
MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p.toPoint(); } };
|
||||
friend class hifi::qml::impl::SharedObject;
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
std::mutex QmlFragmentClass::_mutex;
|
||||
std::map<QString, QScriptValue> QmlFragmentClass::_fragments;
|
||||
|
||||
QmlFragmentClass::QmlFragmentClass(QString id) : qml(id) { }
|
||||
QmlFragmentClass::QmlFragmentClass(bool restricted, QString id) : QmlWindowClass(restricted), qml(id) { }
|
||||
|
||||
// Method called by Qt scripts to create a new bottom menu bar in Android
|
||||
QScriptValue QmlFragmentClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
QScriptValue QmlFragmentClass::internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted) {
|
||||
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
auto qml = context->argument(0).toVariant().toMap().value("qml");
|
||||
|
@ -41,7 +41,7 @@ QScriptValue QmlFragmentClass::constructor(QScriptContext* context, QScriptEngin
|
|||
|
||||
auto properties = parseArguments(context);
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QmlFragmentClass* retVal = new QmlFragmentClass(qml.toString());
|
||||
QmlFragmentClass* retVal = new QmlFragmentClass(restricted, qml.toString());
|
||||
Q_ASSERT(retVal);
|
||||
if (QThread::currentThread() != qApp->thread()) {
|
||||
retVal->moveToThread(qApp->thread());
|
||||
|
|
|
@ -13,9 +13,19 @@
|
|||
|
||||
class QmlFragmentClass : public QmlWindowClass {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
static QScriptValue internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted);
|
||||
public:
|
||||
QmlFragmentClass(QString id);
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
return internal_constructor(context, engine, false);
|
||||
}
|
||||
|
||||
static QScriptValue restricted_constructor(QScriptContext* context, QScriptEngine* engine ){
|
||||
return internal_constructor(context, engine, true);
|
||||
}
|
||||
|
||||
QmlFragmentClass(bool restricted, QString id);
|
||||
|
||||
/**jsdoc
|
||||
* Creates a new button, adds it to this and returns it.
|
||||
|
|
|
@ -20,10 +20,10 @@ static const char* const URL_PROPERTY = "source";
|
|||
static const char* const SCRIPT_PROPERTY = "scriptUrl";
|
||||
|
||||
// Method called by Qt scripts to create a new web window in the overlay
|
||||
QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
QScriptValue QmlWebWindowClass::internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted) {
|
||||
auto properties = parseArguments(context);
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QmlWebWindowClass* retVal = new QmlWebWindowClass();
|
||||
QmlWebWindowClass* retVal = new QmlWebWindowClass(restricted);
|
||||
Q_ASSERT(retVal);
|
||||
if (QThread::currentThread() != qApp->thread()) {
|
||||
retVal->moveToThread(qApp->thread());
|
||||
|
|
|
@ -57,8 +57,18 @@ class QmlWebWindowClass : public QmlWindowClass {
|
|||
Q_OBJECT
|
||||
Q_PROPERTY(QString url READ getURL CONSTANT)
|
||||
|
||||
private:
|
||||
static QScriptValue internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted);
|
||||
public:
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||
QmlWebWindowClass(bool restricted) : QmlWindowClass(restricted) {}
|
||||
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
return internal_constructor(context, engine, false);
|
||||
}
|
||||
|
||||
static QScriptValue restricted_constructor(QScriptContext* context, QScriptEngine* engine ){
|
||||
return internal_constructor(context, engine, true);
|
||||
}
|
||||
|
||||
public slots:
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include <shared/QtHelpers.h>
|
||||
#include "OffscreenUi.h"
|
||||
#include "ui/types/HFWebEngineProfile.h"
|
||||
#include "ui/types/FileTypeProfile.h"
|
||||
|
||||
static const char* const SOURCE_PROPERTY = "source";
|
||||
static const char* const TITLE_PROPERTY = "title";
|
||||
|
@ -68,10 +70,10 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) {
|
|||
|
||||
|
||||
// Method called by Qt scripts to create a new web window in the overlay
|
||||
QScriptValue QmlWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
QScriptValue QmlWindowClass::internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted) {
|
||||
auto properties = parseArguments(context);
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QmlWindowClass* retVal = new QmlWindowClass();
|
||||
QmlWindowClass* retVal = new QmlWindowClass(restricted);
|
||||
Q_ASSERT(retVal);
|
||||
if (QThread::currentThread() != qApp->thread()) {
|
||||
retVal->moveToThread(qApp->thread());
|
||||
|
@ -83,7 +85,7 @@ QScriptValue QmlWindowClass::constructor(QScriptContext* context, QScriptEngine*
|
|||
return engine->newQObject(retVal);
|
||||
}
|
||||
|
||||
QmlWindowClass::QmlWindowClass() {
|
||||
QmlWindowClass::QmlWindowClass(bool restricted) : _restricted(restricted) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -99,8 +101,7 @@ void QmlWindowClass::initQml(QVariantMap properties) {
|
|||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
_source = properties[SOURCE_PROPERTY].toString();
|
||||
|
||||
// Build the event bridge and wrapper on the main thread
|
||||
offscreenUi->loadInNewContext(qmlSource(), [&](QQmlContext* context, QObject* object) {
|
||||
auto objectInitLambda = [&](QQmlContext* context, QObject* object) {
|
||||
_qmlWindow = object;
|
||||
context->setContextProperty(EVENT_BRIDGE_PROPERTY, this);
|
||||
context->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
|
@ -128,7 +129,24 @@ void QmlWindowClass::initQml(QVariantMap properties) {
|
|||
if (metaObject->indexOfSignal("moved") >= 0)
|
||||
connect(_qmlWindow, SIGNAL(moved(QVector2D)), this, SLOT(hasMoved(QVector2D)), Qt::QueuedConnection);
|
||||
connect(_qmlWindow, SIGNAL(windowClosed()), this, SLOT(hasClosed()), Qt::QueuedConnection);
|
||||
});
|
||||
};
|
||||
|
||||
auto contextInitLambda = [&](QQmlContext* context) {
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
// If the restricted flag is on, override the FileTypeProfile and HFWebEngineProfile objects in the
|
||||
// QML surface root context with local ones
|
||||
qDebug() << "Context initialization lambda";
|
||||
if (_restricted) {
|
||||
qDebug() << "Restricting web content";
|
||||
ContextAwareProfile::restrictContext(context);
|
||||
FileTypeProfile::registerWithContext(context);
|
||||
HFWebEngineProfile::registerWithContext(context);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// Build the event bridge and wrapper on the main thread
|
||||
offscreenUi->loadInNewContext(qmlSource(), objectInitLambda, contextInitLambda);
|
||||
|
||||
Q_ASSERT(_qmlWindow);
|
||||
Q_ASSERT(dynamic_cast<const QQuickItem*>(_qmlWindow.data()));
|
||||
|
|
|
@ -38,9 +38,18 @@ class QmlWindowClass : public QObject {
|
|||
Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize NOTIFY sizeChanged)
|
||||
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
|
||||
|
||||
private:
|
||||
static QScriptValue internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted);
|
||||
public:
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||
QmlWindowClass();
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
return internal_constructor(context, engine, false);
|
||||
}
|
||||
|
||||
static QScriptValue restricted_constructor(QScriptContext* context, QScriptEngine* engine ){
|
||||
return internal_constructor(context, engine, true);
|
||||
}
|
||||
|
||||
QmlWindowClass(bool restricted);
|
||||
~QmlWindowClass();
|
||||
|
||||
/**jsdoc
|
||||
|
@ -51,6 +60,8 @@ public:
|
|||
|
||||
QQuickItem* asQuickItem() const;
|
||||
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
/**jsdoc
|
||||
|
@ -250,10 +261,12 @@ protected:
|
|||
|
||||
QPointer<QObject> _qmlWindow;
|
||||
QString _source;
|
||||
const bool _restricted;
|
||||
|
||||
private:
|
||||
// QmlWindow content may include WebView requiring EventBridge.
|
||||
void setKeyboardRaised(QObject* object, bool raised, bool numeric = false);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -265,19 +265,6 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) {
|
|||
if (!javaScriptToInject.isEmpty()) {
|
||||
rootContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject));
|
||||
}
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
|
||||
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
|
||||
{
|
||||
PROFILE_RANGE(startup, "FileTypeProfile");
|
||||
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
|
||||
}
|
||||
{
|
||||
PROFILE_RANGE(startup, "HFWebEngineProfile");
|
||||
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
|
||||
|
||||
}
|
||||
#endif
|
||||
rootContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data());
|
||||
rootContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
||||
rootContext->setContextProperty("Toolbars", DependencyManager::get<ToolbarScriptingInterface>().data());
|
||||
|
@ -300,6 +287,17 @@ void OffscreenQmlSurface::onRootContextCreated(QQmlContext* qmlContext) {
|
|||
// FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper
|
||||
// Find a way to flag older scripts using this mechanism and wanr that this is deprecated
|
||||
qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(this, qmlContext));
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
{
|
||||
PROFILE_RANGE(startup, "FileTypeProfile");
|
||||
FileTypeProfile::registerWithContext(qmlContext);
|
||||
}
|
||||
{
|
||||
PROFILE_RANGE(startup, "HFWebEngineProfile");
|
||||
HFWebEngineProfile::registerWithContext(qmlContext);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QQmlContext* OffscreenQmlSurface::contextForUrl(const QUrl& qmlSource, QQuickItem* parent, bool forceNewContext) {
|
||||
|
|
|
@ -334,6 +334,8 @@ static const char* VRMENU_SOURCE_URL = "hifi/tablet/TabletMenu.qml";
|
|||
|
||||
class TabletRootWindow : public QmlWindowClass {
|
||||
virtual QString qmlSource() const override { return "hifi/tablet/WindowRoot.qml"; }
|
||||
public:
|
||||
TabletRootWindow() : QmlWindowClass(false) {}
|
||||
};
|
||||
|
||||
TabletProxy::TabletProxy(QObject* parent, const QString& name) : QObject(parent), _name(name) {
|
||||
|
|
32
libraries/ui/src/ui/types/ContextAwareProfile.cpp
Normal file
32
libraries/ui/src/ui/types/ContextAwareProfile.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// FileTypeProfile.cpp
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Kunal Gosar on 2017-03-10.
|
||||
// Copyright 2017 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 "ContextAwareProfile.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
|
||||
#include <QtQml/QQmlContext>
|
||||
|
||||
static const QString RESTRICTED_FLAG_PROPERTY = "RestrictFileAccess";
|
||||
|
||||
ContextAwareProfile::ContextAwareProfile(QQmlContext* parent) :
|
||||
QQuickWebEngineProfile(parent), _context(parent) { }
|
||||
|
||||
|
||||
void ContextAwareProfile::restrictContext(QQmlContext* context) {
|
||||
context->setContextProperty(RESTRICTED_FLAG_PROPERTY, true);
|
||||
}
|
||||
|
||||
bool ContextAwareProfile::isRestricted(QQmlContext* context) {
|
||||
return context->contextProperty(RESTRICTED_FLAG_PROPERTY).toBool();
|
||||
}
|
||||
|
||||
#endif
|
42
libraries/ui/src/ui/types/ContextAwareProfile.h
Normal file
42
libraries/ui/src/ui/types/ContextAwareProfile.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2018/07/27
|
||||
// Copyright 2013-2018 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_ContextAwareProfile_h
|
||||
#define hifi_ContextAwareProfile_h
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QtWebEngine/QQuickWebEngineProfile>
|
||||
#include <QtWebEngineCore/QWebEngineUrlRequestInterceptor>
|
||||
|
||||
class QQmlContext;
|
||||
|
||||
class ContextAwareProfile : public QQuickWebEngineProfile {
|
||||
public:
|
||||
static void restrictContext(QQmlContext* context);
|
||||
static bool isRestricted(QQmlContext* context);
|
||||
QQmlContext* getContext() const { return _context; }
|
||||
protected:
|
||||
|
||||
class RequestInterceptor : public QWebEngineUrlRequestInterceptor {
|
||||
public:
|
||||
RequestInterceptor(ContextAwareProfile* parent) : QWebEngineUrlRequestInterceptor(parent), _profile(parent) {}
|
||||
QQmlContext* getContext() const { return _profile->getContext(); }
|
||||
protected:
|
||||
ContextAwareProfile* _profile;
|
||||
};
|
||||
|
||||
ContextAwareProfile(QQmlContext* parent);
|
||||
QQmlContext* _context;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // hifi_FileTypeProfile_h
|
|
@ -11,18 +11,31 @@
|
|||
|
||||
#include "FileTypeProfile.h"
|
||||
|
||||
#include "FileTypeRequestInterceptor.h"
|
||||
#include <QtQml/QQmlContext>
|
||||
|
||||
#include "RequestFilters.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine";
|
||||
|
||||
FileTypeProfile::FileTypeProfile(QObject* parent) :
|
||||
QQuickWebEngineProfile(parent)
|
||||
FileTypeProfile::FileTypeProfile(QQmlContext* parent) :
|
||||
ContextAwareProfile(parent)
|
||||
{
|
||||
static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)";
|
||||
setHttpUserAgent(WEB_ENGINE_USER_AGENT);
|
||||
|
||||
auto requestInterceptor = new FileTypeRequestInterceptor(this);
|
||||
auto requestInterceptor = new RequestInterceptor(this);
|
||||
setRequestInterceptor(requestInterceptor);
|
||||
}
|
||||
|
||||
void FileTypeProfile::RequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||
RequestFilters::interceptHFWebEngineRequest(info, getContext());
|
||||
RequestFilters::interceptFileType(info, getContext());
|
||||
}
|
||||
|
||||
void FileTypeProfile::registerWithContext(QQmlContext* context) {
|
||||
context->setContextProperty("FileTypeProfile", new FileTypeProfile(context));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -17,12 +17,23 @@
|
|||
#include <QtCore/QtGlobal>
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QtWebEngine/QQuickWebEngineProfile>
|
||||
#include "ContextAwareProfile.h"
|
||||
|
||||
class FileTypeProfile : public ContextAwareProfile {
|
||||
using Parent = ContextAwareProfile;
|
||||
|
||||
class FileTypeProfile : public QQuickWebEngineProfile {
|
||||
public:
|
||||
FileTypeProfile(QObject* parent = Q_NULLPTR);
|
||||
static void registerWithContext(QQmlContext* parent);
|
||||
|
||||
protected:
|
||||
FileTypeProfile(QQmlContext* parent);
|
||||
class RequestInterceptor : public Parent::RequestInterceptor {
|
||||
public:
|
||||
RequestInterceptor(ContextAwareProfile* parent) : Parent::RequestInterceptor(parent) {}
|
||||
void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // hifi_FileTypeProfile_h
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// FileTypeRequestInterceptor.cpp
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Kunal Gosar on 2017-03-10.
|
||||
// Copyright 2017 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 "FileTypeRequestInterceptor.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "RequestFilters.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
|
||||
void FileTypeRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||
RequestFilters::interceptHFWebEngineRequest(info);
|
||||
RequestFilters::interceptFileType(info);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,30 +0,0 @@
|
|||
//
|
||||
// FileTypeRequestInterceptor.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Kunal Gosar on 2017-03-10.
|
||||
// Copyright 2017 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_FileTypeRequestInterceptor_h
|
||||
#define hifi_FileTypeRequestInterceptor_h
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QWebEngineUrlRequestInterceptor>
|
||||
|
||||
class FileTypeRequestInterceptor : public QWebEngineUrlRequestInterceptor {
|
||||
public:
|
||||
FileTypeRequestInterceptor(QObject* parent) : QWebEngineUrlRequestInterceptor(parent) {};
|
||||
|
||||
virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // hifi_FileTypeRequestInterceptor_h
|
|
@ -1,23 +0,0 @@
|
|||
//
|
||||
// HFTabletWebEngineProfile.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Dante Ruiz on 2017-03-31.
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
|
||||
#ifndef hifi_HFTabletWebEngineProfile_h
|
||||
#define hifi_HFTabletWebEngineProfile_h
|
||||
|
||||
#include <QtWebEngine/QQuickWebEngineProfile>
|
||||
|
||||
class HFTabletWebEngineProfile : public QQuickWebEngineProfile {
|
||||
public:
|
||||
HFTabletWebEngineProfile(QObject* parent = Q_NULLPTR);
|
||||
};
|
||||
|
||||
#endif // hifi_HFTabletWebEngineProfile_h
|
|
@ -1,30 +0,0 @@
|
|||
//
|
||||
// HFTabletWebEngineRequestInterceptor.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Dante Ruiz on 2017-3-31.
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
#ifndef hifi_HFTabletWebEngineRequestInterceptor_h
|
||||
#define hifi_HFTabletWebEngineRequestInterceptor_h
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <QWebEngineUrlRequestInterceptor>
|
||||
|
||||
class HFTabletWebEngineRequestInterceptor
|
||||
: public QWebEngineUrlRequestInterceptor
|
||||
{
|
||||
public:
|
||||
HFTabletWebEngineRequestInterceptor(QObject* parent)
|
||||
: QWebEngineUrlRequestInterceptor(parent)
|
||||
{};
|
||||
virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // hifi_HFWebEngineRequestInterceptor_h
|
|
@ -11,20 +11,28 @@
|
|||
|
||||
#include "HFWebEngineProfile.h"
|
||||
|
||||
#include "HFWebEngineRequestInterceptor.h"
|
||||
#include <QtQml/QQmlContext>
|
||||
|
||||
#include "RequestFilters.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
|
||||
static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine";
|
||||
|
||||
HFWebEngineProfile::HFWebEngineProfile(QObject* parent) :
|
||||
QQuickWebEngineProfile(parent)
|
||||
HFWebEngineProfile::HFWebEngineProfile(QQmlContext* parent) : Parent(parent)
|
||||
{
|
||||
setStorageName(QML_WEB_ENGINE_STORAGE_NAME);
|
||||
|
||||
// we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user
|
||||
auto requestInterceptor = new HFWebEngineRequestInterceptor(this);
|
||||
setRequestInterceptor(requestInterceptor);
|
||||
setRequestInterceptor(new RequestInterceptor(this));
|
||||
}
|
||||
|
||||
#endif
|
||||
void HFWebEngineProfile::RequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||
RequestFilters::interceptHFWebEngineRequest(info, getContext());
|
||||
}
|
||||
|
||||
void HFWebEngineProfile::registerWithContext(QQmlContext* context) {
|
||||
context->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(context));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,15 +14,24 @@
|
|||
#ifndef hifi_HFWebEngineProfile_h
|
||||
#define hifi_HFWebEngineProfile_h
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include "ContextAwareProfile.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QtWebEngine/QQuickWebEngineProfile>
|
||||
|
||||
class HFWebEngineProfile : public QQuickWebEngineProfile {
|
||||
class HFWebEngineProfile : public ContextAwareProfile {
|
||||
using Parent = ContextAwareProfile;
|
||||
public:
|
||||
HFWebEngineProfile(QObject* parent = Q_NULLPTR);
|
||||
static void registerWithContext(QQmlContext* parent);
|
||||
|
||||
protected:
|
||||
HFWebEngineProfile(QQmlContext* parent);
|
||||
class RequestInterceptor : public Parent::RequestInterceptor {
|
||||
public:
|
||||
RequestInterceptor(ContextAwareProfile* parent) : Parent::RequestInterceptor(parent) {}
|
||||
void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // hifi_HFWebEngineProfile_h
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// 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"
|
||||
#include "RequestFilters.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
|
||||
void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||
RequestFilters::interceptHFWebEngineRequest(info);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,30 +0,0 @@
|
|||
//
|
||||
// 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 <QtCore/QtGlobal>
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QWebEngineUrlRequestInterceptor>
|
||||
|
||||
class HFWebEngineRequestInterceptor : public QWebEngineUrlRequestInterceptor {
|
||||
public:
|
||||
HFWebEngineRequestInterceptor(QObject* parent) : QWebEngineUrlRequestInterceptor(parent) {};
|
||||
|
||||
virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // hifi_HFWebEngineRequestInterceptor_h
|
|
@ -10,12 +10,15 @@
|
|||
//
|
||||
|
||||
#include "RequestFilters.h"
|
||||
#include "NetworkingConstants.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <SettingHandle.h>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
#include "AccountManager.h"
|
||||
#include <SettingHandle.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <AccountManager.h>
|
||||
|
||||
#include "ContextAwareProfile.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
|
||||
|
@ -42,9 +45,28 @@ namespace {
|
|||
return filename.endsWith(".json", Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
bool blockLocalFiles(QWebEngineUrlRequestInfo& info) {
|
||||
auto requestUrl = info.requestUrl();
|
||||
if (!requestUrl.isLocalFile()) {
|
||||
// Not a local file, do not block
|
||||
return false;
|
||||
}
|
||||
|
||||
QString targetFilePath = QFileInfo(requestUrl.toLocalFile()).canonicalFilePath();
|
||||
|
||||
// If we get here, then it's a local file that isn't whitelisted and the
|
||||
// developer mode environment variable is not enabled. Block access to the file
|
||||
qWarning() << "Blocking web access to local file path" << targetFilePath;
|
||||
info.block(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info) {
|
||||
void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info, QQmlContext* context) {
|
||||
if (ContextAwareProfile::isRestricted(context) && blockLocalFiles(info)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check if this is a request to a highfidelity URL
|
||||
bool isAuthable = isAuthableHighFidelityURL(info.requestUrl());
|
||||
if (isAuthable) {
|
||||
|
@ -71,7 +93,7 @@ void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info)
|
|||
info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit());
|
||||
}
|
||||
|
||||
void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info) {
|
||||
void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info, QQmlContext* context) {
|
||||
QString filename = info.requestUrl().fileName();
|
||||
if (isScript(filename) || isJSON(filename)) {
|
||||
static const QString CONTENT_HEADER = "Accept";
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
#include <QObject>
|
||||
#include <QWebEngineUrlRequestInfo>
|
||||
|
||||
class QQmlContext;
|
||||
|
||||
class RequestFilters : public QObject {
|
||||
public:
|
||||
static void interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info);
|
||||
static void interceptFileType(QWebEngineUrlRequestInfo& info);
|
||||
static void interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info, QQmlContext* context);
|
||||
static void interceptFileType(QWebEngineUrlRequestInfo& info, QQmlContext* context);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue