Files
HostKeeper/docs/plans/2024-06-22-hostkeeper-design.md
T

23 KiB

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:

hostkeeper connect <host>              # SSH connection
hostkeeper list                         # List all hosts  
hostkeeper sftp <host>                 # SFTP browser
hostkeeper add                          # Add new host
hostkeeper edit <host>                  # Edit host config
hostkeeper delete <host>                # Delete host
hostkeeper export <file>                # Export credentials
hostkeeper import <file>                # Import credentials
hostkeeper key generate                 # Generate SSH key
hostkeeper key import <file>            # Import existing key
hostkeeper snippet add <name>           # 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 (event-driven TUI) + Lipgloss (styling)

Theme: Orange/light color palette (#FF6B00, #FF9F43, #FFB800) — visually distinct from native terminal to signal the user is inside Hostkeeper

Tab System Architecture

┌─ Hosts ──── Server Nico ── SFTP ── Keys ── Settings ────────┐
│                                                               │
│  [content of active tab]                                      │
│                                                               │
├───────────────────────────────────────────────────────────────┤
│ Ctrl+Q:close  Ctrl+Tab:next  Shift+Tab:prev  ↑↓:nav  /:search│
└───────────────────────────────────────────────────────────────┘

Tab Types:

  • HostsTab — Host list with search, filter, sort, keyboard navigation
  • SessionTab — Live interactive SSH session (input/output piped via Go SSH client)
  • SFTPTab — Remote file browser with upload/download operations
  • KeysTab — SSH key management (list, generate, import)
  • SnippetsTab — Command snippets with variable substitution
  • SettingsTab — Application configuration

SessionTab Internals:

  • Connect via Go SSH client with stored credentials (password auto-injected)
  • 2 goroutines per session: stdin → SSH channel, SSH stdout → TUI render
  • Terminal resize event → WindowChange via SSH channel
  • Ctrl+Q disconnects session and closes tab
  • Multiple session tabs can be open simultaneously (e.g. connect to 3 servers at once)

Keyboard Navigation:

Key Action
Ctrl+Tab / Shift+Tab Cycle tabs forward/backward
Ctrl+N New tab (add host / new connection)
Ctrl+Q Close current tab / disconnect session
/ Navigate lists (hosts, keys, files)
Enter Select host / open directory / confirm
/ Search/filter within active tab
q Quit Hostkeeper (confirmation dialog)

3. Core Engine (Business Logic)

SSH Client Module

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

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

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:

{
  "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:

{
  "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:

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)

$ 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)

$ 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

$ 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

$ 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:

{
  "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:

// 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:

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:

{
  "version": "2.0",
  "encryption": "AES-256-GCM",
  "iterations": 100000,
  "salt": "base64_encoded_salt",
  "data": "encrypted_base64_data"
}

Security Best Practices

Memory Security:

// Clear sensitive data from memory
func ClearSensitiveData(data []byte) {
    for i := range data {
        data[i] = 0
    }
}
defer ClearSensitiveData(password)

Logging Security:

// 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

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: