◐ Shell
clean mode source ↗

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) {

114115

DatabaseSync::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)) {

119121

MakeWeak();

120122

connection_ = nullptr;

123+

allow_load_extension_ = allow_load_extension;

124+

enable_load_extension_ = allow_load_extension;

121125122126

if (open) {

123127

Open();

@@ -182,6 +186,19 @@ bool DatabaseSync::Open() {

182186

CHECK_ERROR_OR_THROW(env()->isolate(), connection_, r, SQLITE_OK, false);

183187

CHECK_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+185202

return true;

186203

}

187204

@@ -227,6 +244,7 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {

227244

DatabaseOpenConfiguration open_config(std::move(location));

228245229246

bool open = true;

247+

bool allow_load_extension = false;

230248231249

if (args.Length() > 1) {

232250

if (!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

}

309346310347

void 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+529630

StatementSync::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);

13131414

SetProtoMethod(

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);

13151422

SetConstructorFunction(context, target, "DatabaseSync", db_tmpl);

13161423

SetConstructorFunction(context,

13171424

target,