dockerfiles/anylink/server/dbdata/user_act_log.go

211 lines
5.2 KiB
Go

package dbdata
import (
"net/url"
"regexp"
"strings"
"github.com/bjdgyc/anylink/base"
"github.com/ivpusic/grpool"
"github.com/spf13/cast"
"xorm.io/xorm"
)
const (
UserAuthFail = 0 // 认证失败
UserAuthSuccess = 1 // 认证成功
UserConnected = 2 // 连线成功
UserLogout = 3 // 用户登出
UserLogoutLose = 0 // 用户掉线
UserLogoutBanner = 1 // 用户banner弹窗取消
UserLogoutClient = 2 // 用户主动登出
UserLogoutTimeout = 3 // 用户超时登出
UserLogoutAdmin = 4 // 账号被管理员踢下线
UserLogoutExpire = 5 // 账号过期被踢下线
)
type UserActLogProcess struct {
Pool *grpool.Pool
StatusOps []string
OsOps []string
ClientOps []string
InfoOps []string
}
var (
UserActLogIns = &UserActLogProcess{
Pool: grpool.NewPool(1, 100),
StatusOps: []string{ // 操作类型
UserAuthFail: "认证失败",
UserAuthSuccess: "认证成功",
UserConnected: "连接成功",
UserLogout: "用户登出",
},
OsOps: []string{ // 操作系统
0: "Unknown",
1: "Windows",
2: "macOS",
3: "Linux",
4: "Android",
5: "iOS",
},
ClientOps: []string{ // 客户端
0: "Unknown",
1: "AnyConnect",
2: "OpenConnect",
3: "AnyLink",
},
InfoOps: []string{ // 信息
UserLogoutLose: "用户掉线",
UserLogoutBanner: "用户取消弹窗/客户端发起的logout",
UserLogoutClient: "用户/客户端主动断开",
UserLogoutTimeout: "Session过期被踢下线",
UserLogoutAdmin: "账号被管理员踢下线",
UserLogoutExpire: "账号过期被踢下线",
},
}
)
// 异步写入用户操作日志
func (ua *UserActLogProcess) Add(u UserActLog, userAgent string) {
// os, client, ver
os_idx, client_idx, ver := ua.ParseUserAgent(userAgent)
u.Os = os_idx
u.Client = client_idx
u.Version = ver
u.RemoteAddr = strings.Split(u.RemoteAddr, ":")[0]
// remove extra characters
infoSlice := strings.Split(u.Info, " ")
infoLen := len(infoSlice)
if infoLen > 1 {
if u.Username == infoSlice[0] {
u.Info = strings.Join(infoSlice[1:], " ")
}
// delete - char
if infoLen > 2 && infoSlice[1] == "-" {
u.Info = u.Info[2:]
}
}
// limit the max length of char
u.Version = substr(u.Version, 0, 15)
u.DeviceType = substr(u.DeviceType, 0, 128)
u.PlatformVersion = substr(u.PlatformVersion, 0, 128)
u.Info = substr(u.Info, 0, 255)
UserActLogIns.Pool.JobQueue <- func() {
err := Add(u)
if err != nil {
base.Error("Add UserActLog error: ", err)
}
}
}
// 转义操作类型, 方便vue显示
func (ua *UserActLogProcess) GetStatusOpsWithTag() interface{} {
type StatusTag struct {
Key int `json:"key"`
Value string `json:"value"`
Tag string `json:"tag"`
}
var res []StatusTag
for k, v := range ua.StatusOps {
tag := "info"
switch k {
case UserAuthFail:
tag = "danger"
case UserAuthSuccess:
tag = "success"
case UserConnected:
tag = ""
}
res = append(res, StatusTag{k, v, tag})
}
return res
}
func (ua *UserActLogProcess) GetInfoOpsById(id uint8) string {
return ua.InfoOps[id]
}
// 解析user agent
func (ua *UserActLogProcess) ParseUserAgent(userAgent string) (os_idx, client_idx uint8, ver string) {
// Unknown
if len(userAgent) == 0 {
return 0, 0, ""
}
// OS
os_idx = 0
if strings.Contains(userAgent, "windows") {
os_idx = 1
} else if strings.Contains(userAgent, "mac os") || strings.Contains(userAgent, "darwin_i386") {
os_idx = 2
} else if strings.Contains(userAgent, "darwin_arm") || strings.Contains(userAgent, "apple") {
os_idx = 5
} else if strings.Contains(userAgent, "android") {
os_idx = 4
} else if strings.Contains(userAgent, "linux") {
os_idx = 3
}
// Client
client_idx = 0
if strings.Contains(userAgent, "anyconnect") {
client_idx = 1
} else if strings.Contains(userAgent, "openconnect") {
client_idx = 2
} else if strings.Contains(userAgent, "anylink") {
client_idx = 3
}
// Version
uaSlice := strings.Split(userAgent, " ")
ver = uaSlice[len(uaSlice)-1]
if ver[0] == 'v' {
ver = ver[1:]
}
if !regexp.MustCompile(`^(\d+\.?)+$`).MatchString(ver) {
ver = ""
}
return
}
// 清除用户操作日志
func (ua *UserActLogProcess) ClearUserActLog(ts string) (int64, error) {
affected, err := xdb.Where("created_at < '" + ts + "'").Delete(&UserActLog{})
return affected, err
}
// 后台筛选用户操作日志
func (ua *UserActLogProcess) GetSession(values url.Values) *xorm.Session {
session := xdb.Where("1=1")
if values.Get("username") != "" {
session.And("username = ?", values.Get("username"))
}
if values.Get("sdate") != "" {
session.And("created_at >= ?", values.Get("sdate")+" 00:00:00'")
}
if values.Get("edate") != "" {
session.And("created_at <= ?", values.Get("edate")+" 23:59:59'")
}
if values.Get("status") != "" {
session.And("status = ?", cast.ToUint8(values.Get("status"))-1)
}
if values.Get("os") != "" {
session.And("os = ?", cast.ToUint8(values.Get("os"))-1)
}
if values.Get("sort") == "1" {
session.OrderBy("id desc")
} else {
session.OrderBy("id asc")
}
return session
}
// 截取字符串
func substr(s string, pos, length int) string {
runes := []rune(s)
l := pos + length
if l > len(runes) {
l = len(runes)
}
return string(runes[pos:l])
}