mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-23 12:59:54 +00:00
parent
f87efcf5bd
commit
44040ba54b
@ -44,6 +44,7 @@ export interface SSHConnection {
|
|||||||
warnOnClose?: boolean
|
warnOnClose?: boolean
|
||||||
algorithms?: Record<string, string[]>
|
algorithms?: Record<string, string[]>
|
||||||
proxyCommand?: string
|
proxyCommand?: string
|
||||||
|
forwardedPorts?: ForwardedPortConfig[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum PortForwardType {
|
export enum PortForwardType {
|
||||||
@ -52,7 +53,15 @@ export enum PortForwardType {
|
|||||||
Dynamic = 'Dynamic',
|
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
|
type: PortForwardType
|
||||||
host = '127.0.0.1'
|
host = '127.0.0.1'
|
||||||
port: number
|
port: number
|
||||||
|
@ -100,6 +100,15 @@
|
|||||||
button.btn.btn-secondary((click)='selectPrivateKey()')
|
button.btn.btn-secondary((click)='selectPrivateKey()')
|
||||||
i.fas.fa-folder-open
|
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)
|
li(ngbNavItem)
|
||||||
a(ngbNavLink) Advanced
|
a(ngbNavLink) Advanced
|
||||||
ng-template(ngbNavContent)
|
ng-template(ngbNavContent)
|
||||||
|
@ -6,7 +6,7 @@ import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'
|
|||||||
|
|
||||||
import { ElectronService, HostAppService, ConfigService } from 'terminus-core'
|
import { ElectronService, HostAppService, ConfigService } from 'terminus-core'
|
||||||
import { PasswordStorageService } from '../services/passwordStorage.service'
|
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 { PromptModalComponent } from './promptModal.component'
|
||||||
import { ALGORITHMS } from 'ssh2-streams/lib/constants'
|
import { ALGORITHMS } from 'ssh2-streams/lib/constants'
|
||||||
|
|
||||||
@ -173,4 +173,13 @@ export class EditConnectionModalComponent {
|
|||||||
}
|
}
|
||||||
this.connection.scripts.push({ expect: '', send: '' })
|
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
|
h5.m-0 Port forwarding
|
||||||
|
|
||||||
.modal-body.pt-0
|
.modal-body.pt-0
|
||||||
.list-group-light.mb-3
|
ssh-port-forwarding-config(
|
||||||
.list-group-item.d-flex.align-items-center(*ngFor='let fw of session.forwardedPorts')
|
[model]='session.forwardedPorts',
|
||||||
strong(*ngIf='fw.type === PortForwardType.Local') Local
|
(forwardAdded)='onForwardAdded($event)',
|
||||||
strong(*ngIf='fw.type === PortForwardType.Remote') Remote
|
(forwardRemoved)='onForwardRemoved($event)'
|
||||||
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
|
|
||||||
|
@ -1,43 +1,21 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Component, Input } from '@angular/core'
|
import { Component, Input } from '@angular/core'
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
import { ForwardedPort, ForwardedPortConfig, SSHSession } from '../api'
|
||||||
import { ForwardedPort, PortForwardType, SSHSession } from '../api'
|
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Component({
|
@Component({
|
||||||
template: require('./sshPortForwardingModal.component.pug'),
|
template: require('./sshPortForwardingModal.component.pug'),
|
||||||
// styles: [require('./sshPortForwardingModal.component.scss')],
|
|
||||||
})
|
})
|
||||||
export class SSHPortForwardingModalComponent {
|
export class SSHPortForwardingModalComponent {
|
||||||
@Input() session: SSHSession
|
@Input() session: SSHSession
|
||||||
newForward = new ForwardedPort()
|
|
||||||
PortForwardType = PortForwardType
|
|
||||||
|
|
||||||
constructor (
|
onForwardAdded (fw: ForwardedPortConfig) {
|
||||||
public modalInstance: NgbActiveModal,
|
const newForward = new ForwardedPort()
|
||||||
) {
|
Object.assign(newForward, fw)
|
||||||
this.reset()
|
this.session.addPortForward(newForward)
|
||||||
}
|
}
|
||||||
|
|
||||||
reset () {
|
onForwardRemoved (fw: ForwardedPortConfig) {
|
||||||
this.newForward = new ForwardedPort()
|
this.session.removePortForward(fw as 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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import TerminusTerminalModule from 'terminus-terminal'
|
|||||||
|
|
||||||
import { EditConnectionModalComponent } from './components/editConnectionModal.component'
|
import { EditConnectionModalComponent } from './components/editConnectionModal.component'
|
||||||
import { SSHPortForwardingModalComponent } from './components/sshPortForwardingModal.component'
|
import { SSHPortForwardingModalComponent } from './components/sshPortForwardingModal.component'
|
||||||
|
import { SSHPortForwardingConfigComponent } from './components/sshPortForwardingConfig.component'
|
||||||
import { PromptModalComponent } from './components/promptModal.component'
|
import { PromptModalComponent } from './components/promptModal.component'
|
||||||
import { SSHSettingsTabComponent } from './components/sshSettingsTab.component'
|
import { SSHSettingsTabComponent } from './components/sshSettingsTab.component'
|
||||||
import { SSHTabComponent } from './components/sshTab.component'
|
import { SSHTabComponent } from './components/sshTab.component'
|
||||||
@ -49,6 +50,7 @@ import { WinSCPContextMenu } from './winSCPIntegration'
|
|||||||
EditConnectionModalComponent,
|
EditConnectionModalComponent,
|
||||||
PromptModalComponent,
|
PromptModalComponent,
|
||||||
SSHPortForwardingModalComponent,
|
SSHPortForwardingModalComponent,
|
||||||
|
SSHPortForwardingConfigComponent,
|
||||||
SSHSettingsTabComponent,
|
SSHSettingsTabComponent,
|
||||||
SSHTabComponent,
|
SSHTabComponent,
|
||||||
],
|
],
|
||||||
|
@ -14,7 +14,7 @@ import * as sshpk from 'sshpk'
|
|||||||
import { Subject, Observable } from 'rxjs'
|
import { Subject, Observable } from 'rxjs'
|
||||||
import { HostAppService, Platform, Logger, LogService, ElectronService, AppService, SelectorOption, ConfigService, NotificationsService } from 'terminus-core'
|
import { HostAppService, Platform, Logger, LogService, ElectronService, AppService, SelectorOption, ConfigService, NotificationsService } from 'terminus-core'
|
||||||
import { SettingsTabComponent } from 'terminus-settings'
|
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 { PromptModalComponent } from '../components/promptModal.component'
|
||||||
import { PasswordStorageService } from './passwordStorage.service'
|
import { PasswordStorageService } from './passwordStorage.service'
|
||||||
import { SSHTabComponent } from '../components/sshTab.component'
|
import { SSHTabComponent } from '../components/sshTab.component'
|
||||||
@ -164,6 +164,11 @@ export class SSHService {
|
|||||||
if (savedPassword) {
|
if (savedPassword) {
|
||||||
this.passwordStorage.savePassword(session.connection, 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)
|
this.zone.run(resolve)
|
||||||
})
|
})
|
||||||
ssh.on('error', error => {
|
ssh.on('error', error => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user