mirror of
https://github.com/Eugeny/tabby.git
synced 2024-12-02 02:23:12 +03:00
ssh jump hosts - fixes #737
This commit is contained in:
parent
129a7c1a09
commit
7f55d6f1e2
@ -35,6 +35,7 @@ export interface SSHConnection {
|
||||
x11?: boolean
|
||||
skipBanner?: boolean
|
||||
disableDynamicTitle?: boolean
|
||||
jumpHost?: string
|
||||
|
||||
algorithms?: {[t: string]: string[]}
|
||||
}
|
||||
@ -80,6 +81,7 @@ export class SSHSession extends BaseSession {
|
||||
ssh: Client
|
||||
forwardedPorts: ForwardedPort[] = []
|
||||
logger: Logger
|
||||
jumpStream: any
|
||||
|
||||
get serviceMessage$ (): Observable<string> { return this.serviceMessage }
|
||||
private serviceMessage = new Subject<string>()
|
||||
|
@ -70,6 +70,12 @@
|
||||
ngb-tab(id='advanced')
|
||||
ng-template(ngbTabTitle) Advanced
|
||||
ng-template(ngbTabContent)
|
||||
.form-line
|
||||
.header
|
||||
.title Jump host
|
||||
select.form-control([(ngModel)]='connection.jumpHost')
|
||||
option([value]='x.name', *ngFor='let x of config.store.ssh.connections') {{x.name}}
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title X11 forwarding
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component } from '@angular/core'
|
||||
import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ElectronService, HostAppService } from 'terminus-core'
|
||||
import { ElectronService, HostAppService, ConfigService } from 'terminus-core'
|
||||
import { PasswordStorageService } from '../services/passwordStorage.service'
|
||||
import { SSHConnection, LoginScript, SSHAlgorithmType } from '../api'
|
||||
import { PromptModalComponent } from './promptModal.component'
|
||||
@ -20,6 +20,7 @@ export class EditConnectionModalComponent {
|
||||
algorithms: {[id: string]: {[a: string]: boolean}} = {}
|
||||
|
||||
constructor (
|
||||
public config: ConfigService,
|
||||
private modalInstance: NgbActiveModal,
|
||||
private electron: ElectronService,
|
||||
private hostApp: HostAppService,
|
||||
|
@ -10,6 +10,7 @@ import { SSHConnection, SSHSession } from '../api'
|
||||
import { SSHPortForwardingModalComponent } from './sshPortForwardingModal.component'
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'ssh-tab',
|
||||
@ -20,6 +21,7 @@ import { Subscription } from 'rxjs'
|
||||
export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
connection: SSHConnection
|
||||
session: SSHSession
|
||||
private sessionStack: SSHSession[] = []
|
||||
private homeEndSubscription: Subscription
|
||||
|
||||
constructor (
|
||||
@ -60,19 +62,40 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
})
|
||||
}
|
||||
|
||||
async initializeSession (): Promise<void> {
|
||||
if (!this.connection) {
|
||||
this.logger.error('No SSH connection info supplied')
|
||||
return
|
||||
async setupOneSession (session: SSHSession): Promise<void> {
|
||||
if (session.connection.jumpHost) {
|
||||
const jumpConnection = this.config.store.ssh.connections.find(x => x.name === session.connection.jumpHost)
|
||||
const jumpSession = this.ssh.createSession(jumpConnection)
|
||||
|
||||
await this.setupOneSession(jumpSession)
|
||||
|
||||
jumpSession.destroyed$.subscribe(() => session.destroy())
|
||||
|
||||
session.jumpStream = await new Promise((resolve, reject) => jumpSession.ssh.forwardOut(
|
||||
'127.0.0.1', 0, session.connection.host, session.connection.port,
|
||||
(err, stream) => {
|
||||
if (err) {
|
||||
jumpSession.emitServiceMessage(colors.bgRed.black(' X ') + ` Could not set up port forward on ${jumpConnection.name}`)
|
||||
return reject(err)
|
||||
}
|
||||
resolve(stream)
|
||||
}
|
||||
))
|
||||
|
||||
session.jumpStream.on('close', () => {
|
||||
jumpSession.destroy()
|
||||
})
|
||||
|
||||
this.sessionStack.push(session)
|
||||
}
|
||||
|
||||
this.session = this.ssh.createSession(this.connection)
|
||||
this.session.serviceMessage$.subscribe(msg => {
|
||||
|
||||
session.serviceMessage$.subscribe(msg => {
|
||||
this.write('\r\n' + colors.black.bgWhite(' SSH ') + ' ' + msg + '\r\n')
|
||||
this.session.resize(this.size.columns, this.size.rows)
|
||||
session.resize(this.size.columns, this.size.rows)
|
||||
})
|
||||
this.attachSessionHandlers()
|
||||
this.write(`Connecting to ${this.connection.host}`)
|
||||
|
||||
this.write('\r\n' + colors.black.bgCyan(' SSH ') + ` Connecting to ${session.connection.host}\r\n`)
|
||||
|
||||
const spinner = new Spinner({
|
||||
text: 'Connecting',
|
||||
@ -84,7 +107,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
spinner.start()
|
||||
|
||||
try {
|
||||
await this.ssh.connectSession(this.session, (message: string) => {
|
||||
await this.ssh.connectSession(session, (message: string) => {
|
||||
spinner.stop(true)
|
||||
this.write(message + '\r\n')
|
||||
spinner.start()
|
||||
@ -95,6 +118,20 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
async initializeSession (): Promise<void> {
|
||||
if (!this.connection) {
|
||||
this.logger.error('No SSH connection info supplied')
|
||||
return
|
||||
}
|
||||
|
||||
this.session = this.ssh.createSession(this.connection)
|
||||
|
||||
await this.setupOneSession(this.session)
|
||||
|
||||
this.attachSessionHandlers()
|
||||
|
||||
await this.session.start()
|
||||
this.session.resize(this.size.columns, this.size.rows)
|
||||
}
|
||||
|
@ -151,6 +151,12 @@ export class SSHService {
|
||||
}
|
||||
})
|
||||
})
|
||||
ssh.on('close', () => {
|
||||
if (session.open) {
|
||||
session.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
ssh.on('keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) => this.zone.run(async () => {
|
||||
log(colors.bgBlackBright(' ') + ` Keyboard-interactive auth requested: ${name}`)
|
||||
this.logger.info('Keyboard-interactive auth:', name, instructions, instructionsLang)
|
||||
@ -211,6 +217,7 @@ export class SSHService {
|
||||
},
|
||||
hostHash: 'sha256' as any,
|
||||
algorithms: session.connection.algorithms,
|
||||
sock: session.jumpStream,
|
||||
})
|
||||
} catch (e) {
|
||||
this.toastr.error(e.message)
|
||||
|
Loading…
Reference in New Issue
Block a user