611b794fc7
- pkg/crypto: AES-256-GCM encryption with PBKDF2 key derivation - 100k iterations, 16-byte salt, SHA-256 - Encrypt/Decrypt/IsEncrypted/HashPassword - Storage layer encryption: - JSONStorage.SetPassword() enables transparent encrypt/decrypt - readJSON auto-decrypts, replace* auto-encrypts - pkg/knownhosts: TOFU host key verification - Verify/Add/Remove host keys - HostKeyCallback for SSH config - SSH client security: - SetHostKeyCallback() replaces InsecureIgnoreHostKey() - SetPassphraseCallback() for encrypted private keys - getKeySigner() tries passphrase on encrypted keys - Models: AppConfig gains EncryptionEnabled, PasswordHash, KnownHostsFile
7.3 KiB
7.3 KiB
Changelog
[Unreleased] — 2025-01-31
Fixed
- TUI host list footer now includes
Ctrl+E:edit - New hosts/keys/snippets created via TUI form now get UUID + timestamps (
CreatedAt,UpdatedAt) - Storage layer auto-generates UUID + timestamps on save if empty (defense-in-depth)
- host_form_tab.go: Space/Left/Right keys now passthrough to text input when not on auth type field (fixes typing spaces and cursor navigation)
- tui.go: Key and snippet list tabs now properly refresh after save/delete (mirrors host flow)
- tabs.go: WindowSizeMsg now forwarded to ALL tabs, not just the active one (fixes stale dimensions after resize)
Changed
- All tab footers are now context-specific (no global status bar)
- SFTP browser uses full-width panes (
t.width/2) - sftp_browser_tab.go footer: Added
Enter/→:open,←/Backspace:up - form tabs footer: Added
Shift+Tab:prev,↑↓:nav
Responsive Layout (Done)
- NEW
responsive.go: Shared helpers (wrapFooter,adaptiveSidePad,clampWidth,truncateStr) - Footer auto-wraps to multi-line when terminal is narrow (full labels preserved)
- Box width clamped to terminal width — no more overflow
- Host/key/snippet rows truncated with
…when names are too long; compact row format on narrow screens - SFTP panes stack vertically when terminal < 50 cols
- Tab bar truncates tab names on overflow
- Form contentW minimum lowered from 50 to 30 for mobile (Termux)
- Fixed: key_list_tab & snippet_list_tab were dropping last data row (off-by-one in
rows[:len(rows)-1]) - Fixed: SFTP pane width — lipgloss
Width(n)rendersn+2chars (border extra). halfW nowt.width/2-2to compensate. File names truncate to…within inner text area. Filter line also truncated. - Verified: zero overflow at 80, 60, 50 (side-by-side), 40, 30 cols (stacked)
SFTP Stacked Mode Fix (Done)
- Stacked mode (<50 cols) now renders only the active pane (Local or Remote)
- Added pane indicator bar:
[Local] Remotewith active pane highlighted - Side-by-side mode (≥50 cols) unchanged — both panes remain visible
- Tab key now visually switches between panes on narrow terminals
- Default active pane: Local (was Remote)
- Border height fix: pane uses fixed
Height(maxH)— border no longer shrinks/grows when scrolling renderPanenow takesmaxHparameter to control content area height- Stacked:
maxH = t.height - 6; Side-by-side:maxH = t.height - 5 - Breakpoints: compact (<60), medium (60–100), wide (≥100)
SFTP Performance Fix
- Added directory listing cache (
dirCache map[string][]os.FileInfo) to each pane - Cache hit: instant navigation (no disk/network call)
- Cache miss: read from disk/SFTP, store in cache
Rkey now clears cache for current directory and forces re-read- Cache is per-path: navigating to a previously visited folder is instant
SFTP File Transfer Progress Bar
- Added progress bar during upload/download:
[████████░░░░] 67% 12.3MB/18.5MB progressWriterwrapsio.Writerand reports bytes transferred- Footer shows live progress during transfer
- Auto-refresh destination pane after transfer completes
- Success message shown for 1 second before clearing
SFTP Auto-Refresh Fix
- Added
program *tea.Programfield to SFTPBrowserTab and Model SetProgram()method allows goroutines to send messages to Bubble Tea- After transfer:
t.program.Send(sftpRefreshMsg{})triggers re-render - Model stores program reference, passes it to SFTP tab on creation
SFTP Bug Fixes
- Auto-refresh: clear dirCache before refresh after transfer/delete/mkdir
- Cache was stale after file operations — old entries returned instead of fresh
- Filter mode: allow command keys (c, d, n, r) and navigation (↑↓, Tab) to pass through
- Filter mode no longer blocks transfer, delete, mkdir, or pane switch
- Delete: clear cache + trigger re-render after file removal
- Mkdir: clear cache + trigger re-render after directory creation
SFTP Rename Feature
- Added
Mkey to rename files and directories - Rename mode: shows input with current name, type new name, Enter to confirm
- Works on both Local and Remote panes
- Clears cache and refreshes after rename
- Footer updated:
M:renameadded - Filter mode allows
Mto pass through
v1.0.0 (2025-01-30)
Added
- Initial release of Hostkeeper SSH/SFTP management tool
- Host management: CRUD operations for SSH hosts (add, list, edit, delete)
- SSH connections: Native SSH (default) and Go SSH direct mode
- TUI interface: Interactive host browser using Bubble Tea
- Export/Import: JSON export and import with merge/replace strategies
- Cross-platform builds: Support for Linux, macOS, Windows, Termux
- Shell completion: Bash, Zsh, Fish, and PowerShell support
- Configuration: File-based credential storage with
0600permissions - Tag and group: Host categorization with tags and groups
- Search and filter: Filter hosts by group, tag, or text search
Commands
hostkeeper add— Add SSH hosts (interactive and flag-based)hostkeeper list— List hosts with table/JSON outputhostkeeper connect— Connect to hosts with custom timeouthostkeeper edit— Edit host configurationshostkeeper delete— Delete hosts with confirmationhostkeeper export— Export data to JSONhostkeeper import— Import data with merge/replacehostkeeper tui— Terminal user interfacehostkeeper completion— Shell completion generationhostkeeper version— Version information
Technical
- Cobra CLI framework for command structure
- Bubble Tea TUI with keyboard navigation
- Go SSH client for direct connections
- Comprehensive test suite with unit and integration tests
- Build automation via Makefile and build.sh
Notes
- Initial MVP release, all core features functional
- Encrypted storage planned for future release
- Interactive shell in Go SSH direct mode not yet available
Phase 2 — Security Enhancement
AES-256-GCM Encryption
- New
pkg/crypto/crypto.go: AES-256-GCM encrypt/decrypt with PBKDF2 key derivation - 100,000 iterations, 16-byte salt, SHA-256 key derivation
Encrypt(plaintext, password)→ base64(salt + nonce + ciphertext)Decrypt(encoded, password)→ plaintextIsEncrypted(data)checks if data looks like encrypted content
Storage Layer Encryption
JSONStoragenow haspasswordfield for master encryption keySetPassword(),GetPassword(),IsEncrypted()methodsreadJSON()auto-decrypts if password is set and data is encryptedreplaceHosts/KeyPairs/Snippets()auto-encrypt before writing- All existing CRUD operations transparently encrypt/decrypt
Known Hosts Verification
- New
pkg/knownhosts/knownhosts.go: TOFU (Trust-On-First-Use) model KnownHostsmanagesknown_hostsfile (JSON format)Verify()checks if host key matches stored keyHostKeyCallback()returnscryptossh.HostKeyCallbackfor SSH config- Warns on key mismatch (potential MITM attack)
SSH Client Security
Clientnow supportshostKeyCallbackandpassphraseCallbackSetHostKeyCallback()— replacesInsecureIgnoreHostKey()SetPassphraseCallback()— prompts for passphrase on encrypted keysgetKeySigner()tries passphrase callback if key is encrypted
Models Updated
AppConfig: addedEncryptionEnabled,PasswordHash,KnownHostsFile