# Hostkeeper: SSH/SFTP Management Tool - Design Document **Date:** 2024-06-22 **Status:** Design Approved **Version:** 1.0-MVP --- ## Executive Summary Hostkeeper is a cross-platform SSH/SFTP management tool written in Go, inspired by Termius but implemented as a CLI tool with progressive TUI enhancement. The goal is to provide secure SSH credential management with cross-device sync capabilities through export/import functionality. ### Key Design Decisions - **Architecture:** TUI-first with tab-based session management (embedded terminal replacement) - **Interface:** TUI for full experience (multiple SSH sessions, host management, SFTP); CLI for quick tasks and automation - **Storage:** JSON/YAML files (Phase 1), encrypted storage (Phase 2) - **Platform:** Cross-platform (Linux, macOS, Windows, Termux/Android) - **Sync:** Manual export/import (Phase 1), cloud sync (future) --- ## Project Requirements ### Must-Have Features (MVP) 1. **SSH Connection Management** - Username/password authentication - SSH key authentication - Host organization and search - Connection testing 2. **SFTP File Transfer** - Native SFTP client (Phase 1) - Custom TUI dual-pane browser (Phase 2) 3. **Credential Management** - Secure local storage - Host metadata (tags, descriptions) - Quick access patterns 4. **SSH Key Management** - Generate SSH keys - Import existing keys - Export keys for distribution - Key-Host association 5. **Connection Snippets** - Save common commands - Variable substitution - Per-host snippets 6. **Export/Import Functionality** - Cross-device credential transfer - Backup and restore - Merge capabilities 7. **Cross-Platform Support** - Single binary distribution - Termux compatibility - Platform-specific optimizations 8. **Security** - File permission management - Secure credential storage - Memory protection for sensitive data --- ## Architecture Overview ### High-Level Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ HOSTKEEPER CLI │ │ (Single Binary) │ └─────────────────────────────────────────────────────────────┘ │ ┌─────────────────────┼─────────────────────┐ │ │ │ ┌───────▼──────────┐ ┌──────▼──────┐ ┌─────────▼────────┐ │ Command Layer │ │ TUI Layer │ │ Core Engine │ │ │ │ │ │ │ │ • connect │ │ • Host List │ │ • SSH Client │ │ • list │ │ • SFTP UI │ │ • SFTP Client │ │ • sftp │ │ • Key Mgmt │ │ • Key Manager │ │ • export │ │ • Snippets │ │ • Encryption │ │ • import │ │ • Settings │ │ • Config I/O │ │ • add │ │ │ │ │ └─────────────────┘ └─────────────┘ └──────────────────┘ │ │ │ └─────────────────────┼─────────────────────┘ │ ┌─────────▼─────────┐ │ Storage Layer │ │ │ │ • hosts.json │ │ • keys.json │ │ • snippets.json │ │ • config.yaml │ └──────────────────┘ ``` ### Key Design Principles 1. **Single Source of Truth** - All data stored in JSON files 2. **TUI-First** - TUI is the primary interface; CLI commands serve quick tasks and scripting 3. **Layered Architecture** - UI → Business Logic → Storage 4. **Cross-Platform** - Pure Go, no OS-specific dependencies 5. **Encrypt-Ready** - Structure prepared for encryption upgrade 6. **Orange Theme** - Distinct orange color palette to visually separate Hostkeeper from the native terminal, signaling the user is inside the application environment --- ## Component Details ### 1. Command Layer (CLI Interface) **Framework:** Cobra (standard Go CLI framework) **Major Commands:** ```bash hostkeeper connect # SSH connection hostkeeper list # List all hosts hostkeeper sftp # SFTP browser hostkeeper add # Add new host hostkeeper edit # Edit host config hostkeeper delete # Delete host hostkeeper export # Export credentials hostkeeper import # Import credentials hostkeeper key generate # Generate SSH key hostkeeper key import # Import existing key hostkeeper snippet add # Add command snippet hostkeeper completion # Shell completion setup ``` **Error Handling:** - Invalid command → Show help message - Missing arguments → Prompt interactive input - Connection errors → User-friendly error messages with hints --- ### 2. TUI Layer (Interactive Interface) **Framework:** Bubble Tea (recommended for modern, maintainable TUI) **Main Screens:** - **Host List:** Grid/List view with status indicators - **Connection Manager:** Active connections, quick actions - **SFTP Browser:** Dual-pane file browser (Phase 2) - **Key Manager:** SSH keys list, import/export, generate - **Snippet Manager:** Command snippets with variables - **Settings:** Config management, preferences **TUI Features:** - Event-driven architecture - Responsive layout - Keyboard navigation - Mouse support (optional) - Quick actions (`/` search, `n` new, `Ctrl+S` SFTP, etc.) --- ### 3. Core Engine (Business Logic) #### SSH Client Module ```go type SSHClient struct { Hostname string Port int AuthMethod AuthMethod // password, key, or both ClientConfig *ssh.ClientConfig } func (c *SSHClient) Connect() (*ssh.Client, error) func (c *SSHClient) Execute(cmd string) (string, error) func (c *SSHClient) Close() error ``` #### SFTP Client Module ```go type SFTPClient struct { SSHClient *SSHClient Client *sftp.Client } func (s *SFTPClient) Connect() error func (s *SFTPClient) Upload(local, remote string) error func (s *SFTPClient) Download(remote, local string) error func (s *SFTPClient) List(path string) ([]os.FileInfo, error) ``` #### Key Management Module ```go type KeyManager struct { StoragePath string } func (k *KeyManager) GenerateKey(name string) (*KeyPair, error) func (k *KeyManager) ImportKey(name, keyPath string) error func (k *KeyManager) ExportKey(name, destPath string) error func (k *KeyManager) ListKeys() ([]KeyInfo, error) ``` --- ### 4. Storage Layer (Data Persistence) #### File Structure ``` ~/.hostkeeper/ ├── config.yaml # App configuration ├── hosts.json # Saved hosts/connections ├── keys.json # SSH keys store ├── snippets.json # Command snippets └── exported/ # Exported configurations └── hostkeeper-backup-2024-06-22.json ``` #### Data Structures **hosts.json:** ```json { "hosts": [ { "id": "server1", "name": "Production Server", "hostname": "192.168.1.100", "port": 22, "username": "admin", "auth": { "type": "key", "key_id": "default_key", "password": null }, "tags": ["production", "linux"], "created_at": "2024-06-22T10:00:00Z" } ] } ``` **keys.json:** ```json { "keys": [ { "id": "default_key", "name": "Default Key", "private_key": "-----BEGIN RSA PRIVATE KEY-----...", "public_key": "ssh-rsa AAAA...", "comment": "Generated by hostkeeper", "created_at": "2024-06-22T10:00:00Z" } ] } ``` **config.yaml:** ```yaml version: "1.0" default_port: 22 connection_timeout: 30 sftp_timeout: 60 log_level: info storage: encrypt: false compression: false terminal: color_scheme: default font_size: medium ``` --- ## Key User Workflows ### Workflow 1: Quick SSH Connection (Command-based) ```bash $ hostkeeper connect production ``` **Flow:** 1. CLI parses command → validates host exists 2. Core Engine loads host config from `hosts.json` 3. Establishes SSH connection with native terminal 4. User gets native terminal experience 5. On exit: connection cleanup, return to CLI **Error Handling:** - Host not found → Show available hosts - Connection failed → User-friendly error with troubleshooting tips - Auth failed → Prompt for password/key selection --- ### Workflow 2: Add New Host (Interactive) ```bash $ hostkeeper add ``` **Interactive Prompts:** ``` Hostname: staging-server IP Address: 192.168.1.50 Port: [22] Username: admin Auth Method: [1] Password [2] SSH Key → 2 Tags: staging, linux, development ``` **Flow:** 1. Collect host information interactively 2. Validate for duplicates 3. Generate UUID for host 4. Append to `hosts.json` 5. Offer connection test --- ### Workflow 3: SFTP File Transfer #### Phase 1 (MVP) - Native SFTP ```bash $ hostkeeper sftp production sftp> put /local/file.txt /remote/path/ sftp> get /remote/file.zip /local/backup/ sftp> ls -la /var/www/ ``` #### Phase 2 - Custom TUI Browser ``` ┌────────────────────┬────────────────────┐ │ Local Files │ Remote Files │ │ │ │ │ 📁 Documents/ │ 📁 /var/www/ │ │ 📄 file.txt │ 📄 index.html │ │ 📄 backup.zip │ 📄 config.php │ │ │ │ │ [Upload] [Refresh] │ [Download] [Delete]│ └────────────────────┴────────────────────┘ ``` --- ### Workflow 4: Export/Import Credentials ```bash $ hostkeeper export backup-2024-06.json $ hostkeeper import backup-2024-06.json ``` **Export Flow:** 1. Read all JSON files 2. Combine into single structure 3. Phase 1: Plain JSON export 4. Phase 2: AES-256 encryption with password 5. Write export file with summary **Export Structure:** ```json { "version": "1.0", "exported_at": "2024-06-22T16:00:00Z", "data": { "hosts": [...], "keys": [...], "snippets": [...], "config": {...} } } ``` **Import Flow:** 1. Validate import file format 2. Phase 2: Decrypt with password 3. Merge options: replace/merge/skip 4. Update local JSON files 5. Show import summary --- ## Security Architecture ### Phase 1 Security (MVP) **File Security:** - File permissions: 0600 (owner read/write only) - Environment variable protection - No password/key logging in errors - Sensitive data filtering from logs - Plain text storage (Phase 2 encryption) **Security Measures:** ```go // Proper file permissions func SaveConfig(data []byte, path string) error { err := os.WriteFile(path, data, 0600) if err != nil { return err } // Validate permissions info, _ := os.Stat(path) if info.Mode().Perm() != 0600 { os.Chmod(path, 0600) } return nil } ``` --- ### Phase 2 Security (Enhanced) **Encryption Layer:** ```go type EncryptionManager struct { MasterPassword []byte Salt []byte } func (e *EncryptionManager) EncryptData(data []byte) ([]byte, error) { // PBKDF2 key derivation key := pbkdf2.Key(e.MasterPassword, e.Salt, 100000, 32, sha256.New) // AES-256-GCM encryption block, err := aes.NewCipher(key) gcm, err := cipher.NewGCM(block) // Encrypt with random nonce nonce := make([]byte, gcm.NonceSize()) rand.Read(nonce) ciphertext := gcm.Seal(nonce, nonce, data, nil) return ciphertext, nil } ``` **Encrypted Storage Format:** ```json { "version": "2.0", "encryption": "AES-256-GCM", "iterations": 100000, "salt": "base64_encoded_salt", "data": "encrypted_base64_data" } ``` --- ### Security Best Practices **Memory Security:** ```go // Clear sensitive data from memory func ClearSensitiveData(data []byte) { for i := range data { data[i] = 0 } } defer ClearSensitiveData(password) ``` **Logging Security:** ```go // Filter sensitive information func sanitizeSensitiveData(input string) string { sensitivePatterns := []string{ `password["']?\s*[:=]\s*["']?[^\s"']+`, `private_key["']?\s*[:=]\s*["']?.+?["']?`, } for _, pattern := range sensitivePatterns { re := regexp.MustCompile(pattern) input = re.ReplaceAllString(input, "[REDACTED]") } return input } ``` --- ## Error Handling Strategy ### Connection Error Handling ```go type ConnectionError struct { Type string // "auth", "network", "timeout", "config" Message string Details string Hints []string } func HandleSSHError(err error) *ConnectionError { switch { case strings.Contains(err.Error(), "connection refused"): return &ConnectionError{ Type: "network", Message: "Cannot connect to server", Details: err.Error(), Hints: []string{"Check if server is running", "Verify firewall rules"}, } case strings.Contains(err.Error(), "authentication failed"): return &ConnectionError{ Type: "auth", Message: "Authentication failed", Details: err.Error(), Hints: []string{"Verify username/password", "Check SSH key permissions"}, } // ... additional cases } } ``` **Error Display Format:** ``` ❌ Connection Error: Authentication failed Details: ssh: handshake failed: ssh: unable to authenticate Possible solutions: 1. Verify username: admin 2. Check SSH key is loaded: hostkeeper key list 3. Test connection manually: ssh admin@192.168.1.100 Use 'hostkeeper edit production' to update credentials ``` --- ### Critical Error Scenarios **Scenario 1: Corrupted Configuration File** ``` ❌ Configuration Error: Invalid hosts.json Details: hosts.json contains corrupted data at line 23 Recovery options: 1. Restore from backup: ~/.hostkeeper/hosts.json.backup 2. Import from export: hostkeeper import backup.json 3. Reset configuration: hostkeeper reset --force (⚠️ This will delete all data) Action needed: Configuration is unusable. Please choose recovery option. ``` **Scenario 2: SSH Key Permission Issues** ``` ⚠️ Security Warning: Insecure key permissions File: ~/.ssh/id_rsa has permissions 644 Recommended: 600 (owner read/write only) Auto-fix command: $ chmod 600 ~/.ssh/id_rsa Continue anyway? [y/N] ``` --- ## Cross-Platform Strategy ### Platform Support **Primary Platforms:** - Linux (x86_64, ARM) - macOS (x86_64, ARM64) - Windows (x86_64) - Termux/Android (ARM) **Build Strategy:** - Go cross-compilation for all platforms - Single binary distribution - Platform-specific optimizations **Platform-Specific Handling:** **Linux/Unix:** - Standard permission handling - Native terminal integration - System configuration paths **macOS:** - Keychain integration (optional) - Proper terminal sizing - macOS-specific paths **Windows:** - Windows Terminal support - Path handling (backslash vs forward slash) - Registry integration (optional) **Termux/Android:** - File permissions workaround - Storage location adaptation - Terminal limitations handling --- ## Technology Stack ### Core Libraries **SSH/SFTP:** - `golang.org/x/crypto/ssh` - SSH protocol implementation - `pkg.sftp.io/ssh` - SFTP client implementation **CLI Framework:** - `github.com/spf13/cobra` - Command framework - `github.com/spf13/viper` - Configuration management **TUI Framework:** - `github.com/charmbracelet/bubbletea` - TUI framework - `github.com/charmbracelet/lipgloss` - Styling **Encryption:** - `crypto/aes` - AES encryption (Phase 2) - `crypto/cipher` - Cipher implementations - `crypto/pbkdf2` - Key derivation **Utilities:** - `encoding/json` - JSON handling - `gopkg.in/yaml.v3` - YAML support - `github.com/google/uuid` - UUID generation --- ## Implementation Phases ### Phase 1: MVP Foundation (3-4 weeks) **Core Functionality:** - Basic SSH connections (native terminal) - Host management (add, list, edit, delete) - SSH key generation and import - Export/Import (plain JSON) - Native SFTP client - Basic TUI for host management **Deliverables:** - Working CLI with core commands - JSON-based storage - Cross-platform binary builds - Basic documentation --- ### Phase 2: Enhanced Features (4-6 weeks) **TUI Enhancement:** - Rich TUI interface for all operations - Dual-pane SFTP browser - Key management UI - Snippet manager - Connection snippets execution **Security Enhancement:** - AES-256 encryption for storage - Master password protection - Secure credential export/import - Enhanced error messages **User Experience:** - Shell completion - Configuration profiles - Theme support - Keyboard shortcuts --- ### Phase 3: Advanced Features (Future) **Cloud Sync:** - User account system - Encrypted cloud storage - Real-time multi-device sync - Conflict resolution **Advanced Terminal:** - Custom terminal emulator - Multiple session management - Tab support - Advanced text selection **Integration:** - Web UI (optional) - API access - Plugin system - Third-party integrations --- ## Development Guidelines ### Code Quality **Standards:** - Follow Go best practices and idioms - Comprehensive error handling - Logging for debugging - Code documentation - Unit tests for critical functions **Security Considerations:** - No hardcoded credentials - Input validation and sanitization - Secure default configurations - Regular security audits --- ### Testing Strategy **Unit Testing:** - Core engine functions - SSH connection logic - Encryption/decryption - Configuration management **Integration Testing:** - End-to-end SSH connections - SFTP operations - Export/Import functionality - Cross-platform compatibility **Manual Testing:** - Cross-platform testing (Linux, macOS, Windows, Termux) - User experience validation - Performance testing - Security validation --- ## Success Criteria ### MVP Success Metrics - ✅ Can establish SSH connections to remote servers - ✅ Can manage multiple hosts with different auth methods - ✅ Can perform SFTP operations (Phase 1: native, Phase 2: TUI) - ✅ Can export/import credentials across devices - ✅ Works on Linux, macOS, Windows, and Termux - ✅ Secure credential storage with proper permissions - ✅ User-friendly error messages and help text ### Phase 2 Success Metrics - ✅ Rich TUI interface for all operations - ✅ Encrypted credential storage - ✅ Dual-pane SFTP browser - ✅ Shell completion and documentation - ✅ Enhanced user experience --- ## Risks and Mitigation ### Technical Risks **Risk:** SSH terminal emulation complexity **Mitigation:** Progressive approach - native terminal first, custom TUI later **Risk:** Cross-platform compatibility issues **Mitigation:** Extensive testing on all platforms, Go's cross-compilation **Risk:** Performance issues with TUI **Mitigation:** Framework selection (Bubble Tea), performance testing ### Security Risks **Risk:** Credential exposure **Mitigation:** Proper file permissions, memory clearing, secure defaults **Risk:** Key management complexity **Mitigation:** Clear user guidance, validation, secure defaults **Risk:** Encryption implementation bugs **Mitigation:** Use standard libraries, security audits, testing --- ## Conclusion Hostkeeper aims to provide a comprehensive SSH/SFTP management solution with cross-platform support and secure credential management. The progressive development approach ensures rapid delivery of core functionality while maintaining a clear path to advanced features. The hybrid CLI/TUI approach balances power user needs with accessibility, while the phased implementation allows for iterative improvement based on user feedback. --- **Document Status:** Approved for implementation **Next Steps:** Implementation planning using writing-plans skill --- *Sources:* - [golang.org/x/crypto/ssh](https://pkg.go.dev/golang.org/x/crypto/ssh) - [Cobra CLI Framework](https://github.com/spf13/cobra) - [Bubble Tea TUI Framework](https://github.com/charmbracelet/bubbletea) - [Tamagosh SSH Manager](https://github.com/Candratama/tamagosh) - [Termius SSH Client](https://termius.com/)