mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
chore: improve x11
This commit is contained in:
@@ -3,7 +3,6 @@ package app.termora
|
|||||||
import app.termora.keyboardinteractive.TerminalUserInteraction
|
import app.termora.keyboardinteractive.TerminalUserInteraction
|
||||||
import app.termora.keymgr.OhKeyPairKeyPairProvider
|
import app.termora.keymgr.OhKeyPairKeyPairProvider
|
||||||
import app.termora.terminal.TerminalSize
|
import app.termora.terminal.TerminalSize
|
||||||
import app.termora.x11.ChannelX11
|
|
||||||
import app.termora.x11.X11ChannelFactory
|
import app.termora.x11.X11ChannelFactory
|
||||||
import com.formdev.flatlaf.FlatLaf
|
import com.formdev.flatlaf.FlatLaf
|
||||||
import com.formdev.flatlaf.util.FontUtils
|
import com.formdev.flatlaf.util.FontUtils
|
||||||
@@ -80,7 +79,6 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
@Suppress("CascadeIf")
|
@Suppress("CascadeIf")
|
||||||
object SshClients {
|
object SshClients {
|
||||||
@@ -111,6 +109,12 @@ object SshClients {
|
|||||||
env.putAll(host.options.envs())
|
env.putAll(host.options.envs())
|
||||||
|
|
||||||
val channel = session.createShellChannel(configuration, env)
|
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()) {
|
if (!channel.open().verify(timeout).await()) {
|
||||||
throw SshException("Failed to open Shell")
|
throw SshException("Failed to open Shell")
|
||||||
}
|
}
|
||||||
@@ -563,7 +567,7 @@ object SshClients {
|
|||||||
): ChannelShell {
|
): ChannelShell {
|
||||||
if (inCipher is CipherNone || outCipher is CipherNone)
|
if (inCipher is CipherNone || outCipher is CipherNone)
|
||||||
throw IllegalStateException("Interactive channels are not supported with none cipher")
|
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)
|
val id = connectionService.registerChannel(channel)
|
||||||
if (log.isDebugEnabled) {
|
if (log.isDebugEnabled) {
|
||||||
log.debug("createShellChannel({}) created id={} - PTY={}", this, id, ptyConfig)
|
log.debug("createShellChannel({}) created id={} - PTY={}", this, id, ptyConfig)
|
||||||
@@ -580,63 +584,6 @@ object SshClients {
|
|||||||
throw UnsupportedOperationException()
|
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) :
|
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 {
|
||||||
|
|||||||
59
src/main/kotlin/app/termora/x11/ChannelShell.kt
Normal file
59
src/main/kotlin/app/termora/x11/ChannelShell.kt
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user