Add environment variables for configuration
This commit is contained in:
		
							parent
							
								
									87b08a8f7c
								
							
						
					
					
						commit
						7088065a2d
					
				
							
								
								
									
										34
									
								
								README.md
								
								
								
								
							
							
						
						
									
										34
									
								
								README.md
								
								
								
								
							| 
						 | 
					@ -30,8 +30,40 @@ wireguard interface stats. See the `cap_add` and `network_mode` options on the d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Environment Variables
 | 
					### Environment Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Variable                    | Description                                                                                         |
 | 
				
			||||||
 | 
					|-----------------------------|-----------------------------------------------------------------------------------------------------|
 | 
				
			||||||
 | 
					| `SESSION_SECRET`            | Used to encrypt the session cookies. Set this to a random value.                                    |
 | 
				
			||||||
 | 
					| `WGUI_USERNAME`             | The username for the login page. (default `admin`)                                                  |
 | 
				
			||||||
 | 
					| `WGUI_PASSWORD`             | The password for the user on the login page. (default `admin`)                                      |
 | 
				
			||||||
 | 
					| `WGUI_DNS`                  | The default DNS servers (comma-separated-list) used in the global settings. (default `1.1.1.1`)     |
 | 
				
			||||||
 | 
					| `WGUI_MTU`                  | The default MTU used in global settings. (default `1450`)                                           |
 | 
				
			||||||
 | 
					| `WGUI_PERSISTENT_KEEPALIVE` | The default persistent keepalive for WireGuard in global settings. (default `15`)                   |
 | 
				
			||||||
 | 
					| `WGUI_FORWARD_MARK`         | The default WireGuard forward mark. (default `0xca6c`)                                              |
 | 
				
			||||||
 | 
					| `WGUI_CONFIG_FILE_PATH`     | The default WireGuard config file path used in global settings. (default `/etc/wireguard/wg0.conf`) |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Set the `SESSION_SECRET` environment variable to a random value.
 | 
					#### Defaults for server configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These environment variables are used to control the default server settings used when initializing the database.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Variable                          | Description                                                                                                              |
 | 
				
			||||||
 | 
					|-----------------------------------|--------------------------------------------------------------------------------------------------------------------------|
 | 
				
			||||||
 | 
					| `WGUI_SERVER_INTERFACE_ADDRESSES` | The default interface addresses (comma-separated-list) for the WireGuard server configuration. (default `10.252.1.0/24`) |
 | 
				
			||||||
 | 
					| `WGUI_SERVER_LISTEN_PORT`         | The default server listen port. (default `51820`)                                                                        |
 | 
				
			||||||
 | 
					| `WGUI_SERVER_POST_UP_SCRIPT`      | The default server post-up script.                                                                                       |
 | 
				
			||||||
 | 
					| `WGUI_SERVER_POST_DOWN_SCRIPT`    | The default server post-down script.                                                                                     |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Defaults for new clients
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These environment variables are used to set the defaults used in `New Client` dialog.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Variable                                    | Description                                                                                                      |
 | 
				
			||||||
 | 
					|---------------------------------------------|------------------------------------------------------------------------------------------------------------------|
 | 
				
			||||||
 | 
					| `WGUI_DEFAULT_CLIENT_ALLOWED_IPS`           | Comma-separated-list of CIDRs for the `Allowed IPs` field. (default `0.0.0.0/0`)                                 |
 | 
				
			||||||
 | 
					| `WGUI_DEFAULT_CLIENT_EXTRA_ALLOWED_IPS`     | Comma-separated-list of CIDRs for the `Extra Allowed IPs` field. (default empty)                                 |
 | 
				
			||||||
 | 
					| `WGUI_DEFAULT_CLIENT_USE_SERVER_DNS`        | Boolean value [`0`, `f`, `F`, `false`, `False`, `FALSE`, `1`, `t`, `T`, `true`, `True`, `TRUE`] (default `true`) |
 | 
				
			||||||
 | 
					| `WGUI_DEFAULT_CLIENT_ENABLE_AFTER_CREATION` | Boolean value [`0`, `f`, `F`, `false`, `False`, `FALSE`, `1`, `t`, `T`, `true`, `True`, `TRUE`] (default `true`) |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Email configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To use custom `wg.conf` template set the `WG_CONF_TEMPLATE` environment variable to a path to such file. Make sure `wireguard-ui` will be able to work with it - use [default template](templates/wg.conf) for reference.
 | 
					To use custom `wg.conf` template set the `WG_CONF_TEMPLATE` environment variable to a path to such file. Make sure `wireguard-ui` will be able to work with it - use [default template](templates/wg.conf) for reference.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					package model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Defaults for creation of new clients used in the templates
 | 
				
			||||||
 | 
					type ClientDefaults struct {
 | 
				
			||||||
 | 
						AllowedIps          []string
 | 
				
			||||||
 | 
						ExtraAllowedIps     []string
 | 
				
			||||||
 | 
						UseServerDNS        bool
 | 
				
			||||||
 | 
						EnableAfterCreation bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@ import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"text/template"
 | 
						"text/template"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rice "github.com/GeertJohan/go.rice"
 | 
						rice "github.com/GeertJohan/go.rice"
 | 
				
			||||||
| 
						 | 
					@ -12,6 +13,7 @@ import (
 | 
				
			||||||
	"github.com/labstack/echo/v4"
 | 
						"github.com/labstack/echo/v4"
 | 
				
			||||||
	"github.com/labstack/echo/v4/middleware"
 | 
						"github.com/labstack/echo/v4/middleware"
 | 
				
			||||||
	"github.com/labstack/gommon/log"
 | 
						"github.com/labstack/gommon/log"
 | 
				
			||||||
 | 
						"github.com/ngoduykhanh/wireguard-ui/util"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TemplateRegistry is a custom html/template renderer for Echo framework
 | 
					// TemplateRegistry is a custom html/template renderer for Echo framework
 | 
				
			||||||
| 
						 | 
					@ -33,6 +35,8 @@ func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c
 | 
				
			||||||
		for k, v := range t.extraData {
 | 
							for k, v := range t.extraData {
 | 
				
			||||||
			data.(map[string]interface{})[k] = v
 | 
								data.(map[string]interface{})[k] = v
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							data.(map[string]interface{})["client_defaults"] = util.ClientDefaultsFromEnv()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// login page does not need the base layout
 | 
						// login page does not need the base layout
 | 
				
			||||||
| 
						 | 
					@ -85,13 +89,16 @@ func New(tmplBox *rice.Box, extraData map[string]string, secret []byte) *echo.Ec
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// create template list
 | 
						// create template list
 | 
				
			||||||
 | 
						funcs := template.FuncMap{
 | 
				
			||||||
 | 
							"StringsJoin": strings.Join,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	templates := make(map[string]*template.Template)
 | 
						templates := make(map[string]*template.Template)
 | 
				
			||||||
	templates["login.html"] = template.Must(template.New("login").Parse(tmplLoginString))
 | 
						templates["login.html"] = template.Must(template.New("login").Funcs(funcs).Parse(tmplLoginString))
 | 
				
			||||||
	templates["clients.html"] = template.Must(template.New("clients").Parse(tmplBaseString + tmplClientsString))
 | 
						templates["clients.html"] = template.Must(template.New("clients").Funcs(funcs).Parse(tmplBaseString + tmplClientsString))
 | 
				
			||||||
	templates["server.html"] = template.Must(template.New("server").Parse(tmplBaseString + tmplServerString))
 | 
						templates["server.html"] = template.Must(template.New("server").Funcs(funcs).Parse(tmplBaseString + tmplServerString))
 | 
				
			||||||
	templates["global_settings.html"] = template.Must(template.New("global_settings").Parse(tmplBaseString + tmplGlobalSettingsString))
 | 
						templates["global_settings.html"] = template.Must(template.New("global_settings").Funcs(funcs).Parse(tmplBaseString + tmplGlobalSettingsString))
 | 
				
			||||||
	templates["status.html"] = template.Must(template.New("status").Parse(tmplBaseString + tmplStatusString))
 | 
						templates["status.html"] = template.Must(template.New("status").Funcs(funcs).Parse(tmplBaseString + tmplStatusString))
 | 
				
			||||||
	templates["wake_on_lan_hosts.html"] = template.Must(template.New("wake_on_lan_hosts").Parse(tmplBaseString + tmplWakeOnLanHostsString))
 | 
						templates["wake_on_lan_hosts.html"] = template.Must(template.New("wake_on_lan_hosts").Funcs(funcs).Parse(tmplBaseString + tmplWakeOnLanHostsString))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	e.Logger.SetLevel(log.DEBUG)
 | 
						e.Logger.SetLevel(log.DEBUG)
 | 
				
			||||||
	e.Pre(middleware.RemoveTrailingSlash())
 | 
						e.Pre(middleware.RemoveTrailingSlash())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,8 +57,10 @@ func (o *JsonDB) Init() error {
 | 
				
			||||||
	// server's interface
 | 
						// server's interface
 | 
				
			||||||
	if _, err := os.Stat(serverInterfacePath); os.IsNotExist(err) {
 | 
						if _, err := os.Stat(serverInterfacePath); os.IsNotExist(err) {
 | 
				
			||||||
		serverInterface := new(model.ServerInterface)
 | 
							serverInterface := new(model.ServerInterface)
 | 
				
			||||||
		serverInterface.Addresses = []string{util.DefaultServerAddress}
 | 
							serverInterface.Addresses = util.LookupEnvOrStrings(util.ServerAddressesEnvVar, []string{util.DefaultServerAddress})
 | 
				
			||||||
		serverInterface.ListenPort = util.DefaultServerPort
 | 
							serverInterface.ListenPort = util.LookupEnvOrInt(util.ServerListenPortEnvVar, util.DefaultServerPort)
 | 
				
			||||||
 | 
							serverInterface.PostUp = util.LookupEnvOrString(util.ServerPostUpScriptEnvVar, "")
 | 
				
			||||||
 | 
							serverInterface.PostDown = util.LookupEnvOrString(util.ServerPostDownScriptEnvVar, "")
 | 
				
			||||||
		serverInterface.UpdatedAt = time.Now().UTC()
 | 
							serverInterface.UpdatedAt = time.Now().UTC()
 | 
				
			||||||
		o.conn.Write("server", "interfaces", serverInterface)
 | 
							o.conn.Write("server", "interfaces", serverInterface)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -87,11 +89,11 @@ func (o *JsonDB) Init() error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		globalSetting := new(model.GlobalSetting)
 | 
							globalSetting := new(model.GlobalSetting)
 | 
				
			||||||
		globalSetting.EndpointAddress = publicInterface.IPAddress
 | 
							globalSetting.EndpointAddress = publicInterface.IPAddress
 | 
				
			||||||
		globalSetting.DNSServers = []string{util.DefaultDNS}
 | 
							globalSetting.DNSServers = util.LookupEnvOrStrings(util.DNSEnvVar, []string{util.DefaultDNS})
 | 
				
			||||||
		globalSetting.MTU = util.DefaultMTU
 | 
							globalSetting.MTU = util.LookupEnvOrInt(util.MTUEnvVar, util.DefaultMTU)
 | 
				
			||||||
		globalSetting.PersistentKeepalive = util.DefaultPersistentKeepalive
 | 
							globalSetting.PersistentKeepalive = util.LookupEnvOrInt(util.PersistentKeepaliveEnvVar, util.DefaultPersistentKeepalive)
 | 
				
			||||||
		globalSetting.ForwardMark = util.DefaultForwardMark
 | 
							globalSetting.ForwardMark = util.LookupEnvOrString(util.ForwardMarkEnvVar, util.DefaultForwardMark)
 | 
				
			||||||
		globalSetting.ConfigFilePath = util.DefaultConfigFilePath
 | 
							globalSetting.ConfigFilePath = util.LookupEnvOrString(util.ConfigFilePathEnvVar, util.DefaultConfigFilePath)
 | 
				
			||||||
		globalSetting.UpdatedAt = time.Now().UTC()
 | 
							globalSetting.UpdatedAt = time.Now().UTC()
 | 
				
			||||||
		o.conn.Write("server", "global_settings", globalSetting)
 | 
							o.conn.Write("server", "global_settings", globalSetting)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -99,8 +101,8 @@ func (o *JsonDB) Init() error {
 | 
				
			||||||
	// user info
 | 
						// user info
 | 
				
			||||||
	if _, err := os.Stat(userPath); os.IsNotExist(err) {
 | 
						if _, err := os.Stat(userPath); os.IsNotExist(err) {
 | 
				
			||||||
		user := new(model.User)
 | 
							user := new(model.User)
 | 
				
			||||||
		user.Username = util.GetCredVar(util.UsernameEnvVar, util.DefaultUsername)
 | 
							user.Username = util.LookupEnvOrString(util.UsernameEnvVar, util.DefaultUsername)
 | 
				
			||||||
		user.Password = util.GetCredVar(util.PasswordEnvVar, util.DefaultPassword)
 | 
							user.Password = util.LookupEnvOrString(util.PasswordEnvVar, util.DefaultPassword)
 | 
				
			||||||
		o.conn.Write("server", "users", user)
 | 
							o.conn.Write("server", "users", user)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -175,7 +175,7 @@
 | 
				
			||||||
                                    </i>
 | 
					                                    </i>
 | 
				
			||||||
                                </label>
 | 
					                                </label>
 | 
				
			||||||
                                <input type="text" data-role="tagsinput" class="form-control" id="client_allowed_ips"
 | 
					                                <input type="text" data-role="tagsinput" class="form-control" id="client_allowed_ips"
 | 
				
			||||||
                                    value="0.0.0.0/0">
 | 
					                                    value="{{ StringsJoin .client_defaults.AllowedIps "," }}">
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
                            <div class="form-group">
 | 
					                            <div class="form-group">
 | 
				
			||||||
                                <label for="client_extra_allowed_ips" class="control-label">Extra Allowed IPs
 | 
					                                <label for="client_extra_allowed_ips" class="control-label">Extra Allowed IPs
 | 
				
			||||||
| 
						 | 
					@ -184,11 +184,11 @@
 | 
				
			||||||
                                       client. These addresses will be included in 'AllowedIPs' of WG server config">
 | 
					                                       client. These addresses will be included in 'AllowedIPs' of WG server config">
 | 
				
			||||||
                                    </i>
 | 
					                                    </i>
 | 
				
			||||||
                                </label>
 | 
					                                </label>
 | 
				
			||||||
                                <input type="text" data-role="tagsinput" class="form-control" id="client_extra_allowed_ips">
 | 
					                                <input type="text" data-role="tagsinput" class="form-control" id="client_extra_allowed_ips" value="{{ StringsJoin .client_defaults.ExtraAllowedIps "," }}">
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
                            <div class="form-group">
 | 
					                            <div class="form-group">
 | 
				
			||||||
                                <div class="icheck-primary d-inline">
 | 
					                                <div class="icheck-primary d-inline">
 | 
				
			||||||
                                    <input type="checkbox" id="use_server_dns" checked>
 | 
					                                    <input type="checkbox" id="use_server_dns" {{ if .client_defaults.UseServerDNS }}checked{{ end }}>
 | 
				
			||||||
                                    <label for="use_server_dns">
 | 
					                                    <label for="use_server_dns">
 | 
				
			||||||
                                        Use server DNS
 | 
					                                        Use server DNS
 | 
				
			||||||
                                    </label>
 | 
					                                    </label>
 | 
				
			||||||
| 
						 | 
					@ -196,7 +196,7 @@
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
                            <div class="form-group">
 | 
					                            <div class="form-group">
 | 
				
			||||||
                                <div class="icheck-primary d-inline">
 | 
					                                <div class="icheck-primary d-inline">
 | 
				
			||||||
                                    <input type="checkbox" id="enabled" checked>
 | 
					                                    <input type="checkbox" id="enabled" {{ if .client_defaults.EnableAfterCreation }}checked{{ end }}>
 | 
				
			||||||
                                    <label for="enabled">
 | 
					                                    <label for="enabled">
 | 
				
			||||||
                                        Enable after creation
 | 
					                                        Enable after creation
 | 
				
			||||||
                                    </label>
 | 
					                                    </label>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,19 @@ const (
 | 
				
			||||||
	DefaultConfigFilePath                  = "/etc/wireguard/wg0.conf"
 | 
						DefaultConfigFilePath                  = "/etc/wireguard/wg0.conf"
 | 
				
			||||||
	UsernameEnvVar                         = "WGUI_USERNAME"
 | 
						UsernameEnvVar                         = "WGUI_USERNAME"
 | 
				
			||||||
	PasswordEnvVar                         = "WGUI_PASSWORD"
 | 
						PasswordEnvVar                         = "WGUI_PASSWORD"
 | 
				
			||||||
 | 
						DNSEnvVar                              = "WGUI_DNS"
 | 
				
			||||||
 | 
						MTUEnvVar                              = "WGUI_MTU"
 | 
				
			||||||
 | 
						PersistentKeepaliveEnvVar              = "WGUI_PERSISTENT_KEEPALIVE"
 | 
				
			||||||
 | 
						ForwardMarkEnvVar                      = "WGUI_FORWARD_MARK"
 | 
				
			||||||
 | 
						ConfigFilePathEnvVar                   = "WGUI_CONFIG_FILE_PATH"
 | 
				
			||||||
 | 
						ServerAddressesEnvVar                  = "WGUI_SERVER_INTERFACE_ADDRESSES"
 | 
				
			||||||
 | 
						ServerListenPortEnvVar                 = "WGUI_SERVER_LISTEN_PORT"
 | 
				
			||||||
 | 
						ServerPostUpScriptEnvVar               = "WGUI_SERVER_POST_UP_SCRIPT"
 | 
				
			||||||
 | 
						ServerPostDownScriptEnvVar             = "WGUI_SERVER_POST_DOWN_SCRIPT"
 | 
				
			||||||
 | 
						DefaultClientAllowedIpsEnvVar          = "WGUI_DEFAULT_CLIENT_ALLOWED_IPS"
 | 
				
			||||||
 | 
						DefaultClientExtraAllowedIpsEnvVar     = "WGUI_DEFAULT_CLIENT_EXTRA_ALLOWED_IPS"
 | 
				
			||||||
 | 
						DefaultClientUseServerDNSEnvVar        = "WGUI_DEFAULT_CLIENT_USE_SERVER_DNS"
 | 
				
			||||||
 | 
						DefaultClientEnableAfterCreationEnvVar = "WGUI_DEFAULT_CLIENT_ENABLE_AFTER_CREATION"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ParseBasePath(basePath string) string {
 | 
					func ParseBasePath(basePath string) string {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										20
									
								
								util/util.go
								
								
								
								
							
							
						
						
									
										20
									
								
								util/util.go
								
								
								
								
							| 
						 | 
					@ -77,6 +77,17 @@ func BuildClientConfig(client model.Client, server model.Server, setting model.G
 | 
				
			||||||
	return strConfig
 | 
						return strConfig
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Read the default values for creating a new client from the environment or use sane defaults
 | 
				
			||||||
 | 
					func ClientDefaultsFromEnv() model.ClientDefaults {
 | 
				
			||||||
 | 
						client_defaults := model.ClientDefaults{}
 | 
				
			||||||
 | 
						client_defaults.AllowedIps = LookupEnvOrStrings(DefaultClientAllowedIpsEnvVar, []string{"0.0.0.0/0"})
 | 
				
			||||||
 | 
						client_defaults.ExtraAllowedIps = LookupEnvOrStrings(DefaultClientExtraAllowedIpsEnvVar, []string{})
 | 
				
			||||||
 | 
						client_defaults.UseServerDNS = LookupEnvOrBool(DefaultClientUseServerDNSEnvVar, true)
 | 
				
			||||||
 | 
						client_defaults.EnableAfterCreation = LookupEnvOrBool(DefaultClientEnableAfterCreationEnvVar, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return client_defaults
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ValidateCIDR to validate a network CIDR
 | 
					// ValidateCIDR to validate a network CIDR
 | 
				
			||||||
func ValidateCIDR(cidr string) bool {
 | 
					func ValidateCIDR(cidr string) bool {
 | 
				
			||||||
	_, _, err := net.ParseCIDR(cidr)
 | 
						_, _, err := net.ParseCIDR(cidr)
 | 
				
			||||||
| 
						 | 
					@ -440,10 +451,9 @@ func LookupEnvOrInt(key string, defaultVal int) int {
 | 
				
			||||||
	return defaultVal
 | 
						return defaultVal
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetCredVar reads value from environment variable or returns fallback
 | 
					func LookupEnvOrStrings(key string, defaultVal []string) []string {
 | 
				
			||||||
func GetCredVar(key, fallback string) string {
 | 
						if val, ok := os.LookupEnv(key); ok {
 | 
				
			||||||
	if value, ok := os.LookupEnv(key); ok {
 | 
							return strings.Split(val, ",")
 | 
				
			||||||
		return value
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return fallback
 | 
						return defaultVal
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue