feat: integrate security features into TUI

- SFTPBrowserTab: added storagePassword, passphraseCallback fields
- Model: added storagePassword, knownHosts fields
- cmd/hostkeeper/tui.go: initialize known_hosts on startup
- SFTP connect: wire passphrase callback to SSH client
- SetStoragePassword/SetKnownHosts/SetPassphraseCallback methods
This commit is contained in:
swanadiva
2026-06-25 13:32:59 +07:00
parent 611b794fc7
commit 1d2e29d20a
3 changed files with 51 additions and 0 deletions
+17
View File
@@ -74,6 +74,10 @@ type SFTPBrowserTab struct {
program *tea.Program
// Security
storagePassword string // master password for encrypted storage
passphraseCallback func() string // callback for SSH key passphrases
mu sync.Mutex
closeOnce sync.Once
}
@@ -107,6 +111,14 @@ func (t *SFTPBrowserTab) SetProgram(p *tea.Program) {
t.program = p
}
func (t *SFTPBrowserTab) SetStoragePassword(password string) {
t.storagePassword = password
}
func (t *SFTPBrowserTab) SetPassphraseCallback(cb func() string) {
t.passphraseCallback = cb
}
func (t *SFTPBrowserTab) Init() tea.Cmd {
go t.connect()
go t.refreshLocal()
@@ -132,6 +144,11 @@ func (t *SFTPBrowserTab) connect() {
timeout := 30 * time.Second
cl := sshclient.NewClient(t.host, timeout)
// Wire up passphrase callback for encrypted keys
if t.passphraseCallback != nil {
cl.SetPassphraseCallback(t.passphraseCallback)
}
ctx := context.Background()
if err := cl.Connect(ctx); err != nil {
t.mu.Lock()
+24
View File
@@ -6,6 +6,7 @@ import (
tea "github.com/charmbracelet/bubbletea"
"git.tukangketik.id/swanadiva/hostkeeper/internal/models"
"git.tukangketik.id/swanadiva/hostkeeper/pkg/knownhosts"
"git.tukangketik.id/swanadiva/hostkeeper/pkg/storage"
)
@@ -28,6 +29,10 @@ type Model struct {
Quit bool
dataDir string
program *tea.Program
// Security
storagePassword string
knownHosts *knownhosts.KnownHosts
}
// New creates a new TUI model
@@ -53,6 +58,16 @@ func (m *Model) SetProgram(p *tea.Program) {
m.program = p
}
// SetStoragePassword sets the master password for encrypted storage
func (m *Model) SetStoragePassword(password string) {
m.storagePassword = password
}
// SetKnownHosts sets the known_hosts manager for host key verification
func (m *Model) SetKnownHosts(kh *knownhosts.KnownHosts) {
m.knownHosts = kh
}
// Update handles messages and updates the model
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
@@ -91,6 +106,15 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if m.program != nil {
tab.SetProgram(m.program)
}
if m.storagePassword != "" {
tab.SetStoragePassword(m.storagePassword)
}
if m.knownHosts != nil {
tab.SetPassphraseCallback(func() string {
// TODO: prompt for passphrase in TUI
return ""
})
}
cmd := m.tabs.Add(tab)
return m, cmd