feat(backend): errors move to pkg

This commit is contained in:
pycook
2025-05-05 21:08:45 +08:00
parent 1ea969e0d9
commit 065f4f787f
18 changed files with 118 additions and 172 deletions

View File

@@ -39,21 +39,16 @@ func initDB() {
} }
// 初始化服务
func initServices() { func initServices() {
// 初始化授权服务
service.InitAuthorizationService() service.InitAuthorizationService()
// 初始化文件服务
service.InitFileService() service.InitFileService()
// 其他服务初始化...
} }
func RunApi() error { func RunApi() error {
initDB() initDB()
// 初始化服务层
initServices() initServices()
r := gin.New() r := gin.New()

View File

@@ -11,6 +11,7 @@ import (
"github.com/veops/oneterm/internal/model" "github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
"github.com/veops/oneterm/pkg/config" "github.com/veops/oneterm/pkg/config"
myErrors "github.com/veops/oneterm/pkg/errors"
) )
var ( var (
@@ -20,7 +21,7 @@ var (
// Validate public key // Validate public key
func(ctx *gin.Context, data *model.Account) { func(ctx *gin.Context, data *model.Account) {
if err := accountService.ValidatePublicKey(data); err != nil { if err := accountService.ValidatePublicKey(data); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrWrongPvk, Data: nil}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrWrongPvk, Data: nil})
return return
} }
}, },
@@ -51,7 +52,7 @@ var (
return return
} }
code := lo.Ternary(err == nil, http.StatusBadRequest, http.StatusInternalServerError) code := lo.Ternary(err == nil, http.StatusBadRequest, http.StatusInternalServerError)
err = lo.Ternary[error](err == nil, &ApiError{Code: ErrHasDepency, Data: map[string]any{"name": assetName}}, err) err = lo.Ternary[error](err == nil, &myErrors.ApiError{Code: myErrors.ErrHasDepency, Data: map[string]any{"name": assetName}}, err)
ctx.AbortWithError(code, err) ctx.AbortWithError(code, err)
}, },
} }
@@ -116,7 +117,7 @@ func (c *Controller) GetAccounts(ctx *gin.Context) {
if !acl.IsAdmin(currentUser) { if !acl.IsAdmin(currentUser) {
assetIds, err := GetAssetIdsByAuthorization(ctx) assetIds, err := GetAssetIdsByAuthorization(ctx)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }

View File

@@ -11,6 +11,7 @@ import (
"github.com/veops/oneterm/internal/model" "github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
"github.com/veops/oneterm/pkg/config" "github.com/veops/oneterm/pkg/config"
"github.com/veops/oneterm/pkg/errors"
"github.com/veops/oneterm/pkg/logger" "github.com/veops/oneterm/pkg/logger"
) )
@@ -110,7 +111,7 @@ func (c *Controller) GetAssets(ctx *gin.Context) {
// Build base query using service layer // Build base query using service layer
db, err := assetService.BuildQuery(ctx) db, err := assetService.BuildQuery(ctx)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -119,7 +120,7 @@ func (c *Controller) GetAssets(ctx *gin.Context) {
db, err = assetService.FilterByParentId(db, cast.ToInt(q)) db, err = assetService.FilterByParentId(db, cast.ToInt(q))
if err != nil { if err != nil {
logger.L().Error("parent id filtering failed", zap.Error(err)) logger.L().Error("parent id filtering failed", zap.Error(err))
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
} }
@@ -132,7 +133,7 @@ func (c *Controller) GetAssets(ctx *gin.Context) {
if !acl.IsAdmin(currentUser) { if !acl.IsAdmin(currentUser) {
ids, err := GetAssetIdsByAuthorization(ctx) ids, err := GetAssetIdsByAuthorization(ctx)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
db = db.Where("id IN ?", ids) db = db.Where("id IN ?", ids)

View File

@@ -14,6 +14,7 @@ import (
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
gsession "github.com/veops/oneterm/internal/session" gsession "github.com/veops/oneterm/internal/session"
"github.com/veops/oneterm/pkg/config" "github.com/veops/oneterm/pkg/config"
myErrors "github.com/veops/oneterm/pkg/errors"
) )
// UpsertAuthorization godoc // UpsertAuthorization godoc
@@ -26,12 +27,12 @@ func (c *Controller) UpsertAuthorization(ctx *gin.Context) {
auth := &model.Authorization{} auth := &model.Authorization{}
err := ctx.ShouldBindBodyWithJSON(auth) err := ctx.ShouldBindBodyWithJSON(auth)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
if !service.DefaultAuthService.HasPermAuthorization(ctx, auth, acl.GRANT) { if !service.DefaultAuthService.HasPermAuthorization(ctx, auth, acl.GRANT) {
err = &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}} err = &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}}
ctx.AbortWithError(http.StatusForbidden, err) ctx.AbortWithError(http.StatusForbidden, err)
return return
} }
@@ -42,7 +43,7 @@ func (c *Controller) UpsertAuthorization(ctx *gin.Context) {
if ctx.IsAborted() { if ctx.IsAborted() {
return return
} }
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -66,21 +67,21 @@ func (c *Controller) DeleteAuthorization(ctx *gin.Context) {
auth, err := service.DefaultAuthService.GetAuthorizationById(ctx, authId) auth, err := service.DefaultAuthService.GetAuthorizationById(ctx, authId)
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
} else { } else {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
} }
return return
} }
if !service.DefaultAuthService.HasPermAuthorization(ctx, auth, acl.GRANT) { if !service.DefaultAuthService.HasPermAuthorization(ctx, auth, acl.GRANT) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}}) ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}})
return return
} }
// Delete authorization // Delete authorization
if err := service.DefaultAuthService.DeleteAuthorization(ctx, auth); err != nil { if err := service.DefaultAuthService.DeleteAuthorization(ctx, auth); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -113,13 +114,13 @@ func (c *Controller) GetAuthorizations(ctx *gin.Context) {
} }
if !service.DefaultAuthService.HasPermAuthorization(ctx, auth, acl.GRANT) { if !service.DefaultAuthService.HasPermAuthorization(ctx, auth, acl.GRANT) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}}) ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}})
return return
} }
auths, count, err := service.DefaultAuthService.GetAuthorizations(ctx, nodeId, assetId, accountId) auths, count, err := service.DefaultAuthService.GetAuthorizations(ctx, nodeId, assetId, accountId)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }

View File

@@ -13,6 +13,7 @@ import (
"github.com/veops/oneterm/internal/model" "github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
"github.com/veops/oneterm/pkg/config" "github.com/veops/oneterm/pkg/config"
myErrors "github.com/veops/oneterm/pkg/errors"
) )
var ( var (
@@ -25,7 +26,7 @@ var (
} }
_, err := regexp.Compile(data.Cmd) _, err := regexp.Compile(data.Cmd)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrBadRequest, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrBadRequest, Data: map[string]any{"err": err}})
} }
}, },
} }
@@ -36,12 +37,12 @@ var (
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return return
} }
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
if assetName != "" { if assetName != "" {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrHasDepency, Data: map[string]any{"name": assetName}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrHasDepency, Data: map[string]any{"name": assetName}})
} }
}, },
} }
@@ -98,7 +99,7 @@ func (c *Controller) GetCommands(ctx *gin.Context) {
db, err := commandService.BuildQuery(ctx) db, err := commandService.BuildQuery(ctx)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }

View File

@@ -11,6 +11,7 @@ import (
"github.com/veops/oneterm/internal/acl" "github.com/veops/oneterm/internal/acl"
"github.com/veops/oneterm/internal/model" "github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
myErrors "github.com/veops/oneterm/pkg/errors"
) )
var ( var (
@@ -26,13 +27,13 @@ var (
func (c *Controller) PostConfig(ctx *gin.Context) { func (c *Controller) PostConfig(ctx *gin.Context) {
currentUser, _ := acl.GetSessionFromCtx(ctx) currentUser, _ := acl.GetSessionFromCtx(ctx)
if !acl.IsAdmin(currentUser) { if !acl.IsAdmin(currentUser) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.WRITE}}) ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.WRITE}})
return return
} }
cfg := &model.Config{} cfg := &model.Config{}
if err := ctx.ShouldBindBodyWithJSON(cfg); err != nil { if err := ctx.ShouldBindBodyWithJSON(cfg); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
@@ -40,7 +41,7 @@ func (c *Controller) PostConfig(ctx *gin.Context) {
cfg.UpdaterId = currentUser.GetUid() cfg.UpdaterId = currentUser.GetUid()
if err := configService.SaveConfig(ctx, cfg); err != nil { if err := configService.SaveConfig(ctx, cfg); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -56,14 +57,14 @@ func (c *Controller) PostConfig(ctx *gin.Context) {
func (c *Controller) GetConfig(ctx *gin.Context) { func (c *Controller) GetConfig(ctx *gin.Context) {
currentUser, _ := acl.GetSessionFromCtx(ctx) currentUser, _ := acl.GetSessionFromCtx(ctx)
if !cast.ToBool(ctx.Query("info")) && !acl.IsAdmin(currentUser) { if !cast.ToBool(ctx.Query("info")) && !acl.IsAdmin(currentUser) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.READ}}) ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.READ}})
return return
} }
cfg, err := configService.GetConfig(ctx) cfg, err := configService.GetConfig(ctx)
if err != nil { if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
} }

View File

