@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.
Files changed (3) hide show
  1. package/README.md +37 -5
  2. package/dist/index.js +61 -17
  3. 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
- config.ssl = value !== "disable";
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=disable";
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 === "encrypt") {
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?encrypt=true";
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 === "ssl") {
934
- config.ssl = value === "true" ? {} : void 0;
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 === "ssl") {
1284
- config.ssl = value === "true" ? {} : void 0;
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 OracleConnector = class {
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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytebase/dbhub",
3
- "version": "0.4.1",
3
+ "version": "0.4.5",
4
4
  "description": "Universal Database MCP Server",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",