diff --git a/cmd/wg-portal/assets/tpl/admin_edit_user.html b/cmd/wg-portal/assets/tpl/admin_edit_user.html deleted file mode 100644 index 9891f32..0000000 --- a/cmd/wg-portal/assets/tpl/admin_edit_user.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - {{ .Static.WebsiteTitle }} - Users - - - - - - - - {{template "prt_nav.html" .}} -
- {{if eq .User.CreatedAt .Epoch}} -

Create a new user

- {{else}} -

Edit user {{.User.Email}}

- {{end}} - - {{template "prt_flashes.html" .}} - -
- - {{if eq .User.CreatedAt .Epoch}} -
-
- - -
-
- {{else}} - - {{end}} -
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
-
- - -
-
- - -
-
-
- - - Cancel -
-
- {{template "prt_footer.html" .}} - - - - - - - - - \ No newline at end of file diff --git a/cmd/wg-portal/assets/tpl/admin_index.html b/cmd/wg-portal/assets/tpl/admin_index.html index 97ad7af..4738c5b 100644 --- a/cmd/wg-portal/assets/tpl/admin_index.html +++ b/cmd/wg-portal/assets/tpl/admin_index.html @@ -1,8 +1,9 @@ + - + {{ .Static.WebsiteTitle }} - Admin @@ -11,119 +12,125 @@ - {{template "prt_nav.html" .}} -
-

WireGuard VPN Administration

+{{template "prt_nav.html" .}} +
+ {{template "prt_flashes.html" .}} -
-
-
- Interface status for {{.Device.DeviceName}} {{if eq $.Device.Type "server"}}(server mode){{end}}{{if eq $.Device.Type "client"}}(client mode){{end}} - -     - -     - +
+
+
+
+ Interface status for {{.Device.DeviceName}} {{if eq $.Device.Type "server"}}(server mode){{end}}{{if eq $.Device.Type "client"}}(client mode){{end}} +
+ +     + +     + +
+
+
+
+ {{if eq $.Device.Type "server"}} +
+ + + + + + + + + + + + + + + + + + + + + + + +
Public Key:{{.Device.PublicKey}}
Public Endpoint:{{.Device.DefaultEndpoint}}
Listening Port:{{.Device.ListenPort}}
Enabled Peers:{{len .Device.Interface.Peers}}
Total Peers:{{.TotalPeers}}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
IP Address:{{.Device.IPsStr}}
Default allowed IP's:{{.Device.DefaultAllowedIPsStr}}
Default DNS servers:{{.Device.DNSStr}}
Default MTU:{{.Device.Mtu}}
Default Keepalive Interval:{{.Device.DefaultPersistentKeepalive}}
+
+ {{end}} + {{if eq $.Device.Type "client"}} +
+ + + + + + + + + + + + + + + +
Public Key:{{.Device.PublicKey}}
Enabled Endpoints:{{len .Device.Interface.Peers}}
Total Endpoints:{{.TotalPeers}}
+
+
+ + + + + + + + + + + + + + + +
IP Address:{{.Device.IPsStr}}
DNS servers:{{.Device.DNSStr}}
Default MTU:{{.Device.Mtu}}
+
+ {{end}} +
+
-
-
- {{if eq $.Device.Type "server"}} -
- - - - - - - - - - - - - - - - - - - - - - - -
Public Key:{{.Device.PublicKey}}
Public Endpoint:{{.Device.DefaultEndpoint}}
Listening Port:{{.Device.ListenPort}}
Enabled Peers:{{len .Device.Interface.Peers}}
Total Peers:{{.TotalPeers}}
-
-
- - - - - - - - - - - - - - - - - - - - - - - -
IP Address:{{.Device.IPsStr}}
Default allowed IP's:{{.Device.DefaultAllowedIPsStr}}
Default DNS servers:{{.Device.DNSStr}}
Default MTU:{{.Device.Mtu}}
Default Keepalive Interval:{{.Device.DefaultPersistentKeepalive}}
-
- {{end}} - {{if eq $.Device.Type "client"}} -
- - - - - - - - - - - - - - - -
Public Key:{{.Device.PublicKey}}
Enabled Endpoints:{{len .Device.Interface.Peers}}
Total Endpoints:{{.TotalPeers}}
-
-
- - - - - - - - - - - - - - - -
IP Address:{{.Device.IPsStr}}
DNS servers:{{.Device.DNSStr}}
Default MTU:{{.Device.Mtu}}
-
- {{end}} -
- -
+
{{if eq $.Device.Type "server"}} @@ -262,11 +269,7 @@
{{template "prt_footer.html" .}} - - - - \ No newline at end of file diff --git a/cmd/wg-portal/assets/tpl/admin_user_edit.html b/cmd/wg-portal/assets/tpl/admin_user_edit.html new file mode 100644 index 0000000..9891f32 --- /dev/null +++ b/cmd/wg-portal/assets/tpl/admin_user_edit.html @@ -0,0 +1,90 @@ + + + + + + {{ .Static.WebsiteTitle }} - Users + + + + + + + + {{template "prt_nav.html" .}} +
+ {{if eq .User.CreatedAt .Epoch}} +

Create a new user

+ {{else}} +

Edit user {{.User.Email}}

