This commit is contained in:
amer cerkic 2019-09-03 10:57:45 -07:00
commit fe3879db4d
108 changed files with 504 additions and 150 deletions

View file

@ -0,0 +1,11 @@
import QtQuick 2.0
import "../../controls" as Controls
Controls.WebView {
id: root
function fromScript(message) {
root.url = message.url;
}
}

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,19 @@ 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 {
auto desktopScriptingInterface = new DesktopScriptingInterface(nullptr, true);
scriptEngine->registerGlobalObject("Desktop", desktopScriptingInterface);
if (QThread::currentThread() != thread()) {
desktopScriptingInterface->moveToThread(thread());
}
}
#endif #endif
qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<ToolbarProxy>, wrapperFromScriptValue<ToolbarProxy>); qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<ToolbarProxy>, wrapperFromScriptValue<ToolbarProxy>);
@ -7523,7 +7537,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

@ -18,6 +18,9 @@
#include <QtQuick/QQuickWindow> #include <QtQuick/QQuickWindow>
#include <QQuickView> #include <QQuickView>
#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>
@ -134,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)) {
@ -228,9 +231,16 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
_dockWidget->setObjectName("DockedWidget"); _dockWidget->setObjectName("DockedWidget");
mainWindow->addDockWidget(dockArea, _dockWidget.get()); mainWindow->addDockWidget(dockArea, _dockWidget.get());
} else { } else {
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto contextInitLambda = [&](QQmlContext* context) {
// Build the event bridge and wrapper on the main thread // If the restricted flag is on, the web content will not be able to access local files
offscreenUi->loadInNewContext(CONTENT_WINDOW_QML, [&](QQmlContext* context, QObject* object) { ContextAwareProfile::restrictContext(context, restricted);
#if !defined(Q_OS_ANDROID)
FileTypeProfile::registerWithContext(context);
HFWebEngineProfile::registerWithContext(context);
#endif
};
auto objectInitLambda = [&](QQmlContext* context, QObject* object) {
_qmlWindowProxy = std::shared_ptr<QmlWindowProxy>(new QmlWindowProxy(object, nullptr), qmlWindowProxyDeleter); _qmlWindowProxy = std::shared_ptr<QmlWindowProxy>(new QmlWindowProxy(object, nullptr), qmlWindowProxyDeleter);
context->setContextProperty(EVENT_BRIDGE_PROPERTY, _interactiveWindowProxy.get()); context->setContextProperty(EVENT_BRIDGE_PROPERTY, _interactiveWindowProxy.get());
if (properties.contains(ADDITIONAL_FLAGS_PROPERTY)) { if (properties.contains(ADDITIONAL_FLAGS_PROPERTY)) {
@ -286,7 +296,11 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
} }
object->setObjectName("InteractiveWindow"); object->setObjectName("InteractiveWindow");
object->setProperty(SOURCE_PROPERTY, sourceURL); object->setProperty(SOURCE_PROPERTY, sourceURL);
}); };
auto offscreenUi = DependencyManager::get<OffscreenUi>();
// Build the event bridge and wrapper on the main thread
offscreenUi->loadInNewContext(CONTENT_WINDOW_QML, objectInitLambda, contextInitLambda);
} }
} }

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

@ -26,9 +26,8 @@
[request setValue:@USER_AGENT_STRING forHTTPHeaderField:@"User-Agent"]; [request setValue:@USER_AGENT_STRING forHTTPHeaderField:@"User-Agent"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
// We're using an ephermeral session here to ensure the tags api response is never cached. request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
NSURLSession* session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.ephemeralSessionConfiguration]; NSURLSessionDataTask* dataTask = [NSURLSession.sharedSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"Latest Build Request error: %@", error); NSLog(@"Latest Build Request error: %@", error);
NSLog(@"Latest Build Request Data: %@", data); NSLog(@"Latest Build Request Data: %@", data);
NSHTTPURLResponse* ne = (NSHTTPURLResponse *)response; NSHTTPURLResponse* ne = (NSHTTPURLResponse *)response;

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

