234 lines
5.3 KiB
Go
234 lines
5.3 KiB
Go
package utils
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
)
|
|
|
|
// FileExists checks if a file exists
|
|
func FileExists(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return !os.IsNotExist(err)
|
|
}
|
|
|
|
// ReadFileLines reads a file and returns its lines
|
|
func ReadFileLines(path string) ([]string, error) {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
var lines []string
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
return lines, scanner.Err()
|
|
}
|
|
|
|
// ReadFirstLine reads the first line of a file
|
|
func ReadFirstLine(path string) (string, error) {
|
|
lines, err := ReadFileLines(path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(lines) == 0 {
|
|
return "", fmt.Errorf("file is empty")
|
|
}
|
|
return lines[0], nil
|
|
}
|
|
|
|
// ParseKeyValue parses a key=value string
|
|
func ParseKeyValue(line string) (string, string, bool) {
|
|
parts := strings.SplitN(line, "=", 2)
|
|
if len(parts) != 2 {
|
|
return "", "", false
|
|
}
|
|
key := strings.TrimSpace(parts[0])
|
|
value := strings.TrimSpace(parts[1])
|
|
// Remove quotes if present
|
|
value = strings.Trim(value, `"'`)
|
|
return key, value, true
|
|
}
|
|
|
|
// ParseInt64 safely parses a string to int64
|
|
func ParseInt64(s string) int64 {
|
|
val, err := strconv.ParseInt(s, 10, 64)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return val
|
|
}
|
|
|
|
// ParseInt safely parses a string to int
|
|
func ParseInt(s string) int {
|
|
val, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return val
|
|
}
|
|
|
|
// IsRoot checks if the current user is root
|
|
func IsRoot() bool {
|
|
return os.Geteuid() == 0
|
|
}
|
|
|
|
// RunCommand executes a command and returns its output
|
|
func RunCommand(name string, args ...string) (string, error) {
|
|
cmd := exec.Command(name, args...)
|
|
output, err := cmd.Output()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return strings.TrimSpace(string(output)), nil
|
|
}
|
|
|
|
// RunCommandWithInput executes a command with stdin input
|
|
func RunCommandWithInput(input, name string, args ...string) (string, error) {
|
|
cmd := exec.Command(name, args...)
|
|
cmd.Stdin = strings.NewReader(input)
|
|
output, err := cmd.Output()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return strings.TrimSpace(string(output)), nil
|
|
}
|
|
|
|
// CommandExists checks if a command exists in PATH
|
|
func CommandExists(cmd string) bool {
|
|
_, err := exec.LookPath(cmd)
|
|
return err == nil
|
|
}
|
|
|
|
// GetUserConfirmation prompts user for yes/no confirmation
|
|
func GetUserConfirmation(prompt string) bool {
|
|
fmt.Printf("%s (y/N): ", prompt)
|
|
var response string
|
|
fmt.Scanln(&response)
|
|
response = strings.ToLower(strings.TrimSpace(response))
|
|
return response == "y" || response == "yes"
|
|
}
|
|
|
|
// GetUserInput prompts user for input with a default value
|
|
func GetUserInput(prompt, defaultValue string) string {
|
|
if defaultValue != "" {
|
|
fmt.Printf("%s [%s]: ", prompt, defaultValue)
|
|
} else {
|
|
fmt.Printf("%s: ", prompt)
|
|
}
|
|
|
|
var input string
|
|
fmt.Scanln(&input)
|
|
input = strings.TrimSpace(input)
|
|
|
|
if input == "" {
|
|
return defaultValue
|
|
}
|
|
return input
|
|
}
|
|
|
|
// EnsureRoot ensures the program is running with root privileges
|
|
func EnsureRoot() error {
|
|
if !IsRoot() {
|
|
return fmt.Errorf("this operation requires root privileges")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RequestElevation requests privilege elevation using sudo
|
|
func RequestElevation(args []string) error {
|
|
if IsRoot() {
|
|
return nil
|
|
}
|
|
|
|
fmt.Println("This operation requires elevated privileges.")
|
|
if !GetUserConfirmation("Continue with sudo?") {
|
|
return fmt.Errorf("operation cancelled by user")
|
|
}
|
|
|
|
// Prepare sudo command
|
|
sudoArgs := append([]string{os.Args[0]}, args...)
|
|
cmd := exec.Command("sudo", sudoArgs...)
|
|
cmd.Stdin = os.Stdin
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
|
|
// Execute with sudo
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
if exitError, ok := err.(*exec.ExitError); ok {
|
|
if status, ok := exitError.Sys().(syscall.WaitStatus); ok {
|
|
os.Exit(status.ExitStatus())
|
|
}
|
|
}
|
|
return fmt.Errorf("failed to execute with elevated privileges: %w", err)
|
|
}
|
|
|
|
// Exit successfully since the elevated process completed
|
|
os.Exit(0)
|
|
return nil // This line will never be reached
|
|
}
|
|
|
|
// SanitizeInput sanitizes user input by removing potentially dangerous characters
|
|
func SanitizeInput(input string) string {
|
|
// Remove null bytes and control characters
|
|
sanitized := strings.ReplaceAll(input, "\x00", "")
|
|
sanitized = strings.TrimSpace(sanitized)
|
|
|
|
// Basic validation - reject inputs with shell metacharacters
|
|
dangerous := []string{";", "&", "|", "`", "$", "(", ")", "<", ">", "\"", "'"}
|
|
for _, char := range dangerous {
|
|
if strings.Contains(sanitized, char) {
|
|
return ""
|
|
}
|
|
}
|
|
|
|
return sanitized
|
|
}
|
|
|
|
// FormatBytes formats bytes into human-readable format
|
|
func FormatBytes(bytes int64) string {
|
|
const unit = 1024
|
|
if bytes < unit {
|
|
return fmt.Sprintf("%d B", bytes)
|
|
}
|
|
|
|
div, exp := int64(unit), 0
|
|
for n := bytes / unit; n >= unit; n /= unit {
|
|
div *= unit
|
|
exp++
|
|
}
|
|
|
|
units := []string{"KB", "MB", "GB", "TB", "PB"}
|
|
return fmt.Sprintf("%.1f %s", float64(bytes)/float64(div), units[exp])
|
|
}
|
|
|
|
// Contains checks if a slice contains a string
|
|
func Contains(slice []string, item string) bool {
|
|
for _, s := range slice {
|
|
if s == item {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// RemoveEmpty removes empty strings from a slice
|
|
func RemoveEmpty(slice []string) []string {
|
|
var result []string
|
|
for _, s := range slice {
|
|
if strings.TrimSpace(s) != "" {
|
|
result = append(result, s)
|
|
}
|
|
}
|
|
return result
|
|
}
|