Skip to content

Commit 114df4d

Browse files
committed
test: test null bytes for String and Buffer
1 parent b9ec8bc commit 114df4d

File tree

3 files changed

+61
-19
lines changed

3 files changed

+61
-19
lines changed

src/node_sqlite.cc

+16-10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "node.h"
88
#include "node_errors.h"
99
#include "node_mem-inl.h"
10+
#include "node_url.h"
1011
#include "sqlite3.h"
1112
#include "threadpoolwork-inl.h"
1213
#include "util-inl.h"
@@ -592,8 +593,15 @@ bool DatabaseSync::ShouldIgnoreSQLiteError() {
592593
std::optional<std::string> ValidateDatabasePath(Environment* env,
593594
Local<Value> path,
594595
const std::string& field_name) {
596+
auto has_null_bytes = [](const std::string& str) {
597+
return str.find('\0') != std::string::npos;
598+
};
599+
std::string location;
595600
if (path->IsString()) {
596-
return Utf8Value(env->isolate(), path.As<String>()).ToString();
601+
location = Utf8Value(env->isolate(), path.As<String>()).ToString();
602+
if (!has_null_bytes(location)) {
603+
return location;
604+
}
597605
}
598606

599607
if (path->IsUint8Array()) {
@@ -623,14 +631,12 @@ std::optional<std::string> ValidateDatabasePath(Environment* env,
623631
href->IsString() &&
624632
url->Get(env->context(), env->protocol_string()).ToLocal(&protocol) &&
625633
protocol->IsString()) {
626-
std::string url_protocol =
627-
Utf8Value(env->isolate(), protocol.As<String>()).ToString();
628-
if (url_protocol != "" && url_protocol != "file:") {
629-
THROW_ERR_INVALID_URL_SCHEME(env->isolate());
630-
return std::nullopt;
634+
location = Utf8Value(env->isolate(), href.As<String>()).ToString();
635+
if (!has_null_bytes(location)) {
636+
auto file_url = ada::parse(location);
637+
CHECK(file_url);
638+
return url::FileURLToPath(env, *file_url);
631639
}
632-
633-
return Utf8Value(env->isolate(), href.As<String>()).ToString();
634640
}
635641
}
636642

@@ -1130,9 +1136,9 @@ void Backup(const FunctionCallbackInfo<Value>& args) {
11301136
BackupJob* job = new BackupJob(env,
11311137
db,
11321138
resolver,
1133-
source_db,
1139+
std::move(source_db),
11341140
dest_path.value(),
1135-
dest_db,
1141+
std::move(dest_db),
11361142
rate,
11371143
progressFunc);
11381144
db->AddBackup(job);

test/parallel/test-sqlite-backup.mjs

+26-8
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,24 @@ describe('backup()', () => {
6161
});
6262
});
6363

64+
test('throws if the database destination contains null bytes', (t) => {
65+
const database = makeSourceDb();
66+
67+
t.assert.throws(() => {
68+
backup(database, Buffer.from('l\0cation'));
69+
}, {
70+
code: 'ERR_INVALID_ARG_TYPE',
71+
message: 'The "destination" argument must be a string, Uint8Array, or URL without null bytes.'
72+
});
73+
74+
t.assert.throws(() => {
75+
backup(database, 'l\0cation');
76+
}, {
77+
code: 'ERR_INVALID_ARG_TYPE',
78+
message: 'The "destination" argument must be a string, Uint8Array, or URL without null bytes.'
79+
});
80+
});
81+
6482
test('throws if options is not an object', (t) => {
6583
const database = makeSourceDb();
6684

@@ -146,14 +164,14 @@ test('backup database using location as URL', async (t) => {
146164
const database = makeSourceDb();
147165
const destDb = pathToFileURL(nextDb());
148166

149-
t.after(() => {
150-
database.close();
151-
backupDb.close();
152-
});
167+
t.after(() => { database.close(); });
153168

154169
await backup(database, destDb);
155170

156171
const backupDb = new DatabaseSync(destDb);
172+
173+
t.after(() => { backupDb.close(); });
174+
157175
const rows = backupDb.prepare('SELECT * FROM data').all();
158176

159177
t.assert.deepStrictEqual(rows, [
@@ -166,14 +184,14 @@ test('backup database using location as Buffer', async (t) => {
166184
const database = makeSourceDb();
167185
const destDb = Buffer.from(nextDb());
168186

169-
t.after(() => {
170-
database.close();
171-
backupDb.close();
172-
});
187+
t.after(() => { database.close(); });
173188

174189
await backup(database, destDb);
175190

176191
const backupDb = new DatabaseSync(destDb);
192+
193+
t.after(() => { backupDb.close(); });
194+
177195
const rows = backupDb.prepare('SELECT * FROM data').all();
178196

179197
t.assert.deepStrictEqual(rows, [

test/parallel/test-sqlite-database-sync.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ suite('DatabaseSync() constructor', () => {
2323
});
2424
});
2525

26-
test('throws if database path is not a string', (t) => {
26+
test('throws if database path is not a string, Uint8Array, or URL', (t) => {
2727
t.assert.throws(() => {
2828
new DatabaseSync();
2929
}, {
@@ -32,6 +32,24 @@ suite('DatabaseSync() constructor', () => {
3232
});
3333
});
3434

35+
test('throws if the database location as Buffer contains null bytes', (t) => {
36+
t.assert.throws(() => {
37+
new DatabaseSync(Buffer.from('l\0cation'));
38+
}, {
39+
code: 'ERR_INVALID_ARG_TYPE',
40+
message: 'The "path" argument must be a string, Uint8Array, or URL without null bytes.',
41+
});
42+
});
43+
44+
test('throws if the database location as string contains null bytes', (t) => {
45+
t.assert.throws(() => {
46+
new DatabaseSync('l\0cation');
47+
}, {
48+
code: 'ERR_INVALID_ARG_TYPE',
49+
message: 'The "path" argument must be a string, Uint8Array, or URL without null bytes.',
50+
});
51+
});
52+
3553
test('throws if options is provided but is not an object', (t) => {
3654
t.assert.throws(() => {
3755
new DatabaseSync('foo', null);

0 commit comments

Comments
 (0)