1f7c491048
- 实现文件系统日志(FilesystemLog)记录文件管理器操作 - 实现操作日志(OperationLog)记录用户操作行为 - 实现数据库SQL日志(DatabaseSQLLog)模型和API - 实现SSH会话命令记录(SessionCommand)含命令输出和风险等级 - 添加IP提取服务支持X-Real-IP和X-Forwarded-For - 添加日志自动清理功能 - 修复ProFormSwitch required验证问题 - 修复设置页面默认值问题 - 修复文件上传错误检测逻辑 - 修复资产树key前缀问题 - 添加VNC/RDP设置默认值 - 修复文件管理标题翻译
208 lines
4.9 KiB
Go
208 lines
4.9 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
|
|
"next-terminal/server/common/guacamole"
|
|
"next-terminal/server/env"
|
|
"next-terminal/server/model"
|
|
"next-terminal/server/repository"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var PropertyService = new(propertyService)
|
|
|
|
type propertyService struct {
|
|
baseService
|
|
}
|
|
|
|
var deprecatedPropertyNames = []string{
|
|
guacamole.EnableDrive,
|
|
guacamole.DrivePath,
|
|
guacamole.DriveName,
|
|
guacamole.DisableGlyphCaching,
|
|
guacamole.CreateRecordingPath,
|
|
}
|
|
|
|
var defaultProperties = map[string]string{
|
|
guacamole.EnableRecording: "true",
|
|
guacamole.FontName: "menlo",
|
|
guacamole.FontSize: "12",
|
|
guacamole.ColorScheme: "gray-black",
|
|
guacamole.EnableWallpaper: "true",
|
|
guacamole.EnableTheming: "true",
|
|
guacamole.EnableFontSmoothing: "true",
|
|
guacamole.EnableFullWindowDrag: "true",
|
|
guacamole.EnableDesktopComposition: "true",
|
|
guacamole.EnableMenuAnimations: "true",
|
|
guacamole.DisableBitmapCaching: "false",
|
|
guacamole.DisableOffscreenCaching: "false",
|
|
guacamole.ColorDepth: "",
|
|
guacamole.Cursor: "",
|
|
guacamole.SwapRedBlue: "false",
|
|
"cron-log-saved-limit": "360",
|
|
"login-log-saved-limit": "360",
|
|
"session-saved-limit": "360",
|
|
"access-log-saved-limit": "30",
|
|
"filesystem-log-saved-limit": "30",
|
|
"operation-log-saved-limit": "30",
|
|
"database-sql-log-saved-limit": "30",
|
|
"user-default-storage-size": "5120",
|
|
"ip-extractor": "direct",
|
|
"ip-trust-list": "",
|
|
}
|
|
|
|
func (service propertyService) InitProperties() error {
|
|
propertyMap := repository.PropertyRepository.FindAllMap(context.TODO())
|
|
|
|
for name, value := range defaultProperties {
|
|
if err := service.CreateIfAbsent(propertyMap, name, value); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (service propertyService) CreateIfAbsent(propertyMap map[string]string, name, value string) error {
|
|
if len(propertyMap[name]) == 0 {
|
|
if value == "" {
|
|
value = "-"
|
|
}
|
|
property := model.Property{
|
|
Name: name,
|
|
Value: value,
|
|
}
|
|
return repository.PropertyRepository.Create(context.TODO(), &property)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (service propertyService) DeleteDeprecatedProperty() error {
|
|
propertyMap := repository.PropertyRepository.FindAllMap(context.TODO())
|
|
for _, name := range deprecatedPropertyNames {
|
|
if propertyMap[name] == "" {
|
|
continue
|
|
}
|
|
if err := repository.PropertyRepository.DeleteByName(context.TODO(), name); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (service propertyService) Update(item map[string]interface{}) error {
|
|
return env.GetDB().Transaction(func(tx *gorm.DB) error {
|
|
c := service.Context(tx)
|
|
for key := range item {
|
|
value := fmt.Sprintf("%v", item[key])
|
|
if value == "" {
|
|
value = "-"
|
|
}
|
|
|
|
property := model.Property{
|
|
Name: key,
|
|
Value: value,
|
|
}
|
|
|
|
if key == "enable-ldap" && value == "false" {
|
|
if err := UserService.DeleteALlLdapUser(c); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
_, err := repository.PropertyRepository.FindByName(c, key)
|
|
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
|
if err := repository.PropertyRepository.Create(c, &property); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := repository.PropertyRepository.UpdateByName(c, &property, key); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
}
|
|
|
|
func (service propertyService) GetClientIP(c echo.Context) string {
|
|
propertyMap := repository.PropertyRepository.FindAllMap(context.TODO())
|
|
extractor := propertyMap["ip-extractor"]
|
|
trustList := propertyMap["ip-trust-list"]
|
|
|
|
directIP := c.RealIP()
|
|
|
|
if extractor == "" || extractor == "direct" {
|
|
return directIP
|
|
}
|
|
|
|
if !service.isTrustedIP(directIP, trustList) {
|
|
return directIP
|
|
}
|
|
|
|
switch extractor {
|
|
case "x-real-ip":
|
|
xRealIP := c.Request().Header.Get("X-Real-IP")
|
|
if xRealIP != "" {
|
|
return xRealIP
|
|
}
|
|
case "x-forwarded-for":
|
|
xForwardedFor := c.Request().Header.Get("X-Forwarded-For")
|
|
if xForwardedFor != "" {
|
|
ips := strings.Split(xForwardedFor, ",")
|
|
if len(ips) > 0 {
|
|
ip := strings.TrimSpace(ips[0])
|
|
if ip != "" {
|
|
return ip
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return directIP
|
|
}
|
|
|
|
func (service propertyService) isTrustedIP(clientIP string, trustList string) bool {
|
|
if trustList == "" {
|
|
return false
|
|
}
|
|
|
|
trustIPs := strings.Split(trustList, ",")
|
|
clientIPAddr := net.ParseIP(clientIP)
|
|
if clientIPAddr == nil {
|
|
return false
|
|
}
|
|
|
|
for _, trustIP := range trustIPs {
|
|
trustIP = strings.TrimSpace(trustIP)
|
|
if trustIP == "" {
|
|
continue
|
|
}
|
|
|
|
if strings.Contains(trustIP, "/") {
|
|
_, ipNet, err := net.ParseCIDR(trustIP)
|
|
if err == nil && ipNet.Contains(clientIPAddr) {
|
|
return true
|
|
}
|
|
} else {
|
|
if trustIP == clientIP {
|
|
return true
|
|
}
|
|
trustIPAddr := net.ParseIP(trustIP)
|
|
if trustIPAddr != nil && trustIPAddr.Equal(clientIPAddr) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|