diff --git a/server/api/account.go b/server/api/account.go index 0854d6d..6c2b470 100644 --- a/server/api/account.go +++ b/server/api/account.go @@ -168,10 +168,7 @@ func (api AccountApi) LoginWithTotpEndpoint(c echo.Context) error { func (api AccountApi) LogoutEndpoint(c echo.Context) error { token := GetToken(c) - err := service.UserService.LogoutByToken(token) - if err != nil { - return err - } + service.UserService.Logout(token) return Success(c, nil) } @@ -317,6 +314,10 @@ func (api AccountApi) AccountAssetEndpoint(c echo.Context) error { if err != nil { return err } + for i := range items { + items[i].IP = "" + items[i].Port = 0 + } return Success(c, Map{ "total": total, diff --git a/server/api/asset.go b/server/api/asset.go index 726bf23..cbbbd82 100644 --- a/server/api/asset.go +++ b/server/api/asset.go @@ -28,7 +28,7 @@ func (assetApi AssetApi) AssetCreateEndpoint(c echo.Context) error { account, _ := GetCurrentAccount(c) m["owner"] = account.ID - if _, err := service.AssetService.Create(m); err != nil { + if _, err := service.AssetService.Create(context.TODO(), m); err != nil { return err } diff --git a/server/api/backup.go b/server/api/backup.go index 429f143..2896550 100644 --- a/server/api/backup.go +++ b/server/api/backup.go @@ -25,7 +25,7 @@ func (api BackupApi) BackupExportEndpoint(c echo.Context) error { if err != nil { return err } - c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=next-terminal_backup_%s.json", time.Now().Format("20060102150405"))) + c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=backup_%s.json", time.Now().Format("20060102150405"))) return c.Stream(http.StatusOK, echo.MIMEOctetStream, bytes.NewReader(jsonBytes)) } diff --git a/server/api/credential.go b/server/api/credential.go index b3709c2..6c6ed4b 100644 --- a/server/api/credential.go +++ b/server/api/credential.go @@ -64,7 +64,7 @@ func (api CredentialApi) CredentialCreateEndpoint(c echo.Context) error { item.Encrypted = true - if err := service.CredentialService.Create(&item); err != nil { + if err := service.CredentialService.Create(context.TODO(), &item); err != nil { return err } diff --git a/server/api/guacamole.go b/server/api/guacamole.go index 8455087..fce46b8 100644 --- a/server/api/guacamole.go +++ b/server/api/guacamole.go @@ -159,6 +159,7 @@ func (api GuacamoleApi) Guacamole(c echo.Context) error { guacamoleHandler := NewGuacamoleHandler(ws, guacdTunnel) guacamoleHandler.Start() + defer guacamoleHandler.Stop() for { _, message, err := ws.ReadMessage() @@ -168,7 +169,6 @@ func (api GuacamoleApi) Guacamole(c echo.Context) error { _ = guacdTunnel.Close() service.SessionService.CloseSessionById(sessionId, Normal, "用户正常退出") - guacamoleHandler.Stop() return nil } _, err = guacdTunnel.WriteAndFlush(message) @@ -193,7 +193,7 @@ func (api GuacamoleApi) setAssetConfig(attributes map[string]string, s model.Ses } realPath := path.Join(service.StorageService.GetBaseDrivePath(), storageId) configuration.SetParameter(guacd.EnableDrive, "true") - configuration.SetParameter(guacd.DriveName, "Next Terminal Filesystem") + configuration.SetParameter(guacd.DriveName, "Filesystem") configuration.SetParameter(guacd.DrivePath, realPath) log.Debugf("[%v] 会话 %v:%v 映射目录地址为 %v", s.ID, s.IP, s.Port, realPath) } else { @@ -258,6 +258,7 @@ func (api GuacamoleApi) GuacamoleMonitor(c echo.Context) error { guacamoleHandler := NewGuacamoleHandler(ws, guacdTunnel) guacamoleHandler.Start() + defer guacamoleHandler.Stop() for { _, message, err := ws.ReadMessage() @@ -269,7 +270,6 @@ func (api GuacamoleApi) GuacamoleMonitor(c echo.Context) error { observerId := nextSession.ID forObsSession.Observer.Del <- observerId log.Debugf("[%v:%v] 观察者[%v]退出会话", sessionId, connectionId, observerId) - guacamoleHandler.Stop() return nil } _, err = guacdTunnel.WriteAndFlush(message) diff --git a/server/api/guacamole_handler.go b/server/api/guacamole_handler.go index f81223a..563515b 100644 --- a/server/api/guacamole_handler.go +++ b/server/api/guacamole_handler.go @@ -2,7 +2,6 @@ package api import ( "context" - "time" "next-terminal/server/guacd" "next-terminal/server/log" @@ -12,73 +11,47 @@ import ( ) type GuacamoleHandler struct { - ws *websocket.Conn - tunnel *guacd.Tunnel - ctx context.Context - cancel context.CancelFunc - dataChan chan []byte - tick *time.Ticker + ws *websocket.Conn + tunnel *guacd.Tunnel + ctx context.Context + cancel context.CancelFunc } func NewGuacamoleHandler(ws *websocket.Conn, tunnel *guacd.Tunnel) *GuacamoleHandler { ctx, cancel := context.WithCancel(context.Background()) - tick := time.NewTicker(time.Millisecond * time.Duration(60)) return &GuacamoleHandler{ - ws: ws, - tunnel: tunnel, - ctx: ctx, - cancel: cancel, - dataChan: make(chan []byte), - tick: tick, + ws: ws, + tunnel: tunnel, + ctx: ctx, + cancel: cancel, } } func (r GuacamoleHandler) Start() { - go r.readFormTunnel() - go r.writeToWebsocket() -} - -func (r GuacamoleHandler) Stop() { - r.tick.Stop() - r.cancel() -} - -func (r GuacamoleHandler) readFormTunnel() { - for { - select { - case <-r.ctx.Done(): - return - default: - instruction, err := r.tunnel.Read() - if err != nil { - utils.Disconnect(r.ws, TunnelClosed, "远程连接已关闭") + go func() { + for { + select { + case <-r.ctx.Done(): return - } - if len(instruction) == 0 { - continue - } - r.dataChan <- instruction - } - } -} - -func (r GuacamoleHandler) writeToWebsocket() { - var buf []byte - for { - select { - case <-r.ctx.Done(): - return - case <-r.tick.C: - if len(buf) > 0 { - err := r.ws.WriteMessage(websocket.TextMessage, buf) + default: + instruction, err := r.tunnel.Read() + if err != nil { + utils.Disconnect(r.ws, TunnelClosed, "远程连接已关闭") + return + } + if len(instruction) == 0 { + continue + } + err = r.ws.WriteMessage(websocket.TextMessage, instruction) if err != nil { log.Debugf("WebSocket写入失败,即将关闭Guacd连接...") return } - buf = []byte{} } - case data := <-r.dataChan: - buf = append(buf, data...) } - } + }() +} + +func (r GuacamoleHandler) Stop() { + r.cancel() } diff --git a/server/api/job.go b/server/api/job.go index fd2791d..b4bad7d 100644 --- a/server/api/job.go +++ b/server/api/job.go @@ -25,7 +25,7 @@ func (api JobApi) JobCreateEndpoint(c echo.Context) error { item.ID = utils.UUID() item.Created = utils.NowJsonTime() - if err := service.JobService.Create(&item); err != nil { + if err := service.JobService.Create(context.TODO(), &item); err != nil { return err } return Success(c, "") diff --git a/server/api/resource-sharer.go b/server/api/resource-sharer.go index fa01985..1e896a2 100644 --- a/server/api/resource-sharer.go +++ b/server/api/resource-sharer.go @@ -2,6 +2,7 @@ package api import ( "context" + "next-terminal/server/service" "next-terminal/server/dto" "next-terminal/server/repository" @@ -42,7 +43,7 @@ func (api ResourceSharerApi) ResourceAddByUserIdAssignEndPoint(c echo.Context) e return err } - if err := repository.ResourceSharerRepository.AddSharerResources(ru.UserGroupId, ru.UserId, ru.StrategyId, ru.ResourceType, ru.ResourceIds); err != nil { + if err := service.UserService.AddSharerResources(context.TODO(), ru.UserGroupId, ru.UserId, ru.StrategyId, ru.ResourceType, ru.ResourceIds); err != nil { return err } diff --git a/server/api/session.go b/server/api/session.go index a6859ee..9508067 100644 --- a/server/api/session.go +++ b/server/api/session.go @@ -312,16 +312,16 @@ func (api SessionApi) SessionDownloadEndpoint(c echo.Context) error { if s.Download != "1" { return errors.New("禁止操作") } - remoteFile := c.QueryParam("file") + file := c.QueryParam("file") // 获取带后缀的文件名称 - filenameWithSuffix := path.Base(remoteFile) + filenameWithSuffix := path.Base(file) if "ssh" == s.Protocol { nextSession := session.GlobalSessionManager.GetById(sessionId) if nextSession == nil { return errors.New("获取会话失败") } - dstFile, err := nextSession.NextTerminal.SftpClient.Open(remoteFile) + dstFile, err := nextSession.NextTerminal.SftpClient.Open(file) if err != nil { return err } @@ -337,7 +337,7 @@ func (api SessionApi) SessionDownloadEndpoint(c echo.Context) error { return c.Stream(http.StatusOK, echo.MIMEOctetStream, bytes.NewReader(buff.Bytes())) } else if "rdp" == s.Protocol { storageId := s.StorageId - return service.StorageService.StorageDownload(c, remoteFile, storageId) + return service.StorageService.StorageDownload(c, file, storageId) } return err @@ -541,7 +541,9 @@ func (api SessionApi) SessionRecordingEndpoint(c echo.Context) error { _ = repository.SessionRepository.UpdateReadByIds(context.TODO(), true, []string{sessionId}) log.Debugf("读取录屏文件:%v,是否存在: %v, 是否为文件: %v", recording, utils.FileExists(recording), utils.IsFile(recording)) - return c.File(recording) + + http.ServeFile(c.Response(), c.Request(), recording) + return nil } func (api SessionApi) SessionGetEndpoint(c echo.Context) error { diff --git a/server/api/storage.go b/server/api/storage.go index 6bb5d52..620b83b 100644 --- a/server/api/storage.go +++ b/server/api/storage.go @@ -134,7 +134,7 @@ func (api StorageApi) StorageDeleteEndpoint(c echo.Context) error { split := strings.Split(ids, ",") for i := range split { id := split[i] - if err := service.StorageService.DeleteStorageById(id, false); err != nil { + if err := service.StorageService.DeleteStorageById(context.TODO(), id, false); err != nil { return err } } @@ -173,8 +173,8 @@ func (api StorageApi) StorageDownloadEndpoint(c echo.Context) error { if err := api.PermissionCheck(c, storageId); err != nil { return err } - remoteFile := c.QueryParam("file") - return service.StorageService.StorageDownload(c, remoteFile, storageId) + file := c.QueryParam("file") + return service.StorageService.StorageDownload(c, file, storageId) } func (api StorageApi) StorageUploadEndpoint(c echo.Context) error { diff --git a/server/api/term.go b/server/api/term.go index 1b463f7..adff3c2 100644 --- a/server/api/term.go +++ b/server/api/term.go @@ -157,6 +157,7 @@ func (api WebTerminalApi) SshEndpoint(c echo.Context) error { termHandler := NewTermHandler(sessionId, isRecording, ws, nextTerminal) termHandler.Start() + defer termHandler.Stop() for { _, message, err := ws.ReadMessage() @@ -164,7 +165,6 @@ func (api WebTerminalApi) SshEndpoint(c echo.Context) error { // web socket会话关闭后主动关闭ssh会话 log.Debugf("WebSocket已关闭") service.SessionService.CloseSessionById(sessionId, Normal, "用户正常退出") - termHandler.Stop() break } diff --git a/server/api/user-group.go b/server/api/user-group.go index dabe649..2a262fd 100644 --- a/server/api/user-group.go +++ b/server/api/user-group.go @@ -20,7 +20,7 @@ func (userGroupApi UserGroupApi) UserGroupCreateEndpoint(c echo.Context) error { return err } - if _, err := service.UserGroupService.Create(item.Name, item.Members); err != nil { + if _, err := service.UserGroupService.Create(context.TODO(), item.Name, item.Members); err != nil { return err } diff --git a/server/api/user.go b/server/api/user.go index caa4599..40a59b1 100644 --- a/server/api/user.go +++ b/server/api/user.go @@ -2,7 +2,7 @@ package api import ( "context" - + "fmt" "strconv" "strings" @@ -141,7 +141,11 @@ func (userApi UserApi) UserChangePasswordEndpoint(c echo.Context) error { } if user.Mail != "" { - go service.MailService.SendMail(user.Mail, "[Next Terminal] 密码修改通知", "你好,"+user.Nickname+"。管理员已将你的密码修改为:"+password) + subject := "密码修改通知" + text := fmt.Sprintf(`您好,%s。 + 管理员已将你的密码修改为:%s。 +`, user.Username, password) + go service.MailService.SendMail(user.Mail, subject, text) } return Success(c, "") diff --git a/server/app/app.go b/server/app/app.go index 5e12766..9466236 100644 --- a/server/app/app.go +++ b/server/app/app.go @@ -26,13 +26,6 @@ func newApp() *App { func init() { setupCache() app = newApp() - if err := app.InitDBData(); err != nil { - panic(err) - } - if err := app.ReloadData(); err != nil { - panic(err) - } - app.Server = setupRoutes() } func (app App) InitDBData() (err error) { @@ -96,7 +89,15 @@ func (app App) ReloadData() error { func Run() error { - fmt.Printf(constant.Banner, constant.Version) + fmt.Printf(constant.AppBanner, constant.AppVersion) + + if err := app.InitDBData(); err != nil { + panic(err) + } + if err := app.ReloadData(); err != nil { + panic(err) + } + app.Server = setupRoutes() if config.GlobalCfg.Debug { jsonBytes, err := json.MarshalIndent(config.GlobalCfg, "", " ") diff --git a/server/constant/const.go b/server/constant/const.go index 95fe276..44704c7 100644 --- a/server/constant/const.go +++ b/server/constant/const.go @@ -5,8 +5,9 @@ import ( ) const ( - Version = "v1.2.5" - Banner = ` + AppVersion = "v1.2.5" + AppName = "Next Terminal" + AppBanner = ` _______ __ ___________ .__ .__ \ \ ____ ___ ____/ |_ \__ ___/__________ _____ |__| ____ _____ | | / | \_/ __ \\ \/ /\ __\ | |_/ __ \_ __ \/ \| |/ \\__ \ | | @@ -72,8 +73,9 @@ const ( SocksProxyUsername = "socks-proxy-username" SocksProxyPassword = "socks-proxy-password" - LoginToken = "login-token" - AccessToken = "access-token" + LoginToken = "login-token" + AccessToken = "access-token" + ShareSession = "share-session" Anonymous = "anonymous" ) diff --git a/server/env/db.go b/server/env/db.go index e5c9287..96946df 100644 --- a/server/env/db.go +++ b/server/env/db.go @@ -36,8 +36,10 @@ func setupDB() *gorm.DB { Logger: logMode, }) } else { - db, err = gorm.Open(sqlite.Open(config.GlobalCfg.Sqlite.File), &gorm.Config{ - Logger: logMode, + dsn := fmt.Sprintf("file:%s?cache=shared&mode=rwc", config.GlobalCfg.Sqlite.File) + db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{ + Logger: logMode, + SkipDefaultTransaction: true, }) } diff --git a/server/repository/base.go b/server/repository/base.go index 3251b3c..e43f74e 100644 --- a/server/repository/base.go +++ b/server/repository/base.go @@ -13,14 +13,9 @@ type baseRepository struct { } func (b *baseRepository) GetDB(c context.Context) *gorm.DB { - db := c.Value(constant.DB) - if db == nil { - return env.GetDB() - } - switch val := db.(type) { - case gorm.DB: - return &val - default: + db, ok := c.Value(constant.DB).(*gorm.DB) + if !ok { return env.GetDB() } + return db } diff --git a/server/repository/resource_sharer.go b/server/repository/resource_sharer.go index e368b0d..72a33f1 100644 --- a/server/repository/resource_sharer.go +++ b/server/repository/resource_sharer.go @@ -7,7 +7,6 @@ import ( "next-terminal/server/utils" "github.com/labstack/echo/v4" - "github.com/pkg/errors" "gorm.io/gorm" ) @@ -101,57 +100,8 @@ func (r *resourceSharerRepository) DeleteByUserGroupId(c context.Context, userGr return r.GetDB(c).Where("user_group_id = ?", userGroupId).Delete(&model.ResourceSharer{}).Error } -func (r *resourceSharerRepository) AddSharerResources(userGroupId, userId, strategyId, resourceType string, resourceIds []string) error { - return r.GetDB(context.TODO()).Transaction(func(tx *gorm.DB) (err error) { - - for i := range resourceIds { - resourceId := resourceIds[i] - - var owner string - // 检查资产是否存在 - switch resourceType { - case "asset": - resource := model.Asset{} - if err = tx.Where("id = ?", resourceId).First(&resource).Error; err != nil { - return errors.Wrap(err, "find asset fail") - } - owner = resource.Owner - case "command": - resource := model.Command{} - if err = tx.Where("id = ?", resourceId).First(&resource).Error; err != nil { - return errors.Wrap(err, "find command fail") - } - owner = resource.Owner - case "credential": - resource := model.Credential{} - if err = tx.Where("id = ?", resourceId).First(&resource).Error; err != nil { - return errors.Wrap(err, "find credential fail") - - } - owner = resource.Owner - } - - if owner == userId { - return echo.NewHTTPError(400, "参数错误") - } - - // 保证同一个资产只能分配给一个用户或者组 - id := utils.Sign([]string{resourceId, resourceType, userId, userGroupId}) - resource := &model.ResourceSharer{ - ID: id, - ResourceId: resourceId, - ResourceType: resourceType, - StrategyId: strategyId, - UserId: userId, - UserGroupId: userGroupId, - } - err = tx.Create(resource).Error - if err != nil { - return err - } - } - return nil - }) +func (r *resourceSharerRepository) AddSharerResource(c context.Context, m *model.ResourceSharer) error { + return r.GetDB(c).Create(m).Error } func (r *resourceSharerRepository) FindAssetIdsByUserId(c context.Context, userId string) (assetIds []string, err error) { @@ -228,3 +178,7 @@ func (r *resourceSharerRepository) FindAll(c context.Context) (o []model.Resourc err = r.GetDB(c).Find(&o).Error return } + +func (r *resourceSharerRepository) DeleteById(ctx context.Context, id string) error { + return r.GetDB(ctx).Where("id = ?", id).Delete(&model.ResourceSharer{}).Error +} diff --git a/server/service/access_token.go b/server/service/access_token.go index c10c3df..d87e8a2 100644 --- a/server/service/access_token.go +++ b/server/service/access_token.go @@ -19,14 +19,9 @@ type accessTokenService struct { baseService } -func (service accessTokenService) FindByUserId(userId string) (model.AccessToken, error) { - return repository.AccessTokenRepository.FindByUserId(context.TODO(), userId) -} - func (service accessTokenService) GenAccessToken(userId string) error { return env.GetDB().Transaction(func(tx *gorm.DB) error { ctx := service.Context(tx) - user, err := repository.UserRepository.FindById(ctx, userId) if err != nil { return err diff --git a/server/service/asset.go b/server/service/asset.go index b558f5d..ef643ea 100644 --- a/server/service/asset.go +++ b/server/service/asset.go @@ -119,7 +119,7 @@ func (s assetService) FindByIdAndDecrypt(c context.Context, id string) (model.As func (s assetService) CheckStatus(accessGatewayId string, ip string, port int) (active bool, err error) { if accessGatewayId != "" && accessGatewayId != "-" { g, e1 := GatewayService.GetGatewayAndReconnectById(accessGatewayId) - if err != nil { + if e1 != nil { return false, e1 } @@ -141,7 +141,7 @@ func (s assetService) CheckStatus(accessGatewayId string, ip string, port int) ( return active, err } -func (s assetService) Create(m echo.Map) (model.Asset, error) { +func (s assetService) Create(ctx context.Context, m echo.Map) (model.Asset, error) { data, err := json.Marshal(m) if err != nil { @@ -156,29 +156,36 @@ func (s assetService) Create(m echo.Map) (model.Asset, error) { item.Created = utils.NowJsonTime() item.Active = true - return item, env.GetDB().Transaction(func(tx *gorm.DB) error { - c := s.Context(tx) + if s.InTransaction(ctx) { + return item, s.create(ctx, item, m) + } else { + return item, env.GetDB().Transaction(func(tx *gorm.DB) error { + c := s.Context(tx) + return s.create(c, item, m) + }) + } +} - if err := s.Encrypt(&item, config.GlobalCfg.EncryptionPassword); err != nil { - return err - } - if err := repository.AssetRepository.Create(c, &item); err != nil { - return err - } +func (s assetService) create(c context.Context, item model.Asset, m echo.Map) error { + if err := s.Encrypt(&item, config.GlobalCfg.EncryptionPassword); err != nil { + return err + } + if err := repository.AssetRepository.Create(c, &item); err != nil { + return err + } - if err := repository.AssetRepository.UpdateAttributes(c, item.ID, item.Protocol, m); err != nil { - return err - } + if err := repository.AssetRepository.UpdateAttributes(c, item.ID, item.Protocol, m); err != nil { + return err + } - go func() { - active, _ := s.CheckStatus(item.AccessGatewayId, item.IP, item.Port) - - if item.Active != active { - _ = repository.AssetRepository.UpdateActiveById(context.TODO(), active, item.ID) - } - }() - return nil - }) + //go func() { + // active, _ := s.CheckStatus(item.AccessGatewayId, item.IP, item.Port) + // + // if item.Active != active { + // _ = repository.AssetRepository.UpdateActiveById(context.TODO(), active, item.ID) + // } + //}() + return nil } func (s assetService) DeleteById(id string) error { diff --git a/server/service/backup.go b/server/service/backup.go index 0184d68..6be6b42 100644 --- a/server/service/backup.go +++ b/server/service/backup.go @@ -128,12 +128,12 @@ func (service backupService) Export() (error, *dto.Backup) { func (service backupService) Import(backup *dto.Backup) error { return env.GetDB().Transaction(func(tx *gorm.DB) error { - c := service.Context(tx) + ctx := service.Context(tx) var userIdMapping = make(map[string]string) if len(backup.Users) > 0 { for _, item := range backup.Users { oldId := item.ID - exist, err := repository.UserRepository.ExistByUsername(c, item.Username) + exist, err := repository.UserRepository.ExistByUsername(ctx, item.Username) if err != nil { return err } @@ -144,7 +144,7 @@ func (service backupService) Import(backup *dto.Backup) error { newId := utils.UUID() item.ID = newId item.Password = utils.GenPassword() - if err := repository.UserRepository.Create(c, &item); err != nil { + if err := repository.UserRepository.Create(ctx, &item); err != nil { return err } userIdMapping[oldId] = newId @@ -163,7 +163,7 @@ func (service backupService) Import(backup *dto.Backup) error { } } - userGroup, err := UserGroupService.Create(item.Name, members) + userGroup, err := UserGroupService.Create(ctx, item.Name, members) if err != nil { if errors.Is(constant.ErrNameAlreadyUsed, err) { // 删除名称重复的用户组 @@ -187,7 +187,7 @@ func (service backupService) Import(backup *dto.Backup) error { item.ID = utils.UUID() item.Owner = owner item.Created = utils.NowJsonTime() - if err := repository.StorageRepository.Create(c, &item); err != nil { + if err := repository.StorageRepository.Create(ctx, &item); err != nil { return err } } @@ -200,7 +200,7 @@ func (service backupService) Import(backup *dto.Backup) error { newId := utils.UUID() item.ID = newId item.Created = utils.NowJsonTime() - if err := repository.StrategyRepository.Create(c, &item); err != nil { + if err := repository.StrategyRepository.Create(ctx, &item); err != nil { return err } strategyIdMapping[oldId] = newId @@ -210,7 +210,7 @@ func (service backupService) Import(backup *dto.Backup) error { if len(backup.AccessSecurities) > 0 { for _, item := range backup.AccessSecurities { item.ID = utils.UUID() - if err := repository.SecurityRepository.Create(c, &item); err != nil { + if err := repository.SecurityRepository.Create(ctx, &item); err != nil { return err } // 更新内存中的安全规则 @@ -231,7 +231,7 @@ func (service backupService) Import(backup *dto.Backup) error { newId := utils.UUID() item.ID = newId item.Created = utils.NowJsonTime() - if err := repository.GatewayRepository.Create(c, &item); err != nil { + if err := repository.GatewayRepository.Create(ctx, &item); err != nil { return err } accessGatewayIdMapping[oldId] = newId @@ -242,7 +242,7 @@ func (service backupService) Import(backup *dto.Backup) error { for _, item := range backup.Commands { item.ID = utils.UUID() item.Created = utils.NowJsonTime() - if err := repository.CommandRepository.Create(c, &item); err != nil { + if err := repository.CommandRepository.Create(ctx, &item); err != nil { return err } } @@ -254,7 +254,7 @@ func (service backupService) Import(backup *dto.Backup) error { oldId := item.ID newId := utils.UUID() item.ID = newId - if err := CredentialService.Create(&item); err != nil { + if err := CredentialService.Create(ctx, &item); err != nil { return err } credentialIdMapping[oldId] = newId @@ -282,7 +282,7 @@ func (service backupService) Import(backup *dto.Backup) error { } oldId := m["id"].(string) - asset, err := AssetService.Create(m) + asset, err := AssetService.Create(ctx, m) if err != nil { return err } @@ -299,7 +299,7 @@ func (service backupService) Import(backup *dto.Backup) error { strategyId := strategyIdMapping[item.StrategyId] resourceId := assetIdMapping[item.ResourceId] - if err := repository.ResourceSharerRepository.AddSharerResources(userGroupId, userId, strategyId, item.ResourceType, []string{resourceId}); err != nil { + if err := UserService.AddSharerResources(ctx, userGroupId, userId, strategyId, item.ResourceType, []string{resourceId}); err != nil { return err } } @@ -311,6 +311,7 @@ func (service backupService) Import(backup *dto.Backup) error { continue } + item.ID = utils.UUID() resourceIds := strings.Split(item.ResourceIds, ",") if len(resourceIds) > 0 { var newResourceIds = make([]string, 0) @@ -319,7 +320,7 @@ func (service backupService) Import(backup *dto.Backup) error { } item.ResourceIds = strings.Join(newResourceIds, ",") } - if err := JobService.Create(&item); err != nil { + if err := JobService.Create(ctx, &item); err != nil { return err } } diff --git a/server/service/base.go b/server/service/base.go index 90a675a..f9be9c3 100644 --- a/server/service/base.go +++ b/server/service/base.go @@ -14,3 +14,8 @@ type baseService struct { func (service baseService) Context(db *gorm.DB) context.Context { return context.WithValue(context.TODO(), constant.DB, db) } + +func (service baseService) InTransaction(ctx context.Context) bool { + _, ok := ctx.Value(constant.DB).(*gorm.DB) + return ok +} diff --git a/server/service/credential.go b/server/service/credential.go index 049c507..efce296 100644 --- a/server/service/credential.go +++ b/server/service/credential.go @@ -99,8 +99,8 @@ func (s credentialService) Decrypt(item *model.Credential, password []byte) erro return nil } -func (s credentialService) FindByIdAndDecrypt(c context.Context, id string) (o model.Credential, err error) { - credential, err := repository.CredentialRepository.FindById(c, id) +func (s credentialService) FindByIdAndDecrypt(ctx context.Context, id string) (o model.Credential, err error) { + credential, err := repository.CredentialRepository.FindById(ctx, id) if err != nil { return o, err } @@ -110,10 +110,10 @@ func (s credentialService) FindByIdAndDecrypt(c context.Context, id string) (o m return credential, nil } -func (s credentialService) Create(item *model.Credential) error { +func (s credentialService) Create(ctx context.Context, item *model.Credential) error { // 加密密码之后进行存储 if err := s.Encrypt(item, config.GlobalCfg.EncryptionPassword); err != nil { return err } - return repository.CredentialRepository.Create(context.TODO(), item) + return repository.CredentialRepository.Create(ctx, item) } diff --git a/server/service/job.go b/server/service/job.go index b36b1d0..9ada289 100644 --- a/server/service/job.go +++ b/server/service/job.go @@ -103,7 +103,7 @@ func (r jobService) InitJob() error { return nil } -func (r jobService) Create(o *model.Job) (err error) { +func (r jobService) Create(ctx context.Context, o *model.Job) (err error) { if o.Status == constant.JobStatusRunning { j, err := getJob(o) @@ -117,7 +117,7 @@ func (r jobService) Create(o *model.Job) (err error) { o.CronJobId = int(jobId) } - return repository.JobRepository.Create(context.TODO(), o) + return repository.JobRepository.Create(ctx, o) } func (r jobService) DeleteJobById(id string) error { diff --git a/server/service/mail.go b/server/service/mail.go index f5a14c5..291b3a2 100644 --- a/server/service/mail.go +++ b/server/service/mail.go @@ -2,6 +2,7 @@ package service import ( "context" + "fmt" "net/smtp" "next-terminal/server/constant" @@ -27,7 +28,7 @@ func (r mailService) SendMail(to, subject, text string) { } e := email.NewEmail() - e.From = "Next Terminal <" + username + ">" + e.From = fmt.Sprintf("%s <%s>", constant.AppName, username) e.To = []string{to} e.Subject = subject e.Text = []byte(text) diff --git a/server/service/property.go b/server/service/property.go index a659180..1000112 100644 --- a/server/service/property.go +++ b/server/service/property.go @@ -17,161 +17,63 @@ type propertyService struct { baseService } +var deprecatedPropertyNames = []string{ + guacd.EnableDrive, + guacd.DrivePath, + guacd.DriveName, + guacd.DisableGlyphCaching, + guacd.CreateRecordingPath, +} + +var defaultProperties = map[string]string{ + guacd.EnableRecording: "true", + guacd.FontName: "menlo", + guacd.FontSize: "12", + guacd.ColorScheme: "gray-black", + guacd.EnableWallpaper: "true", + guacd.EnableTheming: "true", + guacd.EnableFontSmoothing: "true", + guacd.EnableFullWindowDrag: "true", + guacd.EnableDesktopComposition: "true", + guacd.EnableMenuAnimations: "true", + guacd.DisableBitmapCaching: "false", + guacd.DisableOffscreenCaching: "false", + "cron-log-saved-limit": "360", + "login-log-saved-limit": "360", + "session-saved-limit": "360", + "user-default-storage-size": "5120", +} + func (service propertyService) InitProperties() error { propertyMap := repository.PropertyRepository.FindAllMap(context.TODO()) - if len(propertyMap[guacd.EnableRecording]) == 0 { - property := model.Property{ - Name: guacd.EnableRecording, - Value: "true", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { + for name, value := range defaultProperties { + if err := service.CreateIfAbsent(propertyMap, name, value); err != nil { return err } } - if len(propertyMap[guacd.CreateRecordingPath]) == 0 { - property := model.Property{ - Name: guacd.CreateRecordingPath, - Value: "true", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } + return nil +} - if len(propertyMap[guacd.FontName]) == 0 { +func (service propertyService) CreateIfAbsent(propertyMap map[string]string, name, value string) error { + if len(propertyMap[name]) == 0 { property := model.Property{ - Name: guacd.FontName, - Value: "menlo", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.FontSize]) == 0 { - property := model.Property{ - Name: guacd.FontSize, - Value: "12", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.ColorScheme]) == 0 { - property := model.Property{ - Name: guacd.ColorScheme, - Value: "gray-black", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.EnableWallpaper]) == 0 { - property := model.Property{ - Name: guacd.EnableWallpaper, - Value: "false", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.EnableTheming]) == 0 { - property := model.Property{ - Name: guacd.EnableTheming, - Value: "false", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.EnableFontSmoothing]) == 0 { - property := model.Property{ - Name: guacd.EnableFontSmoothing, - Value: "false", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.EnableFullWindowDrag]) == 0 { - property := model.Property{ - Name: guacd.EnableFullWindowDrag, - Value: "false", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.EnableDesktopComposition]) == 0 { - property := model.Property{ - Name: guacd.EnableDesktopComposition, - Value: "false", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.EnableMenuAnimations]) == 0 { - property := model.Property{ - Name: guacd.EnableMenuAnimations, - Value: "false", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.DisableBitmapCaching]) == 0 { - property := model.Property{ - Name: guacd.DisableBitmapCaching, - Value: "false", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.DisableOffscreenCaching]) == 0 { - property := model.Property{ - Name: guacd.DisableOffscreenCaching, - Value: "false", - } - if err := repository.PropertyRepository.Create(context.TODO(), &property); err != nil { - return err - } - } - - if len(propertyMap[guacd.DisableGlyphCaching]) > 0 { - if err := repository.PropertyRepository.DeleteByName(context.TODO(), guacd.DisableGlyphCaching); err != nil { - return err + Name: name, + Value: value, } + return repository.PropertyRepository.Create(context.TODO(), &property) } return nil } func (service propertyService) DeleteDeprecatedProperty() error { propertyMap := repository.PropertyRepository.FindAllMap(context.TODO()) - if propertyMap[guacd.EnableDrive] != "" { - if err := repository.PropertyRepository.DeleteByName(context.TODO(), guacd.DriveName); err != nil { - return err + for _, name := range deprecatedPropertyNames { + if propertyMap[name] == "" { + continue } - } - if propertyMap[guacd.DrivePath] != "" { - if err := repository.PropertyRepository.DeleteByName(context.TODO(), guacd.DrivePath); err != nil { - return err - } - } - if propertyMap[guacd.DriveName] != "" { - if err := repository.PropertyRepository.DeleteByName(context.TODO(), guacd.DriveName); err != nil { + if err := repository.PropertyRepository.DeleteByName(context.TODO(), name); err != nil { return err } } diff --git a/server/service/storage.go b/server/service/storage.go index 1641300..aa926fb 100644 --- a/server/service/storage.go +++ b/server/service/storage.go @@ -4,11 +4,14 @@ import ( "bufio" "context" "errors" + "fmt" "io" "io/ioutil" "mime/multipart" + "net/http" "os" "path" + "strconv" "strings" "next-terminal/server/config" @@ -33,7 +36,7 @@ func (service storageService) InitStorages() error { userId := users[i].ID _, err := repository.StorageRepository.FindByOwnerIdAndDefault(context.TODO(), userId, true) if errors.Is(err, gorm.ErrRecordNotFound) { - err = service.CreateStorageByUser(&users[i]) + err = service.CreateStorageByUser(context.TODO(), &users[i]) if err != nil { return err } @@ -58,7 +61,7 @@ func (service storageService) InitStorages() error { } if !userExist { - if err := service.DeleteStorageById(storage.ID, true); err != nil { + if err := service.DeleteStorageById(context.TODO(), storage.ID, true); err != nil { return err } } @@ -75,14 +78,29 @@ func (service storageService) InitStorages() error { return nil } -func (service storageService) CreateStorageByUser(user *model.User) error { +func (service storageService) CreateStorageByUser(c context.Context, user *model.User) error { drivePath := service.GetBaseDrivePath() + var limitSize int64 = -1 + property, err := repository.PropertyRepository.FindByName(c, "user-default-storage-size") + if err != nil { + return err + } + limitSize, err = strconv.ParseInt(property.Value, 10, 64) + if err != nil { + return err + } + + limitSize = limitSize * 1024 * 1024 + if limitSize < 0 { + limitSize = -1 + } + storage := model.Storage{ ID: user.ID, Name: user.Nickname + "的默认空间", IsShare: false, IsDefault: true, - LimitSize: -1, + LimitSize: limitSize, Owner: user.ID, Created: utils.NowJsonTime(), } @@ -91,8 +109,9 @@ func (service storageService) CreateStorageByUser(user *model.User) error { return err } log.Infof("创建storage:「%v」文件夹: %v", storage.Name, storageDir) - err := repository.StorageRepository.Create(context.TODO(), &storage) + err = repository.StorageRepository.Create(c, &storage) if err != nil { + _ = os.RemoveAll(storageDir) return err } return nil @@ -135,9 +154,9 @@ func (service storageService) GetBaseDrivePath() string { return config.GlobalCfg.Guacd.Drive } -func (service storageService) DeleteStorageById(id string, force bool) error { +func (service storageService) DeleteStorageById(c context.Context, id string, force bool) error { drivePath := service.GetBaseDrivePath() - storage, err := repository.StorageRepository.FindById(context.TODO(), id) + storage, err := repository.StorageRepository.FindById(c, id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil @@ -152,7 +171,7 @@ func (service storageService) DeleteStorageById(id string, force bool) error { if err := os.RemoveAll(path.Join(drivePath, id)); err != nil { return err } - if err := repository.StorageRepository.DeleteById(context.TODO(), id); err != nil { + if err := repository.StorageRepository.DeleteById(c, id); err != nil { return err } return nil @@ -229,14 +248,20 @@ func (service storageService) StorageEdit(file string, fileContent string, stora return nil } -func (service storageService) StorageDownload(c echo.Context, remoteFile, storageId string) error { +func (service storageService) StorageDownload(c echo.Context, file, storageId string) error { drivePath := service.GetBaseDrivePath() - if strings.Contains(remoteFile, "../") { + if strings.Contains(file, "../") { return errors.New("非法请求 :(") } // 获取带后缀的文件名称 - filenameWithSuffix := path.Base(remoteFile) - return c.Attachment(path.Join(path.Join(drivePath, storageId), remoteFile), filenameWithSuffix) + filenameWithSuffix := path.Base(file) + p := path.Join(path.Join(drivePath, storageId), file) + //log.Infof("download %v", p) + c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filenameWithSuffix)) + c.Response().Header().Set("Content-Type", "application/octet-stream") + + http.ServeFile(c.Response(), c.Request(), p) + return nil } func (service storageService) StorageLs(remoteDir, storageId string) (error, []File) { diff --git a/server/service/user.go b/server/service/user.go index a920c41..65692b4 100644 --- a/server/service/user.go +++ b/server/service/user.go @@ -90,31 +90,31 @@ func (service userService) FixUserOnlineState() error { return nil } +func (service userService) Logout(token string) { + cache.TokenManager.Delete(token) +} + func (service userService) LogoutByToken(token string) (err error) { - return env.GetDB().Transaction(func(tx *gorm.DB) error { - c := service.Context(tx) - loginLog, err := repository.LoginLogRepository.FindById(c, token) - if err != nil { - return err - } - cache.TokenManager.Delete(token) - - loginLogForUpdate := &model.LoginLog{LogoutTime: utils.NowJsonTime(), ID: token} - err = repository.LoginLogRepository.Update(c, loginLogForUpdate) - if err != nil { - return err - } - - loginLogs, err := repository.LoginLogRepository.FindAliveLoginLogsByUsername(c, loginLog.Username) - if err != nil { - return err - } - - if len(loginLogs) == 0 { - err = repository.UserRepository.UpdateOnlineByUsername(c, loginLog.Username, false) - } + loginLog, err := repository.LoginLogRepository.FindById(context.TODO(), token) + if err != nil { return err - }) + } + + loginLogForUpdate := &model.LoginLog{LogoutTime: utils.NowJsonTime(), ID: token} + err = repository.LoginLogRepository.Update(context.TODO(), loginLogForUpdate) + if err != nil { + return err + } + + loginLogs, err := repository.LoginLogRepository.FindAliveLoginLogsByUsername(context.TODO(), loginLog.Username) + if err != nil { + return err + } + + if len(loginLogs) == 0 { + err = repository.UserRepository.UpdateOnlineByUsername(context.TODO(), loginLog.Username, false) + } + return err } func (service userService) LogoutById(c context.Context, id string) error { @@ -130,13 +130,26 @@ func (service userService) LogoutById(c context.Context, id string) error { for j := range loginLogs { token := loginLogs[j].ID - if err := service.LogoutByToken(token); err != nil { - return err - } + service.Logout(token) } return nil } +func (service userService) GetUserLoginToken(c context.Context, username string) ([]string, error) { + + loginLogs, err := repository.LoginLogRepository.FindAliveLoginLogsByUsername(c, username) + if err != nil { + return nil, err + } + + var tokens []string + for j := range loginLogs { + token := loginLogs[j].ID + tokens = append(tokens, token) + } + return tokens, nil +} + func (service userService) OnEvicted(token string, value interface{}) { if strings.HasPrefix(token, "forever") { @@ -144,30 +157,24 @@ func (service userService) OnEvicted(token string, value interface{}) { } else { log.Debugf("用户Token「%v」过期", token) err := service.LogoutByToken(token) - if err != nil { + if err != nil && !errors.Is(gorm.ErrRecordNotFound, err) { log.Errorf("退出登录失败 %v", err) } } } func (service userService) UpdateStatusById(id string, status string) error { - return env.GetDB().Transaction(func(tx *gorm.DB) error { - c := service.Context(tx) - if c.Value(constant.DB) == nil { - c = context.WithValue(c, constant.DB, env.GetDB()) + if constant.StatusDisabled == status { + // 将该用户下线 + if err := service.LogoutById(context.TODO(), id); err != nil { + return err } - if constant.StatusDisabled == status { - // 将该用户下线 - if err := service.LogoutById(c, id); err != nil { - return err - } - } - u := model.User{ - ID: id, - Status: status, - } - return repository.UserRepository.Update(c, &u) - }) + } + u := model.User{ + ID: id, + Status: status, + } + return repository.UserRepository.Update(context.TODO(), &u) } @@ -231,13 +238,19 @@ func (service userService) CreateUser(user model.User) (err error) { if err := repository.UserRepository.Create(c, &user); err != nil { return err } - err = StorageService.CreateStorageByUser(&user) + err = StorageService.CreateStorageByUser(c, &user) if err != nil { return err } if user.Mail != "" { - go MailService.SendMail(user.Mail, "[Next Terminal] 注册通知", "你好,"+user.Nickname+"。管理员为你注册了账号:"+user.Username+" 密码:"+password) + subject := fmt.Sprintf("%s 注册通知", constant.AppName) + text := fmt.Sprintf(`您好,%s。 + 管理员为你开通了账户。 + 账号:%s + 密码:%s +`, user.Username, user.Username, password) + go MailService.SendMail(user.Mail, subject, text) } return nil }) @@ -245,16 +258,19 @@ func (service userService) CreateUser(user model.User) (err error) { } func (service userService) DeleteUserById(userId string) error { - return env.GetDB().Transaction(func(tx *gorm.DB) error { + user, err := repository.UserRepository.FindById(context.TODO(), userId) + if err != nil { + return err + } + username := user.Username + // 下线该用户 + loginTokens, err := service.GetUserLoginToken(context.TODO(), username) + if err != nil { + return err + } + + err = env.GetDB().Transaction(func(tx *gorm.DB) error { c := service.Context(tx) - // 下线该用户 - if err := service.LogoutById(c, userId); err != nil { - return err - } - // 删除用户 - if err := repository.UserRepository.DeleteById(c, userId); err != nil { - return err - } // 删除用户与用户组的关系 if err := repository.UserGroupMemberRepository.DeleteByUserId(c, userId); err != nil { return err @@ -264,19 +280,37 @@ func (service userService) DeleteUserById(userId string) error { return err } // 删除用户的默认磁盘空间 - if err := StorageService.DeleteStorageById(userId, true); err != nil { + if err := StorageService.DeleteStorageById(c, userId, true); err != nil { + return err + } + + // 删除用户 + if err := repository.UserRepository.DeleteById(c, userId); err != nil { return err } return nil }) + + if err != nil { + return err + } + + for _, token := range loginTokens { + service.Logout(token) + } + return nil } func (service userService) DeleteLoginLogs(tokens []string) error { if len(tokens) > 0 { for _, token := range tokens { + // 手动触发用户退出登录 if err := service.LogoutByToken(token); err != nil { return err } + // 移除缓存中的token + service.Logout(token) + // 删除登录日志 if err := repository.LoginLogRepository.DeleteById(context.TODO(), token); err != nil { return err } @@ -337,3 +371,37 @@ func (service userService) UpdateUser(id string, user model.User) error { }) } + +func (service userService) AddSharerResources(ctx context.Context, userGroupId, userId, strategyId, resourceType string, resourceIds []string) error { + if service.InTransaction(ctx) { + return service.addSharerResources(ctx, resourceIds, userGroupId, userId, strategyId, resourceType) + } else { + return env.GetDB().Transaction(func(tx *gorm.DB) error { + ctx2 := service.Context(tx) + return service.addSharerResources(ctx2, resourceIds, userGroupId, userId, strategyId, resourceType) + }) + } +} + +func (service userService) addSharerResources(ctx context.Context, resourceIds []string, userGroupId string, userId string, strategyId string, resourceType string) error { + for i := range resourceIds { + resourceId := resourceIds[i] + // 保证同一个资产只能分配给一个用户或者组 + id := utils.Sign([]string{resourceId, resourceType, userId, userGroupId}) + if err := repository.ResourceSharerRepository.DeleteById(ctx, id); err != nil { + return err + } + rs := &model.ResourceSharer{ + ID: id, + ResourceId: resourceId, + ResourceType: resourceType, + StrategyId: strategyId, + UserId: userId, + UserGroupId: userGroupId, + } + if err := repository.ResourceSharerRepository.AddSharerResource(ctx, rs); err != nil { + return err + } + } + return nil +} diff --git a/server/service/user_group.go b/server/service/user_group.go index 47ed9e3..f5a6817 100644 --- a/server/service/user_group.go +++ b/server/service/user_group.go @@ -13,11 +13,12 @@ import ( ) type userGroupService struct { + baseService } func (service userGroupService) DeleteById(userGroupId string) error { return env.GetDB().Transaction(func(tx *gorm.DB) error { - c := context.WithValue(context.TODO(), constant.DB, tx) + c := service.Context(tx) // 删除用户组 if err := repository.UserGroupRepository.DeleteById(c, userGroupId); err != nil { return err @@ -34,8 +35,8 @@ func (service userGroupService) DeleteById(userGroupId string) error { }) } -func (service userGroupService) Create(name string, members []string) (model.UserGroup, error) { - exist, err := repository.UserGroupRepository.ExistByName(context.TODO(), name) +func (service userGroupService) Create(ctx context.Context, name string, members []string) (model.UserGroup, error) { + exist, err := repository.UserGroupRepository.ExistByName(ctx, name) if err != nil { return model.UserGroup{}, err } @@ -51,26 +52,33 @@ func (service userGroupService) Create(name string, members []string) (model.Use Name: name, } - return userGroup, env.GetDB().Transaction(func(tx *gorm.DB) error { - c := context.WithValue(context.TODO(), constant.DB, tx) - if err := repository.UserGroupRepository.Create(c, &userGroup); err != nil { - return err - } - if len(members) > 0 { - for _, member := range members { - userGroupMember := model.UserGroupMember{ - ID: utils.Sign([]string{userGroupId, member}), - UserId: member, - UserGroupId: userGroupId, - } - if err := repository.UserGroupMemberRepository.Create(c, &userGroupMember); err != nil { - return err - } + if service.InTransaction(ctx) { + return userGroup, service.create(ctx, userGroup, members, userGroupId) + } else { + return userGroup, env.GetDB().Transaction(func(tx *gorm.DB) error { + c := service.Context(tx) + return service.create(c, userGroup, members, userGroupId) + }) + } +} + +func (service userGroupService) create(c context.Context, userGroup model.UserGroup, members []string, userGroupId string) error { + if err := repository.UserGroupRepository.Create(c, &userGroup); err != nil { + return err + } + if len(members) > 0 { + for _, member := range members { + userGroupMember := model.UserGroupMember{ + ID: utils.Sign([]string{userGroupId, member}), + UserId: member, + UserGroupId: userGroupId, + } + if err := repository.UserGroupMemberRepository.Create(c, &userGroupMember); err != nil { + return err } } - return nil - }) - + } + return nil } func (service userGroupService) Update(userGroupId string, name string, members []string) (err error) { @@ -91,7 +99,7 @@ func (service userGroupService) Update(userGroupId string, name string, members } return env.GetDB().Transaction(func(tx *gorm.DB) error { - c := context.WithValue(context.TODO(), constant.DB, tx) + c := service.Context(tx) userGroup := model.UserGroup{ ID: userGroupId, Name: name, diff --git a/server/sshd/sshd.go b/server/sshd/sshd.go index 77f7a51..b9a0292 100644 --- a/server/sshd/sshd.go +++ b/server/sshd/sshd.go @@ -131,7 +131,7 @@ func (sshd sshd) sessionHandler(sess *ssh.Session) { func (sshd sshd) Serve() { ssh.Handle(func(s ssh.Session) { - _, _ = io.WriteString(s, fmt.Sprintf(constant.Banner, constant.Version)) + _, _ = io.WriteString(s, fmt.Sprintf(constant.AppBanner, constant.AppVersion)) sshd.sessionHandler(&s) }) diff --git a/server/sshd/ui.go b/server/sshd/ui.go index 547451b..6596798 100644 --- a/server/sshd/ui.go +++ b/server/sshd/ui.go @@ -59,19 +59,22 @@ func (gui Gui) AssetUI(sess *ssh.Session, user model.User) { return } + for i := range assets { + assets[i].IP = "" + assets[i].Port = 0 + } + quitItem := model.Asset{ID: "quit", Name: "返回上级菜单", Description: "这里是返回上级菜单的选项"} assets = append([]model.Asset{quitItem}, assets...) templates := &promptui.SelectTemplates{ Label: "{{ . }}?", - Active: "\U0001F336 {{ .Name | cyan }} ({{ .IP | red }}:{{ .Port | red }})", - Inactive: " {{ .Name | cyan }} ({{ .IP | red }}:{{ .Port | red }})", + Active: "\U0001F336 {{ .Name | cyan }}", + Inactive: " {{ .Name | cyan }}", Selected: "\U0001F336 {{ .Name | red | cyan }}", Details: ` --------- 详细信息 ---------- {{ "名称:" | faint }} {{ .Name }} -{{ "主机:" | faint }} {{ .IP }} -{{ "端口:" | faint }} {{ .Port }} {{ "标签:" | faint }} {{ .Tags }} {{ "备注:" | faint }} {{ .Description }} `, diff --git a/web/package.json b/web/package.json index 7d45bfb..30c8b3a 100644 --- a/web/package.json +++ b/web/package.json @@ -18,7 +18,6 @@ "react-router": "^5.2.0", "react-router-dom": "^5.2.0", "react-scripts": "^4.0.0", - "react-tsparticles": "^1.37.5", "xterm": "^4.9.0", "xterm-addon-fit": "^0.4.0", "xterm-addon-web-links": "^0.4.0" diff --git a/web/src/components/Login.js b/web/src/components/Login.js index ed72eea..9397924 100644 --- a/web/src/components/Login.js +++ b/web/src/components/Login.js @@ -5,8 +5,7 @@ import request from "../common/request"; import {message} from "antd/es"; import {withRouter} from "react-router-dom"; import {LockOutlined, OneToOneOutlined, UserOutlined} from '@ant-design/icons'; -import Particles from "react-tsparticles"; -import Background from '../images/bg.png' +import Background from '../images/bg.jpg' import {setToken} from "../utils/utils"; const {Title} = Typography; @@ -109,90 +108,7 @@ class LoginForm extends Component { render() { return (
上传:{renderStatus(item['strategy']['upload'])}
下载:{renderStatus(item['strategy']['download'])}
+编辑:{renderStatus(item['strategy']['edit'])}
删除:{renderStatus(item['strategy']['delete'])}
-改名:{renderStatus(item['strategy']['rename'])}
+重命名:{renderStatus(item['strategy']['rename'])}
+复制:{renderStatus(item['strategy']['copy'])}
+粘贴:{renderStatus(item['strategy']['paste'])}