Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Connect through a SOCKS5 proxy. Set a host, port, and an optional username and password on the connection form's new SOCKS Proxy pane, alongside SSH Tunnel, Cloudflare Tunnel, and Cloud SQL Auth Proxy. The database hostname is resolved by the proxy, so names that only resolve behind it work. (#1882)
- SQL Server connections can now use Windows Authentication (Kerberos) on macOS. Pick Windows Authentication in the connection form to sign in with the Kerberos ticket you already have from `kinit`, or enter a Kerberos principal and password to sign in with your domain credentials. Connect by hostname, not IP address. (#1879)
- Teradata support through a downloadable driver written in native Swift. Connect over TD2 or TDNEGO logon, optionally with TLS, browse databases, tables, and columns, run SQL, edit rows, and create or alter tables. (#1867)

Expand All @@ -18,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Fixed duplicating a connection dropping its Cloudflare Tunnel and Cloud SQL Auth Proxy settings and stored secrets.
- Fixed the tunnel panes warning about only some of the other enabled connection methods. Each pane now lists every conflicting method with a button to turn it off.
- Fixed Copy as, the context menu's Delete, and the Edit menu's copy and delete commands acting on only the active row instead of every row in a cell-range or column selection in the data grid. (#1898)
- Fixed the Edit menu's Copy as JSON copying the wrong rows when the grid was sorted or filtered. (#1898)
- Fixed tables picked in the sidebar showing up unchecked and getting silently skipped when exporting to SQL or MQL. The export sheet now checks them and applies the format's default per-table options, so Export works right away.
Expand Down
36 changes: 36 additions & 0 deletions TablePro/Core/Database/DatabaseManager+SOCKSProxy.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// DatabaseManager+SOCKSProxy.swift
// TablePro
//

import Foundation

extension DatabaseManager {
func buildSOCKSProxyEffectiveConnection(
for connection: DatabaseConnection
) async throws -> DatabaseConnection {
guard let config = connection.resolvedSOCKSProxyConfig else { return connection }

let password = config.username.isEmpty
? nil
: connectionStorage.loadSOCKSProxyPassword(for: connection.id)

let tunnelPort = try await SOCKSProxyManager.shared.createTunnel(
connectionId: connection.id,
config: config,
password: password,
targetHost: connection.host,
targetPort: connection.port
)

return tunneledConnection(from: connection, localPort: tunnelPort)
}

func handleSOCKSProxyTunnelDied(connectionId: UUID) async {
await recoverDeadTunnel(
connectionId: connectionId,
kind: "SOCKS Proxy",
disconnectedMessage: String(localized: "SOCKS proxy disconnected. Click to reconnect.")
)
}
}
2 changes: 2 additions & 0 deletions TablePro/Core/Database/DatabaseManager+SSH.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ extension DatabaseManager {
return try await buildCloudflareEffectiveConnection(for: connection)
case .cloudSQLProxy:
return try await buildCloudSQLProxyEffectiveConnection(for: connection)
case .socksProxy:
return try await buildSOCKSProxyEffectiveConnection(for: connection)
case .ssh, .none:
break
}
Expand Down
2 changes: 2 additions & 0 deletions TablePro/Core/Database/DatabaseManager+SystemEvents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ extension DatabaseManager {
await handleCloudflareTunnelDied(connectionId: connectionId)
case .cloudSQLProxy:
await handleCloudSQLProxyTunnelDied(connectionId: connectionId)
case .socksProxy:
await handleSOCKSProxyTunnelDied(connectionId: connectionId)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions TablePro/Core/Database/DatabaseManager+Tunnel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ extension DatabaseManager {
case .ssh: return SSHTunnelManager.shared
case .cloudflare: return CloudflareTunnelManager.shared
case .cloudSQLProxy: return CloudSQLProxyManager.shared
case .socksProxy: return SOCKSProxyManager.shared
case .none: return nil
}
}
Expand Down
5 changes: 5 additions & 0 deletions TablePro/Core/Plugins/PluginManager+Registration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,11 @@ extension PluginManager {
.capabilities.supportsCloudflareTunnel ?? true
}

func supportsSOCKSProxy(for databaseType: DatabaseType) -> Bool {
PluginMetadataRegistry.shared.snapshot(forTypeId: databaseType.pluginTypeId)?
.capabilities.supportsSOCKSProxy ?? true
}

func supportsColumnReorder(for databaseType: DatabaseType) -> Bool {
PluginMetadataRegistry.shared.snapshot(forTypeId: databaseType.pluginTypeId)?
.supportsColumnReorder ?? false
Expand Down
2 changes: 2 additions & 0 deletions TablePro/Core/Plugins/PluginMetadataRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ struct PluginMetadataSnapshot: Sendable {
var supportsCloudflareTunnel: Bool = true
var supportsClientKeyPassphrase: Bool = false

var supportsSOCKSProxy: Bool { supportsSSH }

static let defaults = CapabilityFlags(
supportsSchemaSwitching: false,
supportsImport: true,
Expand Down
Loading
Loading