@@ -37,6 +37,7 @@ import (
gsession "github.com/veops/oneterm/internal/session" gsession "github.com/veops/oneterm/internal/session"
"github.com/veops/oneterm/internal/tunneling" "github.com/veops/oneterm/internal/tunneling"
dbpkg "github.com/veops/oneterm/pkg/db" dbpkg "github.com/veops/oneterm/pkg/db"
myErrors "github.com/veops/oneterm/pkg/errors"
"github.com/veops/oneterm/pkg/logger" "github.com/veops/oneterm/pkg/logger"
) )
@@ -163,7 +164,7 @@ func HandleTerm(sess *gsession.Session) (err error) {
return return
case <-sess.IdleTk.C: case <-sess.IdleTk.C:
writeErrMsg(sess, "idle timeout\n\n") writeErrMsg(sess, "idle timeout\n\n")
return &ApiError{Code: ErrIdleTimeout, Data: map[string]any{"second": model.GlobalConfig.Load().Timeout}} return &myErrors.ApiError{Code: myErrors.ErrIdleTimeout, Data: map[string]any{"second": model.GlobalConfig.Load().Timeout}}
case <-tk1m.C: case <-tk1m.C:
if dbpkg.DB.Model(asset).Where("id = ?", sess.AssetId).First(asset).Error != nil { if dbpkg.DB.Model(asset).Where("id = ?", sess.AssetId).First(asset).Error != nil {
continue continue
@@ -171,11 +172,11 @@ func HandleTerm(sess *gsession.Session) (err error) {
if checkTime(asset.AccessAuth) && (sess.ShareId == 0 || time.Now().Before(sess.ShareEnd)) { if checkTime(asset.AccessAuth) && (sess.ShareId == 0 || time.Now().Before(sess.ShareEnd)) {
continue continue
} }
return &ApiError{Code: ErrAccessTime} return &myErrors.ApiError{Code: myErrors.ErrAccessTime}
case closeBy := <-chs.CloseChan: case closeBy := <-chs.CloseChan:
writeErrMsg(sess, "closed by admin\n\n") writeErrMsg(sess, "closed by admin\n\n")
logger.L().Info("closed by", zap.String("admin", closeBy)) logger.L().Info("closed by", zap.String("admin", closeBy))
return &ApiError{Code: ErrAdminClose, Data: map[string]any{"admin": closeBy}} return &myErrors.ApiError{Code: myErrors.ErrAdminClose, Data: map[string]any{"admin": closeBy}}
case err = <-chs.ErrChan: case err = <-chs.ErrChan:
writeErrMsg(sess, err.Error()) writeErrMsg(sess, err.Error())
return return
@@ -257,7 +258,7 @@ func handleGuacd(sess *gsession.Session) (err error) {
case <-sess.Gctx.Done(): case <-sess.Gctx.Done():
return nil return nil
case <-sess.IdleTk.C: case <-sess.IdleTk.C:
return &ApiError{Code: ErrIdleTimeout, Data: map[string]any{"second": model.GlobalConfig.Load().Timeout}} return &myErrors.ApiError{Code: myErrors.ErrIdleTimeout, Data: map[string]any{"second": model.GlobalConfig.Load().Timeout}}
case <-tk.C: case <-tk.C:
if dbpkg.DB.Model(asset).Where("id = ?", sess.AssetId).First(asset).Error != nil { if dbpkg.DB.Model(asset).Where("id = ?", sess.AssetId).First(asset).Error != nil {
continue continue
@@ -265,9 +266,9 @@ func handleGuacd(sess *gsession.Session) (err error) {
if checkTime(asset.AccessAuth) && (sess.ShareId == 0 || time.Now().Before(sess.ShareEnd)) { if checkTime(asset.AccessAuth) && (sess.ShareId == 0 || time.Now().Before(sess.ShareEnd)) {
continue continue
} }
return &ApiError{Code: ErrAccessTime} return &myErrors.ApiError{Code: myErrors.ErrAccessTime}
case closeBy := <-chs.CloseChan: case closeBy := <-chs.CloseChan:
return &ApiError{Code: ErrAdminClose, Data: map[string]any{"admin": closeBy}} return &myErrors.ApiError{Code: myErrors.ErrAdminClose, Data: map[string]any{"admin": closeBy}}
case err := <-chs.ErrChan: case err := <-chs.ErrChan:
return err return err
case out := <-chs.OutChan: case out := <-chs.OutChan:
@@ -350,11 +351,11 @@ func DoConnect(ctx *gin.Context, ws *websocket.Conn) (sess *gsession.Session, er
} }
if !checkTime(asset.AccessAuth) { if !checkTime(asset.AccessAuth) {
err = &ApiError{Code: ErrAccessTime} err = &myErrors.ApiError{Code: myErrors.ErrAccessTime}
return return
} }
if !hasAuthorization(ctx, sess) { if !hasAuthorization(ctx, sess) {
err = &ApiError{Code: ErrUnauthorized} err = &myErrors.ApiError{Code: myErrors.ErrUnauthorized}
return return
} }
@@ -371,7 +372,7 @@ func DoConnect(ctx *gin.Context, ws *websocket.Conn) (sess *gsession.Session, er
if err = <-sess.Chans.ErrChan; err != nil { if err = <-sess.Chans.ErrChan; err != nil {
logger.L().Error("failed to connect", zap.Error(err)) logger.L().Error("failed to connect", zap.Error(err))
err = &ApiError{Code: ErrConnectServer, Data: map[string]any{"err": err}} err = &myErrors.ApiError{Code: myErrors.ErrConnectServer, Data: map[string]any{"err": err}}
return return
} }
@@ -754,12 +755,12 @@ func (c *Controller) ConnectMonitor(ctx *gin.Context) {
}() }()
if !acl.IsAdmin(currentUser) { if !acl.IsAdmin(currentUser) {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": "monitor session"}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": "monitor session"}})
return return
} }
if sess = gsession.GetOnlineSessionById(sessionId); sess == nil { if sess = gsession.GetOnlineSessionById(sessionId); sess == nil {
err = &ApiError{Code: ErrInvalidSessionId, Data: map[string]any{"sessionId": sessionId}} err = &myErrors.ApiError{Code: myErrors.ErrInvalidSessionId, Data: map[string]any{"sessionId": sessionId}}
return return
} }
@@ -860,7 +861,7 @@ func monitGuacd(ctx *gin.Context, sess *gsession.Session, chs *gsession.SessionC
func (c *Controller) ConnectClose(ctx *gin.Context) { func (c *Controller) ConnectClose(ctx *gin.Context) {
currentUser, _ := acl.GetSessionFromCtx(ctx) currentUser, _ := acl.GetSessionFromCtx(ctx)
if !acl.IsAdmin(currentUser) { if !acl.IsAdmin(currentUser) {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": "close session"}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": "close session"}})
return return
} }
@@ -876,7 +877,7 @@ func (c *Controller) ConnectClose(ctx *gin.Context) {
return return
} }
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": "invalid session id"}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": "invalid session id"}})
return return
} }
@@ -961,9 +962,9 @@ func handleError(ctx *gin.Context, sess *gsession.Session, err error, ws *websoc
return return
} }
logger.L().Debug("", zap.String("session_id", sess.SessionId), zap.Error(err)) logger.L().Debug("", zap.String("session_id", sess.SessionId), zap.Error(err))
ae, ok := err.(*ApiError) ae, ok := err.(*myErrors.ApiError)
if sess.IsGuacd() { if sess.IsGuacd() {
ws.WriteMessage(websocket.TextMessage, guacd.NewInstruction("error", lo.Ternary(ok, (ae).MessageBase64(ctx), err.Error()), cast.ToString(ErrAdminClose)).Bytes()) ws.WriteMessage(websocket.TextMessage, guacd.NewInstruction("error", lo.Ternary(ok, (ae).MessageBase64(ctx), err.Error()), cast.ToString(myErrors.ErrAdminClose)).Bytes())
} else { } else {
writeErrMsg(sess, lo.Ternary(ok, ae.MessageWithCtx(ctx), err.Error())) writeErrMsg(sess, lo.Ternary(ok, ae.MessageWithCtx(ctx), err.Error()))
} }

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"net/http" "net/http"
"reflect" "reflect"
"time" "time"
@@ -20,6 +19,7 @@ import (
"github.com/veops/oneterm/internal/repository" "github.com/veops/oneterm/internal/repository"
"github.com/veops/oneterm/pkg/config" "github.com/veops/oneterm/pkg/config"
dbpkg "github.com/veops/oneterm/pkg/db" dbpkg "github.com/veops/oneterm/pkg/db"
myErrors "github.com/veops/oneterm/pkg/errors"
"github.com/veops/oneterm/pkg/remote" "github.com/veops/oneterm/pkg/remote"
) )
@@ -66,7 +66,7 @@ func doCreate[T model.Model](ctx *gin.Context, needAcl bool, md T, resourceType
currentUser, _ := acl.GetSessionFromCtx(ctx) currentUser, _ := acl.GetSessionFromCtx(ctx)
if err = ctx.ShouldBindBodyWithJSON(md); err != nil { if err = ctx.ShouldBindBodyWithJSON(md); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
@@ -128,10 +128,10 @@ func doCreate[T model.Model](ctx *gin.Context, needAcl bool, md T, resourceType
return return
}); err != nil { }); err != nil {
if errors.Is(err, gorm.ErrDuplicatedKey) { if errors.Is(err, gorm.ErrDuplicatedKey) {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrDuplicateName, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrDuplicateName, Data: map[string]any{"err": err}})
return return
} }
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -151,7 +151,7 @@ func doDelete[T model.Model](ctx *gin.Context, needAcl bool, md T, resourceType
id, err := cast.ToIntE(ctx.Param("id")) id, err := cast.ToIntE(ctx.Param("id"))
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
@@ -164,11 +164,11 @@ func doDelete[T model.Model](ctx *gin.Context, needAcl bool, md T, resourceType
}) })
return return
} }
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
if needAcl && !hasPerm(ctx, md, resourceType, acl.DELETE) { if needAcl && !hasPerm(ctx, md, resourceType, acl.DELETE) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.DELETE}}) ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.DELETE}})
return return
} }
for _, dc := range dcs { for _, dc := range dcs {
@@ -212,10 +212,10 @@ func doDelete[T model.Model](ctx *gin.Context, needAcl bool, md T, resourceType
return return
}); err != nil { }); err != nil {
if errors.Is(err, gorm.ErrDuplicatedKey) { if errors.Is(err, gorm.ErrDuplicatedKey) {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrDuplicateName, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrDuplicateName, Data: map[string]any{"err": err}})
return return
} }
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -235,12 +235,12 @@ func doUpdate[T model.Model](ctx *gin.Context, needAcl bool, md T, resourceType
id, err := cast.ToIntE(ctx.Param("id")) id, err := cast.ToIntE(ctx.Param("id"))
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
if err = ctx.ShouldBindBodyWithJSON(md); err != nil { if err = ctx.ShouldBindBodyWithJSON(md); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
md.SetUpdaterId(currentUser.Uid) md.SetUpdaterId(currentUser.Uid)
@@ -261,7 +261,7 @@ func doUpdate[T model.Model](ctx *gin.Context, needAcl bool, md T, resourceType
ctx.JSON(http.StatusOK, defaultHttpResponse) ctx.JSON(http.StatusOK, defaultHttpResponse)
return return
} }
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
if needAcl { if needAcl {
@@ -269,7 +269,7 @@ func doUpdate[T model.Model](ctx *gin.Context, needAcl bool, md T, resourceType
// fmt.Printf("%+v\n", old) // fmt.Printf("%+v\n", old)
// fmt.Printf("%+v\n", md) // fmt.Printf("%+v\n", md)
if !hasPerm(ctx, md, resourceType, acl.WRITE) { if !hasPerm(ctx, md, resourceType, acl.WRITE) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.WRITE}}) ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.WRITE}})
return return
} }
@@ -316,10 +316,10 @@ func doUpdate[T model.Model](ctx *gin.Context, needAcl bool, md T, resourceType
return return
}); err != nil { }); err != nil {
if errors.Is(err, gorm.ErrDuplicatedKey) { if errors.Is(err, gorm.ErrDuplicatedKey) {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrDuplicateName, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrDuplicateName, Data: map[string]any{"err": err}})
return return
} }
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -337,7 +337,7 @@ func doGet[T any](ctx *gin.Context, needAcl bool, dbFind *gorm.DB, resourceType
if needAcl && !acl.IsAdmin(currentUser) { if needAcl && !acl.IsAdmin(currentUser) {
if dbFind, err = handleAcl[T](ctx, dbFind, resourceType); err != nil { if dbFind, err = handleAcl[T](ctx, dbFind, resourceType); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
} }
@@ -365,7 +365,7 @@ func doGet[T any](ctx *gin.Context, needAcl bool, dbFind *gorm.DB, resourceType
Error Error
}) })
if err = eg.Wait(); err != nil { if err = eg.Wait(); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -404,76 +404,15 @@ func handleRemoteErr(ctx *gin.Context, err error) {
switch e := err.(type) { switch e := err.(type) {
case *remote.RemoteError: case *remote.RemoteError:
if e.HttpCode == http.StatusBadRequest { if e.HttpCode == http.StatusBadRequest {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrRemoteClient, Data: e.Resp}) ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrRemoteClient, Data: e.Resp})
return return
} }
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrRemoteServer, Data: e.Resp}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrRemoteServer, Data: e.Resp})
default: default:
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
} }
} }
func filterSearch(ctx *gin.Context, db *gorm.DB, fields ...string) *gorm.DB {
q, ok := ctx.GetQuery("search")
if !ok || len(fields) <= 0 {
return db
}
d := dbpkg.DB
for _, f := range fields {
d = d.Or(fmt.Sprintf("%s LIKE ?", f), fmt.Sprintf("%%%s%%", q))
}
db = db.Where(d)
return db
}
func filterStartEnd(ctx *gin.Context, db *gorm.DB) (*gorm.DB, error) {
if q, ok := ctx.GetQuery("start"); ok {
t, err := time.Parse(time.RFC3339, q)
if err != nil {
ctx.AbortWithError(http.StatusBadRequest, err)
return db, err
}
db = db.Where("created_at >= ?", t)
}
if q, ok := ctx.GetQuery("end"); ok {
t, err := time.Parse(time.RFC3339, q)
if err != nil {
ctx.AbortWithError(http.StatusBadRequest, err)
return db, err
}
db = db.Where("created_at <= ?", t)
}
return db, nil
}
func filterEqual(ctx *gin.Context, db *gorm.DB, fields ...string) *gorm.DB {
for _, f := range fields {
if q, ok := ctx.GetQuery(f); ok {
db = db.Where(fmt.Sprintf("%s = ?", f), q)
}
}
return db
}
func filterLike(ctx *gin.Context, db *gorm.DB, fields ...string) *gorm.DB {
likes := false
d := dbpkg.DB
for _, f := range fields {
if q, ok := ctx.GetQuery(f); ok && q != "" {
d = d.Or(fmt.Sprintf("%s LIKE ?", f), fmt.Sprintf("%%%s%%", q))
likes = true
}
}
if !likes {
return db
}
db = db.Where(d)
return db
}
func toMap(data any) model.Map[string, any] { func toMap(data any) model.Map[string, any] {
bs, _ := json.Marshal(data) bs, _ := json.Marshal(data)
res := make(map[string]any) res := make(map[string]any)
@@ -542,7 +481,7 @@ func handlePermissions[T any](ctx *gin.Context, data []T, resourceTypeName strin
case []*model.Node: case []*model.Node:
resId2perms, err = handleSelfChildPerms(ctx, resId2perms) resId2perms, err = handleSelfChildPerms(ctx, resId2perms)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
case []*model.Asset: case []*model.Asset:
@@ -553,7 +492,7 @@ func handlePermissions[T any](ctx *gin.Context, data []T, resourceTypeName strin
} }
nodeResId2perms := lo.SliceToMap(res, func(r *acl.Resource) (int, []string) { return r.ResourceId, r.Permissions }) nodeResId2perms := lo.SliceToMap(res, func(r *acl.Resource) (int, []string) { return r.ResourceId, r.Permissions })
if nodeResId2perms, err = handleSelfChildPerms(ctx, nodeResId2perms); err != nil { if nodeResId2perms, err = handleSelfChildPerms(ctx, nodeResId2perms); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
var nodeId2ResId map[int]int var nodeId2ResId map[int]int

View File

@@ -16,6 +16,7 @@ import (
"github.com/veops/oneterm/internal/model" "github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
gsession "github.com/veops/oneterm/internal/session" gsession "github.com/veops/oneterm/internal/session"
"github.com/veops/oneterm/pkg/errors"
"github.com/veops/oneterm/pkg/logger" "github.com/veops/oneterm/pkg/logger"
) )
@@ -85,7 +86,7 @@ func (c *Controller) GetFileHistory(ctx *gin.Context) {
// Use global file service // Use global file service
histories, count, err := service.DefaultFileService.GetFileHistory(ctx, filters) histories, count, err := service.DefaultFileService.GetFileHistory(ctx, filters)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -122,14 +123,14 @@ func (c *Controller) FileLS(ctx *gin.Context) {
} }
if !hasAuthorization(ctx, sess) { if !hasAuthorization(ctx, sess) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{}}) ctx.AbortWithError(http.StatusForbidden, &errors.ApiError{Code: errors.ErrNoPerm, Data: map[string]any{}})
return return
} }
// Use global file service // Use global file service
info, err := service.DefaultFileService.ReadDir(ctx, sess.Session.AssetId, sess.Session.AccountId, ctx.Query("dir")) info, err := service.DefaultFileService.ReadDir(ctx, sess.Session.AssetId, sess.Session.AccountId, ctx.Query("dir"))
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
@@ -166,13 +167,13 @@ func (c *Controller) FileMkdir(ctx *gin.Context) {
} }
if !hasAuthorization(ctx, sess) { if !hasAuthorization(ctx, sess) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{}}) ctx.AbortWithError(http.StatusForbidden, &errors.ApiError{Code: errors.ErrNoPerm, Data: map[string]any{}})
return return
} }
// Use global file service // Use global file service
if err := service.DefaultFileService.MkdirAll(ctx, sess.Session.AssetId, sess.Session.AccountId, ctx.Query("dir")); err != nil { if err := service.DefaultFileService.MkdirAll(ctx, sess.Session.AssetId, sess.Session.AccountId, ctx.Query("dir")); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
@@ -213,31 +214,31 @@ func (c *Controller) FileUpload(ctx *gin.Context) {
} }
if !hasAuthorization(ctx, sess) { if !hasAuthorization(ctx, sess) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{}}) ctx.AbortWithError(http.StatusForbidden, &errors.ApiError{Code: errors.ErrNoPerm, Data: map[string]any{}})
return return
} }
f, fh, err := ctx.Request.FormFile("file") f, fh, err := ctx.Request.FormFile("file")
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
content, err := io.ReadAll(f) content, err := io.ReadAll(f)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
// Use global file service // Use global file service
rf, err := service.DefaultFileService.Create(ctx, sess.Session.AssetId, sess.Session.AccountId, filepath.Join(ctx.Query("dir"), fh.Filename)) rf, err := service.DefaultFileService.Create(ctx, sess.Session.AssetId, sess.Session.AccountId, filepath.Join(ctx.Query("dir"), fh.Filename))
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
if _, err = rf.Write(content); err != nil { if _, err = rf.Write(content); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -281,14 +282,14 @@ func (c *Controller) FileDownload(ctx *gin.Context) {
} }
if !hasAuthorization(ctx, sess) { if !hasAuthorization(ctx, sess) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{}}) ctx.AbortWithError(http.StatusForbidden, &errors.ApiError{Code: errors.ErrNoPerm, Data: map[string]any{}})
return return
} }
// Use global file service // Use global file service
rf, err := service.DefaultFileService.Open(ctx, sess.Session.AssetId, sess.Session.AccountId, filepath.Join(ctx.Query("dir"), ctx.Query("filename"))) rf, err := service.DefaultFileService.Open(ctx, sess.Session.AssetId, sess.Session.AccountId, filepath.Join(ctx.Query("dir"), ctx.Query("filename")))
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
@@ -296,7 +297,7 @@ func (c *Controller) FileDownload(ctx *gin.Context) {
content, err := io.ReadAll(rf) content, err := io.ReadAll(rf)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }

View File

@@ -11,6 +11,7 @@ import (
"github.com/veops/oneterm/internal/model" "github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
"github.com/veops/oneterm/pkg/config" "github.com/veops/oneterm/pkg/config"
"github.com/veops/oneterm/pkg/errors"
) )
var ( var (
@@ -20,7 +21,7 @@ var (
// Validate public key // Validate public key
func(ctx *gin.Context, data *model.Gateway) { func(ctx *gin.Context, data *model.Gateway) {
if err := gatewayService.ValidatePublicKey(data); err != nil { if err := gatewayService.ValidatePublicKey(data); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrWrongPk, Data: nil}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrWrongPk, Data: nil})
return return
} }
}, },
@@ -51,7 +52,7 @@ var (
return return
} }
code := lo.Ternary(err == nil, http.StatusBadRequest, http.StatusInternalServerError) code := lo.Ternary(err == nil, http.StatusBadRequest, http.StatusInternalServerError)
err = lo.Ternary[error](err == nil, &ApiError{Code: ErrHasDepency, Data: map[string]any{"name": assetName}}, err) err = lo.Ternary[error](err == nil, &errors.ApiError{Code: errors.ErrHasDepency, Data: map[string]any{"name": assetName}}, err)
ctx.AbortWithError(code, err) ctx.AbortWithError(code, err)
}, },
} }
@@ -112,7 +113,7 @@ func (c *Controller) GetGateways(ctx *gin.Context) {
if info && !acl.IsAdmin(currentUser) { if info && !acl.IsAdmin(currentUser) {
assetIds, err := GetAssetIdsByAuthorization(ctx) assetIds, err := GetAssetIdsByAuthorization(ctx)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }

View File

@@ -7,6 +7,7 @@ import (
"github.com/veops/oneterm/internal/model" "github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
"github.com/veops/oneterm/pkg/errors"
) )
var ( var (
@@ -30,7 +31,7 @@ var (
func (c *Controller) GetHistories(ctx *gin.Context) { func (c *Controller) GetHistories(ctx *gin.Context) {
db, err := historyService.BuildQuery(ctx) db, err := historyService.BuildQuery(ctx)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -45,7 +46,7 @@ func (c *Controller) GetHistories(ctx *gin.Context) {
func (c *Controller) GetHistoryTypeMapping(ctx *gin.Context) { func (c *Controller) GetHistoryTypeMapping(ctx *gin.Context) {
mapping, err := historyService.GetTypeMapping(ctx) mapping, err := historyService.GetTypeMapping(ctx)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }

View File

@@ -13,6 +13,7 @@ import (
"github.com/veops/oneterm/internal/repository" "github.com/veops/oneterm/internal/repository"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
"github.com/veops/oneterm/pkg/config" "github.com/veops/oneterm/pkg/config"
"github.com/veops/oneterm/pkg/errors"
) )
var ( var (
@@ -31,7 +32,7 @@ var (
// @Router /node [post] // @Router /node [post]
func (c *Controller) CreateNode(ctx *gin.Context) { func (c *Controller) CreateNode(ctx *gin.Context) {
if err := nodeService.ClearCache(ctx); err != nil { if err := nodeService.ClearCache(ctx); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
doCreate(ctx, true, &model.Node{}, config.RESOURCE_NODE) doCreate(ctx, true, &model.Node{}, config.RESOURCE_NODE)
@@ -45,7 +46,7 @@ func (c *Controller) CreateNode(ctx *gin.Context) {
// @Router /node/:id [delete] // @Router /node/:id [delete]
func (c *Controller) DeleteNode(ctx *gin.Context) { func (c *Controller) DeleteNode(ctx *gin.Context) {
if err := nodeService.ClearCache(ctx); err != nil { if err := nodeService.ClearCache(ctx); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
doDelete(ctx, true, &model.Node{}, config.RESOURCE_NODE, nodeDcs...) doDelete(ctx, true, &model.Node{}, config.RESOURCE_NODE, nodeDcs...)
@@ -60,7 +61,7 @@ func (c *Controller) DeleteNode(ctx *gin.Context) {
// @Router /node/:id [put] // @Router /node/:id [put]
func (c *Controller) UpdateNode(ctx *gin.Context) { func (c *Controller) UpdateNode(ctx *gin.Context) {
if err := nodeService.ClearCache(ctx); err != nil { if err := nodeService.ClearCache(ctx); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
doUpdate(ctx, true, &model.Node{}, config.RESOURCE_NODE, nodePreHooks...) doUpdate(ctx, true, &model.Node{}, config.RESOURCE_NODE, nodePreHooks...)
@@ -85,7 +86,7 @@ func (c *Controller) GetNodes(ctx *gin.Context) {
db, err := nodeService.BuildQuery(ctx, currentUser, info) db, err := nodeService.BuildQuery(ctx, currentUser, info)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -94,7 +95,7 @@ func (c *Controller) GetNodes(ctx *gin.Context) {
func nodePreHookCheckCycle(ctx *gin.Context, data *model.Node) { func nodePreHookCheckCycle(ctx *gin.Context, data *model.Node) {
if err := nodeService.CheckCycle(ctx, data, cast.ToInt(ctx.Param("id"))); err != nil { if err := nodeService.CheckCycle(ctx, data, cast.ToInt(ctx.Param("id"))); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInvalidArgument})
} }
} }
@@ -113,12 +114,12 @@ func nodePostHookHasChild(ctx *gin.Context, data []*model.Node) {
func nodeDelHook(ctx *gin.Context, id int) { func nodeDelHook(ctx *gin.Context, id int) {
assetName, err := nodeService.CheckDependencies(ctx, id) assetName, err := nodeService.CheckDependencies(ctx, id)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
if assetName != "" { if assetName != "" {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrHasDepency, Data: map[string]any{"name": assetName}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrHasDepency, Data: map[string]any{"name": assetName}})
} }
} }

View File

@@ -7,6 +7,7 @@ import (
"github.com/veops/oneterm/internal/model" "github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
"github.com/veops/oneterm/pkg/errors"
) )
var ( var (
@@ -15,7 +16,7 @@ var (
publicKeyPreHooks = []preHook[*model.PublicKey]{ publicKeyPreHooks = []preHook[*model.PublicKey]{
func(ctx *gin.Context, data *model.PublicKey) { func(ctx *gin.Context, data *model.PublicKey) {
if err := publicKeyService.ValidatePublicKey(data); err != nil { if err := publicKeyService.ValidatePublicKey(data); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrWrongPk, Data: nil}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrWrongPk, Data: nil})
} }
}, },
func(ctx *gin.Context, data *model.PublicKey) { func(ctx *gin.Context, data *model.PublicKey) {

View File

@@ -8,6 +8,7 @@ import (
"github.com/veops/oneterm/internal/model" "github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
"github.com/veops/oneterm/pkg/errors"
) )
var ( var (
@@ -16,7 +17,6 @@ var (
sessionPostHooks = []postHook[*model.Session]{ sessionPostHooks = []postHook[*model.Session]{
func(ctx *gin.Context, data []*model.Session) { func(ctx *gin.Context, data []*model.Session) {
if err := sessionService.AttachCmdCounts(ctx, data); err != nil { if err := sessionService.AttachCmdCounts(ctx, data); err != nil {
// Error already logged in service
} }
}, },
func(ctx *gin.Context, data []*model.Session) { func(ctx *gin.Context, data []*model.Session) {
@@ -34,12 +34,12 @@ var (
func (c *Controller) CreateSessionCmd(ctx *gin.Context) { func (c *Controller) CreateSessionCmd(ctx *gin.Context) {
data := &model.SessionCmd{} data := &model.SessionCmd{}
if err := ctx.BindJSON(data); err != nil { if err := ctx.BindJSON(data); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
if err := sessionService.CreateSessionCmd(ctx, data); err != nil { if err := sessionService.CreateSessionCmd(ctx, data); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -63,7 +63,7 @@ func (c *Controller) CreateSessionCmd(ctx *gin.Context) {
func (c *Controller) GetSessions(ctx *gin.Context) { func (c *Controller) GetSessions(ctx *gin.Context) {
db, err := sessionService.BuildQuery(ctx) db, err := sessionService.BuildQuery(ctx)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
@@ -123,13 +123,13 @@ func (c *Controller) GetSessionOptionClientIp(ctx *gin.Context) {
func (c *Controller) CreateSessionReplay(ctx *gin.Context) { func (c *Controller) CreateSessionReplay(ctx *gin.Context) {
file, _, err := ctx.Request.FormFile("replay.cast") file, _, err := ctx.Request.FormFile("replay.cast")
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
sessionId := ctx.Param("session_id") sessionId := ctx.Param("session_id")
if err := sessionService.CreateSessionReplay(ctx, sessionId, file); err != nil { if err := sessionService.CreateSessionReplay(ctx, sessionId, file); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -147,7 +147,7 @@ func (c *Controller) GetSessionReplay(ctx *gin.Context) {
filename, err := sessionService.GetSessionReplayFilename(ctx, sessionId) filename, err := sessionService.GetSessionReplayFilename(ctx, sessionId)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }

View File

@@ -9,6 +9,7 @@ import (
"github.com/veops/oneterm/internal/acl" "github.com/veops/oneterm/internal/acl"
"github.com/veops/oneterm/internal/model" "github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service" "github.com/veops/oneterm/internal/service"
"github.com/veops/oneterm/pkg/errors"
) )
var ( var (
@@ -26,13 +27,13 @@ func (c *Controller) CreateShare(ctx *gin.Context) {
shares := make([]*model.Share, 0) shares := make([]*model.Share, 0)
if err := ctx.ShouldBindBodyWithJSON(&shares); err != nil { if err := ctx.ShouldBindBodyWithJSON(&shares); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
for _, s := range shares { for _, s := range shares {
if !shareService.HasPermission(ctx, s, acl.GRANT) { if !shareService.HasPermission(ctx, s, acl.GRANT) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}}) ctx.AbortWithError(http.StatusForbidden, &errors.ApiError{Code: errors.ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}})
return return
} }
s.CreatorId = currentUser.GetUid() s.CreatorId = currentUser.GetUid()
@@ -41,7 +42,7 @@ func (c *Controller) CreateShare(ctx *gin.Context) {
uuids, err := shareService.CreateShares(ctx, shares) uuids, err := shareService.CreateShares(ctx, shares)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -58,12 +59,12 @@ func (c *Controller) DeleteShare(ctx *gin.Context) {
id := cast.ToInt(ctx.Param("id")) id := cast.ToInt(ctx.Param("id"))
share, err := shareService.GetShareByID(ctx, id) share, err := shareService.GetShareByID(ctx, id)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusBadRequest, &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
return return
} }
if !shareService.HasPermission(ctx, share, acl.GRANT) { if !shareService.HasPermission(ctx, share, acl.GRANT) {
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}}) ctx.AbortWithError(http.StatusForbidden, &errors.ApiError{Code: errors.ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}})
return return
} }
@@ -88,7 +89,7 @@ func (c *Controller) GetShare(ctx *gin.Context) {
db, err := shareService.BuildQuery(ctx, isAdmin) db, err := shareService.BuildQuery(ctx, isAdmin)
if err != nil { if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) ctx.AbortWithError(http.StatusInternalServerError, &errors.ApiError{Code: errors.ErrInternal, Data: map[string]any{"err": err}})
return return
} }
@@ -108,7 +109,7 @@ func (c *Controller) ConnectShare(ctx *gin.Context) {
uuid := ctx.Param("uuid") uuid := ctx.Param("uuid")
share, err := shareService.ValidateShareForConnection(ctx, uuid) share, err := shareService.ValidateShareForConnection(ctx, uuid)
if err != nil { if err != nil {
ctx.Set("shareErr", &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) ctx.Set("shareErr", &errors.ApiError{Code: errors.ErrInvalidArgument, Data: map[string]any{"err": err}})
} }
shareService.SetupConnectionParams(ctx, share) shareService.SetupConnectionParams(ctx, share)

View File

@@ -7,12 +7,12 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"github.com/veops/oneterm/internal/acl" "github.com/veops/oneterm/internal/acl"
"github.com/veops/oneterm/internal/api/controller" "github.com/veops/oneterm/pkg/errors"
"github.com/veops/oneterm/pkg/logger" "github.com/veops/oneterm/pkg/logger"
) )
var ( var (
errUnauthorized = &controller.ApiError{Code: controller.ErrUnauthorized} errUnauthorized = &errors.ApiError{Code: errors.ErrUnauthorized}
) )
func AuthMiddleware() gin.HandlerFunc { func AuthMiddleware() gin.HandlerFunc {

View File

@@ -8,8 +8,8 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/nicksnyder/go-i18n/v2/i18n" "github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/veops/oneterm/internal/api/controller"
myi18n "github.com/veops/oneterm/internal/i18n" myi18n "github.com/veops/oneterm/internal/i18n"
"github.com/veops/oneterm/pkg/errors"
) )
type bodyWriter struct { type bodyWriter struct {
@@ -47,7 +47,7 @@ func Error2RespMiddleware() gin.HandlerFunc {
e := ctx.Errors.Last().Err e := ctx.Errors.Last().Err
obj["message"] = e.Error() obj["message"] = e.Error()
ae, ok := e.(*controller.ApiError) ae, ok := e.(*errors.ApiError)
if ok { if ok {
lang := ctx.PostForm("lang") lang := ctx.PostForm("lang")
accept := ctx.GetHeader("Accept-Language") accept := ctx.GetHeader("Accept-Language")

View File

@@ -1,4 +1,4 @@
package controller package errors
import ( import (
"encoding/base64" "encoding/base64"