sqlite: support `db.loadExtension` · nodejs/node@53cc0cc
11#include "node_sqlite.h"
2+#include <path.h>
23#include "base_object-inl.h"
34#include "debug_utils-inl.h"
45#include "env-inl.h"
@@ -114,10 +115,13 @@ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, const char* message) {
114115DatabaseSync::DatabaseSync(Environment* env,
115116 Local<Object> object,
116117 DatabaseOpenConfiguration&& open_config,
117-bool open)
118+bool open,
119+bool allow_load_extension)
118120 : BaseObject(env, object), open_config_(std::move(open_config)) {
119121MakeWeak();
120122 connection_ = nullptr;
123+ allow_load_extension_ = allow_load_extension;
124+ enable_load_extension_ = allow_load_extension;
121125122126if (open) {
123127Open();
@@ -182,6 +186,19 @@ bool DatabaseSync::Open() {
182186CHECK_ERROR_OR_THROW(env()->isolate(), connection_, r, SQLITE_OK, false);
183187CHECK_EQ(foreign_keys_enabled, open_config_.get_enable_foreign_keys());
184188189+if (allow_load_extension_) {
190+if (env()->permission()->enabled()) [[unlikely]] {
191+THROW_ERR_LOAD_SQLITE_EXTENSION(env(),
192+"Cannot load SQLite extensions when the "
193+"permission model is enabled.");
194+return false;
195+ }
196+const int load_extension_ret = sqlite3_db_config(
197+ connection_, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, nullptr);
198+CHECK_ERROR_OR_THROW(
199+env()->isolate(), connection_, load_extension_ret, SQLITE_OK, false);
200+ }
201+185202return true;
186203}
187204@@ -227,6 +244,7 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
227244 DatabaseOpenConfiguration open_config(std::move(location));
228245229246bool open = true;
247+bool allow_load_extension = false;
230248231249if (args.Length() > 1) {
232250if (!args[1]->IsObject()) {
@@ -302,9 +320,28 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
302320 }
303321 open_config.set_enable_dqs(enable_dqs_v.As<Boolean>()->Value());
304322 }
323+324+ Local<String> allow_extension_string =
325+FIXED_ONE_BYTE_STRING(env->isolate(), "allowExtension");
326+ Local<Value> allow_extension_v;
327+if (!options->Get(env->context(), allow_extension_string)
328+ .ToLocal(&allow_extension_v)) {
329+return;
330+ }
331+332+if (!allow_extension_v->IsUndefined()) {
333+if (!allow_extension_v->IsBoolean()) {
334+THROW_ERR_INVALID_ARG_TYPE(
335+ env->isolate(),
336+"The \"options.allowExtension\" argument must be a boolean.");
337+return;
338+ }
339+ allow_load_extension = allow_extension_v.As<Boolean>()->Value();
340+ }
305341 }
306342307-new DatabaseSync(env, args.This(), std::move(open_config), open);
343+new DatabaseSync(
344+ env, args.This(), std::move(open_config), open, allow_load_extension);
308345}
309346310347void DatabaseSync::Open(const FunctionCallbackInfo<Value>& args) {
@@ -526,6 +563,70 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
526563 args.GetReturnValue().Set(true);
527564}
528565566+void DatabaseSync::EnableLoadExtension(
567+const FunctionCallbackInfo<Value>& args) {
568+ DatabaseSync* db;
569+ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
570+ Environment* env = Environment::GetCurrent(args);
571+if (!args[0]->IsBoolean()) {
572+THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
573+"The \"allow\" argument must be a boolean.");
574+return;
575+ }
576+577+const int enable = args[0].As<Boolean>()->Value();
578+auto isolate = env->isolate();
579+580+if (db->allow_load_extension_ == false && enable == true) {
581+THROW_ERR_INVALID_STATE(
582+ isolate,
583+"Cannot enable extension loading because it was disabled at database "
584+"creation.");
585+return;
586+ }
587+ db->enable_load_extension_ = enable;
588+const int load_extension_ret = sqlite3_db_config(
589+ db->connection_, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, enable, nullptr);
590+CHECK_ERROR_OR_THROW(
591+ isolate, db->connection_, load_extension_ret, SQLITE_OK, void());
592+}
593+594+void DatabaseSync::LoadExtension(const FunctionCallbackInfo<Value>& args) {
595+ DatabaseSync* db;
596+ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
597+ Environment* env = Environment::GetCurrent(args);
598+THROW_AND_RETURN_ON_BAD_STATE(
599+ env, db->connection_ == nullptr, "database is not open");
600+THROW_AND_RETURN_ON_BAD_STATE(
601+ env, !db->allow_load_extension_, "extension loading is not allowed");
602+THROW_AND_RETURN_ON_BAD_STATE(
603+ env, !db->enable_load_extension_, "extension loading is not allowed");
604+605+if (!args[0]->IsString()) {
606+THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
607+"The \"path\" argument must be a string.");
608+return;
609+ }
610+611+auto isolate = env->isolate();
612+613+ BufferValue path(isolate, args[0]);
614+ BufferValue entryPoint(isolate, args[1]);
615+CHECK_NOT_NULL(*path);
616+ToNamespacedPath(env, &path);
617+if (*entryPoint == nullptr) {
618+ToNamespacedPath(env, &entryPoint);
619+ }
620+THROW_IF_INSUFFICIENT_PERMISSIONS(
621+ env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
622+char* errmsg = nullptr;
623+const int r =
624+sqlite3_load_extension(db->connection_, *path, *entryPoint, &errmsg);
625+if (r != SQLITE_OK) {
626+ isolate->ThrowException(ERR_LOAD_SQLITE_EXTENSION(isolate, errmsg));
627+ }
628+}
629+529630StatementSync::StatementSync(Environment* env,
530631 Local<Object> object,
531632 DatabaseSync* db,
@@ -1312,6 +1413,12 @@ static void Initialize(Local<Object> target,
13121413 isolate, db_tmpl, "createSession", DatabaseSync::CreateSession);
13131414SetProtoMethod(
13141415 isolate, db_tmpl, "applyChangeset", DatabaseSync::ApplyChangeset);
1416+SetProtoMethod(isolate,
1417+ db_tmpl,
1418+"enableLoadExtension",
1419+ DatabaseSync::EnableLoadExtension);
1420+SetProtoMethod(
1421+ isolate, db_tmpl, "loadExtension", DatabaseSync::LoadExtension);
13151422SetConstructorFunction(context, target, "DatabaseSync", db_tmpl);
13161423SetConstructorFunction(context,
13171424 target,