mirror of
https://github.com/ngoduykhanh/wireguard-ui.git
synced 2025-04-19 19:59:13 +03:00
Generate QR code
This commit is contained in:
parent
59e1a9e377
commit
c4e846ccd4
6 changed files with 77 additions and 12 deletions
1
go.mod
1
go.mod
|
@ -10,6 +10,7 @@ require (
|
||||||
github.com/leodido/go-urn v1.2.0 // indirect
|
github.com/leodido/go-urn v1.2.0 // indirect
|
||||||
github.com/rs/xid v1.2.1
|
github.com/rs/xid v1.2.1
|
||||||
github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba
|
github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba
|
||||||
|
github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200324154536-ceff61240acf
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200324154536-ceff61240acf
|
||||||
gopkg.in/go-playground/validator.v9 v9.31.0
|
gopkg.in/go-playground/validator.v9 v9.31.0
|
||||||
)
|
)
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -36,6 +36,8 @@ github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||||
github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba h1:8QAc9wFAf2b/9cAXskm0wBylObZ0bTpRcaP7ThjLPVQ=
|
github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba h1:8QAc9wFAf2b/9cAXskm0wBylObZ0bTpRcaP7ThjLPVQ=
|
||||||
github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba/go.mod h1:W6zxGUBCXRR5QugSd/nFcFVmwoGnvpjiNY/JwT03Wew=
|
github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba/go.mod h1:W6zxGUBCXRR5QugSd/nFcFVmwoGnvpjiNY/JwT03Wew=
|
||||||
|
github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086 h1:RYiqpb2ii2Z6J4x0wxK46kvPBbFuZcdhS+CIztmYgZs=
|
||||||
|
github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
|
|
@ -2,15 +2,18 @@ package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/base64"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/ngoduykhanh/wireguard-ui/model"
|
"github.com/ngoduykhanh/wireguard-ui/model"
|
||||||
|
"github.com/ngoduykhanh/wireguard-ui/util"
|
||||||
"github.com/sdomino/scribble"
|
"github.com/sdomino/scribble"
|
||||||
"github.com/labstack/gommon/log"
|
"github.com/labstack/gommon/log"
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
"github.com/skip2/go-qrcode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Home handler
|
// Home handler
|
||||||
|
@ -28,18 +31,31 @@ func Home() echo.HandlerFunc {
|
||||||
log.Error("Cannot fetch clients from database: ", err)
|
log.Error("Cannot fetch clients from database: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clients := []model.Client{}
|
clientDataList := []model.ClientData{}
|
||||||
for _, f := range records {
|
for _, f := range records {
|
||||||
client := model.Client{}
|
client := model.Client{}
|
||||||
|
clientData := model.ClientData{}
|
||||||
|
|
||||||
|
// get client info
|
||||||
if err := json.Unmarshal([]byte(f), &client); err != nil {
|
if err := json.Unmarshal([]byte(f), &client); err != nil {
|
||||||
log.Error("Cannot decode client json structure: ", err)
|
log.Error("Cannot decode client json structure: ", err)
|
||||||
}
|
}
|
||||||
clients = append(clients, client)
|
clientData.Client = &client
|
||||||
|
|
||||||
|
// generate client qrcode image in base64
|
||||||
|
png, err := qrcode.Encode(util.BuildClientConfig(client), qrcode.Medium, 256)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Cannot generate QRCode: ", err)
|
||||||
|
}
|
||||||
|
clientData.QRCode = "data:image/png;base64," + base64.StdEncoding.EncodeToString([]byte(png))
|
||||||
|
|
||||||
|
// create the list of clients and their qrcode data
|
||||||
|
clientDataList = append(clientDataList, clientData)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "home.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "home.html", map[string]interface{}{
|
||||||
"name": "Khanh",
|
"name": "Khanh",
|
||||||
"clients": clients,
|
"clientDataList": clientDataList,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,3 +17,9 @@ type Client struct {
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClientData includes the Client and extra data
|
||||||
|
type ClientData struct {
|
||||||
|
Client *Client
|
||||||
|
QRCode string
|
||||||
|
}
|
||||||
|
|
|
@ -15,31 +15,31 @@ Dashboard
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<h5 class="mt-4 mb-2">Wireguard Clients</h5>
|
<h5 class="mt-4 mb-2">Wireguard Clients</h5>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{range .clients}}
|
{{range .clientDataList}}
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="info-box">
|
<div class="info-box">
|
||||||
<img
|
<img
|
||||||
src="https://wg-gen-web-demo.127-0-0-1.fr/api/v1.0/client/a69b9f3f-556f-4f2a-8020-55bdd4479841/config?qrcode=true" />
|
src="{{ .QRCode }}" />
|
||||||
<div class="info-box-content">
|
<div class="info-box-content">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button type="button" class="btn btn-outline-success btn-sm">Download</button>
|
<button type="button" class="btn btn-outline-success btn-sm">Download</button>
|
||||||
<button type="button" class="btn btn-outline-primary btn-sm">Edit</button>
|
<button type="button" class="btn btn-outline-primary btn-sm">Edit</button>
|
||||||
<button type="button" class="btn btn-outline-warning btn-sm">Disable</button>
|
<button type="button" class="btn btn-outline-warning btn-sm">Disable</button>
|
||||||
<button type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal" data-target="#modal_remove_client" data-clientid="{{ .ID }}" data-clientname="{{ .Name }}">Remove</button>
|
<button type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal" data-target="#modal_remove_client" data-clientid="{{ .Client.ID }}" data-clientname="{{ .Client.Name }}">Remove</button>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<span class="info-box-text"><i class="fas fa-user"></i> {{ .Name }}</span>
|
<span class="info-box-text"><i class="fas fa-user"></i> {{ .Client.Name }}</span>
|
||||||
<span class="info-box-text"><i class="fas fa-envelope"></i> {{ .Email }}</span>
|
<span class="info-box-text"><i class="fas fa-envelope"></i> {{ .Client.Email }}</span>
|
||||||
<span class="info-box-text"><i class="fas fa-clock"></i>
|
<span class="info-box-text"><i class="fas fa-clock"></i>
|
||||||
{{ .CreatedAt.Format "2 Jan 2006 15:04" }}</span>
|
{{ .Client.CreatedAt.Format "2 Jan 2006 15:04" }}</span>
|
||||||
<span class="info-box-text"><i class="fas fa-history"></i>
|
<span class="info-box-text"><i class="fas fa-history"></i>
|
||||||
{{ .UpdatedAt.Format "2 Jan 2006 15:04" }}</span>
|
{{ .Client.UpdatedAt.Format "2 Jan 2006 15:04" }}</span>
|
||||||
<span class="info-box-text"><strong>IP Allocation</strong></span>
|
<span class="info-box-text"><strong>IP Allocation</strong></span>
|
||||||
{{range .AllocatedIPs}}
|
{{range .Client.AllocatedIPs}}
|
||||||
<small class="badge badge-secondary"></i>{{.}}</small>
|
<small class="badge badge-secondary"></i>{{.}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
<span class="info-box-text"><strong>Allowed IPs</strong></span>
|
<span class="info-box-text"><strong>Allowed IPs</strong></span>
|
||||||
{{range .AllowedIPs}}
|
{{range .Client.AllowedIPs}}
|
||||||
<small class="badge badge-secondary"></i>{{.}}</small>
|
<small class="badge badge-secondary"></i>{{.}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
40
util/util.go
Normal file
40
util/util.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ngoduykhanh/wireguard-ui/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
const wgConfigDNS = "1.1.1.1, 8.8.8.8"
|
||||||
|
const wgConfigPersistentKeepalive = 15
|
||||||
|
const wgConfigEndpoint = "wireguard.example.com:56231"
|
||||||
|
const wgConfigServerPublicKey = "/OKCBc8PxIqCpgqlE9G1kSaTecdAvYf3loEwFj6MXDc="
|
||||||
|
|
||||||
|
// BuildClientConfig to create wireguard client config string
|
||||||
|
func BuildClientConfig(client model.Client) string {
|
||||||
|
// Interface section
|
||||||
|
clientAddress := fmt.Sprintf("Address = %s", strings.Join(client.AllocatedIPs, ","))
|
||||||
|
clientPrivateKey := fmt.Sprintf("PrivateKey = %s", client.PrivateKey)
|
||||||
|
clientDNS := fmt.Sprintf("DNS = %s", wgConfigDNS)
|
||||||
|
|
||||||
|
// Peer section
|
||||||
|
peerPublicKey := fmt.Sprintf("PublicKey = %s", wgConfigServerPublicKey)
|
||||||
|
peerAllowedIPs := fmt.Sprintf("AllowedIPs = %s", strings.Join(client.AllowedIPs, ","))
|
||||||
|
peerEndpoint := fmt.Sprintf("Endpoint = %s", wgConfigEndpoint)
|
||||||
|
peerPersistentKeepalive := fmt.Sprintf("PersistentKeepalive = %d", wgConfigPersistentKeepalive)
|
||||||
|
|
||||||
|
// build the config as string
|
||||||
|
strConfig := "[Interface]\n" +
|
||||||
|
clientAddress + "\n" +
|
||||||
|
clientPrivateKey + "\n" +
|
||||||
|
clientDNS + "\n\n" +
|
||||||
|
"[Peer]" + "\n" +
|
||||||
|
peerPublicKey + "\n" +
|
||||||
|
peerAllowedIPs + "\n" +
|
||||||
|
peerEndpoint + "\n" +
|
||||||
|
peerPersistentKeepalive + "\n"
|
||||||
|
|
||||||
|
return strConfig
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue