mirror of https://github.com/h44z/wg-portal.git
				
				
				
			
		
			
				
	
	
		
			216 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
| package server
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/gin-gonic/gin"
 | |
| 	wgportal "github.com/h44z/wg-portal"
 | |
| 	_ "github.com/h44z/wg-portal/internal/server/docs" // docs is generated by Swag CLI, you have to import it.
 | |
| 	swaggerFiles "github.com/swaggo/files"
 | |
| 	ginSwagger "github.com/swaggo/gin-swagger"
 | |
| 	csrf "github.com/utrack/gin-csrf"
 | |
| )
 | |
| 
 | |
| func SetupRoutes(s *Server) {
 | |
| 	csrfMiddleware := csrf.Middleware(csrf.Options{
 | |
| 		Secret: s.config.Core.SessionSecret,
 | |
| 		ErrorFunc: func(c *gin.Context) {
 | |
| 			c.String(400, "CSRF token mismatch")
 | |
| 			c.Abort()
 | |
| 		},
 | |
| 	})
 | |
| 
 | |
| 	// Startpage
 | |
| 	s.server.GET("/", s.GetIndex)
 | |
| 	s.server.GET("/favicon.ico", func(c *gin.Context) {
 | |
| 		file, _ := wgportal.Statics.ReadFile("assets/img/favicon.ico")
 | |
| 		c.Data(
 | |
| 			http.StatusOK,
 | |
| 			"image/x-icon",
 | |
| 			file,
 | |
| 		)
 | |
| 	})
 | |
| 
 | |
| 	// Auth routes
 | |
| 	auth := s.server.Group("/auth")
 | |
| 	auth.Use(csrfMiddleware)
 | |
| 	auth.GET("/login", s.GetLogin)
 | |
| 	auth.POST("/login", s.PostLogin)
 | |
| 	auth.GET("/logout", s.GetLogout)
 | |
| 
 | |
| 	// Admin routes
 | |
| 	admin := s.server.Group("/admin")
 | |
| 	admin.Use(csrfMiddleware)
 | |
| 	admin.Use(s.RequireAuthentication("admin"))
 | |
| 	admin.GET("/", s.GetAdminIndex)
 | |
| 	admin.GET("/device/edit", s.GetAdminEditInterface)
 | |
| 	admin.POST("/device/edit", s.PostAdminEditInterface)
 | |
| 	admin.GET("/device/download", s.GetInterfaceConfig)
 | |
| 	admin.GET("/device/write", s.GetSaveConfig)
 | |
| 	admin.GET("/device/applyglobals", s.GetApplyGlobalConfig)
 | |
| 	admin.GET("/peer/edit", s.GetAdminEditPeer)
 | |
| 	admin.POST("/peer/edit", s.PostAdminEditPeer)
 | |
| 	admin.GET("/peer/create", s.GetAdminCreatePeer)
 | |
| 	admin.POST("/peer/create", s.PostAdminCreatePeer)
 | |
| 	admin.GET("/peer/createldap", s.GetAdminCreateLdapPeers)
 | |
| 	admin.POST("/peer/createldap", s.PostAdminCreateLdapPeers)
 | |
| 	admin.GET("/peer/delete", s.GetAdminDeletePeer)
 | |
| 	admin.GET("/peer/download", s.GetPeerConfig)
 | |
| 	admin.GET("/peer/email", s.GetPeerConfigMail)
 | |
| 	admin.GET("/peer/emailall", s.GetAdminSendEmails)
 | |
| 
 | |
| 	admin.GET("/users/", s.GetAdminUsersIndex)
 | |
| 	admin.GET("/users/create", s.GetAdminUsersCreate)
 | |
| 	admin.POST("/users/create", s.PostAdminUsersCreate)
 | |
| 	admin.GET("/users/edit", s.GetAdminUsersEdit)
 | |
| 	admin.GET("/users/delete", s.GetAdminUsersDelete)
 | |
| 	admin.POST("/users/edit", s.PostAdminUsersEdit)
 | |
| 
 | |
| 	// User routes
 | |
| 	user := s.server.Group("/user")
 | |
| 	user.Use(csrfMiddleware)
 | |
| 	user.Use(s.RequireAuthentication("")) // empty scope = all logged in users
 | |
| 	user.GET("/qrcode", s.GetPeerQRCode)
 | |
| 	user.GET("/profile", s.GetUserIndex)
 | |
| 	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) {
 | |
| 	api := ApiServer{s: s}
 | |
| 
 | |
| 	// Admin authenticated routes
 | |
| 	apiV1Backend := s.server.Group("/api/v1/backend")
 | |
| 	apiV1Backend.Use(s.RequireApiAuthentication("admin"))
 | |
| 
 | |
| 	apiV1Backend.GET("/users", api.GetUsers)
 | |
| 	apiV1Backend.POST("/users", api.PostUser)
 | |
| 	apiV1Backend.GET("/user", api.GetUser)
 | |
| 	apiV1Backend.PUT("/user", api.PutUser)
 | |
| 	apiV1Backend.PATCH("/user", api.PatchUser)
 | |
| 	apiV1Backend.DELETE("/user", api.DeleteUser)
 | |
| 
 | |
| 	apiV1Backend.GET("/peers", api.GetPeers)
 | |
| 	apiV1Backend.POST("/peers", api.PostPeer)
 | |
| 	apiV1Backend.GET("/peer", api.GetPeer)
 | |
| 	apiV1Backend.PUT("/peer", api.PutPeer)
 | |
| 	apiV1Backend.PATCH("/peer", api.PatchPeer)
 | |
| 	apiV1Backend.DELETE("/peer", api.DeletePeer)
 | |
| 
 | |
| 	apiV1Backend.GET("/devices", api.GetDevices)
 | |
| 	apiV1Backend.GET("/device", api.GetDevice)
 | |
| 	apiV1Backend.PUT("/device", api.PutDevice)
 | |
| 	apiV1Backend.PATCH("/device", api.PatchDevice)
 | |
| 
 | |
| 	// Simple authenticated routes
 | |
| 	apiV1Deployment := s.server.Group("/api/v1/provisioning")
 | |
| 	apiV1Deployment.Use(s.RequireApiAuthentication(""))
 | |
| 
 | |
| 	apiV1Deployment.GET("/peers", api.GetPeerDeploymentInformation)
 | |
| 	apiV1Deployment.GET("/peer", api.GetPeerDeploymentConfig)
 | |
| 	apiV1Deployment.POST("/peers", api.PostPeerDeploymentConfig)
 | |
| 
 | |
| 	// Swagger doc/ui
 | |
| 	s.server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
 | |
| }
 | |
