Merge branch 'master' into master
This commit is contained in:
		
						commit
						b6375edc98
					
				
							
								
								
									
										59
									
								
								README.md
								
								
								
								
							
							
						
						
									
										59
									
								
								README.md
								
								
								
								
							|  | @ -36,33 +36,38 @@ docker-compose up | |||
| 
 | ||||
| ## Environment Variables | ||||
| 
 | ||||
| | Variable                    | Description                                                                                                                                                  | Default                            | | ||||
| |-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------| | ||||
| | `BASE_PATH`                 | Set this variable if you run wireguard-ui under a subpath of your reverse proxy virtual host (e.g. /wireguard))                                              | N/A                                | | ||||
| | `BIND_ADDRESS`              | The addresses that can access to the web interface and the port, use unix:///abspath/to/file.socket for unix domain socket.                                  | 0.0.0.0:80                         | | ||||
| | `SESSION_SECRET`            | The secret key used to encrypt the session cookies. Set this to a random value                                                                               | N/A                                | | ||||
| | `WGUI_USERNAME`             | The username for the login page. Used for db initialization only                                                                                             | `admin`                            | | ||||
| | `WGUI_PASSWORD`             | The password for the user on the login page. Will be hashed automatically. Used for db initialization only                                                   | `admin`                            | | ||||
| | `WGUI_PASSWORD_HASH`        | The password hash for the user on the login page. (alternative to `WGUI_PASSWORD`). Used for db initialization only                                          | N/A                                | | ||||
| | `WGUI_ENDPOINT_ADDRESS`     | The default endpoint address used in global settings where clients should connect to                                                                         | Resolved to your public ip address | | ||||
| | `WGUI_FAVICON_FILE_PATH`    | The file path used as website favicon                                                                                                                        | Embedded WireGuard logo            | | ||||
| | `WGUI_DNS`                  | The default DNS servers (comma-separated-list) used in the global settings                                                                                   | `1.1.1.1`                          | | ||||
| | `WGUI_MTU`                  | The default MTU used in global settings                                                                                                                      | `1450`                             | | ||||
| | `WGUI_PERSISTENT_KEEPALIVE` | The default persistent keepalive for WireGuard in global settings                                                                                            | `15`                               | | ||||
| | `WGUI_FIREWALL_MARK`        | The default WireGuard firewall mark                                                                                                                          | `0xca6c`  (51820)                  | | ||||
| | `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                                | | ||||
| | `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                                | | ||||
| | `SMTP_HOSTNAME`             | The SMTP IP address or hostname                                                                                                                              | `127.0.0.1`                        | | ||||
| | `SMTP_PORT`                 | The SMTP port                                                                                                                                                | `25`                               | | ||||
| | `SMTP_USERNAME`             | The SMTP username                                                                                                                                            | N/A                                | | ||||
| | `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`                         | | ||||
| | Variable                    | Description                                                                                                                                                                 | Default                            | | ||||
| |-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------| | ||||
| | `BASE_PATH`                 | Set this variable if you run wireguard-ui under a subpath of your reverse proxy virtual host (e.g. /wireguard)                                                              | N/A                                | | ||||
| | `BIND_ADDRESS`              | The addresses that can access to the web interface and the port, use unix:///abspath/to/file.socket for unix domain socket.                                                 | 0.0.0.0:80                         | | ||||
| | `SESSION_SECRET`            | The secret key used to encrypt the session cookies. Set this to a random value                                                                                              | N/A                                | | ||||
| | `SESSION_SECRET_FILE`       | Optional filepath for the secret key used to encrypt the session cookies. Leave `SESSION_SECRET` blank to take effect                                                       | N/A                                | | ||||
| | `WGUI_USERNAME`             | The username for the login page. Used for db initialization only                                                                                                            | `admin`                            | | ||||
| | `WGUI_PASSWORD`             | The password for the user on the login page. Will be hashed automatically. Used for db initialization only                                                                  | `admin`                            | | ||||
| | `WGUI_PASSWORD_FILE`        | Optional filepath for the user login password. Will be hashed automatically. Used for db initialization only. Leave `WGUI_PASSWORD` blank to take effect                    | N/A                                | | ||||
| | `WGUI_PASSWORD_HASH`        | The password hash for the user on the login page. (alternative to `WGUI_PASSWORD`). Used for db initialization only                                                         | N/A                                | | ||||
| | `WGUI_PASSWORD_HASH_FILE`   | Optional filepath for the user login password hash. (alternative to `WGUI_PASSWORD_FILE`). Used for db initialization only. Leave `WGUI_PASSWORD_HASH` blank to take effect | N/A                                | | ||||
| | `WGUI_ENDPOINT_ADDRESS`     | The default endpoint address used in global settings where clients should connect to                                                                                        | Resolved to your public ip address | | ||||
| | `WGUI_FAVICON_FILE_PATH`    | The file path used as website favicon                                                                                                                                       | Embedded WireGuard logo            | | ||||
| | `WGUI_DNS`                  | The default DNS servers (comma-separated-list) used in the global settings                                                                                                  | `1.1.1.1`                          | | ||||
| | `WGUI_MTU`                  | The default MTU used in global settings                                                                                                                                     | `1450`                             | | ||||
| | `WGUI_PERSISTENT_KEEPALIVE` | The default persistent keepalive for WireGuard in global settings                                                                                                           | `15`                               | | ||||
| | `WGUI_FIREWALL_MARK`        | The default WireGuard firewall mark                                                                                                                                         | `0xca6c`  (51820)                  | | ||||
| | `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                                | | ||||
| | `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                                | | ||||
| | `SENDGRID_API_KEY_FILE`     | Optional filepath for the SendGrid api key. Leave `SENDGRID_API_KEY` blank to take effect                                                                                   | N/A                                | | ||||
| | `SMTP_HOSTNAME`             | The SMTP IP address or hostname                                                                                                                                             | `127.0.0.1`                        | | ||||
| | `SMTP_PORT`                 | The SMTP port                                                                                                                                                               | `25`                               | | ||||
| | `SMTP_USERNAME`             | The SMTP username                                                                                                                                                           | N/A                                | | ||||
| | `SMTP_PASSWORD`             | The SMTP user password                                                                                                                                                      | N/A                                | | ||||
| | `SMTP_PASSWORD_FILE`        | Optional filepath for the SMTP user password. Leave `SMTP_PASSWORD` blank to take effect                                                                                    | 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`                         | | ||||
| 
 | ||||
| ### Defaults for server configuration | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ import ( | |||
| 	"io/fs" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | @ -26,6 +27,8 @@ import ( | |||
| 	"github.com/ngoduykhanh/wireguard-ui/util" | ||||
| ) | ||||
| 
 | ||||
| var usernameRegexp = regexp.MustCompile("^\\w[\\w\\-.]*$") | ||||
| 
 | ||||
| // Health check handler
 | ||||
| func Health() echo.HandlerFunc { | ||||
| 	return func(c echo.Context) error { | ||||
|  | @ -63,6 +66,10 @@ func Login(db store.IStore) echo.HandlerFunc { | |||
| 		password := data["password"].(string) | ||||
| 		rememberMe := data["rememberMe"].(bool) | ||||
| 
 | ||||
| 		if !usernameRegexp.MatchString(username) { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid username"}) | ||||
| 		} | ||||
| 
 | ||||
| 		dbuser, err := db.GetUserByName(username) | ||||
| 		if err != nil { | ||||
| 			return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot query user from DB"}) | ||||
|  | @ -135,9 +142,12 @@ func GetUsers(db store.IStore) echo.HandlerFunc { | |||
| // GetUser handler returns a JSON object of single user
 | ||||
| func GetUser(db store.IStore) echo.HandlerFunc { | ||||
| 	return func(c echo.Context) error { | ||||
| 
 | ||||
| 		username := c.Param("username") | ||||
| 
 | ||||
| 		if !usernameRegexp.MatchString(username) { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid username"}) | ||||
| 		} | ||||
| 
 | ||||
| 		if !isAdmin(c) && (username != currentUser(c)) { | ||||
| 			return c.JSON(http.StatusForbidden, jsonHTTPResponse{false, "Manager cannot access other user data"}) | ||||
| 		} | ||||
|  | @ -200,12 +210,16 @@ func UpdateUser(db store.IStore) echo.HandlerFunc { | |||
| 			admin = false | ||||
| 		} | ||||
| 
 | ||||
| 		if !usernameRegexp.MatchString(previousUsername) { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid username"}) | ||||
| 		} | ||||
| 
 | ||||
| 		user, err := db.GetUserByName(previousUsername) | ||||
| 		if err != nil { | ||||
| 			return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, err.Error()}) | ||||
| 		} | ||||
| 
 | ||||
| 		if username == "" { | ||||
| 		if username == "" || !usernameRegexp.MatchString(username) { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid username"}) | ||||
| 		} else { | ||||
| 			user.Username = username | ||||
|  | @ -261,7 +275,7 @@ func CreateUser(db store.IStore) echo.HandlerFunc { | |||
| 		password := data["password"].(string) | ||||
| 		admin := data["admin"].(bool) | ||||
| 
 | ||||
| 		if username == "" { | ||||
| 		if username == "" || !usernameRegexp.MatchString(username) { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid username"}) | ||||
| 		} else { | ||||
| 			user.Username = username | ||||
|  | @ -303,6 +317,10 @@ func RemoveUser(db store.IStore) echo.HandlerFunc { | |||
| 
 | ||||
| 		username := data["username"].(string) | ||||
| 
 | ||||
| 		if !usernameRegexp.MatchString(username) { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid username"}) | ||||
| 		} | ||||
| 
 | ||||
| 		if username == currentUser(c) { | ||||
| 			return c.JSON(http.StatusForbidden, jsonHTTPResponse{false, "User cannot delete itself"}) | ||||
| 		} | ||||
|  | @ -357,6 +375,11 @@ func GetClient(db store.IStore) echo.HandlerFunc { | |||
| 	return func(c echo.Context) error { | ||||
| 
 | ||||
| 		clientID := c.Param("id") | ||||
| 
 | ||||
| 		if _, err := xid.FromString(clientID); err != nil { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid client ID"}) | ||||
| 		} | ||||
| 
 | ||||
| 		qrCodeSettings := model.QRCodeSettings{ | ||||
| 			Enabled:       true, | ||||
| 			IncludeDNS:    true, | ||||
|  | @ -485,6 +508,10 @@ func EmailClient(db store.IStore, mailer emailer.Emailer, emailSubject, emailCon | |||
| 		c.Bind(&payload) | ||||
| 		// TODO validate email
 | ||||
| 
 | ||||
| 		if _, err := xid.FromString(payload.ID); err != nil { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid client ID"}) | ||||
| 		} | ||||
| 
 | ||||
| 		qrCodeSettings := model.QRCodeSettings{ | ||||
| 			Enabled:       true, | ||||
| 			IncludeDNS:    true, | ||||
|  | @ -536,6 +563,10 @@ func UpdateClient(db store.IStore) echo.HandlerFunc { | |||
| 		var _client model.Client | ||||
| 		c.Bind(&_client) | ||||
| 
 | ||||
| 		if _, err := xid.FromString(_client.ID); err != nil { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid client ID"}) | ||||
| 		} | ||||
| 
 | ||||
| 		// validate client existence
 | ||||
| 		clientData, err := db.GetClientByID(_client.ID, model.QRCodeSettings{Enabled: false}) | ||||
| 		if err != nil { | ||||
|  | @ -614,6 +645,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() | ||||
|  | @ -642,6 +674,10 @@ func SetClientStatus(db store.IStore) echo.HandlerFunc { | |||
| 		clientID := data["id"].(string) | ||||
| 		status := data["status"].(bool) | ||||
| 
 | ||||
| 		if _, err := xid.FromString(clientID); err != nil { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid client ID"}) | ||||
| 		} | ||||
| 
 | ||||
| 		clientData, err := db.GetClientByID(clientID, model.QRCodeSettings{Enabled: false}) | ||||
| 		if err != nil { | ||||
| 			return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, err.Error()}) | ||||
|  | @ -667,6 +703,10 @@ func DownloadClient(db store.IStore) echo.HandlerFunc { | |||
| 			return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Missing clientid parameter"}) | ||||
| 		} | ||||
| 
 | ||||
| 		if _, err := xid.FromString(clientID); err != nil { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid client ID"}) | ||||
| 		} | ||||
| 
 | ||||
| 		clientData, err := db.GetClientByID(clientID, model.QRCodeSettings{Enabled: false}) | ||||
| 		if err != nil { | ||||
| 			log.Errorf("Cannot generate client id %s config file for downloading: %v", clientID, err) | ||||
|  | @ -689,7 +729,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) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -700,6 +740,10 @@ func RemoveClient(db store.IStore) echo.HandlerFunc { | |||
| 		client := new(model.Client) | ||||
| 		c.Bind(client) | ||||
| 
 | ||||
| 		if _, err := xid.FromString(client.ID); err != nil { | ||||
| 			return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid client ID"}) | ||||
| 		} | ||||
| 
 | ||||
| 		// delete client from database
 | ||||
| 
 | ||||
| 		if err := db.DeleteClient(client.ID); err != nil { | ||||
|  |  | |||
							
								
								
									
										50
									
								
								main.go
								
								
								
								
							
							
						
						
									
										50
									
								
								main.go
								
								
								
								
							|  | @ -4,9 +4,6 @@ import ( | |||
| 	"embed" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"github.com/labstack/echo/v4" | ||||
| 	"github.com/labstack/gommon/log" | ||||
| 	"github.com/ngoduykhanh/wireguard-ui/store" | ||||
| 	"io/fs" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
|  | @ -15,6 +12,10 @@ import ( | |||
| 	"net" | ||||
| 	"syscall" | ||||
| 
 | ||||
| 	"github.com/labstack/echo/v4" | ||||
| 	"github.com/labstack/gommon/log" | ||||
| 	"github.com/ngoduykhanh/wireguard-ui/store" | ||||
| 
 | ||||
| 	"github.com/ngoduykhanh/wireguard-ui/emailer" | ||||
| 	"github.com/ngoduykhanh/wireguard-ui/handler" | ||||
| 	"github.com/ngoduykhanh/wireguard-ui/router" | ||||
|  | @ -73,16 +74,41 @@ func init() { | |||
| 	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(&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.") | ||||
| 	flag.StringVar(&flagSmtpEncryption, "smtp-encryption", util.LookupEnvOrString("SMTP_ENCRYPTION", flagSmtpEncryption), "SMTP Encryption : NONE, SSL, SSLTLS, TLS or STARTTLS (by default)") | ||||
| 	flag.StringVar(&flagSmtpAuthType, "smtp-auth-type", util.LookupEnvOrString("SMTP_AUTH_TYPE", flagSmtpAuthType), "SMTP Auth Type : PLAIN, LOGIN or NONE.") | ||||
| 	flag.StringVar(&flagSendgridApiKey, "sendgrid-api-key", util.LookupEnvOrString("SENDGRID_API_KEY", flagSendgridApiKey), "Your sendgrid api key.") | ||||
| 	flag.StringVar(&flagEmailFrom, "email-from", util.LookupEnvOrString("EMAIL_FROM_ADDRESS", flagEmailFrom), "'From' email address.") | ||||
| 	flag.StringVar(&flagEmailFromName, "email-from-name", util.LookupEnvOrString("EMAIL_FROM_NAME", flagEmailFromName), "'From' email name.") | ||||
| 	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") | ||||
| 
 | ||||
| 	var ( | ||||
| 		smtpPasswordLookup  = util.LookupEnvOrString("SMTP_PASSWORD", flagSmtpPassword) | ||||
| 		sengridApiKeyLookup = util.LookupEnvOrString("SENDGRID_API_KEY", flagSendgridApiKey) | ||||
| 		sessionSecretLookup = util.LookupEnvOrString("SESSION_SECRET", flagSessionSecret) | ||||
| 	) | ||||
| 
 | ||||
| 	// check empty smtpPassword env var
 | ||||
| 	if smtpPasswordLookup != "" { | ||||
| 		flag.StringVar(&flagSmtpPassword, "smtp-password", smtpPasswordLookup, "SMTP Password") | ||||
| 	} else { | ||||
| 		flag.StringVar(&flagSmtpPassword, "smtp-password", util.LookupEnvOrFile("SMTP_PASSWORD_FILE", flagSmtpPassword), "SMTP Password File") | ||||
| 	} | ||||
| 
 | ||||
| 	// check empty sengridApiKey env var
 | ||||
| 	if sengridApiKeyLookup != "" { | ||||
| 		flag.StringVar(&flagSendgridApiKey, "sendgrid-api-key", sengridApiKeyLookup, "Your sendgrid api key.") | ||||
| 	} else { | ||||
| 		flag.StringVar(&flagSendgridApiKey, "sendgrid-api-key", util.LookupEnvOrFile("SENDGRID_API_KEY_FILE", flagSendgridApiKey), "File containing your sendgrid api key.") | ||||
| 	} | ||||
| 
 | ||||
| 	// check empty sessionSecret env var
 | ||||
| 	if sessionSecretLookup != "" { | ||||
| 		flag.StringVar(&flagSessionSecret, "session-secret", sessionSecretLookup, "The key used to encrypt session cookies.") | ||||
| 	} else { | ||||
| 		flag.StringVar(&flagSessionSecret, "session-secret", util.LookupEnvOrFile("SESSION_SECRET_FILE", flagSessionSecret), "File containing the key used to encrypt session cookies.") | ||||
| 	} | ||||
| 
 | ||||
| 	flag.Parse() | ||||
| 
 | ||||
| 	// update runtime config
 | ||||
|  | @ -149,15 +175,19 @@ func main() { | |||
| 
 | ||||
| 	app.GET(util.BasePath, handler.WireGuardClients(db), handler.ValidSession) | ||||
| 
 | ||||
| 	// Important: Make sure that all non-GET routes check the request content type using handler.ContentTypeJson to
 | ||||
| 	// mitigate CSRF attacks. This is effective, because browsers don't allow setting the Content-Type header on
 | ||||
| 	// cross-origin requests.
 | ||||
| 
 | ||||
| 	if !util.DisableLogin { | ||||
| 		app.GET(util.BasePath+"/login", handler.LoginPage()) | ||||
| 		app.POST(util.BasePath+"/login", handler.Login(db)) | ||||
| 		app.POST(util.BasePath+"/login", handler.Login(db), handler.ContentTypeJson) | ||||
| 		app.GET(util.BasePath+"/logout", handler.Logout(), handler.ValidSession) | ||||
| 		app.GET(util.BasePath+"/profile", handler.LoadProfile(db), handler.ValidSession) | ||||
| 		app.GET(util.BasePath+"/users-settings", handler.UsersSettings(db), handler.ValidSession, handler.NeedsAdmin) | ||||
| 		app.POST(util.BasePath+"/update-user", handler.UpdateUser(db), handler.ValidSession) | ||||
| 		app.POST(util.BasePath+"/create-user", handler.CreateUser(db), handler.ValidSession, handler.NeedsAdmin) | ||||
| 		app.POST(util.BasePath+"/remove-user", handler.RemoveUser(db), handler.ValidSession, handler.NeedsAdmin) | ||||
| 		app.POST(util.BasePath+"/update-user", handler.UpdateUser(db), handler.ValidSession, handler.ContentTypeJson) | ||||
| 		app.POST(util.BasePath+"/create-user", handler.CreateUser(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin) | ||||
| 		app.POST(util.BasePath+"/remove-user", handler.RemoveUser(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin) | ||||
| 		app.GET(util.BasePath+"/getusers", handler.GetUsers(db), handler.ValidSession, handler.NeedsAdmin) | ||||
| 		app.GET(util.BasePath+"/api/user/:username", handler.GetUser(db), handler.ValidSession) | ||||
| 	} | ||||
|  |  | |||
|  | @ -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"` | ||||
|  |  | |||
|  | @ -23,5 +23,6 @@ type ServerInterface struct { | |||
| 	ListenPort int       `json:"listen_port,string"` // ,string to get listen_port string input as int
 | ||||
| 	UpdatedAt  time.Time `json:"updated_at"` | ||||
| 	PostUp     string    `json:"post_up"` | ||||
| 	PreDown    string    `json:"pre_down"` | ||||
| 	PostDown   string    `json:"post_down"` | ||||
| } | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ package model | |||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"net" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | @ -18,7 +19,13 @@ func (host WakeOnLanHost) ResolveResourceName() (string, error) { | |||
| 		return "", errors.New("mac Address is Empty") | ||||
| 	} | ||||
| 	resourceName = strings.ToUpper(resourceName) | ||||
| 	return strings.ReplaceAll(resourceName, ":", "-"), nil | ||||
| 	resourceName = strings.ReplaceAll(resourceName, ":", "-") | ||||
| 
 | ||||
| 	if _, err := net.ParseMAC(resourceName); err != nil { | ||||
| 		return "", errors.New("invalid mac address") | ||||
| 	} | ||||
| 
 | ||||
| 	return resourceName, nil | ||||
| } | ||||
| 
 | ||||
| const WakeOnLanHostCollectionName = "wake_on_lan_hosts" | ||||
|  |  | |||
|  | @ -38,12 +38,12 @@ func New(dbPath string) (*JsonDB, error) { | |||
| func (o *JsonDB) Init() error { | ||||
| 	var clientPath string = path.Join(o.dbPath, "clients") | ||||
| 	var serverPath string = path.Join(o.dbPath, "server") | ||||
| 	var userPath string = path.Join(o.dbPath, "users") | ||||
| 	var wakeOnLanHostsPath string = path.Join(o.dbPath, "wake_on_lan_hosts") | ||||
| 	var serverInterfacePath string = path.Join(serverPath, "interfaces.json") | ||||
| 	var serverKeyPairPath string = path.Join(serverPath, "keypair.json") | ||||
| 	var globalSettingPath string = path.Join(serverPath, "global_settings.json") | ||||
| 	var hashesPath string = path.Join(serverPath, "hashes.json") | ||||
| 	var userPath string = path.Join(serverPath, "users.json") | ||||
| 
 | ||||
| 	// create directories if they do not exist
 | ||||
| 	if _, err := os.Stat(clientPath); os.IsNotExist(err) { | ||||
|  | @ -52,12 +52,12 @@ func (o *JsonDB) Init() error { | |||
| 	if _, err := os.Stat(serverPath); os.IsNotExist(err) { | ||||
| 		os.MkdirAll(serverPath, os.ModePerm) | ||||
| 	} | ||||
| 	if _, err := os.Stat(wakeOnLanHostsPath); os.IsNotExist(err) { | ||||
| 		os.MkdirAll(wakeOnLanHostsPath, os.ModePerm) | ||||
| 	} | ||||
| 	if _, err := os.Stat(userPath); os.IsNotExist(err) { | ||||
| 		os.MkdirAll(userPath, os.ModePerm) | ||||
| 	} | ||||
| 	if _, err := os.Stat(wakeOnLanHostsPath); os.IsNotExist(err) { | ||||
| 		os.MkdirAll(wakeOnLanHostsPath, os.ModePerm) | ||||
| 	} | ||||
| 
 | ||||
| 	// server's interface
 | ||||
| 	if _, err := os.Stat(serverInterfacePath); os.IsNotExist(err) { | ||||
|  | @ -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
 | ||||
|  | @ -128,26 +140,30 @@ func (o *JsonDB) Init() error { | |||
| 		user.Admin = util.DefaultIsAdmin | ||||
| 		user.PasswordHash = util.LookupEnvOrString(util.PasswordHashEnvVar, "") | ||||
| 		if user.PasswordHash == "" { | ||||
| 			plaintext := util.LookupEnvOrString(util.PasswordEnvVar, util.DefaultPassword) | ||||
| 			hash, err := util.HashPassword(plaintext) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			user.PasswordHash = util.LookupEnvOrFile(util.PasswordHashFileEnvVar, "") | ||||
| 			if user.PasswordHash == "" { | ||||
| 				plaintext := util.LookupEnvOrString(util.PasswordEnvVar, util.DefaultPassword) | ||||
| 				if plaintext == util.DefaultPassword { | ||||
| 					plaintext = util.LookupEnvOrFile(util.PasswordFileEnvVar, util.DefaultPassword) | ||||
| 				} | ||||
| 				hash, err := util.HashPassword(plaintext) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				user.PasswordHash = hash | ||||
| 			} | ||||
| 			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 | ||||
| } | ||||
| 
 | ||||
| // GetUser func to query user info from the database
 | ||||
| func (o *JsonDB) GetUser() (model.User, error) { | ||||
| 	user := model.User{} | ||||
| 	return user, o.conn.Read("server", "users", &user) | ||||
| } | ||||
| 
 | ||||
| // GetUsers func to get all users from the database
 | ||||
| func (o *JsonDB) GetUsers() ([]model.User, error) { | ||||
| 	var users []model.User | ||||
|  | @ -182,7 +198,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 +314,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 +328,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 +367,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 | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -232,6 +232,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 }}> | ||||
|  | @ -413,6 +417,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 +439,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({ | ||||
|  | @ -492,6 +497,7 @@ | |||
|             'defaultText': 'Add More', | ||||
|             'removeWithBackspace': true, | ||||
|             'minChars': 0, | ||||
|             'minInputWidth': '100%', | ||||
|             'placeholderColor': '#666666' | ||||
|         }); | ||||
| 
 | ||||
|  | @ -503,6 +509,7 @@ | |||
|             'defaultText': 'Add More', | ||||
|             'removeWithBackspace': true, | ||||
|             'minChars': 0, | ||||
|             'minInputWidth': '100%', | ||||
|             'placeholderColor': '#666666' | ||||
|         }); | ||||
| 
 | ||||
|  | @ -513,6 +520,7 @@ | |||
|             'defaultText': 'Add More', | ||||
|             'removeWithBackspace': true, | ||||
|             'minChars': 0, | ||||
|             'minInputWidth': '100%', | ||||
|             'placeholderColor': '#666666' | ||||
|         }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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"> | ||||
|  | @ -423,6 +427,7 @@ Wireguard Clients | |||
|                     'defaultText': 'Add More', | ||||
|                     'removeWithBackspace': true, | ||||
|                     'minChars': 0, | ||||
|                     'minInputWidth': '100%', | ||||
|                     'placeholderColor': '#666666' | ||||
|                 }); | ||||
| 
 | ||||
