feat(api): permission

This commit is contained in:
ttk
2024-09-26 21:42:30 +08:00
parent c646a98059
commit e5fc7077f2
11 changed files with 194 additions and 122 deletions

View File

@@ -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{}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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))

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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()

View File

@@ -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

View File

@@ -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
})