@ -351,8 +351,10 @@ public:
Q_INVOKABLE void removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler); Q_INVOKABLE void removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler);
/**jsdoc /**jsdoc
* Starts running another script in Interface. * Starts running another script in Interface, if it isn't already running. The script is not automatically loaded next
* <table><tr><th>Available in:</th><td>Interface Scripts</td><td>Avatar Scripts</td></tr></table> * time Interface starts.
* <p class="availableIn"><strong>Supported Script Types:</strong> Interface Scripts &bull; Avatar Scripts</p>
* <p>See also, {@link ScriptDiscoveryService.loadScript}.</p>
* @function Script.load * @function Script.load
* @param {string} filename - The URL of the script to load. This can be relative to the current script's URL. * @param {string} filename - The URL of the script to load. This can be relative to the current script's URL.
* @example <caption>Load a script from another script.</caption> * @example <caption>Load a script from another script.</caption>
@ -754,8 +756,8 @@ signals:
void cleanupMenuItem(const QString& menuItemString); void cleanupMenuItem(const QString& menuItemString);
/**jsdoc /**jsdoc
* Triggered when a script prints a message to the program log via {@link Script.print}, {@link print}, * Triggered when the script prints a message to the program log via {@link print}, {@link Script.print},
* {@link console.log}, {@link console.info}, {@link console.warn}, {@link console.error}, or {@link console.debug}. * {@link console.log}, or {@link console.debug}.
* @function Script.printedMessage * @function Script.printedMessage
* @param {string} message - The message. * @param {string} message - The message.
* @param {string} scriptName - The name of the script that generated the message. * @param {string} scriptName - The name of the script that generated the message.
@ -764,7 +766,7 @@ signals:
void printedMessage(const QString& message, const QString& scriptName); void printedMessage(const QString& message, const QString& scriptName);
/**jsdoc /**jsdoc
* Triggered when a script generates an error or {@link console.error} is called. * Triggered when the script generates an error or {@link console.error} is called.
* @function Script.errorMessage * @function Script.errorMessage
* @param {string} message - The error message. * @param {string} message - The error message.
* @param {string} scriptName - The name of the script that generated the error message. * @param {string} scriptName - The name of the script that generated the error message.
@ -773,7 +775,7 @@ signals:
void errorMessage(const QString& message, const QString& scriptName); void errorMessage(const QString& message, const QString& scriptName);
/**jsdoc /**jsdoc
* Triggered when a script generates a warning or {@link console.warn} is called. * Triggered when the script generates a warning or {@link console.warn} is called.
* @function Script.warningMessage * @function Script.warningMessage
* @param {string} message - The warning message. * @param {string} message - The warning message.
* @param {string} scriptName - The name of the script that generated the warning message. * @param {string} scriptName - The name of the script that generated the warning message.
@ -782,7 +784,7 @@ signals:
void warningMessage(const QString& message, const QString& scriptName); void warningMessage(const QString& message, const QString& scriptName);
/**jsdoc /**jsdoc
* Triggered when a script generates an information message or {@link console.info} is called. * Triggered when the script generates an information message or {@link console.info} is called.
* @function Script.infoMessage * @function Script.infoMessage
* @param {string} message - The information message. * @param {string} message - The information message.
* @param {string} scriptName - The name of the script that generated the information message. * @param {string} scriptName - The name of the script that generated the information message.
@ -845,8 +847,9 @@ signals:
* @param {Uuid} entityID - The ID of the entity that the script is running in. * @param {Uuid} entityID - The ID of the entity that the script is running in.
* @returns {Signal} * @returns {Signal}
* @example <caption>Get the ID of the entity that a client entity script is running in.</caption> * @example <caption>Get the ID of the entity that a client entity script is running in.</caption>
* var entityScript = (function () { * var entityScript = function () {
* this.entityID = Uuid.NULL; * this.entityID = Uuid.NULL;
* };
* *
* Script.entityScriptPreloadFinished.connect(function (entityID) { * Script.entityScriptPreloadFinished.connect(function (entityID) {
* this.entityID = entityID; * this.entityID = entityID;

View file

@ -209,6 +209,18 @@ void ScriptEngines::shutdownScripting() {
qCDebug(scriptengine) << "DONE Stopping all scripts...."; qCDebug(scriptengine) << "DONE Stopping all scripts....";
} }
/**jsdoc
* Information on a public script, i.e., a script that's included in the Interface installation.
* @typedef {object} ScriptDiscoveryService.PublicScript
* @property {string} name - The script's file name.
* @property {string} type - <code>"script"</code> or <code>"folder"</code>.
* <p class="important">Deprecated: This property is deprecated and will be removed. It currently always has the value,
* <code>"script"</code>.</p>
* @property {ScriptDiscoveryService.PublicScript[]} [children] - Only present if <code>type == "folder"</code>.
* <p class="important">Deprecated: This property is deprecated and will be removed. It currently is never present.
* @property {string} [url] - The full URL of the script &mdash; including the <code>"file:///"</code> scheme at the start.
* <p>Only present if <code>type == "script"</code>.</p>
*/
QVariantList getPublicChildNodes(TreeNodeFolder* parent) { QVariantList getPublicChildNodes(TreeNodeFolder* parent) {
QVariantList result; QVariantList result;
QList<TreeNodeBase*> treeNodes = getScriptsModel().getFolderNodes(parent); QList<TreeNodeBase*> treeNodes = getScriptsModel().getFolderNodes(parent);
@ -240,6 +252,13 @@ QVariantList ScriptEngines::getPublic() {
return getPublicChildNodes(NULL); return getPublicChildNodes(NULL);
} }
/**jsdoc
* Information on a local script.
* @typedef {object} ScriptDiscoveryService.LocalScript
* @property {string} name - The script's file name.
* @property {string} path - The script's path.
* @deprecated This type is deprecated and will be removed.
*/
QVariantList ScriptEngines::getLocal() { QVariantList ScriptEngines::getLocal() {
QVariantList result; QVariantList result;
QList<TreeNodeBase*> treeNodes = getScriptsModel().getFolderNodes(NULL); QList<TreeNodeBase*> treeNodes = getScriptsModel().getFolderNodes(NULL);
@ -260,6 +279,15 @@ QVariantList ScriptEngines::getLocal() {
return result; return result;
} }
/**jsdoc
* Information on a running script.
* @typedef {object} ScriptDiscoveryService.RunningScript
* @property {boolean} local - <code>true</code> if the script is a local file (i.e., the scheme is "file"), <code>false</code>
* if it isn't (e.g., the scheme is "http").
* @property {string} name - The script's file name.
* @property {string} path - The script's path and file name &mdash; excluding the scheme if a local file.
* @property {string} url - The full URL of the script &mdash; including the scheme if a local file.
*/
QVariantList ScriptEngines::getRunning() { QVariantList ScriptEngines::getRunning() {
QVariantList result; QVariantList result;
auto runningScripts = getRunningScripts(); auto runningScripts = getRunningScripts();

View file

@ -28,18 +28,26 @@
class ScriptEngine; class ScriptEngine;
/**jsdoc /**jsdoc
* The <code>ScriptDiscoveryService</code> API provides facilities to work with Interface scripts.
*
* @namespace ScriptDiscoveryService * @namespace ScriptDiscoveryService
* *
* @hifi-interface * @hifi-interface
* @hifi-client-entity
* @hifi-avatar * @hifi-avatar
* @hifi-client-entity
* *
* @property {string} debugScriptUrl * @property {string} debugScriptUrl="" - The path and name of a script to debug using the "API Debugger" developer tool
* @property {string} defaultScriptsPath * (currentAPI.js). If set, the API Debugger dialog displays the objects and values exposed by the script using
* @property {ScriptsModel} scriptsModel * {@link Script.registerValue} and similar.
* @property {ScriptsModelFilter} scriptsModelFilter * @property {string} defaultScriptsPath - The path where the default scripts are located in the Interface installation.
* <em>Read-only.</em>
* @property {ScriptsModel} scriptsModel - Information on the scripts that are in the default scripts directory of the
* Interface installation.
* <em>Read-only.</em>
* @property {ScriptsModelFilter} scriptsModelFilter - Sorted and filtered information on the scripts that are in the default
* scripts directory of the Interface installation.
* <em>Read-only.</em>
*/ */
class NativeScriptInitializers : public ScriptInitializerMixin { class NativeScriptInitializers : public ScriptInitializerMixin {
public: public:
bool registerNativeScriptInitializer(NativeScriptInitializer initializer) override; bool registerNativeScriptInitializer(NativeScriptInitializer initializer) override;
@ -77,61 +85,92 @@ public:
QString getDefaultScriptsLocation() const; QString getDefaultScriptsLocation() const;
/**jsdoc /**jsdoc
* Starts running an Interface script, if it isn't already running. The script is automatically loaded next time Interface
* starts.
* <p>This is a synonym for calling {@link ScriptDiscoveryService.loadScript|loadScript} with just the script URL.</p>
* <p class="availableIn"><strong>Supported Script Types:</strong> Interface Scripts &bull; Avatar Scripts</p>
* <p>See also, {@link Script.load}.</p>
* @function ScriptDiscoveryService.loadOneScript * @function ScriptDiscoveryService.loadOneScript
* @param {string} filename * @param {string} url - The path and name of the script. If a local file, including the <code>"file:///"</code> scheme is
* optional.
*/ */
Q_INVOKABLE void loadOneScript(const QString& scriptFilename); Q_INVOKABLE void loadOneScript(const QString& scriptFilename);
/**jsdoc /**jsdoc
* Starts running an Interface script, if it isn't already running.
* <p class="availableIn"><strong>Supported Script Types:</strong> Interface Scripts &bull; Avatar Scripts</p>
* <p>See also, {@link Script.load}.</p>
* @function ScriptDiscoveryService.loadScript * @function ScriptDiscoveryService.loadScript
* @param {string} [filename=""] * @param {string} [url=""] - The path and name of the script. If a local file, including the <code>"file:///"</code>
* @param {boolean} [isUserLoaded=true] * scheme is optional.
* @param {boolean} [loadScriptFromEditor=false] * @param {boolean} [isUserLoaded=true] - <code>true</code> if the user specifically loaded it, <code>false</code> if not
* @param {boolean} [activateMainWindow=false] * (e.g., a script loaded it). If <code>false</code>, the script is not automatically loaded next time Interface starts.
* @param {boolean} [reload=false] * @param {boolean} [loadScriptFromEditor=false] - <em>Not used.</em>
* @param {boolean} [quitWhenFinished=false] * @param {boolean} [activateMainWindow=false] - <em>Not used.</em>
* @returns {boolean} * @param {boolean} [reload=false] - <code>true</code> to redownload the script, <code>false</code> to use the copy from
* the cache if available.
* @param {boolean} [quitWhenFinished=false] - <code>true</code> to close Interface when the script finishes,
* <code>false</code> to not close Interface.
* @returns {object} An empty object, <code>{}</code>.
*/ */
Q_INVOKABLE ScriptEnginePointer loadScript(const QUrl& scriptFilename = QString(), Q_INVOKABLE ScriptEnginePointer loadScript(const QUrl& scriptFilename = QString(),
bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false, bool quitWhenFinished = false); bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false, bool quitWhenFinished = false);
/**jsdoc /**jsdoc
* Stops or restarts an Interface script.
* @function ScriptDiscoveryService.stopScript * @function ScriptDiscoveryService.stopScript
* @param {string} scriptHash * @param {string} url - The path and name of the script. If a local file, including the <code>"file:///"</code> scheme is
* @param {boolean} [restart=false] * optional.
* @returns {boolean} * @param {boolean} [restart=false] - <code>true</code> to redownload and restart the script, <code>false</code> to stop
* it.
* @returns {boolean} <code>true</code> if the script was successfully stopped or restarted, <code>false</code> if it
* wasn't (e.g., the script couldn't be found).
*/ */
Q_INVOKABLE bool stopScript(const QString& scriptHash, bool restart = false); Q_INVOKABLE bool stopScript(const QString& scriptHash, bool restart = false);
/**jsdoc /**jsdoc
* @function ScriptDiscoveryService.reloadAllScripts * Restarts all Interface, avatar, and client entity scripts after clearing the scripts cache.
*/ * @function ScriptDiscoveryService.reloadAllScripts
*/
Q_INVOKABLE void reloadAllScripts(); Q_INVOKABLE void reloadAllScripts();
/**jsdoc /**jsdoc
* Stops or restarts all Interface scripts. The scripts cache is not cleared. If restarting, avatar and client entity
* scripts are also restarted.
* @function ScriptDiscoveryService.stopAllScripts * @function ScriptDiscoveryService.stopAllScripts
* @param {boolean} [restart=false] * @param {boolean} [restart=false] - <code>true</code> to restart the scripts, <code>false</code> to stop them.
*/ */
Q_INVOKABLE void stopAllScripts(bool restart = false); Q_INVOKABLE void stopAllScripts(bool restart = false);
/**jsdoc /**jsdoc
* Gets a list of all Interface scripts that are currently running.
* @function ScriptDiscoveryService.getRunning * @function ScriptDiscoveryService.getRunning
* @returns {object[]} * @returns {ScriptDiscoveryService.RunningScript[]} All Interface scripts that are currently running.
* @example <caption>Report all running scripts.</caption>
* var runningScripts = ScriptDiscoveryService.getRunning();
* print("Running scripts:");
* for (var i = 0; i < runningScripts.length; i++) {
* print(JSON.stringify(runningScripts[i]));
* }
*/ */
Q_INVOKABLE QVariantList getRunning(); Q_INVOKABLE QVariantList getRunning();
/**jsdoc /**jsdoc
* Gets a list of all script files that are in the default scripts directory of the Interface installation.
* @function ScriptDiscoveryService.getPublic * @function ScriptDiscoveryService.getPublic
* @returns {object[]} * @returns {ScriptDiscoveryService.PublicScript[]} All scripts in the "scripts" directory of the Interface
* installation.
*/ */
Q_INVOKABLE QVariantList getPublic(); Q_INVOKABLE QVariantList getPublic();
/**jsdoc /**jsdoc
* @function ScriptDiscoveryService.getLocal * @function ScriptDiscoveryService.getLocal
* @returns {object[]} * @returns {ScriptDiscoveryService.LocalScript[]} Local scripts.
* @deprecated This function is deprecated and will be removed.
*/ */
// Deprecated because there is no longer a notion of a "local" scripts folder where you would put your personal scripts.
Q_INVOKABLE QVariantList getLocal(); Q_INVOKABLE QVariantList getLocal();
// FIXME: Move to other Q_PROPERTY declarations. // FIXME: Move to other Q_PROPERTY declarations.
@ -148,65 +187,82 @@ public:
signals: signals:
/**jsdoc /**jsdoc
* Triggered when the number of Interface scripts running changes.
* @function ScriptDiscoveryService.scriptCountChanged * @function ScriptDiscoveryService.scriptCountChanged
* @returns {Signal} * @returns {Signal}
* @example <caption>Report when the number of running scripts changes.</caption>
* ScriptDiscoveryService.scriptCountChanged.connect(function () {
* print("Scripts count changed: " + ScriptDiscoveryService.getRunning().length);
* });
*/ */
void scriptCountChanged(); void scriptCountChanged();
/**jsdoc /**jsdoc
* Triggered when Interface, avatar, and client entity scripts are restarting as a result of
* {@link ScriptDiscoveryService.reloadAllScripts|reloadAllScripts} or
* {@link ScriptDiscoveryService.stopAllScripts|stopAllScripts}.
* @function ScriptDiscoveryService.scriptsReloading * @function ScriptDiscoveryService.scriptsReloading
* @returns {Signal} * @returns {Signal}
*/ */
void scriptsReloading(); void scriptsReloading();
/**jsdoc /**jsdoc
* Triggered when a script could not be loaded.
* @function ScriptDiscoveryService.scriptLoadError * @function ScriptDiscoveryService.scriptLoadError
* @param {string} filename * @param {string} url - The path and name of the script that could not be loaded.
* @param {string} error * @param {string} error - <code>""</code> always.
* @returns {Signal} * @returns {Signal}
*/ */
void scriptLoadError(const QString& filename, const QString& error); void scriptLoadError(const QString& filename, const QString& error);
/**jsdoc /**jsdoc
* Triggered when any script prints a message to the program log via {@link print}, {@link Script.print},
* {@link console.log}, or {@link console.debug}.
* @function ScriptDiscoveryService.printedMessage * @function ScriptDiscoveryService.printedMessage
* @param {string} message * @param {string} message - The message.
* @param {string} engineName * @param {string} scriptName - The name of the script that generated the message.
* @returns {Signal} * @returns {Signal}
*/ */
void printedMessage(const QString& message, const QString& engineName); void printedMessage(const QString& message, const QString& engineName);
/**jsdoc /**jsdoc
* Triggered when any script generates an error or {@link console.error} is called.
* @function ScriptDiscoveryService.errorMessage * @function ScriptDiscoveryService.errorMessage
* @param {string} message * @param {string} message - The error message.
* @param {string} engineName * @param {string} scriptName - The name of the script that generated the error message.
* @returns {Signal} * @returns {Signal}
*/ */
void errorMessage(const QString& message, const QString& engineName); void errorMessage(const QString& message, const QString& engineName);
/**jsdoc /**jsdoc
* Triggered when any script generates a warning or {@link console.warn} is called.
* @function ScriptDiscoveryService.warningMessage * @function ScriptDiscoveryService.warningMessage
* @param {string} message * @param {string} message - The warning message.
* @param {string} engineName * @param {string} scriptName - The name of the script that generated the warning message.
* @returns {Signal} * @returns {Signal}
*/ */
void warningMessage(const QString& message, const QString& engineName); void warningMessage(const QString& message, const QString& engineName);
/**jsdoc /**jsdoc
* Triggered when any script generates an information message or {@link console.info} is called.
* @function ScriptDiscoveryService.infoMessage * @function ScriptDiscoveryService.infoMessage
* @param {string} message * @param {string} message - The information message.
* @param {string} engineName * @param {string} scriptName - The name of the script that generated the informaton message.
* @returns {Signal} * @returns {Signal}
*/ */
void infoMessage(const QString& message, const QString& engineName); void infoMessage(const QString& message, const QString& engineName);
/**jsdoc /**jsdoc
* @function ScriptDiscoveryService.errorLoadingScript * @function ScriptDiscoveryService.errorLoadingScript
* @param {string} url * @param {string} url - URL.
* @returns {Signal} * @returns {Signal}
* @deprecated This signal is deprecated and will be removed.
*/ */
// Deprecated because never emitted.
void errorLoadingScript(const QString& url); void errorLoadingScript(const QString& url);
/**jsdoc /**jsdoc
* Triggered when the Debug Window is cleared.
* @function ScriptDiscoveryService.clearDebugWindow * @function ScriptDiscoveryService.clearDebugWindow
* @returns {Signal} * @returns {Signal}
*/ */
@ -216,50 +272,64 @@ public slots:
/**jsdoc /**jsdoc
* @function ScriptDiscoveryService.onPrintedMessage * @function ScriptDiscoveryService.onPrintedMessage
* @param {string} message * @param {string} message - Message.
* @param {string} scriptName * @param {string} scriptName - Script name.
* @deprecated This function is deprecated and will be removed.
*/ */
// Deprecated because only use is to emit a signal.
void onPrintedMessage(const QString& message, const QString& scriptName); void onPrintedMessage(const QString& message, const QString& scriptName);
/**jsdoc /**jsdoc
* @function ScriptDiscoveryService.onErrorMessage * @function ScriptDiscoveryService.onErrorMessage
* @param {string} message * @param {string} message - Message.
* @param {string} scriptName * @param {string} scriptName - Script name.
* @deprecated This function is deprecated and will be removed.
*/ */
// Deprecated because only use is to emit a signal.
void onErrorMessage(const QString& message, const QString& scriptName); void onErrorMessage(const QString& message, const QString& scriptName);
/**jsdoc /**jsdoc
* @function ScriptDiscoveryService.onWarningMessage * @function ScriptDiscoveryService.onWarningMessage
* @param {string} message * @param {string} message - Message.
* @param {string} scriptName * @param {string} scriptName - Script name.
* @deprecated This function is deprecated and will be removed.
*/ */
// Deprecated because only use is to emit a signal.
void onWarningMessage(const QString& message, const QString& scriptName); void onWarningMessage(const QString& message, const QString& scriptName);
/**jsdoc /**jsdoc
* @function ScriptDiscoveryService.onInfoMessage * @function ScriptDiscoveryService.onInfoMessage
* @param {string} message * @param {string} message - Message.
* @param {string} scriptName * @param {string} scriptName - Script name.
* @deprecated This function is deprecated and will be removed.
*/ */
// Deprecated because only use is to emit a signal.
void onInfoMessage(const QString& message, const QString& scriptName); void onInfoMessage(const QString& message, const QString& scriptName);
/**jsdoc /**jsdoc
* @function ScriptDiscoveryService.onErrorLoadingScript * @function ScriptDiscoveryService.onErrorLoadingScript
* @param {string} url * @param {string} url - URL.
* @deprecated This function is deprecated and will be removed.
*/ */
// Deprecated because only use is to emit a signal. And it isn't used.
void onErrorLoadingScript(const QString& url); void onErrorLoadingScript(const QString& url);
/**jsdoc /**jsdoc
* @function ScriptDiscoveryService.onClearDebugWindow * @function ScriptDiscoveryService.onClearDebugWindow
* @deprecated This function is deprecated and will be removed.
*/ */
// Deprecated because only use is to emit a signal.
void onClearDebugWindow(); void onClearDebugWindow();
protected slots: protected slots:
/**jsdoc /**jsdoc
* @function ScriptDiscoveryService.onScriptFinished * @function ScriptDiscoveryService.onScriptFinished
* @param {string} filename * @param {string} scriptName - Script name.
* @param {object} engine * @param {object} engine - Engine.
* @deprecated This function is deprecated and will be removed.
*/ */
// Deprecated because it wasn't intended to be in the API.
void onScriptFinished(const QString& fileNameString, ScriptEnginePointer engine); void onScriptFinished(const QString& fileNameString, ScriptEnginePointer engine);
protected: protected:

View file

@ -64,14 +64,60 @@ public:
}; };
/**jsdoc /**jsdoc
* <p>Provided as a property of {@link ScriptDiscoveryService}.</p> * Information on the scripts that are in the default scripts directory of the Interface installation. This is provided as a
* <p>Has properties and functions below in addition to those of <a href="http://doc.qt.io/qt-5/qabstractitemmodel.html"> * property of {@link ScriptDiscoveryService}.
* http://doc.qt.io/qt-5/qabstractitemmodel.html</a>.</p> *
* <p>The information provided reflects the subdirectory structure. Methods and signals are per QT's
* <a href="http://doc.qt.io/qt-5/qabstractitemmodel.html">QAbstractItemModel</a> class, with the following details:</p>
* <ul>
* <li>A single column of data: <code>columnCount(index)</code> returns <code>1</code>. </li>
* <li>Data is provided for the following roles:
* <table>
* <thead>
* <tr><th>Role</th><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td>Display</td><td><code>0</code></td><td>The directory or script file name.</td></tr>
* <tr><td>Path</td><td><code>256</code></td><td>The path and filename of the data item if it is a script,
* <code>undefined</code> if it is a directory.</td></tr>
* </tbody>
* </table>
* </li>
* <li>Use <code>null</code> for the root directory's index.</li>
* </ul>
*
* @class ScriptsModel * @class ScriptsModel
* @hideconstructor
* *
* @hifi-interface * @hifi-interface
* @hifi-client-entity * @hifi-client-entity
* @hifi-avatar * @hifi-avatar
*
* @example <caption>List the first 2 levels of the scripts directory.</caption>
* var MAX_DIRECTORY_LEVEL = 1;
* var DISPLAY_ROLE = 0;
* var PATH_ROLE = 256;
*
* function printDirectory(parentIndex, directoryLevel, indent) {
* var numRows = ScriptDiscoveryService.scriptsModel.rowCount(parentIndex);
* for (var i = 0; i < numRows; i++) {
* var rowIndex = ScriptDiscoveryService.scriptsModel.index(i, 0, parentIndex);
*
* var name = ScriptDiscoveryService.scriptsModel.data(rowIndex, DISPLAY_ROLE);
* var hasChildren = ScriptDiscoveryService.scriptsModel.hasChildren(rowIndex);
* var path = hasChildren ? "" : ScriptDiscoveryService.scriptsModel.data(rowIndex, PATH_ROLE);
*
* print(indent + "- " + name + (hasChildren ? "" : " - " + path));
*
* if (hasChildren && directoryLevel < MAX_DIRECTORY_LEVEL) {
* printDirectory(rowIndex, directoryLevel + 1, indent + " ");
* }
* }
* }
*
* print("Scripts:");
* printDirectory(null, 0, ""); // null index for the root directory.
*/ */
class ScriptsModel : public QAbstractItemModel { class ScriptsModel : public QAbstractItemModel {
Q_OBJECT Q_OBJECT
@ -79,56 +125,25 @@ public:
ScriptsModel(QObject* parent = NULL); ScriptsModel(QObject* parent = NULL);
~ScriptsModel(); ~ScriptsModel();
/**jsdoc // No JSDoc because the particulars of the parent class is provided in the @class description.
* @function ScriptsModel.index
* @param {number} row
* @param {number} column
* @param {QModelIndex} parent
* @returns {QModelIndex}
*/
QModelIndex index(int row, int column, const QModelIndex& parent) const override; QModelIndex index(int row, int column, const QModelIndex& parent) const override;
/**jsdoc // No JSDoc because the particulars of the parent class is provided in the @class description.
* @function ScriptsModel.parent
* @param {QModelIndex} child
* @returns {QModelIndex}
*/
QModelIndex parent(const QModelIndex& child) const override; QModelIndex parent(const QModelIndex& child) const override;
/**jsdoc // No JSDoc because the particulars of the parent class is provided in the @class description.
* @function ScriptsModel.data
* @param {QModelIndex} index
* @param {number} [role=0]
* returns {string}
*/
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
/**jsdoc // No JSDoc because the particulars of the parent class is provided in the @class description.
* @function ScriptsModel.rowCount
* @param {QmodelIndex} [parent=null]
* @returns {number}
*/
int rowCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override;
/**jsdoc // No JSDoc because the particulars of the parent class is provided in the @class description.
* @function ScriptsModel.columnCount
* @param {QmodelIndex} [parent=null]
* @returns {number}
*/
int columnCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override;
/**jsdoc // Not exposed in the API because no conversion between TreeNodeBase and QScriptValue is provided.
* @function ScriptsModel.getTreeNodeFromIndex
* @param {QmodelIndex} index
* @returns {TreeNodeBase}
*/
TreeNodeBase* getTreeNodeFromIndex(const QModelIndex& index) const; TreeNodeBase* getTreeNodeFromIndex(const QModelIndex& index) const;
/**jsdoc // Not exposed in the API because no conversion between TreeNodeBase and QScriptValue is provided.
* @function ScriptsModel.getFolderNodes
* @param {TreeNodeFolder} parent
* @returns {TreeNodeBase[]}
*/
QList<TreeNodeBase*> getFolderNodes(TreeNodeFolder* parent) const; QList<TreeNodeBase*> getFolderNodes(TreeNodeFolder* parent) const;
enum Role { enum Role {
@ -136,9 +151,30 @@ public:
}; };
protected slots: protected slots:
/**jsdoc
* @function ScriptsModel.updateScriptsLocation
* @param {string} newPath - New path.
* @deprecated This method is deprecated and will be removed from the API.
*/
void updateScriptsLocation(const QString& newPath); void updateScriptsLocation(const QString& newPath);
/**jsdoc
* @function ScriptsModel.downloadFinished
* @deprecated This method is deprecated and will be removed from the API.
*/
void downloadFinished(); void downloadFinished();
/**jsdoc
* @function ScriptsModel.reloadLocalFiles
* @deprecated This method is deprecated and will be removed from the API.
*/
void reloadLocalFiles(); void reloadLocalFiles();
/**jsdoc
* @function ScriptsModel.reloadDefaultFiles
* @deprecated This method is deprecated and will be removed from the API.
*/
void reloadDefaultFiles(); void reloadDefaultFiles();
protected: protected:

View file

@ -16,14 +16,60 @@
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
/**jsdoc /**jsdoc
* <p>Provided as a property of {@link ScriptDiscoveryService}.</p> * Sorted and filtered information on the scripts that are in the default scripts directory of the Interface installation. This
* <p>Has properties and functions per <a href="http://doc.qt.io/qt-5/qsortfilterproxymodel.html"> * is provided as a property of {@link ScriptDiscoveryService}.
* http://doc.qt.io/qt-5/qsortfilterproxymodel.html</a>.</p> *
* <p>The information provided reflects the subdirectory structure. Properties, methods, and signals are per QT's
* <a href="https://doc.qt.io/qt-5/qsortfilterproxymodel.html">QSortFilterProxyModel</a> class, with the following details:</p>
* <ul>
* <li>The rows are sorted per directory and file names.</li>
* <li>A single column of data: <code>columnCount(index)</code> returns <code>1</code>. </li>
* <li>Data is provided for the following roles:
* <table>
* <thead>
* <tr><th>Role</th><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td>Display</td><td><code>0</code></td><td>The directory or script file name.</td></tr>
* <tr><td>Path</td><td><code>256</code></td><td>The path and filename of the data item if it is a script,
* <code>undefined</code> if it is a directory.</td></tr>
* </tbody>
* </table>
* </li>
* <li>Use <code>null</code> for the root directory's index.</li>
* </ul>
*
* @class ScriptsModelFilter * @class ScriptsModelFilter
* @hideconstructor
* *
* @hifi-interface * @hifi-interface
* @hifi-client-entity * @hifi-client-entity
* @hifi-avatar * @hifi-avatar
*
* @example <caption>List all scripts that include "edit" in their name.</caption>
* var DISPLAY_ROLE = 0;
* var PATH_ROLE = 256;
*
* function printDirectory(parentIndex, directoryLevel, indent) {
* var numRows = ScriptDiscoveryService.scriptsModelFilter.rowCount(parentIndex);
* for (var i = 0; i < numRows; i++) {
* var rowIndex = ScriptDiscoveryService.scriptsModelFilter.index(i, 0, parentIndex);
*
* var name = ScriptDiscoveryService.scriptsModelFilter.data(rowIndex, DISPLAY_ROLE);
* var hasChildren = ScriptDiscoveryService.scriptsModelFilter.hasChildren(rowIndex);
* var path = hasChildren ? "" : ScriptDiscoveryService.scriptsModelFilter.data(rowIndex, PATH_ROLE);
*
* print(indent + "- " + name + (hasChildren ? "" : " - " + path));
*
* if (hasChildren) {
* printDirectory(rowIndex, directoryLevel + 1, indent + " ");
* }
* }
* }
*
* ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*edit.*$", "i"); // Set the filter.
* print("Edit scripts:");
* printDirectory(null, 0, ""); // null index for the root directory.
*/ */
class ScriptsModelFilter : public QSortFilterProxyModel { class ScriptsModelFilter : public QSortFilterProxyModel {
Q_OBJECT Q_OBJECT

View file

@ -136,13 +136,9 @@ void QmlWindowClass::initQml(QVariantMap properties) {
#if !defined(Q_OS_ANDROID) #if !defined(Q_OS_ANDROID)
// 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
qDebug() << "Context initialization lambda"; ContextAwareProfile::restrictContext(context, _restricted);
if (_restricted) { FileTypeProfile::registerWithContext(context);
qDebug() << "Restricting web content"; HFWebEngineProfile::registerWithContext(context);
ContextAwareProfile::restrictContext(context);
FileTypeProfile::registerWithContext(context);
HFWebEngineProfile::registerWithContext(context);
}
#endif #endif
}; };

View file

@ -11,22 +11,47 @@
#include "ContextAwareProfile.h" #include "ContextAwareProfile.h"
#if !defined(Q_OS_ANDROID) #include <cassert>
#include <QtCore/QThread>
#include <QtQml/QQmlContext> #include <QtQml/QQmlContext>
#include <shared/QtHelpers.h>
#include <SharedUtil.h>
static const QString RESTRICTED_FLAG_PROPERTY = "RestrictFileAccess"; static const QString RESTRICTED_FLAG_PROPERTY = "RestrictFileAccess";
ContextAwareProfile::ContextAwareProfile(QQmlContext* parent) : ContextAwareProfile::ContextAwareProfile(QQmlContext* context) :
QQuickWebEngineProfile(parent), _context(parent) { } ContextAwareProfileParent(context), _context(context) {
assert(context);
void ContextAwareProfile::restrictContext(QQmlContext* context) {
context->setContextProperty(RESTRICTED_FLAG_PROPERTY, true);
} }
bool ContextAwareProfile::isRestricted(QQmlContext* context) {
return context->contextProperty(RESTRICTED_FLAG_PROPERTY).toBool(); void ContextAwareProfile::restrictContext(QQmlContext* context, bool restrict) {
context->setContextProperty(RESTRICTED_FLAG_PROPERTY, restrict);
} }
#endif bool ContextAwareProfile::isRestrictedInternal() {
if (QThread::currentThread() != thread()) {
bool restrictedResult = false;
BLOCKING_INVOKE_METHOD(this, "isRestrictedInternal", Q_RETURN_ARG(bool, restrictedResult));
return restrictedResult;
}
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() {
auto now = usecTimestampNow();
if (now > _cacheExpiry) {
_cachedValue = isRestrictedInternal();
_cacheExpiry = now + MAX_CACHE_AGE;
}
return _cachedValue;
}

View file

@ -17,26 +17,40 @@
#include <QtWebEngine/QQuickWebEngineProfile> #include <QtWebEngine/QQuickWebEngineProfile>
#include <QtWebEngineCore/QWebEngineUrlRequestInterceptor> #include <QtWebEngineCore/QWebEngineUrlRequestInterceptor>
using ContextAwareProfileParent = QQuickWebEngineProfile;
using RequestInterceptorParent = QWebEngineUrlRequestInterceptor;
#else
#include <QtCore/QObject>
using ContextAwareProfileParent = QObject;
using RequestInterceptorParent = QObject;
#endif
#include <NumericalConstants.h>
class QQmlContext; class QQmlContext;
class ContextAwareProfile : public QQuickWebEngineProfile { class ContextAwareProfile : public ContextAwareProfileParent {
Q_OBJECT
public: public:
static void restrictContext(QQmlContext* context); static void restrictContext(QQmlContext* context, bool restrict = true);
static bool isRestricted(QQmlContext* context); bool isRestricted();
QQmlContext* getContext() const { return _context; } Q_INVOKABLE bool isRestrictedInternal();
protected: protected:
class RequestInterceptor : public QWebEngineUrlRequestInterceptor { class RequestInterceptor : public RequestInterceptorParent {
public: public:
RequestInterceptor(ContextAwareProfile* parent) : QWebEngineUrlRequestInterceptor(parent), _profile(parent) {} RequestInterceptor(ContextAwareProfile* parent) : RequestInterceptorParent(parent), _profile(parent) { }
QQmlContext* getContext() const { return _profile->getContext(); } bool isRestricted() { return _profile->isRestricted(); }
protected: protected:
ContextAwareProfile* _profile; ContextAwareProfile* _profile;
}; };
ContextAwareProfile(QQmlContext* parent); ContextAwareProfile(QQmlContext* parent);
QQmlContext* _context; QQmlContext* _context{ nullptr };
bool _cachedValue{ false };
quint64 _cacheExpiry{ 0 };
constexpr static quint64 MAX_CACHE_AGE = MSECS_PER_SECOND;
}; };
#endif
#endif // hifi_FileTypeProfile_h #endif // hifi_FileTypeProfile_h

Some files were not shown because too many files have changed in this diff Show more