mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
chore: improve proxy
This commit is contained in:
@@ -18,12 +18,14 @@ import org.apache.sshd.client.channel.ClientChannelEvent
|
|||||||
import org.apache.sshd.client.config.hosts.HostConfigEntry
|
import org.apache.sshd.client.config.hosts.HostConfigEntry
|
||||||
import org.apache.sshd.client.config.hosts.HostConfigEntryResolver
|
import org.apache.sshd.client.config.hosts.HostConfigEntryResolver
|
||||||
import org.apache.sshd.client.config.hosts.KnownHostEntry
|
import org.apache.sshd.client.config.hosts.KnownHostEntry
|
||||||
import org.apache.sshd.client.future.ConnectFuture
|
|
||||||
import org.apache.sshd.client.kex.DHGClient
|
import org.apache.sshd.client.kex.DHGClient
|
||||||
import org.apache.sshd.client.keyverifier.KnownHostsServerKeyVerifier
|
import org.apache.sshd.client.keyverifier.KnownHostsServerKeyVerifier
|
||||||
import org.apache.sshd.client.keyverifier.ModifiedServerKeyAcceptor
|
import org.apache.sshd.client.keyverifier.ModifiedServerKeyAcceptor
|
||||||
import org.apache.sshd.client.keyverifier.ServerKeyVerifier
|
import org.apache.sshd.client.keyverifier.ServerKeyVerifier
|
||||||
|
import org.apache.sshd.client.session.ClientProxyConnector
|
||||||
import org.apache.sshd.client.session.ClientSession
|
import org.apache.sshd.client.session.ClientSession
|
||||||
|
import org.apache.sshd.client.session.ClientSessionImpl
|
||||||
|
import org.apache.sshd.client.session.SessionFactory
|
||||||
import org.apache.sshd.common.AttributeRepository
|
import org.apache.sshd.common.AttributeRepository
|
||||||
import org.apache.sshd.common.SshConstants
|
import org.apache.sshd.common.SshConstants
|
||||||
import org.apache.sshd.common.SshException
|
import org.apache.sshd.common.SshException
|
||||||
@@ -48,23 +50,25 @@ import org.eclipse.jgit.internal.transport.sshd.JGitSshClient
|
|||||||
import org.eclipse.jgit.internal.transport.sshd.agent.JGitSshAgentFactory
|
import org.eclipse.jgit.internal.transport.sshd.agent.JGitSshAgentFactory
|
||||||
import org.eclipse.jgit.internal.transport.sshd.agent.connector.PageantConnector
|
import org.eclipse.jgit.internal.transport.sshd.agent.connector.PageantConnector
|
||||||
import org.eclipse.jgit.internal.transport.sshd.agent.connector.UnixDomainSocketConnector
|
import org.eclipse.jgit.internal.transport.sshd.agent.connector.UnixDomainSocketConnector
|
||||||
|
import org.eclipse.jgit.internal.transport.sshd.proxy.AbstractClientProxyConnector
|
||||||
|
import org.eclipse.jgit.internal.transport.sshd.proxy.HttpClientConnector
|
||||||
|
import org.eclipse.jgit.internal.transport.sshd.proxy.Socks5ClientConnector
|
||||||
import org.eclipse.jgit.transport.CredentialsProvider
|
import org.eclipse.jgit.transport.CredentialsProvider
|
||||||
import org.eclipse.jgit.transport.SshConstants.IDENTITY_AGENT
|
import org.eclipse.jgit.transport.SshConstants.IDENTITY_AGENT
|
||||||
import org.eclipse.jgit.transport.sshd.IdentityPasswordProvider
|
import org.eclipse.jgit.transport.sshd.IdentityPasswordProvider
|
||||||
import org.eclipse.jgit.transport.sshd.ProxyData
|
|
||||||
import org.eclipse.jgit.transport.sshd.agent.ConnectorFactory
|
import org.eclipse.jgit.transport.sshd.agent.ConnectorFactory
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.Window
|
import java.awt.Window
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.net.Proxy
|
|
||||||
import java.net.SocketAddress
|
import java.net.SocketAddress
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
@@ -497,26 +501,36 @@ object SshClients {
|
|||||||
JGitSshClient::class.java.getDeclaredField("HOST_CONFIG_ENTRY").apply { isAccessible = true }
|
JGitSshClient::class.java.getDeclaredField("HOST_CONFIG_ENTRY").apply { isAccessible = true }
|
||||||
.get(null) as AttributeRepository.AttributeKey<HostConfigEntry>
|
.get(null) as AttributeRepository.AttributeKey<HostConfigEntry>
|
||||||
}
|
}
|
||||||
|
private const val CLIENT_PROXY_CONNECTOR = "ClientProxyConnectorId"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val sshClient = this
|
||||||
|
private val clientProxyConnectors = ConcurrentHashMap<String, ClientProxyConnector>()
|
||||||
|
|
||||||
|
|
||||||
override fun createConnector(): IoConnector {
|
override fun createConnector(): IoConnector {
|
||||||
return MyIoConnector(this, super.createConnector())
|
return MyIoConnector(this, super.createConnector())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun createSessionFactory(): SessionFactory {
|
||||||
* 加上 synchronized ,因为默认代理是全局的(需要在连接时动态修改),所以这里需要一个个连接
|
return object : SessionFactory(sshClient) {
|
||||||
*/
|
override fun doCreateSession(ioSession: IoSession): ClientSessionImpl {
|
||||||
override fun connect(
|
return object : JGitClientSession(sshClient, ioSession) {
|
||||||
hostConfig: HostConfigEntry?,
|
override fun getClientProxyConnector(): ClientProxyConnector? {
|
||||||
context: AttributeRepository?,
|
val entry = getAttribute(HOST_CONFIG_ENTRY) ?: return null
|
||||||
localAddress: SocketAddress?
|
val clientProxyConnectorId = entry.getProperty(CLIENT_PROXY_CONNECTOR) ?: return null
|
||||||
): ConnectFuture {
|
return sshClient.clientProxyConnectors.remove(clientProxyConnectorId)
|
||||||
synchronized(this) {
|
}
|
||||||
return super.connect(hostConfig, context, localAddress)
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MyIoConnector(private val sshClient: SshClient, private val ioConnector: IoConnector) :
|
override fun setClientProxyConnector(proxyConnector: ClientProxyConnector?) {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyIoConnector(private val sshClient: MyJGitSshClient, private val ioConnector: IoConnector) :
|
||||||
IoConnector {
|
IoConnector {
|
||||||
override fun close(immediately: Boolean): CloseFuture {
|
override fun close(immediately: Boolean): CloseFuture {
|
||||||
return ioConnector.close(immediately)
|
return ioConnector.close(immediately)
|
||||||
@@ -560,58 +574,57 @@ object SshClients {
|
|||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
val host = hostManager.getHost(entry.getProperty("Host") ?: StringUtils.EMPTY)
|
val host = hostManager.getHost(entry.getProperty("Host") ?: StringUtils.EMPTY)
|
||||||
if (host != null) {
|
if (host != null) {
|
||||||
tAddress = configureProxy(host, tAddress)
|
tAddress = configureProxy(entry, host, tAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ioConnector.connect(tAddress, context, localAddress)
|
||||||
|
}
|
||||||
|
|
||||||
val proxyConnector = sshClient.clientProxyConnector
|
private fun configureProxy(
|
||||||
val future = ioConnector.connect(tAddress, context, localAddress)
|
entry: HostConfigEntry,
|
||||||
|
host: Host,
|
||||||
// 代理是一次性的
|
targetAddress: SocketAddress
|
||||||
// 如果 tAddress != targetAddress 为 true 那么表示进行代理了
|
): SocketAddress {
|
||||||
if (proxyConnector != null && tAddress != targetAddress) {
|
|
||||||
future.addListener {
|
|
||||||
if (it.isDone) {
|
|
||||||
if (sshClient.clientProxyConnector == proxyConnector) {
|
|
||||||
sshClient.clientProxyConnector = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return future
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun configureProxy(host: Host, targetAddress: SocketAddress): SocketAddress {
|
|
||||||
if (host.proxy.type == ProxyType.No) return targetAddress
|
if (host.proxy.type == ProxyType.No) return targetAddress
|
||||||
if (targetAddress.toString().contains(SshdSocketAddress.LOCALHOST_IPV4)) return targetAddress
|
val address = targetAddress as? InetSocketAddress ?: return targetAddress
|
||||||
|
if (address.hostString == (SshdSocketAddress.LOCALHOST_IPV4)) return targetAddress
|
||||||
|
|
||||||
val proxyData = ProxyData(
|
// 获取代理连接器
|
||||||
|
val clientProxyConnector = getClientProxyConnector(host, address) ?: return targetAddress
|
||||||
|
|
||||||
|
val id = UUID.randomUUID().toSimpleString()
|
||||||
|
entry.setProperty(CLIENT_PROXY_CONNECTOR, id)
|
||||||
|
sshClient.clientProxyConnectors[id] = clientProxyConnector
|
||||||
|
|
||||||
|
return InetSocketAddress(host.proxy.host, host.proxy.port)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getClientProxyConnector(
|
||||||
|
host: Host,
|
||||||
|
remoteAddress: InetSocketAddress
|
||||||
|
): AbstractClientProxyConnector? {
|
||||||
if (host.proxy.type == ProxyType.HTTP) {
|
if (host.proxy.type == ProxyType.HTTP) {
|
||||||
Proxy(Proxy.Type.HTTP, InetSocketAddress(host.proxy.host, host.proxy.port))
|
return HttpClientConnector(
|
||||||
} else {
|
InetSocketAddress(host.proxy.host, host.proxy.port),
|
||||||
Proxy(Proxy.Type.SOCKS, InetSocketAddress(host.proxy.host, host.proxy.port))
|
remoteAddress,
|
||||||
},
|
|
||||||
host.proxy.username.ifBlank { null },
|
host.proxy.username.ifBlank { null },
|
||||||
if (host.proxy.password.isBlank()) null else host.proxy.password.toCharArray(),
|
if (host.proxy.password.isBlank()) null else host.proxy.password.toCharArray()
|
||||||
)
|
)
|
||||||
|
} else if (host.proxy.type == ProxyType.SOCKS5) {
|
||||||
// 反射调用
|
return Socks5ClientConnector(
|
||||||
val configureProxy = JGitSshClient::class.java.getDeclaredMethod(
|
InetSocketAddress(host.proxy.host, host.proxy.port),
|
||||||
"configureProxy",
|
remoteAddress,
|
||||||
ProxyData::class.java,
|
host.proxy.username.ifBlank { null },
|
||||||
InetSocketAddress::class.java
|
if (host.proxy.password.isBlank()) null else host.proxy.password.toCharArray()
|
||||||
)
|
)
|
||||||
configureProxy.isAccessible = true
|
|
||||||
val address = configureProxy.invoke(sshClient, proxyData, InetSocketAddress(host.host, host.port))
|
|
||||||
if (address is InetSocketAddress) {
|
|
||||||
return address
|
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
return targetAddress
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user