Add WireGuard TUI implementation
- Add Go TUI with bubbletea for WireGuard management - Implement client CRUD operations with QR code generation - Add configuration and validation modules - Install/update scripts for client setup - Update Makefile to build binaries to bin/ directory - Add .gitignore for Go projects
This commit is contained in:
122
internal/backup/restore.go
Normal file
122
internal/backup/restore.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package backup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ValidateBackup checks if a backup exists and is valid
|
||||
func ValidateBackup(backupName string) error {
|
||||
backupDir := "/etc/wg-admin/backups"
|
||||
backupPath := filepath.Join(backupDir, backupName)
|
||||
|
||||
// Check if backup directory exists
|
||||
info, err := os.Stat(backupPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("backup '%s' does not exist", backupName)
|
||||
}
|
||||
return fmt.Errorf("failed to access backup '%s': %w", backupName, err)
|
||||
}
|
||||
|
||||
// Check if it's a directory
|
||||
if !info.IsDir() {
|
||||
return fmt.Errorf("'%s' is not a valid backup directory", backupName)
|
||||
}
|
||||
|
||||
// Check for required files
|
||||
metadataPath := filepath.Join(backupPath, "backup-info.txt")
|
||||
if _, err := os.Stat(metadataPath); os.IsNotExist(err) {
|
||||
return fmt.Errorf("backup '%s' is missing required metadata", backupName)
|
||||
}
|
||||
|
||||
// Check for wireguard directory
|
||||
wgBackupPath := filepath.Join(backupPath, "wireguard")
|
||||
if _, err := os.Stat(wgBackupPath); os.IsNotExist(err) {
|
||||
return fmt.Errorf("backup '%s' is missing wireguard configuration", backupName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReloadWireGuard reloads the WireGuard interface to apply configuration changes
|
||||
func ReloadWireGuard() error {
|
||||
interfaceName := "wg0"
|
||||
|
||||
// Try to down the interface first
|
||||
cmdDown := exec.Command("wg-quick", "down", interfaceName)
|
||||
_ = cmdDown.Run() // Ignore errors if interface is not up
|
||||
|
||||
// Bring the interface up
|
||||
cmdUp := exec.Command("wg-quick", "up", interfaceName)
|
||||
output, err := cmdUp.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to reload wireguard interface: %w, output: %s", err, string(output))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBackupSize calculates the total size of a backup directory
|
||||
func GetBackupSize(backupName string) (int64, error) {
|
||||
backupDir := "/etc/wg-admin/backups"
|
||||
backupPath := filepath.Join(backupDir, backupName)
|
||||
|
||||
var size int64
|
||||
|
||||
err := filepath.Walk(backupPath, func(_ string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
size += info.Size()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return size, err
|
||||
}
|
||||
|
||||
// GetBackupPath returns the full path for a backup name
|
||||
func GetBackupPath(backupName string) string {
|
||||
return filepath.Join("/etc/wg-admin/backups", backupName)
|
||||
}
|
||||
|
||||
// ParseBackupName extracts operation and timestamp from backup directory name
|
||||
// Format: wg-backup-{operation}-{timestamp}
|
||||
func ParseBackupName(backupName string) (operation, timestamp string, err error) {
|
||||
if !strings.HasPrefix(backupName, "wg-backup-") {
|
||||
return "", "", fmt.Errorf("invalid backup name format")
|
||||
}
|
||||
|
||||
nameWithoutPrefix := strings.TrimPrefix(backupName, "wg-backup-")
|
||||
|
||||
// Timestamp format: 20060102-150405 (15 chars)
|
||||
if len(nameWithoutPrefix) < 16 {
|
||||
return "", "", fmt.Errorf("backup name too short")
|
||||
}
|
||||
|
||||
// Extract operation (everything before last timestamp)
|
||||
timestampLen := 15
|
||||
if len(nameWithoutPrefix) > timestampLen+1 {
|
||||
operation = nameWithoutPrefix[:len(nameWithoutPrefix)-timestampLen-1]
|
||||
// Remove trailing dash if present
|
||||
if strings.HasSuffix(operation, "-") {
|
||||
operation = operation[:len(operation)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// Extract timestamp
|
||||
timestamp = nameWithoutPrefix[len(nameWithoutPrefix)-timestampLen:]
|
||||
|
||||
// Validate timestamp format
|
||||
if _, err := time.Parse("20060102-150405", timestamp); err != nil {
|
||||
return "", "", fmt.Errorf("invalid timestamp format in backup name: %w", err)
|
||||
}
|
||||
|
||||
return operation, timestamp, nil
|
||||
}
|
||||
Reference in New Issue
Block a user