| @@ -3,8 +3,8 @@ | |||||
| #include <iostream> | #include <iostream> | ||||
| #include <fstream> | #include <fstream> | ||||
| #include <sstream> | #include <sstream> | ||||
| #include <mutex> | |||||
| #include <thread> | #include <thread> | ||||
| #include <mutex> | |||||
| #include "ScriptEngine.hpp" | #include "ScriptEngine.hpp" | ||||
| #include <efsw/efsw.h> | #include <efsw/efsw.h> | ||||
| @@ -13,6 +13,11 @@ using namespace rack; | |||||
| Plugin* pluginInstance; | Plugin* pluginInstance; | ||||
| // Global warning message for script security | |||||
| bool securityRequested = false; | |||||
| bool securityAccepted = false; | |||||
| struct Prototype : Module { | struct Prototype : Module { | ||||
| enum ParamIds { | enum ParamIds { | ||||
| ENUMS(KNOB_PARAMS, NUM_ROWS), | ENUMS(KNOB_PARAMS, NUM_ROWS), | ||||
| @@ -36,6 +41,8 @@ struct Prototype : Module { | |||||
| std::string message; | std::string message; | ||||
| std::string path; | std::string path; | ||||
| std::string script; | std::string script; | ||||
| /** Script that has not yet been approved to load */ | |||||
| std::string securityScript; | |||||
| std::string engineName; | std::string engineName; | ||||
| std::mutex scriptMutex; | std::mutex scriptMutex; | ||||
| ScriptEngine* scriptEngine = NULL; | ScriptEngine* scriptEngine = NULL; | ||||
| @@ -72,6 +79,12 @@ struct Prototype : Module { | |||||
| return; | return; | ||||
| frame = 0; | frame = 0; | ||||
| // Load security-sandboxed script if the security warning message is accepted. | |||||
| if (securityScript != "" && securityAccepted) { | |||||
| setScript(securityScript); | |||||
| securityScript = ""; | |||||
| } | |||||
| // Inputs | // Inputs | ||||
| for (int i = 0; i < NUM_ROWS; i++) | for (int i = 0; i < NUM_ROWS; i++) | ||||
| block->inputs[i][bufferIndex] = inputs[IN_INPUTS + i].getVoltage(); | block->inputs[i][bufferIndex] = inputs[IN_INPUTS + i].getVoltage(); | ||||
| @@ -94,8 +107,8 @@ struct Prototype : Module { | |||||
| // Run ScriptEngine's process function | // Run ScriptEngine's process function | ||||
| { | { | ||||
| // Process buffer | |||||
| std::lock_guard<std::mutex> lock(scriptMutex); | std::lock_guard<std::mutex> lock(scriptMutex); | ||||
| // Check for certain inside the mutex | |||||
| if (scriptEngine) { | if (scriptEngine) { | ||||
| if (scriptEngine->process()) { | if (scriptEngine->process()) { | ||||
| WARN("Script %s process() failed. Stopped script.", path.c_str()); | WARN("Script %s process() failed. Stopped script.", path.c_str()); | ||||
| @@ -229,6 +242,11 @@ struct Prototype : Module { | |||||
| json_t* rootJ = json_object(); | json_t* rootJ = json_object(); | ||||
| json_object_set_new(rootJ, "path", json_string(path.c_str())); | json_object_set_new(rootJ, "path", json_string(path.c_str())); | ||||
| std::string script = this->script; | |||||
| // If we haven't accepted the security of this script, serialize the security-sandboxed script anyway. | |||||
| if (script == "") | |||||
| script = securityScript; | |||||
| json_object_set_new(rootJ, "script", json_stringn(script.data(), script.size())); | json_object_set_new(rootJ, "script", json_stringn(script.data(), script.size())); | ||||
| return rootJ; | return rootJ; | ||||
| @@ -247,7 +265,13 @@ struct Prototype : Module { | |||||
| json_t* scriptJ = json_object_get(rootJ, "script"); | json_t* scriptJ = json_object_get(rootJ, "script"); | ||||
| if (scriptJ) { | if (scriptJ) { | ||||
| std::string script = std::string(json_string_value(scriptJ), json_string_length(scriptJ)); | std::string script = std::string(json_string_value(scriptJ), json_string_length(scriptJ)); | ||||
| setScript(script); | |||||
| if (script != "") { | |||||
| // Request security warning message | |||||
| if (!securityAccepted) { | |||||
| securityRequested = true; | |||||
| } | |||||
| securityScript = script; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -481,6 +505,16 @@ struct PrototypeWidget : ModuleWidget { | |||||
| module->setPath(e.paths[0]); | module->setPath(e.paths[0]); | ||||
| } | } | ||||
| } | } | ||||
| void step() override { | |||||
| if (securityRequested) { | |||||
| if (osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, "VCV Prototype is about to load a script from a patch or module preset. Running Prototype scripts from untrusted sources may compromise your computer and personal information. Proceed and don't display this message again?")) { | |||||
| securityAccepted = true; | |||||
| } | |||||
| securityRequested = false; | |||||
| } | |||||
| ModuleWidget::step(); | |||||
| } | |||||
| }; | }; | ||||
| void init(Plugin* p) { | void init(Plugin* p) { | ||||