@bytebase/dbhub 0.4.1 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -5
- package/dist/index.js +61 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,7 +113,7 @@ docker run --rm --init \
|
|
|
113
113
|
|
|
114
114
|
```bash
|
|
115
115
|
# PostgreSQL example
|
|
116
|
-
npx @bytebase/dbhub --transport sse --port 8080 --dsn "postgres://user:password@localhost:5432/dbname"
|
|
116
|
+
npx @bytebase/dbhub --transport sse --port 8080 --dsn "postgres://user:password@localhost:5432/dbname?sslmode=disable"
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
```bash
|
|
@@ -175,6 +175,38 @@ npx @bytebase/dbhub --transport sse --port 8080 --demo
|
|
|
175
175
|
|
|
176
176
|
## Usage
|
|
177
177
|
|
|
178
|
+
### SSL Connections
|
|
179
|
+
|
|
180
|
+
You can specify the SSL mode using the `sslmode` parameter in your DSN string:
|
|
181
|
+
|
|
182
|
+
| Database | `sslmode=disable` | `sslmode=require` | Default SSL Behavior |
|
|
183
|
+
|------------|:----------------:|:----------------:|:-------------------:|
|
|
184
|
+
| PostgreSQL | ✅ | ✅ | Certificate verification |
|
|
185
|
+
| MySQL | ✅ | ✅ | Certificate verification |
|
|
186
|
+
| MariaDB | ✅ | ✅ | Certificate verification |
|
|
187
|
+
| SQL Server | ✅ | ✅ | Certificate verification |
|
|
188
|
+
| Oracle | ✅ | ✅ | N/A (use Oracle client config) |
|
|
189
|
+
| SQLite | ❌ | ❌ | N/A (file-based) |
|
|
190
|
+
|
|
191
|
+
**SSL Mode Options:**
|
|
192
|
+
|
|
193
|
+
- `sslmode=disable`: All SSL/TLS encryption is turned off. Data is transmitted in plaintext.
|
|
194
|
+
- `sslmode=require`: Connection is encrypted, but the server's certificate is not verified. This provides protection against packet sniffing but not against man-in-the-middle attacks. You may use this for trusted self-signed CA.
|
|
195
|
+
|
|
196
|
+
Without specifying `sslmode`, most databases default to certificate verification, which provides the highest level of security.
|
|
197
|
+
|
|
198
|
+
Example usage:
|
|
199
|
+
```bash
|
|
200
|
+
# Disable SSL
|
|
201
|
+
postgres://user:password@localhost:5432/dbname?sslmode=disable
|
|
202
|
+
|
|
203
|
+
# Require SSL without certificate verification
|
|
204
|
+
postgres://user:password@localhost:5432/dbname?sslmode=require
|
|
205
|
+
|
|
206
|
+
# Standard SSL with certificate verification (default)
|
|
207
|
+
postgres://user:password@localhost:5432/dbname
|
|
208
|
+
```
|
|
209
|
+
|
|
178
210
|
### Read-only Mode
|
|
179
211
|
|
|
180
212
|
You can run DBHub in read-only mode, which restricts SQL query execution to read-only operations:
|
|
@@ -225,12 +257,12 @@ DBHub supports the following database connection string formats:
|
|
|
225
257
|
|
|
226
258
|
| Database | DSN Format | Example |
|
|
227
259
|
| ---------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
228
|
-
| MySQL | `mysql://[user]:[password]@[host]:[port]/[database]` | `mysql://user:password@localhost:3306/dbname` |
|
|
229
|
-
| MariaDB | `mariadb://[user]:[password]@[host]:[port]/[database]` | `mariadb://user:password@localhost:3306/dbname` |
|
|
260
|
+
| MySQL | `mysql://[user]:[password]@[host]:[port]/[database]` | `mysql://user:password@localhost:3306/dbname?sslmode=disable` |
|
|
261
|
+
| MariaDB | `mariadb://[user]:[password]@[host]:[port]/[database]` | `mariadb://user:password@localhost:3306/dbname?sslmode=disable` |
|
|
230
262
|
| PostgreSQL | `postgres://[user]:[password]@[host]:[port]/[database]` | `postgres://user:password@localhost:5432/dbname?sslmode=disable` |
|
|
231
|
-
| SQL Server | `sqlserver://[user]:[password]@[host]:[port]/[database]` | `sqlserver://user:password@localhost:1433/dbname`
|
|
263
|
+
| SQL Server | `sqlserver://[user]:[password]@[host]:[port]/[database]` | `sqlserver://user:password@localhost:1433/dbname?sslmode=disable` |
|
|
232
264
|
| SQLite | `sqlite:///[path/to/file]` or `sqlite::memory:` | `sqlite:///path/to/database.db`, `sqlite:C:/Users/YourName/data/database.db (windows)` or `sqlite::memory:` |
|
|
233
|
-
| Oracle | `oracle://[user]:[password]@[host]:[port]/[service_name]` | `oracle://username:password@localhost:1521/service_name`
|
|
265
|
+
| Oracle | `oracle://[user]:[password]@[host]:[port]/[service_name]` | `oracle://username:password@localhost:1521/service_name?sslmode=disable` |
|
|
234
266
|
|
|
235
267
|
#### Oracle
|
|
236
268
|
|
package/dist/index.js
CHANGED
|
@@ -76,7 +76,13 @@ var PostgresDSNParser = class {
|
|
|
76
76
|
};
|
|
77
77
|
url.searchParams.forEach((value, key) => {
|
|
78
78
|
if (key === "sslmode") {
|
|
79
|
-
|
|
79
|
+
if (value === "disable") {
|
|
80
|
+
config.ssl = false;
|
|
81
|
+
} else if (value === "require") {
|
|
82
|
+
config.ssl = { rejectUnauthorized: false };
|
|
83
|
+
} else {
|
|
84
|
+
config.ssl = true;
|
|
85
|
+
}
|
|
80
86
|
}
|
|
81
87
|
});
|
|
82
88
|
return config;
|
|
@@ -87,7 +93,7 @@ var PostgresDSNParser = class {
|
|
|
87
93
|
}
|
|
88
94
|
}
|
|
89
95
|
getSampleDSN() {
|
|
90
|
-
return "postgres://postgres:password@localhost:5432/postgres?sslmode=
|
|
96
|
+
return "postgres://postgres:password@localhost:5432/postgres?sslmode=require";
|
|
91
97
|
}
|
|
92
98
|
isValidDSN(dsn) {
|
|
93
99
|
try {
|
|
@@ -388,16 +394,22 @@ var SQLServerDSNParser = class {
|
|
|
388
394
|
const password = url.password ? decodeURIComponent(url.password) : "";
|
|
389
395
|
const options = {};
|
|
390
396
|
for (const [key, value] of url.searchParams.entries()) {
|
|
391
|
-
if (key === "
|
|
392
|
-
options.encrypt = value === "true" ? true : value === "false" ? false : value;
|
|
393
|
-
} else if (key === "trustServerCertificate") {
|
|
394
|
-
options.trustServerCertificate = value === "true";
|
|
395
|
-
} else if (key === "connectTimeout") {
|
|
397
|
+
if (key === "connectTimeout") {
|
|
396
398
|
options.connectTimeout = parseInt(value, 10);
|
|
397
399
|
} else if (key === "requestTimeout") {
|
|
398
400
|
options.requestTimeout = parseInt(value, 10);
|
|
399
401
|
} else if (key === "authentication") {
|
|
400
402
|
options.authentication = value;
|
|
403
|
+
} else if (key === "sslmode") {
|
|
404
|
+
options.sslmode = value;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (options.sslmode) {
|
|
408
|
+
if (options.sslmode === "disable") {
|
|
409
|
+
options.encrypt = false;
|
|
410
|
+
} else if (options.sslmode === "require") {
|
|
411
|
+
options.encrypt = true;
|
|
412
|
+
options.trustServerCertificate = true;
|
|
401
413
|
}
|
|
402
414
|
}
|
|
403
415
|
const config = {
|
|
@@ -433,7 +445,7 @@ var SQLServerDSNParser = class {
|
|
|
433
445
|
return config;
|
|
434
446
|
}
|
|
435
447
|
getSampleDSN() {
|
|
436
|
-
return "sqlserver://username:password@localhost:1433/database?
|
|
448
|
+
return "sqlserver://username:password@localhost:1433/database?sslmode=require";
|
|
437
449
|
}
|
|
438
450
|
isValidDSN(dsn) {
|
|
439
451
|
try {
|
|
@@ -930,8 +942,14 @@ var MySQLDSNParser = class {
|
|
|
930
942
|
password: url.password ? decodeURIComponent(url.password) : ""
|
|
931
943
|
};
|
|
932
944
|
url.searchParams.forEach((value, key) => {
|
|
933
|
-
if (key === "
|
|
934
|
-
|
|
945
|
+
if (key === "sslmode") {
|
|
946
|
+
if (value === "disable") {
|
|
947
|
+
config.ssl = void 0;
|
|
948
|
+
} else if (value === "require") {
|
|
949
|
+
config.ssl = { rejectUnauthorized: false };
|
|
950
|
+
} else {
|
|
951
|
+
config.ssl = {};
|
|
952
|
+
}
|
|
935
953
|
}
|
|
936
954
|
});
|
|
937
955
|
return config;
|
|
@@ -942,7 +960,7 @@ var MySQLDSNParser = class {
|
|
|
942
960
|
}
|
|
943
961
|
}
|
|
944
962
|
getSampleDSN() {
|
|
945
|
-
return "mysql://root:password@localhost:3306/mysql";
|
|
963
|
+
return "mysql://root:password@localhost:3306/mysql?sslmode=require";
|
|
946
964
|
}
|
|
947
965
|
isValidDSN(dsn) {
|
|
948
966
|
try {
|
|
@@ -1280,8 +1298,14 @@ var MariadbDSNParser = class {
|
|
|
1280
1298
|
password: decodeURIComponent(url.password)
|
|
1281
1299
|
};
|
|
1282
1300
|
url.searchParams.forEach((value, key) => {
|
|
1283
|
-
if (key === "
|
|
1284
|
-
|
|
1301
|
+
if (key === "sslmode") {
|
|
1302
|
+
if (value === "disable") {
|
|
1303
|
+
config.ssl = void 0;
|
|
1304
|
+
} else if (value === "require") {
|
|
1305
|
+
config.ssl = { rejectUnauthorized: false };
|
|
1306
|
+
} else {
|
|
1307
|
+
config.ssl = {};
|
|
1308
|
+
}
|
|
1285
1309
|
}
|
|
1286
1310
|
});
|
|
1287
1311
|
return config;
|
|
@@ -1292,7 +1316,7 @@ var MariadbDSNParser = class {
|
|
|
1292
1316
|
}
|
|
1293
1317
|
}
|
|
1294
1318
|
getSampleDSN() {
|
|
1295
|
-
return "mariadb://root:password@localhost:3306/db";
|
|
1319
|
+
return "mariadb://root:password@localhost:3306/db?sslmode=require";
|
|
1296
1320
|
}
|
|
1297
1321
|
isValidDSN(dsn) {
|
|
1298
1322
|
try {
|
|
@@ -1617,7 +1641,7 @@ ConnectorRegistry.register(mariadbConnector);
|
|
|
1617
1641
|
// src/connectors/oracle/index.ts
|
|
1618
1642
|
import oracledb from "oracledb";
|
|
1619
1643
|
oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT;
|
|
1620
|
-
var
|
|
1644
|
+
var _OracleConnector = class _OracleConnector {
|
|
1621
1645
|
// constructor(config: ConnectionConfig) { // Removed config
|
|
1622
1646
|
constructor() {
|
|
1623
1647
|
// Connector ID and Name are part of the Connector interface
|
|
@@ -1661,6 +1685,15 @@ var OracleConnector = class {
|
|
|
1661
1685
|
case "poolincrement":
|
|
1662
1686
|
config.poolIncrement = parseInt(value, 10);
|
|
1663
1687
|
break;
|
|
1688
|
+
case "sslmode":
|
|
1689
|
+
switch (value.toLowerCase()) {
|
|
1690
|
+
case "disable":
|
|
1691
|
+
break;
|
|
1692
|
+
case "require":
|
|
1693
|
+
config.sslServerDNMatch = false;
|
|
1694
|
+
break;
|
|
1695
|
+
}
|
|
1696
|
+
break;
|
|
1664
1697
|
}
|
|
1665
1698
|
});
|
|
1666
1699
|
return config;
|
|
@@ -1669,7 +1702,7 @@ var OracleConnector = class {
|
|
|
1669
1702
|
}
|
|
1670
1703
|
},
|
|
1671
1704
|
getSampleDSN: () => {
|
|
1672
|
-
return "oracle://username:password@host:1521/service_name";
|
|
1705
|
+
return "oracle://username:password@host:1521/service_name?sslmode=require";
|
|
1673
1706
|
},
|
|
1674
1707
|
isValidDSN: (dsn) => {
|
|
1675
1708
|
try {
|
|
@@ -1680,6 +1713,13 @@ var OracleConnector = class {
|
|
|
1680
1713
|
}
|
|
1681
1714
|
}
|
|
1682
1715
|
};
|
|
1716
|
+
oracledb.autoCommit = true;
|
|
1717
|
+
}
|
|
1718
|
+
// Initialize Oracle client only once
|
|
1719
|
+
initClient() {
|
|
1720
|
+
if (_OracleConnector.clientInitialized) {
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1683
1723
|
try {
|
|
1684
1724
|
if (process.env.ORACLE_LIB_DIR) {
|
|
1685
1725
|
oracledb.initOracleClient({ libDir: process.env.ORACLE_LIB_DIR });
|
|
@@ -1687,13 +1727,14 @@ var OracleConnector = class {
|
|
|
1687
1727
|
} else {
|
|
1688
1728
|
console.error("ORACLE_LIB_DIR not specified, will use Thin mode by default");
|
|
1689
1729
|
}
|
|
1730
|
+
_OracleConnector.clientInitialized = true;
|
|
1690
1731
|
} catch (err) {
|
|
1691
1732
|
console.error("Failed to initialize Oracle client:", err);
|
|
1692
1733
|
}
|
|
1693
|
-
oracledb.autoCommit = true;
|
|
1694
1734
|
}
|
|
1695
1735
|
async connect(dsn, initializationScript) {
|
|
1696
1736
|
try {
|
|
1737
|
+
this.initClient();
|
|
1697
1738
|
const config = await this.dsnParser.parse(dsn);
|
|
1698
1739
|
this.pool = await oracledb.createPool(config);
|
|
1699
1740
|
const conn = await this.getConnection();
|
|
@@ -2074,6 +2115,9 @@ To resolve this, you need to use Thick mode:
|
|
|
2074
2115
|
return this.pool.getConnection();
|
|
2075
2116
|
}
|
|
2076
2117
|
};
|
|
2118
|
+
// Track if we've already initialized the client
|
|
2119
|
+
_OracleConnector.clientInitialized = false;
|
|
2120
|
+
var OracleConnector = _OracleConnector;
|
|
2077
2121
|
function formatOracleDataType(dataType, dataLength, dataPrecision, dataScale) {
|
|
2078
2122
|
if (!dataType) {
|
|
2079
2123
|
return "UNKNOWN";
|