diff --git a/README.md b/README.md index 6f7de5f..8843874 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,13 @@ Simple Web based configuration generator for [WireGuard](https://wireguard.com). +--- + +
+ ## Whay another one ? All WireGuard UI implementation are trying to manage the WireGuard by applying configurations or creation network rules. diff --git a/api/api.go b/api/api.go index 4564ab4..9978adb 100644 --- a/api/api.go +++ b/api/api.go @@ -29,7 +29,6 @@ func ApplyRoutes(r *gin.Engine) { } } - func createClient(c *gin.Context) { var data model.Client @@ -136,19 +135,18 @@ func configClient(c *gin.Context) { c.Header("Content-Disposition", "attachment; filename=wg0.conf") c.Data(http.StatusOK, "application/config", configData) return - } else { - // return config as png qrcode - png, err := qrcode.Encode(string(configData), qrcode.Medium, 220) - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to create qrcode") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - c.Data(http.StatusOK, "image/png", png) + } + // return config as png qrcode + png, err := qrcode.Encode(string(configData), qrcode.Medium, 220) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to create qrcode") + c.AbortWithStatus(http.StatusInternalServerError) return } + c.Data(http.StatusOK, "image/png", png) + return } func readServer(c *gin.Context) { @@ -185,4 +183,4 @@ func updateServer(c *gin.Context) { } c.JSON(http.StatusOK, client) -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index 8e4942c..5ab8ea8 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,5 @@ require ( github.com/satori/go.uuid v1.2.0 github.com/sirupsen/logrus v1.4.2 github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086 - golang.org/x/crypto v0.0.0-20200117160349-530e935923ad golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200114203027-fcfc50b29cbb ) diff --git a/go.sum b/go.sum index 9516bc7..682d047 100644 --- a/go.sum +++ b/go.sum @@ -39,10 +39,8 @@ github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdA github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= -github.com/mdlayher/netlink v1.0.0 h1:vySPY5Oxnn/8lxAPn2cK6kAzcZzYJl3KriSLO46OT18= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -70,16 +68,14 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg= -golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -88,7 +84,6 @@ golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/model/client.go b/model/client.go index fe6d592..e18eb8a 100644 --- a/model/client.go +++ b/model/client.go @@ -2,15 +2,16 @@ package model import "time" +// client structure type Client struct { - Id string `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Enable bool `json:"enable"` - Created time.Time `json:"created"` - Updated time.Time `json:"updated"` - AllowedIPs string `json:"allowedIPs"` - Address string `json:"address"` - PrivateKey string `json:"privateKey"` - PublicKey string `json:"publicKey"` + Id string `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Enable bool `json:"enable"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` + AllowedIPs string `json:"allowedIPs"` + Address string `json:"address"` + PrivateKey string `json:"privateKey"` + PublicKey string `json:"publicKey"` } diff --git a/model/server.go b/model/server.go index 6dc1a24..5177c93 100644 --- a/model/server.go +++ b/model/server.go @@ -2,16 +2,17 @@ package model import "time" +// server structure type Server struct { - Name string `json:"name"` - Created time.Time `json:"created"` - Updated time.Time `json:"updated"` - Address string `json:"address"` - ListenPort int `json:"listenPort"` - PrivateKey string `json:"privateKey"` - PublicKey string `json:"publicKey"` - PresharedKey string `json:"presharedKey"` - Endpoint string `json:"endpoint"` - PersistentKeepalive int `json:"persistentKeepalive"` - Dns string `json:"dns"` + Name string `json:"name"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` + Address string `json:"address"` + ListenPort int `json:"listenPort"` + PrivateKey string `json:"privateKey"` + PublicKey string `json:"publicKey"` + PresharedKey string `json:"presharedKey"` + Endpoint string `json:"endpoint"` + PersistentKeepalive int `json:"persistentKeepalive"` + Dns string `json:"dns"` } diff --git a/repository/repository.go b/repository/repository.go index 3d35988..5821f9c 100644 --- a/repository/repository.go +++ b/repository/repository.go @@ -16,6 +16,9 @@ import ( "time" ) +/* + * Create client with all necessary data + */ func CreateClient(client *model.Client) (*model.Client, error) { u := uuid.NewV4() client.Id = u.String() @@ -37,10 +40,10 @@ func CreateClient(client *model.Client) (*model.Client, error) { for _, client := range clients { ips := strings.Split(client.Address, ",") for i := range ips { - if util.IsIPv6(ips[i]){ - ips[i] = strings.ReplaceAll(strings.TrimSpace(ips[i]), "/128","") + if util.IsIPv6(ips[i]) { + ips[i] = strings.ReplaceAll(strings.TrimSpace(ips[i]), "/128", "") } else { - ips[i] = strings.ReplaceAll(strings.TrimSpace(ips[i]), "/32","") + ips[i] = strings.ReplaceAll(strings.TrimSpace(ips[i]), "/32", "") } } reserverIps = append(reserverIps, ips...) @@ -56,7 +59,7 @@ func CreateClient(client *model.Client) (*model.Client, error) { if err != nil { return nil, err } - if util.IsIPv6(ip){ + if util.IsIPv6(ip) { ip = ip + "/128" } else { ip = ip + "/32" @@ -64,7 +67,7 @@ func CreateClient(client *model.Client) (*model.Client, error) { ips = append(ips, ip) } client.Address = strings.Join(ips, ",") - + client.Created = time.Now().UTC() client.Updated = client.Created @@ -82,6 +85,9 @@ func CreateClient(client *model.Client) (*model.Client, error) { return client, nil } +/* + * Read client by id + */ func ReadClient(id string) (*model.Client, error) { v, err := deserialize(id) if err != nil { @@ -92,6 +98,9 @@ func ReadClient(id string) (*model.Client, error) { return client, nil } +/* + * Get client config ion wg format + */ func ReadClientConfig(id string) ([]byte, error) { client, err := ReadClient(id) if err != nil { @@ -111,6 +120,9 @@ func ReadClientConfig(id string) ([]byte, error) { return configDataWg.Bytes(), nil } +/* + * Update client preserve keys + */ func UpdateClient(Id string, client *model.Client) (*model.Client, error) { v, err := deserialize(Id) if err != nil { @@ -141,6 +153,9 @@ func UpdateClient(Id string, client *model.Client) (*model.Client, error) { return client, nil } +/* + * Delete client from disk + */ func DeleteClient(id string) error { path := filepath.Join(os.Getenv("WG_CONF_DIR"), id) err := os.Remove(path) @@ -152,6 +167,9 @@ func DeleteClient(id string) error { return generateWgConfig() } +/* + * Read all clients + */ func ReadClients() ([]*model.Client, error) { clients := make([]*model.Client, 0) @@ -253,6 +271,7 @@ func UpdateServer(server *model.Server) (*model.Server, error) { return server, nil } + /* * Write object to disk */ @@ -270,6 +289,7 @@ func serialize(id string, c interface{}) error { // data modified, dump new config return generateWgConfig() } + /* * Read client from disc */ @@ -282,6 +302,7 @@ func deserializeClient(data []byte) (*model.Client, error) { return c, nil } + /* * Read server from disc */ @@ -307,6 +328,7 @@ func deserialize(id string) (interface{}, error) { return deserializeClient(b) } + /* * Generate Wireguard interface configuration */ @@ -332,4 +354,4 @@ func generateWgConfig() error { } return nil -} \ No newline at end of file +} diff --git a/util/tpl.go b/util/tpl.go index 163a9b8..99a5502 100644 --- a/util/tpl.go +++ b/util/tpl.go @@ -40,6 +40,7 @@ AllowedIPs = {{.Address}} {{end}}` ) +// dump client wg config with go template func DumpClient(client *model.Client, server *model.Server) (bytes.Buffer, error) { var tplBuff bytes.Buffer @@ -57,6 +58,7 @@ func DumpClient(client *model.Client, server *model.Server) (bytes.Buffer, error }) } +// dump server wg config with go template func DumpServerWg(clients []*model.Client, server *model.Server) (bytes.Buffer, error) { var tplBuff bytes.Buffer @@ -66,17 +68,17 @@ func DumpServerWg(clients []*model.Client, server *model.Server) (bytes.Buffer, } return dump(t, struct { - Clients []*model.Client - Server *model.Server + Clients []*model.Client + Server *model.Server ServerAdresses []string }{ ServerAdresses: strings.Split(server.Address, ","), - Clients: clients, - Server: server, + Clients: clients, + Server: server, }) } -func dump(tpl *template.Template , data interface{}) (bytes.Buffer, error) { +func dump(tpl *template.Template, data interface{}) (bytes.Buffer, error) { var tplBuff bytes.Buffer err := tpl.Execute(&tplBuff, data) diff --git a/util/util.go b/util/util.go index 0c17d02..5f2de8e 100644 --- a/util/util.go +++ b/util/util.go @@ -8,6 +8,7 @@ import ( "strings" ) +// read file content func ReadFile(path string) (bytes []byte, err error) { bytes, err = ioutil.ReadFile(path) if err != nil { @@ -17,6 +18,7 @@ func ReadFile(path string) (bytes []byte, err error) { return bytes, nil } +// write content to file func WriteFile(path string, bytes []byte) (err error) { err = ioutil.WriteFile(path, bytes, 0644) if err != nil { @@ -26,6 +28,7 @@ func WriteFile(path string, bytes []byte) (err error) { return nil } +// check if file exists func FileExists(name string) bool { info, err := os.Stat(name) if os.IsNotExist(err) { @@ -34,6 +37,7 @@ func FileExists(name string) bool { return !info.IsDir() } +// check if directory exists func DirectoryExists(name string) bool { info, err := os.Stat(name) if os.IsNotExist(err) { @@ -42,6 +46,7 @@ func DirectoryExists(name string) bool { return info.IsDir() } +// search for an available in cidr against a list of reserved ips func GetAvailableIp(cidr string, reserved []string) (string, error) { addresses, err := GetAllAddressesFromCidr(cidr) if err != nil { @@ -64,6 +69,7 @@ func GetAvailableIp(cidr string, reserved []string) (string, error) { return "", errors.New("no more available address from cidr") } +// get all ip addresses from cidr func GetAllAddressesFromCidr(cidr string) ([]string, error) { ip, ipnet, err := net.ParseCIDR(cidr) if err != nil { @@ -88,6 +94,7 @@ func inc(ip net.IP) { } } +// check if given ip is IPv6 func IsIPv6(address string) bool { return strings.Count(address, ":") >= 2 -} \ No newline at end of file +}