|
1 | 1 | #include "node_sqlite.h"
|
| 2 | +#include <path.h> |
2 | 3 | #include "base_object-inl.h"
|
3 | 4 | #include "debug_utils-inl.h"
|
4 | 5 | #include "env-inl.h"
|
@@ -114,10 +115,13 @@ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, const char* message) {
|
114 | 115 | DatabaseSync::DatabaseSync(Environment* env,
|
115 | 116 | Local<Object> object,
|
116 | 117 | DatabaseOpenConfiguration&& open_config,
|
117 |
| - bool open) |
| 118 | + bool open, |
| 119 | + bool allow_load_extension) |
118 | 120 | : BaseObject(env, object), open_config_(std::move(open_config)) {
|
119 | 121 | MakeWeak();
|
120 | 122 | connection_ = nullptr;
|
| 123 | + allow_load_extension_ = allow_load_extension; |
| 124 | + enable_load_extension_ = allow_load_extension; |
121 | 125 |
|
122 | 126 | if (open) {
|
123 | 127 | Open();
|
@@ -182,6 +186,19 @@ bool DatabaseSync::Open() {
|
182 | 186 | CHECK_ERROR_OR_THROW(env()->isolate(), connection_, r, SQLITE_OK, false);
|
183 | 187 | CHECK_EQ(foreign_keys_enabled, open_config_.get_enable_foreign_keys());
|
184 | 188 |
|
| 189 | + 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 | + |
185 | 202 | return true;
|
186 | 203 | }
|
187 | 204 |
|
@@ -227,6 +244,7 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
|
227 | 244 | DatabaseOpenConfiguration open_config(std::move(location));
|
228 | 245 |
|
229 | 246 | bool open = true;
|
| 247 | + bool allow_load_extension = false; |
230 | 248 |
|
231 | 249 | if (args.Length() > 1) {
|
232 | 250 | if (!args[1]->IsObject()) {
|
@@ -302,9 +320,28 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
|
302 | 320 | }
|
303 | 321 | open_config.set_enable_dqs(enable_dqs_v.As<Boolean>()->Value());
|
304 | 322 | }
|
| 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 | + } |
305 | 341 | }
|
306 | 342 |
|
307 |
| - 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); |
308 | 345 | }
|
309 | 346 |
|
310 | 347 | void DatabaseSync::Open(const FunctionCallbackInfo<Value>& args) {
|
@@ -526,6 +563,70 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
|
526 | 563 | args.GetReturnValue().Set(true);
|
527 | 564 | }
|
528 | 565 |
|
| 566 | +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 | + |
529 | 630 | StatementSync::StatementSync(Environment* env,
|
530 | 631 | Local<Object> object,
|
531 | 632 | DatabaseSync* db,
|
@@ -1312,6 +1413,12 @@ static void Initialize(Local<Object> target,
|
1312 | 1413 | isolate, db_tmpl, "createSession", DatabaseSync::CreateSession);
|
1313 | 1414 | SetProtoMethod(
|
1314 | 1415 | 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); |
1315 | 1422 | SetConstructorFunction(context, target, "DatabaseSync", db_tmpl);
|
1316 | 1423 | SetConstructorFunction(context,
|
1317 | 1424 | target,
|
|
0 commit comments