diff --git a/CHANGELOG.md b/CHANGELOG.md index 758a054b0..ef6b027d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The connection switcher and welcome list now show each connection's tags and group. (#1323) - The ER diagram marks relationship cardinality (one-to-one, one-to-many, and optional variants) with crow's foot notation, read from primary keys and unique indexes. Junction tables collapse into a single many-to-many link, with a toolbar toggle to expand them. (#1335) - Export the ER diagram to SQL. A toolbar button opens a query tab with CREATE TABLE and foreign key statements for the current schema. (#1335) +- Oracle connections have a Native network encryption option, off by default, for servers that require encrypted traffic. (#1746) ### Changed @@ -26,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Opening a new query tab now puts keyboard focus in the SQL editor instead of the sidebar filter, so you can type right away. (#1765) - Raw filters in the data grid now work on document and key-value databases; the typed text was dropped before reaching the driver. (#1529) - Connecting to Oracle no longer crashes on certain server values during the handshake; a bad packet now fails the connection with an error. (#1746) +- Connecting to Oracle no longer hangs when the server permits but does not require native network encryption; TablePro now connects in clear text by default, like Oracle's own clients. (#1746) - Following a foreign key into another schema now opens the correct table on SQL Server and Oracle, instead of falling back to the default schema. (#1754) - Browsing or editing a SQL Server or Oracle table outside the default schema no longer fails with "Invalid object name" or writes to the wrong table; queries now qualify the table with its schema. (#1754) diff --git a/Plugins/OracleDriverPlugin/OracleConnection.swift b/Plugins/OracleDriverPlugin/OracleConnection.swift index bbf182816..9130f8adb 100644 --- a/Plugins/OracleDriverPlugin/OracleConnection.swift +++ b/Plugins/OracleDriverPlugin/OracleConnection.swift @@ -120,6 +120,7 @@ final class OracleConnectionWrapper: @unchecked Sendable { private let serviceName: String private let useSID: Bool private let sslConfig: SSLConfiguration + private let nativeNetworkEncryption: Bool private struct LockedState: Sendable { var isConnected = false @@ -143,7 +144,8 @@ final class OracleConnectionWrapper: @unchecked Sendable { database: String, serviceName: String = "", useSID: Bool = false, - sslConfig: SSLConfiguration = SSLConfiguration() + sslConfig: SSLConfiguration = SSLConfiguration(), + nativeNetworkEncryption: Bool = false ) { self.host = host self.port = port @@ -153,6 +155,7 @@ final class OracleConnectionWrapper: @unchecked Sendable { self.serviceName = serviceName self.useSID = useSID self.sslConfig = sslConfig + self.nativeNetworkEncryption = nativeNetworkEncryption } // MARK: - Connection @@ -161,7 +164,7 @@ final class OracleConnectionWrapper: @unchecked Sendable { let identifier = serviceName.isEmpty ? database : serviceName let service: OracleServiceMethod = useSID ? .sid(identifier) : .serviceName(identifier) let tls = try OracleSSLMapping.tls(for: sslConfig) - let config = OracleNIO.OracleConnection.Configuration( + var config = OracleNIO.OracleConnection.Configuration( host: host, port: port, service: service, @@ -169,6 +172,7 @@ final class OracleConnectionWrapper: @unchecked Sendable { password: password, tls: tls ) + config.nativeNetworkEncryption = nativeNetworkEncryption let connectionId = Self.connectionCounter.withLock { state -> Int in state += 1 diff --git a/Plugins/OracleDriverPlugin/OraclePlugin.swift b/Plugins/OracleDriverPlugin/OraclePlugin.swift index 1718fcdd3..2d514ad1c 100644 --- a/Plugins/OracleDriverPlugin/OraclePlugin.swift +++ b/Plugins/OracleDriverPlugin/OraclePlugin.swift @@ -38,6 +38,12 @@ final class OraclePlugin: NSObject, TableProPlugin, DriverPlugin, PluginDiagnost label: "SID", placeholder: "XE", visibleWhen: FieldVisibilityRule(fieldId: "oracleConnectionType", values: ["sid"]) + ), + ConnectionField( + id: "oracleNativeEncryption", + label: "Native network encryption", + defaultValue: "false", + fieldType: .toggle ) ] @@ -230,7 +236,8 @@ final class OraclePluginDriver: PluginDatabaseDriver, @unchecked Sendable { database: config.database, serviceName: identifier, useSID: useSID, - sslConfig: config.ssl + sslConfig: config.ssl, + nativeNetworkEncryption: config.additionalFields["oracleNativeEncryption"] == "true" ) try await conn.connect() self.oracleConn = conn diff --git a/TablePro.xcodeproj/project.pbxproj b/TablePro.xcodeproj/project.pbxproj index b4a4b29a5..ccb9c6378 100644 --- a/TablePro.xcodeproj/project.pbxproj +++ b/TablePro.xcodeproj/project.pbxproj @@ -4934,7 +4934,7 @@ repositoryURL = "https://github.com/TableProApp/oracle-nio"; requirement = { kind = revision; - revision = f58c1aa2fe0c308aa99edfd18081ae9a98e3d3ed; + revision = 1140759e3bc339a8383b5d38f45fcb4ef61e602a; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/TablePro.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/TablePro.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ee32ea676..7b2a97d0a 100644 --- a/TablePro.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/TablePro.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -24,7 +24,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/TableProApp/oracle-nio", "state" : { - "revision" : "f58c1aa2fe0c308aa99edfd18081ae9a98e3d3ed" + "revision" : "1140759e3bc339a8383b5d38f45fcb4ef61e602a" } }, { diff --git a/docs/databases/oracle.mdx b/docs/databases/oracle.mdx index 76b29e5db..6a058dadd 100644 --- a/docs/databases/oracle.mdx +++ b/docs/databases/oracle.mdx @@ -40,6 +40,7 @@ The Oracle driver is available as a downloadable plugin. When you select Oracle | **Port** | `1521` | Listener port | | **Service Name** | - | **Required**. Check `tnsnames.ora` if unclear. To connect by SID instead, set **Connection Type** to SID and enter the SID. | | **Username** | - | Requires username/password auth (no OS auth) | +| **Native network encryption** | Off | Advanced. Turn on only if the server requires encrypted traffic (`SQLNET.ENCRYPTION_SERVER = REQUIRED`). Leave off for servers that merely accept encryption, which connect in clear text like Oracle's own clients. | ## Example Configurations @@ -148,6 +149,6 @@ Columns with types not yet supported render as `` rather than **Instant Client not found**: Download Basic package, extract to `/usr/local/oracle/instantclient`, set `DYLD_LIBRARY_PATH` -**Connection dropped during handshake**: The server closed the connection mid-login. The error dialog shows the handshake phase it stopped at (for example `dataTypeNegotiation` or `authentication`). Check for a firewall, VPN, or proxy that resets traffic, and confirm the host and port reach the listener directly. On Oracle 11g, open an issue and include the handshake phase. +**Connection dropped during handshake**: The server closed the connection mid-login. The error dialog shows the handshake phase it stopped at (for example `advancedNegotiation`, `dataTypeNegotiation`, or `authentication`). Check for a firewall, VPN, or proxy that resets traffic, and confirm the host and port reach the listener directly. If the phase is around negotiation and the server requires native network encryption, turn on the **Native network encryption** option; if you turned it on for a server that only accepts encryption, turn it back off. **Limitations**: Username/password only, BFILE shows locator metadata only (content fetch via DBMS_LOB not supported), PL/SQL limited to anonymous blocks.