add remotelyCallable and remoteCallerID to provide additional security to Entities.callEntityServerMethod()

This commit is contained in:
ZappoMan 2017-10-22 14:30:58 -07:00
parent fb7f6df694
commit a7e21d7e76
4 changed files with 39 additions and 8 deletions

View file

@ -248,7 +248,7 @@ void EntityScriptServer::handleEntityScriptCallMethodPacket(QSharedPointer<Recei
params << paramString; params << paramString;
} }
_entitiesScriptEngine->callEntityScriptMethod(entityID, method, params); _entitiesScriptEngine->callEntityScriptMethod(entityID, method, params, senderNode->getUUID());
} }
} }

View file

@ -20,7 +20,8 @@
class EntitiesScriptEngineProvider { class EntitiesScriptEngineProvider {
public: 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<QVariant> getLocalEntityScriptDetails(const EntityItemID& entityID) = 0; virtual QFuture<QVariant> getLocalEntityScriptDetails(const EntityItemID& entityID) = 0;
}; };

View file

@ -2476,7 +2476,7 @@ void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, const QUrl&
doWithEnvironment(entityID, sandboxURL, operation); 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()) { if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING #ifdef THREAD_DEBUGGING
qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " 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", QMetaObject::invokeMethod(this, "callEntityScriptMethod",
Q_ARG(const EntityItemID&, entityID), Q_ARG(const EntityItemID&, entityID),
Q_ARG(const QString&, methodName), Q_ARG(const QString&, methodName),
Q_ARG(const QStringList&, params)); Q_ARG(const QStringList&, params),
Q_ARG(const QUuid&, remoteCallerID));
return; return;
} }
#ifdef THREAD_DEBUGGING #ifdef THREAD_DEBUGGING
@ -2500,13 +2501,41 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
if (isEntityScriptRunning(entityID)) { if (isEntityScriptRunning(entityID)) {
EntityScriptDetails details = _entityScripts[entityID]; EntityScriptDetails details = _entityScripts[entityID];
QScriptValue entityScript = details.scriptObject; // previously loaded 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; QScriptValueList args;
args << entityID.toScriptValue(this); args << entityID.toScriptValue(this);
args << qScriptValueFromSequence(this, params); 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);
}
} }
} }

View file

@ -198,7 +198,8 @@ public:
Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap = false); // will call unload method Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap = false); // will call unload method
Q_INVOKABLE void unloadAllEntityScripts(); Q_INVOKABLE void unloadAllEntityScripts();
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, 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 PointerEvent& event);
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision); Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision);