mirror of
https://github.com/veops/oneterm.git
synced 2025-10-22 23:09:31 +08:00
feat(api): permission
This commit is contained in:
@@ -45,7 +45,7 @@ func migrateNode() {
|
||||
}
|
||||
|
||||
nodes := make([]*model.Node, 0)
|
||||
if err = mysql.DB.Model(&nodes).Where("resource_id IS NULL").Find(&nodes).Error; err != nil {
|
||||
if err = mysql.DB.Model(&nodes).Where("resource_id=0").Find(&nodes).Error; err != nil {
|
||||
logger.L().Fatal("get nodes failed", zap.Error(err))
|
||||
}
|
||||
eg := errgroup.Group{}
|
||||
|
@@ -3,13 +3,11 @@ package acl
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/cast"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
redis "github.com/veops/oneterm/cache"
|
||||
"github.com/veops/oneterm/conf"
|
||||
"github.com/veops/oneterm/remote"
|
||||
)
|
||||
@@ -19,10 +17,10 @@ const (
|
||||
)
|
||||
|
||||
func GetRoleResources(ctx context.Context, rid int, resourceTypeId string) (res []*Resource, err error) {
|
||||
k := fmt.Sprintf(kFmtResources, resourceTypeId, rid)
|
||||
if err = redis.Get(ctx, k, &res); err == nil {
|
||||
return
|
||||
}
|
||||
// k := fmt.Sprintf(kFmtResources, resourceTypeId, rid)
|
||||
// if err = redis.Get(ctx, k, &res); err == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
token, err := remote.GetAclToken(ctx)
|
||||
if err != nil {
|
||||
@@ -46,7 +44,7 @@ func GetRoleResources(ctx context.Context, rid int, resourceTypeId string) (res
|
||||
|
||||
res = data.Resources
|
||||
|
||||
redis.SetEx(ctx, k, res, time.Minute)
|
||||
// redis.SetEx(ctx, k, res, time.Minute)
|
||||
|
||||
return
|
||||
}
|
||||
|
@@ -2,10 +2,8 @@ package controller
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/samber/lo"
|
||||
@@ -14,7 +12,6 @@ import (
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/veops/oneterm/acl"
|
||||
redis "github.com/veops/oneterm/cache"
|
||||
"github.com/veops/oneterm/conf"
|
||||
mysql "github.com/veops/oneterm/db"
|
||||
"github.com/veops/oneterm/model"
|
||||
@@ -166,12 +163,12 @@ func (c *Controller) GetAccounts(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
func GetAccountIdsByAuthorization(ctx *gin.Context) (ids []int, err error) {
|
||||
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
// currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
|
||||
k := fmt.Sprintf(kFmtAccountIds, currentUser.GetUid())
|
||||
if err = redis.Get(ctx, k, &ids); err == nil {
|
||||
return
|
||||
}
|
||||
// k := fmt.Sprintf(kFmtAccountIds, currentUser.GetUid())
|
||||
// if err = redis.Get(ctx, k, &ids); err == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
assetIds, err := GetAssetIdsByAuthorization(ctx)
|
||||
if err != nil {
|
||||
@@ -187,7 +184,7 @@ func GetAccountIdsByAuthorization(ctx *gin.Context) (ids []int, err error) {
|
||||
_, _, accountIds := getIdsByAuthorizationIds(ctx)
|
||||
ids = lo.Uniq(append(ids, accountIds...))
|
||||
|
||||
redis.SetEx(ctx, k, ids, time.Minute)
|
||||
// redis.SetEx(ctx, k, ids, time.Minute)
|
||||
|
||||
return
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/samber/lo"
|
||||
@@ -13,7 +12,6 @@ import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/veops/oneterm/acl"
|
||||
redis "github.com/veops/oneterm/cache"
|
||||
"github.com/veops/oneterm/conf"
|
||||
mysql "github.com/veops/oneterm/db"
|
||||
"github.com/veops/oneterm/logger"
|
||||
@@ -154,12 +152,21 @@ func assetPostHookAuth(ctx *gin.Context, data []*model.Asset) {
|
||||
if acl.IsAdmin(currentUser) {
|
||||
return
|
||||
}
|
||||
info := cast.ToBool(ctx.Query("info"))
|
||||
noInfoIds := make([]int, 0)
|
||||
if !info {
|
||||
t := mysql.DB.Model(&model.Asset{})
|
||||
assetResIds, _ := acl.GetRoleResourceIds(ctx, currentUser.GetRid(), conf.RESOURCE_ASSET)
|
||||
t, _ = handleAssetIds(ctx, t, assetResIds)
|
||||
t.Pluck("id", &noInfoIds)
|
||||
}
|
||||
|
||||
authorizationIds, _ := ctx.Value(kAuthorizationIds).([]*model.AuthorizationIds)
|
||||
nodeIds, _, accountIds := getIdsByAuthorizationIds(ctx)
|
||||
nodeIds, _ = handleSelfChild(ctx, nodeIds...)
|
||||
|
||||
for _, a := range data {
|
||||
if lo.Contains(nodeIds, a.ParentId) {
|
||||
if lo.Contains(nodeIds, a.ParentId) || lo.Contains(noInfoIds, a.Id) {
|
||||
continue
|
||||
}
|
||||
if lo.ContainsBy(authorizationIds, func(item *model.AuthorizationIds) bool {
|
||||
@@ -203,7 +210,7 @@ func handleParentId(ctx context.Context, parentId int) (pids []int, err error) {
|
||||
}
|
||||
|
||||
func GetAssetIdsByAuthorization(ctx *gin.Context) (ids []int, err error) {
|
||||
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
// currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
|
||||
authIds, err := getAuthorizationIds(ctx)
|
||||
if err != nil {
|
||||
@@ -211,10 +218,10 @@ func GetAssetIdsByAuthorization(ctx *gin.Context) (ids []int, err error) {
|
||||
}
|
||||
ctx.Set(kAuthorizationIds, authIds)
|
||||
|
||||
k := fmt.Sprintf(kFmtAssetIds, currentUser.GetUid())
|
||||
if err = redis.Get(ctx, k, &ids); err == nil {
|
||||
return
|
||||
}
|
||||
// k := fmt.Sprintf(kFmtAssetIds, currentUser.GetUid())
|
||||
// if err = redis.Get(ctx, k, &ids); err == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
nodeIds, ids, accountIds := getIdsByAuthorizationIds(ctx)
|
||||
|
||||
@@ -231,21 +238,22 @@ func GetAssetIdsByAuthorization(ctx *gin.Context) (ids []int, err error) {
|
||||
}
|
||||
ids = lo.Uniq(append(ids, tmp...))
|
||||
|
||||
redis.SetEx(ctx, k, ids, time.Minute)
|
||||
// redis.SetEx(ctx, k, ids, time.Minute)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getIdsByAuthorizationIds(ctx context.Context) (nodeIds, assetIds, accountIds []int) {
|
||||
func getIdsByAuthorizationIds(ctx *gin.Context) (nodeIds, assetIds, accountIds []int) {
|
||||
authIds, _ := ctx.Value(kAuthorizationIds).([]*model.AuthorizationIds)
|
||||
info := cast.ToBool(ctx.Query("info"))
|
||||
for _, a := range authIds {
|
||||
if a.NodeId != 0 && a.AssetId == 0 && a.AccountId == 0 {
|
||||
nodeIds = append(nodeIds, a.NodeId)
|
||||
}
|
||||
if a.AssetId != 0 && a.NodeId == 0 && a.AccountId == 0 {
|
||||
if a.AssetId != 0 && a.NodeId == 0 && (info || a.AccountId == 0) {
|
||||
assetIds = append(assetIds, a.AssetId)
|
||||
}
|
||||
if a.AccountId != 0 && a.AssetId == 0 && a.NodeId == 0 {
|
||||
if a.AccountId != 0 && a.AssetId == 0 && (info || a.NodeId == 0) {
|
||||
accountIds = append(accountIds, a.AccountId)
|
||||
}
|
||||
}
|
||||
@@ -253,6 +261,11 @@ func getIdsByAuthorizationIds(ctx context.Context) (nodeIds, assetIds, accountId
|
||||
}
|
||||
|
||||
func getAssetIdsByNodeAccount(ctx context.Context, nodeIds, accountIds []int) (assetIds []int, err error) {
|
||||
err = mysql.DB.WithContext(ctx).Model(&model.Asset{}).Where("parent_id IN?", nodeIds).Or("JSON_KEYS(authorization) IN ?", accountIds).Pluck("id", &assetIds).Error
|
||||
db := mysql.DB.WithContext(ctx).Model(&model.Asset{}).Where("parent_id IN ?", nodeIds)
|
||||
if len(accountIds) > 0 {
|
||||
db = db.Or(fmt.Sprintf("JSON_CONTAINS_PATH(authorization,'one',%s)",
|
||||
strings.Join(lo.Map(accountIds, func(id int, _ int) string { return fmt.Sprintf("'$.\"%d\"'", id) }), ",")))
|
||||
}
|
||||
err = db.Pluck("id", &assetIds).Error
|
||||
return
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/samber/lo"
|
||||
@@ -15,7 +14,6 @@ import (
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/veops/oneterm/acl"
|
||||
redis "github.com/veops/oneterm/cache"
|
||||
"github.com/veops/oneterm/conf"
|
||||
mysql "github.com/veops/oneterm/db"
|
||||
"github.com/veops/oneterm/logger"
|
||||
@@ -123,20 +121,14 @@ func (c *Controller) GetAuthorizations(ctx *gin.Context) {
|
||||
auth := &model.Authorization{}
|
||||
db := mysql.DB.Model(auth)
|
||||
for _, k := range []string{"node_id", "asset_id", "account_id"} {
|
||||
q, ok := ctx.GetQuery(k)
|
||||
if ok {
|
||||
q, _ := ctx.GetQuery(k)
|
||||
db = db.Where(fmt.Sprintf("%s=?", k), cast.ToInt(q))
|
||||
switch k {
|
||||
case "node_id":
|
||||
auth.NodeId = cast.ToInt(q)
|
||||
case "asset_id":
|
||||
auth.AssetId = cast.ToInt(q)
|
||||
case "account_id":
|
||||
auth.AccountId = cast.ToInt(q)
|
||||
}
|
||||
} else {
|
||||
db = db.Where("?=0", k)
|
||||
}
|
||||
t := db.Session(&gorm.Session{})
|
||||
|
||||
if err := t.First(&auth).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}})
|
||||
return
|
||||
}
|
||||
|
||||
if !hasPermAuthorization(ctx, auth, acl.GRANT) {
|
||||
@@ -213,7 +205,11 @@ func hasPermAuthorization(ctx context.Context, auth *model.Authorization, action
|
||||
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
|
||||
if ok = acl.IsAdmin(currentUser); ok {
|
||||
return true
|
||||
return
|
||||
}
|
||||
|
||||
if ok = auth == nil || auth.Id == 0; ok {
|
||||
return
|
||||
}
|
||||
|
||||
nodeIds, assetIds, accountIds, err := getGrantNodeAssetAccoutIds(ctx, action)
|
||||
@@ -233,41 +229,51 @@ func hasPermAuthorization(ctx context.Context, auth *model.Authorization, action
|
||||
}
|
||||
|
||||
func getAuthsByAsset(t *model.Asset) (data []*model.Authorization, err error) {
|
||||
db := mysql.DB.Model(data)
|
||||
for accountId := range t.Authorization {
|
||||
db = db.Or("asset_id=? AND account_id=? AND node_id=NULL", t.Id, accountId)
|
||||
}
|
||||
err = db.Find(&data).Error
|
||||
|
||||
err = mysql.DB.Model(data).Where("asset_id=? AND account_id IN ? AND node_id=0", t.Id, lo.Without(lo.Keys(t.Authorization), 0)).Find(&data).Error
|
||||
return
|
||||
}
|
||||
|
||||
func handleAuthorization(ctx *gin.Context, tx *gorm.DB, action int, asset *model.Asset, auths ...*model.Authorization) (err error) {
|
||||
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
|
||||
eg := &errgroup.Group{}
|
||||
|
||||
if asset != nil {
|
||||
if action == model.ACTION_UPDATE {
|
||||
if asset != nil && asset.Id > 0 {
|
||||
var pres []*model.Authorization
|
||||
pres, err = getAuthsByAsset(asset)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, pre := range pres {
|
||||
p := pre
|
||||
if _, ok := asset.Authorization[p.AccountId]; ok {
|
||||
auths = append(auths, p)
|
||||
} else {
|
||||
eg.Go(func() error {
|
||||
return acl.DeleteResource(ctx, currentUser.GetUid(), p.ResourceId)
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch action {
|
||||
case model.ACTION_CREATE:
|
||||
auths = lo.Map(lo.Keys(asset.Authorization), func(id int, _ int) *model.Authorization {
|
||||
return &model.Authorization{AssetId: asset.Id, AccountId: id, Rids: asset.Authorization[id]}
|
||||
})
|
||||
case model.ACTION_DELETE:
|
||||
auths = pres
|
||||
case model.ACTION_UPDATE:
|
||||
for _, pre := range pres {
|
||||
p := pre
|
||||
if v, ok := asset.Authorization[p.AccountId]; ok {
|
||||
p.Rids = v
|
||||
auths = append(auths, p)
|
||||
} else {
|
||||
eg.Go(func() (err error) {
|
||||
if err = acl.DeleteResource(ctx, currentUser.GetUid(), p.ResourceId); err != nil {
|
||||
return
|
||||
}
|
||||
if err = mysql.DB.Model(p).Where("id=?", p.Id).Delete(p).Error; err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
}
|
||||
preAccountsIds := lo.Map(pres, func(p *model.Authorization, _ int) int { return p.AccountId })
|
||||
for k, v := range asset.Authorization {
|
||||
if !lo.Contains(preAccountsIds, k) {
|
||||
auths = append(auths, &model.Authorization{AssetId: asset.Id, AccountId: k, Rids: v})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,9 +301,19 @@ func handleAuthorization(ctx *gin.Context, tx *gorm.DB, action int, asset *model
|
||||
case model.ACTION_UPDATE:
|
||||
eg.Go(func() (err error) {
|
||||
pre := &model.Authorization{}
|
||||
if err = mysql.DB.First(pre, auth.GetId()).Error; err != nil {
|
||||
if err = mysql.DB.Where("id=?", auth.GetId()).First(pre).Error; err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return
|
||||
}
|
||||
resourceId := 0
|
||||
if resourceId, err = acl.CreateGrantAcl(ctx, currentUser, conf.RESOURCE_AUTHORIZATION, auth.GetName()); err != nil {
|
||||
return
|
||||
}
|
||||
auth.ResourceId = resourceId
|
||||
if err = tx.Create(auth).Error; err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
revokeRids := lo.Without(pre.Rids, auth.Rids...)
|
||||
if len(revokeRids) > 0 {
|
||||
if err = acl.BatchRevokeRoleResource(ctx, currentUser.GetUid(), revokeRids, auth.ResourceId, []string{acl.READ}); err != nil {
|
||||
@@ -323,17 +339,17 @@ func handleAuthorization(ctx *gin.Context, tx *gorm.DB, action int, asset *model
|
||||
func getAuthorizations(ctx *gin.Context) (res []*acl.Resource, err error) {
|
||||
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
|
||||
k := fmt.Sprintf(kFmtAuthorizations, currentUser.GetUid())
|
||||
if err = redis.Get(ctx, k, &res); err == nil {
|
||||
return
|
||||
}
|
||||
// k := fmt.Sprintf(kFmtAuthorizations, currentUser.GetUid())
|
||||
// if err = redis.Get(ctx, k, &res); err == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
res, err = acl.GetRoleResources(ctx, currentUser.Acl.Rid, conf.RESOURCE_AUTHORIZATION)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
redis.SetEx(ctx, k, res, time.Minute)
|
||||
// redis.SetEx(ctx, k, res, time.Minute)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -367,12 +383,13 @@ func hasAuthorization(ctx *gin.Context, sess *gsession.Session) (ok bool) {
|
||||
return true
|
||||
}
|
||||
|
||||
k := fmt.Sprintf(kFmtHasAuthorization, currentUser.GetUid(), sess.AccountId, sess.AssetId)
|
||||
if err := redis.Get(ctx, k, &ok); err == nil {
|
||||
return
|
||||
}
|
||||
// k := fmt.Sprintf(kFmtHasAuthorization, currentUser.GetUid(), sess.AccountId, sess.AssetId)
|
||||
// if err := redis.Get(ctx, k, &ok); err == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
defer func() {
|
||||
redis.SetEx(ctx, k, ok, time.Minute)
|
||||
// redis.SetEx(ctx, k, ok, time.Minute)
|
||||
}()
|
||||
|
||||
if ok = acl.IsAdmin(currentUser); ok {
|
||||
@@ -380,7 +397,7 @@ func hasAuthorization(ctx *gin.Context, sess *gsession.Session) (ok bool) {
|
||||
}
|
||||
|
||||
if sess.Session.Asset == nil {
|
||||
if err := mysql.DB.Model(sess.Session.Asset).First(&sess.Session.Asset, sess.AssetId).Error; err != nil {
|
||||
if err := mysql.DB.Model(sess.Session.Asset).Where("id=?", sess.AssetId).First(&sess.Session.Asset).Error; err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -389,25 +406,25 @@ func hasAuthorization(ctx *gin.Context, sess *gsession.Session) (ok bool) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if lo.ContainsBy(authIds, func(item *model.AuthorizationIds) bool {
|
||||
if ok = lo.ContainsBy(authIds, func(item *model.AuthorizationIds) bool {
|
||||
return item.NodeId == 0 && item.AssetId == sess.AssetId && item.AccountId == sess.AccountId
|
||||
}) {
|
||||
}); ok {
|
||||
return
|
||||
}
|
||||
ctx.Set(kAuthorizationIds, authIds)
|
||||
|
||||
parentNodeIds, assetIds, accountIds := getIdsByAuthorizationIds(ctx)
|
||||
tmp, err := handleSelfChild(ctx, parentNodeIds...)
|
||||
nodeIds, assetIds, accountIds := getIdsByAuthorizationIds(ctx)
|
||||
tmp, err := handleSelfChild(ctx, nodeIds...)
|
||||
if err != nil {
|
||||
logger.L().Error("", zap.Error(err))
|
||||
return
|
||||
}
|
||||
parentNodeIds = append(parentNodeIds, tmp...)
|
||||
if ok = lo.Contains(parentNodeIds, sess.Session.Asset.ParentId) || lo.Contains(assetIds, sess.AssetId) || lo.Contains(accountIds, sess.AccountId); ok {
|
||||
nodeIds = append(nodeIds, tmp...)
|
||||
if ok = lo.Contains(nodeIds, sess.Session.Asset.ParentId) || lo.Contains(assetIds, sess.AssetId) || lo.Contains(accountIds, sess.AccountId); ok {
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := getAssetIdsByNodeAccount(ctx, parentNodeIds, accountIds)
|
||||
ids, err := getAssetIdsByNodeAccount(ctx, nodeIds, accountIds)
|
||||
if err != nil {
|
||||
logger.L().Error("", zap.Error(err))
|
||||
return
|
||||
|
@@ -314,12 +314,10 @@ func DoConnect(ctx *gin.Context, ws *websocket.Conn) (sess *gsession.Session, er
|
||||
|
||||
if !checkTime(asset.AccessAuth) {
|
||||
err = &ApiError{Code: ErrAccessTime}
|
||||
ctx.AbortWithError(http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
if !hasAuthorization(ctx, sess) {
|
||||
err = &ApiError{Code: ErrUnauthorized}
|
||||
ctx.AbortWithError(http.StatusForbidden, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -334,7 +332,7 @@ func DoConnect(ctx *gin.Context, ws *websocket.Conn) (sess *gsession.Session, er
|
||||
|
||||
if err = <-sess.Chans.ErrChan; err != nil {
|
||||
logger.L().Error("failed to connect", zap.Error(err))
|
||||
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrConnectServer, Data: map[string]any{"err": err}})
|
||||
err = &ApiError{Code: ErrConnectServer, Data: map[string]any{"err": err}}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -374,6 +372,12 @@ func connectSsh(ctx *gin.Context, sess *gsession.Session, asset *model.Asset, ac
|
||||
return
|
||||
}
|
||||
|
||||
if asset.GatewayId != 0 {
|
||||
if err = <-ggateway.GetGatewayBySessionId(sess.SessionId).Opened; err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
sshSess, err := sshCli.NewSession()
|
||||
if err != nil {
|
||||
logger.L().Error("ssh session create failed", zap.Error(err))
|
||||
|
@@ -253,6 +253,9 @@ func doUpdate[T model.Model](ctx *gin.Context, needAcl bool, md T, resourceType
|
||||
return
|
||||
}
|
||||
if needAcl {
|
||||
md.SetResourceId(old.GetResourceId())
|
||||
fmt.Printf("%+v\n", old)
|
||||
fmt.Printf("%+v\n", md)
|
||||
if !hasPerm(ctx, md, resourceType, acl.WRITE) {
|
||||
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.WRITE}})
|
||||
return
|
||||
@@ -488,7 +491,7 @@ func hasPerm[T model.Model](ctx context.Context, md T, resourceTypeName, action
|
||||
case *model.Asset:
|
||||
pids, _ = handleSelfParent(ctx, t.ParentId)
|
||||
case *model.Node:
|
||||
pids, _ = handleSelfParent(ctx, t.ParentId)
|
||||
pids, _ = handleSelfParent(ctx, t.Id)
|
||||
}
|
||||
|
||||
if len(pids) > 0 {
|
||||
@@ -574,6 +577,12 @@ func handleAcl[T any](ctx *gin.Context, dbFind *gorm.DB, resourceType string) (d
|
||||
db, err = handleNodeIds(ctx, dbFind, resIds)
|
||||
case *model.Asset:
|
||||
db, err = handleAssetIds(ctx, dbFind, resIds)
|
||||
case *model.Account:
|
||||
db, err = handleAccountIds(ctx, dbFind, resIds)
|
||||
case *model.Gateway:
|
||||
db = dbFind
|
||||
case *model.Command:
|
||||
db = dbFind
|
||||
default:
|
||||
db = dbFind.Where("resource_id IN ?", resIds)
|
||||
}
|
||||
@@ -594,7 +603,7 @@ func handleNodeIds(ctx *gin.Context, dbFind *gorm.DB, resIds []int) (db *gorm.DB
|
||||
return
|
||||
}
|
||||
|
||||
assetResIds, err := acl.GetRoleResources(ctx, currentUser.GetRid(), conf.RESOURCE_ASSET)
|
||||
assetResIds, err := acl.GetRoleResourceIds(ctx, currentUser.GetRid(), conf.RESOURCE_ASSET)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -637,3 +646,24 @@ func handleAssetIds(ctx *gin.Context, dbFind *gorm.DB, resIds []int) (db *gorm.D
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func handleAccountIds(ctx *gin.Context, dbFind *gorm.DB, resIds []int) (db *gorm.DB, err error) {
|
||||
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
|
||||
assetResIds, err := acl.GetRoleResourceIds(ctx, currentUser.GetRid(), conf.RESOURCE_ASSET)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t, _ := handleAssetIds(ctx, mysql.DB.Model(&model.Asset{}), assetResIds)
|
||||
ss := make([]model.Slice[string], 0)
|
||||
if err = t.Pluck("JSON_KEYS(authorization)", &ss).Error; err != nil {
|
||||
return
|
||||
}
|
||||
ids := lo.Uniq(lo.Map(lo.Flatten(ss), func(s string, _ int) int { return cast.ToInt(s) }))
|
||||
|
||||
d := mysql.DB.Where("resource_id IN ?", resIds).Or("id IN ?", ids)
|
||||
|
||||
db = dbFind.Where(d)
|
||||
|
||||
return
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@ package controller
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -114,9 +113,6 @@ func (c *Controller) GetNodes(ctx *gin.Context) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if ids, err = handleSelfChild(ctx, ids...); err != nil {
|
||||
return
|
||||
}
|
||||
if ids, err = handleSelfParent(ctx, ids...); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -149,15 +145,26 @@ func nodePreHookCheckCycle(ctx *gin.Context, data *model.Node) {
|
||||
|
||||
func nodePostHookCountAsset(ctx *gin.Context, data []*model.Node) {
|
||||
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
isAdmin := acl.IsAdmin(currentUser)
|
||||
assets := make([]*model.AssetIdPid, 0)
|
||||
db := mysql.DB.Model(&model.Asset{})
|
||||
if !isAdmin {
|
||||
if !acl.IsAdmin(currentUser) {
|
||||
info := cast.ToBool(ctx.Query("info"))
|
||||
if info {
|
||||
assetIds, err := GetAssetIdsByAuthorization(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
db = db.Where("id IN ?", assetIds)
|
||||
} else {
|
||||
assetResId, err := acl.GetRoleResourceIds(ctx, currentUser.GetRid(), conf.RESOURCE_ASSET)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
db, err = handleAssetIds(ctx, db, assetResId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := db.Find(&assets).Error; err != nil {
|
||||
logger.L().Error("node posthookfailed asset count", zap.Error(err))
|
||||
@@ -321,12 +328,12 @@ func handleSelfChild(ctx context.Context, ids ...int) (res []int, err error) {
|
||||
}
|
||||
|
||||
func GetNodeIdsByAuthorization(ctx *gin.Context) (ids []int, err error) {
|
||||
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
// currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
|
||||
k := fmt.Sprintf(kFmtNodeIds, currentUser.GetUid())
|
||||
if err = redis.Get(ctx, k, &ids); err == nil {
|
||||
return
|
||||
}
|
||||
// k := fmt.Sprintf(kFmtNodeIds, currentUser.GetUid())
|
||||
// if err = redis.Get(ctx, k, &ids); err == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
assetIds, err := GetAssetIdsByAuthorization(ctx)
|
||||
if err != nil {
|
||||
@@ -336,7 +343,7 @@ func GetNodeIdsByAuthorization(ctx *gin.Context) (ids []int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
redis.SetEx(ctx, k, ids, time.Minute)
|
||||
// redis.SetEx(ctx, k, ids, time.Minute)
|
||||
|
||||
return
|
||||
}
|
||||
|
@@ -27,6 +27,10 @@ func GetGatewayManager() *GateWayManager {
|
||||
return manager
|
||||
}
|
||||
|
||||
func GetGatewayBySessionId(sessionId string) *GatewayTunnel {
|
||||
return manager.gateways[sessionId]
|
||||
}
|
||||
|
||||
type GatewayTunnel struct {
|
||||
listener net.Listener
|
||||
GatewayId int
|
||||
@@ -37,7 +41,7 @@ type GatewayTunnel struct {
|
||||
RemotePort int
|
||||
LocalConn net.Conn
|
||||
RemoteConn net.Conn
|
||||
Opened chan struct{}
|
||||
Opened chan error
|
||||
}
|
||||
|
||||
func (gt *GatewayTunnel) Open() (err error) {
|
||||
@@ -46,20 +50,21 @@ func (gt *GatewayTunnel) Open() (err error) {
|
||||
logger.L().Debug("timeout 5 second close listener", zap.String("sessionId", gt.SessionId))
|
||||
gt.listener.Close()
|
||||
}()
|
||||
close(gt.Opened)
|
||||
defer func() {
|
||||
gt.Opened <- err
|
||||
}()
|
||||
gt.Opened <- nil
|
||||
gt.LocalConn, err = gt.listener.Accept()
|
||||
if err != nil {
|
||||
logger.L().Error("accept failed", zap.String("sessionId", gt.SessionId), zap.Error(err))
|
||||
return err
|
||||
return
|
||||
}
|
||||
|
||||
remoteAddr := fmt.Sprintf("%s:%d", gt.RemoteIp, gt.RemotePort)
|
||||
gt.RemoteConn, err = manager.sshClients[gt.GatewayId].Dial("tcp", remoteAddr)
|
||||
if err != nil {
|
||||
logger.L().Error("dial remote failed", zap.String("sessionId", gt.SessionId), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
go io.Copy(gt.LocalConn, gt.RemoteConn)
|
||||
go io.Copy(gt.RemoteConn, gt.LocalConn)
|
||||
|
||||
@@ -95,6 +100,7 @@ func (gm *GateWayManager) Open(sessionId, remoteIp string, remotePort int, gatew
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
})
|
||||
if err != nil {
|
||||
logger.L().Error("open gateway sshcli failed", zap.Int("gatewayId", gateway.Id), zap.Error(err))
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
@@ -120,7 +126,7 @@ func (gm *GateWayManager) Open(sessionId, remoteIp string, remotePort int, gatew
|
||||
LocalPort: localPort,
|
||||
RemoteIp: remoteIp,
|
||||
RemotePort: remotePort,
|
||||
Opened: make(chan struct{}),
|
||||
Opened: make(chan error),
|
||||
}
|
||||
gm.gateways[sessionId] = g
|
||||
go g.Open()
|
||||
|
@@ -45,7 +45,7 @@ func (m *Node) SetUpdaterId(updaterId int) {
|
||||
m.UpdaterId = updaterId
|
||||
}
|
||||
func (m *Node) SetResourceId(resourceId int) {
|
||||
|
||||
m.ResourceId = resourceId
|
||||
}
|
||||
func (m *Node) GetResourceId() int {
|
||||
return m.ResourceId
|
||||
|
@@ -133,7 +133,7 @@ func (m *view) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if ln > 100 {
|
||||
m.cmds = m.cmds[ln-100 : ln]
|
||||
}
|
||||
m.cmdsIdx = len(m.cmds) - 1
|
||||
m.cmdsIdx = len(m.cmds)
|
||||
if cmd == "exit" {
|
||||
return m, tea.Sequence(hisCmd, tea.Quit)
|
||||
} else if strings.HasPrefix(cmd, "ssh") {
|
||||
@@ -286,7 +286,7 @@ func (m *view) refresh() {
|
||||
return err
|
||||
}
|
||||
m.cmds, err = redis.RC.LRange(m.Ctx, fmt.Sprintf(hisCmdsFmt, m.currentUser.GetUid()), -100, -1).Result()
|
||||
m.cmdsIdx = len(m.cmds) - 1
|
||||
m.cmdsIdx = len(m.cmds)
|
||||
return err
|
||||
})
|
||||
|
||||
|
Reference in New Issue
Block a user