mirror of
https://github.com/ngoduykhanh/wireguard-ui.git
synced 2025-06-07 00:46:58 +03:00
Merge 24aa2a6cec
into b55543f424
This commit is contained in:
commit
fa905d5f22
20 changed files with 250 additions and 129 deletions
17
README.md
17
README.md
|
@ -1,4 +1,4 @@
|
||||||

|

|
||||||
|
|
||||||
# wireguard-ui
|
# wireguard-ui
|
||||||
|
|
||||||
|
@ -53,7 +53,11 @@ docker-compose up
|
||||||
| `WGUI_TABLE` | The default WireGuard table value settings | `auto` |
|
| `WGUI_TABLE` | The default WireGuard table value settings | `auto` |
|
||||||
| `WGUI_CONFIG_FILE_PATH` | The default WireGuard config file path used in global settings | `/etc/wireguard/wg0.conf` |
|
| `WGUI_CONFIG_FILE_PATH` | The default WireGuard config file path used in global settings | `/etc/wireguard/wg0.conf` |
|
||||||
| `WGUI_LOG_LEVEL` | The default log level. Possible values: `DEBUG`, `INFO`, `WARN`, `ERROR`, `OFF` | `INFO` |
|
| `WGUI_LOG_LEVEL` | The default log level. Possible values: `DEBUG`, `INFO`, `WARN`, `ERROR`, `OFF` | `INFO` |
|
||||||
| `WG_CONF_TEMPLATE` | The custom `wg.conf` config file template. Please refer to our [default template](https://github.com/ngoduykhanh/wireguard-ui/blob/master/templates/wg.conf) | N/A |
|
| `WGUI_BRAND_TEXT` | The brand text of the web application | `WireGuard UI` |
|
||||||
|
| `WGUI_ACCENT_COLOR` | The color of the interface sidebar | `#343a40` |
|
||||||
|
| `WGUI_LOGO_FILE_PATH` | The file path of the website logo | Embedded WireGuard logo |
|
||||||
|
| `WGUI_PAGE_TITLE_PREFIX` | The HTML title prefix for all pages | N/A |
|
||||||
|
| `WG_CONF_TEMPLATE` | The custom `wg.conf` config file template. Please refer to our [default template](https://github.com/idressos/wireguard-ui/blob/master/templates/wg.conf) | N/A |
|
||||||
| `EMAIL_FROM_ADDRESS` | The sender email address | N/A |
|
| `EMAIL_FROM_ADDRESS` | The sender email address | N/A |
|
||||||
| `EMAIL_FROM_NAME` | The sender name | `WireGuard UI` |
|
| `EMAIL_FROM_NAME` | The sender name | `WireGuard UI` |
|
||||||
| `SENDGRID_API_KEY` | The SendGrid api key | N/A |
|
| `SENDGRID_API_KEY` | The SendGrid api key | N/A |
|
||||||
|
@ -63,6 +67,7 @@ docker-compose up
|
||||||
| `SMTP_PASSWORD` | The SMTP user password | N/A |
|
| `SMTP_PASSWORD` | The SMTP user password | N/A |
|
||||||
| `SMTP_AUTH_TYPE` | The SMTP authentication type. Possible values: `PLAIN`, `LOGIN`, `NONE` | `NONE` |
|
| `SMTP_AUTH_TYPE` | The SMTP authentication type. Possible values: `PLAIN`, `LOGIN`, `NONE` | `NONE` |
|
||||||
| `SMTP_ENCRYPTION` | the encryption method. Possible values: `NONE`, `SSL`, `SSLTLS`, `TLS`, `STARTTLS` | `STARTTLS` |
|
| `SMTP_ENCRYPTION` | the encryption method. Possible values: `NONE`, `SSL`, `SSLTLS`, `TLS`, `STARTTLS` | `STARTTLS` |
|
||||||
|
| `HELLO_HOSTNAME` | Hostname to use for the hello message. smtp-relay.gmail.com needs this set to anything but `localhost` | `localhost` |
|
||||||
|
|
||||||
### Defaults for server configuration
|
### Defaults for server configuration
|
||||||
|
|
||||||
|
@ -181,9 +186,9 @@ rc-update add wgui default
|
||||||
|
|
||||||
### Using Docker
|
### Using Docker
|
||||||
|
|
||||||
Set `WGUI_MANAGE_RESTART=true` to manage Wireguard interface restarts.
|
Set `WGUI_MANAGE_RESTART=true` to manage WireGuard interface restarts.
|
||||||
Using `WGUI_MANAGE_START=true` can also replace the function of `wg-quick@wg0` service, to start Wireguard at boot, by
|
Using `WGUI_MANAGE_START=true` can also replace the function of `wg-quick@wg0` service, to start WireGuard at boot, by
|
||||||
running the container with `restart: unless-stopped`. These settings can also pick up changes to Wireguard Config File
|
running the container with `restart: unless-stopped`. These settings can also pick up changes to WireGuard Config File
|
||||||
Path, after restarting the container. Please make sure you have `--cap-add=NET_ADMIN` in your container config to make
|
Path, after restarting the container. Please make sure you have `--cap-add=NET_ADMIN` in your container config to make
|
||||||
this
|
this
|
||||||
feature work.
|
feature work.
|
||||||
|
@ -224,7 +229,7 @@ go build -o wireguard-ui
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT. See [LICENSE](https://github.com/ngoduykhanh/wireguard-ui/blob/master/LICENSE).
|
MIT. See [LICENSE](https://github.com/idressos/wireguard-ui/blob/master/LICENSE).
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
|
|
BIN
custom/img/logo.png
Normal file
BIN
custom/img/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
|
@ -13,6 +13,7 @@ type SmtpMail struct {
|
||||||
port int
|
port int
|
||||||
username string
|
username string
|
||||||
password string
|
password string
|
||||||
|
helloHostName string
|
||||||
authType mail.AuthType
|
authType mail.AuthType
|
||||||
encryption mail.Encryption
|
encryption mail.Encryption
|
||||||
noTLSCheck bool
|
noTLSCheck bool
|
||||||
|
@ -46,8 +47,8 @@ func encryptionType(encryptionType string) mail.Encryption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSmtpMail(hostname string, port int, username string, password string, noTLSCheck bool, auth string, fromName, from string, encryption string) *SmtpMail {
|
func NewSmtpMail(hostname string, port int, username string, password string, helloHostName string, noTLSCheck bool, auth string, fromName, from string, encryption string) *SmtpMail {
|
||||||
ans := SmtpMail{hostname: hostname, port: port, username: username, password: password, noTLSCheck: noTLSCheck, fromName: fromName, from: from, authType: authType(auth), encryption: encryptionType(encryption)}
|
ans := SmtpMail{hostname: hostname, port: port, username: username, password: password, helloHostName: helloHostName, noTLSCheck: noTLSCheck, fromName: fromName, from: from, authType: authType(auth), encryption: encryptionType(encryption)}
|
||||||
return &ans
|
return &ans
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +67,7 @@ func (o *SmtpMail) Send(toName string, to string, subject string, content string
|
||||||
server.Authentication = o.authType
|
server.Authentication = o.authType
|
||||||
server.Username = o.username
|
server.Username = o.username
|
||||||
server.Password = o.password
|
server.Password = o.password
|
||||||
|
server.Helo = o.helloHostName
|
||||||
server.Encryption = o.encryption
|
server.Encryption = o.encryption
|
||||||
server.KeepAlive = false
|
server.KeepAlive = false
|
||||||
server.ConnectTimeout = 10 * time.Second
|
server.ConnectTimeout = 10 * time.Second
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
### Kernel Module
|
### Kernel Module
|
||||||
|
|
||||||
Depending on if the Wireguard kernel module is available on your system you have more or less choices which example to use.
|
Depending on if the WireGuard kernel module is available on your system you have more or less choices which example to use.
|
||||||
|
|
||||||
You can check if the kernel modules are available via the following command:
|
You can check if the kernel modules are available via the following command:
|
||||||
```shell
|
```shell
|
||||||
|
@ -21,10 +21,10 @@ For security reasons it's highly recommended to change them before the first sta
|
||||||
## Examples
|
## Examples
|
||||||
- **[system](system.yml)**
|
- **[system](system.yml)**
|
||||||
|
|
||||||
If you have Wireguard already installed on your system and only want to run the UI in docker this might fit the most.
|
If you have WireGuard already installed on your system and only want to run the UI in docker this might fit the most.
|
||||||
- **[linuxserver](linuxserver.yml)**
|
- **[linuxserver](linuxserver.yml)**
|
||||||
|
|
||||||
If you have the Wireguard kernel modules installed (included in the mainline kernel since version 5.6) but want it running inside of docker, this might fit the most.
|
If you have the WireGuard kernel modules installed (included in the mainline kernel since version 5.6) but want it running inside of docker, this might fit the most.
|
||||||
- **[boringtun](boringtun.yml)**
|
- **[boringtun](boringtun.yml)**
|
||||||
|
|
||||||
If Wireguard kernel modules are not available, you can switch to an userspace implementation like [boringtun](https://github.com/cloudflare/boringtun).
|
If WireGuard kernel modules are not available, you can switch to an userspace implementation like [boringtun](https://github.com/cloudflare/boringtun).
|
||||||
|
|
|
@ -2,6 +2,7 @@ package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
|
"path/filepath"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -42,6 +43,15 @@ func Favicon() echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Logo() echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
if logo, ok := os.LookupEnv(util.LogoFilePathEnvVar); ok {
|
||||||
|
return c.File(logo)
|
||||||
|
}
|
||||||
|
return c.Redirect(http.StatusFound, util.BasePath+"/static/custom/img/logo.png")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LoginPage handler
|
// LoginPage handler
|
||||||
func LoginPage() echo.HandlerFunc {
|
func LoginPage() echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
|
@ -337,7 +347,7 @@ func WireGuardClients(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClients handler return a JSON list of Wireguard client data
|
// GetClients handler return a JSON list of WireGuard client data
|
||||||
func GetClients(db store.IStore) echo.HandlerFunc {
|
func GetClients(db store.IStore) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
|
|
||||||
|
@ -352,7 +362,7 @@ func GetClients(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClient handler returns a JSON object of Wireguard client data
|
// GetClient handler returns a JSON object of WireGuard client data
|
||||||
func GetClient(db store.IStore) echo.HandlerFunc {
|
func GetClient(db store.IStore) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
|
|
||||||
|
@ -409,12 +419,12 @@ func NewClient(db store.IStore) echo.HandlerFunc {
|
||||||
guid := xid.New()
|
guid := xid.New()
|
||||||
client.ID = guid.String()
|
client.ID = guid.String()
|
||||||
|
|
||||||
// gen Wireguard key pair
|
// gen WireGuard key pair
|
||||||
if client.PublicKey == "" {
|
if client.PublicKey == "" {
|
||||||
key, err := wgtypes.GeneratePrivateKey()
|
key, err := wgtypes.GeneratePrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot generate wireguard key pair: ", err)
|
log.Error("Cannot generate wireguard key pair: ", err)
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot generate Wireguard key pair"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot generate WireGuard key pair"})
|
||||||
}
|
}
|
||||||
client.PrivateKey = key.String()
|
client.PrivateKey = key.String()
|
||||||
client.PublicKey = key.PublicKey().String()
|
client.PublicKey = key.PublicKey().String()
|
||||||
|
@ -422,7 +432,7 @@ func NewClient(db store.IStore) echo.HandlerFunc {
|
||||||
_, err := wgtypes.ParseKey(client.PublicKey)
|
_, err := wgtypes.ParseKey(client.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot verify wireguard public key: ", err)
|
log.Error("Cannot verify wireguard public key: ", err)
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify Wireguard public key"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify WireGuard public key"})
|
||||||
}
|
}
|
||||||
// check for duplicates
|
// check for duplicates
|
||||||
clients, err := db.GetClients(false)
|
clients, err := db.GetClients(false)
|
||||||
|
@ -444,7 +454,7 @@ func NewClient(db store.IStore) echo.HandlerFunc {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot generated preshared key: ", err)
|
log.Error("Cannot generated preshared key: ", err)
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
|
||||||
false, "Cannot generate Wireguard preshared key",
|
false, "Cannot generate WireGuard preshared key",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
client.PresharedKey = presharedKey.String()
|
client.PresharedKey = presharedKey.String()
|
||||||
|
@ -455,7 +465,7 @@ func NewClient(db store.IStore) echo.HandlerFunc {
|
||||||
_, err := wgtypes.ParseKey(client.PresharedKey)
|
_, err := wgtypes.ParseKey(client.PresharedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot verify wireguard preshared key: ", err)
|
log.Error("Cannot verify wireguard preshared key: ", err)
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify Wireguard preshared key"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify WireGuard preshared key"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.CreatedAt = time.Now().UTC()
|
client.CreatedAt = time.Now().UTC()
|
||||||
|
@ -567,12 +577,12 @@ func UpdateClient(db store.IStore) echo.HandlerFunc {
|
||||||
return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Extra Allowed IPs must be in CIDR format"})
|
return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Extra Allowed IPs must be in CIDR format"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// update Wireguard Client PublicKey
|
// update WireGuard Client PublicKey
|
||||||
if client.PublicKey != _client.PublicKey && _client.PublicKey != "" {
|
if client.PublicKey != _client.PublicKey && _client.PublicKey != "" {
|
||||||
_, err := wgtypes.ParseKey(_client.PublicKey)
|
_, err := wgtypes.ParseKey(_client.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot verify provided Wireguard public key: ", err)
|
log.Error("Cannot verify provided WireGuard public key: ", err)
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify provided Wireguard public key"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify provided WireGuard public key"})
|
||||||
}
|
}
|
||||||
// check for duplicates
|
// check for duplicates
|
||||||
clients, err := db.GetClients(false)
|
clients, err := db.GetClients(false)
|
||||||
|
@ -587,7 +597,7 @@ func UpdateClient(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When replacing any PublicKey, discard any locally stored Wireguard Client PrivateKey
|
// When replacing any PublicKey, discard any locally stored WireGuard Client PrivateKey
|
||||||
// Client PubKey no longer corresponds to locally stored PrivKey.
|
// Client PubKey no longer corresponds to locally stored PrivKey.
|
||||||
// QR code (needs PrivateKey) for this client is no longer possible now.
|
// QR code (needs PrivateKey) for this client is no longer possible now.
|
||||||
|
|
||||||
|
@ -597,12 +607,12 @@ func UpdateClient(db store.IStore) echo.HandlerFunc {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update Wireguard Client PresharedKey
|
// update WireGuard Client PresharedKey
|
||||||
if client.PresharedKey != _client.PresharedKey && _client.PresharedKey != "" {
|
if client.PresharedKey != _client.PresharedKey && _client.PresharedKey != "" {
|
||||||
_, err := wgtypes.ParseKey(_client.PresharedKey)
|
_, err := wgtypes.ParseKey(_client.PresharedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot verify provided Wireguard preshared key: ", err)
|
log.Error("Cannot verify provided WireGuard preshared key: ", err)
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify provided Wireguard preshared key"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify provided WireGuard preshared key"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,6 +624,7 @@ func UpdateClient(db store.IStore) echo.HandlerFunc {
|
||||||
client.AllocatedIPs = _client.AllocatedIPs
|
client.AllocatedIPs = _client.AllocatedIPs
|
||||||
client.AllowedIPs = _client.AllowedIPs
|
client.AllowedIPs = _client.AllowedIPs
|
||||||
client.ExtraAllowedIPs = _client.ExtraAllowedIPs
|
client.ExtraAllowedIPs = _client.ExtraAllowedIPs
|
||||||
|
client.Endpoint = _client.Endpoint
|
||||||
client.PublicKey = _client.PublicKey
|
client.PublicKey = _client.PublicKey
|
||||||
client.PresharedKey = _client.PresharedKey
|
client.PresharedKey = _client.PresharedKey
|
||||||
client.UpdatedAt = time.Now().UTC()
|
client.UpdatedAt = time.Now().UTC()
|
||||||
|
@ -689,7 +700,7 @@ func DownloadClient(db store.IStore) echo.HandlerFunc {
|
||||||
|
|
||||||
// set response header for downloading
|
// set response header for downloading
|
||||||
c.Response().Header().Set(echo.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s.conf", clientData.Client.Name))
|
c.Response().Header().Set(echo.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s.conf", clientData.Client.Name))
|
||||||
return c.Stream(http.StatusOK, "text/plain", reader)
|
return c.Stream(http.StatusOK, "text/conf", reader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -759,11 +770,11 @@ func WireGuardServerInterfaces(db store.IStore) echo.HandlerFunc {
|
||||||
func WireGuardServerKeyPair(db store.IStore) echo.HandlerFunc {
|
func WireGuardServerKeyPair(db store.IStore) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
|
|
||||||
// gen Wireguard key pair
|
// gen WireGuard key pair
|
||||||
key, err := wgtypes.GeneratePrivateKey()
|
key, err := wgtypes.GeneratePrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot generate wireguard key pair: ", err)
|
log.Error("Cannot generate wireguard key pair: ", err)
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot generate Wireguard key pair"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot generate WireGuard key pair"})
|
||||||
}
|
}
|
||||||
|
|
||||||
var serverKeyPair model.ServerKeypair
|
var serverKeyPair model.ServerKeypair
|
||||||
|
@ -772,7 +783,7 @@ func WireGuardServerKeyPair(db store.IStore) echo.HandlerFunc {
|
||||||
serverKeyPair.UpdatedAt = time.Now().UTC()
|
serverKeyPair.UpdatedAt = time.Now().UTC()
|
||||||
|
|
||||||
if err := db.SaveServerKeyPair(serverKeyPair); err != nil {
|
if err := db.SaveServerKeyPair(serverKeyPair); err != nil {
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot generate Wireguard key pair"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot generate WireGuard key pair"})
|
||||||
}
|
}
|
||||||
log.Infof("Updated wireguard server interfaces settings: %v", serverKeyPair)
|
log.Infof("Updated wireguard server interfaces settings: %v", serverKeyPair)
|
||||||
|
|
||||||
|
@ -796,6 +807,16 @@ func GlobalSettings(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractDeviceNameFromConfigPath(db store.IStore) string {
|
||||||
|
settings, err := db.GetGlobalSettings()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Cannot get global settings: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
base := filepath.Base(settings.ConfigFilePath)
|
||||||
|
return strings.TrimSuffix(base, filepath.Ext(base))
|
||||||
|
}
|
||||||
|
|
||||||
// Status handler
|
// Status handler
|
||||||
func Status(db store.IStore) echo.HandlerFunc {
|
func Status(db store.IStore) echo.HandlerFunc {
|
||||||
type PeerVM struct {
|
type PeerVM struct {
|
||||||
|
@ -826,6 +847,8 @@ func Status(db store.IStore) echo.HandlerFunc {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deviceName := extractDeviceNameFromConfigPath(db)
|
||||||
|
|
||||||
devices, err := wgClient.Devices()
|
devices, err := wgClient.Devices()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
||||||
|
@ -854,35 +877,37 @@ func Status(db store.IStore) echo.HandlerFunc {
|
||||||
|
|
||||||
conv := map[bool]int{true: 1, false: 0}
|
conv := map[bool]int{true: 1, false: 0}
|
||||||
for i := range devices {
|
for i := range devices {
|
||||||
devVm := DeviceVM{Name: devices[i].Name}
|
if devices[i].Name == deviceName {
|
||||||
for j := range devices[i].Peers {
|
devVm := DeviceVM{Name: devices[i].Name}
|
||||||
var allocatedIPs string
|
for j := range devices[i].Peers {
|
||||||
for _, ip := range devices[i].Peers[j].AllowedIPs {
|
var allocatedIPs string
|
||||||
if len(allocatedIPs) > 0 {
|
for _, ip := range devices[i].Peers[j].AllowedIPs {
|
||||||
allocatedIPs += "</br>"
|
if len(allocatedIPs) > 0 {
|
||||||
|
allocatedIPs += "</br>"
|
||||||
|
}
|
||||||
|
allocatedIPs += ip.String()
|
||||||
}
|
}
|
||||||
allocatedIPs += ip.String()
|
pVm := PeerVM{
|
||||||
}
|
PublicKey: devices[i].Peers[j].PublicKey.String(),
|
||||||
pVm := PeerVM{
|
ReceivedBytes: devices[i].Peers[j].ReceiveBytes,
|
||||||
PublicKey: devices[i].Peers[j].PublicKey.String(),
|
TransmitBytes: devices[i].Peers[j].TransmitBytes,
|
||||||
ReceivedBytes: devices[i].Peers[j].ReceiveBytes,
|
LastHandshakeTime: devices[i].Peers[j].LastHandshakeTime,
|
||||||
TransmitBytes: devices[i].Peers[j].TransmitBytes,
|
LastHandshakeRel: time.Since(devices[i].Peers[j].LastHandshakeTime),
|
||||||
LastHandshakeTime: devices[i].Peers[j].LastHandshakeTime,
|
AllocatedIP: allocatedIPs,
|
||||||
LastHandshakeRel: time.Since(devices[i].Peers[j].LastHandshakeTime),
|
Endpoint: devices[i].Peers[j].Endpoint.String(),
|
||||||
AllocatedIP: allocatedIPs,
|
}
|
||||||
Endpoint: devices[i].Peers[j].Endpoint.String(),
|
pVm.Connected = pVm.LastHandshakeRel.Minutes() < 3.
|
||||||
}
|
|
||||||
pVm.Connected = pVm.LastHandshakeRel.Minutes() < 3.
|
|
||||||
|
|
||||||
if _client, ok := m[pVm.PublicKey]; ok {
|
if _client, ok := m[pVm.PublicKey]; ok {
|
||||||
pVm.Name = _client.Name
|
pVm.Name = _client.Name
|
||||||
pVm.Email = _client.Email
|
pVm.Email = _client.Email
|
||||||
|
}
|
||||||
|
devVm.Peers = append(devVm.Peers, pVm)
|
||||||
}
|
}
|
||||||
devVm.Peers = append(devVm.Peers, pVm)
|
sort.SliceStable(devVm.Peers, func(i, j int) bool { return devVm.Peers[i].Name < devVm.Peers[j].Name })
|
||||||
|
sort.SliceStable(devVm.Peers, func(i, j int) bool { return conv[devVm.Peers[i].Connected] > conv[devVm.Peers[j].Connected] })
|
||||||
|
devicesVm = append(devicesVm, devVm)
|
||||||
}
|
}
|
||||||
sort.SliceStable(devVm.Peers, func(i, j int) bool { return devVm.Peers[i].Name < devVm.Peers[j].Name })
|
|
||||||
sort.SliceStable(devVm.Peers, func(i, j int) bool { return conv[devVm.Peers[i].Connected] > conv[devVm.Peers[j].Connected] })
|
|
||||||
devicesVm = append(devicesVm, devVm)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,7 +936,7 @@ func GlobalSettingSubmit(db store.IStore) echo.HandlerFunc {
|
||||||
|
|
||||||
// write config to the database
|
// write config to the database
|
||||||
if err := db.SaveGlobalSettings(globalSettings); err != nil {
|
if err := db.SaveGlobalSettings(globalSettings); err != nil {
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot generate Wireguard key pair"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot generate WireGuard key pair"})
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Updated global settings: %v", globalSettings)
|
log.Infof("Updated global settings: %v", globalSettings)
|
||||||
|
@ -985,7 +1010,7 @@ func SuggestIPAllocation(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyServerConfig handler to write config file and restart Wireguard server
|
// ApplyServerConfig handler to write config file and restart WireGuard server
|
||||||
func ApplyServerConfig(db store.IStore, tmplDir fs.FS) echo.HandlerFunc {
|
func ApplyServerConfig(db store.IStore, tmplDir fs.FS) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
|
|
||||||
|
|
34
main.go
34
main.go
|
@ -30,6 +30,7 @@ var (
|
||||||
flagBindAddress string = "0.0.0.0:5000"
|
flagBindAddress string = "0.0.0.0:5000"
|
||||||
flagSmtpHostname string = "127.0.0.1"
|
flagSmtpHostname string = "127.0.0.1"
|
||||||
flagSmtpPort int = 25
|
flagSmtpPort int = 25
|
||||||
|
flagHelloHostName string = "localhost"
|
||||||
flagSmtpUsername string
|
flagSmtpUsername string
|
||||||
flagSmtpPassword string
|
flagSmtpPassword string
|
||||||
flagSmtpAuthType string = "NONE"
|
flagSmtpAuthType string = "NONE"
|
||||||
|
@ -41,14 +42,18 @@ var (
|
||||||
flagSessionSecret string = util.RandomString(32)
|
flagSessionSecret string = util.RandomString(32)
|
||||||
flagWgConfTemplate string
|
flagWgConfTemplate string
|
||||||
flagBasePath string
|
flagBasePath string
|
||||||
|
flagBrandText string = "WireGuard UI"
|
||||||
|
flagAccentColor string = "#343a40"
|
||||||
|
flagPageTitlePrefix string
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultEmailSubject = "Your wireguard configuration"
|
defaultEmailSubject = "Your VPN configuration"
|
||||||
defaultEmailContent = `Hi,</br>
|
|
||||||
<p>In this email you can find your personal configuration for our wireguard server.</p>
|
|
||||||
|
|
||||||
<p>Best</p>
|
defaultEmailContent = `
|
||||||
|
<p>Greetings,</p>
|
||||||
|
<p>Please find attached your personal configuration for our VPN server.<br>You may find instructions on how to install the WireGuard VPN client <a href="https://www.wireguard.com/install/">here</a>.</p>
|
||||||
|
<p>Best regards.</p>
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -69,6 +74,7 @@ func init() {
|
||||||
flag.StringVar(&flagBindAddress, "bind-address", util.LookupEnvOrString("BIND_ADDRESS", flagBindAddress), "Address:Port to which the app will be bound.")
|
flag.StringVar(&flagBindAddress, "bind-address", util.LookupEnvOrString("BIND_ADDRESS", flagBindAddress), "Address:Port to which the app will be bound.")
|
||||||
flag.StringVar(&flagSmtpHostname, "smtp-hostname", util.LookupEnvOrString("SMTP_HOSTNAME", flagSmtpHostname), "SMTP Hostname")
|
flag.StringVar(&flagSmtpHostname, "smtp-hostname", util.LookupEnvOrString("SMTP_HOSTNAME", flagSmtpHostname), "SMTP Hostname")
|
||||||
flag.IntVar(&flagSmtpPort, "smtp-port", util.LookupEnvOrInt("SMTP_PORT", flagSmtpPort), "SMTP Port")
|
flag.IntVar(&flagSmtpPort, "smtp-port", util.LookupEnvOrInt("SMTP_PORT", flagSmtpPort), "SMTP Port")
|
||||||
|
flag.StringVar(&flagHelloHostName, "hello-hostname", util.LookupEnvOrString("HELLO_HOSTNAME", flagHelloHostName), "Hello HostName")
|
||||||
flag.StringVar(&flagSmtpUsername, "smtp-username", util.LookupEnvOrString("SMTP_USERNAME", flagSmtpUsername), "SMTP Username")
|
flag.StringVar(&flagSmtpUsername, "smtp-username", util.LookupEnvOrString("SMTP_USERNAME", flagSmtpUsername), "SMTP Username")
|
||||||
flag.StringVar(&flagSmtpPassword, "smtp-password", util.LookupEnvOrString("SMTP_PASSWORD", flagSmtpPassword), "SMTP Password")
|
flag.StringVar(&flagSmtpPassword, "smtp-password", util.LookupEnvOrString("SMTP_PASSWORD", flagSmtpPassword), "SMTP Password")
|
||||||
flag.BoolVar(&flagSmtpNoTLSCheck, "smtp-no-tls-check", util.LookupEnvOrBool("SMTP_NO_TLS_CHECK", flagSmtpNoTLSCheck), "Disable TLS verification for SMTP. This is potentially dangerous.")
|
flag.BoolVar(&flagSmtpNoTLSCheck, "smtp-no-tls-check", util.LookupEnvOrBool("SMTP_NO_TLS_CHECK", flagSmtpNoTLSCheck), "Disable TLS verification for SMTP. This is potentially dangerous.")
|
||||||
|
@ -80,6 +86,10 @@ func init() {
|
||||||
flag.StringVar(&flagSessionSecret, "session-secret", util.LookupEnvOrString("SESSION_SECRET", flagSessionSecret), "The key used to encrypt session cookies.")
|
flag.StringVar(&flagSessionSecret, "session-secret", util.LookupEnvOrString("SESSION_SECRET", flagSessionSecret), "The key used to encrypt session cookies.")
|
||||||
flag.StringVar(&flagWgConfTemplate, "wg-conf-template", util.LookupEnvOrString("WG_CONF_TEMPLATE", flagWgConfTemplate), "Path to custom wg.conf template.")
|
flag.StringVar(&flagWgConfTemplate, "wg-conf-template", util.LookupEnvOrString("WG_CONF_TEMPLATE", flagWgConfTemplate), "Path to custom wg.conf template.")
|
||||||
flag.StringVar(&flagBasePath, "base-path", util.LookupEnvOrString("BASE_PATH", flagBasePath), "The base path of the URL")
|
flag.StringVar(&flagBasePath, "base-path", util.LookupEnvOrString("BASE_PATH", flagBasePath), "The base path of the URL")
|
||||||
|
flag.StringVar(&flagBrandText, "brand-text", util.LookupEnvOrString("WGUI_BRAND_TEXT", flagBrandText), "The UI brand text or name")
|
||||||
|
flag.StringVar(&flagAccentColor, "accent-color", util.LookupEnvOrString("WGUI_ACCENT_COLOR", flagAccentColor), "The UI accent color")
|
||||||
|
flag.StringVar(&flagPageTitlePrefix, "page-title-prefix", util.LookupEnvOrString("WGUI_PAGE_TITLE_PREFIX", flagPageTitlePrefix), "The prefix of the page title")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// update runtime config
|
// update runtime config
|
||||||
|
@ -87,6 +97,7 @@ func init() {
|
||||||
util.BindAddress = flagBindAddress
|
util.BindAddress = flagBindAddress
|
||||||
util.SmtpHostname = flagSmtpHostname
|
util.SmtpHostname = flagSmtpHostname
|
||||||
util.SmtpPort = flagSmtpPort
|
util.SmtpPort = flagSmtpPort
|
||||||
|
util.HelloHostName = flagHelloHostName
|
||||||
util.SmtpUsername = flagSmtpUsername
|
util.SmtpUsername = flagSmtpUsername
|
||||||
util.SmtpPassword = flagSmtpPassword
|
util.SmtpPassword = flagSmtpPassword
|
||||||
util.SmtpAuthType = flagSmtpAuthType
|
util.SmtpAuthType = flagSmtpAuthType
|
||||||
|
@ -98,16 +109,19 @@ func init() {
|
||||||
util.SessionSecret = []byte(flagSessionSecret)
|
util.SessionSecret = []byte(flagSessionSecret)
|
||||||
util.WgConfTemplate = flagWgConfTemplate
|
util.WgConfTemplate = flagWgConfTemplate
|
||||||
util.BasePath = util.ParseBasePath(flagBasePath)
|
util.BasePath = util.ParseBasePath(flagBasePath)
|
||||||
|
util.BrandText = flagBrandText
|
||||||
|
util.AccentColor = flagAccentColor
|
||||||
|
util.PageTitlePrefix = flagPageTitlePrefix
|
||||||
|
|
||||||
// print only if log level is INFO or lower
|
// print only if log level is INFO or lower
|
||||||
if lvl, _ := util.ParseLogLevel(util.LookupEnvOrString(util.LogLevel, "INFO")); lvl <= log.INFO {
|
if lvl, _ := util.ParseLogLevel(util.LookupEnvOrString(util.LogLevel, "INFO")); lvl <= log.INFO {
|
||||||
// print app information
|
// print app information
|
||||||
fmt.Println("Wireguard UI")
|
fmt.Println("WireGuard UI")
|
||||||
fmt.Println("App Version\t:", appVersion)
|
fmt.Println("App Version\t:", appVersion)
|
||||||
fmt.Println("Git Commit\t:", gitCommit)
|
fmt.Println("Git Commit\t:", gitCommit)
|
||||||
fmt.Println("Git Ref\t\t:", gitRef)
|
fmt.Println("Git Ref\t\t:", gitRef)
|
||||||
fmt.Println("Build Time\t:", buildTime)
|
fmt.Println("Build Time\t:", buildTime)
|
||||||
fmt.Println("Git Repo\t:", "https://github.com/ngoduykhanh/wireguard-ui")
|
fmt.Println("Git Repo\t:", "https://github.com/idressos/wireguard-ui")
|
||||||
fmt.Println("Authentication\t:", !util.DisableLogin)
|
fmt.Println("Authentication\t:", !util.DisableLogin)
|
||||||
fmt.Println("Bind address\t:", util.BindAddress)
|
fmt.Println("Bind address\t:", util.BindAddress)
|
||||||
//fmt.Println("Sendgrid key\t:", util.SendgridApiKey)
|
//fmt.Println("Sendgrid key\t:", util.SendgridApiKey)
|
||||||
|
@ -133,6 +147,9 @@ func main() {
|
||||||
extraData["gitCommit"] = gitCommit
|
extraData["gitCommit"] = gitCommit
|
||||||
extraData["basePath"] = util.BasePath
|
extraData["basePath"] = util.BasePath
|
||||||
extraData["loginDisabled"] = flagDisableLogin
|
extraData["loginDisabled"] = flagDisableLogin
|
||||||
|
extraData["brandText"] = flagBrandText;
|
||||||
|
extraData["accentColor"] = flagAccentColor;
|
||||||
|
extraData["pageTitlePrefix"] = flagPageTitlePrefix;
|
||||||
|
|
||||||
// strip the "templates/" prefix from the embedded directory so files can be read by their direct name (e.g.
|
// strip the "templates/" prefix from the embedded directory so files can be read by their direct name (e.g.
|
||||||
// "base.html" instead of "templates/base.html")
|
// "base.html" instead of "templates/base.html")
|
||||||
|
@ -163,13 +180,14 @@ func main() {
|
||||||
if util.SendgridApiKey != "" {
|
if util.SendgridApiKey != "" {
|
||||||
sendmail = emailer.NewSendgridApiMail(util.SendgridApiKey, util.EmailFromName, util.EmailFrom)
|
sendmail = emailer.NewSendgridApiMail(util.SendgridApiKey, util.EmailFromName, util.EmailFrom)
|
||||||
} else {
|
} else {
|
||||||
sendmail = emailer.NewSmtpMail(util.SmtpHostname, util.SmtpPort, util.SmtpUsername, util.SmtpPassword, util.SmtpNoTLSCheck, util.SmtpAuthType, util.EmailFromName, util.EmailFrom, util.SmtpEncryption)
|
sendmail = emailer.NewSmtpMail(util.SmtpHostname, util.SmtpPort, util.SmtpUsername, util.SmtpPassword, util.HelloHostName, util.SmtpNoTLSCheck, util.SmtpAuthType, util.EmailFromName, util.EmailFrom, util.SmtpEncryption)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.GET(util.BasePath+"/test-hash", handler.GetHashesChanges(db), handler.ValidSession)
|
app.GET(util.BasePath+"/test-hash", handler.GetHashesChanges(db), handler.ValidSession)
|
||||||
app.GET(util.BasePath+"/about", handler.AboutPage())
|
app.GET(util.BasePath+"/about", handler.AboutPage())
|
||||||
app.GET(util.BasePath+"/_health", handler.Health())
|
app.GET(util.BasePath+"/_health", handler.Health())
|
||||||
app.GET(util.BasePath+"/favicon", handler.Favicon())
|
app.GET(util.BasePath+"/favicon", handler.Favicon())
|
||||||
|
app.GET(util.BasePath+"/logo", handler.Logo())
|
||||||
app.POST(util.BasePath+"/new-client", handler.NewClient(db), handler.ValidSession, handler.ContentTypeJson)
|
app.POST(util.BasePath+"/new-client", handler.NewClient(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.POST(util.BasePath+"/update-client", handler.UpdateClient(db), handler.ValidSession, handler.ContentTypeJson)
|
app.POST(util.BasePath+"/update-client", handler.UpdateClient(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.POST(util.BasePath+"/email-client", handler.EmailClient(db, sendmail, defaultEmailSubject, defaultEmailContent), handler.ValidSession, handler.ContentTypeJson)
|
app.POST(util.BasePath+"/email-client", handler.EmailClient(db, sendmail, defaultEmailSubject, defaultEmailContent), handler.ValidSession, handler.ContentTypeJson)
|
||||||
|
|
|
@ -15,6 +15,7 @@ type Client struct {
|
||||||
AllocatedIPs []string `json:"allocated_ips"`
|
AllocatedIPs []string `json:"allocated_ips"`
|
||||||
AllowedIPs []string `json:"allowed_ips"`
|
AllowedIPs []string `json:"allowed_ips"`
|
||||||
ExtraAllowedIPs []string `json:"extra_allowed_ips"`
|
ExtraAllowedIPs []string `json:"extra_allowed_ips"`
|
||||||
|
Endpoint string `json:"endpoint"`
|
||||||
UseServerDNS bool `json:"use_server_dns"`
|
UseServerDNS bool `json:"use_server_dns"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "wireguard-ui",
|
"name": "wireguard-ui",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Wireguard web interface",
|
"description": "WireGuard web interface",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": "git@github.com:ngoduykhanh/wireguard-ui.git",
|
"repository": "git@github.com:ngoduykhanh/wireguard-ui.git",
|
||||||
"author": "Khanh Ngo <k@ndk.name>",
|
"author": "Khanh Ngo <k@ndk.name>",
|
||||||
|
|
|
@ -68,7 +68,10 @@ func (o *JsonDB) Init() error {
|
||||||
serverInterface.PostDown = util.LookupEnvOrString(util.ServerPostDownScriptEnvVar, "")
|
serverInterface.PostDown = util.LookupEnvOrString(util.ServerPostDownScriptEnvVar, "")
|
||||||
serverInterface.UpdatedAt = time.Now().UTC()
|
serverInterface.UpdatedAt = time.Now().UTC()
|
||||||
o.conn.Write("server", "interfaces", serverInterface)
|
o.conn.Write("server", "interfaces", serverInterface)
|
||||||
os.Chmod(serverInterfacePath, 0600)
|
err := util.ManagePerms(serverInterfacePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// server's key pair
|
// server's key pair
|
||||||
|
@ -83,7 +86,10 @@ func (o *JsonDB) Init() error {
|
||||||
serverKeyPair.PublicKey = key.PublicKey().String()
|
serverKeyPair.PublicKey = key.PublicKey().String()
|
||||||
serverKeyPair.UpdatedAt = time.Now().UTC()
|
serverKeyPair.UpdatedAt = time.Now().UTC()
|
||||||
o.conn.Write("server", "keypair", serverKeyPair)
|
o.conn.Write("server", "keypair", serverKeyPair)
|
||||||
os.Chmod(serverKeyPairPath, 0600)
|
err = util.ManagePerms(serverKeyPairPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// global settings
|
// global settings
|
||||||
|
@ -108,7 +114,10 @@ func (o *JsonDB) Init() error {
|
||||||
globalSetting.ConfigFilePath = util.LookupEnvOrString(util.ConfigFilePathEnvVar, util.DefaultConfigFilePath)
|
globalSetting.ConfigFilePath = util.LookupEnvOrString(util.ConfigFilePathEnvVar, util.DefaultConfigFilePath)
|
||||||
globalSetting.UpdatedAt = time.Now().UTC()
|
globalSetting.UpdatedAt = time.Now().UTC()
|
||||||
o.conn.Write("server", "global_settings", globalSetting)
|
o.conn.Write("server", "global_settings", globalSetting)
|
||||||
os.Chmod(globalSettingPath, 0600)
|
err := util.ManagePerms(globalSettingPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hashes
|
// hashes
|
||||||
|
@ -117,7 +126,10 @@ func (o *JsonDB) Init() error {
|
||||||
clientServerHashes.Client = "none"
|
clientServerHashes.Client = "none"
|
||||||
clientServerHashes.Server = "none"
|
clientServerHashes.Server = "none"
|
||||||
o.conn.Write("server", "hashes", clientServerHashes)
|
o.conn.Write("server", "hashes", clientServerHashes)
|
||||||
os.Chmod(hashesPath, 0600)
|
err := util.ManagePerms(hashesPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// user info
|
// user info
|
||||||
|
@ -136,7 +148,10 @@ func (o *JsonDB) Init() error {
|
||||||
user.PasswordHash = hash
|
user.PasswordHash = hash
|
||||||
}
|
}
|
||||||
o.conn.Write("users", user.Username, user)
|
o.conn.Write("users", user.Username, user)
|
||||||
os.Chmod(path.Join(path.Join(o.dbPath, "users"), user.Username+".json"), 0600)
|
err = util.ManagePerms(path.Join(path.Join(o.dbPath, "users"), user.Username+".json"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -182,7 +197,10 @@ func (o *JsonDB) GetUserByName(username string) (model.User, error) {
|
||||||
func (o *JsonDB) SaveUser(user model.User) error {
|
func (o *JsonDB) SaveUser(user model.User) error {
|
||||||
userPath := path.Join(path.Join(o.dbPath, "users"), user.Username+".json")
|
userPath := path.Join(path.Join(o.dbPath, "users"), user.Username+".json")
|
||||||
output := o.conn.Write("users", user.Username, user)
|
output := o.conn.Write("users", user.Username, user)
|
||||||
os.Chmod(userPath, 0600)
|
err := util.ManagePerms(userPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +313,10 @@ func (o *JsonDB) GetClientByID(clientID string, qrCodeSettings model.QRCodeSetti
|
||||||
func (o *JsonDB) SaveClient(client model.Client) error {
|
func (o *JsonDB) SaveClient(client model.Client) error {
|
||||||
clientPath := path.Join(path.Join(o.dbPath, "clients"), client.ID+".json")
|
clientPath := path.Join(path.Join(o.dbPath, "clients"), client.ID+".json")
|
||||||
output := o.conn.Write("clients", client.ID, client)
|
output := o.conn.Write("clients", client.ID, client)
|
||||||
os.Chmod(clientPath, 0600)
|
err := util.ManagePerms(clientPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,21 +327,30 @@ func (o *JsonDB) DeleteClient(clientID string) error {
|
||||||
func (o *JsonDB) SaveServerInterface(serverInterface model.ServerInterface) error {
|
func (o *JsonDB) SaveServerInterface(serverInterface model.ServerInterface) error {
|
||||||
serverInterfacePath := path.Join(path.Join(o.dbPath, "server"), "interfaces.json")
|
serverInterfacePath := path.Join(path.Join(o.dbPath, "server"), "interfaces.json")
|
||||||
output := o.conn.Write("server", "interfaces", serverInterface)
|
output := o.conn.Write("server", "interfaces", serverInterface)
|
||||||
os.Chmod(serverInterfacePath, 0600)
|
err := util.ManagePerms(serverInterfacePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *JsonDB) SaveServerKeyPair(serverKeyPair model.ServerKeypair) error {
|
func (o *JsonDB) SaveServerKeyPair(serverKeyPair model.ServerKeypair) error {
|
||||||
serverKeyPairPath := path.Join(path.Join(o.dbPath, "server"), "keypair.json")
|
serverKeyPairPath := path.Join(path.Join(o.dbPath, "server"), "keypair.json")
|
||||||
output := o.conn.Write("server", "keypair", serverKeyPair)
|
output := o.conn.Write("server", "keypair", serverKeyPair)
|
||||||
os.Chmod(serverKeyPairPath, 0600)
|
err := util.ManagePerms(serverKeyPairPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *JsonDB) SaveGlobalSettings(globalSettings model.GlobalSetting) error {
|
func (o *JsonDB) SaveGlobalSettings(globalSettings model.GlobalSetting) error {
|
||||||
globalSettingsPath := path.Join(path.Join(o.dbPath, "server"), "global_settings.json")
|
globalSettingsPath := path.Join(path.Join(o.dbPath, "server"), "global_settings.json")
|
||||||
output := o.conn.Write("server", "global_settings", globalSettings)
|
output := o.conn.Write("server", "global_settings", globalSettings)
|
||||||
os.Chmod(globalSettingsPath, 0600)
|
err := util.ManagePerms(globalSettingsPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,6 +366,9 @@ func (o *JsonDB) GetHashes() (model.ClientServerHashes, error) {
|
||||||
func (o *JsonDB) SaveHashes(hashes model.ClientServerHashes) error {
|
func (o *JsonDB) SaveHashes(hashes model.ClientServerHashes) error {
|
||||||
hashesPath := path.Join(path.Join(o.dbPath, "server"), "hashes.json")
|
hashesPath := path.Join(path.Join(o.dbPath, "server"), "hashes.json")
|
||||||
output := o.conn.Write("server", "hashes", hashes)
|
output := o.conn.Write("server", "hashes", hashes)
|
||||||
os.Chmod(hashesPath, 0600)
|
err := util.ManagePerms(hashesPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
|
@ -3,10 +3,10 @@ package jsondb
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/ngoduykhanh/wireguard-ui/model"
|
"github.com/ngoduykhanh/wireguard-ui/model"
|
||||||
|
"github.com/ngoduykhanh/wireguard-ui/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (o *JsonDB) GetWakeOnLanHosts() ([]model.WakeOnLanHost, error) {
|
func (o *JsonDB) GetWakeOnLanHosts() ([]model.WakeOnLanHost, error) {
|
||||||
|
@ -70,7 +70,11 @@ func (o *JsonDB) SaveWakeOnLanHost(host model.WakeOnLanHost) error {
|
||||||
|
|
||||||
wakeOnLanHostPath := path.Join(path.Join(o.dbPath, model.WakeOnLanHostCollectionName), resourceName+".json")
|
wakeOnLanHostPath := path.Join(path.Join(o.dbPath, model.WakeOnLanHostCollectionName), resourceName+".json")
|
||||||
output := o.conn.Write(model.WakeOnLanHostCollectionName, resourceName, host)
|
output := o.conn.Write(model.WakeOnLanHostCollectionName, resourceName, host)
|
||||||
os.Chmod(wakeOnLanHostPath, 0600)
|
err = util.ManagePerms(wakeOnLanHostPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ About
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card card-success">
|
<div class="card card-success">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="card-title">About Wireguard-UI</h3>
|
<h3 class="card-title">About WireGuard-UI</h3>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card-header -->
|
<!-- /.card-header -->
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
@ -63,7 +63,7 @@ About
|
||||||
</div>
|
</div>
|
||||||
<strong>Copyright ©
|
<strong>Copyright ©
|
||||||
<script>document.write(new Date().getFullYear())</script>
|
<script>document.write(new Date().getFullYear())</script>
|
||||||
<a href="https://github.com/ngoduykhanh/wireguard-ui">Wireguard UI</a>.
|
<a href="https://github.com/idressos/wireguard-ui">WireGuard UI</a>.
|
||||||
</strong> All rights reserved.
|
</strong> All rights reserved.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -83,7 +83,7 @@ About
|
||||||
$.ajax({
|
$.ajax({
|
||||||
cache: false,
|
cache: false,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: 'https://api.github.com/repos/ngoduykhanh/wireguard-ui/releases/tags/' + $("#version").val(),
|
url: 'https://api.github.com/repos/idressos/wireguard-ui/releases/tags/' + $("#version").val(),
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
|
@ -99,7 +99,7 @@ About
|
||||||
$.ajax({
|
$.ajax({
|
||||||
cache: false,
|
cache: false,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: 'https://api.github.com/repos/ngoduykhanh/wireguard-ui/releases/latest',
|
url: 'https://api.github.com/repos/idressos/wireguard-ui/releases/latest',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
|
@ -121,7 +121,7 @@ About
|
||||||
$.ajax({
|
$.ajax({
|
||||||
cache: false,
|
cache: false,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: 'https://api.github.com/repos/ngoduykhanh/wireguard-ui/contributors',
|
url: 'https://api.github.com/repos/idressos/wireguard-ui/contributors',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<title>{{template "title" .}}</title>
|
<title>{{.pageTitlePrefix}}{{template "title" .}}</title>
|
||||||
<!-- Tell the browser to be responsive to screen width -->
|
<!-- Tell the browser to be responsive to screen width -->
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
|
@ -84,10 +84,10 @@
|
||||||
<!-- /.navbar -->
|
<!-- /.navbar -->
|
||||||
|
|
||||||
<!-- Main Sidebar Container -->
|
<!-- Main Sidebar Container -->
|
||||||
<aside class="main-sidebar sidebar-dark-primary elevation-4">
|
<aside class="main-sidebar sidebar-dark-primary elevation-4" style="background-color: {{.accentColor}};">
|
||||||
<!-- Brand Logo -->
|
<!-- Brand Logo -->
|
||||||
<a href="{{.basePath}}" class="brand-link">
|
<a href="{{.basePath}}" class="brand-link">
|
||||||
<span class="brand-text"> WIREGUARD UI</span>
|
<span class="brand-text"> {{.brandText}}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
|
@ -120,7 +120,7 @@
|
||||||
<a href="{{.basePath}}/" class="nav-link {{if eq .baseData.Active ""}}active{{end}}">
|
<a href="{{.basePath}}/" class="nav-link {{if eq .baseData.Active ""}}active{{end}}">
|
||||||
<i class="nav-icon fas fa-user-secret"></i>
|
<i class="nav-icon fas fa-user-secret"></i>
|
||||||
<p>
|
<p>
|
||||||
Wireguard Clients
|
Clients
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -130,7 +130,7 @@
|
||||||
<a href="{{.basePath}}/wg-server" class="nav-link {{if eq .baseData.Active "wg-server" }}active{{end}}">
|
<a href="{{.basePath}}/wg-server" class="nav-link {{if eq .baseData.Active "wg-server" }}active{{end}}">
|
||||||
<i class="nav-icon fas fa-server"></i>
|
<i class="nav-icon fas fa-server"></i>
|
||||||
<p>
|
<p>
|
||||||
Wireguard Server
|
WireGuard Server
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -174,6 +174,8 @@
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
{{if .baseData.Admin}}
|
||||||
<li class="nav-header">ABOUT</li>
|
<li class="nav-header">ABOUT</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="{{.basePath}}/about" class="nav-link {{if eq .baseData.Active "about" }}active{{end}}">
|
<a href="{{.basePath}}/about" class="nav-link {{if eq .baseData.Active "about" }}active{{end}}">
|
||||||
|
@ -183,6 +185,7 @@
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<!-- /.sidebar-menu -->
|
<!-- /.sidebar-menu -->
|
||||||
|
@ -194,7 +197,7 @@
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 class="modal-title">New Wireguard Client</h4>
|
<h4 class="modal-title">New WireGuard Client</h4>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -232,6 +235,10 @@
|
||||||
</label>
|
</label>
|
||||||
<input type="text" data-role="tagsinput" class="form-control" id="client_extra_allowed_ips" value="{{ StringsJoin .client_defaults.ExtraAllowedIps "," }}">
|
<input type="text" data-role="tagsinput" class="form-control" id="client_extra_allowed_ips" value="{{ StringsJoin .client_defaults.ExtraAllowedIps "," }}">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="client_endpoint" class="control-label">Endpoint</label>
|
||||||
|
<input type="text" class="form-control" id="client_endpoint" name="client_endpoint">
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="icheck-primary d-inline">
|
<div class="icheck-primary d-inline">
|
||||||
<input type="checkbox" id="use_server_dns" {{ if .client_defaults.UseServerDNS }}checked{{ end }}>
|
<input type="checkbox" id="use_server_dns" {{ if .client_defaults.UseServerDNS }}checked{{ end }}>
|
||||||
|
@ -328,7 +335,7 @@
|
||||||
<div class="float-right d-none d-sm-block">
|
<div class="float-right d-none d-sm-block">
|
||||||
<b>Version</b> {{ .appVersion }}
|
<b>Version</b> {{ .appVersion }}
|
||||||
</div>
|
</div>
|
||||||
<strong>Copyright © <script>document.write(new Date().getFullYear())</script> <a href="https://github.com/ngoduykhanh/wireguard-ui">Wireguard UI</a>.</strong> All rights
|
<strong>Copyright © <script>document.write(new Date().getFullYear())</script> <a href="https://github.com/idressos/wireguard-ui">WireGuard UI</a>.</strong> All rights
|
||||||
reserved.
|
reserved.
|
||||||
</footer>
|
</footer>
|
||||||
-->
|
-->
|
||||||
|
@ -413,6 +420,7 @@
|
||||||
const email = $("#client_email").val();
|
const email = $("#client_email").val();
|
||||||
const allocated_ips = $("#client_allocated_ips").val().split(",");
|
const allocated_ips = $("#client_allocated_ips").val().split(",");
|
||||||
const allowed_ips = $("#client_allowed_ips").val().split(",");
|
const allowed_ips = $("#client_allowed_ips").val().split(",");
|
||||||
|
const endpoint = $("#client_endpoint").val();
|
||||||
let use_server_dns = false;
|
let use_server_dns = false;
|
||||||
let extra_allowed_ips = [];
|
let extra_allowed_ips = [];
|
||||||
|
|
||||||
|
@ -434,7 +442,7 @@
|
||||||
const preshared_key = $("#client_preshared_key").val();
|
const preshared_key = $("#client_preshared_key").val();
|
||||||
|
|
||||||
const data = {"name": name, "email": email, "allocated_ips": allocated_ips, "allowed_ips": allowed_ips,
|
const data = {"name": name, "email": email, "allocated_ips": allocated_ips, "allowed_ips": allowed_ips,
|
||||||
"extra_allowed_ips": extra_allowed_ips, "use_server_dns": use_server_dns, "enabled": enabled,
|
"extra_allowed_ips": extra_allowed_ips, "endpoint": endpoint, "use_server_dns": use_server_dns, "enabled": enabled,
|
||||||
"public_key": public_key, "preshared_key": preshared_key};
|
"public_key": public_key, "preshared_key": preshared_key};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{{define "title"}}
|
{{define "title"}}
|
||||||
Wireguard Clients
|
Clients
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "top_css"}}
|
{{define "top_css"}}
|
||||||
|
@ -17,13 +17,13 @@ Wireguard Clients
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "page_title"}}
|
{{define "page_title"}}
|
||||||
Wireguard Clients
|
Clients
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "page_content"}}
|
{{define "page_content"}}
|
||||||
<section class="content">
|
<section class="content">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!-- <h5 class="mt-4 mb-2">Wireguard Clients</h5> -->
|
<!-- <h5 class="mt-4 mb-2">Clients</h5> -->
|
||||||
<div class="row" id="client-list">
|
<div class="row" id="client-list">
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
<!-- /.row -->
|
||||||
|
@ -113,6 +113,10 @@ Wireguard Clients
|
||||||
<input type="text" data-role="tagsinput" class="form-control"
|
<input type="text" data-role="tagsinput" class="form-control"
|
||||||
id="_client_extra_allowed_ips">
|
id="_client_extra_allowed_ips">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="_client_endpoint" class="control-label">Endpoint</label>
|
||||||
|
<input type="text" class="form-control" id="_client_endpoint" name="client_endpoint">
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="icheck-primary d-inline">
|
<div class="icheck-primary d-inline">
|
||||||
<input type="checkbox" id="_use_server_dns">
|
<input type="checkbox" id="_use_server_dns">
|
||||||
|
@ -477,6 +481,8 @@ Wireguard Clients
|
||||||
modal.find("#_client_extra_allowed_ips").addTag(obj);
|
modal.find("#_client_extra_allowed_ips").addTag(obj);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modal.find("#_client_endpoint").val(client.endpoint);
|
||||||
|
|
||||||
modal.find("#_use_server_dns").prop("checked", client.use_server_dns);
|
modal.find("#_use_server_dns").prop("checked", client.use_server_dns);
|
||||||
modal.find("#_enabled").prop("checked", client.enabled);
|
modal.find("#_enabled").prop("checked", client.enabled);
|
||||||
|
|
||||||
|
@ -564,6 +570,8 @@ Wireguard Clients
|
||||||
extra_allowed_ips = $("#_client_extra_allowed_ips").val().split(",");
|
extra_allowed_ips = $("#_client_extra_allowed_ips").val().split(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const endpoint = $("#_client_endpoint").val();
|
||||||
|
|
||||||
if ($("#_use_server_dns").is(':checked')){
|
if ($("#_use_server_dns").is(':checked')){
|
||||||
use_server_dns = true;
|
use_server_dns = true;
|
||||||
}
|
}
|
||||||
|
@ -575,7 +583,8 @@ Wireguard Clients
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {"id": client_id, "name": name, "email": email, "allocated_ips": allocated_ips,
|
const data = {"id": client_id, "name": name, "email": email, "allocated_ips": allocated_ips,
|
||||||
"allowed_ips": allowed_ips, "extra_allowed_ips": extra_allowed_ips, "use_server_dns": use_server_dns, "enabled": enabled, "public_key": public_key, "preshared_key": preshared_key};
|
"allowed_ips": allowed_ips, "extra_allowed_ips": extra_allowed_ips, "endpoint": endpoint,
|
||||||
|
"use_server_dns": use_server_dns, "enabled": enabled, "public_key": public_key, "preshared_key": preshared_key};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
cache: false,
|
cache: false,
|
||||||
|
|
|
@ -22,7 +22,7 @@ Global Settings
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card card-success">
|
<div class="card card-success">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="card-title">Wireguard Global Settings</h3>
|
<h3 class="card-title">WireGuard Global Settings</h3>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card-header -->
|
<!-- /.card-header -->
|
||||||
<!-- form start -->
|
<!-- form start -->
|
||||||
|
@ -68,7 +68,7 @@ Global Settings
|
||||||
value="{{ .globalSettings.Table }}">
|
value="{{ .globalSettings.Table }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="config_file_path">Wireguard Config File Path</label>
|
<label for="config_file_path">WireGuard Config File Path</label>
|
||||||
<input type="text" class="form-control" id="config_file_path"
|
<input type="text" class="form-control" id="config_file_path"
|
||||||
name="config_file_path" placeholder="E.g. /etc/wireguard/wg0.conf"
|
name="config_file_path" placeholder="E.g. /etc/wireguard/wg0.conf"
|
||||||
value="{{ .globalSettings.ConfigFilePath }}">
|
value="{{ .globalSettings.ConfigFilePath }}">
|
||||||
|
@ -92,7 +92,7 @@ Global Settings
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<dl>
|
<dl>
|
||||||
<dt>1. Endpoint Address</dt>
|
<dt>1. Endpoint Address</dt>
|
||||||
<dd>The public IP address of your Wireguard server that the client will connect to. Click on
|
<dd>The public IP address of your WireGuard server that the client will connect to. Click on
|
||||||
<strong>Suggest</strong> button to auto detect the public IP address of your server.</dd>
|
<strong>Suggest</strong> button to auto detect the public IP address of your server.</dd>
|
||||||
<dt>2. DNS Servers</dt>
|
<dt>2. DNS Servers</dt>
|
||||||
<dd>The DNS servers will be set to client config.</dd>
|
<dd>The DNS servers will be set to client config.</dd>
|
||||||
|
@ -110,8 +110,8 @@ Global Settings
|
||||||
<dd>Add a matching <code>fwmark</code> on all packets going out of a WireGuard non-default-route tunnel. Default value: <code>0xca6c</code></dd>
|
<dd>Add a matching <code>fwmark</code> on all packets going out of a WireGuard non-default-route tunnel. Default value: <code>0xca6c</code></dd>
|
||||||
<dt>6. Table</dt>
|
<dt>6. Table</dt>
|
||||||
<dd>Value for the <code>Table</code> setting in the wg conf file. Default value: <code>auto</code></dd>
|
<dd>Value for the <code>Table</code> setting in the wg conf file. Default value: <code>auto</code></dd>
|
||||||
<dt>7. Wireguard Config File Path</dt>
|
<dt>7. WireGuard Config File Path</dt>
|
||||||
<dd>The path of your Wireguard server config file. Please make sure the parent directory
|
<dd>The path of your WireGuard server config file. Please make sure the parent directory
|
||||||
exists and is writable.</dd>
|
exists and is writable.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
@ -195,7 +195,7 @@ Global Settings
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
// Wireguard Interface DNS server tag input
|
// WireGuard Interface DNS server tag input
|
||||||
$("#dns_servers").tagsInput({
|
$("#dns_servers").tagsInput({
|
||||||
'width': '100%',
|
'width': '100%',
|
||||||
'height': '75%',
|
'height': '75%',
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<title>WireGuard UI</title>
|
<title>{{.brandText}}</title>
|
||||||
<!-- Tell the browser to be responsive to screen width -->
|
<!-- Tell the browser to be responsive to screen width -->
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
|
@ -24,8 +24,8 @@
|
||||||
|
|
||||||
<body class="hold-transition login-page">
|
<body class="hold-transition login-page">
|
||||||
<div class="login-box">
|
<div class="login-box">
|
||||||
<div class="login-logo">
|
<div class="login-logo pb-3">
|
||||||
<a href="https://github.com/ngoduykhanh/wireguard-ui">WireGuard UI</a>
|
<img class="img-fluid" src="{{.basePath}}/logo">
|
||||||
</div>
|
</div>
|
||||||
<!-- /.login-logo -->
|
<!-- /.login-logo -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{{define "title"}}
|
{{define "title"}}
|
||||||
Wireguard Server
|
WireGuard Server
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "top_css"}}
|
{{define "top_css"}}
|
||||||
|
@ -10,13 +10,13 @@ Wireguard Server
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "page_title"}}
|
{{define "page_title"}}
|
||||||
Wireguard Server Settings
|
WireGuard Server Settings
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "page_content"}}
|
{{define "page_content"}}
|
||||||
<section class="content">
|
<section class="content">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!-- <h5 class="mt-4 mb-2">Wireguard Server</h5> -->
|
<!-- <h5 class="mt-4 mb-2">WireGuard Server</h5> -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- left column -->
|
<!-- left column -->
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
@ -39,13 +39,13 @@ Wireguard Server Settings
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="post_up">Post Up Script</label>
|
<label for="post_up">Post Up Script</label>
|
||||||
<input type="text" class="form-control" id="post_up" name="post_up"
|
<textarea class="form-control" id="post_up" name="post_up"
|
||||||
placeholder="Post Up Script" value="{{ .serverInterface.PostUp }}">
|
placeholder="Post Up Script">{{ .serverInterface.PostUp }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="post_down">Post Down Script</label>
|
<label for="post_down">Post Down Script</label>
|
||||||
<input type="text" class="form-control" id="post_down" name="post_down"
|
<textarea class="form-control" id="post_down" name="post_down"
|
||||||
placeholder="Post Down Script" value="{{ .serverInterface.PostDown }}">
|
placeholder="Post Down Script">{{ .serverInterface.PostDown }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card-body -->
|
<!-- /.card-body -->
|
||||||
|
@ -109,7 +109,7 @@ Wireguard Server Settings
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>Are you sure to generate a new key pair for the Wireguard server?<br/>
|
<p>Are you sure to generate a new key pair for the WireGuard server?<br/>
|
||||||
The existing Client's peer public key need to be updated to keep the connection working.</p>
|
The existing Client's peer public key need to be updated to keep the connection working.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer justify-content-between">
|
<div class="modal-footer justify-content-between">
|
||||||
|
@ -142,7 +142,7 @@ Wireguard Server Settings
|
||||||
data: JSON.stringify(data),
|
data: JSON.stringify(data),
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
$("#modal_new_client").modal('hide');
|
$("#modal_new_client").modal('hide');
|
||||||
toastr.success('Updated Wireguard server interface addresses successfully');
|
toastr.success('Updated WireGuard server interface addresses successfully');
|
||||||
},
|
},
|
||||||
error: function(jqXHR, exception) {
|
error: function(jqXHR, exception) {
|
||||||
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
||||||
|
@ -152,7 +152,7 @@ Wireguard Server Settings
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
// Wireguard Interface Addresses tag input
|
// WireGuard Interface Addresses tag input
|
||||||
$("#addresses").tagsInput({
|
$("#addresses").tagsInput({
|
||||||
'width': '100%',
|
'width': '100%',
|
||||||
// 'height': '75%',
|
// 'height': '75%',
|
||||||
|
@ -169,7 +169,7 @@ Wireguard Server Settings
|
||||||
$("#addresses").addTag('{{.}}');
|
$("#addresses").addTag('{{.}}');
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
// Wireguard Interface Addresses form validation
|
// WireGuard Interface Addresses form validation
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$.validator.setDefaults({
|
$.validator.setDefaults({
|
||||||
submitHandler: function () {
|
submitHandler: function () {
|
||||||
|
@ -205,7 +205,7 @@ Wireguard Server Settings
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wireguard Key Pair generation confirmation button
|
// WireGuard Key Pair generation confirmation button
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("#btn_generate_confirm").click(function () {
|
$("#btn_generate_confirm").click(function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|
|
@ -35,7 +35,6 @@ Connected Peers
|
||||||
{{ end}}
|
{{ end}}
|
||||||
{{ range $dev := .devices }}
|
{{ range $dev := .devices }}
|
||||||
<table class="table table-sm">
|
<table class="table table-sm">
|
||||||
<caption>List of connected peers for device with name {{ $dev.Name }} </caption>
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">#</th>
|
<th scope="col">#</th>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# This file was generated using wireguard-ui (https://github.com/ngoduykhanh/wireguard-ui)
|
# This file was generated using wireguard-ui (https://github.com/idressos/wireguard-ui)
|
||||||
# Please don't modify it manually, otherwise your change might get replaced.
|
# Please don't modify it manually, otherwise your change might get replaced.
|
||||||
|
|
||||||
# Address updated at: {{ .serverConfig.Interface.UpdatedAt }}
|
# Address updated at: {{ .serverConfig.Interface.UpdatedAt }}
|
||||||
|
@ -7,10 +7,11 @@
|
||||||
Address = {{$first :=true}}{{range .serverConfig.Interface.Addresses }}{{if $first}}{{$first = false}}{{else}},{{end}}{{.}}{{end}}
|
Address = {{$first :=true}}{{range .serverConfig.Interface.Addresses }}{{if $first}}{{$first = false}}{{else}},{{end}}{{.}}{{end}}
|
||||||
ListenPort = {{ .serverConfig.Interface.ListenPort }}
|
ListenPort = {{ .serverConfig.Interface.ListenPort }}
|
||||||
PrivateKey = {{ .serverConfig.KeyPair.PrivateKey }}
|
PrivateKey = {{ .serverConfig.KeyPair.PrivateKey }}
|
||||||
|
{{if .globalSettings.FirewallMark }}FwMark = {{ .globalSettings.FirewallMark }}{{end}}
|
||||||
{{if .globalSettings.MTU}}MTU = {{ .globalSettings.MTU }}{{end}}
|
{{if .globalSettings.MTU}}MTU = {{ .globalSettings.MTU }}{{end}}
|
||||||
PostUp = {{ .serverConfig.Interface.PostUp }}
|
{{if .serverConfig.Interface.PostUp }}PostUp = {{ .serverConfig.Interface.PostUp }}{{end}}
|
||||||
PostDown = {{ .serverConfig.Interface.PostDown }}
|
{{if .serverConfig.Interface.PostDown }}PostDown = {{ .serverConfig.Interface.PostDown }}{{end}}
|
||||||
Table = {{ .globalSettings.Table }}
|
{{if .globalSettings.Table}}Table = {{ .globalSettings.Table }}{{end}}
|
||||||
|
|
||||||
{{range .clientDataList}}{{if eq .Client.Enabled true}}
|
{{range .clientDataList}}{{if eq .Client.Enabled true}}
|
||||||
# ID: {{ .Client.ID }}
|
# ID: {{ .Client.ID }}
|
||||||
|
@ -20,6 +21,8 @@ Table = {{ .globalSettings.Table }}
|
||||||
# Update at: {{ .Client.UpdatedAt }}
|
# Update at: {{ .Client.UpdatedAt }}
|
||||||
[Peer]
|
[Peer]
|
||||||
PublicKey = {{ .Client.PublicKey }}
|
PublicKey = {{ .Client.PublicKey }}
|
||||||
{{if .Client.PresharedKey }}PresharedKey = {{ .Client.PresharedKey }}
|
{{if .Client.PresharedKey }}PresharedKey = {{ .Client.PresharedKey }}{{end}}
|
||||||
{{end}}AllowedIPs = {{$first :=true}}{{range .Client.AllocatedIPs }}{{if $first}}{{$first = false}}{{else}},{{end}}{{.}}{{end}}{{range .Client.ExtraAllowedIPs }},{{.}}{{end}}
|
AllowedIPs = {{$first :=true}}{{range .Client.AllocatedIPs }}{{if $first}}{{$first = false}}{{else}},{{end}}{{.}}{{end}}{{range .Client.ExtraAllowedIPs }},{{.}}{{end}}{{end}}
|
||||||
{{end}}{{end}}
|
{{if $.globalSettings.PersistentKeepalive}}PersistentKeepalive = {{ $.globalSettings.PersistentKeepalive }}{{end}}
|
||||||
|
{{if .Client.Endpoint }}Endpoint = {{ .Client.Endpoint }}{{end}}
|
||||||
|
{{end}}
|
|
@ -10,6 +10,7 @@ var (
|
||||||
SmtpPort int
|
SmtpPort int
|
||||||
SmtpUsername string
|
SmtpUsername string
|
||||||
SmtpPassword string
|
SmtpPassword string
|
||||||
|
HelloHostName string
|
||||||
SmtpNoTLSCheck bool
|
SmtpNoTLSCheck bool
|
||||||
SmtpEncryption string
|
SmtpEncryption string
|
||||||
SmtpAuthType string
|
SmtpAuthType string
|
||||||
|
@ -19,6 +20,9 @@ var (
|
||||||
SessionSecret []byte
|
SessionSecret []byte
|
||||||
WgConfTemplate string
|
WgConfTemplate string
|
||||||
BasePath string
|
BasePath string
|
||||||
|
BrandText string
|
||||||
|
AccentColor string
|
||||||
|
PageTitlePrefix string
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -53,6 +57,10 @@ const (
|
||||||
DefaultClientExtraAllowedIpsEnvVar = "WGUI_DEFAULT_CLIENT_EXTRA_ALLOWED_IPS"
|
DefaultClientExtraAllowedIpsEnvVar = "WGUI_DEFAULT_CLIENT_EXTRA_ALLOWED_IPS"
|
||||||
DefaultClientUseServerDNSEnvVar = "WGUI_DEFAULT_CLIENT_USE_SERVER_DNS"
|
DefaultClientUseServerDNSEnvVar = "WGUI_DEFAULT_CLIENT_USE_SERVER_DNS"
|
||||||
DefaultClientEnableAfterCreationEnvVar = "WGUI_DEFAULT_CLIENT_ENABLE_AFTER_CREATION"
|
DefaultClientEnableAfterCreationEnvVar = "WGUI_DEFAULT_CLIENT_ENABLE_AFTER_CREATION"
|
||||||
|
BrandTextEnvVar = "WGUI_BRAND_TEXT"
|
||||||
|
AccentColorEnvVar = "WGUI_ACCENT_COLOR"
|
||||||
|
PageTitlePrefixEnvVar = "WGUI_PAGE_TITLE_PREFIX"
|
||||||
|
LogoFilePathEnvVar = "WGUI_LOGO_FILE_PATH"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseBasePath(basePath string) string {
|
func ParseBasePath(basePath string) string {
|
||||||
|
|
12
util/util.go
12
util/util.go
|
@ -4,8 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ngoduykhanh/wireguard-ui/store"
|
|
||||||
"golang.org/x/mod/sumdb/dirhash"
|
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -19,6 +17,9 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ngoduykhanh/wireguard-ui/store"
|
||||||
|
"golang.org/x/mod/sumdb/dirhash"
|
||||||
|
|
||||||
externalip "github.com/glendc/go-external-ip"
|
externalip "github.com/glendc/go-external-ip"
|
||||||
"github.com/labstack/gommon/log"
|
"github.com/labstack/gommon/log"
|
||||||
"github.com/ngoduykhanh/wireguard-ui/model"
|
"github.com/ngoduykhanh/wireguard-ui/model"
|
||||||
|
@ -382,7 +383,7 @@ func ValidateIPAllocation(serverAddresses []string, ipAllocatedList []string, ip
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteWireGuardServerConfig to write Wireguard server config. e.g. wg0.conf
|
// WriteWireGuardServerConfig to write WireGuard server config. e.g. wg0.conf
|
||||||
func WriteWireGuardServerConfig(tmplDir fs.FS, serverConfig model.Server, clientDataList []model.ClientData, usersList []model.User, globalSettings model.GlobalSetting) error {
|
func WriteWireGuardServerConfig(tmplDir fs.FS, serverConfig model.Server, clientDataList []model.ClientData, usersList []model.User, globalSettings model.GlobalSetting) error {
|
||||||
var tmplWireguardConf string
|
var tmplWireguardConf string
|
||||||
|
|
||||||
|
@ -540,3 +541,8 @@ func RandomString(length int) string {
|
||||||
}
|
}
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ManagePerms(path string) error {
|
||||||
|
err := os.Chmod(path, 0600)
|
||||||
|
return err
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue