Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 2 files). Show all
Unified · Split
| @@ -578,7 +578,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 577 unmodified lines | ||
| 578 | 578 | _registeredHandlers[entityID] = RegisteredEventHandlers(); |
| 579 | 579 | } |
| 580 | 580 | CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName]; |
| 581 | − CallbackData handlerData = {handler, currentEntityIdentifier}; | |
| 581 | + CallbackData handlerData = {handler, currentEntityIdentifier, currentSandboxURL}; | |
| 582 | 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 | 796 | // call the associated JS function, if it exists |
| 797 | 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 | 810 | // make sure the timer stops when the script does |
| 811 | 811 | connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); |
| 812 | 812 | |
| 813 | − CallbackData timerData = {function, currentEntityIdentifier}; | |
| 813 | + CallbackData timerData = {function, currentEntityIdentifier, currentSandboxURL}; | |
| 814 | 814 | _timerFunctionMap.insert(newTimer, timerData); |
| 815 | 815 | |
| 816 | 816 | newTimer->start(intervalMS); |
| @@ -885,19 +885,46 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 68 unmodified lines | ||
| 885 | 885 | return; // bail early |
| 886 | 886 | } |
| 887 | 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 | 901 | for (QString file : includeFiles) { |
| 889 | 902 | QUrl thisURL { resolvePath(file) }; |
| 890 | 903 | if (!_includedURLs.contains(thisURL)) { |
| 891 | − urls.append(thisURL); | |
| 892 | − _includedURLs << thisURL; | |
| 893 | − } | |
| 894 | − else { | |
| 904 | + if (!currentSandboxURL.isEmpty() && (thisURL.scheme() == "file") && | |
| 905 | + ( | |
| 906 | + (currentSandboxURL.scheme() != "file") || | |
| 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 | 921 | qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL; |
| 896 | 922 | } |
| 897 | 923 | } |
| 898 | 924 | |
| 899 | 925 | BatchLoader* loader = new BatchLoader(urls); |
| 900 | 926 | EntityItemID capturedEntityIdentifier = currentEntityIdentifier; |
| 927 | + QUrl capturedSandboxURL = currentSandboxURL; | |
| 901 | 928 | |
| 902 | 929 | auto evaluateScripts = [=](const QMap<QUrl, QString>& data) { |
| 903 | 930 | auto parentURL = _parentURL; |
| @@ -912,13 +939,13 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 8 unmodified lines | ||
| 912 | 939 | auto operation = [&]() { |
| 913 | 940 | evaluate(contents, url.toString()); |
| 914 | 941 | }; |
| 915 | − doWithEnvironment(capturedEntityIdentifier, operation); | |
| 942 | + doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation); | |
| 916 | 943 | } |
| 917 | 944 | } |
| 918 | 945 | _parentURL = parentURL; |
| 919 | 946 | |
| 920 | 947 | if (callback.isFunction()) { |
| 921 | − callWithEnvironment(capturedEntityIdentifier, QScriptValue(callback), QScriptValue(), QScriptValueList()); | |
| 948 | + callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, QScriptValue(callback), QScriptValue(), QScriptValueList()); | |
| 922 | 949 | } |
| 923 | 950 | |
| 924 | 951 | loader->deleteLater(); |
| @@ -996,10 +1023,11 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin · 71 unmodified lines | ||
| 996 | 1023 | CallbackList handlersForEvent = handlersOnEntity[eventName]; |
| 997 | 1024 | if (!handlersForEvent.isEmpty()) { |
| 998 | 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 | 1027 | // and the entity scripts may be for entities other than the one this is a handler for. |
| 1001 | 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 | 1134 | lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch(); |
| 1107 | 1135 | } |
| 1108 | 1136 | QScriptValue entityScriptConstructor, entityScriptObject; |
| 1137 | + QUrl sandboxURL = currentSandboxURL.isEmpty() ? scriptOrURL : currentSandboxURL; | |
| 1109 | 1138 | auto initialization = [&]{ |
| 1110 | 1139 | entityScriptConstructor = evaluate(contents, fileName); |
| 1111 | 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 | 1145 | _entityScripts[entityID] = newDetails; |
| 1117 | 1146 | if (isURL) { |
| 1118 | 1147 | setParentURL(""); |
| @@ -1201,9 +1230,11 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 82 unmodified lines | ||
| 1201 | 1230 | // Even if entityID is supplied as currentEntityIdentifier, this still documents the source |
| 1202 | 1231 | // of the code being executed (e.g., if we ever sandbox different entity scripts, or provide different |
| 1203 | 1232 | // global values for different entity scripts). |
| 1204 | −void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, std::function<void()> operation) { | |
| 1233 | +void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function<void()> operation) { | |
| 1205 | 1234 | EntityItemID oldIdentifier = currentEntityIdentifier; |
| 1235 | + QUrl oldSandboxURL = currentSandboxURL; | |
| 1206 | 1236 | currentEntityIdentifier = entityID; |
| 1237 | + currentSandboxURL = sandboxURL; | |
| 1207 | 1238 | |
| 1208 | 1239 | #if DEBUG_CURRENT_ENTITY |
| 1209 | 1240 | QScriptValue oldData = this->globalObject().property("debugEntityID"); |
| @@ -1215,12 +1246,13 @@ void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, std::function · 5 unmodified lines | ||
| 1215 | 1246 | #endif |
| 1216 | 1247 | |
| 1217 | 1248 | currentEntityIdentifier = oldIdentifier; |
| 1249 | + currentSandboxURL = oldSandboxURL; | |
| 1218 | 1250 | } |
| 1219 | −void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, QScriptValue function, QScriptValue thisObject, QScriptValueList args) { | |
| 1251 | +void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args) { | |
| 1220 | 1252 | auto operation = [&]() { |
| 1221 | 1253 | function.call(thisObject, args); |
| 1222 | 1254 | }; |
| 1223 | − doWithEnvironment(entityID, operation); | |
| 1255 | + doWithEnvironment(entityID, sandboxURL, operation); | |
| 1224 | 1256 | } |
| 1225 | 1257 | |
| 1226 | 1258 | void 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 | 1281 | QScriptValueList args; |
| 1250 | 1282 | args << entityID.toScriptValue(this); |
| 1251 | 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 | 1313 | QScriptValueList args; |
| 1282 | 1314 | args << entityID.toScriptValue(this); |
| 1283 | 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 | 1347 | args << entityID.toScriptValue(this); |
| 1316 | 1348 | args << otherID.toScriptValue(this); |
| 1317 | 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 | } |