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:
@@ -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
|
||||
)
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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,7 +248,42 @@ 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)
|
||||
|
||||
@@ -265,17 +292,6 @@ func initAdmin(keyPath string) error {
|
||||
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 {
|
||||
@@ -296,6 +312,21 @@ func initAdmin(keyPath string) error {
|
||||
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