BUGZ-1365: Ensure that by default web views can't access local content

This commit is contained in:
Brad Davis 2019-08-29 13:44:49 -07:00
parent 36be00bf97
commit 428a58710d
9 changed files with 41 additions and 19 deletions

View file

@ -139,6 +139,7 @@
#include <SoundCacheScriptingInterface.h> #include <SoundCacheScriptingInterface.h>
#include <ui/TabletScriptingInterface.h> #include <ui/TabletScriptingInterface.h>
#include <ui/ToolbarScriptingInterface.h> #include <ui/ToolbarScriptingInterface.h>
#include <ui/types/ContextAwareProfile.h>
#include <Tooltip.h> #include <Tooltip.h>
#include <udt/PacketHeaders.h> #include <udt/PacketHeaders.h>
#include <UserActivityLogger.h> #include <UserActivityLogger.h>
@ -3285,6 +3286,9 @@ void Application::initializeUi() {
} }
return result.toPoint(); return result.toPoint();
}); });
// BUGZ-1365 - the root context should explicitly default to being unable to load local HTML content
ContextAwareProfile::restrictContext(offscreenUi->getSurfaceContext(), true);
offscreenUi->resume(); offscreenUi->resume();
#endif #endif
connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r){ connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r){
@ -7457,7 +7461,7 @@ void Application::addingEntityWithCertificate(const QString& certificateID, cons
ledger->updateLocation(certificateID, placeName); ledger->updateLocation(certificateID, placeName);
} }
void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) { void Application::registerScriptEngineWithApplicationServices(const ScriptEnginePointer& scriptEngine) {
scriptEngine->setEmitScriptUpdatesFunction([this]() { scriptEngine->setEmitScriptUpdatesFunction([this]() {
SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer); SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer);
@ -7496,9 +7500,15 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue, qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue,
RayToOverlayIntersectionResultFromScriptValue); RayToOverlayIntersectionResultFromScriptValue);
bool clientScript = scriptEngine->isClientScript();
#if !defined(DISABLE_QML) #if !defined(DISABLE_QML)
scriptEngine->registerGlobalObject("OffscreenFlags", getOffscreenUI()->getFlags()); scriptEngine->registerGlobalObject("OffscreenFlags", getOffscreenUI()->getFlags());
scriptEngine->registerGlobalObject("Desktop", DependencyManager::get<DesktopScriptingInterface>().data()); if (clientScript) {
scriptEngine->registerGlobalObject("Desktop", DependencyManager::get<DesktopScriptingInterface>().data());
} else {
scriptEngine->registerGlobalObject("Desktop", new DesktopScriptingInterface(scriptEngine.get(), true));
}
#endif #endif
qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<ToolbarProxy>, wrapperFromScriptValue<ToolbarProxy>); qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<ToolbarProxy>, wrapperFromScriptValue<ToolbarProxy>);
@ -7523,7 +7533,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
LocationScriptingInterface::locationSetter); LocationScriptingInterface::locationSetter);
bool clientScript = scriptEngine->isClientScript();
scriptEngine->registerFunction("OverlayWindow", clientScript ? QmlWindowClass::constructor : QmlWindowClass::restricted_constructor); scriptEngine->registerFunction("OverlayWindow", clientScript ? QmlWindowClass::constructor : QmlWindowClass::restricted_constructor);
#if !defined(Q_OS_ANDROID) && !defined(DISABLE_QML) #if !defined(Q_OS_ANDROID) && !defined(DISABLE_QML)
scriptEngine->registerFunction("OverlayWebWindow", clientScript ? QmlWebWindowClass::constructor : QmlWebWindowClass::restricted_constructor); scriptEngine->registerFunction("OverlayWebWindow", clientScript ? QmlWebWindowClass::constructor : QmlWebWindowClass::restricted_constructor);

View file

