diff --git a/pass_mgr/go.mod b/pass_mgr/go.mod index c013613..19e7de1 100644 --- a/pass_mgr/go.mod +++ b/pass_mgr/go.mod @@ -1,10 +1,12 @@ module pass_mgr -go 1.22 +go 1.24.0 require github.com/spf13/cobra v1.8.0 require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/term v0.40.0 // indirect ) diff --git a/pass_mgr/go.sum b/pass_mgr/go.sum index d0e8c2c..9dfa6e5 100644 --- a/pass_mgr/go.sum +++ b/pass_mgr/go.sum @@ -6,5 +6,9 @@ github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pass_mgr/src/main.go b/pass_mgr/src/main.go index 773e31e..474c2a1 100644 --- a/pass_mgr/src/main.go +++ b/pass_mgr/src/main.go @@ -12,9 +12,11 @@ import ( "os" "path/filepath" "strings" + "syscall" "time" "github.com/spf13/cobra" + "golang.org/x/term" ) const ( @@ -173,27 +175,17 @@ func rotateCmd() *cobra.Command { } func adminInitCmd() *cobra.Command { - var keyPath string - cmd := &cobra.Command{ + return &cobra.Command{ Use: "admin init", Short: "Initialize pass_mgr with admin key", Run: func(cmd *cobra.Command, args []string) { - // Require --key-path parameter - if keyPath == "" { - fmt.Fprintln(os.Stderr, "Error: --key-path is required") - fmt.Fprintln(os.Stderr, "Usage: pass_mgr admin init --key-path ") - fmt.Fprintln(os.Stderr, "The key file must contain a password with at least 6 characters") - os.Exit(1) - } - if err := initAdmin(keyPath); err != nil { + if err := initAdminInteractive(); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } fmt.Println("pass_mgr initialized successfully") }, } - cmd.Flags().StringVar(&keyPath, "key-path", "", "Path to admin key file (required, password must be >= 6 chars)") - return cmd } func setCmd() *cobra.Command { @@ -256,32 +248,56 @@ func loadAdminKey() ([]byte, error) { return hash[:], nil } -func initAdmin(keyPath string) error { +func initAdminInteractive() error { + fmt.Print("Enter admin password: ") + password1, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return fmt.Errorf("failed to read password: %w", err) + } + fmt.Println() + + // Trim whitespace/newlines + password1 = []byte(strings.TrimSpace(string(password1))) + + // Validate password length + if len(password1) < 6 { + return fmt.Errorf("password must be at least 6 characters long (got %d)", len(password1)) + } + + fmt.Print("Confirm admin password: ") + password2, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return fmt.Errorf("failed to read password confirmation: %w", err) + } + fmt.Println() + + // Trim whitespace/newlines + password2 = []byte(strings.TrimSpace(string(password2))) + + // Check passwords match + if string(password1) != string(password2) { + return fmt.Errorf("passwords do not match") + } + + // Save the key + return saveAdminKey(password1) +} + +func saveAdminKey(key []byte) error { homeDir := getHomeDir() adminDir := filepath.Join(homeDir, AdminKeyDir) - + // Create admin directory if err := os.MkdirAll(adminDir, 0700); err != nil { return fmt.Errorf("failed to create admin directory: %w", err) } - - // Read provided key - key, err := os.ReadFile(keyPath) - if err != nil { - return fmt.Errorf("failed to read key file: %w", err) - } - - // Validate password length (must be >= 6 characters) - if len(key) < 6 { - return fmt.Errorf("password must be at least 6 characters long (got %d)", len(key)) - } - + // Save key keyFile := filepath.Join(adminDir, AdminKeyFile) if err := os.WriteFile(keyFile, key, 0600); err != nil { return fmt.Errorf("failed to save key: %w", err) } - + // Save config config := Config{ KeyHash: fmt.Sprintf("%x", sha256.Sum256(key)), @@ -292,10 +308,25 @@ func initAdmin(keyPath string) error { if err := os.WriteFile(configPath, configData, 0600); err != nil { return fmt.Errorf("failed to save config: %w", err) } - + return nil } +func initAdmin(keyPath string) error { + // Read provided key + key, err := os.ReadFile(keyPath) + if err != nil { + return fmt.Errorf("failed to read key file: %w", err) + } + + // Validate password length (must be >= 6 characters) + if len(key) < 6 { + return fmt.Errorf("password must be at least 6 characters long (got %d)", len(key)) + } + + return saveAdminKey(key) +} + func getSecretsDir() string { if workspaceDir != "" && agentID != "" { return filepath.Join(workspaceDir, SecretsDirName, agentID)