mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
sqlite: validate backup() source is a Database
backup() only checked that the source argument was a BaseObject before casting it to Database, so passing a Statement or Session caused a type confusion. Check against the Database constructor template instead. Signed-off-by: Guilherme Araújo <arauujogui@gmail.com> PR-URL: https://github.com/nodejs/node/pull/66797 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
This commit is contained in:
1 parent
c7ae7ab5b9
commit
e20da720c8
3 files changed
+73
-45
No files matched your search
@@ -451,6 +451,7 @@
|
|||||||
V(socketaddress_constructor_template, v8::FunctionTemplate) \
|
V(socketaddress_constructor_template, v8::FunctionTemplate) \
|
||||||
V(space_stats_template, v8::DictionaryTemplate) \
|
V(space_stats_template, v8::DictionaryTemplate) \
|
||||||
V(sqlite_column_template, v8::DictionaryTemplate) \
|
V(sqlite_column_template, v8::DictionaryTemplate) \
|
||||||
|
V(sqlite_database_constructor_template, v8::FunctionTemplate) \
|
||||||
V(sqlite_limits_template, v8::ObjectTemplate) \
|
V(sqlite_limits_template, v8::ObjectTemplate) \
|
||||||
V(sqlite_run_result_template, v8::DictionaryTemplate) \
|
V(sqlite_run_result_template, v8::DictionaryTemplate) \
|
||||||
V(sqlite_statement_sync_constructor_template, v8::FunctionTemplate) \
|
V(sqlite_statement_sync_constructor_template, v8::FunctionTemplate) \
|
||||||
|
|||||||
+55
-44
@@ -2909,9 +2909,11 @@ void Database::CreateSession(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
void Backup(const FunctionCallbackInfo<Value>& args) {
|
void Backup(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
if (args.Length() < 1 || !args[0]->IsObject()) {
|
if (!args[0]->IsObject() ||
|
||||||
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
|
!env->sqlite_database_constructor_template()->HasInstance(args[0])) {
|
||||||
"The \"sourceDb\" argument must be an object.");
|
THROW_ERR_INVALID_ARG_TYPE(
|
||||||
|
env->isolate(),
|
||||||
|
"The \"sourceDb\" argument must be an instance of Database.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5085,51 +5087,60 @@ static void Initialize(Local<Object> target,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Local<FunctionTemplate> db_tmpl = NewFunctionTemplate(isolate, Database::New);
|
|
||||||
db_tmpl->InstanceTemplate()->SetInternalFieldCount(
|
|
||||||
Database::kInternalFieldCount);
|
|
||||||
Local<Object> constants = Object::New(isolate);
|
Local<Object> constants = Object::New(isolate);
|
||||||
|
|
||||||
DefineConstants(constants);
|
DefineConstants(constants);
|
||||||
|
|
||||||
SetProtoMethod(isolate, db_tmpl, "open", Database::Open);
|
Local<FunctionTemplate> db_tmpl = env->sqlite_database_constructor_template();
|
||||||
SetProtoMethod(isolate, db_tmpl, "close", Database::Close);
|
if (db_tmpl.IsEmpty()) {
|
||||||
SetProtoDispose(isolate, db_tmpl, Database::Dispose);
|
db_tmpl = NewFunctionTemplate(isolate, Database::New);
|
||||||
SetProtoMethod(isolate, db_tmpl, "prepare", Database::Prepare);
|
db_tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "Database"));
|
||||||
SetProtoMethod(isolate, db_tmpl, "exec", Database::Exec);
|
db_tmpl->InstanceTemplate()->SetInternalFieldCount(
|
||||||
SetProtoMethod(isolate, db_tmpl, "function", Database::CustomFunction);
|
Database::kInternalFieldCount);
|
||||||
SetProtoMethod(isolate, db_tmpl, "createTagStore", Database::CreateTagStore);
|
SetProtoMethod(isolate, db_tmpl, "open", Database::Open);
|
||||||
SetProtoMethodNoSideEffect(isolate, db_tmpl, "location", Database::Location);
|
SetProtoMethod(isolate, db_tmpl, "close", Database::Close);
|
||||||
SetProtoMethod(isolate, db_tmpl, "aggregate", Database::AggregateFunction);
|
SetProtoDispose(isolate, db_tmpl, Database::Dispose);
|
||||||
SetProtoMethod(isolate, db_tmpl, "createSession", Database::CreateSession);
|
SetProtoMethod(isolate, db_tmpl, "prepare", Database::Prepare);
|
||||||
SetProtoMethod(isolate, db_tmpl, "applyChangeset", Database::ApplyChangeset);
|
SetProtoMethod(isolate, db_tmpl, "exec", Database::Exec);
|
||||||
SetProtoMethod(
|
SetProtoMethod(isolate, db_tmpl, "function", Database::CustomFunction);
|
||||||
isolate, db_tmpl, "enableLoadExtension", Database::EnableLoadExtension);
|
SetProtoMethod(
|
||||||
SetProtoMethod(
|
isolate, db_tmpl, "createTagStore", Database::CreateTagStore);
|
||||||
isolate, db_tmpl, "enableDefensive", Database::EnableDefensive);
|
SetProtoMethodNoSideEffect(
|
||||||
SetProtoMethod(isolate, db_tmpl, "loadExtension", Database::LoadExtension);
|
isolate, db_tmpl, "location", Database::Location);
|
||||||
SetProtoMethod(isolate, db_tmpl, "serialize", Database::Serialize);
|
SetProtoMethod(isolate, db_tmpl, "aggregate", Database::AggregateFunction);
|
||||||
SetProtoMethod(isolate, db_tmpl, "deserialize", Database::Deserialize);
|
SetProtoMethod(isolate, db_tmpl, "createSession", Database::CreateSession);
|
||||||
SetProtoMethod(isolate, db_tmpl, "setAuthorizer", Database::SetAuthorizer);
|
SetProtoMethod(
|
||||||
SetProtoMethod(isolate, db_tmpl, "createModule", Database::CreateModule);
|
isolate, db_tmpl, "applyChangeset", Database::ApplyChangeset);
|
||||||
SetSideEffectFreeGetter(isolate,
|
SetProtoMethod(
|
||||||
db_tmpl,
|
isolate, db_tmpl, "enableLoadExtension", Database::EnableLoadExtension);
|
||||||
FIXED_ONE_BYTE_STRING(isolate, "isOpen"),
|
SetProtoMethod(
|
||||||
Database::IsOpenGetter);
|
isolate, db_tmpl, "enableDefensive", Database::EnableDefensive);
|
||||||
SetSideEffectFreeGetter(isolate,
|
SetProtoMethod(isolate, db_tmpl, "loadExtension", Database::LoadExtension);
|
||||||
db_tmpl,
|
SetProtoMethod(isolate, db_tmpl, "serialize", Database::Serialize);
|
||||||
FIXED_ONE_BYTE_STRING(isolate, "isTransaction"),
|
SetProtoMethod(isolate, db_tmpl, "deserialize", Database::Deserialize);
|
||||||
Database::IsTransactionGetter);
|
SetProtoMethod(isolate, db_tmpl, "setAuthorizer", Database::SetAuthorizer);
|
||||||
SetSideEffectFreeGetter(
|
SetProtoMethod(isolate, db_tmpl, "createModule", Database::CreateModule);
|
||||||
isolate, db_tmpl, env->limits_string(), Database::LimitsGetter);
|
SetSideEffectFreeGetter(isolate,
|
||||||
Local<String> sqlite_type_key = FIXED_ONE_BYTE_STRING(isolate, "sqlite-type");
|
db_tmpl,
|
||||||
Local<v8::Symbol> sqlite_type_symbol =
|
FIXED_ONE_BYTE_STRING(isolate, "isOpen"),
|
||||||
v8::Symbol::For(isolate, sqlite_type_key);
|
Database::IsOpenGetter);
|
||||||
Local<String> database_sync_string =
|
SetSideEffectFreeGetter(isolate,
|
||||||
FIXED_ONE_BYTE_STRING(isolate, "node:sqlite");
|
db_tmpl,
|
||||||
db_tmpl->InstanceTemplate()->Set(sqlite_type_symbol, database_sync_string);
|
FIXED_ONE_BYTE_STRING(isolate, "isTransaction"),
|
||||||
|
Database::IsTransactionGetter);
|
||||||
SetConstructorFunction(context, target, "Database", db_tmpl);
|
SetSideEffectFreeGetter(
|
||||||
|
isolate, db_tmpl, env->limits_string(), Database::LimitsGetter);
|
||||||
|
Local<String> sqlite_type_key =
|
||||||
|
FIXED_ONE_BYTE_STRING(isolate, "sqlite-type");
|
||||||
|
Local<v8::Symbol> sqlite_type_symbol =
|
||||||
|
v8::Symbol::For(isolate, sqlite_type_key);
|
||||||
|
Local<String> database_sync_string =
|
||||||
|
FIXED_ONE_BYTE_STRING(isolate, "node:sqlite");
|
||||||
|
db_tmpl->InstanceTemplate()->Set(sqlite_type_symbol, database_sync_string);
|
||||||
|
env->set_sqlite_database_constructor_template(db_tmpl);
|
||||||
|
}
|
||||||
|
SetConstructorFunction(
|
||||||
|
context, target, "Database", db_tmpl, SetConstructorFunctionFlag::NONE);
|
||||||
SetConstructorFunction(context,
|
SetConstructorFunction(context,
|
||||||
target,
|
target,
|
||||||
"Statement",
|
"Statement",
|
||||||
|
|||||||
@@ -48,10 +48,26 @@ describe('backup()', () => {
|
|||||||
backup();
|
backup();
|
||||||
}, {
|
}, {
|
||||||
code: 'ERR_INVALID_ARG_TYPE',
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
message: 'The "sourceDb" argument must be an object.'
|
message: 'The "sourceDb" argument must be an instance of Database.'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('throws if the source is not an instance of Database', (t) => {
|
||||||
|
const database = makeSourceDb();
|
||||||
|
for (const source of [
|
||||||
|
{},
|
||||||
|
database.prepare('SELECT 1'),
|
||||||
|
database.createSession(),
|
||||||
|
]) {
|
||||||
|
t.assert.throws(() => {
|
||||||
|
backup(source, 'out.db');
|
||||||
|
}, {
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
|
message: 'The "sourceDb" argument must be an instance of Database.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('throws if path is not a string, URL, or Buffer', (t) => {
|
test('throws if path is not a string, URL, or Buffer', (t) => {
|
||||||
const database = makeSourceDb();
|
const database = makeSourceDb();
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user