From a3cc85627dd1cf9c77a0f0f2f79861ea4069e8d1 Mon Sep 17 00:00:00 2001 From: Eugene Date: Sat, 3 Aug 2024 23:28:46 +0200 Subject: [PATCH] jump hosts --- app/package.json | 2 +- app/yarn.lock | 8 +++--- tabby-ssh/src/components/sshTab.component.ts | 27 ++++++++++++-------- tabby-ssh/src/session/ssh.ts | 10 ++++---- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/app/package.json b/app/package.json index 2f88ce91..02f9a7ad 100644 --- a/app/package.json +++ b/app/package.json @@ -30,7 +30,7 @@ "native-process-working-directory": "^1.0.2", "npm": "6", "rxjs": "^7.5.7", - "russh": "^0.0.1-alpha.7", + "russh": "^0.0.1-alpha.8", "source-map-support": "^0.5.20", "v8-compile-cache": "^2.3.0", "yargs": "^17.7.2" diff --git a/app/yarn.lock b/app/yarn.lock index 0e8effd9..c137c938 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -3613,10 +3613,10 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -russh@^0.0.1-alpha.7: - version "0.0.1-alpha.7" - resolved "https://registry.yarnpkg.com/russh/-/russh-0.0.1-alpha.7.tgz#9cf66298e6e976e697f8211a24def2458e77f220" - integrity sha512-WB/2NVyr/ZvEQIkwTAf3r5UdUo52lNXhfJHwjs9uG1fabOQlJ5A+Fs8F6rGne+gJMe/Y9pqdrTQaSujUlNdMVA== +russh@^0.0.1-alpha.8: + version "0.0.1-alpha.8" + resolved "https://registry.yarnpkg.com/russh/-/russh-0.0.1-alpha.8.tgz#f7b580abdc7ee22968c77220b7031eb7d83a476c" + integrity sha512-/VJCjw1ce1uuRfF7Nk5RWhkWHbco4qaD2abL43BtSyT+XcxySl95Fv623cBMUkbGqyCQyDVItDP5zV6Sgy5vuA== dependencies: "@napi-rs/cli" "^2.18.3" diff --git a/tabby-ssh/src/components/sshTab.component.ts b/tabby-ssh/src/components/sshTab.component.ts index c0b53d6b..54bb8c0b 100644 --- a/tabby-ssh/src/components/sshTab.component.ts +++ b/tabby-ssh/src/components/sshTab.component.ts @@ -1,3 +1,4 @@ +import * as russh from 'russh' import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker' import colors from 'ansi-colors' import { Component, Injector, HostListener } from '@angular/core' @@ -94,17 +95,21 @@ export class SSHTabComponent extends ConnectableTerminalTabComponent } }) - // session.jumpStream = await new Promise((resolve, reject) => jumpSession.ssh.forwardOut( - // '127.0.0.1', 0, profile.options.host, profile.options.port ?? 22, - // (err, stream) => { - // if (err) { - // jumpSession.emitServiceMessage(colors.bgRed.black(' X ') + ` Could not set up port forward on ${jumpConnection.name}`) - // reject(err) - // return - // } - // resolve(stream) - // }, - // )) + if (!(jumpSession.ssh instanceof russh.AuthenticatedSSHClient)) { + throw new Error('Jump session is not authenticated yet somehow') + } + + try { + session.jumpChannel = await jumpSession.ssh.openTCPForwardChannel({ + addressToConnectTo: profile.options.host, + portToConnectTo: profile.options.port ?? 22, + originatorAddress: '127.0.0.1', + originatorPort: 0, + }) + } catch (err) { + jumpSession.emitServiceMessage(colors.bgRed.black(' X ') + ` Could not set up port forward on ${jumpConnection.name}`) + throw err + } } } diff --git a/tabby-ssh/src/session/ssh.ts b/tabby-ssh/src/session/ssh.ts index 82f07f95..85a95490 100644 --- a/tabby-ssh/src/session/ssh.ts +++ b/tabby-ssh/src/session/ssh.ts @@ -9,7 +9,7 @@ import { ConfigService, FileProvidersService, HostAppService, NotificationsServi import { Socket } from 'net' import { Subject, Observable } from 'rxjs' import { HostKeyPromptModalComponent } from '../components/hostKeyPromptModal.component' -// import { HTTPProxyStream, ProxyCommandStream, SocksProxyStream } from '../services/ssh.service' +// import { HTTPProxyStream, SocksProxyStream } from '../services/ssh.service' import { PasswordStorageService } from '../services/passwordStorage.service' import { SSHKnownHostsService } from '../services/sshKnownHosts.service' import { SFTPSession } from './sftp' @@ -64,7 +64,7 @@ export class SSHSession { ssh: russh.SSHClient|russh.AuthenticatedSSHClient sftp?: russh.SFTP forwardedPorts: ForwardedPort[] = [] - jumpStream: any + jumpChannel: russh.Channel|null = null proxyCommandStream: SSHProxyStream|null = null savedPassword?: string get serviceMessage$ (): Observable { return this.serviceMessage } @@ -225,6 +225,9 @@ export class SSHSession { // this.proxyCommandStream.message$.subscribe(message => { // this.emitServiceMessage(colors.bgBlue.black(' Proxy ') + ' ' + message.trim()) // }) + } else if (this.jumpChannel) { + transport = await russh.SshTransport.newSshChannel(await this.jumpChannel.take()) + this.jumpChannel = null } else { transport = await russh.SshTransport.newSocket(`${this.profile.options.host.trim()}:${this.profile.options.port ?? 22}`) } @@ -314,9 +317,6 @@ export class SSHSession { // ssh.connect({ - // host: this.profile.options.host.trim(), - // port: this.profile.options.port ?? 22, - // sock: this.proxyCommandStream?.socket ?? this.jumpStream, // agent: this.agentPath, // agentForward: this.profile.options.agentForward && !!this.agentPath, // keepaliveInterval: this.profile.options.keepaliveInterval ?? 15000,