package gui import ( "os/exec" "sort" "strconv" "strings" "time" "github.com/UnnoTed/wireguird/gui/get" "github.com/dustin/go-humanize" "github.com/gotk3/gotk3/glib" "github.com/gotk3/gotk3/gtk" "github.com/rs/zerolog/log" "github.com/ungerik/go-dry" "gopkg.in/ini.v1" ) var Connected = false type Tunnels struct { Interface struct { Status *gtk.Label PublicKey *gtk.Label ListenPort *gtk.Label Addresses *gtk.Label DNS *gtk.Label } Peer struct { PublicKey *gtk.Label AllowedIPs *gtk.Label Endpoint *gtk.Label LatestHandshake *gtk.Label Transfer *gtk.Label } ButtonChangeState *gtk.Button icons map[string]*gtk.Image ticker *time.Ticker } func (t *Tunnels) Create() error { t.icons = map[string]*gtk.Image{} t.ticker = time.NewTicker(1 * time.Second) var configList []string list, err := dry.ListDirFiles("/etc/wireguard/") if err != nil { // showError(err) return err } for _, fileName := range list { if !strings.HasSuffix(fileName, ".conf") { continue } configList = append(configList, strings.TrimSuffix(fileName, ".conf")) } tl, err := get.ListBox("tunnel_list") if err != nil { return err } sort.Slice(configList, func(a, b int) bool { return configList[a] < configList[b] }) activeName := t.ActiveDeviceName() lasti := len(configList) - 1 for i, name := range configList { row, err := gtk.ListBoxRowNew() if err != nil { return err } row.SetName(name) row.SetMarginStart(8) row.SetMarginEnd(8) if i == 0 { row.SetMarginTop(8) } else if i == lasti { row.SetMarginBottom(8) } // icon, err := gtk.ButtonNew() // icon, err := gtk.ColorButtonNew() // if err != nil { // return err // } var img *gtk.Image if activeName == name { green, err := gtk.ImageNewFromFile("/opt/wireguird/Icon/dot-green.png") if err != nil { return err } img = green } else { gray, err := gtk.ImageNewFromFile("/opt/wireguird/Icon/dot-gray.png") if err != nil { return err } img = gray } t.icons[name] = img // img, err := gtk.ImageNewFromFile("/opt/wireguird/Icon/dot-gray.png") // if err != nil { // return err // } // icon.SetImage(img) // dg, err := static.ReadFile("icon/dot-gray.svg") // if err != nil { // return err // } // pbl, err := gdk.PixbufLoaderNew() // if err != nil { // return err // } // pb, err := pbl.WriteAndReturnPixbuf(dg) // if err != nil { // return err // } // img, err := gtk.ImageNewFromPixbuf(pb) // if err != nil { // return err // } // icon.Image // icon.SetImage(img) img.SetVAlign(gtk.ALIGN_CENTER) img.SetHAlign(gtk.ALIGN_START) img.SetSizeRequest(10, 10) // icon.SetMarginBottom(0) // icon.SetMarginTop(0) img.SetVExpand(false) img.SetHExpand(false) // sctx, err := icon.GetStyleContext() // if err != nil { // return err // } // sctx.AddClass("circular") // if name == activeName { // sctx.AddClass("btn-green") // // rgba := gdk.NewRGBA(102, 204, 153, 1) // } label, err := gtk.LabelNew(name) if err != nil { return err } label.SetHAlign(gtk.ALIGN_START) // label.SetHExpand(true) label.SetMarginStart(8) label.SetMarginEnd(8) label.SetMarginTop(8) label.SetMarginBottom(8) box, err := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 4) if err != nil { return err } box.Add(img) box.Add(label) row.SetName(name) row.Add(box) row.ShowAll() tl.Insert(row, -1) } t.Interface.Status, err = get.Label("label_interface_status") if err != nil { return err } t.Interface.PublicKey, err = get.Label("label_interface_public_key") if err != nil { return err } t.Interface.ListenPort, err = get.Label("label_interface_listen_port") if err != nil { return err } t.Interface.Addresses, err = get.Label("label_interface_addresses") if err != nil { return err } t.Interface.DNS, err = get.Label("label_interface_dns_servers") if err != nil { return err } t.Peer.PublicKey, err = get.Label("label_peer_public_key") if err != nil { return err } t.Peer.AllowedIPs, err = get.Label("label_peer_allowed_ips") if err != nil { return err } t.Peer.Endpoint, err = get.Label("label_peer_endpoint") if err != nil { return err } t.Peer.LatestHandshake, err = get.Label("label_peer_latest_handshake") if err != nil { return err } t.Peer.Transfer, err = get.Label("label_peer_transfer") if err != nil { return err } t.ButtonChangeState, err = get.Button("button_change_state") if err != nil { return err } t.ButtonChangeState.Connect("clicked", func() { err := func() error { list, err := wgc.Devices() if err != nil { return err } activeName = t.ActiveDeviceName() for _, d := range list { gray, err := gtk.ImageNewFromFile("/opt/wireguird/Icon/dot-gray.png") if err != nil { return err } glib.IdleAdd(func() { t.icons[d.Name].SetFromPixbuf(gray.GetPixbuf()) }) if err := exec.Command("wg-quick", "down", d.Name).Run(); err != nil { return err } indicator.SetIcon("wireguard_off") } row := tl.GetSelectedRow() // row not found for config if row == nil { return nil } name, err := row.GetName() if err != nil { return err } // dont connect to the new one if activeName != "" && activeName == name { t.UpdateRow(row) glib.IdleAdd(func() { header.SetSubtitle("Not connected!") }) return nil } if err := exec.Command("wg-quick", "up", name).Run(); err != nil { return err } glib.IdleAdd(func() { header.SetSubtitle("Connected to " + name) }) green, err := gtk.ImageNewFromFile("/opt/wireguird/Icon/dot-green.png") if err != nil { return err } glib.IdleAdd(func() { t.icons[name].SetFromPixbuf(green.GetPixbuf()) t.UpdateRow(row) indicator.SetIcon("wireguard") }) if err := wlog("INFO", "Connected to "+name); err != nil { return err } return nil }() if err != nil { ShowError(window, err) } }) // boxPeers, err := get.Box("box_peers") // if err != nil { // return err // } tl.Connect("row-activated", func(l *gtk.ListBox, row *gtk.ListBoxRow) { t.UpdateRow(row) }) go func() { for { <-t.ticker.C if !window.HasToplevelFocus() { continue } row := tl.GetSelectedRow() if row == nil { t.UnknownLabels() continue } name, err := row.GetName() if err != nil { log.Error().Err(err).Msg("row get name err") continue } if name != t.ActiveDeviceName() { continue } d, err := wgc.Device(name) if err != nil { log.Error().Err(err).Msg("wgc get device err") continue } t.Interface.PublicKey.SetText(d.PublicKey.String()) t.Interface.ListenPort.SetText(strconv.Itoa(d.ListenPort)) for _, p := range d.Peers { hs := humanize.Time(p.LastHandshakeTime) glib.IdleAdd(func() { t.Peer.LatestHandshake.SetText(hs) t.Peer.Transfer.SetText(humanize.Bytes(uint64(p.ReceiveBytes)) + " received, " + humanize.Bytes(uint64(p.TransmitBytes)) + " sent") }) } } }() return nil } func (t *Tunnels) UpdateRow(row *gtk.ListBoxRow) { err := func() error { ds, err := wgc.Devices() if err != nil { return err } log.Debug().Interface("list", ds).Msg("devices") id, err := row.GetName() if err != nil { return err } cfg, err := ini.Load("/etc/wireguard/" + id + ".conf") if err != nil { return err } t.UnknownLabels() peersec := cfg.Section("Peer") insec := cfg.Section("Interface") glib.IdleAdd(func() { t.Interface.Addresses.SetText(insec.Key("Address").String()) t.Interface.Status.SetText("Inactive") t.Interface.DNS.SetText(insec.Key("DNS").String()) t.ButtonChangeState.SetLabel("Activate") t.Peer.AllowedIPs.SetText(peersec.Key("AllowedIPs").String()) t.Peer.PublicKey.SetText(peersec.Key("PublicKey").String()) t.Peer.Endpoint.SetText(peersec.Key("Endpoint").String()) }) for _, d := range ds { if d.Name != id { continue } // i'll do this later // _ = boxPeers // boxPeers.GetChildren().Foreach(func(item interface{}) { // boxPeers.Remove(item.(*gtk.Widget)) // }) glib.IdleAdd(func() { t.Interface.Status.SetText("Active") t.ButtonChangeState.SetLabel("Deactivate") t.Interface.PublicKey.SetText(d.PublicKey.String()) t.Interface.ListenPort.SetText(strconv.Itoa(d.ListenPort)) }) for _, p := range d.Peers { hs := humanize.Time(p.LastHandshakeTime) glib.IdleAdd(func() { t.Peer.LatestHandshake.SetText(hs) t.Peer.Transfer.SetText(humanize.Bytes(uint64(p.ReceiveBytes)) + " received, " + humanize.Bytes(uint64(p.TransmitBytes)) + " sent") }) } break } return nil }() if err != nil { log.Error().Err(err).Msg("row activated") ShowError(window, err) } } func (t *Tunnels) UnknownLabels() { glib.IdleAdd(func() { t.ButtonChangeState.SetLabel("unknown") t.Interface.Addresses.SetText("unknown") t.Interface.Status.SetText("unknown") t.Interface.DNS.SetText("unknown") t.Peer.AllowedIPs.SetText("unknown") t.Peer.PublicKey.SetText("unknown") t.Peer.Endpoint.SetText("unknown") t.Interface.Status.SetText("unknown") t.ButtonChangeState.SetLabel("unknown") t.Interface.PublicKey.SetText("unknown") t.Interface.ListenPort.SetText("unknown") t.Peer.LatestHandshake.SetText("unknown") t.Peer.Transfer.SetText("unknown") }) } func (t *Tunnels) ActiveDeviceName() string { ds, _ := wgc.Devices() for _, d := range ds { return d.Name } return "" } func wlog(t string, text string) error { wlogs, err := get.ListBox("wireguard_logs") if err != nil { return err } l, err := gtk.LabelNew("") if err != nil { return err } if t == "ERROR" { t = `` + t + "" } l.SetMarkup(`[` + time.Now().Format("02/Jan/06 15:04:05 MST") + `][` + t + `]: ` + text) l.SetHExpand(true) l.SetHAlign(gtk.ALIGN_START) glib.IdleAdd(func() { l.Show() wlogs.Add(l) }) return nil }