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
|
||||
|
||||
|
@ -53,7 +53,11 @@ docker-compose up
|
|||
| `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_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_NAME` | The sender name | `WireGuard UI` |
|
||||
| `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_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` |
|
||||
| `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
|
||||
|
||||
|
@ -181,9 +186,9 @@ rc-update add wgui default
|
|||
|
||||
### Using Docker
|
||||
|
||||
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
|
||||
running the container with `restart: unless-stopped`. These settings can also pick up changes to Wireguard Config File
|
||||
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
|
||||
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
|
||||
this
|
||||
feature work.
|
||||
|
@ -224,7 +229,7 @@ go build -o wireguard-ui
|
|||
|
||||
## 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
|
||||
|
||||
|
|
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
|
||||
username string
|
||||
password string
|
||||
helloHostName string
|
||||
authType mail.AuthType
|
||||
encryption mail.Encryption
|
||||
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 {
|
||||
ans := SmtpMail{hostname: hostname, port: port, username: username, password: password, noTLSCheck: noTLSCheck, fromName: fromName, from: from, authType: authType(auth), encryption: encryptionType(encryption)}
|
||||
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, helloHostName: helloHostName, noTLSCheck: noTLSCheck, fromName: fromName, from: from, authType: authType(auth), encryption: encryptionType(encryption)}
|
||||
return &ans
|
||||
}
|
||||
|
||||
|
@ -66,6 +67,7 @@ func (o *SmtpMail) Send(toName string, to string, subject string, content string
|
|||
server.Authentication = o.authType
|
||||
server.Username = o.username
|
||||
server.Password = o.password
|
||||
server.Helo = o.helloHostName
|
||||
server.Encryption = o.encryption
|
||||
server.KeepAlive = false
|
||||
server.ConnectTimeout = 10 * time.Second
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
### 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:
|
||||
```shell
|
||||
|
@ -21,10 +21,10 @@ For security reasons it's highly recommended to change them before the first sta
|
|||
## Examples
|
||||
- **[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)**
|
||||
|
||||
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)**
|
||||
|
||||
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 (
|
||||
"crypto/subtle"
|
||||
"path/filepath"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"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
|
||||
func LoginPage() echo.HandlerFunc {
|
||||
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 {
|
||||
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 {
|
||||
return func(c echo.Context) error {
|
||||
|
||||
|
@ -409,12 +419,12 @@ func NewClient(db store.IStore) echo.HandlerFunc {
|
|||
guid := xid.New()
|
||||
client.ID = guid.String()
|
||||
|
||||
// gen Wireguard key pair
|
||||
// gen WireGuard key pair
|
||||
if client.PublicKey == "" {
|
||||
key, err := wgtypes.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
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.PublicKey = key.PublicKey().String()
|
||||
|
@ -422,7 +432,7 @@ func NewClient(db store.IStore) echo.HandlerFunc {
|
|||
_, err := wgtypes.ParseKey(client.PublicKey)
|
||||
if err != nil {
|
||||
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
|
||||
clients, err := db.GetClients(false)
|
||||
|
@ -444,7 +454,7 @@ func NewClient(db store.IStore) echo.HandlerFunc {
|
|||
if err != nil {
|
||||
log.Error("Cannot generated preshared key: ", err)
|
||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
|
||||
false, "Cannot generate Wireguard preshared key",
|
||||
false, "Cannot generate WireGuard preshared key",
|
||||
})
|
||||
}
|
||||
client.PresharedKey = presharedKey.String()
|
||||
|
@ -455,7 +465,7 @@ func NewClient(db store.IStore) echo.HandlerFunc {
|
|||
_, err := wgtypes.ParseKey(client.PresharedKey)
|
||||
if err != nil {
|
||||
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()
|
||||
|
@ -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"})
|
||||
}
|
||||
|
||||
// update Wireguard Client PublicKey
|
||||
// update WireGuard Client PublicKey
|
||||
if client.PublicKey != _client.PublicKey && _client.PublicKey != "" {
|
||||
_, err := wgtypes.ParseKey(_client.PublicKey)
|
||||
if err != nil {
|
||||
log.Error("Cannot verify provided Wireguard public key: ", err)
|
||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify provided Wireguard public key"})
|
||||
log.Error("Cannot verify provided WireGuard public key: ", err)
|
||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify provided WireGuard public key"})
|
||||
}
|
||||
// check for duplicates
|
||||
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.
|
||||
// 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 != "" {
|
||||
_, err := wgtypes.ParseKey(_client.PresharedKey)
|
||||
if err != nil {
|
||||
log.Error("Cannot verify provided Wireguard preshared key: ", err)
|
||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify provided Wireguard preshared key"})
|
||||
log.Error("Cannot verify provided WireGuard preshared key: ", err)
|
||||
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.AllowedIPs = _client.AllowedIPs
|
||||
client.ExtraAllowedIPs = _client.ExtraAllowedIPs
|
||||
client.Endpoint = _client.Endpoint
|
||||
client.PublicKey = _client.PublicKey
|
||||
client.PresharedKey = _client.PresharedKey
|
||||
client.UpdatedAt = time.Now().UTC()
|
||||
|
@ -689,7 +700,7 @@ func DownloadClient(db store.IStore) echo.HandlerFunc {
|
|||
|
||||
// set response header for downloading
|
||||
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 {
|
||||
return func(c echo.Context) error {
|
||||
|
||||
// gen Wireguard key pair
|
||||
// gen WireGuard key pair
|
||||
key, err := wgtypes.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
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
|
||||
|
@ -772,7 +783,7 @@ func WireGuardServerKeyPair(db store.IStore) echo.HandlerFunc {
|
|||
serverKeyPair.UpdatedAt = time.Now().UTC()
|
||||
|
||||
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)
|
||||
|
||||
|
@ -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
|
||||
func Status(db store.IStore) echo.HandlerFunc {
|
||||
type PeerVM struct {
|
||||
|
@ -826,6 +847,8 @@ func Status(db store.IStore) echo.HandlerFunc {
|
|||
})
|
||||
}
|
||||
|
||||
deviceName := extractDeviceNameFromConfigPath(db)
|
||||
|
||||
devices, err := wgClient.Devices()
|
||||
if err != nil {
|
||||
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}
|
||||
for i := range devices {
|
||||
devVm := DeviceVM{Name: devices[i].Name}
|
||||
for j := range devices[i].Peers {
|
||||
var allocatedIPs string
|
||||
for _, ip := range devices[i].Peers[j].AllowedIPs {
|
||||
if len(allocatedIPs) > 0 {
|
||||
allocatedIPs += "</br>"
|
||||
if devices[i].Name == deviceName {
|
||||
devVm := DeviceVM{Name: devices[i].Name}
|
||||
for j := range devices[i].Peers {
|
||||
var allocatedIPs string
|
||||
for _, ip := range devices[i].Peers[j].AllowedIPs {
|
||||
if len(allocatedIPs) > 0 {
|
||||
allocatedIPs += "</br>"
|
||||
}
|
||||
allocatedIPs += ip.String()
|
||||
}
|
||||
allocatedIPs += ip.String()
|
||||
}
|
||||
pVm := PeerVM{
|
||||
PublicKey: devices[i].Peers[j].PublicKey.String(),
|
||||
ReceivedBytes: devices[i].Peers[j].ReceiveBytes,
|
||||
TransmitBytes: devices[i].Peers[j].TransmitBytes,
|
||||
LastHandshakeTime: devices[i].Peers[j].LastHandshakeTime,
|
||||
LastHandshakeRel: time.Since(devices[i].Peers[j].LastHandshakeTime),
|
||||
AllocatedIP: allocatedIPs,
|
||||
Endpoint: devices[i].Peers[j].Endpoint.String(),
|
||||
}
|
||||
pVm.Connected = pVm.LastHandshakeRel.Minutes() < 3.
|
||||
pVm := PeerVM{
|
||||
PublicKey: devices[i].Peers[j].PublicKey.String(),
|
||||
ReceivedBytes: devices[i].Peers[j].ReceiveBytes,
|
||||
TransmitBytes: devices[i].Peers[j].TransmitBytes,
|
||||
LastHandshakeTime: devices[i].Peers[j].LastHandshakeTime,
|
||||
LastHandshakeRel: time.Since(devices[i].Peers[j].LastHandshakeTime),
|
||||
AllocatedIP: allocatedIPs,
|
||||
Endpoint: devices[i].Peers[j].Endpoint.String(),
|
||||
}
|
||||
pVm.Connected = pVm.LastHandshakeRel.Minutes() < 3.
|
||||
|
||||
if _client, ok := m[pVm.PublicKey]; ok {
|
||||
pVm.Name = _client.Name
|
||||
pVm.Email = _client.Email
|
||||
if _client, ok := m[pVm.PublicKey]; ok {
|
||||
pVm.Name = _client.Name
|
||||
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
|
||||
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)
|
||||
|
@ -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 {
|
||||
return func(c echo.Context) error {
|
||||
|
||||
|
|
34
main.go
34
main.go
|
@ -30,6 +30,7 @@ var (
|
|||
flagBindAddress string = "0.0.0.0:5000"
|
||||
flagSmtpHostname string = "127.0.0.1"
|
||||
flagSmtpPort int = 25
|
||||
flagHelloHostName string = "localhost"
|
||||
flagSmtpUsername string
|
||||
flagSmtpPassword string
|
||||
flagSmtpAuthType string = "NONE"
|
||||
|
@ -41,14 +42,18 @@ var (
|
|||
flagSessionSecret string = util.RandomString(32)
|
||||
flagWgConfTemplate string
|
||||
flagBasePath string
|
||||
flagBrandText string = "WireGuard UI"
|
||||
flagAccentColor string = "#343a40"
|
||||
flagPageTitlePrefix string
|
||||
)
|
||||
|
||||
const (
|
||||
defaultEmailSubject = "Your wireguard configuration"
|
||||
defaultEmailContent = `Hi,</br>
|
||||
<p>In this email you can find your personal configuration for our wireguard server.</p>
|
||||
defaultEmailSubject = "Your VPN configuration"
|
||||
|
||||
<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(&flagSmtpHostname, "smtp-hostname", util.LookupEnvOrString("SMTP_HOSTNAME", flagSmtpHostname), "SMTP Hostname")
|
||||
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(&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.")
|
||||
|
@ -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(&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(&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()
|
||||
|
||||
// update runtime config
|
||||
|
@ -87,6 +97,7 @@ func init() {
|
|||
util.BindAddress = flagBindAddress
|
||||
util.SmtpHostname = flagSmtpHostname
|
||||
util.SmtpPort = flagSmtpPort
|
||||
util.HelloHostName = flagHelloHostName
|
||||
util.SmtpUsername = flagSmtpUsername
|
||||
util.SmtpPassword = flagSmtpPassword
|
||||
util.SmtpAuthType = flagSmtpAuthType
|
||||
|
@ -98,16 +109,19 @@ func init() {
|
|||
util.SessionSecret = []byte(flagSessionSecret)
|
||||
util.WgConfTemplate = flagWgConfTemplate
|
||||
util.BasePath = util.ParseBasePath(flagBasePath)
|
||||
|
||||
util.BrandText = flagBrandText
|
||||
util.AccentColor = flagAccentColor
|
||||
util.PageTitlePrefix = flagPageTitlePrefix
|
||||
|
||||
// print only if log level is INFO or lower
|
||||
if lvl, _ := util.ParseLogLevel(util.LookupEnvOrString(util.LogLevel, "INFO")); lvl <= log.INFO {
|
||||
// print app information
|
||||
fmt.Println("Wireguard UI")
|
||||
fmt.Println("WireGuard UI")
|
||||
fmt.Println("App Version\t:", appVersion)
|
||||
fmt.Println("Git Commit\t:", gitCommit)
|
||||
fmt.Println("Git Ref\t\t:", gitRef)
|
||||
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("Bind address\t:", util.BindAddress)
|
||||
//fmt.Println("Sendgrid key\t:", util.SendgridApiKey)
|
||||
|
@ -133,6 +147,9 @@ func main() {
|
|||
extraData["gitCommit"] = gitCommit
|
||||
extraData["basePath"] = util.BasePath
|
||||
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.
|
||||
// "base.html" instead of "templates/base.html")
|
||||
|
@ -163,13 +180,14 @@ func main() {
|
|||
if util.SendgridApiKey != "" {
|
||||
sendmail = emailer.NewSendgridApiMail(util.SendgridApiKey, util.EmailFromName, util.EmailFrom)
|
||||
} 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+"/about", handler.AboutPage())
|
||||
app.GET(util.BasePath+"/_health", handler.Health())
|
||||
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+"/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)
|
||||
|
|
|
@ -15,6 +15,7 @@ type Client struct {
|
|||
AllocatedIPs []string `json:"allocated_ips"`
|
||||
AllowedIPs []string `json:"allowed_ips"`
|
||||
ExtraAllowedIPs []string `json:"extra_allowed_ips"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
UseServerDNS bool `json:"use_server_dns"`
|
||||
Enabled bool `json:"enabled"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "wireguard-ui",
|
||||
"version": "1.0.0",
|
||||
"description": "Wireguard web interface",
|
||||
"description": "WireGuard web interface",
|
||||
"main": "index.js",
|
||||
"repository": "git@github.com:ngoduykhanh/wireguard-ui.git",
|
||||
"author": "Khanh Ngo <k@ndk.name>",
|
||||
|
|
|
@ -68,7 +68,10 @@ func (o *JsonDB) Init() error {
|
|||
serverInterface.PostDown = util.LookupEnvOrString(util.ServerPostDownScriptEnvVar, "")
|
||||
serverInterface.UpdatedAt = time.Now().UTC()
|
||||
o.conn.Write("server", "interfaces", serverInterface)
|
||||
os.Chmod(serverInterfacePath, 0600)
|
||||
err := util.ManagePerms(serverInterfacePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// server's key pair
|
||||
|
@ -83,7 +86,10 @@ func (o *JsonDB) Init() error {
|
|||
serverKeyPair.PublicKey = key.PublicKey().String()
|
||||
serverKeyPair.UpdatedAt = time.Now().UTC()
|
||||
o.conn.Write("server", "keypair", serverKeyPair)
|
||||
os.Chmod(serverKeyPairPath, 0600)
|
||||
err = util.ManagePerms(serverKeyPairPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// global settings
|
||||
|
@ -108,7 +114,10 @@ func (o *JsonDB) Init() error {
|
|||
globalSetting.ConfigFilePath = util.LookupEnvOrString(util.ConfigFilePathEnvVar, util.DefaultConfigFilePath)
|
||||
globalSetting.UpdatedAt = time.Now().UTC()
|
||||
o.conn.Write("server", "global_settings", globalSetting)
|
||||
os.Chmod(globalSettingPath, 0600)
|
||||
err := util.ManagePerms(globalSettingPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// hashes
|
||||
|
@ -117,7 +126,10 @@ func (o *JsonDB) Init() error {
|
|||
clientServerHashes.Client = "none"
|
||||
clientServerHashes.Server = "none"
|
||||
o.conn.Write("server", "hashes", clientServerHashes)
|
||||
os.Chmod(hashesPath, 0600)
|
||||
err := util.ManagePerms(hashesPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// user info
|
||||
|
@ -136,7 +148,10 @@ func (o *JsonDB) Init() error {
|
|||
user.PasswordHash = hash
|
||||
}
|
||||
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
|
||||
|
@ -182,7 +197,10 @@ func (o *JsonDB) GetUserByName(username string) (model.User, error) {
|
|||
func (o *JsonDB) SaveUser(user model.User) error {
|
||||
userPath := path.Join(path.Join(o.dbPath, "users"), user.Username+".json")
|
||||
output := o.conn.Write("users", user.Username, user)
|
||||
os.Chmod(userPath, 0600)
|
||||
err := util.ManagePerms(userPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
|
@ -295,7 +313,10 @@ func (o *JsonDB) GetClientByID(clientID string, qrCodeSettings model.QRCodeSetti
|
|||
func (o *JsonDB) SaveClient(client model.Client) error {
|
||||
clientPath := path.Join(path.Join(o.dbPath, "clients"), client.ID+".json")
|
||||
output := o.conn.Write("clients", client.ID, client)
|
||||
os.Chmod(clientPath, 0600)
|
||||
err := util.ManagePerms(clientPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
|
@ -306,21 +327,30 @@ func (o *JsonDB) DeleteClient(clientID string) error {
|
|||
func (o *JsonDB) SaveServerInterface(serverInterface model.ServerInterface) error {
|
||||
serverInterfacePath := path.Join(path.Join(o.dbPath, "server"), "interfaces.json")
|
||||
output := o.conn.Write("server", "interfaces", serverInterface)
|
||||
os.Chmod(serverInterfacePath, 0600)
|
||||
err := util.ManagePerms(serverInterfacePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func (o *JsonDB) SaveServerKeyPair(serverKeyPair model.ServerKeypair) error {
|
||||
serverKeyPairPath := path.Join(path.Join(o.dbPath, "server"), "keypair.json")
|
||||
output := o.conn.Write("server", "keypair", serverKeyPair)
|
||||
os.Chmod(serverKeyPairPath, 0600)
|
||||
err := util.ManagePerms(serverKeyPairPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func (o *JsonDB) SaveGlobalSettings(globalSettings model.GlobalSetting) error {
|
||||
globalSettingsPath := path.Join(path.Join(o.dbPath, "server"), "global_settings.json")
|
||||
output := o.conn.Write("server", "global_settings", globalSettings)
|
||||
os.Chmod(globalSettingsPath, 0600)
|
||||
err := util.ManagePerms(globalSettingsPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
|
@ -336,6 +366,9 @@ func (o *JsonDB) GetHashes() (model.ClientServerHashes, error) {
|
|||
func (o *JsonDB) SaveHashes(hashes model.ClientServerHashes) error {
|
||||
hashesPath := path.Join(path.Join(o.dbPath, "server"), "hashes.json")
|
||||
output := o.conn.Write("server", "hashes", hashes)
|
||||
os.Chmod(hashesPath, 0600)
|
||||
err := util.ManagePerms(hashesPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return output
|
||||
}
|
||||
}
|
|
@ -3,10 +3,10 @@ package jsondb
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/ngoduykhanh/wireguard-ui/model"
|
||||
"github.com/ngoduykhanh/wireguard-ui/util"
|
||||
)
|
||||
|
||||
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")
|
||||
output := o.conn.Write(model.WakeOnLanHostCollectionName, resourceName, host)
|
||||
os.Chmod(wakeOnLanHostPath, 0600)
|
||||
err = util.ManagePerms(wakeOnLanHostPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return output
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ About
|
|||
<div class="col-md-6">
|
||||
<div class="card card-success">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">About Wireguard-UI</h3>
|
||||
<h3 class="card-title">About WireGuard-UI</h3>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
<div class="card-body">
|
||||
|
@ -63,7 +63,7 @@ About
|
|||
</div>
|
||||
<strong>Copyright ©
|
||||
<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.
|
||||
|
||||
</div>
|
||||
|
@ -83,7 +83,7 @@ About
|
|||
$.ajax({
|
||||
cache: false,
|
||||
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',
|
||||
contentType: "application/json",
|
||||
success: function (data) {
|
||||
|
@ -99,7 +99,7 @@ About
|
|||
$.ajax({
|
||||
cache: false,
|
||||
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',
|
||||
contentType: "application/json",
|
||||
success: function (data) {
|
||||
|
@ -121,7 +121,7 @@ About
|
|||
$.ajax({
|
||||
cache: false,
|
||||
method: 'GET',
|
||||
url: 'https://api.github.com/repos/ngoduykhanh/wireguard-ui/contributors',
|
||||
url: 'https://api.github.com/repos/idressos/wireguard-ui/contributors',
|
||||
dataType: 'json',
|
||||
contentType: "application/json",
|
||||
success: function (data) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<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 -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Favicon -->
|
||||
|
@ -84,10 +84,10 @@
|
|||
<!-- /.navbar -->
|
||||
|
||||
<!-- 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 -->
|
||||
<a href="{{.basePath}}" class="brand-link">
|
||||
<span class="brand-text"> WIREGUARD UI</span>
|
||||
<span class="brand-text"> {{.brandText}}</span>
|
||||
</a>
|
||||
|
||||
<!-- Sidebar -->
|
||||
|
@ -120,7 +120,7 @@
|
|||
<a href="{{.basePath}}/" class="nav-link {{if eq .baseData.Active ""}}active{{end}}">
|
||||
<i class="nav-icon fas fa-user-secret"></i>
|
||||
<p>
|
||||
Wireguard Clients
|
||||
Clients
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
|
@ -130,7 +130,7 @@
|
|||
<a href="{{.basePath}}/wg-server" class="nav-link {{if eq .baseData.Active "wg-server" }}active{{end}}">
|
||||
<i class="nav-icon fas fa-server"></i>
|
||||
<p>
|
||||
Wireguard Server
|
||||
WireGuard Server
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
|
@ -174,6 +174,8 @@
|
|||
</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{{if .baseData.Admin}}
|
||||
<li class="nav-header">ABOUT</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{.basePath}}/about" class="nav-link {{if eq .baseData.Active "about" }}active{{end}}">
|
||||
|
@ -183,6 +185,7 @@
|
|||
</p>
|
||||
</a>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</nav>
|
||||
<!-- /.sidebar-menu -->
|
||||
|
@ -194,7 +197,7 @@
|
|||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<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">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
|
@ -232,6 +235,10 @@
|
|||
</label>
|
||||
<input type="text" data-role="tagsinput" class="form-control" id="client_extra_allowed_ips" value="{{ StringsJoin .client_defaults.ExtraAllowedIps "," }}">
|
||||
</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="icheck-primary d-inline">
|
||||
<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">
|
||||
<b>Version</b> {{ .appVersion }}
|
||||
</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.
|
||||
</footer>
|
||||
-->
|
||||
|
@ -413,6 +420,7 @@
|
|||
const email = $("#client_email").val();
|
||||
const allocated_ips = $("#client_allocated_ips").val().split(",");
|
||||
const allowed_ips = $("#client_allowed_ips").val().split(",");
|
||||
const endpoint = $("#client_endpoint").val();
|
||||
let use_server_dns = false;
|
||||
let extra_allowed_ips = [];
|
||||
|
||||
|
@ -434,7 +442,7 @@
|
|||
const preshared_key = $("#client_preshared_key").val();
|
||||
|
||||
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};
|
||||
|
||||
$.ajax({
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{define "title"}}
|
||||
Wireguard Clients
|
||||
Clients
|
||||
{{end}}
|
||||
|
||||
{{define "top_css"}}
|
||||
|
@ -17,13 +17,13 @@ Wireguard Clients
|
|||
{{end}}
|
||||
|
||||
{{define "page_title"}}
|
||||
Wireguard Clients
|
||||
Clients
|
||||
{{end}}
|
||||
|
||||
{{define "page_content"}}
|
||||
<section class="content">
|
||||
<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>
|
||||
<!-- /.row -->
|
||||
|
@ -113,6 +113,10 @@ Wireguard Clients
|
|||
<input type="text" data-role="tagsinput" class="form-control"
|
||||
id="_client_extra_allowed_ips">
|
||||
</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="icheck-primary d-inline">
|
||||
<input type="checkbox" id="_use_server_dns">
|
||||
|
@ -477,6 +481,8 @@ Wireguard Clients
|
|||
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("#_enabled").prop("checked", client.enabled);
|
||||
|
||||
|
@ -564,6 +570,8 @@ Wireguard Clients
|
|||
extra_allowed_ips = $("#_client_extra_allowed_ips").val().split(",");
|
||||
}
|
||||
|
||||
const endpoint = $("#_client_endpoint").val();
|
||||
|
||||
if ($("#_use_server_dns").is(':checked')){
|
||||
use_server_dns = true;
|
||||
}
|
||||
|
@ -575,7 +583,8 @@ Wireguard Clients
|
|||
}
|
||||
|
||||
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({
|
||||
cache: false,
|
||||
|
|
|
@ -22,7 +22,7 @@ Global Settings
|
|||
<div class="col-md-6">
|
||||
<div class="card card-success">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Wireguard Global Settings</h3>
|
||||
<h3 class="card-title">WireGuard Global Settings</h3>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
<!-- form start -->
|
||||
|
@ -68,7 +68,7 @@ Global Settings
|
|||
value="{{ .globalSettings.Table }}">
|
||||
</div>
|
||||
<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"
|
||||
name="config_file_path" placeholder="E.g. /etc/wireguard/wg0.conf"
|
||||
value="{{ .globalSettings.ConfigFilePath }}">
|
||||
|
@ -92,7 +92,7 @@ Global Settings
|
|||
<div class="card-body">
|
||||
<dl>
|
||||
<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>
|
||||
<dt>2. DNS Servers</dt>
|
||||
<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>
|
||||
<dt>6. Table</dt>
|
||||
<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>
|
||||
<dd>The path of your Wireguard server config file. Please make sure the parent directory
|
||||
<dt>7. WireGuard Config File Path</dt>
|
||||
<dd>The path of your WireGuard server config file. Please make sure the parent directory
|
||||
exists and is writable.</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
@ -195,7 +195,7 @@ Global Settings
|
|||
}
|
||||
</script>
|
||||
<script>
|
||||
// Wireguard Interface DNS server tag input
|
||||
// WireGuard Interface DNS server tag input
|
||||
$("#dns_servers").tagsInput({
|
||||
'width': '100%',
|
||||
'height': '75%',
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<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 -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Favicon -->
|
||||
|
@ -24,8 +24,8 @@
|
|||
|
||||
<body class="hold-transition login-page">
|
||||
<div class="login-box">
|
||||
<div class="login-logo">
|
||||
<a href="https://github.com/ngoduykhanh/wireguard-ui">WireGuard UI</a>
|
||||
<div class="login-logo pb-3">
|
||||
<img class="img-fluid" src="{{.basePath}}/logo">
|
||||
</div>
|
||||
<!-- /.login-logo -->
|
||||
<div class="card">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{define "title"}}
|
||||
Wireguard Server
|
||||
WireGuard Server
|
||||
{{end}}
|
||||
|
||||
{{define "top_css"}}
|
||||
|
@ -10,13 +10,13 @@ Wireguard Server
|
|||
{{end}}
|
||||
|
||||
{{define "page_title"}}
|
||||
Wireguard Server Settings
|
||||
WireGuard Server Settings
|
||||
{{end}}
|
||||
|
||||
{{define "page_content"}}
|
||||
<section class="content">
|
||||
<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">
|
||||
<!-- left column -->
|
||||
<div class="col-md-6">
|
||||
|
@ -39,13 +39,13 @@ Wireguard Server Settings
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label for="post_up">Post Up Script</label>
|
||||
<input type="text" class="form-control" id="post_up" name="post_up"
|
||||
placeholder="Post Up Script" value="{{ .serverInterface.PostUp }}">
|
||||
<textarea class="form-control" id="post_up" name="post_up"
|
||||
placeholder="Post Up Script">{{ .serverInterface.PostUp }}</textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="post_down">Post Down Script</label>
|
||||
<input type="text" class="form-control" id="post_down" name="post_down"
|
||||
placeholder="Post Down Script" value="{{ .serverInterface.PostDown }}">
|
||||
<textarea class="form-control" id="post_down" name="post_down"
|
||||
placeholder="Post Down Script">{{ .serverInterface.PostDown }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
|
@ -109,7 +109,7 @@ Wireguard Server Settings
|
|||
</button>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<div class="modal-footer justify-content-between">
|
||||
|
@ -142,7 +142,7 @@ Wireguard Server Settings
|
|||
data: JSON.stringify(data),
|
||||
success: function(data) {
|
||||
$("#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) {
|
||||
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
||||
|
@ -152,7 +152,7 @@ Wireguard Server Settings
|
|||
}
|
||||
</script>
|
||||
<script>
|
||||
// Wireguard Interface Addresses tag input
|
||||
// WireGuard Interface Addresses tag input
|
||||
$("#addresses").tagsInput({
|
||||
'width': '100%',
|
||||
// 'height': '75%',
|
||||
|
@ -169,7 +169,7 @@ Wireguard Server Settings
|
|||
$("#addresses").addTag('{{.}}');
|
||||
{{end}}
|
||||
|
||||
// Wireguard Interface Addresses form validation
|
||||
// WireGuard Interface Addresses form validation
|
||||
$(document).ready(function () {
|
||||
$.validator.setDefaults({
|
||||
submitHandler: function () {
|
||||
|
@ -205,7 +205,7 @@ Wireguard Server Settings
|
|||
});
|
||||
});
|
||||
|
||||
// Wireguard Key Pair generation confirmation button
|
||||
// WireGuard Key Pair generation confirmation button
|
||||
$(document).ready(function () {
|
||||
$("#btn_generate_confirm").click(function () {
|
||||
$.ajax({
|
||||
|
|
|
@ -35,7 +35,6 @@ Connected Peers
|
|||
{{ end}}
|
||||
{{ range $dev := .devices }}
|
||||
<table class="table table-sm">
|
||||
<caption>List of connected peers for device with name {{ $dev.Name }} </caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<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.
|
||||
|
||||
# Address updated at: {{ .serverConfig.Interface.UpdatedAt }}
|
||||
|
@ -7,10 +7,11 @@
|
|||
Address = {{$first :=true}}{{range .serverConfig.Interface.Addresses }}{{if $first}}{{$first = false}}{{else}},{{end}}{{.}}{{end}}
|
||||
ListenPort = {{ .serverConfig.Interface.ListenPort }}
|
||||
PrivateKey = {{ .serverConfig.KeyPair.PrivateKey }}
|
||||
{{if .globalSettings.FirewallMark }}FwMark = {{ .globalSettings.FirewallMark }}{{end}}
|
||||
{{if .globalSettings.MTU}}MTU = {{ .globalSettings.MTU }}{{end}}
|
||||
PostUp = {{ .serverConfig.Interface.PostUp }}
|
||||
PostDown = {{ .serverConfig.Interface.PostDown }}
|
||||
Table = {{ .globalSettings.Table }}
|
||||
{{if .serverConfig.Interface.PostUp }}PostUp = {{ .serverConfig.Interface.PostUp }}{{end}}
|
||||
{{if .serverConfig.Interface.PostDown }}PostDown = {{ .serverConfig.Interface.PostDown }}{{end}}
|
||||
{{if .globalSettings.Table}}Table = {{ .globalSettings.Table }}{{end}}
|
||||
|
||||
{{range .clientDataList}}{{if eq .Client.Enabled true}}
|
||||
# ID: {{ .Client.ID }}
|
||||
|
@ -20,6 +21,8 @@ Table = {{ .globalSettings.Table }}
|
|||
# Update at: {{ .Client.UpdatedAt }}
|
||||
[Peer]
|
||||
PublicKey = {{ .Client.PublicKey }}
|
||||
{{if .Client.PresharedKey }}PresharedKey = {{ .Client.PresharedKey }}
|
||||
{{end}}AllowedIPs = {{$first :=true}}{{range .Client.AllocatedIPs }}{{if $first}}{{$first = false}}{{else}},{{end}}{{.}}{{end}}{{range .Client.ExtraAllowedIPs }},{{.}}{{end}}
|
||||
{{end}}{{end}}
|
||||
{{if .Client.PresharedKey }}PresharedKey = {{ .Client.PresharedKey }}{{end}}
|
||||
AllowedIPs = {{$first :=true}}{{range .Client.AllocatedIPs }}{{if $first}}{{$first = false}}{{else}},{{end}}{{.}}{{end}}{{range .Client.ExtraAllowedIPs }},{{.}}{{end}}{{end}}
|
||||
{{if $.globalSettings.PersistentKeepalive}}PersistentKeepalive = {{ $.globalSettings.PersistentKeepalive }}{{end}}
|
||||
{{if .Client.Endpoint }}Endpoint = {{ .Client.Endpoint }}{{end}}
|
||||
{{end}}
|
|
@ -10,6 +10,7 @@ var (
|
|||
SmtpPort int
|
||||
SmtpUsername string
|
||||
SmtpPassword string
|
||||
HelloHostName string
|
||||
SmtpNoTLSCheck bool
|
||||
SmtpEncryption string
|
||||
SmtpAuthType string
|
||||
|
@ -19,6 +20,9 @@ var (
|
|||
SessionSecret []byte
|
||||
WgConfTemplate string
|
||||
BasePath string
|
||||
BrandText string
|
||||
AccentColor string
|
||||
PageTitlePrefix string
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -53,6 +57,10 @@ const (
|
|||
DefaultClientExtraAllowedIpsEnvVar = "WGUI_DEFAULT_CLIENT_EXTRA_ALLOWED_IPS"
|
||||
DefaultClientUseServerDNSEnvVar = "WGUI_DEFAULT_CLIENT_USE_SERVER_DNS"
|
||||
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 {
|
||||
|
|
12
util/util.go
12
util/util.go
|
@ -4,8 +4,6 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ngoduykhanh/wireguard-ui/store"
|
||||
"golang.org/x/mod/sumdb/dirhash"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
|
@ -19,6 +17,9 @@ import (
|
|||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/ngoduykhanh/wireguard-ui/store"
|
||||
"golang.org/x/mod/sumdb/dirhash"
|
||||
|
||||
externalip "github.com/glendc/go-external-ip"
|
||||
"github.com/labstack/gommon/log"
|
||||
"github.com/ngoduykhanh/wireguard-ui/model"
|
||||
|
@ -382,7 +383,7 @@ func ValidateIPAllocation(serverAddresses []string, ipAllocatedList []string, ip
|
|||
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 {
|
||||
var tmplWireguardConf string
|
||||
|
||||
|
@ -540,3 +541,8 @@ func RandomString(length int) string {
|
|||
}
|
||||
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