mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-28 07:19:54 +00:00
more explicit SSH auth options and agent forwarding - fixes #2284, fixes #2511, fixes #2717, fixes #2184
This commit is contained in:
parent
34752ed69e
commit
da21895e40
@ -24,6 +24,7 @@ export interface SSHConnection {
|
|||||||
host: string
|
host: string
|
||||||
port: number
|
port: number
|
||||||
user: string
|
user: string
|
||||||
|
auth?: null|'password'|'publicKey'|'agent'|'keyboardInteractive'
|
||||||
password?: string
|
password?: string
|
||||||
privateKey?: string
|
privateKey?: string
|
||||||
group: string | null
|
group: string | null
|
||||||
@ -36,7 +37,6 @@ export interface SSHConnection {
|
|||||||
skipBanner?: boolean
|
skipBanner?: boolean
|
||||||
disableDynamicTitle?: boolean
|
disableDynamicTitle?: boolean
|
||||||
jumpHost?: string
|
jumpHost?: string
|
||||||
agentForward?: boolean
|
|
||||||
|
|
||||||
algorithms?: {[t: string]: string[]}
|
algorithms?: {[t: string]: string[]}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,34 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
.form-line
|
.form-line
|
||||||
|
.header
|
||||||
|
.title Authentication
|
||||||
|
.btn-group.w-100(
|
||||||
|
[(ngModel)]='connection.auth',
|
||||||
|
ngbRadioGroup
|
||||||
|
)
|
||||||
|
label.btn.btn-outline-secondary(ngbButtonLabel)
|
||||||
|
input(type='radio', ngbButton, [value]='null')
|
||||||
|
i.far.fa-lightbulb
|
||||||
|
.m-0 Auto
|
||||||
|
label.btn.btn-outline-secondary(ngbButtonLabel)
|
||||||
|
input(type='radio', ngbButton, [value]='"password"')
|
||||||
|
i.fas.fa-font
|
||||||
|
.m-0 Password
|
||||||
|
label.btn.btn-outline-secondary(ngbButtonLabel)
|
||||||
|
input(type='radio', ngbButton, [value]='"publicKey"')
|
||||||
|
i.fas.fa-key
|
||||||
|
.m-0 Key
|
||||||
|
label.btn.btn-outline-secondary(ngbButtonLabel)
|
||||||
|
input(type='radio', ngbButton, [value]='"agent"')
|
||||||
|
i.fas.fa-user-secret
|
||||||
|
.m-0 Agent
|
||||||
|
label.btn.btn-outline-secondary(ngbButtonLabel)
|
||||||
|
input(type='radio', ngbButton, [value]='"keyboardInteractive"')
|
||||||
|
i.far.fa-keyboard
|
||||||
|
.m-0 Interactive
|
||||||
|
|
||||||
|
.form-line(*ngIf='!connection.auth || connection.auth === "password"')
|
||||||
.header
|
.header
|
||||||
.title Password
|
.title Password
|
||||||
.description(*ngIf='!hasSavedPassword') Save a password in the keychain
|
.description(*ngIf='!hasSavedPassword') Save a password in the keychain
|
||||||
@ -54,7 +82,7 @@
|
|||||||
i.fas.fa-trash-alt
|
i.fas.fa-trash-alt
|
||||||
span Forget
|
span Forget
|
||||||
|
|
||||||
.form-line
|
.form-line(*ngIf='!connection.auth || connection.auth === "publicKey"')
|
||||||
.header
|
.header
|
||||||
.title Private key
|
.title Private key
|
||||||
.description Path to the private key file
|
.description Path to the private key file
|
||||||
@ -83,11 +111,6 @@
|
|||||||
.title X11 forwarding
|
.title X11 forwarding
|
||||||
toggle([(ngModel)]='connection.x11')
|
toggle([(ngModel)]='connection.x11')
|
||||||
|
|
||||||
.form-line
|
|
||||||
.header
|
|
||||||
.title Allow Agent Forwarding
|
|
||||||
toggle([(ngModel)]='connection.agentForward')
|
|
||||||
|
|
||||||
.form-line
|
.form-line
|
||||||
.header
|
.header
|
||||||
.title Tab color
|
.title Tab color
|
||||||
|
@ -49,6 +49,7 @@ export class EditConnectionModalComponent {
|
|||||||
this.hasSavedPassword = !!await this.passwordStorage.loadPassword(this.connection)
|
this.hasSavedPassword = !!await this.passwordStorage.loadPassword(this.connection)
|
||||||
this.connection.algorithms = this.connection.algorithms || {}
|
this.connection.algorithms = this.connection.algorithms || {}
|
||||||
this.connection.scripts = this.connection.scripts || []
|
this.connection.scripts = this.connection.scripts || []
|
||||||
|
this.connection.auth = this.connection.auth || null
|
||||||
|
|
||||||
for (const k of Object.values(SSHAlgorithmType)) {
|
for (const k of Object.values(SSHAlgorithmType)) {
|
||||||
if (!this.connection.algorithms[k]) {
|
if (!this.connection.algorithms[k]) {
|
||||||
|
@ -160,6 +160,9 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async canClose (): Promise<boolean> {
|
async canClose (): Promise<boolean> {
|
||||||
|
if (!this.session?.open) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return (await this.electron.showMessageBox(
|
return (await this.electron.showMessageBox(
|
||||||
this.hostApp.getWindow(),
|
this.hostApp.getWindow(),
|
||||||
{
|
{
|
||||||
|
@ -165,8 +165,13 @@ export class SSHService {
|
|||||||
const modal = this.ngbModal.open(PromptModalComponent)
|
const modal = this.ngbModal.open(PromptModalComponent)
|
||||||
modal.componentInstance.prompt = prompt.prompt
|
modal.componentInstance.prompt = prompt.prompt
|
||||||
modal.componentInstance.password = !prompt.echo
|
modal.componentInstance.password = !prompt.echo
|
||||||
const result = await modal.result
|
|
||||||
results.push(result ? result.value : '')
|
try {
|
||||||
|
const result = await modal.result
|
||||||
|
results.push(result ? result.value : '')
|
||||||
|
} catch {
|
||||||
|
results.push('')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finish(results)
|
finish(results)
|
||||||
}))
|
}))
|
||||||
@ -194,6 +199,29 @@ export class SSHService {
|
|||||||
agent = process.env.SSH_AUTH_SOCK as string
|
agent = process.env.SSH_AUTH_SOCK as string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const authMethodsLeft = ['none']
|
||||||
|
if (!session.connection.auth || session.connection.auth === 'password') {
|
||||||
|
authMethodsLeft.push('password')
|
||||||
|
}
|
||||||
|
if (!session.connection.auth || session.connection.auth === 'publicKey') {
|
||||||
|
if (!privateKey) {
|
||||||
|
log('\r\nPrivate key auth selected, but no key is loaded\r\n')
|
||||||
|
} else {
|
||||||
|
authMethodsLeft.push('publickey')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!session.connection.auth || session.connection.auth === 'agent') {
|
||||||
|
if (!agent) {
|
||||||
|
log('\r\nAgent auth selected, but no running agent is detected\r\n')
|
||||||
|
} else {
|
||||||
|
authMethodsLeft.push('agent')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!session.connection.auth || session.connection.auth === 'keyboardInteractive') {
|
||||||
|
authMethodsLeft.push('keyboard-interactive')
|
||||||
|
}
|
||||||
|
authMethodsLeft.push('hostbased')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ssh.connect({
|
ssh.connect({
|
||||||
host: session.connection.host,
|
host: session.connection.host,
|
||||||
@ -202,8 +230,8 @@ export class SSHService {
|
|||||||
password: session.connection.privateKey ? undefined : '',
|
password: session.connection.privateKey ? undefined : '',
|
||||||
privateKey: privateKey || undefined,
|
privateKey: privateKey || undefined,
|
||||||
tryKeyboard: true,
|
tryKeyboard: true,
|
||||||
agent: session.connection.agentForward && agent || undefined,
|
agent: agent || undefined,
|
||||||
agentForward: session.connection.agentForward && !!agent,
|
agentForward: (!session.connection.auth || session.connection.auth === 'agent') && !!agent,
|
||||||
keepaliveInterval: session.connection.keepaliveInterval,
|
keepaliveInterval: session.connection.keepaliveInterval,
|
||||||
keepaliveCountMax: session.connection.keepaliveCountMax,
|
keepaliveCountMax: session.connection.keepaliveCountMax,
|
||||||
readyTimeout: session.connection.readyTimeout,
|
readyTimeout: session.connection.readyTimeout,
|
||||||
@ -215,7 +243,21 @@ export class SSHService {
|
|||||||
hostHash: 'sha256' as any,
|
hostHash: 'sha256' as any,
|
||||||
algorithms: session.connection.algorithms,
|
algorithms: session.connection.algorithms,
|
||||||
sock: session.jumpStream,
|
sock: session.jumpStream,
|
||||||
})
|
authHandler: methodsLeft => {
|
||||||
|
while (true) {
|
||||||
|
let method = authMethodsLeft.shift()
|
||||||
|
if (!method) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (methodsLeft && !methodsLeft.includes(method) && method !== 'agent') {
|
||||||
|
// Agent can still be used even if not in methodsLeft
|
||||||
|
this.logger.info('Server does not support auth method', method)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return method
|
||||||
|
}
|
||||||
|
},
|
||||||
|
} as any)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.toastr.error(e.message)
|
this.toastr.error(e.message)
|
||||||
reject(e)
|
reject(e)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user