+ {{end}} + + {{template "prt_flashes.html" .}} + +
+ + {{if eq .User.CreatedAt .Epoch}} +
+
+ + +
+
+ {{else}} + + {{end}} +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+ + +
+
+ + +
+
+
+ + + Cancel +
+
+ {{template "prt_footer.html" .}} + + + + + + + + + \ No newline at end of file diff --git a/cmd/wg-portal/assets/tpl/prt_nav.html b/cmd/wg-portal/assets/tpl/prt_nav.html index 63d444f..7f1c540 100644 --- a/cmd/wg-portal/assets/tpl/prt_nav.html +++ b/cmd/wg-portal/assets/tpl/prt_nav.html @@ -10,7 +10,7 @@ {{with eq $.Session.LoggedIn true}}{{with eq $.Session.IsAdmin true}} {{with eq $.Route "/admin/"}} -
+
@@ -27,35 +27,33 @@ diff --git a/cmd/wg-portal/ui/handler.go b/cmd/wg-portal/ui/handler.go index 8d8e0ab..de99677 100644 --- a/cmd/wg-portal/ui/handler.go +++ b/cmd/wg-portal/ui/handler.go @@ -2,11 +2,14 @@ import ( "context" + "net/http" "net/url" "path" "strings" "time" + "github.com/h44z/wg-portal/internal/persistence" + "github.com/gin-gonic/gin" "github.com/h44z/wg-portal/cmd/wg-portal/common" "github.com/h44z/wg-portal/internal/portal" @@ -100,6 +103,55 @@ return nil } +func (h *handler) authenticationMiddleware(scope string) gin.HandlerFunc { + return func(c *gin.Context) { + session := h.session.GetData(c) + + if !session.LoggedIn { + session.DeepLink = c.Request.RequestURI + h.session.SetData(c, session) + + // Abort the request with the appropriate error code + c.Abort() + c.Redirect(http.StatusSeeOther, "/auth/login") + return + } + + if scope == "admin" && !session.IsAdmin { + // Abort the request with the appropriate error code + c.Abort() + c.String(http.StatusUnauthorized, "unauthorized: not enough permissions") + return + } + + // default case if some random scope was set... + if scope != "" && !session.IsAdmin { + // Abort the request with the appropriate error code + c.Abort() + c.String(http.StatusUnauthorized, "unauthorized: not enough permissions") + return + } + + // Check if logged-in user is still valid + if !h.isUserStillValid(session.UserIdentifier) { + h.session.DestroyData(c) + c.Abort() + c.String(http.StatusUnauthorized, "unauthorized: session no longer available") + return + } + + // Continue down the chain to handler etc + c.Next() + } +} + +func (h *handler) isUserStillValid(id persistence.UserIdentifier) bool { + if _, err := h.backend.GetActiveUser(id); err != nil { + return false + } + return true +} + func (h *handler) RegisterRoutes(g *gin.Engine) { csrfMiddleware := csrf.Middleware(csrf.Options{ Secret: h.config.Core.SessionSecret, @@ -110,7 +162,7 @@ }) // Entrypoint - g.GET("/", h.GetIndex()) + g.GET("/", h.handleIndexGet()) // Auth routes auth := g.Group("/auth") @@ -122,6 +174,11 @@ auth.GET("/logout", h.handleLogoutGet()) // Admin routes + admin := g.Group("/admin") + admin.Use(csrfMiddleware) + admin.Use(h.authenticationMiddleware("admin")) + admin.GET("/", h.handleAdminIndexGet()) + admin.GET("/users", h.handleAdminUserIndexGet()) // User routes } diff --git a/cmd/wg-portal/ui/pages_admin.go b/cmd/wg-portal/ui/pages_admin.go new file mode 100644 index 0000000..303ebf9 --- /dev/null +++ b/cmd/wg-portal/ui/pages_admin.go @@ -0,0 +1,22 @@ +package ui + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +func (h *handler) handleAdminIndexGet() gin.HandlerFunc { + return func(c *gin.Context) { + currentSession := h.session.GetData(c) + + c.HTML(http.StatusOK, "admin_index.html", gin.H{ + "Route": c.Request.URL.Path, + "Alerts": h.session.GetFlashes(c), + "Session": currentSession, + "Static": h.getStaticData(), + "Interface": nil, // TODO: load interface specified in the session + "InterfaceNames": map[string]string{"wgX": "wgX descr"}, + }) + } +} diff --git a/cmd/wg-portal/ui/pages_admin_user.go b/cmd/wg-portal/ui/pages_admin_user.go new file mode 100644 index 0000000..7e3560c --- /dev/null +++ b/cmd/wg-portal/ui/pages_admin_user.go @@ -0,0 +1,22 @@ +package ui + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +func (h *handler) handleAdminUserIndexGet() gin.HandlerFunc { + return func(c *gin.Context) { + currentSession := h.session.GetData(c) + + c.HTML(http.StatusOK, "admin_user_index.html", gin.H{ + "Route": c.Request.URL.Path, + "Alerts": h.session.GetFlashes(c), + "Session": currentSession, + "Static": h.getStaticData(), + "Interface": nil, // TODO: load interface specified in the session + "InterfaceNames": map[string]string{"wgX": "wgX descr"}, + }) + } +} diff --git a/cmd/wg-portal/ui/pages_core.go b/cmd/wg-portal/ui/pages_core.go index fca4e1e..66bdc1b 100644 --- a/cmd/wg-portal/ui/pages_core.go +++ b/cmd/wg-portal/ui/pages_core.go @@ -29,7 +29,7 @@ } } -func (h *handler) GetIndex() gin.HandlerFunc { +func (h *handler) handleIndexGet() gin.HandlerFunc { return func(c *gin.Context) { currentSession := h.session.GetData(c)