summaryrefslogtreecommitdiff
path: root/pkg/wgconf
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/wgconf')
-rw-r--r--pkg/wgconf/wgconf.go97
-rw-r--r--pkg/wgconf/wgconf_test.go66
2 files changed, 158 insertions, 5 deletions
diff --git a/pkg/wgconf/wgconf.go b/pkg/wgconf/wgconf.go
new file mode 100644
index 0000000..2615892
--- /dev/null
+++ b/pkg/wgconf/wgconf.go
@@ -0,0 +1,97 @@
+package wgconf
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strings"
+)
+
+// Config represents a parsed WireGuard configuration file.
+type Config struct {
+ PrivateKey string
+ Address string
+ DNS string
+ Peers []Peer
+}
+
+// Peer represents a WireGuard peer.
+type Peer struct {
+ PublicKey string
+ Endpoint string
+ AllowedIPs []string
+}
+
+// Parse reads a WireGuard .conf file and returns a Config struct.
+func Parse(path string) (*Config, error) {
+ file, err := os.Open(path)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open config file: %w", err)
+ }
+ defer func() {
+ if err := file.Close(); err != nil {
+ // We use a simple print here because we are in a defer
+ fmt.Printf("warning: failed to close config file %s: %v\n", path, err)
+ }
+ }()
+
+ cfg := &Config{}
+ var currentPeer *Peer
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ line := strings.TrimSpace(scanner.Text())
+ if line == "" || strings.HasPrefix(line, "#") {
+ continue
+ }
+
+ if strings.HasPrefix(line, "[") {
+ section := strings.Trim(line, "[]")
+ if section == "Peer" {
+ if currentPeer != nil {
+ cfg.Peers = append(cfg.Peers, *currentPeer)
+ }
+ currentPeer = &Peer{}
+ }
+ continue
+ }
+
+ parts := strings.SplitN(line, "=", 2)
+ if len(parts) != 2 {
+ return nil, fmt.Errorf("invalid line format: %s", line)
+ }
+
+ key := strings.TrimSpace(parts[0])
+ val := strings.TrimSpace(parts[1])
+
+ if currentPeer != nil {
+ switch key {
+ case "PublicKey":
+ currentPeer.PublicKey = val
+ case "Endpoint":
+ currentPeer.Endpoint = val
+ case "AllowedIPs":
+ currentPeer.AllowedIPs = strings.Split(val, ",")
+ }
+ } else {
+ switch key {
+ case "PrivateKey":
+ cfg.PrivateKey = val
+ case "Address":
+ cfg.Address = val
+ case "DNS":
+ cfg.DNS = val
+ }
+ }
+ }
+
+ if currentPeer != nil {
+ cfg.Peers = append(cfg.Peers, *currentPeer)
+ }
+
+ if err := scanner.Err(); err != nil {
+ return nil, fmt.Errorf("error reading config file: %w", err)
+ }
+
+ return cfg, nil
+}
diff --git a/pkg/wgconf/wgconf_test.go b/pkg/wgconf/wgconf_test.go
index d0bcb0b..805aeaa 100644
--- a/pkg/wgconf/wgconf_test.go
+++ b/pkg/wgconf/wgconf_test.go
@@ -1,15 +1,71 @@
package wgconf
import (
+ "os"
+ "path/filepath"
"testing"
)
func TestParseConfig(t *testing.T) {
- // Test that valid .conf files are parsed correctly and invalid ones return errors.
- t.Skip("not implemented")
+ content := `[Interface]
+PrivateKey = ABC123XYZ
+Address = 10.0.0.1/24
+DNS = 1.1.1.1
+
+[Peer]
+PublicKey = DEF456UVW
+Endpoint = 1.2.3.4:51820
+AllowedIPs = 0.0.0.0/0
+
+[Peer]
+PublicKey = GHI789TSR
+Endpoint = 5.6.7.8:51820
+AllowedIPs = 192.168.1.0/24, 192.168.2.0/24`
+
+ tmpFile := filepath.Join(t.TempDir(), "test.conf")
+ if err := os.WriteFile(tmpFile, []byte(content), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ cfg, err := Parse(tmpFile)
+ if err != nil {
+ t.Fatalf("Parse failed: %v", err)
+ }
+
+ if cfg.PrivateKey != "ABC123XYZ" {
+ t.Errorf("expected PrivateKey ABC123XYZ, got %s", cfg.PrivateKey)
+ }
+ if cfg.Address != "10.0.0.1/24" {
+ t.Errorf("expected Address 10.0.0.1/24, got %s", cfg.Address)
+ }
+ if cfg.DNS != "1.1.1.1" {
+ t.Errorf("expected DNS 1.1.1.1, got %s", cfg.DNS)
+ }
+ if len(cfg.Peers) != 2 {
+ t.Fatalf("expected 2 peers, got %d", len(cfg.Peers))
+ }
+
+ p1 := cfg.Peers[0]
+ if p1.PublicKey != "DEF456UVW" || p1.Endpoint != "1.2.3.4:51820" || len(p1.AllowedIPs) != 1 || p1.AllowedIPs[0] != "0.0.0.0/0" {
+ t.Errorf("Peer 1 mismatch: %+v", p1)
+ }
+
+ p2 := cfg.Peers[1]
+ if p2.PublicKey != "GHI789TSR" || p2.Endpoint != "5.6.7.8:51820" || len(p2.AllowedIPs) != 2 || p2.AllowedIPs[0] != "192.168.1.0/24" {
+ t.Errorf("Peer 2 mismatch: %+v", p2)
+ }
}
-func TestValidateProfile(t *testing.T) {
- // Test that profile names are resolved correctly to ~/.config/wg-wrap/profiles/*.conf.
- t.Skip("not implemented")
+func TestParseInvalidConfig(t *testing.T) {
+ content := `[Interface]
+InvalidLineWithoutEquals`
+ tmpFile := filepath.Join(t.TempDir(), "invalid.conf")
+ if err := os.WriteFile(tmpFile, []byte(content), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ _, err := Parse(tmpFile)
+ if err == nil {
+ t.Error("expected error for invalid line format, got nil")
+ }
}