|  | @ -434,6 +439,7 @@ Wireguard Clients | |||
|                     'defaultText': 'Add More', | ||||
|                     'removeWithBackspace': true, | ||||
|                     'minChars': 0, | ||||
|                     'minInputWidth': '100%', | ||||
|                     'placeholderColor': '#666666' | ||||
|                 }); | ||||
| 
 | ||||
|  | @ -444,6 +450,7 @@ Wireguard Clients | |||
|                     'defaultText': 'Add More', | ||||
|                     'removeWithBackspace' : true, | ||||
|                     'minChars': 0, | ||||
|                     'minInputWidth': '100%', | ||||
|                     'placeholderColor': '#666666' | ||||
|                 }) | ||||
| 
 | ||||
|  | @ -477,6 +484,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 +573,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 +586,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, | ||||
|  |  | |||
|  | @ -203,6 +203,7 @@ Global Settings | |||
|             'defaultText': 'Add More', | ||||
|             'removeWithBackspace': true, | ||||
|             'minChars': 0, | ||||
|             'minInputWidth': '100%', | ||||
|             'placeholderColor': '#666666' | ||||
|         }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,6 +42,12 @@ Wireguard Server Settings | |||
|                                 <input type="text" class="form-control" id="post_up" name="post_up" | ||||
|                                        placeholder="Post Up Script" value="{{ .serverInterface.PostUp }}"> | ||||
|                             </div> | ||||
|                             <div class="form-group"> | ||||
|                                 <label for="pre_down">Pre Down Script</label> | ||||
|                                 <input type="text" class="form-control" id="pre_down" name="pre_down" | ||||
|                                        placeholder="Pre Down Script" value="{{ .serverInterface.PreDown }}"> | ||||
|                             </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" | ||||
|  | @ -130,8 +136,9 @@ Wireguard Server Settings | |||
|             const addresses = $("#addresses").val().split(","); | ||||
|             const listen_port = $("#listen_port").val(); | ||||
|             const post_up = $("#post_up").val(); | ||||
|             const pre_down = $("#pre_down").val(); | ||||
|             const post_down = $("#post_down").val(); | ||||
|             const data = {"addresses": addresses, "listen_port": listen_port, "post_up": post_up, "post_down": post_down}; | ||||
|             const data = {"addresses": addresses, "listen_port": listen_port, "post_up": post_up, "pre_down": pre_down, "post_down": post_down}; | ||||
| 
 | ||||
