mirror of
https://github.com/eugeny/tabby
synced 2026-05-03 07:50:45 +00:00
* feat(ssh): pre-populate vault password in auth prompts for MFA use cases When a keyboard-interactive password prompt is shown and the response field is empty, load and pre-fill the saved vault password. This lets users with hardware tokens (e.g. YubiKey) press their token to append a TOTP to the pre-filled base password without re-typing it. Also pre-fill the prompt-password modal with the vault password so the same workflow applies when SSH password auth is used with MFA. Closes #9911 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ssh): remove unnecessary null coalescing in loadPassword call Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Component, Input, Output, EventEmitter, ViewChild, ElementRef, ChangeDetectionStrategy } from '@angular/core'
|
||||
import { Component, Input, Output, EventEmitter, ViewChild, ElementRef, ChangeDetectionStrategy, OnInit, ChangeDetectorRef } from '@angular/core'
|
||||
import { KeyboardInteractivePrompt } from '../session/ssh'
|
||||
import { SSHProfile } from '../api'
|
||||
import { PasswordStorageService } from '../services/passwordStorage.service'
|
||||
@@ -9,7 +9,7 @@ import { PasswordStorageService } from '../services/passwordStorage.service'
|
||||
styleUrls: ['./keyboardInteractiveAuthPanel.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class KeyboardInteractiveAuthComponent {
|
||||
export class KeyboardInteractiveAuthComponent implements OnInit {
|
||||
@Input() profile: SSHProfile
|
||||
@Input() prompt: KeyboardInteractivePrompt
|
||||
@Input() step = 0
|
||||
@@ -17,7 +17,22 @@ export class KeyboardInteractiveAuthComponent {
|
||||
@ViewChild('input') input: ElementRef
|
||||
remember = false
|
||||
|
||||
constructor (private passwordStorage: PasswordStorageService) {}
|
||||
constructor (
|
||||
private passwordStorage: PasswordStorageService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
) {}
|
||||
|
||||
async ngOnInit (): Promise<void> {
|
||||
const savedPassword = await this.passwordStorage.loadPassword(this.profile)
|
||||
if (savedPassword) {
|
||||
for (let i = 0; i < this.prompt.prompts.length; i++) {
|
||||
if (this.prompt.isAPasswordPrompt(i) && !this.prompt.responses[i]) {
|
||||
this.prompt.responses[i] = savedPassword
|
||||
}
|
||||
}
|
||||
this.cdr.markForCheck()
|
||||
}
|
||||
}
|
||||
|
||||
isPassword (): boolean {
|
||||
return this.prompt.isAPasswordPrompt(this.step)
|
||||
|
||||
@@ -657,6 +657,10 @@ export class SSHSession {
|
||||
modal.componentInstance.prompt = `Password for ${this.authUsername}@${this.profile.options.host}`
|
||||
modal.componentInstance.password = true
|
||||
modal.componentInstance.showRememberCheckbox = true
|
||||
const prefilledPassword = await this.passwordStorage.loadPassword(this.profile, this.authUsername)
|
||||
if (prefilledPassword) {
|
||||
modal.componentInstance.value = prefilledPassword
|
||||
}
|
||||
|
||||
try {
|
||||
const promptResult = await modal.result.catch(() => null)
|
||||
|
||||
Reference in New Issue
Block a user