From e39e793b5b18fa5c329ddd681997ea6ad41241f1 Mon Sep 17 00:00:00 2001 From: uubulb Date: Tue, 17 Dec 2024 22:33:47 +0800 Subject: [PATCH] admin handler --- cmd/dashboard/controller/controller.go | 62 +++++++++++++++++--------- cmd/dashboard/controller/fm.go | 19 +++++--- cmd/dashboard/controller/terminal.go | 19 +++++--- cmd/dashboard/controller/user.go | 1 + 4 files changed, 67 insertions(+), 34 deletions(-) diff --git a/cmd/dashboard/controller/controller.go b/cmd/dashboard/controller/controller.go index 333b632..4b6d832 100644 --- a/cmd/dashboard/controller/controller.go +++ b/cmd/dashboard/controller/controller.go @@ -80,8 +80,8 @@ func routers(r *gin.Engine, frontendDist fs.FS) { auth.GET("/profile", commonHandler(getProfile)) auth.POST("/profile", commonHandler(updateProfile)) auth.GET("/user", commonHandler(listUser)) - auth.POST("/user", commonHandler(createUser)) - auth.POST("/batch-delete/user", commonHandler(batchDeleteUser)) + auth.POST("/user", adminHandler(createUser)) + auth.POST("/batch-delete/user", adminHandler(batchDeleteUser)) auth.GET("/service/list", listHandler(listService)) auth.POST("/service", commonHandler(createService)) @@ -130,9 +130,9 @@ func routers(r *gin.Engine, frontendDist fs.FS) { auth.POST("/batch-delete/nat", commonHandler(batchDeleteNAT)) auth.GET("/waf", commonHandler(listBlockedAddress)) - auth.POST("/batch-delete/waf", commonHandler(batchDeleteBlockedAddress)) + auth.POST("/batch-delete/waf", adminHandler(batchDeleteBlockedAddress)) - auth.PATCH("/setting", commonHandler(updateConfig)) + auth.PATCH("/setting", adminHandler(updateConfig)) r.NoRoute(fallbackToFrontend(frontendDist)) } @@ -190,26 +190,48 @@ func (we *wsError) Error() string { func commonHandler[T any](handler handlerFunc[T]) func(*gin.Context) { return func(c *gin.Context) { - data, err := handler(c) - if err == nil { - c.JSON(http.StatusOK, model.CommonResponse[T]{Success: true, Data: data}) + handle(c, handler) + } +} + +func adminHandler[T any](handler handlerFunc[T]) func(*gin.Context) { + return func(c *gin.Context) { + auth, ok := c.Get(model.CtxKeyAuthorizedUser) + if !ok { + c.JSON(http.StatusOK, newErrorResponse(singleton.Localizer.ErrorT("unauthorized"))) return } - switch err.(type) { - case *gormError: - log.Printf("NEZHA>> gorm error: %v", err) - c.JSON(http.StatusOK, newErrorResponse(singleton.Localizer.ErrorT("database error"))) - return - case *wsError: - // Connection is upgraded to WebSocket, so c.Writer is no longer usable - if msg := err.Error(); msg != "" { - log.Printf("NEZHA>> websocket error: %v", err) - } - return - default: - c.JSON(http.StatusOK, newErrorResponse(err)) + + user := *auth.(*model.User) + if user.Role != model.RoleAdmin { + c.JSON(http.StatusOK, newErrorResponse(singleton.Localizer.ErrorT("permission denied"))) return } + + handle(c, handler) + } +} + +func handle[T any](c *gin.Context, handler handlerFunc[T]) { + data, err := handler(c) + if err == nil { + c.JSON(http.StatusOK, model.CommonResponse[T]{Success: true, Data: data}) + return + } + switch err.(type) { + case *gormError: + log.Printf("NEZHA>> gorm error: %v", err) + c.JSON(http.StatusOK, newErrorResponse(singleton.Localizer.ErrorT("database error"))) + return + case *wsError: + // Connection is upgraded to WebSocket, so c.Writer is no longer usable + if msg := err.Error(); msg != "" { + log.Printf("NEZHA>> websocket error: %v", err) + } + return + default: + c.JSON(http.StatusOK, newErrorResponse(err)) + return } } diff --git a/cmd/dashboard/controller/fm.go b/cmd/dashboard/controller/fm.go index c413d62..955970b 100644 --- a/cmd/dashboard/controller/fm.go +++ b/cmd/dashboard/controller/fm.go @@ -7,6 +7,7 @@ import ( "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "github.com/hashicorp/go-uuid" + "github.com/nezhahq/nezha/model" "github.com/nezhahq/nezha/pkg/utils" "github.com/nezhahq/nezha/pkg/websocketx" @@ -31,13 +32,6 @@ func createFM(c *gin.Context) (*model.CreateFMResponse, error) { return nil, err } - streamId, err := uuid.GenerateUUID() - if err != nil { - return nil, err - } - - rpc.NezhaHandlerSingleton.CreateStream(streamId) - singleton.ServerLock.RLock() server := singleton.ServerList[id] singleton.ServerLock.RUnlock() @@ -45,6 +39,17 @@ func createFM(c *gin.Context) (*model.CreateFMResponse, error) { return nil, singleton.Localizer.ErrorT("server not found or not connected") } + if !server.HasPermission(c) { + return nil, singleton.Localizer.ErrorT("permission denied") + } + + streamId, err := uuid.GenerateUUID() + if err != nil { + return nil, err + } + + rpc.NezhaHandlerSingleton.CreateStream(streamId) + fmData, _ := utils.Json.Marshal(&model.TaskFM{ StreamID: streamId, }) diff --git a/cmd/dashboard/controller/terminal.go b/cmd/dashboard/controller/terminal.go index a5011b0..3c1ef0c 100644 --- a/cmd/dashboard/controller/terminal.go +++ b/cmd/dashboard/controller/terminal.go @@ -6,6 +6,7 @@ import ( "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "github.com/hashicorp/go-uuid" + "github.com/nezhahq/nezha/model" "github.com/nezhahq/nezha/pkg/utils" "github.com/nezhahq/nezha/pkg/websocketx" @@ -29,13 +30,6 @@ func createTerminal(c *gin.Context) (*model.CreateTerminalResponse, error) { return nil, err } - streamId, err := uuid.GenerateUUID() - if err != nil { - return nil, err - } - - rpc.NezhaHandlerSingleton.CreateStream(streamId) - singleton.ServerLock.RLock() server := singleton.ServerList[createTerminalReq.ServerID] singleton.ServerLock.RUnlock() @@ -43,6 +37,17 @@ func createTerminal(c *gin.Context) (*model.CreateTerminalResponse, error) { return nil, singleton.Localizer.ErrorT("server not found or not connected") } + if !server.HasPermission(c) { + return nil, singleton.Localizer.ErrorT("permission denied") + } + + streamId, err := uuid.GenerateUUID() + if err != nil { + return nil, err + } + + rpc.NezhaHandlerSingleton.CreateStream(streamId) + terminalData, _ := utils.Json.Marshal(&model.TerminalTask{ StreamID: streamId, }) diff --git a/cmd/dashboard/controller/user.go b/cmd/dashboard/controller/user.go index 7c8b9b9..52f9d70 100644 --- a/cmd/dashboard/controller/user.go +++ b/cmd/dashboard/controller/user.go @@ -114,6 +114,7 @@ func createUser(c *gin.Context) (uint64, error) { var u model.User u.Username = uf.Username + u.Role = model.RoleMember hash, err := bcrypt.GenerateFromPassword([]byte(uf.Password), bcrypt.DefaultCost) if err != nil {