| 
 | |
| func (s *Server) RequireAuthentication(scope string) gin.HandlerFunc {
 | |
| 	return func(c *gin.Context) {
 | |
| 		session := GetSessionData(c)
 | |
| 
 | |
| 		if !session.LoggedIn {
 | |
| 			// Abort the request with the appropriate error code
 | |
| 			c.Abort()
 | |
| 			c.Redirect(http.StatusSeeOther, "/auth/login?err=loginreq")
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		if scope == "admin" && !session.IsAdmin {
 | |
| 			// Abort the request with the appropriate error code
 | |
| 			c.Abort()
 | |
| 			s.GetHandleError(c, 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()
 | |
| 			s.GetHandleError(c, http.StatusUnauthorized, "unauthorized", "not enough permissions")
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// Check if logged-in user is still valid
 | |
| 		if !s.isUserStillValid(session.Email) {
 | |
| 			_ = DestroySessionData(c)
 | |
| 			c.Abort()
 | |
| 			s.GetHandleError(c, http.StatusUnauthorized, "unauthorized", "session no longer available")
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// Continue down the chain to handler etc
 | |
| 		c.Next()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s *Server) RequireApiAuthentication(scope string) gin.HandlerFunc {
 | |
| 	return func(c *gin.Context) {
 | |
| 		username, password, hasAuth := c.Request.BasicAuth()
 | |
| 		if !hasAuth {
 | |
| 			c.Abort()
 | |
| 			c.JSON(http.StatusUnauthorized, ApiError{Message: "unauthorized"})
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// Validate form input
 | |
| 		if strings.Trim(username, " ") == "" || strings.Trim(password, " ") == "" {
 | |
| 			c.Abort()
 | |
| 			c.JSON(http.StatusUnauthorized, ApiError{Message: "unauthorized"})
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// Check all available auth backends
 | |
| 		user, err := s.checkAuthentication(username, password)
 | |
| 		if err != nil {
 | |
| 			c.Abort()
 | |
| 			c.JSON(http.StatusInternalServerError, ApiError{Message: "login error"})
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// Check if user is authenticated
 | |
| 		if user == nil {
 | |
| 			c.Abort()
 | |
| 			c.JSON(http.StatusUnauthorized, ApiError{Message: "unauthorized"})
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// Check admin scope
 | |
| 		if scope == "admin" && !user.IsAdmin {
 | |
| 			// Abort the request with the appropriate error code
 | |
| 			c.Abort()
 | |
| 			c.JSON(http.StatusForbidden, ApiError{Message: "unauthorized"})
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// default case if some random scope was set...
 | |
| 		if scope != "" && !user.IsAdmin {
 | |
| 			// Abort the request with the appropriate error code
 | |
| 			c.Abort()
 | |
| 			c.JSON(http.StatusForbidden, ApiError{Message: "unauthorized"})
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// Continue down the chain to handler etc
 | |
| 		c.Next()
 | |
| 	}
 | |
| }
 |