mirror of
https://github.com/eugeny/tabby
synced 2025-10-29 21:47:03 +00:00
Pr askeverytime fix https://github.com/Eugeny/tabby/issues/10681 (#10786)
This commit is contained in:
committed by
GitHub
parent
6da2259dc3
commit
264f1cbe85
@@ -44,7 +44,7 @@ export class AutoSudoPasswordMiddleware extends SessionMiddleware {
|
||||
|
||||
async handlePrompt (username: string): Promise<void> {
|
||||
console.log(`Detected sudo prompt for user: ${username}`)
|
||||
const pw = await this.ps.loadPassword(this.profile)
|
||||
const pw = await this.ps.loadPassword(this.profile, username)
|
||||
if (pw) {
|
||||
this.outputToTerminal.next(Buffer.from(this.pasteHint))
|
||||
this.pendingPasswordToPaste = pw
|
||||
@@ -55,7 +55,7 @@ export class AutoSudoPasswordMiddleware extends SessionMiddleware {
|
||||
if (this.profile.options.user !== username) {
|
||||
return null
|
||||
}
|
||||
return this.ps.loadPassword(this.profile)
|
||||
return this.ps.loadPassword(this.profile, username)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,33 +10,45 @@ export const VAULT_SECRET_TYPE_PASSPHRASE = 'ssh:key-passphrase'
|
||||
export class PasswordStorageService {
|
||||
constructor (private vault: VaultService) { }
|
||||
|
||||
async savePassword (profile: SSHProfile, password: string): Promise<void> {
|
||||
async savePassword (profile: SSHProfile, password: string, username?: string): Promise<void> {
|
||||
const account = username ?? profile.options.user
|
||||
if (this.vault.isEnabled()) {
|
||||
const key = this.getVaultKeyForConnection(profile)
|
||||
const key = this.getVaultKeyForConnection(profile, account)
|
||||
this.vault.addSecret({ type: VAULT_SECRET_TYPE_PASSWORD, key, value: password })
|
||||
} else {
|
||||
if (!account) {
|
||||
return
|
||||
}
|
||||
const key = this.getKeytarKeyForConnection(profile)
|
||||
return keytar.setPassword(key, profile.options.user, password)
|
||||
return keytar.setPassword(key, account, password)
|
||||
}
|
||||
}
|
||||
|
||||
async deletePassword (profile: SSHProfile): Promise<void> {
|
||||
async deletePassword (profile: SSHProfile, username?: string): Promise<void> {
|
||||
const account = username ?? profile.options.user
|
||||
if (this.vault.isEnabled()) {
|
||||
const key = this.getVaultKeyForConnection(profile)
|
||||
const key = this.getVaultKeyForConnection(profile, account)
|
||||
this.vault.removeSecret(VAULT_SECRET_TYPE_PASSWORD, key)
|
||||
} else {
|
||||
if (!account) {
|
||||
return
|
||||
}
|
||||
const key = this.getKeytarKeyForConnection(profile)
|
||||
await keytar.deletePassword(key, profile.options.user)
|
||||
await keytar.deletePassword(key, account)
|
||||
}
|
||||
}
|
||||
|
||||
async loadPassword (profile: SSHProfile): Promise<string|null> {
|
||||
async loadPassword (profile: SSHProfile, username?: string): Promise<string|null> {
|
||||
const account = username ?? profile.options.user
|
||||
if (this.vault.isEnabled()) {
|
||||
const key = this.getVaultKeyForConnection(profile)
|
||||
const key = this.getVaultKeyForConnection(profile, account)
|
||||
return (await this.vault.getSecret(VAULT_SECRET_TYPE_PASSWORD, key))?.value ?? null
|
||||
} else {
|
||||
if (!account) {
|
||||
return null
|
||||
}
|
||||
const key = this.getKeytarKeyForConnection(profile)
|
||||
return keytar.getPassword(key, profile.options.user)
|
||||
return keytar.getPassword(key, account)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,9 +94,9 @@ export class PasswordStorageService {
|
||||
return `ssh-private-key:${id}`
|
||||
}
|
||||
|
||||
private getVaultKeyForConnection (profile: SSHProfile) {
|
||||
private getVaultKeyForConnection (profile: SSHProfile, username?: string) {
|
||||
return {
|
||||
user: profile.options.user,
|
||||
user: username ?? profile.options.user,
|
||||
host: profile.options.host,
|
||||
port: profile.options.port,
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export class SSHService {
|
||||
|
||||
async getWinSCPURI (profile: SSHProfile, cwd?: string, username?: string): Promise<string> {
|
||||
let uri = `scp://${username ?? profile.options.user}`
|
||||
const password = await this.passwordStorage.loadPassword(profile)
|
||||
const password = await this.passwordStorage.loadPassword(profile, username)
|
||||
if (password) {
|
||||
uri += ':' + encodeURIComponent(password)
|
||||
}
|
||||
|
||||
@@ -200,15 +200,10 @@ export class SSHSession {
|
||||
if (this.profile.options.password) {
|
||||
this.allAuthMethods.push({ type: 'saved-password', password: this.profile.options.password })
|
||||
}
|
||||
const password = await this.passwordStorage.loadPassword(this.profile)
|
||||
if (password) {
|
||||
this.allAuthMethods.push({ type: 'saved-password', password })
|
||||
}
|
||||
}
|
||||
if (!this.profile.options.auth || this.profile.options.auth === 'keyboardInteractive') {
|
||||
const savedPassword = this.profile.options.password ?? await this.passwordStorage.loadPassword(this.profile)
|
||||
if (savedPassword) {
|
||||
this.allAuthMethods.push({ type: 'keyboard-interactive', savedPassword })
|
||||
if (this.profile.options.password) {
|
||||
this.allAuthMethods.push({ type: 'keyboard-interactive', savedPassword: this.profile.options.password })
|
||||
}
|
||||
this.allAuthMethods.push({ type: 'keyboard-interactive' })
|
||||
}
|
||||
@@ -218,6 +213,38 @@ export class SSHSession {
|
||||
this.allAuthMethods.push({ type: 'hostbased' })
|
||||
}
|
||||
|
||||
private async populateStoredPasswordsForResolvedUsername (): Promise<void> {
|
||||
if (!this.authUsername) {
|
||||
return
|
||||
}
|
||||
|
||||
const storedPassword = await this.passwordStorage.loadPassword(this.profile, this.authUsername)
|
||||
if (!storedPassword) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.profile.options.auth || this.profile.options.auth === 'password') {
|
||||
const hasSavedPassword = this.allAuthMethods.some(method => method.type === 'saved-password' && method.password === storedPassword)
|
||||
if (!hasSavedPassword) {
|
||||
const promptIndex = this.allAuthMethods.findIndex(method => method.type === 'prompt-password')
|
||||
const insertIndex = promptIndex >= 0 ? promptIndex : this.allAuthMethods.length
|
||||
this.allAuthMethods.splice(insertIndex, 0, { type: 'saved-password', password: storedPassword })
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.profile.options.auth || this.profile.options.auth === 'keyboardInteractive') {
|
||||
const existingSaved = this.allAuthMethods.find(method => method.type === 'keyboard-interactive' && method.savedPassword === storedPassword)
|
||||
if (!existingSaved) {
|
||||
const updatable = this.allAuthMethods.find(method => method.type === 'keyboard-interactive' && method.savedPassword === undefined)
|
||||
if (updatable && updatable.type === 'keyboard-interactive') {
|
||||
updatable.savedPassword = storedPassword
|
||||
} else {
|
||||
this.allAuthMethods.push({ type: 'keyboard-interactive', savedPassword: storedPassword })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async getAgentConnectionSpec (): Promise<russh.AgentConnectionSpec|null> {
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
if (this.config.store.ssh.agentType === 'auto') {
|
||||
@@ -363,12 +390,14 @@ export class SSHSession {
|
||||
}
|
||||
}
|
||||
|
||||
await this.populateStoredPasswordsForResolvedUsername()
|
||||
|
||||
const authenticatedClient = await this.handleAuth()
|
||||
if (authenticatedClient) {
|
||||
this.ssh = authenticatedClient
|
||||
} else {
|
||||
this.ssh.disconnect()
|
||||
this.passwordStorage.deletePassword(this.profile)
|
||||
this.passwordStorage.deletePassword(this.profile, this.authUsername ?? undefined)
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
throw new Error('Authentication rejected')
|
||||
}
|
||||
@@ -376,7 +405,7 @@ export class SSHSession {
|
||||
// auth success
|
||||
|
||||
if (this.savedPassword) {
|
||||
this.passwordStorage.savePassword(this.profile, this.savedPassword)
|
||||
this.passwordStorage.savePassword(this.profile, this.savedPassword, this.authUsername ?? undefined)
|
||||
}
|
||||
|
||||
for (const fw of this.profile.options.forwardedPorts ?? []) {
|
||||
|
||||
Reference in New Issue
Block a user