- 修复「修改接入网关失败」的问题

- 完成「[功能请求]审计的历史会话建议添加“已阅”的功能」close #194
- 增加一键删除登录日志和历史会话的功能
This commit is contained in:
dushixiang
2021-11-12 20:07:15 +08:00
parent 09040c316e
commit f1432b6886
34 changed files with 801 additions and 234 deletions

View File

@ -78,8 +78,7 @@ func AccessGatewayUpdateEndpoint(c echo.Context) error {
if err := accessGatewayRepository.UpdateById(&item, id); err != nil {
return err
}
accessGatewayService.DisconnectById(id)
_, _ = accessGatewayService.GetGatewayAndReconnectById(id)
accessGatewayService.ReConnect(&item)
return Success(c, nil)
}

View File

@ -1,6 +1,7 @@
package api
import (
"next-terminal/server/constant"
"path"
"strconv"
"strings"
@ -49,8 +50,6 @@ func LoginEndpoint(c echo.Context) error {
return err
}
user, err := userRepository.FindByUsername(loginAccount.Username)
// 存储登录失败次数信息
loginFailCountKey := c.RealIP() + loginAccount.Username
v, ok := cache.GlobalCache.Get(loginFailCountKey)
@ -62,6 +61,7 @@ func LoginEndpoint(c echo.Context) error {
return Fail(c, -1, "登录失败次数过多请等待5分钟后再试")
}
user, err := userRepository.FindByUsername(loginAccount.Username)
if err != nil {
count++
cache.GlobalCache.Set(loginFailCountKey, count, time.Minute*time.Duration(5))
@ -72,6 +72,10 @@ func LoginEndpoint(c echo.Context) error {
return FailWithData(c, -1, "您输入的账号或密码不正确", count)
}
if user.Status == constant.StatusDisabled {
return Fail(c, -1, "该账户已停用")
}
if err := utils.Encoder.Match([]byte(user.Password), []byte(loginAccount.Password)); err != nil {
count++
cache.GlobalCache.Set(loginFailCountKey, count, time.Minute*time.Duration(5))
@ -172,6 +176,10 @@ func loginWithTotpEndpoint(c echo.Context) error {
return FailWithData(c, -1, "您输入的账号或密码不正确", count)
}
if user.Status == constant.StatusDisabled {
return Fail(c, -1, "该账户已停用")
}
if err := utils.Encoder.Match([]byte(user.Password), []byte(loginAccount.Password)); err != nil {
count++
cache.GlobalCache.Set(loginFailCountKey, count, time.Minute*time.Duration(5))
@ -206,9 +214,7 @@ func loginWithTotpEndpoint(c echo.Context) error {
func LogoutEndpoint(c echo.Context) error {
token := GetToken(c)
cacheKey := userService.BuildCacheKeyByToken(token)
cache.GlobalCache.Delete(cacheKey)
err := userService.Logout(token)
err := userService.LogoutByToken(token)
if err != nil {
return err
}

102
server/api/backup.go Normal file
View File

@ -0,0 +1,102 @@
package api
import (
"bytes"
"encoding/json"
"fmt"
"github.com/labstack/echo/v4"
"net/http"
"next-terminal/server/model"
"time"
)
type Backup struct {
Users []model.User `json:"users"`
UserGroups []model.UserGroup `json:"user_groups"`
UserGroupMembers []model.UserGroupMember `json:"user_group_members"`
Strategies []model.Strategy `json:"strategies"`
Jobs []model.Job `json:"jobs"`
AccessSecurities []model.AccessSecurity `json:"access_securities"`
AccessGateways []model.AccessGateway `json:"access_gateways"`
Commands []model.Command `json:"commands"`
Credentials []model.Credential `json:"credentials"`
Assets []model.Asset `json:"assets"`
ResourceSharers []model.ResourceSharer `json:"resource_sharers"`
}
func BackupExportEndpoint(c echo.Context) error {
users, err := userRepository.FindAll()
if err != nil {
return err
}
for i := range users {
users[i].Password = ""
}
userGroups, err := userGroupRepository.FindAll()
if err != nil {
return err
}
userGroupMembers, err := userGroupRepository.FindAllUserGroupMembers()
if err != nil {
return err
}
strategies, err := strategyRepository.FindAll()
if err != nil {
return err
}
jobs, err := jobRepository.FindAll()
if err != nil {
return err
}
accessSecurities, err := accessSecurityRepository.FindAll()
if err != nil {
return err
}
accessGateways, err := accessGatewayRepository.FindAll()
if err != nil {
return err
}
commands, err := commandRepository.FindAll()
if err != nil {
return err
}
credentials, err := credentialRepository.FindAll()
if err != nil {
return err
}
assets, err := assetRepository.FindAll()
if err != nil {
return err
}
resourceSharers, err := resourceSharerRepository.FindAll()
if err != nil {
return err
}
backup := Backup{
Users: users,
UserGroups: userGroups,
UserGroupMembers: userGroupMembers,
Strategies: strategies,
Jobs: jobs,
AccessSecurities: accessSecurities,
AccessGateways: accessGateways,
Commands: commands,
Credentials: credentials,
Assets: assets,
ResourceSharers: resourceSharers,
}
jsonBytes, err := json.Marshal(backup)
if err != nil {
return err
}
c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=next-terminal_backup_%s.json", time.Now().Format("20060102150405")))
return c.Stream(http.StatusOK, echo.MIMEOctetStream, bytes.NewReader(jsonBytes))
}
func BackupImportEndpoint(c echo.Context) error {
return nil
}

View File

@ -4,9 +4,6 @@ import (
"strconv"
"strings"
"next-terminal/server/global/cache"
"next-terminal/server/log"
"github.com/labstack/echo/v4"
)
@ -31,24 +28,26 @@ func LoginLogPagingEndpoint(c echo.Context) error {
func LoginLogDeleteEndpoint(c echo.Context) error {
ids := c.Param("id")
split := strings.Split(ids, ",")
for i := range split {
token := split[i]
cache.GlobalCache.Delete(token)
if err := userService.Logout(token); err != nil {
log.WithError(err).Error("Cache Delete Failed")
}
}
if err := loginLogRepository.DeleteByIdIn(split); err != nil {
tokens := strings.Split(ids, ",")
if err := userService.DeleteLoginLogs(tokens); err != nil {
return err
}
return Success(c, nil)
}
//func LoginLogClearEndpoint(c echo.Context) error {
// loginLogs, err := loginLogRepository.FindAliveLoginLogs()
// if err != nil {
// return err
// }
//}
func LoginLogClearEndpoint(c echo.Context) error {
loginLogs, err := loginLogRepository.FindAllLoginLogs()
if err != nil {
return err
}
var tokens = make([]string, 0)
for i := range loginLogs {
tokens = append(tokens, loginLogs[i].ID)
}
if err := userService.DeleteLoginLogs(tokens); err != nil {
return err
}
return Success(c, nil)
}

View File

@ -110,6 +110,7 @@ func SetupRoutes(db *gorm.DB) *echo.Echo {
users.POST("", UserCreateEndpoint)
users.GET("/paging", UserPagingEndpoint)
users.PUT("/:id", UserUpdateEndpoint)
users.PATCH("/:id/status", UserUpdateStatusEndpoint)
users.DELETE("/:id", UserDeleteEndpoint)
users.GET("/:id", UserGetEndpoint)
users.POST("/:id/change-password", UserChangePasswordEndpoint)
@ -169,6 +170,10 @@ func SetupRoutes(db *gorm.DB) *echo.Echo {
sessions.DELETE("/:id", Admin(SessionDeleteEndpoint))
sessions.GET("/:id/recording", Admin(SessionRecordingEndpoint))
sessions.GET("/:id", Admin(SessionGetEndpoint))
sessions.POST("/:id/reviewed", Admin(SessionReviewedEndpoint))
sessions.POST("/:id/unreviewed", Admin(SessionUnViewedEndpoint))
sessions.POST("/clear", Admin(SessionClearEndpoint))
sessions.POST("/reviewed", Admin(SessionReviewedAllEndpoint))
sessions.POST("", SessionCreateEndpoint)
sessions.POST("/:id/connect", SessionConnectEndpoint)
@ -195,7 +200,7 @@ func SetupRoutes(db *gorm.DB) *echo.Echo {
{
loginLogs.GET("/paging", LoginLogPagingEndpoint)
loginLogs.DELETE("/:id", LoginLogDeleteEndpoint)
//loginLogs.DELETE("/clear", LoginLogClearEndpoint)
loginLogs.POST("/clear", LoginLogClearEndpoint)
}
e.GET("/properties", Admin(PropertyGetEndpoint))
@ -268,6 +273,12 @@ func SetupRoutes(db *gorm.DB) *echo.Echo {
accessGateways.POST("/:id/reconnect", AccessGatewayReconnectEndpoint)
}
backup := e.Group("/backup", Admin)
{
backup.GET("/export", BackupExportEndpoint)
backup.POST("/import", BackupImportEndpoint)
}
return e
}

View File

@ -36,7 +36,7 @@ func SecurityCreateEndpoint(c echo.Context) error {
}
func ReloadAccessSecurity() error {
rules, err := accessSecurityRepository.FindAllAccessSecurities()
rules, err := accessSecurityRepository.FindAll()
if err != nil {
return err
}

View File

@ -35,8 +35,9 @@ func SessionPagingEndpoint(c echo.Context) error {
clientIp := c.QueryParam("clientIp")
assetId := c.QueryParam("assetId")
protocol := c.QueryParam("protocol")
reviewed := c.QueryParam("reviewed")
items, total, err := sessionRepository.Find(pageIndex, pageSize, status, userId, clientIp, assetId, protocol)
items, total, err := sessionRepository.Find(pageIndex, pageSize, status, userId, clientIp, assetId, protocol, reviewed)
if err != nil {
return err
@ -69,9 +70,8 @@ func SessionPagingEndpoint(c echo.Context) error {
}
func SessionDeleteEndpoint(c echo.Context) error {
sessionIds := c.Param("id")
split := strings.Split(sessionIds, ",")
err := sessionRepository.DeleteByIds(split)
sessionIds := strings.Split(c.Param("id"), ",")
err := sessionRepository.DeleteByIds(sessionIds)
if err != nil {
return err
}
@ -79,6 +79,37 @@ func SessionDeleteEndpoint(c echo.Context) error {
return Success(c, nil)
}
func SessionClearEndpoint(c echo.Context) error {
err := sessionService.ClearOfflineSession()
if err != nil {
return err
}
return Success(c, nil)
}
func SessionReviewedEndpoint(c echo.Context) error {
sessionIds := strings.Split(c.Param("id"), ",")
if err := sessionRepository.UpdateReadByIds(true, sessionIds); err != nil {
return err
}
return Success(c, nil)
}
func SessionUnViewedEndpoint(c echo.Context) error {
sessionIds := strings.Split(c.Param("id"), ",")
if err := sessionRepository.UpdateReadByIds(false, sessionIds); err != nil {
return err
}
return Success(c, nil)
}
func SessionReviewedAllEndpoint(c echo.Context) error {
if err := sessionService.ReviewedAll(); err != nil {
return err
}
return Success(c, nil)
}
func SessionConnectEndpoint(c echo.Context) error {
sessionId := c.Param("id")
@ -299,6 +330,7 @@ func SessionCreateEndpoint(c echo.Context) error {
Edit: edit,
StorageId: storageId,
AccessGatewayId: asset.AccessGatewayId,
Reviewed: false,
}
if asset.AccountType == "credential" {
@ -645,6 +677,7 @@ func SessionRecordingEndpoint(c echo.Context) error {
} else {
recording = s.Recording + "/recording"
}
_ = sessionRepository.UpdateReadByIds(true, []string{sessionId})
log.Debugf("读取录屏文件:%v,是否存在: %v, 是否为文件: %v", recording, utils.FileExists(recording), utils.IsFile(recording))
return c.File(recording)

View File

@ -2,6 +2,7 @@ package api
import (
"errors"
"next-terminal/server/constant"
"strconv"
"strings"
@ -29,6 +30,7 @@ func UserCreateEndpoint(c echo.Context) (err error) {
item.ID = utils.UUID()
item.Created = utils.NowJsonTime()
item.Status = constant.StatusEnabled
if err := userRepository.Create(&item); err != nil {
return err
@ -82,6 +84,21 @@ func UserUpdateEndpoint(c echo.Context) error {
return Success(c, nil)
}
func UserUpdateStatusEndpoint(c echo.Context) error {
id := c.Param("id")
status := c.QueryParam("status")
account, _ := GetCurrentAccount(c)
if account.ID == id {
return Fail(c, -1, "不能操作自身账户")
}
if err := userService.UpdateStatusById(id, status); err != nil {
return err
}
return Success(c, nil)
}
func UserDeleteEndpoint(c echo.Context) error {
ids := c.Param("id")
account, found := GetCurrentAccount(c)
@ -94,26 +111,10 @@ func UserDeleteEndpoint(c echo.Context) error {
if account.ID == userId {
return Fail(c, -1, "不允许删除自身账户")
}
user, err := userRepository.FindById(userId)
if err != nil {
// 下线该用户
if err := userService.LogoutById(userId); err != nil {
return err
}
// 将用户强制下线
loginLogs, err := loginLogRepository.FindAliveLoginLogsByUsername(user.Username)
if err != nil {
return err
}
for j := range loginLogs {
token := loginLogs[j].ID
cacheKey := userService.BuildCacheKeyByToken(token)
cache.GlobalCache.Delete(cacheKey)
if err := userService.Logout(token); err != nil {
log.WithError(err).WithField("id:", token).Error("Cache Deleted Error")
return Fail(c, 500, "强制下线错误")
}
}
// 删除用户
if err := userRepository.DeleteById(userId); err != nil {
return err