feat: interactive password input for pass_mgr admin init
- Remove --key-path parameter requirement - Add interactive password prompt (hidden input like sudo) - Require password confirmation - Password must be at least 6 characters - Uses golang.org/x/term for secure password input
This commit is contained in:
@@ -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 <path-to-key-file>")
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user