diff --git a/assets/css/custom.css b/assets/css/custom.css index 5a6294c..ae0b24f 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -73,6 +73,10 @@ pre{background:#f7f7f9}iframe{overflow:hidden;border:none}@media (min-width: 768 color: #d03131; } +.expiring-peer { + color: #d09d12; +} + .tokenfield .token { border-radius: 0px; border: 1px solid #1a1a1a; @@ -105,4 +109,10 @@ a.advanced-settings.collapsed:before { .text-blue { color: #0057bb; +} + +@media (min-width: 992px) { + .pull-right-lg { + float: right; + } } \ No newline at end of file diff --git a/assets/tpl/admin_edit_client.html b/assets/tpl/admin_edit_client.html index 0b85284..d7d5cbf 100644 --- a/assets/tpl/admin_edit_client.html +++ b/assets/tpl/admin_edit_client.html @@ -106,7 +106,7 @@
-
+
+
+ + +
@@ -185,7 +189,7 @@
-
+
+
+ + +
diff --git a/assets/tpl/admin_index.html b/assets/tpl/admin_index.html index 8a3c572..e000068 100644 --- a/assets/tpl/admin_index.html +++ b/assets/tpl/admin_index.html @@ -170,7 +170,7 @@ - {{$p.Identifier}} + {{$p.Identifier}}{{if $p.WillExpire}} {{end}} {{$p.PublicKey}} {{if eq $.Device.Type "server"}} {{$p.Email}} @@ -243,8 +243,14 @@ {{end}}
+ {{if $p.DeactivatedAt}} +
Peer is disabled!
+ {{end}} + {{if $p.WillExpire}}{{if not $p.DeactivatedAt}} +
Peer will expire on {{ formatDate $p.ExpiresAt}}
+ {{end}}{{end}} {{if eq $.Device.Type "server"}} -
+ diff --git a/assets/tpl/user_index.html b/assets/tpl/user_index.html index f0e53d7..619fe19 100644 --- a/assets/tpl/user_index.html +++ b/assets/tpl/user_index.html @@ -102,7 +102,10 @@
-
+ {{if $p.DeactivatedAt}} +
Peer is disabled!
+ {{end}} + diff --git a/internal/common/db.go b/internal/common/db.go index d8122be..9e8f403 100644 --- a/internal/common/db.go +++ b/internal/common/db.go @@ -36,6 +36,14 @@ func init() { return nil }, }) + + migrations = append(migrations, Migration{ + version: "1.0.9", + migrateFn: func(db *gorm.DB) error { + logrus.Infof("upgraded database format to version 1.0.9") + return nil + }, + }) } type SupportedDatabase string diff --git a/internal/common/util.go b/internal/common/util.go index bbde700..e33ebf9 100644 --- a/internal/common/util.go +++ b/internal/common/util.go @@ -4,6 +4,7 @@ import ( "fmt" "net" "strings" + "time" ) // BroadcastAddr returns the last address in the given network, or the broadcast address. @@ -21,7 +22,7 @@ func BroadcastAddr(n *net.IPNet) net.IP { return broadcast } -// http://play.golang.org/p/m8TNTtygK0 +// http://play.golang.org/p/m8TNTtygK0 func IncreaseIP(ip net.IP) { for j := len(ip) - 1; j >= 0; j-- { ip[j]++ @@ -84,3 +85,11 @@ func ByteCountSI(b int64) string { return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp]) } + +func FormatDateHTML(t *time.Time) string { + if t == nil { + return "" + } + + return t.Format("2006-01-02") +} diff --git a/internal/server/api.go b/internal/server/api.go index 11f3be0..0bfb471 100644 --- a/internal/server/api.go +++ b/internal/server/api.go @@ -439,6 +439,7 @@ func (s *ApiServer) PutPeer(c *gin.Context) { now := time.Now() if updatePeer.DeactivatedAt != nil { updatePeer.DeactivatedAt = &now + updatePeer.DeactivatedReason = "api update" } if err := s.s.UpdatePeer(updatePeer, now); err != nil { c.JSON(http.StatusInternalServerError, ApiError{Message: err.Error()}) @@ -516,6 +517,7 @@ func (s *ApiServer) PatchPeer(c *gin.Context) { now := time.Now() if mergedPeer.DeactivatedAt != nil { mergedPeer.DeactivatedAt = &now + mergedPeer.DeactivatedReason = "api update" } if err := s.s.UpdatePeer(mergedPeer, now); err != nil { c.JSON(http.StatusInternalServerError, ApiError{Message: err.Error()}) diff --git a/internal/server/handlers_peer.go b/internal/server/handlers_peer.go index 78966ee..9e87e5b 100644 --- a/internal/server/handlers_peer.go +++ b/internal/server/handlers_peer.go @@ -71,8 +71,13 @@ func (s *Server) PostAdminEditPeer(c *gin.Context) { now := time.Now() if disabled && currentPeer.DeactivatedAt == nil { formPeer.DeactivatedAt = &now + formPeer.DeactivatedReason = "admin update" } else if !disabled { formPeer.DeactivatedAt = nil + formPeer.DeactivatedReason = "" + } + if formPeer.ExpiresAt != nil && formPeer.ExpiresAt.IsZero() { + formPeer.ExpiresAt = nil } // Update in database @@ -129,6 +134,7 @@ func (s *Server) PostAdminCreatePeer(c *gin.Context) { now := time.Now() if disabled { formPeer.DeactivatedAt = &now + formPeer.DeactivatedReason = "admin create" } if err := s.CreatePeer(currentSession.DeviceName, formPeer); err != nil { @@ -189,7 +195,7 @@ func (s *Server) PostAdminCreateLdapPeers(c *gin.Context) { logrus.Infof("creating %d ldap peers", len(emails)) for i := range emails { - if err := s.CreatePeerByEmail(currentSession.DeviceName, emails[i], formData.Identifier, false); err != nil { + if err := s.CreatePeerByEmail(currentSession.DeviceName, emails[i], formData.Identifier); err != nil { _ = s.updateFormInSession(c, formData) SetFlashMessage(c, "failed to add user: "+err.Error(), "danger") c.Redirect(http.StatusSeeOther, "/admin/peer/createldap?formerr=create") @@ -440,6 +446,7 @@ func (s *Server) PostUserCreatePeer(c *gin.Context) { now := time.Now() if disabled { formPeer.DeactivatedAt = &now + formPeer.DeactivatedReason = "user create" } if err := s.CreatePeer(currentSession.DeviceName, formPeer); err != nil { @@ -496,6 +503,7 @@ func (s *Server) PostUserEditPeer(c *gin.Context) { now := time.Now() if disabled && currentPeer.DeactivatedAt == nil { currentPeer.DeactivatedAt = &now + currentPeer.DeactivatedReason = "user update" } // Update in database diff --git a/internal/server/ldapsync.go b/internal/server/ldapsync.go index 9bef96d..6cee9c0 100644 --- a/internal/server/ldapsync.go +++ b/internal/server/ldapsync.go @@ -112,6 +112,7 @@ func (s *Server) disableMissingLdapUsers(ldapUsers []ldap.RawLdapData) { for _, peer := range s.peers.GetPeersByMail(activeUsers[i].Email) { now := time.Now() peer.DeactivatedAt = &now + peer.DeactivatedReason = "missing ldap user" if err := s.UpdatePeer(peer, now); err != nil { logrus.Errorf("failed to update deactivated peer %s: %v", peer.PublicKey, err) } @@ -141,6 +142,7 @@ func (s *Server) updateLdapUsers(ldapUsers []ldap.RawLdapData) { for _, peer := range s.peers.GetPeersByMail(user.Email) { now := time.Now() peer.DeactivatedAt = nil + peer.DeactivatedReason = "" if err = s.UpdatePeer(peer, now); err != nil { logrus.Errorf("failed to update activated peer %s: %v", peer.PublicKey, err) } diff --git a/internal/server/server.go b/internal/server/server.go index a22e84d..7968bd0 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -127,6 +127,7 @@ func (s *Server) Setup(ctx context.Context) error { }) s.server.Use(sessions.Sessions("authsession", cookieStore)) s.server.SetFuncMap(template.FuncMap{ + "formatDate": common.FormatDateHTML, "formatBytes": common.ByteCountSI, "urlEncode": url.QueryEscape, "startsWith": strings.HasPrefix, diff --git a/internal/server/server_helper.go b/internal/server/server_helper.go index f366396..71582d1 100644 --- a/internal/server/server_helper.go +++ b/internal/server/server_helper.go @@ -62,7 +62,7 @@ func (s *Server) PrepareNewPeer(device string) (wireguard.Peer, error) { } // CreatePeerByEmail creates a new peer for the given email. -func (s *Server) CreatePeerByEmail(device, email, identifierSuffix string, disabled bool) error { +func (s *Server) CreatePeerByEmail(device, email, identifierSuffix string) error { user := s.users.GetUser(email) peer, err := s.PrepareNewPeer(device) @@ -75,10 +75,6 @@ func (s *Server) CreatePeerByEmail(device, email, identifierSuffix string, disab } else { peer.Identifier = fmt.Sprintf("%s (%s)", email, identifierSuffix) } - now := time.Now() - if disabled { - peer.DeactivatedAt = &now - } return s.CreatePeer(device, peer) } @@ -281,6 +277,7 @@ func (s *Server) UpdateUser(user users.User) error { for _, peer := range s.peers.GetPeersByMail(user.Email) { now := time.Now() peer.DeactivatedAt = nil + peer.DeactivatedReason = "" if err := s.UpdatePeer(peer, now); err != nil { logrus.Errorf("failed to update (re)activated peer %s for %s: %v", peer.PublicKey, user.Email, err) } @@ -302,6 +299,7 @@ func (s *Server) DeleteUser(user users.User) error { for _, peer := range s.peers.GetPeersByMail(user.Email) { now := time.Now() peer.DeactivatedAt = &now + peer.DeactivatedReason = "user deleted" if err := s.UpdatePeer(peer, now); err != nil { logrus.Errorf("failed to update deactivated peer %s for %s: %v", peer.PublicKey, user.Email, err) } diff --git a/internal/server/version.go b/internal/server/version.go index a1b0048..58fdf31 100644 --- a/internal/server/version.go +++ b/internal/server/version.go @@ -1,4 +1,4 @@ package server var Version = "testbuild" -var DatabaseVersion = "1.0.8" +var DatabaseVersion = "1.0.9" diff --git a/internal/wireguard/peermanager.go b/internal/wireguard/peermanager.go index 504b9a4..3b4e504 100644 --- a/internal/wireguard/peermanager.go +++ b/internal/wireguard/peermanager.go @@ -108,11 +108,15 @@ type Peer struct { // Global Device Settings (can be ignored, only make sense if device is in server mode) Mtu int `form:"mtu" binding:"gte=0,lte=1500"` - DeactivatedAt *time.Time `json:",omitempty"` - CreatedBy string - UpdatedBy string - CreatedAt time.Time - UpdatedAt time.Time + DeactivatedAt *time.Time `json:",omitempty"` + DeactivatedReason string `json:",omitempty"` + + ExpiresAt *time.Time `json:",omitempty" form:"expires_at" binding:"omitempty" time_format:"2006-01-02"` + + CreatedBy string + UpdatedBy string + CreatedAt time.Time + UpdatedAt time.Time } func (p *Peer) SetIPAddresses(addresses ...string) { @@ -238,6 +242,19 @@ func (p Peer) IsValid() bool { return true } +func (p Peer) WillExpire() bool { + if p.ExpiresAt == nil { + return false + } + if p.DeactivatedAt != nil { + return false // already deactivated... + } + if p.ExpiresAt.After(time.Now()) { + return true + } + return false +} + func (p Peer) GetConfigFileName() string { reg := regexp.MustCompile("[^a-zA-Z0-9_-]+") return reg.ReplaceAllString(strings.ReplaceAll(p.Identifier, " ", "-"), "") + ".conf"