diff --git a/main.go b/main.go index 3f2f03e..46a65e2 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package main import ( - "flag" "fmt" "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" @@ -10,26 +9,164 @@ import ( "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/widget" "image/color" + "io/fs" "log" "os" + "os/exec" + "path/filepath" "strings" + "time" ) +type Config struct { + Name string + File string +} + func main() { application := app.New() window := application.NewWindow("Wireguard GUI (deblan)") + configs := []Config{} + directory := "/etc/wireguard/" - iface := flag.String("iface", "wg0", "wireguard iface") - filename := flag.String("filename", "/etc/wireguard/wg0.conf", "wireguard iface") - flag.Parse() + err := filepath.WalkDir(directory, func(path string, info fs.DirEntry, err error) error { + if err != nil { + return err + } - data, err := os.ReadFile(*filename) + if info.IsDir() { + return nil + } + + basename := string(info.Name()) + + if !strings.HasSuffix(basename, ".conf") { + return nil + } + + if strings.Contains(strings.ReplaceAll(path, directory, ""), "/") { + return nil + } + + configs = append(configs, Config{ + Name: strings.ReplaceAll(basename, ".conf", ""), + File: path, + }) + + return nil + }) if err != nil { log.Fatalln(err) - os.Exit(1) } - _ = iface + + menu := container.NewAppTabs() + tabs := make([]fyne.Container, len(configs)) + + for i, config := range configs { + tabs[i] = *createTab(config) + } + + for i, config := range configs { + menu.Append( + container.NewTabItem( + config.Name, + &tabs[i], + ), + ) + } + + content := container.New(layout.NewVBoxLayout(), menu) + + window.SetContent(content) + window.Resize(fyne.NewSize(900, 400)) + window.ShowAndRun() +} + +func WgUp(config Config, notice *canvas.Text) { + notice.Hidden = false + notice.Text = fmt.Sprintf("Interface is starting") + notice.Color = color.RGBA{R: 200, G: 165, B: 76} + notice.Refresh() + + exec.Command("wg-quick", "up", config.Name).Output() + + notice.Text = fmt.Sprintf("Interface is up") + notice.Color = color.RGBA{R: 111, G: 200, B: 72} + notice.Refresh() + + go func() { + time.Sleep(2 * time.Second) + notice.Hidden = true + notice.Refresh() + }() +} + +func WgDown(config Config, notice *canvas.Text) { + notice.Refresh() + + notice.Hidden = false + notice.Text = fmt.Sprintf("Interface is stopping") + notice.Color = color.RGBA{R: 200, G: 165, B: 76} + notice.Refresh() + + exec.Command("wg-quick", "down", config.Name).Output() + + notice.Text = fmt.Sprintf("Interface is down") + notice.Color = color.RGBA{R: 111, G: 200, B: 72} + notice.Refresh() + + go func() { + time.Sleep(2 * time.Second) + notice.Hidden = true + notice.Refresh() + }() +} + +func WgRestart(config Config, notice *canvas.Text) { + WgDown(config, notice) + WgUp(config, notice) +} + +func createTab(config Config) *fyne.Container { + notice := canvas.NewText("", color.White) + notice.TextStyle.Bold = true + + r1 := canvas.NewText("", color.Transparent) + r2 := canvas.NewText("", color.Transparent) + r1.TextSize = 5 + r2.TextSize = 5 + + data, err := os.ReadFile(config.File) + + if err != nil { + log.Fatalln(err) + } + + buttonStart := widget.NewButton("Start", func() { + WgUp(config, notice) + }) + + buttonStop := widget.NewButton("Stop", func() { + WgDown(config, notice) + }) + + buttonRestart := widget.NewButton("Restart", func() { + WgRestart(config, notice) + }) + + top := container.New( + layout.NewVBoxLayout(), + r1, + container.New( + layout.NewHBoxLayout(), + buttonStart, + buttonStop, + buttonRestart, + notice, + ), + r2, + ) configuration := string(data) @@ -37,7 +174,10 @@ func main() { textareaConfiguration.SetText(configuration) textareaConfiguration.SetMinRowsVisible(strings.Count(configuration, "\n")) - notice := canvas.NewText("", color.White) + textareaConfiguration.OnChanged = func(text string) { + textareaConfiguration.SetMinRowsVisible(strings.Count(text, "\n")) + textareaConfiguration.Refresh() + } form := &widget.Form{ Items: []*widget.FormItem{ @@ -47,20 +187,24 @@ func main() { }, }, OnSubmit: func() { - notice.Text = "" - notice.Refresh() - - configuration := textareaConfiguration.Text - err := os.WriteFile(*filename, []byte(configuration), 600) + notice.Hidden = false + configuration := fmt.Sprintf("%s\n", textareaConfiguration.Text) + err := os.WriteFile(config.File, []byte(configuration), 600) if err != nil { log.Println(err) - notice.Text = fmt.Sprintf("Error: %s", err) - notice.Color = color.RGBA{R: 255} + notice.Text = fmt.Sprintf("Error while updating: %s", err) + notice.Color = color.RGBA{R: 200, G: 68, B: 68} notice.Refresh() } else { - notice.Text = "Configuration updated!" - notice.Color = color.RGBA{G: 255} + notice.Text = fmt.Sprintf("Configuration updated") + notice.Color = color.RGBA{R: 111, G: 200, B: 72} + + go func() { + time.Sleep(2 * time.Second) + notice.Hidden = true + notice.Refresh() + }() } notice.Refresh() @@ -68,9 +212,11 @@ func main() { SubmitText: "Save", } - content := container.New(layout.NewVBoxLayout(), form, notice) + content := container.New( + layout.NewVBoxLayout(), + top, + form, + ) - window.SetContent(content) - window.Resize(fyne.NewSize(900, 400)) - window.ShowAndRun() + return content }