History

Prohibit entity script file includes from outside the original entity script's directory (unless its in our resources).

howard-stearns committed 10 years ago

Commit 7b7ec5a1 parent 278fe932 files · +56 −21Browse files

Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 2 files). Show all

Unified · Split

libraries/script-engine/src/ScriptEngine.cpp+51−19
@@ -578,7 +578,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 577 unmodified lines
578 _registeredHandlers[entityID] = RegisteredEventHandlers();578 _registeredHandlers[entityID] = RegisteredEventHandlers();
579 }579 }
580 CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName];580 CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName];
581 CallbackData handlerData = {handler, currentEntityIdentifier};581 CallbackData handlerData = {handler, currentEntityIdentifier, currentSandboxURL};
582 handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler().582 handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler().
583}583}
584 584
@@ -795,7 +795,7 @@ void ScriptEngine::timerFired() { · 210 unmodified lines
795 795
796 // call the associated JS function, if it exists796 // call the associated JS function, if it exists
797 if (timerData.function.isValid()) {797 if (timerData.function.isValid()) {
798 callWithEnvironment(timerData.definingEntityIdentifier, timerData.function, timerData.function, QScriptValueList());798 callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, QScriptValueList());
799 }799 }
800}800}
801 801
@@ -810,7 +810,7 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int · 8 unmodified lines
810 // make sure the timer stops when the script does810 // make sure the timer stops when the script does
811 connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);811 connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
812 812
813 CallbackData timerData = {function, currentEntityIdentifier};813 CallbackData timerData = {function, currentEntityIdentifier, currentSandboxURL};
814 _timerFunctionMap.insert(newTimer, timerData);814 _timerFunctionMap.insert(newTimer, timerData);
815 815
816 newTimer->start(intervalMS);816 newTimer->start(intervalMS);
@@ -885,19 +885,46 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 68 unmodified lines
885 return; // bail early885 return; // bail early
886 }886 }
887 QList<QUrl> urls;887 QList<QUrl> urls;
888 bool knowsSensitivity = false;
889 Qt::CaseSensitivity sensitivity;
890 auto getSensitivity = [&]() {
891 if (!knowsSensitivity) {
892 QString path = currentSandboxURL.path();
893 QFileInfo upperFI(path.toUpper());
894 QFileInfo lowerFI(path.toLower());
895 sensitivity = (upperFI == lowerFI) ? Qt::CaseInsensitive : Qt::CaseSensitive;
896 knowsSensitivity = true;
897 }
898 return sensitivity;
899 };
900
888 for (QString file : includeFiles) {901 for (QString file : includeFiles) {
889 QUrl thisURL { resolvePath(file) };902 QUrl thisURL { resolvePath(file) };
890 if (!_includedURLs.contains(thisURL)) {903 if (!_includedURLs.contains(thisURL)) {
891 urls.append(thisURL);904 if (!currentSandboxURL.isEmpty() && (thisURL.scheme() == "file") &&
892 _includedURLs << thisURL;905 (
893 }906 (currentSandboxURL.scheme() != "file") ||
894 else {907 (
908 !thisURL.toString(QUrl::RemoveFilename).startsWith(defaultScriptsLocation().toString(), getSensitivity()) &&
909 !thisURL.toString(QUrl::RemoveFilename).startsWith(currentSandboxURL.toString(QUrl::RemoveFilename), getSensitivity())
910 )
911 )
912 ) {
913 qCWarning(scriptengine) << "Script.include() ignoring file path" << thisURL << "outside of original entity script" << currentSandboxURL;
914 } else {
915 // We could also check here for CORS, but we don't yet.
916 // It turns out that QUrl.resolve will not change hosts and copy authority, so we don't need to check that here.
917 urls.append(thisURL);
918 _includedURLs << thisURL;
919 }
920 } else {
895 qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL;921 qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL;
896 }922 }
897 }923 }
898 924
899 BatchLoader* loader = new BatchLoader(urls);925 BatchLoader* loader = new BatchLoader(urls);
900 EntityItemID capturedEntityIdentifier = currentEntityIdentifier;926 EntityItemID capturedEntityIdentifier = currentEntityIdentifier;
927 QUrl capturedSandboxURL = currentSandboxURL;
901 928
902 auto evaluateScripts = [=](const QMap<QUrl, QString>& data) {929 auto evaluateScripts = [=](const QMap<QUrl, QString>& data) {
903 auto parentURL = _parentURL;930 auto parentURL = _parentURL;
@@ -912,13 +939,13 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 8 unmodified lines
912 auto operation = [&]() {939 auto operation = [&]() {
913 evaluate(contents, url.toString());940 evaluate(contents, url.toString());
914 };941 };
915 doWithEnvironment(capturedEntityIdentifier, operation);942 doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation);
916 }943 }
917 }944 }
918 _parentURL = parentURL;945 _parentURL = parentURL;
919 946
920 if (callback.isFunction()) {947 if (callback.isFunction()) {
921 callWithEnvironment(capturedEntityIdentifier, QScriptValue(callback), QScriptValue(), QScriptValueList());948 callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, QScriptValue(callback), QScriptValue(), QScriptValueList());
922 }949 }
923 950
924 loader->deleteLater();951 loader->deleteLater();
@@ -996,10 +1023,11 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin · 71 unmodified lines
996 CallbackList handlersForEvent = handlersOnEntity[eventName];1023 CallbackList handlersForEvent = handlersOnEntity[eventName];
997 if (!handlersForEvent.isEmpty()) {1024 if (!handlersForEvent.isEmpty()) {
998 for (int i = 0; i < handlersForEvent.count(); ++i) {1025 for (int i = 0; i < handlersForEvent.count(); ++i) {
999 // handlersForEvent[i] can tonain many handlers that may have each been added by different interface or entity scripts,1026 // handlersForEvent[i] can contain many handlers that may have each been added by different interface or entity scripts,
1000 // and the entity scripts may be for entities other than the one this is a handler for.1027 // and the entity scripts may be for entities other than the one this is a handler for.
1001 // Fortunately, the definingEntityIdentifier captured the entity script id (if any) when the handler was added.1028 // Fortunately, the definingEntityIdentifier captured the entity script id (if any) when the handler was added.
1002 callWithEnvironment(handlersForEvent[i].definingEntityIdentifier, handlersForEvent[i].function, QScriptValue(), eventHandlerArgs);1029 CallbackData& handler = handlersForEvent[i];
1030 callWithEnvironment(handler.definingEntityIdentifier, handler.definingSandboxURL, handler.function, QScriptValue(), eventHandlerArgs);
1003 }1031 }
1004 }1032 }
1005}1033}
@@ -1106,13 +1134,14 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 100 unmodified lines
1106 lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();1134 lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();
1107 }1135 }
1108 QScriptValue entityScriptConstructor, entityScriptObject;1136 QScriptValue entityScriptConstructor, entityScriptObject;
1137 QUrl sandboxURL = currentSandboxURL.isEmpty() ? scriptOrURL : currentSandboxURL;
1109 auto initialization = [&]{1138 auto initialization = [&]{
1110 entityScriptConstructor = evaluate(contents, fileName);1139 entityScriptConstructor = evaluate(contents, fileName);
1111 entityScriptObject = entityScriptConstructor.construct();1140 entityScriptObject = entityScriptConstructor.construct();
1112 };1141 };
1113 doWithEnvironment(entityID, initialization);1142 doWithEnvironment(entityID, sandboxURL, initialization);
1114 1143
1115 EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified };1144 EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified, sandboxURL };
1116 _entityScripts[entityID] = newDetails;1145 _entityScripts[entityID] = newDetails;
1117 if (isURL) {1146 if (isURL) {
1118 setParentURL("");1147 setParentURL("");
@@ -1201,9 +1230,11 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 82 unmodified lines
1201// Even if entityID is supplied as currentEntityIdentifier, this still documents the source1230// Even if entityID is supplied as currentEntityIdentifier, this still documents the source
1202// of the code being executed (e.g., if we ever sandbox different entity scripts, or provide different1231// of the code being executed (e.g., if we ever sandbox different entity scripts, or provide different
1203// global values for different entity scripts).1232// global values for different entity scripts).
1204void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, std::function<void()> operation) {1233void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function<void()> operation) {
1205 EntityItemID oldIdentifier = currentEntityIdentifier;1234 EntityItemID oldIdentifier = currentEntityIdentifier;
1235 QUrl oldSandboxURL = currentSandboxURL;
1206 currentEntityIdentifier = entityID;1236 currentEntityIdentifier = entityID;
1237 currentSandboxURL = sandboxURL;
1207 1238
1208#if DEBUG_CURRENT_ENTITY1239#if DEBUG_CURRENT_ENTITY
1209 QScriptValue oldData = this->globalObject().property("debugEntityID");1240 QScriptValue oldData = this->globalObject().property("debugEntityID");
@@ -1215,12 +1246,13 @@ void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, std::function · 5 unmodified lines
1215#endif1246#endif
1216 1247
1217 currentEntityIdentifier = oldIdentifier;1248 currentEntityIdentifier = oldIdentifier;
1249 currentSandboxURL = oldSandboxURL;
1218}1250}
1219void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, QScriptValue function, QScriptValue thisObject, QScriptValueList args) {1251void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args) {
1220 auto operation = [&]() {1252 auto operation = [&]() {
1221 function.call(thisObject, args);1253 function.call(thisObject, args);
1222 };1254 };
1223 doWithEnvironment(entityID, operation);1255 doWithEnvironment(entityID, sandboxURL, operation);
1224}1256}
1225 1257
1226void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) {1258void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) {
@@ -1249,7 +1281,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 22 unmodified lines
1249 QScriptValueList args;1281 QScriptValueList args;
1250 args << entityID.toScriptValue(this);1282 args << entityID.toScriptValue(this);
1251 args << qScriptValueFromSequence(this, params);1283 args << qScriptValueFromSequence(this, params);
1252 callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args);1284 callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args);
1253 }1285 }
1254 1286
1255 }1287 }
@@ -1281,7 +1313,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 25 unmodified lines
1281 QScriptValueList args;1313 QScriptValueList args;
1282 args << entityID.toScriptValue(this);1314 args << entityID.toScriptValue(this);
1283 args << event.toScriptValue(this);1315 args << event.toScriptValue(this);
1284 callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args);1316 callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args);
1285 }1317 }
1286 }1318 }
1287}1319}
@@ -1315,7 +1347,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 27 unmodified lines
1315 args << entityID.toScriptValue(this);1347 args << entityID.toScriptValue(this);
1316 args << otherID.toScriptValue(this);1348 args << otherID.toScriptValue(this);
1317 args << collisionToScriptValue(this, collision);1349 args << collisionToScriptValue(this, collision);
1318 callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args);1350 callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args);
1319 }1351 }
1320 }1352 }
1321}1353}