2022-09-12 11:14:53 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"image/color"
|
2022-09-12 13:31:42 +02:00
|
|
|
"io/fs"
|
2022-09-12 11:14:53 +02:00
|
|
|
"log"
|
|
|
|
"os"
|
2022-09-12 13:31:42 +02:00
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
2022-09-12 11:14:53 +02:00
|
|
|
"strings"
|
2022-09-12 13:31:42 +02:00
|
|
|
"time"
|
2022-09-13 11:54:20 +02:00
|
|
|
|
|
|
|
"fyne.io/fyne/v2"
|
|
|
|
"fyne.io/fyne/v2/app"
|
|
|
|
"fyne.io/fyne/v2/canvas"
|
|
|
|
"fyne.io/fyne/v2/container"
|
|
|
|
"fyne.io/fyne/v2/layout"
|
|
|
|
"fyne.io/fyne/v2/widget"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
directory string
|
|
|
|
configs []Config
|
|
|
|
application fyne.App
|
|
|
|
window fyne.Window
|
|
|
|
menu *container.AppTabs
|
2022-09-12 11:14:53 +02:00
|
|
|
)
|
|
|
|
|
2022-09-12 13:31:42 +02:00
|
|
|
type Config struct {
|
|
|
|
Name string
|
|
|
|
File string
|
|
|
|
}
|
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
type ButtonCallback func()
|
2022-09-12 14:00:24 +02:00
|
|
|
|
2022-09-12 11:14:53 +02:00
|
|
|
func main() {
|
2022-09-13 11:54:20 +02:00
|
|
|
application = app.New()
|
|
|
|
window = application.NewWindow("Wireguard GUI")
|
|
|
|
directory = "/etc/wireguard/"
|
|
|
|
menu = container.NewAppTabs()
|
|
|
|
|
|
|
|
err := initConfigs()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
initMenu()
|
|
|
|
|
|
|
|
content := container.New(layout.NewVBoxLayout(), menu)
|
2022-09-12 13:31:42 +02:00
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
window.SetContent(content)
|
|
|
|
window.Resize(fyne.NewSize(900, 400))
|
|
|
|
window.ShowAndRun()
|
|
|
|
}
|
|
|
|
|
|
|
|
func initMenu() {
|
|
|
|
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],
|
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func initConfigs() error {
|
2022-09-12 13:31:42 +02:00
|
|
|
err := filepath.WalkDir(directory, func(path string, info fs.DirEntry, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2022-09-12 11:14:53 +02:00
|
|
|
|
2022-09-12 13:31:42 +02:00
|
|
|
configs = append(configs, Config{
|
|
|
|
Name: strings.ReplaceAll(basename, ".conf", ""),
|
|
|
|
File: path,
|
|
|
|
})
|
2022-09-12 11:14:53 +02:00
|
|
|
|
2022-09-12 13:31:42 +02:00
|
|
|
return nil
|
|
|
|
})
|
2022-09-12 11:14:53 +02:00
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
return err
|
|
|
|
}
|
2022-09-12 13:31:42 +02:00
|
|
|
|
2023-12-27 19:09:45 +01:00
|
|
|
func toggleNotice(notice *widget.Label, isVisible bool) {
|
2022-09-13 11:54:20 +02:00
|
|
|
notice.Hidden = !isVisible
|
|
|
|
notice.Refresh()
|
|
|
|
}
|
2022-09-12 13:31:42 +02:00
|
|
|
|
2023-12-27 19:09:45 +01:00
|
|
|
func updateNotice(notice *widget.Label, text string, importance widget.Importance, isVisible, isFlash bool) {
|
2022-09-13 11:54:20 +02:00
|
|
|
notice.Text = text
|
2023-12-27 19:09:45 +01:00
|
|
|
notice.Importance = importance
|
2022-09-13 11:54:20 +02:00
|
|
|
notice.Hidden = !isVisible
|
|
|
|
notice.Refresh()
|
2022-09-12 13:31:42 +02:00
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
if isFlash {
|
|
|
|
go func() {
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
toggleNotice(notice, false)
|
|
|
|
}()
|
2022-09-12 13:31:42 +02:00
|
|
|
}
|
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
log.Println(text)
|
2022-09-12 13:31:42 +02:00
|
|
|
}
|
|
|
|
|
2023-12-27 19:09:45 +01:00
|
|
|
func wgUp(config Config, notice *widget.Label) {
|
|
|
|
updateNotice(notice, fmt.Sprintf("Interface is starting"), widget.WarningImportance, true, false)
|
2022-09-12 13:31:42 +02:00
|
|
|
exec.Command("wg-quick", "up", config.Name).Output()
|
2023-12-27 19:09:45 +01:00
|
|
|
updateNotice(notice, fmt.Sprintf("Interface is up"), widget.SuccessImportance, true, true)
|
2022-09-12 13:31:42 +02:00
|
|
|
}
|
|
|
|
|
2023-12-27 19:09:45 +01:00
|
|
|
func wgDown(config Config, notice *widget.Label) {
|
|
|
|
updateNotice(notice, fmt.Sprintf("Interface is stopping"), widget.WarningImportance, true, false)
|
2022-09-12 13:31:42 +02:00
|
|
|
exec.Command("wg-quick", "down", config.Name).Output()
|
2023-12-27 19:09:45 +01:00
|
|
|
updateNotice(notice, fmt.Sprintf("Interface is down"), widget.SuccessImportance, true, true)
|
2022-09-12 13:31:42 +02:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
notice.Hidden = true
|
|
|
|
notice.Refresh()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2023-12-27 19:09:45 +01:00
|
|
|
func wgRestart(config Config, notice *widget.Label) {
|
2022-09-13 12:01:33 +02:00
|
|
|
wgDown(config, notice)
|
|
|
|
wgUp(config, notice)
|
2022-09-12 13:31:42 +02:00
|
|
|
}
|
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
func lintConfiguration(configuration string) string {
|
|
|
|
configuration = strings.TrimSpace(configuration)
|
|
|
|
configuration = fmt.Sprintf("%s\n", configuration)
|
|
|
|
|
|
|
|
return configuration
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateTextareaConfiguration(textarea *widget.Entry, content string) {
|
|
|
|
textarea.SetText(content)
|
|
|
|
textarea.OnChanged(content)
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateConfigFile(config Config, content string) error {
|
|
|
|
return os.WriteFile(config.File, []byte(content), 600)
|
|
|
|
}
|
|
|
|
|
|
|
|
func createTextarea() *widget.Entry {
|
|
|
|
textarea := widget.NewMultiLineEntry()
|
2022-09-13 14:30:58 +02:00
|
|
|
textarea.TextStyle.Monospace = true
|
2022-09-13 11:54:20 +02:00
|
|
|
textarea.OnChanged = func(text string) {
|
|
|
|
textarea.SetMinRowsVisible(strings.Count(text, "\n"))
|
|
|
|
textarea.Refresh()
|
|
|
|
}
|
|
|
|
|
|
|
|
return textarea
|
|
|
|
}
|
|
|
|
|
2023-12-27 19:09:45 +01:00
|
|
|
func createColoredButton(label string, importance widget.Importance, callback ButtonCallback) *fyne.Container {
|
|
|
|
button := widget.NewButton(label, callback)
|
|
|
|
button.Importance = importance
|
|
|
|
|
|
|
|
return container.NewMax(button)
|
2022-09-13 11:54:20 +02:00
|
|
|
}
|
|
|
|
|
2023-12-27 19:09:45 +01:00
|
|
|
func createNotice() *widget.Label {
|
|
|
|
notice := widget.NewLabel("")
|
2022-09-12 13:31:42 +02:00
|
|
|
notice.TextStyle.Bold = true
|
2023-12-27 19:09:45 +01:00
|
|
|
notice.Importance = widget.LowImportance
|
2022-09-12 13:31:42 +02:00
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
return notice
|
|
|
|
}
|
2022-09-12 13:31:42 +02:00
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
func createMargin() *canvas.Text {
|
|
|
|
text := canvas.NewText("", color.Transparent)
|
|
|
|
text.TextSize = 5
|
|
|
|
|
|
|
|
return text
|
|
|
|
}
|
2022-09-12 13:31:42 +02:00
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
func createTab(config Config) *fyne.Container {
|
|
|
|
data, err := os.ReadFile(config.File)
|
2022-09-12 13:31:42 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
notice := createNotice()
|
|
|
|
|
2023-12-27 19:09:45 +01:00
|
|
|
buttonStart := createColoredButton("Start", widget.SuccessImportance, func() {
|
2022-09-13 12:01:33 +02:00
|
|
|
wgUp(config, notice)
|
2022-09-12 13:31:42 +02:00
|
|
|
})
|
|
|
|
|
2023-12-27 19:09:45 +01:00
|
|
|
buttonStop := createColoredButton("Stop", widget.DangerImportance, func() {
|
2022-09-13 12:01:33 +02:00
|
|
|
wgDown(config, notice)
|
2022-09-12 13:31:42 +02:00
|
|
|
})
|
|
|
|
|
2023-12-27 19:09:45 +01:00
|
|
|
buttonRestart := createColoredButton("Restart", widget.WarningImportance, func() {
|
2022-09-13 12:01:33 +02:00
|
|
|
wgRestart(config, notice)
|
2022-09-12 13:31:42 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
top := container.New(
|
|
|
|
layout.NewVBoxLayout(),
|
2022-09-13 11:54:20 +02:00
|
|
|
createMargin(),
|
2022-09-12 13:31:42 +02:00
|
|
|
container.New(
|
|
|
|
layout.NewHBoxLayout(),
|
|
|
|
notice,
|
2022-09-12 14:00:24 +02:00
|
|
|
layout.NewSpacer(),
|
2022-09-13 11:54:20 +02:00
|
|
|
buttonStart,
|
|
|
|
buttonStop,
|
|
|
|
buttonRestart,
|
2022-09-12 13:31:42 +02:00
|
|
|
),
|
2022-09-13 11:54:20 +02:00
|
|
|
createMargin(),
|
2022-09-12 13:31:42 +02:00
|
|
|
)
|
2022-09-12 11:14:53 +02:00
|
|
|
|
2022-09-13 11:54:20 +02:00
|
|
|
textareaConfiguration := createTextarea()
|
|
|
|
updateTextareaConfiguration(textareaConfiguration, string(data))
|
2022-09-12 11:14:53 +02:00
|
|
|
|
|
|
|
form := &widget.Form{
|
|
|
|
Items: []*widget.FormItem{
|
|
|
|
{
|
|
|
|
Text: "Configuration",
|
|
|
|
Widget: textareaConfiguration,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
OnSubmit: func() {
|
2022-09-13 11:54:20 +02:00
|
|
|
toggleNotice(notice, false)
|
|
|
|
|
|
|
|
configuration := lintConfiguration(textareaConfiguration.Text)
|
|
|
|
updateTextareaConfiguration(textareaConfiguration, configuration)
|
|
|
|
err := updateConfigFile(config, configuration)
|
2022-09-12 11:14:53 +02:00
|
|
|
|
2022-09-13 14:30:58 +02:00
|
|
|
log.Println("Configuration of", config.Name)
|
|
|
|
|
2022-09-12 11:14:53 +02:00
|
|
|
if err != nil {
|
2023-12-27 19:09:45 +01:00
|
|
|
updateNotice(notice, fmt.Sprintf("Error while updating: %s", err), widget.DangerImportance, true, false)
|
2022-09-12 11:14:53 +02:00
|
|
|
} else {
|
2023-12-27 19:09:45 +01:00
|
|
|
updateNotice(notice, fmt.Sprintf("Configuration updated"), widget.SuccessImportance, true, true)
|
2022-09-12 11:14:53 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
SubmitText: "Save",
|
|
|
|
}
|
|
|
|
|
2022-09-12 13:31:42 +02:00
|
|
|
content := container.New(
|
|
|
|
layout.NewVBoxLayout(),
|
|
|
|
top,
|
|
|
|
form,
|
|
|
|
)
|
2022-09-12 11:14:53 +02:00
|
|
|
|
2022-09-12 13:31:42 +02:00
|
|
|
return content
|
2022-09-12 11:14:53 +02:00
|
|
|
}
|