Files
HostKeeper/cmd/hostkeeper/root.go
T
swanadiva 93957e3989 feat: auto-detect encrypted files + CLI --password flag
- Storage.IsDataEncrypted() checks if hosts.json is encrypted
- TUI auto-detects encrypted files, prompts password automatically
- Root command: --password flag for all CLI commands
- newStorage() helper applies password flag to storage
- add/list/edit/delete commands now support encrypted storage
- passwordSetMsg loads hosts after password is set
2026-06-25 14:34:41 +07:00

102 lines
2.6 KiB
Go

package main
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"git.tukangketik.id/swanadiva/hostkeeper/pkg/config"
"git.tukangketik.id/swanadiva/hostkeeper/pkg/storage"
)
var (
cfgFile string
appCfg *config.Config
verbose int
debug bool
passwordFlag string
)
var rootCmd = &cobra.Command{
Use: "hostkeeper",
Short: "Cross-platform SSH/SFTP management tool",
Long: `Hostkeeper - Cross-platform SSH/SFTP Management Tool
A comprehensive SSH/SFTP management tool with secure credential storage,
host management, and cross-device sync capabilities.
Quick Start:
hostkeeper add myserver --host 192.168.1.10 --user admin
hostkeeper list
hostkeeper connect myserver
For more information, visit the project repository.`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// Initialize configuration
cfg, err := config.New()
if err != nil {
return fmt.Errorf("failed to initialize config: %w", err)
}
appCfg = cfg
return nil
},
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is platform-specific app dir)")
rootCmd.PersistentFlags().CountVarP(&verbose, "verbose", "v", "verbose output (-v for info, -vv for debug)")
rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "enable debug mode")
rootCmd.PersistentFlags().StringVar(&passwordFlag, "password", "", "master password for encrypted storage")
rootCmd.AddCommand(versionCmd)
}
// initConfig reads in config file and ENV variables if set
func initConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
// Use platform-specific config directory
cfg, err := config.New()
if err != nil {
return
}
viper.AddConfigPath(cfg.GetConfigDir())
viper.SetConfigType("json")
viper.SetConfigName("config")
}
viper.AutomaticEnv()
// Read config file (ignore if not found for first run)
_ = viper.ReadInConfig()
}
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number",
Long: `Print the version and build information for HostKeeper.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("hostkeeper %s (built: %s)\n", version, buildTime)
},
}
// Execute runs the root command
func Execute() error {
return rootCmd.Execute()
}
// newStorage creates a new JSONStorage with the password flag applied
func newStorage(cfg *config.Config) (*storage.JSONStorage, error) {
store, err := storage.NewJSONStorage(cfg.GetDataDir())
if err != nil {
return nil, err
}
if passwordFlag != "" {
store.SetPassword(passwordFlag)
}
return store, nil
}