Files
dbbackup/internal/security/paths.go
Renz 0cf21cd893 feat: Complete MEDIUM priority security features with testing
- Implemented TUI auto-select for automated testing
- Fixed TUI automation: autoSelectMsg handling in Update()
- Auto-database selection in DatabaseSelector
- Created focused test suite (test_as_postgres.sh)
- Created retention policy test (test_retention.sh)
- All 10 security tests passing

Features validated:
 Backup retention policy (30 days, min backups)
 Rate limiting (exponential backoff)
 Privilege checks (root detection)
 Resource limit validation
 Path sanitization
 Checksum verification (SHA-256)
 Audit logging
 Secure permissions
 Configuration persistence
 TUI automation framework

Test results: 10/10 passed
Backup files created with .dump, .sha256, .info
Retention cleanup verified (old files removed)
2025-11-25 15:25:56 +00:00

73 lines
1.6 KiB
Go
Executable File

package security
import (
"fmt"
"path/filepath"
"strings"
)
// CleanPath sanitizes a file path to prevent path traversal attacks
func CleanPath(path string) (string, error) {
if path == "" {
return "", fmt.Errorf("path cannot be empty")
}
// Clean the path (removes .., ., //)
cleaned := filepath.Clean(path)
// Detect path traversal attempts
if strings.Contains(cleaned, "..") {
return "", fmt.Errorf("path traversal detected: %s", path)
}
return cleaned, nil
}
// ValidateBackupPath ensures backup path is safe
func ValidateBackupPath(path string) (string, error) {
cleaned, err := CleanPath(path)
if err != nil {
return "", err
}
// Convert to absolute path
absPath, err := filepath.Abs(cleaned)
if err != nil {
return "", fmt.Errorf("failed to get absolute path: %w", err)
}
return absPath, nil
}
// ValidateArchivePath validates an archive file path
func ValidateArchivePath(path string) (string, error) {
cleaned, err := CleanPath(path)
if err != nil {
return "", err
}
// Must have a valid archive extension
ext := strings.ToLower(filepath.Ext(cleaned))
validExtensions := []string{".dump", ".sql", ".gz", ".tar"}
valid := false
for _, validExt := range validExtensions {
if strings.HasSuffix(cleaned, validExt) {
valid = true
break
}
}
if !valid {
return "", fmt.Errorf("invalid archive extension: %s (must be .dump, .sql, .gz, or .tar)", ext)
}
// Convert to absolute path
absPath, err := filepath.Abs(cleaned)
if err != nil {
return "", fmt.Errorf("failed to get absolute path: %w", err)
}
return absPath, nil
}