@ -252,7 +252,7 @@ public:
NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; } NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; } virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; }
virtual void registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) override; virtual void registerScriptEngineWithApplicationServices(const ScriptEnginePointer& scriptEngine) override;
virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const override { copyDisplayViewFrustum(viewOut); } virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const override { copyDisplayViewFrustum(viewOut); }
virtual QThread* getMainThread() override { return thread(); } virtual QThread* getMainThread() override { return thread(); }

View file

@ -52,6 +52,9 @@ static const QVariantMap DOCK_AREA {
{ "RIGHT", DockArea::RIGHT } { "RIGHT", DockArea::RIGHT }
}; };
DesktopScriptingInterface::DesktopScriptingInterface(QObject* parent, bool restricted)
: QObject(parent), _restricted(restricted) { }
int DesktopScriptingInterface::getWidth() { int DesktopScriptingInterface::getWidth() {
QSize size = qApp->getWindow()->windowHandle()->screen()->virtualSize(); QSize size = qApp->getWindow()->windowHandle()->screen()->virtualSize();
return size.width(); return size.width();
@ -128,7 +131,7 @@ InteractiveWindowPointer DesktopScriptingInterface::createWindow(const QString&
return nullptr; return nullptr;
} }
return new InteractiveWindow(sourceUrl, properties); return new InteractiveWindow(sourceUrl, properties, _restricted);
} }
InteractiveWindowPointer DesktopScriptingInterface::createWindowOnThread(const QString& sourceUrl, const QVariantMap& properties, QThread* targetThread) { InteractiveWindowPointer DesktopScriptingInterface::createWindowOnThread(const QString& sourceUrl, const QVariantMap& properties, QThread* targetThread) {
@ -139,7 +142,7 @@ InteractiveWindowPointer DesktopScriptingInterface::createWindowOnThread(const Q
if (!urlValidator(sourceUrl)) { if (!urlValidator(sourceUrl)) {
return nullptr; return nullptr;
} }
InteractiveWindowPointer window = new InteractiveWindow(sourceUrl, properties); InteractiveWindowPointer window = new InteractiveWindow(sourceUrl, properties, _restricted);
window->moveToThread(targetThread); window->moveToThread(targetThread);
return window; return window;
} }

View file

@ -54,6 +54,8 @@ class DesktopScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(int CLOSE_BUTTON_HIDES READ flagCloseButtonHides CONSTANT FINAL) Q_PROPERTY(int CLOSE_BUTTON_HIDES READ flagCloseButtonHides CONSTANT FINAL)
public: public:
DesktopScriptingInterface(QObject* parent= nullptr, bool restricted = false);
/**jsdoc /**jsdoc
* Sets the opacity of the HUD surface. * Sets the opacity of the HUD surface.
* @function Desktop.setHUDAlpha * @function Desktop.setHUDAlpha
@ -106,6 +108,7 @@ private:
static QVariantMap getDockArea(); static QVariantMap getDockArea();
Q_INVOKABLE static QVariantMap getPresentationMode(); Q_INVOKABLE static QVariantMap getPresentationMode();
const bool _restricted;
}; };

View file

@ -19,6 +19,8 @@
#include <QQuickView> #include <QQuickView>
#include <ui/types/ContextAwareProfile.h> #include <ui/types/ContextAwareProfile.h>
#include <ui/types/HFWebEngineProfile.h>
#include <ui/types/FileTypeProfile.h>
#include <DependencyManager.h> #include <DependencyManager.h>
#include <DockWidget.h> #include <DockWidget.h>
#include <RegisteredMetaTypes.h> #include <RegisteredMetaTypes.h>
@ -135,7 +137,7 @@ void InteractiveWindow::emitMainWindowResizeEvent() {
* Set at window creation. Possible flag values are provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}. * Set at window creation. Possible flag values are provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}.
* Additional flag values can be found on Qt's website at https://doc.qt.io/qt-5/qt.html#WindowType-enum. * Additional flag values can be found on Qt's website at https://doc.qt.io/qt-5/qt.html#WindowType-enum.
*/ */
InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties) { InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties, bool restricted) {
InteractiveWindowPresentationMode presentationMode = InteractiveWindowPresentationMode::Native; InteractiveWindowPresentationMode presentationMode = InteractiveWindowPresentationMode::Native;
if (properties.contains(PRESENTATION_MODE_PROPERTY)) { if (properties.contains(PRESENTATION_MODE_PROPERTY)) {
@ -230,11 +232,10 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
mainWindow->addDockWidget(dockArea, _dockWidget.get()); mainWindow->addDockWidget(dockArea, _dockWidget.get());
} else { } else {
auto contextInitLambda = [&](QQmlContext* context) { auto contextInitLambda = [&](QQmlContext* context) {
#if !defined(Q_OS_ANDROID) // If the restricted flag is on, the web content will not be able to access local files
// If the restricted flag is on, override the FileTypeProfile and HFWebEngineProfile objects in the ContextAwareProfile::restrictContext(context, restricted);
// QML surface root context with local ones FileTypeProfile::registerWithContext(context);
ContextAwareProfile::restrictContext(context, false); HFWebEngineProfile::registerWithContext(context);
#endif
}; };
auto objectInitLambda = [&](QQmlContext* context, QObject* object) { auto objectInitLambda = [&](QQmlContext* context, QObject* object) {

View file

@ -126,7 +126,7 @@ class InteractiveWindow : public QObject {
Q_PROPERTY(int presentationMode READ getPresentationMode WRITE setPresentationMode) Q_PROPERTY(int presentationMode READ getPresentationMode WRITE setPresentationMode)
public: public:
InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties); InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties, bool restricted);
~InteractiveWindow(); ~InteractiveWindow();
private: private:

View file

@ -18,7 +18,7 @@
class AbstractScriptingServicesInterface { class AbstractScriptingServicesInterface {
public: public:
/// Registers application specific services with a script engine. /// Registers application specific services with a script engine.
virtual void registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) = 0; virtual void registerScriptEngineWithApplicationServices(const ScriptEnginePointer& scriptEngine) = 0;
}; };

View file

@ -137,10 +137,8 @@ void QmlWindowClass::initQml(QVariantMap properties) {
// If the restricted flag is on, override the FileTypeProfile and HFWebEngineProfile objects in the // If the restricted flag is on, override the FileTypeProfile and HFWebEngineProfile objects in the
// QML surface root context with local ones // QML surface root context with local ones
ContextAwareProfile::restrictContext(context, _restricted); ContextAwareProfile::restrictContext(context, _restricted);
if (_restricted) { FileTypeProfile::registerWithContext(context);
FileTypeProfile::registerWithContext(context); HFWebEngineProfile::registerWithContext(context);
HFWebEngineProfile::registerWithContext(context);
}
#endif #endif
}; };

View file

@ -36,7 +36,15 @@ bool ContextAwareProfile::isRestrictedInternal() {
BLOCKING_INVOKE_METHOD(this, "isRestrictedInternal", Q_RETURN_ARG(bool, restrictedResult)); BLOCKING_INVOKE_METHOD(this, "isRestrictedInternal", Q_RETURN_ARG(bool, restrictedResult));
return restrictedResult; return restrictedResult;
} }
return _context->contextProperty(RESTRICTED_FLAG_PROPERTY).toBool();
QVariant variant = _context->contextProperty(RESTRICTED_FLAG_PROPERTY);
if (variant.isValid()) {
return variant.toBool();
}
// BUGZ-1365 - we MUST defalut to restricted mode in the absence of a flag, or it's too easy for someone to make
// a new mechanism for loading web content that fails to restrict access to local files
return true;
} }
bool ContextAwareProfile::isRestricted() { bool ContextAwareProfile::isRestricted() {