#pragma once #include #include #include #include #include #include #include #ifdef _WIN32 #include #else #include #endif #include namespace workerd::api { // A special binding object that allows for dynamic evaluation. class UnsafeEval: public jsg::Object { public: UnsafeEval() = default; UnsafeEval(jsg::Lock&, const jsg::Url&) {} // A non-capturing eval. Compile and evaluates the given script, returning whatever // value is returned by the script. This version of eval intentionally does not // capture any part of the outer scope other than globalThis and globally scoped // variables. The optional `name` will appear in stack traces for any errors thrown. // // console.log(env.unsafe.eval('1 + 1')); // prints 2 // jsg::JsValue eval(jsg::Lock& js, kj::String script, jsg::Optional name); using UnsafeEvalFunction = jsg::Function)>; // Compiles and returns a new Function using the given script. The function does not // capture any part of the outer scope other than globalThis and globally scoped // variables. The optional `name` will be set as the name of the function and will // appear in stack traces for any errors thrown. An optional list of argument names // can be passed in. // // const fn = env.unsafe.newFunction('return m', 'foo', 'm'); // console.log(fn(1)); // prints 1 // UnsafeEvalFunction newFunction(jsg::Lock& js, jsg::JsString script, jsg::Optional name, jsg::Arguments> args, const jsg::TypeHandler& handler); // Compiles and returns a new Async Function using the given script. The function // does not capture any part of the outer scope other than globalThis and globally // scoped variables. The optional `name` will be set as the name of the function // and will appear in stack traces for any errors thrown. An optional list of // arguments names can be passed in. If your function needs to use the await // key, use this instead of newFunction. UnsafeEvalFunction newAsyncFunction(jsg::Lock& js, jsg::JsString script, jsg::Optional name, jsg::Arguments> args, const jsg::TypeHandler& handler); jsg::JsValue newWasmModule(jsg::Lock& js, kj::Array src); JSG_RESOURCE_TYPE(UnsafeEval) { JSG_METHOD(eval); JSG_METHOD(newFunction); JSG_METHOD(newAsyncFunction); JSG_METHOD(newWasmModule); } }; // A special binding that allows access to stdin. Used for REPL. class Stdin: public jsg::Object { public: Stdin() = default; void reprl(jsg::Lock& js); kj::String getline(jsg::Lock& js) { std::string res; std::getline(std::cin, res); return kj::heapString(res.c_str()); } JSG_RESOURCE_TYPE(Stdin) { JSG_METHOD(getline); #ifdef WORKERD_FUZZILLI JSG_METHOD(reprl); #endif } }; class UnsafeModule: public jsg::Object { public: UnsafeModule() = default; UnsafeModule(jsg::Lock&, const jsg::Url&) {} jsg::Promise abortAllDurableObjects(jsg::Lock& js); // Like abortAllDurableObjects(), but also deletes storage and cancels alarms so DOs // restart with clean state. Namespaces with preventEviction are not affected. jsg::Promise deleteAllDurableObjects(jsg::Lock& js); // Returns true if the TEST_WORKERD autogate is enabled. // This is used to verify that the all-autogates test variant is working correctly. bool isTestAutogateEnabled(); JSG_RESOURCE_TYPE(UnsafeModule) { JSG_METHOD(abortAllDurableObjects); JSG_METHOD(deleteAllDurableObjects); JSG_METHOD(isTestAutogateEnabled); } }; #ifdef WORKERD_FUZZILLI // Fuzzilli fuzzing support for triggering crashes and printing debug output class Fuzzilli: public jsg::Object { public: Fuzzilli() = default; Fuzzilli(jsg::Lock&, const jsg::Url&) {} // Fuzzilli function for triggering crashes or printing debug output // fuzzilli('FUZZILLI_CRASH', type: number): Triggers a crash based on type // fuzzilli('FUZZILLI_PRINT', message: string): Prints message to fuzzer output void fuzzilli(jsg::Lock& js, jsg::Arguments args); JSG_RESOURCE_TYPE(Fuzzilli) { JSG_METHOD(fuzzilli); } }; #endif template void registerUnsafeModule(Registry& registry) { registry.template addBuiltinModule( "workerd:unsafe", workerd::jsg::ModuleRegistry::Type::BUILTIN); registry.template addBuiltinModule( "workerd:unsafe-eval", workerd::jsg::ModuleRegistry::Type::BUILTIN); } #ifdef WORKERD_FUZZILLI #define EW_UNSAFE_ISOLATE_TYPES api::UnsafeEval, api::UnsafeModule, api::Stdin, api::Fuzzilli #else #define EW_UNSAFE_ISOLATE_TYPES api::UnsafeEval, api::UnsafeModule, api::Stdin #endif template void registerUnsafeModules(Registry& registry, auto featureFlags) { registry.template addBuiltinModule( "internal:unsafe-eval", workerd::jsg::ModuleRegistry::Type::INTERNAL); #ifdef WORKERD_FUZZILLI registry.template addBuiltinModule( "workerd:stdin", workerd::jsg::ModuleRegistry::Type::BUILTIN); if (featureFlags.getWorkerdExperimental()) { registry.template addBuiltinModule( "workerd:fuzzilli", workerd::jsg::ModuleRegistry::Type::BUILTIN); } #endif } template kj::Own getInternalUnsafeModuleBundle(auto featureFlags) { jsg::modules::ModuleBundle::BuiltinBuilder builder( jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN_ONLY); static const auto kSpecifier = "internal:unsafe-eval"_url; builder.addObject(kSpecifier); return builder.finish(); } template kj::Own getExternalUnsafeModuleBundle(auto featureFlags) { jsg::modules::ModuleBundle::BuiltinBuilder builder( jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN); static const auto kSpecifier = "workerd:unsafe-eval"_url; builder.addObject(kSpecifier); static const auto kUnsafeSpecifier = "workerd:unsafe"_url; builder.addObject(kUnsafeSpecifier); #ifdef WORKERD_FUZZILLI { static const auto kStdinSpecifier = "workerd:stdin"_url; builder.addSynthetic(kStdinSpecifier, jsg::modules::Module::newJsgObjectModuleHandler( [](jsg::Lock& js) { return js.alloc(); })); } if (featureFlags.getWorkerdExperimental()) { static const auto kFuzzilliSpecifier = "workerd:fuzzilli"_url; builder.addSynthetic(kFuzzilliSpecifier, jsg::modules::Module::newJsgObjectModuleHandler( [](jsg::Lock& js) { return js.alloc(); })); } #endif return builder.finish(); } } // namespace workerd::api