2020-09-20 20:12:47 +08:00
package models
import (
2020-10-06 21:02:15 +08:00
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
2020-09-20 20:12:47 +08:00
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
2021-08-25 11:18:37 +08:00
"github.com/iwind/TeaGo/lists"
2021-01-17 16:48:00 +08:00
"github.com/iwind/TeaGo/maps"
2020-10-06 21:02:15 +08:00
"github.com/iwind/TeaGo/types"
2020-09-20 20:12:47 +08:00
)
const (
HTTPFirewallPolicyStateEnabled = 1 // 已启用
HTTPFirewallPolicyStateDisabled = 0 // 已禁用
)
type HTTPFirewallPolicyDAO dbs . DAO
func NewHTTPFirewallPolicyDAO ( ) * HTTPFirewallPolicyDAO {
return dbs . NewDAO ( & HTTPFirewallPolicyDAO {
DAOObject : dbs . DAOObject {
DB : Tea . Env ,
Table : "edgeHTTPFirewallPolicies" ,
Model : new ( HTTPFirewallPolicy ) ,
PkName : "id" ,
} ,
} ) . ( * HTTPFirewallPolicyDAO )
}
2020-10-13 20:05:13 +08:00
var SharedHTTPFirewallPolicyDAO * HTTPFirewallPolicyDAO
func init ( ) {
dbs . OnReady ( func ( ) {
SharedHTTPFirewallPolicyDAO = NewHTTPFirewallPolicyDAO ( )
} )
}
2020-09-20 20:12:47 +08:00
2021-06-07 08:58:26 +08:00
// Init 初始化
2020-09-26 08:06:40 +08:00
func ( this * HTTPFirewallPolicyDAO ) Init ( ) {
2021-01-17 16:48:00 +08:00
_ = this . DAOObject . Init ( )
2020-09-26 08:06:40 +08:00
}
2021-06-07 08:58:26 +08:00
// EnableHTTPFirewallPolicy 启用条目
2021-01-01 23:31:30 +08:00
func ( this * HTTPFirewallPolicyDAO ) EnableHTTPFirewallPolicy ( tx * dbs . Tx , id int64 ) error {
_ , err := this . Query ( tx ) .
2020-09-20 20:12:47 +08:00
Pk ( id ) .
Set ( "state" , HTTPFirewallPolicyStateEnabled ) .
Update ( )
return err
}
2021-06-07 08:58:26 +08:00
// DisableHTTPFirewallPolicy 禁用条目
2021-02-02 16:22:47 +08:00
func ( this * HTTPFirewallPolicyDAO ) DisableHTTPFirewallPolicy ( tx * dbs . Tx , policyId int64 ) error {
2021-01-01 23:31:30 +08:00
_ , err := this . Query ( tx ) .
2021-02-02 16:22:47 +08:00
Pk ( policyId ) .
2020-09-20 20:12:47 +08:00
Set ( "state" , HTTPFirewallPolicyStateDisabled ) .
Update ( )
2021-02-02 16:22:47 +08:00
if err != nil {
return err
}
return this . NotifyUpdate ( tx , policyId )
2020-09-20 20:12:47 +08:00
}
2021-06-07 08:58:26 +08:00
// FindEnabledHTTPFirewallPolicy 查找启用中的条目
2021-01-01 23:31:30 +08:00
func ( this * HTTPFirewallPolicyDAO ) FindEnabledHTTPFirewallPolicy ( tx * dbs . Tx , id int64 ) ( * HTTPFirewallPolicy , error ) {
result , err := this . Query ( tx ) .
2020-09-20 20:12:47 +08:00
Pk ( id ) .
Attr ( "state" , HTTPFirewallPolicyStateEnabled ) .
Find ( )
if result == nil {
return nil , err
}
return result . ( * HTTPFirewallPolicy ) , err
}
2021-06-07 08:58:26 +08:00
// FindHTTPFirewallPolicyName 根据主键查找名称
2021-01-01 23:31:30 +08:00
func ( this * HTTPFirewallPolicyDAO ) FindHTTPFirewallPolicyName ( tx * dbs . Tx , id int64 ) ( string , error ) {
return this . Query ( tx ) .
2020-09-20 20:12:47 +08:00
Pk ( id ) .
Result ( "name" ) .
FindStringCol ( "" )
}
2021-06-07 08:58:26 +08:00
// FindAllEnabledFirewallPolicies 查找所有可用策略
2021-01-01 23:31:30 +08:00
func ( this * HTTPFirewallPolicyDAO ) FindAllEnabledFirewallPolicies ( tx * dbs . Tx ) ( result [ ] * HTTPFirewallPolicy , err error ) {
_ , err = this . Query ( tx ) .
2020-09-20 20:12:47 +08:00
State ( HTTPFirewallPolicyStateEnabled ) .
DescPk ( ) .
Slice ( & result ) .
FindAll ( )
return
}
2020-10-06 21:02:15 +08:00
2021-06-07 08:58:26 +08:00
// CreateFirewallPolicy 创建策略
2021-01-20 14:19:29 +08:00
func ( this * HTTPFirewallPolicyDAO ) CreateFirewallPolicy ( tx * dbs . Tx , userId int64 , serverId int64 , isOn bool , name string , description string , inboundJSON [ ] byte , outboundJSON [ ] byte ) ( int64 , error ) {
2020-10-06 21:02:15 +08:00
op := NewHTTPFirewallPolicyOperator ( )
2021-01-03 20:18:07 +08:00
op . UserId = userId
2021-01-20 14:19:29 +08:00
op . ServerId = serverId
2020-10-06 21:02:15 +08:00
op . State = HTTPFirewallPolicyStateEnabled
op . IsOn = isOn
op . Name = name
op . Description = description
if len ( inboundJSON ) > 0 {
op . Inbound = inboundJSON
}
if len ( outboundJSON ) > 0 {
op . Outbound = outboundJSON
}
2021-01-01 23:31:30 +08:00
err := this . Save ( tx , op )
2020-10-06 21:02:15 +08:00
return types . Int64 ( op . Id ) , err
}
2021-08-25 11:18:37 +08:00
// CreateDefaultFirewallPolicy 创建默认的WAF策略
func ( this * HTTPFirewallPolicyDAO ) CreateDefaultFirewallPolicy ( tx * dbs . Tx , name string ) ( int64 , error ) {
policyId , err := this . CreateFirewallPolicy ( tx , 0 , 0 , true , "\"" + name + "\"WAF策略" , "默认创建的WAF策略" , nil , nil )
if err != nil {
return 0 , err
}
// 初始化
var groupCodes = [ ] string { }
templatePolicy := firewallconfigs . HTTPFirewallTemplate ( )
for _ , group := range templatePolicy . AllRuleGroups ( ) {
groupCodes = append ( groupCodes , group . Code )
}
inboundConfig := & firewallconfigs . HTTPFirewallInboundConfig { IsOn : true }
outboundConfig := & firewallconfigs . HTTPFirewallOutboundConfig { IsOn : true }
if templatePolicy . Inbound != nil {
for _ , group := range templatePolicy . Inbound . Groups {
isOn := lists . ContainsString ( groupCodes , group . Code )
group . IsOn = isOn
groupId , err := SharedHTTPFirewallRuleGroupDAO . CreateGroupFromConfig ( tx , group )
if err != nil {
return 0 , err
}
inboundConfig . GroupRefs = append ( inboundConfig . GroupRefs , & firewallconfigs . HTTPFirewallRuleGroupRef {
IsOn : true ,
GroupId : groupId ,
} )
}
}
if templatePolicy . Outbound != nil {
for _ , group := range templatePolicy . Outbound . Groups {
isOn := lists . ContainsString ( groupCodes , group . Code )
group . IsOn = isOn
groupId , err := SharedHTTPFirewallRuleGroupDAO . CreateGroupFromConfig ( tx , group )
if err != nil {
return 0 , err
}
outboundConfig . GroupRefs = append ( outboundConfig . GroupRefs , & firewallconfigs . HTTPFirewallRuleGroupRef {
IsOn : true ,
GroupId : groupId ,
} )
}
}
inboundConfigJSON , err := json . Marshal ( inboundConfig )
if err != nil {
return 0 , err
}
outboundConfigJSON , err := json . Marshal ( outboundConfig )
if err != nil {
return 0 , err
}
err = this . UpdateFirewallPolicyInboundAndOutbound ( tx , policyId , inboundConfigJSON , outboundConfigJSON , false )
if err != nil {
return 0 , err
}
return policyId , nil
}
2021-06-07 08:58:26 +08:00
// UpdateFirewallPolicyInboundAndOutbound 修改策略的Inbound和Outbound
2021-08-25 11:18:37 +08:00
func ( this * HTTPFirewallPolicyDAO ) UpdateFirewallPolicyInboundAndOutbound ( tx * dbs . Tx , policyId int64 , inboundJSON [ ] byte , outboundJSON [ ] byte , shouldNotify bool ) error {
2020-10-06 21:02:15 +08:00
if policyId <= 0 {
return errors . New ( "invalid policyId" )
}
op := NewHTTPFirewallPolicyOperator ( )
op . Id = policyId
if len ( inboundJSON ) > 0 {
op . Inbound = inboundJSON
} else {
op . Inbound = "null"
}
if len ( outboundJSON ) > 0 {
op . Outbound = outboundJSON
} else {
op . Outbound = "null"
}
2021-01-01 23:31:30 +08:00
err := this . Save ( tx , op )
2021-02-02 16:22:47 +08:00
if err != nil {
return err
}
2021-08-25 11:18:37 +08:00
if shouldNotify {
return this . NotifyUpdate ( tx , policyId )
}
return nil
2020-10-06 21:02:15 +08:00
}
2021-06-07 08:58:26 +08:00
// UpdateFirewallPolicyInbound 修改策略的Inbound
2021-01-01 23:31:30 +08:00
func ( this * HTTPFirewallPolicyDAO ) UpdateFirewallPolicyInbound ( tx * dbs . Tx , policyId int64 , inboundJSON [ ] byte ) error {
2020-11-06 11:02:53 +08:00
if policyId <= 0 {
return errors . New ( "invalid policyId" )
}
op := NewHTTPFirewallPolicyOperator ( )
op . Id = policyId
if len ( inboundJSON ) > 0 {
op . Inbound = inboundJSON
} else {
op . Inbound = "null"
}
2021-01-01 23:31:30 +08:00
err := this . Save ( tx , op )
2021-02-02 16:22:47 +08:00
if err != nil {
return err
}
return this . NotifyUpdate ( tx , policyId )
2020-11-06 11:02:53 +08:00
}
2021-06-07 08:58:26 +08:00
// UpdateFirewallPolicy 修改策略
2021-09-30 11:30:45 +08:00
func ( this * HTTPFirewallPolicyDAO ) UpdateFirewallPolicy ( tx * dbs . Tx , policyId int64 , isOn bool , name string , description string , inboundJSON [ ] byte , outboundJSON [ ] byte , blockOptionsJSON [ ] byte , mode firewallconfigs . FirewallMode ) error {
2020-10-06 21:02:15 +08:00
if policyId <= 0 {
return errors . New ( "invalid policyId" )
}
op := NewHTTPFirewallPolicyOperator ( )
op . Id = policyId
op . IsOn = isOn
op . Name = name
op . Description = description
2021-09-30 11:30:45 +08:00
op . Mode = mode
2020-10-06 21:02:15 +08:00
if len ( inboundJSON ) > 0 {
op . Inbound = inboundJSON
} else {
op . Inbound = "null"
}
if len ( outboundJSON ) > 0 {
op . Outbound = outboundJSON
} else {
op . Outbound = "null"
}
2020-11-22 16:54:48 +08:00
if len ( blockOptionsJSON ) > 0 {
op . BlockOptions = blockOptionsJSON
}
2021-01-01 23:31:30 +08:00
err := this . Save ( tx , op )
2021-02-02 16:22:47 +08:00
if err != nil {
return err
}
return this . NotifyUpdate ( tx , policyId )
2020-10-06 21:02:15 +08:00
}
2021-06-07 08:58:26 +08:00
// CountAllEnabledFirewallPolicies 计算所有可用的策略数量
func ( this * HTTPFirewallPolicyDAO ) CountAllEnabledFirewallPolicies ( tx * dbs . Tx , keyword string ) ( int64 , error ) {
query := this . Query ( tx )
if len ( keyword ) > 0 {
query . Where ( "(name LIKE :keyword)" ) .
Param ( "keyword" , "%" + keyword + "%" )
}
return query .
2020-10-06 21:02:15 +08:00
State ( HTTPFirewallPolicyStateEnabled ) .
2021-01-05 14:11:00 +08:00
Attr ( "userId" , 0 ) .
2021-01-20 14:19:29 +08:00
Attr ( "serverId" , 0 ) .
2020-10-06 21:02:15 +08:00
Count ( )
}
2021-06-07 08:58:26 +08:00
// ListEnabledFirewallPolicies 列出单页的策略
func ( this * HTTPFirewallPolicyDAO ) ListEnabledFirewallPolicies ( tx * dbs . Tx , keyword string , offset int64 , size int64 ) ( result [ ] * HTTPFirewallPolicy , err error ) {
query := this . Query ( tx )
if len ( keyword ) > 0 {
query . Where ( "(name LIKE :keyword)" ) .
Param ( "keyword" , "%" + keyword + "%" )
}
_ , err = query .
2020-10-06 21:02:15 +08:00
State ( HTTPFirewallPolicyStateEnabled ) .
2021-01-05 14:11:00 +08:00
Attr ( "userId" , 0 ) .
2021-01-20 14:19:29 +08:00
Attr ( "serverId" , 0 ) .
2020-10-06 21:02:15 +08:00
Offset ( offset ) .
Limit ( size ) .
DescPk ( ) .
Slice ( & result ) .
FindAll ( )
return
}
2021-06-07 08:58:26 +08:00
// ComposeFirewallPolicy 组合策略配置
2021-08-22 11:35:33 +08:00
func ( this * HTTPFirewallPolicyDAO ) ComposeFirewallPolicy ( tx * dbs . Tx , policyId int64 , cacheMap maps . Map ) ( * firewallconfigs . HTTPFirewallPolicy , error ) {
if cacheMap == nil {
cacheMap = maps . Map { }
}
var cacheKey = this . Table + ":config:" + types . String ( policyId )
var cache = cacheMap . Get ( cacheKey )
if cache != nil {
return cache . ( * firewallconfigs . HTTPFirewallPolicy ) , nil
}
2021-01-01 23:31:30 +08:00
policy , err := this . FindEnabledHTTPFirewallPolicy ( tx , policyId )
2020-10-06 21:02:15 +08:00
if err != nil {
return nil , err
}
if policy == nil {
return nil , nil
}
config := & firewallconfigs . HTTPFirewallPolicy { }
config . Id = int64 ( policy . Id )
config . IsOn = policy . IsOn == 1
config . Name = policy . Name
config . Description = policy . Description
2021-09-30 11:30:45 +08:00
config . Mode = policy . Mode
2020-10-06 21:02:15 +08:00
// Inbound
2020-10-07 11:18:12 +08:00
inbound := & firewallconfigs . HTTPFirewallInboundConfig { }
2020-10-06 21:02:15 +08:00
if IsNotNull ( policy . Inbound ) {
err = json . Unmarshal ( [ ] byte ( policy . Inbound ) , inbound )
if err != nil {
return nil , err
}
if len ( inbound . GroupRefs ) > 0 {
resultGroupRefs := [ ] * firewallconfigs . HTTPFirewallRuleGroupRef { }
resultGroups := [ ] * firewallconfigs . HTTPFirewallRuleGroup { }
for _ , groupRef := range inbound . GroupRefs {
2021-01-01 23:31:30 +08:00
groupConfig , err := SharedHTTPFirewallRuleGroupDAO . ComposeFirewallRuleGroup ( tx , groupRef . GroupId )
2020-10-06 21:02:15 +08:00
if err != nil {
return nil , err
}
if groupConfig != nil {
resultGroupRefs = append ( resultGroupRefs , groupRef )
resultGroups = append ( resultGroups , groupConfig )
}
}
inbound . GroupRefs = resultGroupRefs
inbound . Groups = resultGroups
}
}
2020-10-07 11:18:12 +08:00
config . Inbound = inbound
2020-10-06 21:02:15 +08:00
// Outbound
2020-10-07 11:18:12 +08:00
outbound := & firewallconfigs . HTTPFirewallOutboundConfig { }
2020-10-06 21:02:15 +08:00
if IsNotNull ( policy . Outbound ) {
err = json . Unmarshal ( [ ] byte ( policy . Outbound ) , outbound )
if err != nil {
return nil , err
}
if len ( outbound . GroupRefs ) > 0 {
resultGroupRefs := [ ] * firewallconfigs . HTTPFirewallRuleGroupRef { }
resultGroups := [ ] * firewallconfigs . HTTPFirewallRuleGroup { }
for _ , groupRef := range outbound . GroupRefs {
2021-01-01 23:31:30 +08:00
groupConfig , err := SharedHTTPFirewallRuleGroupDAO . ComposeFirewallRuleGroup ( tx , groupRef . GroupId )
2020-10-06 21:02:15 +08:00
if err != nil {
return nil , err
}
if groupConfig != nil {
resultGroupRefs = append ( resultGroupRefs , groupRef )
resultGroups = append ( resultGroups , groupConfig )
}
}
outbound . GroupRefs = resultGroupRefs
outbound . Groups = resultGroups
}
}
2020-10-07 11:18:12 +08:00
config . Outbound = outbound
2020-10-06 21:02:15 +08:00
2020-11-22 16:54:48 +08:00
// Block动作配置
if IsNotNull ( policy . BlockOptions ) {
blockAction := & firewallconfigs . HTTPFirewallBlockAction { }
err = json . Unmarshal ( [ ] byte ( policy . BlockOptions ) , blockAction )
if err != nil {
return config , err
}
config . BlockOptions = blockAction
}
2021-08-22 11:35:33 +08:00
cacheMap [ cacheKey ] = config
2020-10-06 21:02:15 +08:00
return config , nil
}
2021-01-03 20:18:07 +08:00
2021-06-07 08:58:26 +08:00
// CheckUserFirewallPolicy 检查用户防火墙策略
2021-01-03 20:18:07 +08:00
func ( this * HTTPFirewallPolicyDAO ) CheckUserFirewallPolicy ( tx * dbs . Tx , userId int64 , firewallPolicyId int64 ) error {
ok , err := this . Query ( tx ) .
Pk ( firewallPolicyId ) .
Attr ( "userId" , userId ) .
Exist ( )
if err != nil {
return err
}
2021-01-18 21:28:51 +08:00
if ok {
return nil
2021-01-03 20:18:07 +08:00
}
2021-01-18 21:28:51 +08:00
2021-06-27 08:31:10 +08:00
// 检查是否为用户Server所使用
webIds , err := SharedHTTPWebDAO . FindAllWebIdsWithHTTPFirewallPolicyId ( tx , firewallPolicyId )
if err != nil {
return err
}
for _ , webId := range webIds {
err := SharedHTTPWebDAO . CheckUserWeb ( tx , userId , webId )
if err != nil {
if err != ErrNotFound {
return err
}
} else {
return nil
}
}
2021-01-18 21:28:51 +08:00
return ErrNotFound
2021-01-03 20:18:07 +08:00
}
2021-01-17 16:48:00 +08:00
2021-06-07 08:58:26 +08:00
// FindEnabledFirewallPolicyIdsWithIPListId 查找包含某个IPList的所有策略
2021-01-17 16:48:00 +08:00
func ( this * HTTPFirewallPolicyDAO ) FindEnabledFirewallPolicyIdsWithIPListId ( tx * dbs . Tx , ipListId int64 ) ( [ ] int64 , error ) {
ones , err := this . Query ( tx ) .
ResultPk ( ) .
State ( HTTPFirewallPolicyStateEnabled ) .
2021-06-23 13:12:54 +08:00
Where ( "(JSON_CONTAINS(inbound, :listQuery, '$.whiteListRef') OR JSON_CONTAINS(inbound, :listQuery, '$.blackListRef') OR JSON_CONTAINS(inbound, :listQuery, '$.publicWhiteListRefs') OR JSON_CONTAINS(inbound, :listQuery, '$.publicBlackListRefs'))" ) .
2021-01-17 16:48:00 +08:00
Param ( "listQuery" , maps . Map { "isOn" : true , "listId" : ipListId } . AsJSON ( ) ) .
FindAll ( )
if err != nil {
return nil , err
}
result := [ ] int64 { }
for _ , one := range ones {
result = append ( result , int64 ( one . ( * HTTPFirewallPolicy ) . Id ) )
}
return result , nil
}
2021-06-07 08:58:26 +08:00
// FindEnabledFirewallPolicyIdWithRuleGroupId 查找包含某个规则分组的策略ID
2021-01-17 16:48:00 +08:00
func ( this * HTTPFirewallPolicyDAO ) FindEnabledFirewallPolicyIdWithRuleGroupId ( tx * dbs . Tx , ruleGroupId int64 ) ( int64 , error ) {
return this . Query ( tx ) .
ResultPk ( ) .
State ( HTTPFirewallPolicyStateEnabled ) .
Where ( "(JSON_CONTAINS(inbound, :jsonQuery, '$.groupRefs') OR JSON_CONTAINS(outbound, :jsonQuery, '$.groupRefs'))" ) .
Param ( "jsonQuery" , maps . Map { "groupId" : ruleGroupId } . AsJSON ( ) ) .
FindInt64Col ( 0 )
}
2021-06-07 08:58:26 +08:00
// UpdateFirewallPolicyServerId 设置某个策略所属的服务ID
2021-01-20 14:19:29 +08:00
func ( this * HTTPFirewallPolicyDAO ) UpdateFirewallPolicyServerId ( tx * dbs . Tx , policyId int64 , serverId int64 ) error {
2021-02-02 16:22:47 +08:00
_ , err := this . Query ( tx ) .
2021-01-20 14:19:29 +08:00
Pk ( policyId ) .
Set ( "serverId" , serverId ) .
Update ( )
return err
}
2021-06-07 08:58:26 +08:00
// NotifyUpdate 通知更新
2021-01-17 16:48:00 +08:00
func ( this * HTTPFirewallPolicyDAO ) NotifyUpdate ( tx * dbs . Tx , policyId int64 ) error {
webIds , err := SharedHTTPWebDAO . FindAllWebIdsWithHTTPFirewallPolicyId ( tx , policyId )
if err != nil {
return err
}
for _ , webId := range webIds {
err := SharedHTTPWebDAO . NotifyUpdate ( tx , webId )
if err != nil {
return err
}
}
clusterIds , err := SharedNodeClusterDAO . FindAllEnabledNodeClusterIdsWithHTTPFirewallPolicyId ( tx , policyId )
if err != nil {
return err
}
for _ , clusterId := range clusterIds {
err := SharedNodeClusterDAO . NotifyUpdate ( tx , clusterId )
if err != nil {
return err
}
}
return nil
}