|             $.ajax({ | ||||
|                 cache: false, | ||||
|  | @ -160,6 +167,7 @@ Wireguard Server Settings | |||
|             'defaultText': 'Add More', | ||||
|             'removeWithBackspace': true, | ||||
|             'minChars': 0, | ||||
|             'minInputWidth': '100%', | ||||
|             'placeholderColor': '#666666' | ||||
|         }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ ListenPort = {{ .serverConfig.Interface.ListenPort }} | |||
| PrivateKey = {{ .serverConfig.KeyPair.PrivateKey }} | ||||
| {{if .globalSettings.MTU}}MTU = {{ .globalSettings.MTU }}{{end}} | ||||
| PostUp = {{ .serverConfig.Interface.PostUp }} | ||||
| PreDown = {{ .serverConfig.Interface.PreDown }} | ||||
| PostDown = {{ .serverConfig.Interface.PostDown }} | ||||
| Table = {{ .globalSettings.Table }} | ||||
| 
 | ||||
|  | @ -20,6 +21,7 @@ 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 .Client.Endpoint }}Endpoint = {{ .Client.Endpoint }}{{end}} | ||||
| {{end}} | ||||
|  |  | |||
|  | @ -30,12 +30,14 @@ const ( | |||
| 	DefaultDNS                             = "1.1.1.1" | ||||
| 	DefaultMTU                             = 1450 | ||||
| 	DefaultPersistentKeepalive             = 15 | ||||
| 	DefaultFirewallMark                    = "0xca6c"  // i.e. 51820
 | ||||
| 	DefaultFirewallMark                    = "0xca6c" // i.e. 51820
 | ||||
| 	DefaultTable                           = "auto" | ||||
| 	DefaultConfigFilePath                  = "/etc/wireguard/wg0.conf" | ||||
| 	UsernameEnvVar                         = "WGUI_USERNAME" | ||||
| 	PasswordEnvVar                         = "WGUI_PASSWORD" | ||||
| 	PasswordFileEnvVar                     = "WGUI_PASSWORD_FILE" | ||||
| 	PasswordHashEnvVar                     = "WGUI_PASSWORD_HASH" | ||||
| 	PasswordHashFileEnvVar                 = "WGUI_PASSWORD_HASH_FILE" | ||||
| 	FaviconFilePathEnvVar                  = "WGUI_FAVICON_FILE_PATH" | ||||
| 	EndpointAddressEnvVar                  = "WGUI_ENDPOINT_ADDRESS" | ||||
| 	DNSEnvVar                              = "WGUI_DNS" | ||||
|  |  | |||
							
								
								
									
										25
									
								
								util/util.go
								
								
								
								
							
							
						
						
									
										25
									
								
								util/util.go
								
								
								
								
							|  | @ -1,11 +1,10 @@ | |||
| package util | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/ngoduykhanh/wireguard-ui/store" | ||||
| 	"golang.org/x/mod/sumdb/dirhash" | ||||
| 	"io" | ||||
| 	"io/fs" | ||||
| 	"io/ioutil" | ||||
|  | @ -19,6 +18,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" | ||||
|  | @ -466,6 +468,20 @@ func LookupEnvOrStrings(key string, defaultVal []string) []string { | |||
| 	return defaultVal | ||||
| } | ||||
| 
 | ||||
| func LookupEnvOrFile(key string, defaultVal string) string { | ||||
| 	if val, ok := os.LookupEnv(key); ok { | ||||
| 		if file, err := os.Open(val); err == nil { | ||||
| 			var content string | ||||
| 			scanner := bufio.NewScanner(file) | ||||
| 			for scanner.Scan() { | ||||
| 				content += scanner.Text() | ||||
| 			} | ||||
| 			return content | ||||
| 		} | ||||
| 	} | ||||
| 	return defaultVal | ||||
| } | ||||
| 
 | ||||
| func StringFromEmbedFile(embed fs.FS, filename string) (string, error) { | ||||
| 	file, err := embed.Open(filename) | ||||
| 	if err != nil { | ||||
|  | @ -540,3 +556,8 @@ func RandomString(length int) string { | |||
| 	} | ||||
| 	return string(b) | ||||
| } | ||||
| 
 | ||||
| func ManagePerms(path string) error { | ||||
| 	err := os.Chmod(path, 0600) | ||||
| 	return err | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue