mirror of
https://github.com/Eugeny/tabby.git
synced 2024-11-27 10:42:35 +03:00
parent
f87efcf5bd
commit
44040ba54b
@ -44,6 +44,7 @@ export interface SSHConnection {
|
||||
warnOnClose?: boolean
|
||||
algorithms?: Record<string, string[]>
|
||||
proxyCommand?: string
|
||||
forwardedPorts?: ForwardedPortConfig[]
|
||||
}
|
||||
|
||||
export enum PortForwardType {
|
||||
@ -52,7 +53,15 @@ export enum PortForwardType {
|
||||
Dynamic = 'Dynamic',
|
||||
}
|
||||
|
||||
export class ForwardedPort {
|
||||
export interface ForwardedPortConfig {
|
||||
type: PortForwardType
|
||||
host: string
|
||||
port: number
|
||||
targetAddress: string
|
||||
targetPort: number
|
||||
}
|
||||
|
||||
export class ForwardedPort implements ForwardedPortConfig {
|
||||
type: PortForwardType
|
||||
host = '127.0.0.1'
|
||||
port: number
|
||||
|
@ -100,6 +100,15 @@
|
||||
button.btn.btn-secondary((click)='selectPrivateKey()')
|
||||
i.fas.fa-folder-open
|
||||
|
||||
li(ngbNavItem)
|
||||
a(ngbNavLink) Ports
|
||||
ng-template(ngbNavContent)
|
||||
ssh-port-forwarding-config(
|
||||
[model]='connection.forwardedPorts',
|
||||
(forwardAdded)='onForwardAdded($event)',
|
||||
(forwardRemoved)='onForwardRemoved($event)'
|
||||
)
|
||||
|
||||
li(ngbNavItem)
|
||||
a(ngbNavLink) Advanced
|
||||
ng-template(ngbNavContent)
|
||||
|
@ -6,7 +6,7 @@ import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'
|
||||
|
||||
import { ElectronService, HostAppService, ConfigService } from 'terminus-core'
|
||||
import { PasswordStorageService } from '../services/passwordStorage.service'
|
||||
import { SSHConnection, LoginScript, SSHAlgorithmType, ALGORITHM_BLACKLIST } from '../api'
|
||||
import { SSHConnection, LoginScript, ForwardedPortConfig, SSHAlgorithmType, ALGORITHM_BLACKLIST } from '../api'
|
||||
import { PromptModalComponent } from './promptModal.component'
|
||||
import { ALGORITHMS } from 'ssh2-streams/lib/constants'
|
||||
|
||||
@ -173,4 +173,13 @@ export class EditConnectionModalComponent {
|
||||
}
|
||||
this.connection.scripts.push({ expect: '', send: '' })
|
||||
}
|
||||
|
||||
onForwardAdded (fw: ForwardedPortConfig) {
|
||||
this.connection.forwardedPorts = this.connection.forwardedPorts ?? []
|
||||
this.connection.forwardedPorts.push(fw)
|
||||
}
|
||||
|
||||
onForwardRemoved (fw: ForwardedPortConfig) {
|
||||
this.connection.forwardedPorts = this.connection.forwardedPorts?.filter(x => x !== fw)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
.list-group-light.mb-3
|
||||
.list-group-item.d-flex.align-items-center(*ngFor='let fw of model')
|
||||
strong(*ngIf='fw.type === PortForwardType.Local') Local
|
||||
strong(*ngIf='fw.type === PortForwardType.Remote') Remote
|
||||
strong(*ngIf='fw.type === PortForwardType.Dynamic') Dynamic
|
||||
.ml-3 {{fw.host}}:{{fw.port}}
|
||||
.ml-2 →
|
||||
.ml-2(*ngIf='fw.type !== PortForwardType.Dynamic') {{fw.targetAddress}}:{{fw.targetPort}}
|
||||
.ml-2(*ngIf='fw.type === PortForwardType.Dynamic') SOCKS proxy
|
||||
button.btn.btn-link.ml-auto((click)='remove(fw)')
|
||||
i.fas.fa-trash-alt.mr-2
|
||||
span Remove
|
||||
|
||||
.input-group.mb-2(*ngIf='newForward.type === PortForwardType.Dynamic')
|
||||
input.form-control(type='text', [(ngModel)]='newForward.host')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.port')
|
||||
|
||||
.input-group.mb-2(*ngIf='newForward.type !== PortForwardType.Dynamic')
|
||||
input.form-control(type='text', [(ngModel)]='newForward.host')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.port')
|
||||
.input-group-append
|
||||
.input-group-text →
|
||||
input.form-control(type='text', [(ngModel)]='newForward.targetAddress')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.targetPort')
|
||||
|
||||
.d-flex
|
||||
.btn-group.mr-auto(
|
||||
[(ngModel)]='newForward.type',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Local'
|
||||
)
|
||||
| Local
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Remote'
|
||||
)
|
||||
| Remote
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Dynamic'
|
||||
)
|
||||
| Dynamic
|
||||
|
||||
button.btn.btn-primary((click)='addForward()')
|
||||
i.fas.fa-check.mr-2
|
||||
span Forward port
|
@ -0,0 +1,44 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core'
|
||||
import { ForwardedPortConfig, PortForwardType } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'ssh-port-forwarding-config',
|
||||
template: require('./sshPortForwardingConfig.component.pug'),
|
||||
})
|
||||
export class SSHPortForwardingConfigComponent {
|
||||
@Input() model: ForwardedPortConfig[]
|
||||
@Output() forwardAdded = new EventEmitter<ForwardedPortConfig>()
|
||||
@Output() forwardRemoved = new EventEmitter<ForwardedPortConfig>()
|
||||
newForward: ForwardedPortConfig
|
||||
PortForwardType = PortForwardType
|
||||
|
||||
constructor (
|
||||
) {
|
||||
this.reset()
|
||||
}
|
||||
|
||||
reset () {
|
||||
this.newForward = {
|
||||
type: PortForwardType.Local,
|
||||
host: '127.0.0.1',
|
||||
port: 8000,
|
||||
targetAddress: '127.0.0.1',
|
||||
targetPort: 80,
|
||||
}
|
||||
}
|
||||
|
||||
async addForward () {
|
||||
try {
|
||||
this.forwardAdded.emit(this.newForward)
|
||||
this.reset()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
remove (fw: ForwardedPortConfig) {
|
||||
this.forwardRemoved.emit(fw)
|
||||
}
|
||||
}
|
@ -2,64 +2,8 @@
|
||||
h5.m-0 Port forwarding
|
||||
|
||||
.modal-body.pt-0
|
||||
.list-group-light.mb-3
|
||||
.list-group-item.d-flex.align-items-center(*ngFor='let fw of session.forwardedPorts')
|
||||
strong(*ngIf='fw.type === PortForwardType.Local') Local
|
||||
strong(*ngIf='fw.type === PortForwardType.Remote') Remote
|
||||
strong(*ngIf='fw.type === PortForwardType.Dynamic') Dynamic
|
||||
.ml-3 {{fw.host}}:{{fw.port}}
|
||||
.ml-2 →
|
||||
.ml-2(*ngIf='fw.type !== PortForwardType.Dynamic') {{fw.targetAddress}}:{{fw.targetPort}}
|
||||
.ml-2(*ngIf='fw.type === PortForwardType.Dynamic') SOCKS proxy
|
||||
button.btn.btn-link.ml-auto((click)='remove(fw)')
|
||||
i.fas.fa-trash-alt.mr-2
|
||||
span Remove
|
||||
|
||||
.input-group.mb-2(*ngIf='newForward.type === PortForwardType.Dynamic')
|
||||
input.form-control(type='text', [(ngModel)]='newForward.host')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.port')
|
||||
|
||||
.input-group.mb-2(*ngIf='newForward.type !== PortForwardType.Dynamic')
|
||||
input.form-control(type='text', [(ngModel)]='newForward.host')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.port')
|
||||
.input-group-append
|
||||
.input-group-text →
|
||||
input.form-control(type='text', [(ngModel)]='newForward.targetAddress')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.targetPort')
|
||||
|
||||
.d-flex
|
||||
.btn-group.mr-auto(
|
||||
[(ngModel)]='newForward.type',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Local'
|
||||
)
|
||||
| Local
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Remote'
|
||||
)
|
||||
| Remote
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Dynamic'
|
||||
)
|
||||
| Dynamic
|
||||
|
||||
button.btn.btn-primary((click)='addForward()')
|
||||
i.fas.fa-check.mr-2
|
||||
span Forward port
|
||||
ssh-port-forwarding-config(
|
||||
[model]='session.forwardedPorts',
|
||||
(forwardAdded)='onForwardAdded($event)',
|
||||
(forwardRemoved)='onForwardRemoved($event)'
|
||||
)
|
||||
|
@ -1,43 +1,21 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ForwardedPort, PortForwardType, SSHSession } from '../api'
|
||||
import { ForwardedPort, ForwardedPortConfig, SSHSession } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
template: require('./sshPortForwardingModal.component.pug'),
|
||||
// styles: [require('./sshPortForwardingModal.component.scss')],
|
||||
})
|
||||
export class SSHPortForwardingModalComponent {
|
||||
@Input() session: SSHSession
|
||||
newForward = new ForwardedPort()
|
||||
PortForwardType = PortForwardType
|
||||
|
||||
constructor (
|
||||
public modalInstance: NgbActiveModal,
|
||||
) {
|
||||
this.reset()
|
||||
onForwardAdded (fw: ForwardedPortConfig) {
|
||||
const newForward = new ForwardedPort()
|
||||
Object.assign(newForward, fw)
|
||||
this.session.addPortForward(newForward)
|
||||
}
|
||||
|
||||
reset () {
|
||||
this.newForward = new ForwardedPort()
|
||||
this.newForward.type = PortForwardType.Local
|
||||
this.newForward.host = '127.0.0.1'
|
||||
this.newForward.port = 8000
|
||||
this.newForward.targetAddress = '127.0.0.1'
|
||||
this.newForward.targetPort = 80
|
||||
}
|
||||
|
||||
async addForward () {
|
||||
try {
|
||||
await this.session.addPortForward(this.newForward)
|
||||
this.reset()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
remove (fw: ForwardedPort) {
|
||||
this.session.removePortForward(fw)
|
||||
onForwardRemoved (fw: ForwardedPortConfig) {
|
||||
this.session.removePortForward(fw as ForwardedPort)
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import TerminusTerminalModule from 'terminus-terminal'
|
||||
|
||||
import { EditConnectionModalComponent } from './components/editConnectionModal.component'
|
||||
import { SSHPortForwardingModalComponent } from './components/sshPortForwardingModal.component'
|
||||
import { SSHPortForwardingConfigComponent } from './components/sshPortForwardingConfig.component'
|
||||
import { PromptModalComponent } from './components/promptModal.component'
|
||||
import { SSHSettingsTabComponent } from './components/sshSettingsTab.component'
|
||||
import { SSHTabComponent } from './components/sshTab.component'
|
||||
@ -49,6 +50,7 @@ import { WinSCPContextMenu } from './winSCPIntegration'
|
||||
EditConnectionModalComponent,
|
||||
PromptModalComponent,
|
||||
SSHPortForwardingModalComponent,
|
||||
SSHPortForwardingConfigComponent,
|
||||
SSHSettingsTabComponent,
|
||||
SSHTabComponent,
|
||||
],
|
||||
|
@ -14,7 +14,7 @@ import * as sshpk from 'sshpk'
|
||||
import { Subject, Observable } from 'rxjs'
|
||||
import { HostAppService, Platform, Logger, LogService, ElectronService, AppService, SelectorOption, ConfigService, NotificationsService } from 'terminus-core'
|
||||
import { SettingsTabComponent } from 'terminus-settings'
|
||||
import { ALGORITHM_BLACKLIST, SSHConnection, SSHSession } from '../api'
|
||||
import { ALGORITHM_BLACKLIST, ForwardedPort, SSHConnection, SSHSession } from '../api'
|
||||
import { PromptModalComponent } from '../components/promptModal.component'
|
||||
import { PasswordStorageService } from './passwordStorage.service'
|
||||
import { SSHTabComponent } from '../components/sshTab.component'
|
||||
@ -164,6 +164,11 @@ export class SSHService {
|
||||
if (savedPassword) {
|
||||
this.passwordStorage.savePassword(session.connection, savedPassword)
|
||||
}
|
||||
|
||||
for (const fw of session.connection.forwardedPorts ?? []) {
|
||||
session.addPortForward(Object.assign(new ForwardedPort(), fw))
|
||||
}
|
||||
|
||||
this.zone.run(resolve)
|
||||
})
|
||||
ssh.on('error', error => {
|
||||
|
Loading…
Reference in New Issue
Block a user