mirror of
https://github.com/h44z/wg-portal.git
synced 2025-10-06 16:36:18 +00:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
83271b5d34 | ||
|
cc50fcf8e6 | ||
|
5d4d06db81 | ||
|
e581b3a69f | ||
|
acb629f672 | ||
|
b5cb967e09 | ||
|
5a9918e00d |
@@ -109,7 +109,7 @@ For example: `CONFIG_FILE=/home/test/config.yml ./wg-portal-amd64`.
|
|||||||
The following configuration options are available:
|
The following configuration options are available:
|
||||||
|
|
||||||
| environment | yaml | yaml_parent | default_value | description |
|
| environment | yaml | yaml_parent | default_value | description |
|
||||||
|-----------------------|-------------------|-------------|-------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
|
|----------------------------|-------------------------|-------------|-------------------------------------------------|-------------------------------------------------------------------------------------------|
|
||||||
| LISTENING_ADDRESS | listeningAddress | core | :8123 | The address on which the web server is listening. Optional IP address and port, e.g.: 127.0.0.1:8080. |
|
| LISTENING_ADDRESS | listeningAddress | core | :8123 | The address on which the web server is listening. Optional IP address and port, e.g.: 127.0.0.1:8080. |
|
||||||
| EXTERNAL_URL | externalUrl | core | http://localhost:8123 | The external URL where the web server is reachable. This link is used in emails that are created by the WireGuard Portal. |
|
| EXTERNAL_URL | externalUrl | core | http://localhost:8123 | The external URL where the web server is reachable. This link is used in emails that are created by the WireGuard Portal. |
|
||||||
| WEBSITE_TITLE | title | core | WireGuard VPN | The website title. |
|
| WEBSITE_TITLE | title | core | WireGuard VPN | The website title. |
|
||||||
@@ -121,6 +121,7 @@ The following configuration options are available:
|
|||||||
| EDITABLE_KEYS | editableKeys | core | true | Allow to edit key-pairs in the UI. |
|
| EDITABLE_KEYS | editableKeys | core | true | Allow to edit key-pairs in the UI. |
|
||||||
| CREATE_DEFAULT_PEER | createDefaultPeer | core | false | If an LDAP user logs in for the first time, a new WireGuard peer will be created on the WG_DEFAULT_DEVICE if this option is enabled. |
|
| CREATE_DEFAULT_PEER | createDefaultPeer | core | false | If an LDAP user logs in for the first time, a new WireGuard peer will be created on the WG_DEFAULT_DEVICE if this option is enabled. |
|
||||||
| SELF_PROVISIONING | selfProvisioning | core | false | Allow registered users to automatically create peers via the RESTful API. |
|
| SELF_PROVISIONING | selfProvisioning | core | false | Allow registered users to automatically create peers via the RESTful API. |
|
||||||
|
| WG_EXPORTER_FRIENDLY_NAMES | wgExporterFriendlyNames | core | false | Enable integration with [prometheus_wireguard_exporter friendly name](https://github.com/MindFlavor/prometheus_wireguard_exporter#friendly-tags). |
|
||||||
| LDAP_ENABLED | ldapEnabled | core | false | Enable or disable the LDAP backend. |
|
| LDAP_ENABLED | ldapEnabled | core | false | Enable or disable the LDAP backend. |
|
||||||
| SESSION_SECRET | sessionSecret | core | secret | Use a custom secret to encrypt session data. |
|
| SESSION_SECRET | sessionSecret | core | secret | Use a custom secret to encrypt session data. |
|
||||||
| DATABASE_TYPE | typ | database | sqlite | Either mysql or sqlite. |
|
| DATABASE_TYPE | typ | database | sqlite | Either mysql or sqlite. |
|
||||||
@@ -155,6 +156,9 @@ The following configuration options are available:
|
|||||||
| LDAP_ATTR_LASTNAME | attrLastname | ldap | sn | User lastname attribute. |
|
| LDAP_ATTR_LASTNAME | attrLastname | ldap | sn | User lastname attribute. |
|
||||||
| LDAP_ATTR_PHONE | attrPhone | ldap | telephoneNumber | User phone number attribute. |
|
| LDAP_ATTR_PHONE | attrPhone | ldap | telephoneNumber | User phone number attribute. |
|
||||||
| LDAP_ATTR_GROUPS | attrGroups | ldap | memberOf | User groups attribute. |
|
| LDAP_ATTR_GROUPS | attrGroups | ldap | memberOf | User groups attribute. |
|
||||||
|
| LDAP_CERT_CONN | ldapCertConn | ldap | false | Allow connection with certificate against LDAP server without user/password |
|
||||||
|
| LDAPTLS_CERT | ldapTlsCert | ldap | | The LDAP cert's path |
|
||||||
|
| LDAPTLS_KEY | ldapTlsKey | ldap | | The LDAP key's path |
|
||||||
| LOG_LEVEL | | | debug | Specify log level, one of: trace, debug, info, off. |
|
| LOG_LEVEL | | | debug | Specify log level, one of: trace, debug, info, off. |
|
||||||
| LOG_JSON | | | false | Format log output as JSON. |
|
| LOG_JSON | | | false | Format log output as JSON. |
|
||||||
| LOG_COLOR | | | true | Colorize log output. |
|
| LOG_COLOR | | | true | Colorize log output. |
|
||||||
|
@@ -76,6 +76,11 @@
|
|||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Save</button>
|
<button type="submit" class="btn btn-primary">Save</button>
|
||||||
<a href="/admin/users/" class="btn btn-secondary">Cancel</a>
|
<a href="/admin/users/" class="btn btn-secondary">Cancel</a>
|
||||||
|
{{if eq $.Session.IsAdmin true}}
|
||||||
|
{{if eq .User.Source "db"}}
|
||||||
|
<a href="/admin/users/delete?pkey={{.User.Email}}" data-toggle="confirmation" data-title="Really delete user and associated peers?" title="Delete user and associated peers" class="btn btn-danger float-right">Delete</a>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{{template "prt_footer.html" .}}
|
{{template "prt_footer.html" .}}
|
||||||
|
@@ -4,6 +4,10 @@ services:
|
|||||||
image: h44z/wg-portal:1.0.6
|
image: h44z/wg-portal:1.0.6
|
||||||
container_name: wg-portal
|
container_name: wg-portal
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
logging:
|
||||||
|
options:
|
||||||
|
max-size: "10m"
|
||||||
|
max-file: "3"
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
@@ -2,6 +2,7 @@ package ldap
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -154,23 +155,49 @@ func (provider Provider) GetUserModel(ctx *authentication.AuthContext) (*authent
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (provider Provider) open() (*ldap.Conn, error) {
|
func (provider Provider) open() (*ldap.Conn, error) {
|
||||||
tlsConfig := &tls.Config{InsecureSkipVerify: !provider.config.CertValidation}
|
var tlsConfig *tls.Config
|
||||||
|
|
||||||
|
if provider.config.LdapCertConn {
|
||||||
|
|
||||||
|
cert_plain, err := ioutil.ReadFile(provider.config.LdapTlsCert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to load the certificate")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := ioutil.ReadFile(provider.config.LdapTlsKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to load the key")
|
||||||
|
}
|
||||||
|
|
||||||
|
cert_x509, err := tls.X509KeyPair(cert_plain, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed X509")
|
||||||
|
|
||||||
|
}
|
||||||
|
tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert_x509}}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
tlsConfig = &tls.Config{InsecureSkipVerify: !provider.config.CertValidation}
|
||||||
|
}
|
||||||
|
|
||||||
conn, err := ldap.DialURL(provider.config.URL, ldap.DialWithTLSConfig(tlsConfig))
|
conn, err := ldap.DialURL(provider.config.URL, ldap.DialWithTLSConfig(tlsConfig))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.WithMessage(err, "failed to connect to LDAP")
|
||||||
}
|
}
|
||||||
|
|
||||||
if provider.config.StartTLS {
|
if provider.config.StartTLS {
|
||||||
// Reconnect with TLS
|
// Reconnect with TLS
|
||||||
err = conn.StartTLS(tlsConfig)
|
err = conn.StartTLS(tlsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.WithMessage(err, "failed to start TLS session")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = conn.Bind(provider.config.BindUser, provider.config.BindPass)
|
err = conn.Bind(provider.config.BindUser, provider.config.BindPass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.WithMessage(err, "failed to bind user")
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
|
@@ -4,7 +4,6 @@ import (
|
|||||||
gldap "github.com/go-ldap/ldap/v3"
|
gldap "github.com/go-ldap/ldap/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type Type string
|
type Type string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -30,4 +29,7 @@ type Config struct {
|
|||||||
SyncFilter string `yaml:"syncFilter" envconfig:"LDAP_SYNC_FILTER"`
|
SyncFilter string `yaml:"syncFilter" envconfig:"LDAP_SYNC_FILTER"`
|
||||||
AdminLdapGroup string `yaml:"adminGroup" envconfig:"LDAP_ADMIN_GROUP"` // Members of this group receive admin rights in WG-Portal
|
AdminLdapGroup string `yaml:"adminGroup" envconfig:"LDAP_ADMIN_GROUP"` // Members of this group receive admin rights in WG-Portal
|
||||||
AdminLdapGroup_ *gldap.DN `yaml:"-"`
|
AdminLdapGroup_ *gldap.DN `yaml:"-"`
|
||||||
|
LdapCertConn bool `yaml:"ldapCertConn" envconfig:"LDAP_CERT_CONN"`
|
||||||
|
LdapTlsCert string `yaml:"ldapTlsCert" envconfig:"LDAPTLS_CERT"`
|
||||||
|
LdapTlsKey string `yaml:"ldapTlsKey" envconfig:"LDAPTLS_KEY"`
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package ldap
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/go-ldap/ldap/v3"
|
"github.com/go-ldap/ldap/v3"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -14,7 +15,33 @@ type RawLdapData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Open(cfg *Config) (*ldap.Conn, error) {
|
func Open(cfg *Config) (*ldap.Conn, error) {
|
||||||
tlsConfig := &tls.Config{InsecureSkipVerify: !cfg.CertValidation}
|
var tlsConfig *tls.Config
|
||||||
|
|
||||||
|
if cfg.LdapCertConn {
|
||||||
|
|
||||||
|
cert_plain, err := ioutil.ReadFile(cfg.LdapTlsCert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to load the certificate")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := ioutil.ReadFile(cfg.LdapTlsKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to load the key")
|
||||||
|
}
|
||||||
|
|
||||||
|
cert_x509, err := tls.X509KeyPair(cert_plain, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed X509")
|
||||||
|
|
||||||
|
}
|
||||||
|
tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert_x509}}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
tlsConfig = &tls.Config{InsecureSkipVerify: !cfg.CertValidation}
|
||||||
|
}
|
||||||
|
|
||||||
conn, err := ldap.DialURL(cfg.URL, ldap.DialWithTLSConfig(tlsConfig))
|
conn, err := ldap.DialURL(cfg.URL, ldap.DialWithTLSConfig(tlsConfig))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to connect to LDAP")
|
return nil, errors.Wrap(err, "failed to connect to LDAP")
|
||||||
|
@@ -67,6 +67,7 @@ type Config struct {
|
|||||||
EditableKeys bool `yaml:"editableKeys" envconfig:"EDITABLE_KEYS"`
|
EditableKeys bool `yaml:"editableKeys" envconfig:"EDITABLE_KEYS"`
|
||||||
CreateDefaultPeer bool `yaml:"createDefaultPeer" envconfig:"CREATE_DEFAULT_PEER"`
|
CreateDefaultPeer bool `yaml:"createDefaultPeer" envconfig:"CREATE_DEFAULT_PEER"`
|
||||||
SelfProvisioningAllowed bool `yaml:"selfProvisioning" envconfig:"SELF_PROVISIONING"`
|
SelfProvisioningAllowed bool `yaml:"selfProvisioning" envconfig:"SELF_PROVISIONING"`
|
||||||
|
WGExoprterFriendlyNames bool `yaml:"wgExporterFriendlyNames" envconfig:"WG_EXPORTER_FRIENDLY_NAMES"`
|
||||||
LdapEnabled bool `yaml:"ldapEnabled" envconfig:"LDAP_ENABLED"`
|
LdapEnabled bool `yaml:"ldapEnabled" envconfig:"LDAP_ENABLED"`
|
||||||
SessionSecret string `yaml:"sessionSecret" envconfig:"SESSION_SECRET"`
|
SessionSecret string `yaml:"sessionSecret" envconfig:"SESSION_SECRET"`
|
||||||
LogoUrl string `yaml:"logoUrl" envconfig:"LOGO_URL"`
|
LogoUrl string `yaml:"logoUrl" envconfig:"LOGO_URL"`
|
||||||
@@ -91,6 +92,7 @@ func NewConfig() *Config {
|
|||||||
cfg.Core.AdminPassword = "wgportal"
|
cfg.Core.AdminPassword = "wgportal"
|
||||||
cfg.Core.LdapEnabled = false
|
cfg.Core.LdapEnabled = false
|
||||||
cfg.Core.EditableKeys = true
|
cfg.Core.EditableKeys = true
|
||||||
|
cfg.Core.WGExoprterFriendlyNames = false
|
||||||
cfg.Core.SessionSecret = "secret"
|
cfg.Core.SessionSecret = "secret"
|
||||||
|
|
||||||
cfg.Database.Typ = "sqlite"
|
cfg.Database.Typ = "sqlite"
|
||||||
|
@@ -112,7 +112,7 @@ func (s *Server) GetInterfaceConfig(c *gin.Context) {
|
|||||||
currentSession := GetSessionData(c)
|
currentSession := GetSessionData(c)
|
||||||
device := s.peers.GetDevice(currentSession.DeviceName)
|
device := s.peers.GetDevice(currentSession.DeviceName)
|
||||||
peers := s.peers.GetActivePeers(device.DeviceName)
|
peers := s.peers.GetActivePeers(device.DeviceName)
|
||||||
cfg, err := device.GetConfigFile(peers)
|
cfg, err := device.GetConfigFile(peers, s.config.Core.WGExoprterFriendlyNames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.GetHandleError(c, http.StatusInternalServerError, "ConfigFile error", err.Error())
|
s.GetHandleError(c, http.StatusInternalServerError, "ConfigFile error", err.Error())
|
||||||
return
|
return
|
||||||
|
@@ -236,7 +236,7 @@ func (s *Server) GetPeerConfig(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := peer.GetConfigFile(s.peers.GetDevice(currentSession.DeviceName))
|
cfg, err := peer.GetConfigFile(s.peers.GetDevice(peer.DeviceName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.GetHandleError(c, http.StatusInternalServerError, "ConfigFile error", err.Error())
|
s.GetHandleError(c, http.StatusInternalServerError, "ConfigFile error", err.Error())
|
||||||
return
|
return
|
||||||
|
@@ -83,6 +83,26 @@ func (s *Server) GetAdminUsersEdit(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetAdminUsersDelete(c *gin.Context) {
|
||||||
|
user := s.users.GetUserUnscoped(c.Query("pkey"))
|
||||||
|
if user == nil {
|
||||||
|
SetFlashMessage(c, "invalid user", "danger")
|
||||||
|
c.Redirect(http.StatusSeeOther, "/admin/users/")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
urlEncodedKey := url.QueryEscape(c.Query("pkey"))
|
||||||
|
|
||||||
|
if err := s.HardDeleteUser(*user); err != nil {
|
||||||
|
SetFlashMessage(c, "failed to delete user: "+err.Error(), "danger")
|
||||||
|
c.Redirect(http.StatusSeeOther, "/admin/users/edit?pkey="+urlEncodedKey+"&formerr=delete")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
SetFlashMessage(c, "user deleted successfully", "success")
|
||||||
|
c.Redirect(http.StatusSeeOther, "/admin/users/")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) PostAdminUsersEdit(c *gin.Context) {
|
func (s *Server) PostAdminUsersEdit(c *gin.Context) {
|
||||||
currentUser := s.users.GetUserUnscoped(c.Query("pkey"))
|
currentUser := s.users.GetUserUnscoped(c.Query("pkey"))
|
||||||
if currentUser == nil {
|
if currentUser == nil {
|
||||||
@@ -113,7 +133,7 @@ func (s *Server) PostAdminUsersEdit(c *gin.Context) {
|
|||||||
} else {
|
} else {
|
||||||
formUser.DeletedAt = gorm.DeletedAt{}
|
formUser.DeletedAt = gorm.DeletedAt{}
|
||||||
}
|
}
|
||||||
formUser.IsAdmin = c.PostForm("isadmin") == "true"
|
formUser.IsAdmin = c.PostForm("isadmin") != ""
|
||||||
|
|
||||||
if err := s.UpdateUser(formUser); err != nil {
|
if err := s.UpdateUser(formUser); err != nil {
|
||||||
_ = s.updateFormInSession(c, formUser)
|
_ = s.updateFormInSession(c, formUser)
|
||||||
|
@@ -114,7 +114,7 @@ func (s *Server) disableMissingLdapUsers(ldapUsers []ldap.RawLdapData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.users.DeleteUser(&activeUsers[i]); err != nil {
|
if err := s.users.DeleteUser(&activeUsers[i], true); err != nil {
|
||||||
logrus.Errorf("failed to delete deactivated user %s in database: %v", activeUsers[i].Email, err)
|
logrus.Errorf("failed to delete deactivated user %s in database: %v", activeUsers[i].Email, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -64,6 +64,7 @@ func SetupRoutes(s *Server) {
|
|||||||
admin.GET("/users/create", s.GetAdminUsersCreate)
|
admin.GET("/users/create", s.GetAdminUsersCreate)
|
||||||
admin.POST("/users/create", s.PostAdminUsersCreate)
|
admin.POST("/users/create", s.PostAdminUsersCreate)
|
||||||
admin.GET("/users/edit", s.GetAdminUsersEdit)
|
admin.GET("/users/edit", s.GetAdminUsersEdit)
|
||||||
|
admin.GET("/users/delete", s.GetAdminUsersDelete)
|
||||||
admin.POST("/users/edit", s.PostAdminUsersEdit)
|
admin.POST("/users/edit", s.PostAdminUsersEdit)
|
||||||
|
|
||||||
// User routes
|
// User routes
|
||||||
|
@@ -103,16 +103,21 @@ func (s *Server) CreatePeer(device string, peer wireguard.Peer) error {
|
|||||||
}
|
}
|
||||||
peer.SetIPAddresses(peerIPs...)
|
peer.SetIPAddresses(peerIPs...)
|
||||||
}
|
}
|
||||||
if peer.PrivateKey == "" && dev.Type == wireguard.DeviceTypeServer { // if private key is empty create a new one
|
if peer.PresharedKey == "" && dev.Type == wireguard.DeviceTypeServer { // if preshared key is empty create a new one
|
||||||
|
|
||||||
psk, err := wgtypes.GenerateKey()
|
psk, err := wgtypes.GenerateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to generate key")
|
return errors.Wrap(err, "failed to generate key")
|
||||||
}
|
}
|
||||||
|
peer.PresharedKey = psk.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if peer.PrivateKey == "" && peer.PublicKey == "" && dev.Type == wireguard.DeviceTypeServer { // if private key is empty create a new one
|
||||||
|
|
||||||
key, err := wgtypes.GeneratePrivateKey()
|
key, err := wgtypes.GeneratePrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to generate private key")
|
return errors.Wrap(err, "failed to generate private key")
|
||||||
}
|
}
|
||||||
peer.PresharedKey = psk.String()
|
|
||||||
peer.PrivateKey = key.String()
|
peer.PrivateKey = key.String()
|
||||||
peer.PublicKey = key.PublicKey().String()
|
peer.PublicKey = key.PublicKey().String()
|
||||||
}
|
}
|
||||||
@@ -204,7 +209,7 @@ func (s *Server) WriteWireGuardConfigFile(device string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dev := s.peers.GetDevice(device)
|
dev := s.peers.GetDevice(device)
|
||||||
cfg, err := dev.GetConfigFile(s.peers.GetActivePeers(device))
|
cfg, err := dev.GetConfigFile(s.peers.GetActivePeers(device), s.config.Core.WGExoprterFriendlyNames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithMessage(err, "failed to get config file")
|
return errors.WithMessage(err, "failed to get config file")
|
||||||
}
|
}
|
||||||
@@ -248,10 +253,6 @@ func (s *Server) CreateUser(user users.User, device string) error {
|
|||||||
// UpdateUser updates the user in the database. If the user is marked as deleted, it will get remove from the database.
|
// UpdateUser updates the user in the database. If the user is marked as deleted, it will get remove from the database.
|
||||||
// Also, if the user is re-enabled, all it's linked WireGuard peers will be activated again.
|
// Also, if the user is re-enabled, all it's linked WireGuard peers will be activated again.
|
||||||
func (s *Server) UpdateUser(user users.User) error {
|
func (s *Server) UpdateUser(user users.User) error {
|
||||||
if user.DeletedAt.Valid {
|
|
||||||
return s.DeleteUser(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentUser := s.users.GetUserUnscoped(user.Email)
|
currentUser := s.users.GetUserUnscoped(user.Email)
|
||||||
|
|
||||||
// Hash user password (if set)
|
// Hash user password (if set)
|
||||||
@@ -270,7 +271,12 @@ func (s *Server) UpdateUser(user users.User) error {
|
|||||||
return errors.WithMessage(err, "failed to update user in manager")
|
return errors.WithMessage(err, "failed to update user in manager")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If user was deleted (disabled), reactivate it's peers
|
// Set to deleted (disabled) if user's deletedAt date is not empty
|
||||||
|
if user.DeletedAt.Valid {
|
||||||
|
return s.DeleteUser(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, if user was deleted (disabled), reactivate it's peers
|
||||||
if currentUser.DeletedAt.Valid {
|
if currentUser.DeletedAt.Valid {
|
||||||
for _, peer := range s.peers.GetPeersByMail(user.Email) {
|
for _, peer := range s.peers.GetPeersByMail(user.Email) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
@@ -284,18 +290,15 @@ func (s *Server) UpdateUser(user users.User) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUser removes the user from the database.
|
// DeleteUser soft-deletes the user from the database (disable the user).
|
||||||
// Also, if the user has linked WireGuard peers, they will be deactivated.
|
// Also, if the user has linked WireGuard peers, they will be deactivated.
|
||||||
func (s *Server) DeleteUser(user users.User) error {
|
func (s *Server) DeleteUser(user users.User) error {
|
||||||
currentUser := s.users.GetUserUnscoped(user.Email)
|
|
||||||
|
|
||||||
// Update in database
|
// Update in database
|
||||||
if err := s.users.DeleteUser(&user); err != nil {
|
if err := s.users.DeleteUser(&user, true); err != nil {
|
||||||
return errors.WithMessage(err, "failed to delete user in manager")
|
return errors.WithMessage(err, "failed to disable user in manager")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If user was active, disable it's peers
|
// Disable users peers
|
||||||
if !currentUser.DeletedAt.Valid {
|
|
||||||
for _, peer := range s.peers.GetPeersByMail(user.Email) {
|
for _, peer := range s.peers.GetPeersByMail(user.Email) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
peer.DeactivatedAt = &now
|
peer.DeactivatedAt = &now
|
||||||
@@ -303,6 +306,23 @@ func (s *Server) DeleteUser(user users.User) error {
|
|||||||
logrus.Errorf("failed to update deactivated peer %s for %s: %v", peer.PublicKey, user.Email, err)
|
logrus.Errorf("failed to update deactivated peer %s for %s: %v", peer.PublicKey, user.Email, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HardDeleteUser removes the user from the database.
|
||||||
|
// Also, if the user has linked WireGuard peers, they will be deleted.
|
||||||
|
func (s *Server) HardDeleteUser(user users.User) error {
|
||||||
|
// Update in database
|
||||||
|
if err := s.users.DeleteUser(&user, false); err != nil {
|
||||||
|
return errors.WithMessage(err, "failed to delete user in manager")
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove all linked peers
|
||||||
|
for _, peer := range s.peers.GetPeersByMail(user.Email) {
|
||||||
|
if err := s.DeletePeer(peer); err != nil {
|
||||||
|
logrus.Errorf("failed to delete peer %s for %s: %v", peer.PublicKey, user.Email, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@@ -161,9 +161,14 @@ func (m Manager) UpdateUser(user *User) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Manager) DeleteUser(user *User) error {
|
func (m Manager) DeleteUser(user *User, soft bool) error {
|
||||||
user.Email = strings.ToLower(user.Email)
|
user.Email = strings.ToLower(user.Email)
|
||||||
res := m.db.Delete(user)
|
var res *gorm.DB
|
||||||
|
if soft {
|
||||||
|
res = m.db.Delete(user)
|
||||||
|
} else {
|
||||||
|
res = m.db.Unscoped().Delete(user)
|
||||||
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
return errors.Wrapf(res.Error, "failed to update user %s", user.Email)
|
return errors.Wrapf(res.Error, "failed to update user %s", user.Email)
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,7 @@ type User struct {
|
|||||||
// required fields
|
// required fields
|
||||||
Email string `gorm:"primaryKey" form:"email" binding:"required,email"`
|
Email string `gorm:"primaryKey" form:"email" binding:"required,email"`
|
||||||
Source UserSource
|
Source UserSource
|
||||||
IsAdmin bool
|
IsAdmin bool `form:"isadmin"`
|
||||||
|
|
||||||
// optional fields
|
// optional fields
|
||||||
Firstname string `form:"firstname" binding:"required"`
|
Firstname string `form:"firstname" binding:"required"`
|
||||||
|
@@ -338,12 +338,13 @@ func (d Device) GetConfig() wgtypes.Config {
|
|||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Device) GetConfigFile(peers []Peer) ([]byte, error) {
|
func (d Device) GetConfigFile(peers []Peer, friendlyNames bool) ([]byte, error) {
|
||||||
var tplBuff bytes.Buffer
|
var tplBuff bytes.Buffer
|
||||||
|
|
||||||
err := templateCache.ExecuteTemplate(&tplBuff, "interface.tpl", gin.H{
|
err := templateCache.ExecuteTemplate(&tplBuff, "interface.tpl", gin.H{
|
||||||
"Peers": peers,
|
"Peers": peers,
|
||||||
"Interface": d,
|
"Interface": d,
|
||||||
|
"FriendlyNames": friendlyNames,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to execute server template")
|
return nil, errors.Wrap(err, "failed to execute server template")
|
||||||
|
@@ -56,6 +56,9 @@ PostDown = {{ .Interface.PostDown }}
|
|||||||
# -WGP- PrivateKey: {{.PrivateKey}}
|
# -WGP- PrivateKey: {{.PrivateKey}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
[Peer]
|
[Peer]
|
||||||
|
{{- if $.FriendlyNames}}
|
||||||
|
# friendly_name = {{ .Identifier }}
|
||||||
|
{{- end}}
|
||||||
PublicKey = {{ .PublicKey }}
|
PublicKey = {{ .PublicKey }}
|
||||||
{{- if .PresharedKey}}
|
{{- if .PresharedKey}}
|
||||||
PresharedKey = {{ .PresharedKey }}
|
PresharedKey = {{ .PresharedKey }}
|
||||||
|
Reference in New Issue
Block a user