feat:add notice manage

#560
This commit is contained in:
samwaf
2025-11-25 12:51:13 +08:00
parent 14ee020e88
commit 00c281f67a
9 changed files with 481 additions and 135 deletions

View File

@@ -65,9 +65,18 @@ func (w *WafLogAPi) GetListApi(c *gin.Context) {
}
func (w *WafLogAPi) ExportDBApi(c *gin.Context) {
if global.GWAF_CAN_EXPORT_DOWNLOAD_LOG == false {
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "导出失败"},
OperaCnt: "当前不允许导出",
// 使用操作结果消息格式
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OpResultMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "导出失败",
Server: serverName,
},
Msg: "当前不允许导出",
Success: "false",
})
response.FailWithMessage("当前不允许导出", c)
return
@@ -121,9 +130,18 @@ func (w *WafLogAPi) ExportDBApi(c *gin.Context) {
}
func (w *WafLogAPi) DownloadApi(c *gin.Context) {
if global.GWAF_CAN_EXPORT_DOWNLOAD_LOG == false {
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "下载失败"},
OperaCnt: "当前不允许下载",
// 使用操作结果消息格式
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OpResultMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "下载失败",
Server: serverName,
},
Msg: "当前不允许下载",
Success: "false",
})
c.JSON(http.StatusInternalServerError, gin.H{"message": "当前不允许下载"})
return

View File

@@ -11,12 +11,13 @@ import (
"SamWaf/model/common/response"
"SamWaf/model/request"
response2 "SamWaf/model/response"
"SamWaf/service/waf_service"
"SamWaf/utils"
"fmt"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/pquerna/otp/totp"
"time"
)
type WafLoginApi struct {
@@ -68,7 +69,8 @@ func (w *WafLoginApi) LoginApi(c *gin.Context) {
hitCounter++
global.GCACHE_WAFCACHE.SetWithTTl(cacheKey, hitCounter, time.Duration(global.GCONFIG_RECORD_LOGIN_LIMIT_MINTUTES)*time.Minute)
loginError := fmt.Sprintf("输入密码错误超过次数限制IP:%s 归属地区:%s", clientIP, clientCountry)
clientCountryStr := strings.Join(clientCountry, ",")
loginError := fmt.Sprintf("输入密码错误超过次数限制IP:%s 归属地区:%s", clientIP, clientCountryStr)
wafSysLog := model.WafSysLog{
BaseOrm: baseorm.BaseOrm{
Id: uuid.GenUUID(),
@@ -82,9 +84,19 @@ func (w *WafLoginApi) LoginApi(c *gin.Context) {
}
global.GQEQUE_LOG_DB.Enqueue(&wafSysLog)
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "登录错误"},
OperaCnt: loginError,
// 使用新的系统错误消息格式
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.SystemErrorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "登录错误",
Server: serverName,
},
ErrorType: "登录失败",
ErrorMsg: fmt.Sprintf("密码错误超限IP:%s (%s)", clientIP, clientCountryStr),
Time: time.Now().Format("2006-01-02 15:04:05"),
})
response.FailWithMessage("登录密码错误", c)
return
@@ -133,13 +145,27 @@ func (w *WafLoginApi) LoginApi(c *gin.Context) {
//令牌记录到cache里
global.GCACHE_WAFCACHE.SetWithTTl(enums.CACHE_TOKEN+accessToken, *tokenInfo, time.Duration(global.GCONFIG_RECORD_TOKEN_EXPIRE_MINTUTES)*time.Minute)
//通知信息
noticeStr := fmt.Sprintf("登录IP:%s 归属地区:%s", clientIP, clientCountry)
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "登录信息"},
OperaCnt: noticeStr,
//通知信息(使用新的消息格式,通过队列统一处理)
currentTime := time.Now().Format("2006-01-02 15:04:05")
clientCountryStr := strings.Join(clientCountry, ",")
noticeStr := fmt.Sprintf("登录IP:%s 归属地区:%s", clientIP, clientCountryStr)
// 将用户登录信息加入消息队列(新格式)
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.UserLoginMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "登录信息",
Server: serverName,
},
Username: bean.LoginAccount,
Ip: clientIP + " (" + clientCountryStr + ")",
Time: currentTime,
})
// 记录系统日志
wafSysLog := model.WafSysLog{
BaseOrm: baseorm.BaseOrm{
Id: uuid.GenUUID(),
@@ -153,16 +179,6 @@ func (w *WafLoginApi) LoginApi(c *gin.Context) {
}
global.GQEQUE_LOG_DB.Enqueue(&wafSysLog)
// 发送用户登录通知
go func() {
title, content := waf_service.WafNotifySenderServiceApp.FormatUserLoginMessage(
bean.LoginAccount,
clientIP,
time.Now().Format("2006-01-02 15:04:05"),
)
waf_service.WafNotifySenderServiceApp.SendNotification(model.MSG_TYPE_USER_LOGIN, title, content)
}()
response.OkWithDetailed(response2.LoginRep{
AccessToken: tokenInfo.AccessToken,
}, "登录成功", c)

View File

@@ -63,6 +63,74 @@ type OpResultMessageInfo struct {
Success string `json:"success"`
}
/*
*
用户登录信息
*/
type UserLoginMessageInfo struct {
BaseMessageInfo
Username string `json:"username"` // 用户名
Ip string `json:"ip"` // 登录IP
Time string `json:"time"` // 登录时间
}
/*
*
攻击信息
*/
type AttackInfoMessageInfo struct {
BaseMessageInfo
AttackType string `json:"attack_type"` // 攻击类型
Url string `json:"url"` // 攻击URL
Ip string `json:"ip"` // 攻击IP
Time string `json:"time"` // 攻击时间
}
/*
*
周报信息
*/
type WeeklyReportMessageInfo struct {
BaseMessageInfo
TotalRequests int64 `json:"total_requests"` // 总请求数
BlockedRequests int64 `json:"blocked_requests"` // 拦截请求数
WeekRange string `json:"week_range"` // 周期范围
}
/*
*
SSL证书过期信息
*/
type SSLExpireMessageInfo struct {
BaseMessageInfo
Domain string `json:"domain"` // 域名
ExpireTime string `json:"expire_time"` // 过期时间
DaysLeft int `json:"days_left"` // 剩余天数
}
/*
*
系统错误信息
*/
type SystemErrorMessageInfo struct {
BaseMessageInfo
ErrorType string `json:"error_type"` // 错误类型
ErrorMsg string `json:"error_msg"` // 错误信息
Time string `json:"time"` // 发生时间
}
/*
*
IP封禁信息
*/
type IPBanMessageInfo struct {
BaseMessageInfo
Ip string `json:"ip"` // IP地址
Reason string `json:"reason"` // 封禁原因
Duration int `json:"duration"` // 封禁时长(分钟)
Time string `json:"time"` // 封禁时间
}
func (r RuleMessageInfo) ToFormat() map[string]*wechat.DataItem {
Data := map[string]*wechat.DataItem{}
Data["domain"] = &wechat.DataItem{

View File

@@ -19,6 +19,8 @@ type NotifySubscription struct {
// 消息类型常量
const (
MSG_TYPE_RULE_TRIGGER = "rule_trigger" // 规则触发
MSG_TYPE_OPERATION_NOTICE = "operation_notice" // 操作通知
MSG_TYPE_USER_LOGIN = "user_login" // 用户登录
MSG_TYPE_ATTACK_INFO = "attack_info" // 攻击信息
MSG_TYPE_WEEKLY_REPORT = "weekly_report" // 周报

View File

@@ -3,6 +3,7 @@ package waf_service
import (
"SamWaf/common/zlog"
"SamWaf/global"
"SamWaf/innerbean"
"SamWaf/model"
"SamWaf/wafnotify/dingtalk"
"SamWaf/wafnotify/feishu"
@@ -126,3 +127,95 @@ func (receiver *WafNotifySenderService) FormatIPBanMessage(ip, reason, time stri
content := fmt.Sprintf("**IP地址:** %s\n\n**封禁原因:** %s\n\n**封禁时长:** %d分钟\n\n**封禁时间:** %s", ip, reason, duration, time)
return title, content
}
// ========== 消息映射方法:将旧消息结构转换为新格式 ==========
// FormatMessageByType 根据消息类型格式化消息(统一入口)
func (receiver *WafNotifySenderService) FormatMessageByType(messageInfo interface{}) (messageType, title, content string) {
switch msg := messageInfo.(type) {
case innerbean.RuleMessageInfo:
return receiver.FormatRuleMessage(msg)
case innerbean.OperatorMessageInfo:
return receiver.FormatOperatorMessage(msg)
case innerbean.UserLoginMessageInfo:
return receiver.FormatUserLoginMessageFromBean(msg)
case innerbean.AttackInfoMessageInfo:
return receiver.FormatAttackInfoMessageFromBean(msg)
case innerbean.WeeklyReportMessageInfo:
return receiver.FormatWeeklyReportMessageFromBean(msg)
case innerbean.SSLExpireMessageInfo:
return receiver.FormatSSLExpireMessageFromBean(msg)
case innerbean.SystemErrorMessageInfo:
return receiver.FormatSystemErrorMessageFromBean(msg)
case innerbean.IPBanMessageInfo:
return receiver.FormatIPBanMessageFromBean(msg)
default:
return "", "", ""
}
}
// FormatRuleMessage 格式化规则触发消息(映射旧的 RuleMessageInfo
func (receiver *WafNotifySenderService) FormatRuleMessage(msg innerbean.RuleMessageInfo) (string, string, string) {
messageType := "rule_trigger" // 规则触发类型
title := "安全规则触发通知"
content := fmt.Sprintf("**操作类型:** %s\n\n**服务器:** %s\n\n**域名:** %s\n\n**规则信息:** %s\n\n**IP地址:** %s",
msg.OperaType,
msg.Server,
msg.Domain,
msg.RuleInfo,
msg.Ip)
return messageType, title, content
}
// FormatOperatorMessage 格式化操作消息(映射旧的 OperatorMessageInfo
func (receiver *WafNotifySenderService) FormatOperatorMessage(msg innerbean.OperatorMessageInfo) (string, string, string) {
messageType := "operation_notice" // 操作通知类型
title := "操作通知"
content := fmt.Sprintf("**操作类型:** %s\n\n**服务器:** %s\n\n**操作内容:** %s",
msg.OperaType,
msg.Server,
msg.OperaCnt)
return messageType, title, content
}
// FormatUserLoginMessageFromBean 格式化用户登录消息从Bean
func (receiver *WafNotifySenderService) FormatUserLoginMessageFromBean(msg innerbean.UserLoginMessageInfo) (string, string, string) {
messageType := "user_login" // 用户登录类型
title, content := receiver.FormatUserLoginMessage(msg.Username, msg.Ip, msg.Time)
return messageType, title, content
}
// FormatAttackInfoMessageFromBean 格式化攻击信息消息从Bean
func (receiver *WafNotifySenderService) FormatAttackInfoMessageFromBean(msg innerbean.AttackInfoMessageInfo) (string, string, string) {
messageType := "attack_info" // 攻击信息类型
title, content := receiver.FormatAttackInfoMessage(msg.AttackType, msg.Url, msg.Ip, msg.Time)
return messageType, title, content
}
// FormatWeeklyReportMessageFromBean 格式化周报消息从Bean
func (receiver *WafNotifySenderService) FormatWeeklyReportMessageFromBean(msg innerbean.WeeklyReportMessageInfo) (string, string, string) {
messageType := "weekly_report" // 周报类型
title, content := receiver.FormatWeeklyReportMessage(msg.TotalRequests, msg.BlockedRequests, msg.WeekRange)
return messageType, title, content
}
// FormatSSLExpireMessageFromBean 格式化SSL证书过期消息从Bean
func (receiver *WafNotifySenderService) FormatSSLExpireMessageFromBean(msg innerbean.SSLExpireMessageInfo) (string, string, string) {
messageType := "ssl_expire" // SSL证书过期类型
title, content := receiver.FormatSSLExpireMessage(msg.Domain, msg.ExpireTime, msg.DaysLeft)
return messageType, title, content
}
// FormatSystemErrorMessageFromBean 格式化系统错误消息从Bean
func (receiver *WafNotifySenderService) FormatSystemErrorMessageFromBean(msg innerbean.SystemErrorMessageInfo) (string, string, string) {
messageType := "system_error" // 系统错误类型
title, content := receiver.FormatSystemErrorMessage(msg.ErrorType, msg.ErrorMsg, msg.Time)
return messageType, title, content
}
// FormatIPBanMessageFromBean 格式化IP封禁消息从Bean
func (receiver *WafNotifySenderService) FormatIPBanMessageFromBean(msg innerbean.IPBanMessageInfo) (string, string, string) {
messageType := "ip_ban" // IP封禁类型
title, content := receiver.FormatIPBanMessage(msg.Ip, msg.Reason, msg.Time, msg.Duration)
return messageType, title, content
}

View File

@@ -69,8 +69,15 @@ func (waf *WafEngine) ApplySSLOrder(chanType int, bean model.SslOrder) {
}
global.GQEQUE_LOG_DB.Enqueue(&wafSysLog)
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "SSL证书申请失败"},
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "SSL证书申请失败",
Server: serverName,
},
OperaCnt: sslError,
})
} else {
@@ -94,8 +101,15 @@ func (waf *WafEngine) ApplySSLOrder(chanType int, bean model.SslOrder) {
}
global.GQEQUE_LOG_DB.Enqueue(&wafSysLog)
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "SSL证书申请成功"},
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "SSL证书申请成功",
Server: serverName,
},
OperaCnt: sslSuccess,
})
}
@@ -122,8 +136,15 @@ func (waf *WafEngine) ApplySSLOrder(chanType int, bean model.SslOrder) {
}
global.GQEQUE_LOG_DB.Enqueue(&wafSysLog)
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "SSL证书申请失败"},
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "SSL证书申请失败",
Server: serverName,
},
OperaCnt: sslError,
})
}
@@ -162,8 +183,15 @@ func (waf *WafEngine) ApplySSLOrder(chanType int, bean model.SslOrder) {
}
global.GQEQUE_LOG_DB.Enqueue(&wafSysLog)
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "SSL证书续期失败"},
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "SSL证书续期失败",
Server: serverName,
},
OperaCnt: sslError,
})
} else {
@@ -187,8 +215,15 @@ func (waf *WafEngine) ApplySSLOrder(chanType int, bean model.SslOrder) {
}
global.GQEQUE_LOG_DB.Enqueue(&wafSysLog)
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "SSL证书续期成功"},
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "SSL证书续期成功",
Server: serverName,
},
OperaCnt: sslSuccess,
})
}
@@ -214,8 +249,15 @@ func (waf *WafEngine) ApplySSLOrder(chanType int, bean model.SslOrder) {
}
global.GQEQUE_LOG_DB.Enqueue(&wafSysLog)
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "SSL证书续期失败"},
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "SSL证书续期失败",
Server: serverName,
},
OperaCnt: sslError,
})
}

View File

@@ -338,10 +338,21 @@ func (waf *WafEngine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 检测是否已经被CC封禁
ccCacheKey := enums.CACHE_CCVISITBAN_PRE + weblogbean.NetSrcIp
if global.GCACHE_WAFCACHE.IsKeyExist(ccCacheKey) {
visitIPError := fmt.Sprintf("当前IP已经被CC封禁IP:%s 归属地区:%s", weblogbean.NetSrcIp, region)
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "CC封禁提醒"},
OperaCnt: visitIPError,
// 使用新的IP封禁消息格式
regionStr := strings.Join(region, ",")
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.IPBanMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "CC封禁提醒",
Server: serverName,
},
Ip: weblogbean.NetSrcIp + " (" + regionStr + ")",
Reason: "CC攻击访问频次过高",
Duration: 0, // CC封禁时长由配置决定
Time: time.Now().Format("2006-01-02 15:04:05"),
})
EchoErrorInfo(w, r, &weblogbean, "", "当前IP由于访问频次太高暂时无法访问", hostTarget, waf.HostTarget[waf.HostCode[global.GWAF_GLOBAL_HOST_CODE]], false)
return

View File

@@ -7,9 +7,11 @@ import (
"SamWaf/global"
"SamWaf/innerbean"
"SamWaf/model"
"SamWaf/service/waf_service"
"SamWaf/utils"
"SamWaf/wafsec"
"encoding/json"
"fmt"
"strings"
"time"
)
@@ -31,84 +33,27 @@ func ProcessMessageDequeEngine() {
zlog.Error("来得信息未空")
continue
}
messageinfo := popFront.(interface{})
isCanSend := false
switch messageinfo.(type) {
// 处理不同类型的消息
switch msg := popFront.(type) {
case innerbean.RuleMessageInfo:
rulemessage := messageinfo.(innerbean.RuleMessageInfo)
isCanSend = checkCanSend(rulemessage.RuleInfo)
if isCanSend {
if global.GWAF_NOTICE_ENABLE == false {
zlog.Debug("通知关闭状态")
} else {
utils.NotifyHelperApp.SendRuleInfo(rulemessage)
}
if rulemessage.BaseMessageInfo.OperaType == "命中保护规则" {
//发送websocket
for _, ws := range global.GWebSocket.GetAllWebSocket() {
if ws != nil {
msgBody, _ := json.Marshal(model.MsgDataPacket{
MessageId: uuid.GenUUID(),
MessageType: "命中保护规则",
MessageData: rulemessage.RuleInfo + rulemessage.Ip,
MessageAttach: nil,
MessageDateTime: time.Now().Format("2006-01-02 15:04:05"),
MessageUnReadStatus: true,
})
encryptStr, _ := wafsec.AesEncrypt(msgBody, global.GWAF_COMMUNICATION_KEY)
//写入ws数据
msgBytes, err := json.Marshal(model.MsgPacket{
MsgCode: "200",
MsgDataPacket: encryptStr,
MsgCmdType: "Info",
})
err = ws.WriteMessage(1, msgBytes)
if err != nil {
continue
}
}
}
}
}
break
handleRuleMessage(msg)
case innerbean.OperatorMessageInfo:
operatorMessage := messageinfo.(innerbean.OperatorMessageInfo)
isCanSend = checkCanSend(operatorMessage.OperaType)
if !isCanSend {
continue
}
utils.NotifyHelperApp.SendNoticeInfo(operatorMessage)
//发送websocket
for _, ws := range global.GWebSocket.GetAllWebSocket() {
if ws != nil {
msgBody, _ := json.Marshal(model.MsgDataPacket{
MessageId: uuid.GenUUID(),
MessageType: operatorMessage.OperaType,
MessageData: operatorMessage.OperaCnt,
MessageAttach: nil,
MessageDateTime: time.Now().Format("2006-01-02 15:04:05"),
MessageUnReadStatus: true,
})
encryptStr, _ := wafsec.AesEncrypt(msgBody, global.GWAF_COMMUNICATION_KEY)
//写入ws数据
msgBytes, err := json.Marshal(model.MsgPacket{
MsgCode: "200",
MsgDataPacket: encryptStr,
MsgCmdType: "Info",
})
err = ws.WriteMessage(1, msgBytes)
if err != nil {
continue
}
}
}
break
handleOperatorMessage(msg)
case innerbean.UserLoginMessageInfo:
handleUserLoginMessage(msg)
case innerbean.AttackInfoMessageInfo:
handleAttackInfoMessage(msg)
case innerbean.WeeklyReportMessageInfo:
handleWeeklyReportMessage(msg)
case innerbean.SSLExpireMessageInfo:
handleSSLExpireMessage(msg)
case innerbean.SystemErrorMessageInfo:
handleSystemErrorMessage(msg)
case innerbean.IPBanMessageInfo:
handleIPBanMessage(msg)
case innerbean.ExportResultMessageInfo:
exportResult := messageinfo.(innerbean.ExportResultMessageInfo)
exportResult := msg
//发送websocket
for _, ws := range global.GWebSocket.GetAllWebSocket() {
if ws != nil {
@@ -135,10 +80,9 @@ func ProcessMessageDequeEngine() {
}
}
}
break
case innerbean.UpdateResultMessageInfo:
//升级结果
updatemessage := messageinfo.(innerbean.UpdateResultMessageInfo)
updatemessage := msg
//发送websocket
for _, ws := range global.GWebSocket.GetAllWebSocket() {
if ws != nil {
@@ -165,10 +109,9 @@ func ProcessMessageDequeEngine() {
}
}
}
break
case innerbean.OpResultMessageInfo:
//操作实时结果
updatemessage := messageinfo.(innerbean.OpResultMessageInfo)
updatemessage := msg
//发送websocket
for _, ws := range global.GWebSocket.GetAllWebSocket() {
if ws != nil {
@@ -195,9 +138,8 @@ func ProcessMessageDequeEngine() {
}
}
}
break
case innerbean.SystemStatsData:
statsData := messageinfo.(innerbean.SystemStatsData)
statsData := msg
//发送websocket
for _, ws := range global.GWebSocket.GetAllWebSocket() {
if ws != nil {
@@ -224,8 +166,6 @@ func ProcessMessageDequeEngine() {
}
}
}
break
}
}
@@ -237,7 +177,8 @@ func ProcessMessageDequeEngine() {
// checkCanSend 抑止发送频率
func checkCanSend(key string) bool {
isCanSend := false
if strings.HasPrefix(key, "SSL证书申请") {
// SSL证书相关的消息包括申请和续期都直接发送不受频率限制
if strings.HasPrefix(key, "SSL证书") {
isCanSend = true
return isCanSend
}
@@ -268,3 +209,151 @@ func checkCanSend(key string) bool {
}
return isCanSend
}
// ========== 各类消息处理函数(保持队列+WebSocket方式集成新的通知系统 ==========
// handleRuleMessage 处理规则触发消息
func handleRuleMessage(msg innerbean.RuleMessageInfo) {
isCanSend := checkCanSend(msg.RuleInfo)
if !isCanSend {
return
}
// 1. 发送到新的通知订阅系统(使用格式化后的消息)
messageType, title, content := waf_service.WafNotifySenderServiceApp.FormatRuleMessage(msg)
waf_service.WafNotifySenderServiceApp.SendNotification(messageType, title, content)
// 2. 保留原有的通知方式(兼容旧系统)
if global.GWAF_NOTICE_ENABLE {
utils.NotifyHelperApp.SendRuleInfo(msg)
} else {
zlog.Debug("通知关闭状态")
}
// 3. 发送到 WebSocket保持原有功能
if msg.BaseMessageInfo.OperaType == "命中保护规则" {
sendToWebSocket("命中保护规则", msg.RuleInfo+msg.Ip, nil, "Info")
}
}
// handleOperatorMessage 处理操作消息
func handleOperatorMessage(msg innerbean.OperatorMessageInfo) {
isCanSend := checkCanSend(msg.OperaType)
if !isCanSend {
return
}
// 1. 发送到新的通知订阅系统
messageType, title, content := waf_service.WafNotifySenderServiceApp.FormatOperatorMessage(msg)
waf_service.WafNotifySenderServiceApp.SendNotification(messageType, title, content)
// 2. 保留原有的通知方式
utils.NotifyHelperApp.SendNoticeInfo(msg)
// 3. 发送到 WebSocket
sendToWebSocket(msg.OperaType, msg.OperaCnt, nil, "Info")
}
// handleUserLoginMessage 处理用户登录消息
func handleUserLoginMessage(msg innerbean.UserLoginMessageInfo) {
// 1. 发送到新的通知订阅系统
messageType, title, content := waf_service.WafNotifySenderServiceApp.FormatUserLoginMessageFromBean(msg)
waf_service.WafNotifySenderServiceApp.SendNotification(messageType, title, content)
// 2. 发送到 WebSocket
wsContent := fmt.Sprintf("用户 %s 从 %s 登录", msg.Username, msg.Ip)
sendToWebSocket("用户登录", wsContent, nil, "Info")
}
// handleAttackInfoMessage 处理攻击信息消息
func handleAttackInfoMessage(msg innerbean.AttackInfoMessageInfo) {
isCanSend := checkCanSend(msg.AttackType)
if !isCanSend {
return
}
// 1. 发送到新的通知订阅系统
messageType, title, content := waf_service.WafNotifySenderServiceApp.FormatAttackInfoMessageFromBean(msg)
waf_service.WafNotifySenderServiceApp.SendNotification(messageType, title, content)
// 2. 发送到 WebSocket
wsContent := fmt.Sprintf("检测到 %s 攻击来源IP: %s", msg.AttackType, msg.Ip)
sendToWebSocket("攻击告警", wsContent, nil, "Info")
}
// handleWeeklyReportMessage 处理周报消息
func handleWeeklyReportMessage(msg innerbean.WeeklyReportMessageInfo) {
// 1. 发送到新的通知订阅系统
messageType, title, content := waf_service.WafNotifySenderServiceApp.FormatWeeklyReportMessageFromBean(msg)
waf_service.WafNotifySenderServiceApp.SendNotification(messageType, title, content)
// 2. 发送到 WebSocket
wsContent := fmt.Sprintf("周期: %s, 总请求: %d, 拦截: %d", msg.WeekRange, msg.TotalRequests, msg.BlockedRequests)
sendToWebSocket("WAF周报", wsContent, nil, "Info")
}
// handleSSLExpireMessage 处理SSL证书过期消息
func handleSSLExpireMessage(msg innerbean.SSLExpireMessageInfo) {
// SSL证书消息总是发送不受频率限制
// 1. 发送到新的通知订阅系统
messageType, title, content := waf_service.WafNotifySenderServiceApp.FormatSSLExpireMessageFromBean(msg)
waf_service.WafNotifySenderServiceApp.SendNotification(messageType, title, content)
// 2. 发送到 WebSocket
wsContent := fmt.Sprintf("域名 %s 的SSL证书将在 %d 天后过期", msg.Domain, msg.DaysLeft)
sendToWebSocket("SSL证书过期提醒", wsContent, nil, "Info")
}
// handleSystemErrorMessage 处理系统错误消息
func handleSystemErrorMessage(msg innerbean.SystemErrorMessageInfo) {
// 1. 发送到新的通知订阅系统
messageType, title, content := waf_service.WafNotifySenderServiceApp.FormatSystemErrorMessageFromBean(msg)
waf_service.WafNotifySenderServiceApp.SendNotification(messageType, title, content)
// 2. 发送到 WebSocket
wsContent := fmt.Sprintf("系统错误: %s - %s", msg.ErrorType, msg.ErrorMsg)
sendToWebSocket("系统错误", wsContent, nil, "Info")
}
// handleIPBanMessage 处理IP封禁消息
func handleIPBanMessage(msg innerbean.IPBanMessageInfo) {
isCanSend := checkCanSend(msg.Ip)
if !isCanSend {
return
}
// 1. 发送到新的通知订阅系统
messageType, title, content := waf_service.WafNotifySenderServiceApp.FormatIPBanMessageFromBean(msg)
waf_service.WafNotifySenderServiceApp.SendNotification(messageType, title, content)
// 2. 发送到 WebSocket
wsContent := fmt.Sprintf("IP %s 已被封禁,原因: %s", msg.Ip, msg.Reason)
sendToWebSocket("IP封禁通知", wsContent, nil, "Info")
}
// sendToWebSocket 统一的 WebSocket 发送函数
func sendToWebSocket(messageType, messageData string, messageAttach interface{}, cmdType string) {
for _, ws := range global.GWebSocket.GetAllWebSocket() {
if ws != nil {
msgBody, _ := json.Marshal(model.MsgDataPacket{
MessageId: uuid.GenUUID(),
MessageType: messageType,
MessageData: messageData,
MessageAttach: messageAttach,
MessageDateTime: time.Now().Format("2006-01-02 15:04:05"),
MessageUnReadStatus: true,
})
encryptStr, _ := wafsec.AesEncrypt(msgBody, global.GWAF_COMMUNICATION_KEY)
msgBytes, err := json.Marshal(model.MsgPacket{
MsgCode: "200",
MsgDataPacket: encryptStr,
MsgCmdType: cmdType,
})
err = ws.WriteMessage(1, msgBytes)
if err != nil {
zlog.Debug("发送websocket错误", err)
continue
}
}
}
}

View File

@@ -15,8 +15,15 @@ func TaskStatusNotify() {
if err == nil {
noticeStr := fmt.Sprintf("今日访问量:%d 今天恶意访问量:%d 昨日恶意访问量:%d", statHomeInfo.VisitCountOfToday, statHomeInfo.AttackCountOfToday, statHomeInfo.AttackCountOfYesterday)
serverName := global.GWAF_CUSTOM_SERVER_NAME
if serverName == "" {
serverName = "未命名服务器"
}
global.GQEQUE_MESSAGE_DB.Enqueue(innerbean.OperatorMessageInfo{
BaseMessageInfo: innerbean.BaseMessageInfo{OperaType: "汇总通知"},
BaseMessageInfo: innerbean.BaseMessageInfo{
OperaType: "汇总通知",
Server: serverName,
},
OperaCnt: noticeStr,
})
} else {