diff --git a/assets/tpl/user_create_client.html b/assets/tpl/user_create_client.html new file mode 100644 index 00000000..5e6540c3 --- /dev/null +++ b/assets/tpl/user_create_client.html @@ -0,0 +1,44 @@ + + +
+ + +IP's | Handshake | + {{if eq $.UserManagePeers true}} ++ {{end}} @@ -42,6 +54,11 @@ | {{$p.Email}} | {{$p.IPsStr}} | {{$p.LastHandshake}} | + {{if eq $.UserManagePeers true}} ++ + | + {{end}}
---|---|---|---|---|---|
diff --git a/internal/server/configuration.go b/internal/server/configuration.go
index 3b013d1c..f904dbb5 100644
--- a/internal/server/configuration.go
+++ b/internal/server/configuration.go
@@ -116,6 +116,7 @@ func NewConfig() *Config {
cfg.WG.DefaultDeviceName = "wg0"
cfg.WG.ConfigDirectoryPath = "/etc/wireguard"
cfg.WG.ManageIPAddresses = true
+ cfg.WG.UserManagePeers = false
cfg.Email.Host = "127.0.0.1"
cfg.Email.Port = 25
cfg.Email.Encryption = common.MailEncryptionNone
diff --git a/internal/server/handlers_common.go b/internal/server/handlers_common.go
index ab851bbd..6a30812f 100644
--- a/internal/server/handlers_common.go
+++ b/internal/server/handlers_common.go
@@ -135,15 +135,16 @@ func (s *Server) GetUserIndex(c *gin.Context) {
peers := s.peers.GetSortedPeersForEmail(currentSession.SortedBy["userpeers"], currentSession.SortDirection["userpeers"], currentSession.Email)
c.HTML(http.StatusOK, "user_index.html", gin.H{
- "Route": c.Request.URL.Path,
- "Alerts": GetFlashes(c),
- "Session": currentSession,
- "Static": s.getStaticData(),
- "Peers": peers,
- "TotalPeers": len(peers),
- "Users": []users.User{*s.users.GetUser(currentSession.Email)},
- "Device": s.peers.GetDevice(currentSession.DeviceName),
- "DeviceNames": s.GetDeviceNames(),
+ "Route": c.Request.URL.Path,
+ "Alerts": GetFlashes(c),
+ "Session": currentSession,
+ "Static": s.getStaticData(),
+ "Peers": peers,
+ "TotalPeers": len(peers),
+ "Users": []users.User{*s.users.GetUser(currentSession.Email)},
+ "Device": s.peers.GetDevice(currentSession.DeviceName),
+ "DeviceNames": s.GetDeviceNames(),
+ "UserManagePeers": s.config.WG.UserManagePeers,
})
}
diff --git a/internal/server/handlers_peer.go b/internal/server/handlers_peer.go
index 36664091..76aa376e 100644
--- a/internal/server/handlers_peer.go
+++ b/internal/server/handlers_peer.go
@@ -392,3 +392,117 @@ func (s *Server) sendPeerConfigMail(peer wireguard.Peer) error {
return nil
}
+
+func (s *Server) GetUserCreatePeer(c *gin.Context) {
+ currentSession, err := s.setNewPeerFormInSession(c)
+ if err != nil {
+ s.GetHandleError(c, http.StatusInternalServerError, "Session error", err.Error())
+ return
+ }
+ c.HTML(http.StatusOK, "user_create_client.html", gin.H{
+ "Route": c.Request.URL.Path,
+ "Alerts": GetFlashes(c),
+ "Session": currentSession,
+ "Static": s.getStaticData(),
+ "Peer": currentSession.FormData.(wireguard.Peer),
+ "EditableKeys": s.config.Core.EditableKeys,
+ "Device": s.peers.GetDevice(currentSession.DeviceName),
+ "DeviceNames": s.GetDeviceNames(),
+ "AdminEmail": s.config.Core.AdminUser,
+ "Csrf": csrf.GetToken(c),
+ })
+}
+
+func (s *Server) PostUserCreatePeer(c *gin.Context) {
+ currentSession := GetSessionData(c)
+ var formPeer wireguard.Peer
+ if currentSession.FormData != nil {
+ formPeer = currentSession.FormData.(wireguard.Peer)
+ }
+
+ formPeer.Email = currentSession.Email;
+ formPeer.Identifier = currentSession.Email;
+ formPeer.DeviceType = wireguard.DeviceTypeServer;
+ formPeer.PrivateKey = "";
+
+ if err := c.ShouldBind(&formPeer); err != nil {
+ _ = s.updateFormInSession(c, formPeer)
+ SetFlashMessage(c, "failed to bind form data: "+err.Error(), "danger")
+ c.Redirect(http.StatusSeeOther, "/user/peer/create?formerr=bind")
+ return
+ }
+
+ disabled := c.PostForm("isdisabled") != ""
+ now := time.Now()
+ if disabled {
+ formPeer.DeactivatedAt = &now
+ }
+
+ if err := s.CreatePeer(currentSession.DeviceName, formPeer); err != nil {
+ _ = s.updateFormInSession(c, formPeer)
+ SetFlashMessage(c, "failed to add user: "+err.Error(), "danger")
+ c.Redirect(http.StatusSeeOther, "/user/peer/create?formerr=create")
+ return
+ }
+
+ SetFlashMessage(c, "client created successfully", "success")
+ c.Redirect(http.StatusSeeOther, "/user/profile")
+}
+
+func (s *Server) GetUserEditPeer(c *gin.Context) {
+ peer := s.peers.GetPeerByKey(c.Query("pkey"))
+
+
+ currentSession, err := s.setFormInSession(c, peer)
+ if err != nil {
+ s.GetHandleError(c, http.StatusInternalServerError, "Session error", err.Error())
+ return
+ }
+
+ if peer.Email != currentSession.Email {
+ s.GetHandleError(c, http.StatusUnauthorized, "No permissions", "You don't have permissions to view this resource!")
+ return;
+ }
+
+ c.HTML(http.StatusOK, "user_edit_client.html", gin.H{
+ "Route": c.Request.URL.Path,
+ "Alerts": GetFlashes(c),
+ "Session": currentSession,
+ "Static": s.getStaticData(),
+ "Peer": currentSession.FormData.(wireguard.Peer),
+ "EditableKeys": s.config.Core.EditableKeys,
+ "Device": s.peers.GetDevice(currentSession.DeviceName),
+ "DeviceNames": s.GetDeviceNames(),
+ "AdminEmail": s.config.Core.AdminUser,
+ "Csrf": csrf.GetToken(c),
+ })
+}
+
+func (s *Server) PostUserEditPeer(c *gin.Context) {
+ currentPeer := s.peers.GetPeerByKey(c.Query("pkey"))
+ urlEncodedKey := url.QueryEscape(c.Query("pkey"))
+
+ currentSession := GetSessionData(c)
+
+ if currentPeer.Email != currentSession.Email {
+ s.GetHandleError(c, http.StatusUnauthorized, "No permissions", "You don't have permissions to view this resource!")
+ return;
+ }
+
+ disabled := c.PostForm("isdisabled") != ""
+ now := time.Now()
+ if disabled && currentPeer.DeactivatedAt == nil {
+ currentPeer.DeactivatedAt = &now
+ }
+
+ // Update in database
+ if err := s.UpdatePeer(currentPeer, now); err != nil {
+ _ = s.updateFormInSession(c, currentPeer)
+ SetFlashMessage(c, "failed to update user: "+err.Error(), "danger")
+ c.Redirect(http.StatusSeeOther, "/user/peer/edit?pkey="+urlEncodedKey+"&formerr=update")
+ return
+ }
+
+ SetFlashMessage(c, "changes applied successfully", "success")
+ c.Redirect(http.StatusSeeOther, "/user/peer/edit?pkey="+urlEncodedKey)
+}
\ No newline at end of file
diff --git a/internal/server/routes.go b/internal/server/routes.go
index 3922cad1..98660355 100644
--- a/internal/server/routes.go
+++ b/internal/server/routes.go
@@ -76,6 +76,13 @@ func SetupRoutes(s *Server) {
user.GET("/download", s.GetPeerConfig)
user.GET("/email", s.GetPeerConfigMail)
user.GET("/status", s.GetPeerStatus)
+
+ if s.config.WG.UserManagePeers {
+ user.GET("/peer/create", s.GetUserCreatePeer)
+ user.POST("/peer/create", s.PostUserCreatePeer)
+ user.GET("/peer/edit", s.GetUserEditPeer)
+ user.POST("/peer/edit", s.PostUserEditPeer)
+ }
}
func SetupApiRoutes(s *Server) {
diff --git a/internal/wireguard/config.go b/internal/wireguard/config.go
index 29370134..0d079e3e 100644
--- a/internal/wireguard/config.go
+++ b/internal/wireguard/config.go
@@ -7,6 +7,7 @@ type Config struct {
DefaultDeviceName string `yaml:"defaultDevice" envconfig:"WG_DEFAULT_DEVICE"` // this device is used for auto-created peers, use GetDefaultDeviceName() to access this field
ConfigDirectoryPath string `yaml:"configDirectory" envconfig:"WG_CONFIG_PATH"` // optional, if set, updates will be written to this path, filename: |