From a7e21d7e76e20abde0bba92bf50681952c5dfac1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 22 Oct 2017 14:30:58 -0700 Subject: [PATCH] add remotelyCallable and remoteCallerID to provide additional security to Entities.callEntityServerMethod() --- .../src/scripts/EntityScriptServer.cpp | 2 +- .../src/EntitiesScriptEngineProvider.h | 3 +- libraries/script-engine/src/ScriptEngine.cpp | 39 ++++++++++++++++--- libraries/script-engine/src/ScriptEngine.h | 3 +- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index c40ff3ba86..0ced0a632e 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -248,7 +248,7 @@ void EntityScriptServer::handleEntityScriptCallMethodPacket(QSharedPointercallEntityScriptMethod(entityID, method, params); + _entitiesScriptEngine->callEntityScriptMethod(entityID, method, params, senderNode->getUUID()); } } diff --git a/libraries/entities/src/EntitiesScriptEngineProvider.h b/libraries/entities/src/EntitiesScriptEngineProvider.h index d87dd105c2..100c17df5f 100644 --- a/libraries/entities/src/EntitiesScriptEngineProvider.h +++ b/libraries/entities/src/EntitiesScriptEngineProvider.h @@ -20,7 +20,8 @@ class EntitiesScriptEngineProvider { public: - virtual void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params = QStringList()) = 0; + virtual void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, + const QStringList& params = QStringList(), const QUuid& remoteCallerID = QUuid()) = 0; virtual QFuture getLocalEntityScriptDetails(const EntityItemID& entityID) = 0; }; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 348a687ae2..3df69f6f0d 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -2476,7 +2476,7 @@ void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, const QUrl& doWithEnvironment(entityID, sandboxURL, operation); } -void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) { +void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params, const QUuid& remoteCallerID) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " @@ -2486,7 +2486,8 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS QMetaObject::invokeMethod(this, "callEntityScriptMethod", Q_ARG(const EntityItemID&, entityID), Q_ARG(const QString&, methodName), - Q_ARG(const QStringList&, params)); + Q_ARG(const QStringList&, params), + Q_ARG(const QUuid&, remoteCallerID)); return; } #ifdef THREAD_DEBUGGING @@ -2500,13 +2501,41 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS if (isEntityScriptRunning(entityID)) { EntityScriptDetails details = _entityScripts[entityID]; QScriptValue entityScript = details.scriptObject; // previously loaded - if (entityScript.property(methodName).isFunction()) { + + // If this is a remote call, we need to check to see if the function is remotely callable + // we do this by checking for the existance of the 'remotelyCallable' property on the + // entityScript. And we confirm that the method name is included. If this fails, the + // function will not be called. + bool callAllowed = false; + if (remoteCallerID == QUuid()) { + callAllowed = true; + } else { + if (entityScript.property("remotelyCallable").isArray()) { + auto callables = entityScript.property("remotelyCallable"); + auto callableCount = callables.property("length").toInteger(); + for (int i = 0; i < callableCount; i++) { + auto callable = callables.property(i).toString(); + if (callable == methodName) { + callAllowed = true; + break; + } + } + } + if (!callAllowed) { + qDebug() << "Method [" << methodName << "] not remotely callable."; + } + } + + if (callAllowed && entityScript.property(methodName).isFunction()) { QScriptValueList args; args << entityID.toScriptValue(this); args << qScriptValueFromSequence(this, params); - callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); - } + QScriptValue oldData = this->globalObject().property("remoteCallerID"); + this->globalObject().setProperty("remoteCallerID", remoteCallerID.toString()); // Make the remoteCallerID available to javascript as a global. + callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); + this->globalObject().setProperty("remoteCallerID", oldData); + } } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 7109e0f582..db159e7265 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -198,7 +198,8 @@ public: Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap = false); // will call unload method Q_INVOKABLE void unloadAllEntityScripts(); Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, - const QStringList& params = QStringList()) override; + const QStringList& params = QStringList(), + const QUuid& remoteCallerID = QUuid()) override; Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event); Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision);