package ui import ( "bufio" "fmt" "os" "strings" "syscall" "golang.org/x/term" ) // GetUserInputForGhcr prompts the user for GitHub-related credentials for GHCR. func GetUserInputForGhcr() (username, registryToken, orgToken string, err error) { reader := bufio.NewReader(os.Stdin) fmt.Print("Enter your GitHub username: ") username, err = reader.ReadString('\n') if err != nil { return } username = strings.TrimSpace(username) if username == "" { err = fmt.Errorf("username cannot be empty") return } registryToken, err = promptForToken(reader, "Enter your GitHub PAT for container registry") if err != nil { return } orgToken, err = promptForToken(reader, "Enter your GitHub PAT for organization management") if err != nil { return } return } // GetUserInputForDockerHub prompts the user for Docker Hub credentials. func GetUserInputForDockerHub() (username, password string, err error) { reader := bufio.NewReader(os.Stdin) fmt.Print("Enter your Docker Hub username: ") username, err = reader.ReadString('\n') if err != nil { return } username = strings.TrimSpace(username) fmt.Print("Enter your Docker Hub password or access token: ") passwordBytes, err := term.ReadPassword(int(syscall.Stdin)) fmt.Println() if err != nil { return "", "", err } password = string(passwordBytes) if username == "" || password == "" { err = fmt.Errorf("username and password cannot be empty") } return } // GetUserInputForGithubAuth prompts the user for a general GitHub PAT. func GetUserInputForGithubAuth() (username, token string, err error) { reader := bufio.NewReader(os.Stdin) fmt.Print("Enter your GitHub username: ") username, err = reader.ReadString('\n') if err != nil { return } username = strings.TrimSpace(username) if username == "" { err = fmt.Errorf("username cannot be empty") return } token, err = promptForToken(reader, "Enter your GitHub PAT for repository access") if err != nil { return } return } func promptForToken(reader *bufio.Reader, prompt string) (string, error) { token := promptSecret(reader, prompt, "") if token == "" { return "", fmt.Errorf("token cannot be empty") } validPrefixes := []string{"ghp_", "gho_", "ghu_", "ghs_", "ghr_", "github_pat_"} hasValidPrefix := false for _, prefix := range validPrefixes { if strings.HasPrefix(token, prefix) { hasValidPrefix = true break } } if !hasValidPrefix { fmt.Printf("[WARNING] The token does not appear to be a valid GitHub PAT (should start with one of %v)\n", validPrefixes) fmt.Print("Do you want to continue anyway? (y/N): ") confirm, _ := reader.ReadString('\n') if strings.TrimSpace(strings.ToLower(confirm)) != "y" { return "", fmt.Errorf("operation cancelled by user") } } return token, nil } func promptSecret(reader *bufio.Reader, prompt, fallback string) string { if fallback != "" { fmt.Printf("%s [saved]: ", prompt) } else { fmt.Printf("%s: ", prompt) } secretBytes, err := term.ReadPassword(int(syscall.Stdin)) fmt.Println() if err != nil { return fallback } secret := strings.TrimSpace(string(secretBytes)) if secret == "" { return fallback } return secret }