chore: improve x11

This commit is contained in:
hstyi
2025-04-01 10:37:38 +08:00
committed by hstyi
parent 054c4701d2
commit 2c5442f1f3
2 changed files with 66 additions and 60 deletions

View File

@@ -3,7 +3,6 @@ package app.termora
import app.termora.keyboardinteractive.TerminalUserInteraction
import app.termora.keymgr.OhKeyPairKeyPairProvider
import app.termora.terminal.TerminalSize
import app.termora.x11.ChannelX11
import app.termora.x11.X11ChannelFactory
import com.formdev.flatlaf.FlatLaf
import com.formdev.flatlaf.util.FontUtils
@@ -80,7 +79,6 @@ import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
import javax.swing.*
import kotlin.math.max
import kotlin.random.Random
@Suppress("CascadeIf")
object SshClients {
@@ -111,6 +109,12 @@ object SshClients {
env.putAll(host.options.envs())
val channel = session.createShellChannel(configuration, env)
if (host.options.enableX11Forwarding) {
if (channel is app.termora.x11.ChannelShell) {
channel.xForwarding = true
}
}
if (!channel.open().verify(timeout).await()) {
throw SshException("Failed to open Shell")
}
@@ -563,7 +567,7 @@ object SshClients {
): ChannelShell {
if (inCipher is CipherNone || outCipher is CipherNone)
throw IllegalStateException("Interactive channels are not supported with none cipher")
val channel = MyChannelShell(ptyConfig, env)
val channel = app.termora.x11.ChannelShell(ptyConfig, env)
val id = connectionService.registerChannel(channel)
if (log.isDebugEnabled) {
log.debug("createShellChannel({}) created id={} - PTY={}", this, id, ptyConfig)
@@ -580,63 +584,6 @@ object SshClients {
throw UnsupportedOperationException()
}
private class MyChannelShell(
configHolder: PtyChannelConfigurationHolder?,
env: MutableMap<String, *>?
) : ChannelShell(configHolder, env) {
override fun doOpenPty() {
val session = super.getSession()
val x11Host = CoreModuleProperties.X11_BIND_HOST.getOrNull(session)
val x11Port = CoreModuleProperties.X11_BASE_PORT.getOrNull(session)
if (x11Port == null || x11Host == null) {
super.doOpenPty()
return
}
val buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST)
buffer.putInt(super.getRecipient())
buffer.putString("x11-req")
buffer.putBoolean(false) // want-reply
buffer.putBoolean(false)
buffer.putString("MIT-MAGIC-COOKIE-1")
buffer.putBytes(getFakedCookie())
buffer.putInt(0)
writePacket(buffer)
super.doOpenPty()
}
private fun getFakedCookie(): ByteArray {
val session = super.getSession()
var cookie = ChannelX11.X11_COOKIE_HEX.getOrNull(session)
if (cookie != null) {
return cookie as ByteArray
}
synchronized(session) {
cookie = ChannelX11.X11_COOKIE_HEX.getOrNull(session)
if (cookie != null) {
return cookie as ByteArray
}
val foo = Random.nextBytes(16)
ChannelX11.X11_COOKIE.set(session, foo)
val bar = foo.copyOf(32)
for (i in 0..15) {
bar[2 * i] = ChannelX11.COOKIE_TABLE[(foo[i].toInt() ushr 4) and 0xf]
bar[2 * i + 1] = ChannelX11.COOKIE_TABLE[foo[i].toInt() and 0xf]
}
ChannelX11.X11_COOKIE_HEX.set(session, bar)
return bar
}
}
}
private class MyIoConnector(private val sshClient: MyJGitSshClient, private val ioConnector: IoConnector) :
IoConnector {
override fun close(immediately: Boolean): CloseFuture {

View File

@@ -0,0 +1,59 @@
package app.termora.x11
import org.apache.sshd.client.channel.ChannelShell
import org.apache.sshd.common.SshConstants
import org.apache.sshd.common.channel.PtyChannelConfigurationHolder
import kotlin.random.Random
class ChannelShell(
configHolder: PtyChannelConfigurationHolder?,
env: MutableMap<String, *>?
) : ChannelShell(configHolder, env) {
var xForwarding = false
override fun doOpenPty() {
val session = super.getSession()
if (xForwarding) {
val buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST)
buffer.putInt(super.getRecipient())
buffer.putString("x11-req")
buffer.putBoolean(false) // want-reply
buffer.putBoolean(false)
buffer.putString("MIT-MAGIC-COOKIE-1")
buffer.putBytes(getFakedCookie())
buffer.putInt(0)
writePacket(buffer)
}
super.doOpenPty()
}
private fun getFakedCookie(): ByteArray {
val session = super.getSession()
var cookie = ChannelX11.X11_COOKIE_HEX.getOrNull(session)
if (cookie != null) {
return cookie as ByteArray
}
synchronized(session) {
cookie = ChannelX11.X11_COOKIE_HEX.getOrNull(session)
if (cookie != null) {
return cookie as ByteArray
}
val foo = Random.nextBytes(16)
ChannelX11.X11_COOKIE.set(session, foo)
val bar = foo.copyOf(32)
for (i in 0..15) {
bar[2 * i] = ChannelX11.COOKIE_TABLE[(foo[i].toInt() ushr 4) and 0xf]
bar[2 * i + 1] = ChannelX11.COOKIE_TABLE[foo[i].toInt() and 0xf]
}
ChannelX11.X11_COOKIE_HEX.set(session, bar)
return bar
}
}
}