Files
HostKeeper/CHANGELOG.md
T
2026-07-07 11:53:16 +07:00

231 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
## [Unreleased] — V2 Planning Complete (2026-06-29)
### Added (V2 Planning Documents)
- `docs/v2/PROGRESS.md` — Status tracker for V2 development
- `docs/v2/ARCHITECTURE.md` — System architecture (GoFiber + React + Electron)
- `docs/v2/API.md` — REST API + WebSocket specification
- `docs/v2/DATA_MODELS.md` — Extended data models (Groups, PortForward, Workspace)
- `docs/v2/UI_COMPONENTS.md` — React component tree + state management
- `docs/v2/UI_TERMIUS_REFERENCE.md` — Termius visual reference
- `docs/v2/SPRINT_PLAN.md` — Sprint-by-sprint task breakdown
- `docs/v2/BUILD_SYSTEM.md` — Cross-platform build pipeline
- `docs/v2/PERFORMANCE.md` — Performance & stability guide
### Architecture Decision
- Backend: GoFiber v2 (fasthttp-based) replacing chi/net/http
- WebSocket: gofiber/contrib/websocket (fasthttp/websocket) replacing gorilla/websocket
- Frontend: React 19 + TypeScript + xterm.js + Zustand
- Desktop: Electron (electron-builder)
- Mobile: gomobile + WebView
### V1 Status (FROZEN)
- All V1 code (pkg/, internal/, cmd/, test/) is complete and frozen
- V1 CLI/TUI remains functional alongside V2 GUI
- 105 tests passing, zero race conditions
## [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)` renders `n+2` chars (border extra). halfW now `t.width/2-2` to 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] Remote` with 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
- `renderPane` now takes `maxH` parameter to control content area height
- Stacked: `maxH = t.height - 6`; Side-by-side: `maxH = t.height - 5`
- Breakpoints: compact (<60), medium (60100), 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
- `R` key 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`
- `progressWriter` wraps `io.Writer` and 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.Program` field 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 `M` key 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:rename` added
- Filter mode allows `M` to 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 `0600` permissions
- **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 output
- `hostkeeper connect` — Connect to hosts with custom timeout
- `hostkeeper edit` — Edit host configurations
- `hostkeeper delete` — Delete hosts with confirmation
- `hostkeeper export` — Export data to JSON
- `hostkeeper import` — Import data with merge/replace
- `hostkeeper tui` — Terminal user interface
- `hostkeeper completion` — Shell completion generation
- `hostkeeper 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)` → plaintext
- `IsEncrypted(data)` checks if data looks like encrypted content
### Storage Layer Encryption
- `JSONStorage` now has `password` field for master encryption key
- `SetPassword()`, `GetPassword()`, `IsEncrypted()` methods
- `readJSON()` auto-decrypts if password is set and data is encrypted
- `replaceHosts/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
- `KnownHosts` manages `known_hosts` file (JSON format)
- `Verify()` checks if host key matches stored key
- `HostKeyCallback()` returns `cryptossh.HostKeyCallback` for SSH config
- Warns on key mismatch (potential MITM attack)
### SSH Client Security
- `Client` now supports `hostKeyCallback` and `passphraseCallback`
- `SetHostKeyCallback()` — replaces `InsecureIgnoreHostKey()`
- `SetPassphraseCallback()` — prompts for passphrase on encrypted keys
- `getKeySigner()` tries passphrase callback if key is encrypted
### Models Updated
- `AppConfig`: added `EncryptionEnabled`, `PasswordHash`, `KnownHostsFile`
## Phase 2 UX Polish (Done)
### Theme System
- **NEW `themes.go`**: `Theme` struct with full color palette
- 3 predefined themes: `dark` (Gruvbox), `light`, `dracula`
- `SetTheme(name)` — updates all component styles at runtime
- `GetActiveTheme()` — returns current theme
- All palette vars now derived from active theme
### Config Profiles
- **`models.go`**: `Profile` struct — name, theme, default group, default auth, editor, notes
- `AppConfig.Profiles []Profile` — list of named profiles
- `AppConfig.ActiveProfile string` — currently active profile
- `GetProfile(name)`, `GetActiveProfile()`, `AddProfile()`, `RemoveProfile()`
- Default config includes "default" profile
### Enhanced Error Display
- **NEW `error_banner.go`**: `ErrorBanner` with severity levels (Error/Warning/Info)
- Structured format: title + detail + numbered hints
- Auto-dismiss after 5 seconds (configurable)
- Color-coded: red (error), yellow (warning), blue (info)
- `Show()`, `Hide()`, `Update()`, `View(width)` methods
### Tests
- **`test/tui/theme_test.go`**: GetTheme, SetTheme, GetActiveTheme, registry
- **`test/tui/error_banner_test.go`**: Show/Hide, AutoDismiss, Severity, View
- **`test/models_test.go`**: DefaultConfig, Profile CRUD
## Phase 3 Testing (Done)
### Security-Critical Tests (0% → 100%)
- **`test/crypto/crypto_test.go`** (19 tests): DeriveKey, Encrypt/Decrypt round-trip, empty/large/unicode/newlines data, wrong/empty password, IsEncrypted, HashPassword, randomness
- **`test/knownhosts/knownhosts_test.go`** (14 tests): New, Add/Get/Remove CRUD, Verify unknown/match/mismatch (MITM), HostKeyCallback autoAdd, persistence, corrupted file
### Core Tests (40% → 90%)
- **`test/storage/json_storage_test.go`** (20 tests): KeyPair CRUD (6), Snippet CRUD (6), encryption (SetPassword, IsDataEncrypted, wrong password), MergeStrategy (merge/replace), edge cases
### Config Tests (22% → 80%)
- **`test/config/config_test.go`** (9 tests): New first run, Save, UpdateAppConfig, path getters
### UI Tests (40% → 70%)
- **`test/tui/responsive_test.go`** (10 tests): WrapFooter, ClampWidth, TruncateStr
### Bug Fixes
- **knownhosts deadlock**: `Add()`/`Remove()` now call `saveInternal()` instead of `Save()` to avoid re-locking
- **responsive.go**: Exported `WrapFooter`, `ClampWidth`, `TruncateStr` for testing
### Coverage Summary
- `pkg/crypto`: 0% → **100%** (19 tests)
- `pkg/knownhosts`: 0% → **100%** (14 tests)
- `pkg/storage`: 40% → **90%** (20 tests)
- `pkg/config`: 22% → **80%** (9 tests)
- `pkg/tui`: 40% → **70%** (10 new tests)
- Total: **105 tests**, all passing, zero race conditions