mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-08 13:30:02 +00:00
fixed #4608 - make ssh username setting optional
This commit is contained in:
parent
02b7b12ea5
commit
4c6227fccf
@ -25,6 +25,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
|
|||||||
label Username
|
label Username
|
||||||
input.form-control(
|
input.form-control(
|
||||||
type='text',
|
type='text',
|
||||||
|
placeholder='Ask every time',
|
||||||
[(ngModel)]='profile.options.user',
|
[(ngModel)]='profile.options.user',
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
|
|||||||
i.far.fa-keyboard
|
i.far.fa-keyboard
|
||||||
.m-0 Interactive
|
.m-0 Interactive
|
||||||
|
|
||||||
.form-line(*ngIf='!profile.options.auth || profile.options.auth === "password"')
|
.form-line(*ngIf='profile.options.user && (!profile.options.auth || profile.options.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
|
||||||
|
@ -44,12 +44,14 @@ export class SSHProfileSettingsComponent {
|
|||||||
this.profile.options.privateKeys ??= []
|
this.profile.options.privateKeys ??= []
|
||||||
|
|
||||||
this.useProxyCommand = !!this.profile.options.proxyCommand
|
this.useProxyCommand = !!this.profile.options.proxyCommand
|
||||||
|
if (this.profile.options.user) {
|
||||||
try {
|
try {
|
||||||
this.hasSavedPassword = !!await this.passwordStorage.loadPassword(this.profile)
|
this.hasSavedPassword = !!await this.passwordStorage.loadPassword(this.profile)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Could not check for saved password', e)
|
console.error('Could not check for saved password', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async setPassword () {
|
async setPassword () {
|
||||||
const modal = this.ngbModal.open(PromptModalComponent)
|
const modal = this.ngbModal.open(PromptModalComponent)
|
||||||
|
@ -81,7 +81,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
|||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
async setupOneSession (session: SSHSession): Promise<void> {
|
async setupOneSession (session: SSHSession, interactive: boolean): Promise<void> {
|
||||||
if (session.profile.options.jumpHost) {
|
if (session.profile.options.jumpHost) {
|
||||||
const jumpConnection: PartialProfile<SSHProfile>|null = this.config.store.profiles.find(x => x.id === session.profile.options.jumpHost)
|
const jumpConnection: PartialProfile<SSHProfile>|null = this.config.store.profiles.find(x => x.id === session.profile.options.jumpHost)
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
|||||||
this.profilesService.getConfigProxyForProfile(jumpConnection)
|
this.profilesService.getConfigProxyForProfile(jumpConnection)
|
||||||
)
|
)
|
||||||
|
|
||||||
await this.setupOneSession(jumpSession)
|
await this.setupOneSession(jumpSession, false)
|
||||||
|
|
||||||
this.attachSessionHandler(jumpSession.destroyed$, () => {
|
this.attachSessionHandler(jumpSession.destroyed$, () => {
|
||||||
if (session.open) {
|
if (session.open) {
|
||||||
@ -142,7 +142,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
|||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.ssh.connectSession(session)
|
await session.start(interactive)
|
||||||
this.stopSpinner()
|
this.stopSpinner()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.stopSpinner()
|
this.stopSpinner()
|
||||||
@ -189,12 +189,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
|||||||
this.setSession(session)
|
this.setSession(session)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.setupOneSession(session)
|
await this.setupOneSession(session, true)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n')
|
this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.session!.start()
|
|
||||||
this.session!.resize(this.size.columns, this.size.rows)
|
this.session!.resize(this.size.columns, this.size.rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,156 +1,29 @@
|
|||||||
import colors from 'ansi-colors'
|
|
||||||
import * as shellQuote from 'shell-quote'
|
import * as shellQuote from 'shell-quote'
|
||||||
import { Duplex } from 'stream'
|
import { Duplex } from 'stream'
|
||||||
import { Injectable, NgZone } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { Client } from 'ssh2'
|
|
||||||
import { spawn } from 'child_process'
|
import { spawn } from 'child_process'
|
||||||
import { ChildProcess } from 'node:child_process'
|
import { ChildProcess } from 'node:child_process'
|
||||||
import { Subject, Observable } from 'rxjs'
|
import { Subject, Observable } from 'rxjs'
|
||||||
import { Logger, LogService, ConfigService, NotificationsService, HostAppService, Platform, PlatformService } from 'tabby-core'
|
import { ConfigService, HostAppService, Platform, PlatformService } from 'tabby-core'
|
||||||
import { KeyboardInteractivePrompt, SSHSession } from '../session/ssh'
|
import { SSHSession } from '../session/ssh'
|
||||||
import { ForwardedPort } from '../session/forwards'
|
import { SSHProfile } from '../api'
|
||||||
import { ALGORITHM_BLACKLIST, SSHAlgorithmType, SSHProfile } from '../api'
|
|
||||||
import { PasswordStorageService } from './passwordStorage.service'
|
import { PasswordStorageService } from './passwordStorage.service'
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class SSHService {
|
export class SSHService {
|
||||||
private logger: Logger
|
|
||||||
private detectedWinSCPPath: string | null
|
private detectedWinSCPPath: string | null
|
||||||
|
|
||||||
private constructor (
|
private constructor (
|
||||||
log: LogService,
|
|
||||||
private zone: NgZone,
|
|
||||||
private passwordStorage: PasswordStorageService,
|
private passwordStorage: PasswordStorageService,
|
||||||
private notifications: NotificationsService,
|
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
hostApp: HostAppService,
|
hostApp: HostAppService,
|
||||||
private platform: PlatformService,
|
private platform: PlatformService,
|
||||||
) {
|
) {
|
||||||
this.logger = log.create('ssh')
|
|
||||||
if (hostApp.platform === Platform.Windows) {
|
if (hostApp.platform === Platform.Windows) {
|
||||||
this.detectedWinSCPPath = platform.getWinSCPPath()
|
this.detectedWinSCPPath = platform.getWinSCPPath()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async connectSession (session: SSHSession): Promise<void> {
|
|
||||||
const log = (s: any) => session.emitServiceMessage(s)
|
|
||||||
|
|
||||||
const ssh = new Client()
|
|
||||||
session.ssh = ssh
|
|
||||||
await session.init()
|
|
||||||
|
|
||||||
let connected = false
|
|
||||||
const algorithms = {}
|
|
||||||
for (const key of Object.values(SSHAlgorithmType)) {
|
|
||||||
algorithms[key] = session.profile.options.algorithms![key].filter(x => !ALGORITHM_BLACKLIST.includes(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
const resultPromise: Promise<void> = new Promise(async (resolve, reject) => {
|
|
||||||
ssh.on('ready', () => {
|
|
||||||
connected = true
|
|
||||||
if (session.savedPassword) {
|
|
||||||
this.passwordStorage.savePassword(session.profile, session.savedPassword)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const fw of session.profile.options.forwardedPorts ?? []) {
|
|
||||||
session.addPortForward(Object.assign(new ForwardedPort(), fw))
|
|
||||||
}
|
|
||||||
|
|
||||||
this.zone.run(resolve)
|
|
||||||
})
|
|
||||||
ssh.on('handshake', negotiated => {
|
|
||||||
this.logger.info('Handshake complete:', negotiated)
|
|
||||||
})
|
|
||||||
ssh.on('error', error => {
|
|
||||||
if (error.message === 'All configured authentication methods failed') {
|
|
||||||
this.passwordStorage.deletePassword(session.profile)
|
|
||||||
}
|
|
||||||
this.zone.run(() => {
|
|
||||||
if (connected) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
||||||
this.notifications.error(error.toString())
|
|
||||||
} else {
|
|
||||||
reject(error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
ssh.on('close', () => {
|
|
||||||
if (session.open) {
|
|
||||||
session.destroy()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
ssh.on('keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) => this.zone.run(async () => {
|
|
||||||
session.emitKeyboardInteractivePrompt(new KeyboardInteractivePrompt(
|
|
||||||
name,
|
|
||||||
instructions,
|
|
||||||
prompts.map(x => x.prompt),
|
|
||||||
finish,
|
|
||||||
))
|
|
||||||
}))
|
|
||||||
|
|
||||||
ssh.on('greeting', greeting => {
|
|
||||||
if (!session.profile.options.skipBanner) {
|
|
||||||
log('Greeting: ' + greeting)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
ssh.on('banner', banner => {
|
|
||||||
if (!session.profile.options.skipBanner) {
|
|
||||||
log(banner)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (session.profile.options.proxyCommand) {
|
|
||||||
session.emitServiceMessage(colors.bgBlue.black(' Proxy command ') + ` Using ${session.profile.options.proxyCommand}`)
|
|
||||||
session.proxyCommandStream = new ProxyCommandStream(session.profile.options.proxyCommand)
|
|
||||||
|
|
||||||
session.proxyCommandStream.on('error', err => {
|
|
||||||
session.emitServiceMessage(colors.bgRed.black(' X ') + ` ${err.message}`)
|
|
||||||
session.destroy()
|
|
||||||
})
|
|
||||||
|
|
||||||
session.proxyCommandStream.output$.subscribe((message: string) => {
|
|
||||||
session.emitServiceMessage(colors.bgBlue.black(' Proxy command ') + ' ' + message.trim())
|
|
||||||
})
|
|
||||||
|
|
||||||
await session.proxyCommandStream.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh.connect({
|
|
||||||
host: session.profile.options.host.trim(),
|
|
||||||
port: session.profile.options.port ?? 22,
|
|
||||||
sock: session.proxyCommandStream ?? session.jumpStream,
|
|
||||||
username: session.profile.options.user,
|
|
||||||
tryKeyboard: true,
|
|
||||||
agent: session.agentPath,
|
|
||||||
agentForward: session.profile.options.agentForward && !!session.agentPath,
|
|
||||||
keepaliveInterval: session.profile.options.keepaliveInterval ?? 15000,
|
|
||||||
keepaliveCountMax: session.profile.options.keepaliveCountMax,
|
|
||||||
readyTimeout: session.profile.options.readyTimeout,
|
|
||||||
hostVerifier: (digest: string) => {
|
|
||||||
log('Host key fingerprint:')
|
|
||||||
log(colors.white.bgBlack(' SHA256 ') + colors.bgBlackBright(' ' + digest + ' '))
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
hostHash: 'sha256' as any,
|
|
||||||
algorithms,
|
|
||||||
authHandler: (methodsLeft, partialSuccess, callback) => {
|
|
||||||
this.zone.run(async () => {
|
|
||||||
callback(await session.handleAuth(methodsLeft))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
this.notifications.error(e.message)
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultPromise
|
|
||||||
}
|
|
||||||
|
|
||||||
getWinSCPPath (): string|undefined {
|
getWinSCPPath (): string|undefined {
|
||||||
return this.detectedWinSCPPath ?? this.config.store.ssh.winSCPPath
|
return this.detectedWinSCPPath ?? this.config.store.ssh.winSCPPath
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import { ProxyCommandStream } from '../services/ssh.service'
|
|||||||
import { PasswordStorageService } from '../services/passwordStorage.service'
|
import { PasswordStorageService } from '../services/passwordStorage.service'
|
||||||
import { promisify } from 'util'
|
import { promisify } from 'util'
|
||||||
import { SFTPSession } from './sftp'
|
import { SFTPSession } from './sftp'
|
||||||
import { PortForwardType, SSHProfile } from '../api/interfaces'
|
import { ALGORITHM_BLACKLIST, SSHAlgorithmType, PortForwardType, SSHProfile } from '../api'
|
||||||
import { ForwardedPort } from './forwards'
|
import { ForwardedPort } from './forwards'
|
||||||
|
|
||||||
const WINDOWS_OPENSSH_AGENT_PIPE = '\\\\.\\pipe\\openssh-ssh-agent'
|
const WINDOWS_OPENSSH_AGENT_PIPE = '\\\\.\\pipe\\openssh-ssh-agent'
|
||||||
@ -60,6 +60,7 @@ export class SSHSession extends BaseSession {
|
|||||||
private serviceMessage = new Subject<string>()
|
private serviceMessage = new Subject<string>()
|
||||||
private keyboardInteractivePrompt = new Subject<KeyboardInteractivePrompt>()
|
private keyboardInteractivePrompt = new Subject<KeyboardInteractivePrompt>()
|
||||||
private keychainPasswordUsed = false
|
private keychainPasswordUsed = false
|
||||||
|
private authUsername: string|null = null
|
||||||
|
|
||||||
private passwordStorage: PasswordStorageService
|
private passwordStorage: PasswordStorageService
|
||||||
private ngbModal: NgbModal
|
private ngbModal: NgbModal
|
||||||
@ -157,9 +158,143 @@ export class SSHSession extends BaseSession {
|
|||||||
return new SFTPSession(this.sftp, this.injector)
|
return new SFTPSession(this.sftp, this.injector)
|
||||||
}
|
}
|
||||||
|
|
||||||
async start (): Promise<void> {
|
|
||||||
|
async start (interactive = true): Promise<void> {
|
||||||
|
const log = (s: any) => this.emitServiceMessage(s)
|
||||||
|
|
||||||
|
const ssh = new Client()
|
||||||
|
this.ssh = ssh
|
||||||
|
await this.init()
|
||||||
|
|
||||||
|
let connected = false
|
||||||
|
const algorithms = {}
|
||||||
|
for (const key of Object.values(SSHAlgorithmType)) {
|
||||||
|
algorithms[key] = this.profile.options.algorithms![key].filter(x => !ALGORITHM_BLACKLIST.includes(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultPromise: Promise<void> = new Promise(async (resolve, reject) => {
|
||||||
|
ssh.on('ready', () => {
|
||||||
|
connected = true
|
||||||
|
if (this.savedPassword) {
|
||||||
|
this.passwordStorage.savePassword(this.profile, this.savedPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const fw of this.profile.options.forwardedPorts ?? []) {
|
||||||
|
this.addPortForward(Object.assign(new ForwardedPort(), fw))
|
||||||
|
}
|
||||||
|
|
||||||
|
this.zone.run(resolve)
|
||||||
|
})
|
||||||
|
ssh.on('handshake', negotiated => {
|
||||||
|
this.logger.info('Handshake complete:', negotiated)
|
||||||
|
})
|
||||||
|
ssh.on('error', error => {
|
||||||
|
if (error.message === 'All configured authentication methods failed') {
|
||||||
|
this.passwordStorage.deletePassword(this.profile)
|
||||||
|
}
|
||||||
|
this.zone.run(() => {
|
||||||
|
if (connected) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||||
|
this.notifications.error(error.toString())
|
||||||
|
} else {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
ssh.on('close', () => {
|
||||||
|
if (this.open) {
|
||||||
|
this.destroy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ssh.on('keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) => this.zone.run(async () => {
|
||||||
|
this.emitKeyboardInteractivePrompt(new KeyboardInteractivePrompt(
|
||||||
|
name,
|
||||||
|
instructions,
|
||||||
|
prompts.map(x => x.prompt),
|
||||||
|
finish,
|
||||||
|
))
|
||||||
|
}))
|
||||||
|
|
||||||
|
ssh.on('greeting', greeting => {
|
||||||
|
if (!this.profile.options.skipBanner) {
|
||||||
|
log('Greeting: ' + greeting)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ssh.on('banner', banner => {
|
||||||
|
if (!this.profile.options.skipBanner) {
|
||||||
|
log(banner)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.profile.options.proxyCommand) {
|
||||||
|
this.emitServiceMessage(colors.bgBlue.black(' Proxy command ') + ` Using ${this.profile.options.proxyCommand}`)
|
||||||
|
this.proxyCommandStream = new ProxyCommandStream(this.profile.options.proxyCommand)
|
||||||
|
|
||||||
|
this.proxyCommandStream.on('error', err => {
|
||||||
|
this.emitServiceMessage(colors.bgRed.black(' X ') + ` ${err.message}`)
|
||||||
|
this.destroy()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.proxyCommandStream.output$.subscribe((message: string) => {
|
||||||
|
this.emitServiceMessage(colors.bgBlue.black(' Proxy command ') + ' ' + message.trim())
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.proxyCommandStream.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.authUsername ??= this.profile.options.user
|
||||||
|
if (!this.authUsername) {
|
||||||
|
const modal = this.ngbModal.open(PromptModalComponent)
|
||||||
|
modal.componentInstance.prompt = `Username for ${this.profile.options.host}`
|
||||||
|
const result = await modal.result
|
||||||
|
this.authUsername = result?.value ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh.connect({
|
||||||
|
host: this.profile.options.host.trim(),
|
||||||
|
port: this.profile.options.port ?? 22,
|
||||||
|
sock: this.proxyCommandStream ?? this.jumpStream,
|
||||||
|
username: this.authUsername ?? undefined,
|
||||||
|
tryKeyboard: true,
|
||||||
|
agent: this.agentPath,
|
||||||
|
agentForward: this.profile.options.agentForward && !!this.agentPath,
|
||||||
|
keepaliveInterval: this.profile.options.keepaliveInterval ?? 15000,
|
||||||
|
keepaliveCountMax: this.profile.options.keepaliveCountMax,
|
||||||
|
readyTimeout: this.profile.options.readyTimeout,
|
||||||
|
hostVerifier: (digest: string) => {
|
||||||
|
log('Host key fingerprint:')
|
||||||
|
log(colors.white.bgBlack(' SHA256 ') + colors.bgBlackBright(' ' + digest + ' '))
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
hostHash: 'sha256' as any,
|
||||||
|
algorithms,
|
||||||
|
authHandler: (methodsLeft, partialSuccess, callback) => {
|
||||||
|
this.zone.run(async () => {
|
||||||
|
const a = await this.handleAuth(methodsLeft)
|
||||||
|
console.warn(a)
|
||||||
|
callback(a)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
this.notifications.error(e.message)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
await resultPromise
|
||||||
|
|
||||||
this.open = true
|
this.open = true
|
||||||
|
|
||||||
|
if (!interactive) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.shell = await this.openShellChannel({ x11: this.profile.options.x11 })
|
this.shell = await this.openShellChannel({ x11: this.profile.options.x11 })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -292,26 +427,26 @@ export class SSHSession extends BaseSession {
|
|||||||
this.emitServiceMessage('Using preset password')
|
this.emitServiceMessage('Using preset password')
|
||||||
return {
|
return {
|
||||||
type: 'password',
|
type: 'password',
|
||||||
username: this.profile.options.user,
|
username: this.authUsername,
|
||||||
password: this.profile.options.password,
|
password: this.profile.options.password,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.keychainPasswordUsed) {
|
if (!this.keychainPasswordUsed && this.profile.options.user) {
|
||||||
const password = await this.passwordStorage.loadPassword(this.profile)
|
const password = await this.passwordStorage.loadPassword(this.profile)
|
||||||
if (password) {
|
if (password) {
|
||||||
this.emitServiceMessage('Trying saved password')
|
this.emitServiceMessage('Trying saved password')
|
||||||
this.keychainPasswordUsed = true
|
this.keychainPasswordUsed = true
|
||||||
return {
|
return {
|
||||||
type: 'password',
|
type: 'password',
|
||||||
username: this.profile.options.user,
|
username: this.authUsername,
|
||||||
password,
|
password,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const modal = this.ngbModal.open(PromptModalComponent)
|
const modal = this.ngbModal.open(PromptModalComponent)
|
||||||
modal.componentInstance.prompt = `Password for ${this.profile.options.user}@${this.profile.options.host}`
|
modal.componentInstance.prompt = `Password for ${this.authUsername}@${this.profile.options.host}`
|
||||||
modal.componentInstance.password = true
|
modal.componentInstance.password = true
|
||||||
modal.componentInstance.showRememberCheckbox = true
|
modal.componentInstance.showRememberCheckbox = true
|
||||||
|
|
||||||
@ -323,7 +458,7 @@ export class SSHSession extends BaseSession {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
type: 'password',
|
type: 'password',
|
||||||
username: this.profile.options.user,
|
username: this.authUsername,
|
||||||
password: result.value,
|
password: result.value,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -338,7 +473,7 @@ export class SSHSession extends BaseSession {
|
|||||||
const key = await this.loadPrivateKey(method.contents)
|
const key = await this.loadPrivateKey(method.contents)
|
||||||
return {
|
return {
|
||||||
type: 'publickey',
|
type: 'publickey',
|
||||||
username: this.profile.options.user,
|
username: this.authUsername,
|
||||||
key,
|
key,
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user