//go:build windows package sys import ( "fmt" "log" "os/exec" "strings" ) // EnsureInboundTCPPort adds a Windows Firewall inbound allow rule for the control server port. func EnsureInboundTCPPort(port int, ruleName string) error { if port <= 0 { return fmt.Errorf("invalid port") } if strings.TrimSpace(ruleName) == "" { ruleName = "AetherForge Control Server" } nameEsc := strings.ReplaceAll(ruleName, `'`, `''`) script := fmt.Sprintf(` $name = '%s' $port = %d if (Get-NetFirewallRule -DisplayName $name -ErrorAction SilentlyContinue) { exit 0 } New-NetFirewallRule -DisplayName $name -Direction Inbound -Protocol TCP -LocalPort $port -Action Allow -Profile Any | Out-Null `, nameEsc, port) cmd := exec.Command("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", script) if err := cmd.Run(); err != nil { return fmt.Errorf("firewall rule: %w (run server once as Administrator or open port %d manually)", err, port) } log.Printf("[firewall] inbound TCP %d allowed (%s)", port, ruleName) return nil }