实现WAF部分功能

This commit is contained in:
GoEdgeLab
2020-10-08 11:11:37 +08:00
parent 15d88b71a3
commit 8e0c10419a
28 changed files with 1443 additions and 17 deletions

1
go.mod
View File

@@ -13,6 +13,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 // indirect github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 // indirect
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa
google.golang.org/grpc v1.32.0 google.golang.org/grpc v1.32.0
google.golang.org/protobuf v1.25.0 // indirect google.golang.org/protobuf v1.25.0 // indirect
) )

1
go.sum
View File

@@ -154,6 +154,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa h1:5E4dL8+NgFOgjwbTKz+OOEGGhP+ectTmF842l6KjupQ=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

View File

@@ -131,6 +131,10 @@ func (this *RPCClient) HTTPFirewallRuleGroupRPC() pb.HTTPFirewallRuleGroupServic
return pb.NewHTTPFirewallRuleGroupServiceClient(this.pickConn()) return pb.NewHTTPFirewallRuleGroupServiceClient(this.pickConn())
} }
func (this *RPCClient) HTTPFirewallRuleSetRPC() pb.HTTPFirewallRuleSetServiceClient {
return pb.NewHTTPFirewallRuleSetServiceClient(this.pickConn())
}
func (this *RPCClient) HTTPLocationRPC() pb.HTTPLocationServiceClient { func (this *RPCClient) HTTPLocationRPC() pb.HTTPLocationServiceClient {
return pb.NewHTTPLocationServiceClient(this.pickConn()) return pb.NewHTTPLocationServiceClient(this.pickConn())
} }

View File

@@ -0,0 +1,104 @@
package waf
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
)
type CreateRulePopupAction struct {
actionutils.ParentAction
}
func (this *CreateRulePopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreateRulePopupAction) RunGet(params struct {
Type string
}) {
// check points
checkpointList := []maps.Map{}
for _, def := range firewallconfigs.AllCheckpoints {
if (params.Type == "inbound" && def.IsRequest) || (params.Type == "outbound" && !def.IsRequest) {
checkpointList = append(checkpointList, maps.Map{
"name": def.Name,
"prefix": def.Prefix,
"description": def.Description,
"hasParams": len(def.Params) > 0,
"params": def.Params,
"options": def.Options,
})
}
}
// operators
this.Data["operators"] = lists.Map(firewallconfigs.AllRuleOperators, func(k int, v interface{}) interface{} {
def := v.(*firewallconfigs.RuleOperatorDefinition)
return maps.Map{
"name": def.Name,
"code": def.Code,
"description": def.Description,
"case": def.CaseInsensitive,
}
})
this.Data["checkpoints"] = checkpointList
this.Show()
}
func (this *CreateRulePopupAction) RunPost(params struct {
RuleId int64
Prefix string
Operator string
Param string
OptionsJSON []byte
Value string
Case bool
Must *actions.Must
}) {
params.Must.
Field("prefix", params.Prefix).
Require("请选择参数")
rule := &firewallconfigs.HTTPFirewallRule{
Id: params.RuleId,
IsOn: true,
}
if len(params.Param) > 0 {
rule.Param = "${" + params.Prefix + "." + params.Param + "}"
} else {
rule.Param = "${" + params.Prefix + "}"
}
rule.Operator = params.Operator
rule.Value = params.Value
rule.IsCaseInsensitive = params.Case
if len(params.OptionsJSON) > 0 {
options := []maps.Map{}
err := json.Unmarshal(params.OptionsJSON, &options)
if err != nil {
this.ErrorPage(err)
return
}
rule.CheckpointOptions = map[string]interface{}{}
for _, option := range options {
rule.CheckpointOptions[option.GetString("code")] = option.GetString("value")
}
}
// 校验
err := rule.Init()
if err != nil {
this.Fail("校验规则 '" + rule.Param + " " + rule.Operator + " " + rule.Value + "' 失败,原因:" + err.Error())
}
this.Data["rule"] = rule
this.Success()
}

View File

@@ -0,0 +1,159 @@
package waf
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/models"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"strconv"
"strings"
)
type CreateSetPopupAction struct {
actionutils.ParentAction
}
func (this *CreateSetPopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreateSetPopupAction) RunGet(params struct {
FirewallPolicyId int64
GroupId int64
Type string
}) {
this.Data["groupId"] = params.GroupId
this.Data["type"] = params.Type
firewallPolicy, err := models.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
if err != nil {
this.ErrorPage(err)
return
}
if firewallPolicy == nil {
this.NotFound("firewallPolicy", params.FirewallPolicyId)
return
}
this.Data["firewallPolicy"] = firewallPolicy
// 一些配置
this.Data["connectors"] = []maps.Map{
{
"name": "和(AND)",
"value": firewallconfigs.HTTPFirewallRuleConnectorAnd,
"description": "所有规则都满足才视为匹配",
},
{
"name": "或(OR)",
"value": firewallconfigs.HTTPFirewallRuleConnectorOr,
"description": "任一规则满足了就视为匹配",
},
}
actionMaps := []maps.Map{}
for _, action := range firewallconfigs.AllActions {
actionMaps = append(actionMaps, maps.Map{
"name": action.Name,
"description": action.Description,
"code": action.Code,
})
}
this.Data["actions"] = actionMaps
this.Show()
}
func (this *CreateSetPopupAction) RunPost(params struct {
GroupId int64
Name string
RulesJSON []byte
Connector string
Action string
Must *actions.Must
}) {
groupConfig, err := models.SharedHTTPFirewallRuleGroupDAO.FindRuleGroupConfig(this.AdminContext(), params.GroupId)
if err != nil {
this.ErrorPage(err)
return
}
if groupConfig == nil {
this.Fail("找不到分组Id" + strconv.FormatInt(params.GroupId, 10))
}
params.Must.
Field("name", params.Name).
Require("请输入规则集名称")
if len(params.RulesJSON) == 0 {
this.Fail("请添加至少一个规则")
}
rules := []*firewallconfigs.HTTPFirewallRule{}
err = json.Unmarshal(params.RulesJSON, &rules)
if err != nil {
this.ErrorPage(err)
}
if len(rules) == 0 {
this.Fail("请添加至少一个规则")
}
setConfig := &firewallconfigs.HTTPFirewallRuleSet{
Id: 0,
IsOn: true,
Name: params.Name,
Code: "",
Description: "",
Connector: params.Connector,
RuleRefs: nil,
Rules: rules,
Action: params.Action,
ActionOptions: maps.Map{},
}
for k, v := range this.ParamsMap {
if len(v) == 0 {
continue
}
index := strings.Index(k, "action_")
if index > -1 {
setConfig.ActionOptions[k[len("action_"):]] = v[0]
}
}
setConfigJSON, err := json.Marshal(setConfig)
if err != nil {
this.ErrorPage(err)
return
}
createUpdateResp, err := this.RPC().HTTPFirewallRuleSetRPC().CreateOrUpdateHTTPFirewallRuleSetFromConfig(this.AdminContext(), &pb.CreateOrUpdateHTTPFirewallRuleSetFromConfigRequest{FirewallRuleSetConfigJSON: setConfigJSON})
if err != nil {
this.ErrorPage(err)
return
}
groupConfig.SetRefs = append(groupConfig.SetRefs, &firewallconfigs.HTTPFirewallRuleSetRef{
IsOn: true,
SetId: createUpdateResp.FirewallRuleSetId,
})
setRefsJSON, err := json.Marshal(groupConfig.SetRefs)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPFirewallRuleGroupRPC().UpdateHTTPFirewallRuleGroupSets(this.AdminContext(), &pb.UpdateHTTPFirewallRuleGroupSetsRequest{
FirewallRuleGroupId: params.GroupId,
FirewallRuleSetsJSON: setRefsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,50 @@
package waf
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/models"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
)
type DeleteSetAction struct {
actionutils.ParentAction
}
func (this *DeleteSetAction) RunPost(params struct {
GroupId int64
SetId int64
}) {
groupConfig, err := models.SharedHTTPFirewallRuleGroupDAO.FindRuleGroupConfig(this.AdminContext(), params.GroupId)
if err != nil {
this.ErrorPage(err)
return
}
if groupConfig == nil {
this.NotFound("firewallRuleGroup", params.GroupId)
return
}
newRefs := []*firewallconfigs.HTTPFirewallRuleSetRef{}
for _, ref := range groupConfig.SetRefs {
if ref.SetId != params.SetId {
newRefs = append(newRefs, ref)
}
}
newRefsJSON, err := json.Marshal(newRefs)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPFirewallRuleGroupRPC().UpdateHTTPFirewallRuleGroupSets(this.AdminContext(), &pb.UpdateHTTPFirewallRuleGroupSetsRequest{
FirewallRuleGroupId: params.GroupId,
FirewallRuleSetsJSON: newRefsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,107 @@
package waf
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/models"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"strconv"
"strings"
)
type GroupAction struct {
actionutils.ParentAction
}
func (this *GroupAction) Init() {
this.Nav("", "", this.ParamString("type"))
}
func (this *GroupAction) RunGet(params struct {
FirewallPolicyId int64
GroupId int64
Type string
}) {
this.Data["type"] = params.Type
// policy
firewallPolicy, err := models.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
if err != nil {
this.ErrorPage(err)
return
}
if firewallPolicy == nil {
this.NotFound("firewallPolicy", params.FirewallPolicyId)
return
}
// group config
groupConfig, err := models.SharedHTTPFirewallRuleGroupDAO.FindRuleGroupConfig(this.AdminContext(), params.GroupId)
if err != nil {
this.ErrorPage(err)
return
}
if groupConfig == nil {
this.NotFound("firewallRuleGroup", params.GroupId)
return
}
this.Data["group"] = groupConfig
// rule sets
this.Data["sets"] = lists.Map(groupConfig.Sets, func(k int, v interface{}) interface{} {
set := v.(*firewallconfigs.HTTPFirewallRuleSet)
// 动作说明
actionLinks := []maps.Map{}
if set.Action == firewallconfigs.HTTPFirewallActionGoGroup {
nextGroup := firewallPolicy.FindRuleGroup(set.ActionOptions.GetInt64("groupId"))
if nextGroup != nil {
actionLinks = append(actionLinks, maps.Map{
"name": nextGroup.Name,
"url": "/servers/components/waf/group?firewallPolicyId=" + strconv.FormatInt(params.FirewallPolicyId, 10) + "&type=" + params.Type + "&groupId=" + strconv.FormatInt(nextGroup.Id, 10),
})
}
} else if set.Action == firewallconfigs.HTTPFirewallActionGoSet {
nextGroup := firewallPolicy.FindRuleGroup(set.ActionOptions.GetInt64("groupId"))
if nextGroup != nil {
actionLinks = append(actionLinks, maps.Map{
"name": nextGroup.Name,
"url": "/servers/components/waf/group?firewallPolicyId=" + strconv.FormatInt(params.FirewallPolicyId, 10) + "&type=" + params.Type + "&groupId=" + strconv.FormatInt(nextGroup.Id, 10),
})
nextSet := nextGroup.FindRuleSet(set.ActionOptions.GetInt64("setId"))
if nextSet != nil {
actionLinks = append(actionLinks, maps.Map{
"name": nextSet.Name,
"url": "/servers/components/waf/group?firewallPolicyId=" + strconv.FormatInt(params.FirewallPolicyId, 10) + "&type=" + params.Type + "&groupId=" + strconv.FormatInt(nextGroup.Id, 10),
})
}
}
}
return maps.Map{
"id": set.Id,
"name": set.Name,
"rules": lists.Map(set.Rules, func(k int, v interface{}) interface{} {
rule := v.(*firewallconfigs.HTTPFirewallRule)
return maps.Map{
"param": rule.Param,
"operator": rule.Operator,
"value": rule.Value,
"isCaseInsensitive": rule.IsCaseInsensitive,
}
}),
"isOn": set.IsOn,
"action": strings.ToUpper(set.Action),
"actionOptions": set.ActionOptions,
"actionName": firewallconfigs.FindActionName(set.Action),
"actionLinks": actionLinks,
"connector": strings.ToUpper(set.Connector),
}
})
this.Show()
}

View File

@@ -18,7 +18,7 @@ func init() {
Post("/delete", new(DeleteAction)). Post("/delete", new(DeleteAction)).
Get("/policy", new(PolicyAction)). Get("/policy", new(PolicyAction)).
Get("/groups", new(GroupsAction)). Get("/groups", new(GroupsAction)).
Get("/sets", new(SetsAction)). Get("/group", new(GroupAction)).
Get("/log", new(LogAction)). Get("/log", new(LogAction)).
GetPost("/update", new(UpdateAction)). GetPost("/update", new(UpdateAction)).
GetPost("/test", new(TestAction)). GetPost("/test", new(TestAction)).
@@ -29,6 +29,13 @@ func init() {
GetPost("/ipadmin", new(IpadminAction)). GetPost("/ipadmin", new(IpadminAction)).
GetPost("/createGroupPopup", new(CreateGroupPopupAction)). GetPost("/createGroupPopup", new(CreateGroupPopupAction)).
Post("/sortGroups", new(SortGroupsAction)). Post("/sortGroups", new(SortGroupsAction)).
GetPost("/updateGroupPopup", new(UpdateGroupPopupAction)).
GetPost("/createSetPopup", new(CreateSetPopupAction)).
GetPost("/createRulePopup", new(CreateRulePopupAction)).
Post("/sortSets", new(SortSetsAction)).
Post("/updateSetOn", new(UpdateSetOnAction)).
Post("/deleteSet", new(DeleteSetAction)).
GetPost("/updateSetPopup", new(UpdateSetPopupAction)).
EndAll() EndAll()
}) })
} }

View File

@@ -1,15 +0,0 @@
package waf
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
type SetsAction struct {
actionutils.ParentAction
}
func (this *SetsAction) Init() {
this.Nav("", "", "")
}
func (this *SetsAction) RunGet(params struct{}) {
this.Show()
}

View File

@@ -0,0 +1,53 @@
package waf
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/models"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
)
type SortSetsAction struct {
actionutils.ParentAction
}
func (this *SortSetsAction) RunPost(params struct {
GroupId int64
SetIds []int64
}) {
groupConfig, err := models.SharedHTTPFirewallRuleGroupDAO.FindRuleGroupConfig(this.AdminContext(), params.GroupId)
if err != nil {
this.ErrorPage(err)
return
}
if groupConfig == nil {
this.NotFound("firewallRuleGroup", params.GroupId)
return
}
setMap := map[int64]*firewallconfigs.HTTPFirewallRuleSetRef{}
for _, setRef := range groupConfig.SetRefs {
setMap[setRef.SetId] = setRef
}
newRefs := []*firewallconfigs.HTTPFirewallRuleSetRef{}
for _, setId := range params.SetIds {
ref, ok := setMap[setId]
if ok {
newRefs = append(newRefs, ref)
}
}
newRefsJSON, err := json.Marshal(newRefs)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPFirewallRuleGroupRPC().UpdateHTTPFirewallRuleGroupSets(this.AdminContext(), &pb.UpdateHTTPFirewallRuleGroupSetsRequest{
FirewallRuleGroupId: params.GroupId,
FirewallRuleSetsJSON: newRefsJSON,
})
this.Success()
}

View File

@@ -0,0 +1,66 @@
package waf
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/models"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type UpdateGroupPopupAction struct {
actionutils.ParentAction
}
func (this *UpdateGroupPopupAction) Init() {
this.Nav("", "", "")
}
func (this *UpdateGroupPopupAction) RunGet(params struct {
GroupId int64
}) {
groupConfig, err := models.SharedHTTPFirewallRuleGroupDAO.FindRuleGroupConfig(this.AdminContext(), params.GroupId)
if err != nil {
this.ErrorPage(err)
return
}
if groupConfig == nil {
this.NotFound("ruleGroup", params.GroupId)
return
}
this.Data["group"] = maps.Map{
"id": groupConfig.Id,
"name": groupConfig.Name,
"description": groupConfig.Description,
"isOn": groupConfig.IsOn,
}
this.Show()
}
func (this *UpdateGroupPopupAction) RunPost(params struct {
GroupId int64
Name string
Description string
IsOn bool
Must *actions.Must
}) {
params.Must.
Field("name", params.Name).
Require("请输入分组名称")
_, err := this.RPC().HTTPFirewallRuleGroupRPC().UpdateHTTPFirewallRuleGroup(this.AdminContext(), &pb.UpdateHTTPFirewallRuleGroupRequest{
FirewallRuleGroupId: params.GroupId,
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,26 @@
package waf
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type UpdateSetOnAction struct {
actionutils.ParentAction
}
func (this *UpdateSetOnAction) RunPost(params struct {
SetId int64
IsOn bool
}) {
_, err := this.RPC().HTTPFirewallRuleSetRPC().UpdateHTTPFirewallRuleSetIsOn(this.AdminContext(), &pb.UpdateHTTPFirewallRuleSetIsOnRequest{
FirewallRuleSetId: params.SetId,
IsOn: params.IsOn,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,152 @@
package waf
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/models"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"strings"
)
type UpdateSetPopupAction struct {
actionutils.ParentAction
}
func (this *UpdateSetPopupAction) Init() {
this.Nav("", "", "")
}
func (this *UpdateSetPopupAction) RunGet(params struct {
FirewallPolicyId int64
GroupId int64
Type string
SetId int64
}) {
this.Data["groupId"] = params.GroupId
this.Data["type"] = params.Type
firewallPolicy, err := models.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
if err != nil {
this.ErrorPage(err)
return
}
if firewallPolicy == nil {
this.NotFound("firewallPolicy", params.FirewallPolicyId)
return
}
this.Data["firewallPolicy"] = firewallPolicy
// 一些配置
this.Data["connectors"] = []maps.Map{
{
"name": "和(AND)",
"value": firewallconfigs.HTTPFirewallRuleConnectorAnd,
"description": "所有规则都满足才视为匹配",
},
{
"name": "或(OR)",
"value": firewallconfigs.HTTPFirewallRuleConnectorOr,
"description": "任一规则满足了就视为匹配",
},
}
actionMaps := []maps.Map{}
for _, action := range firewallconfigs.AllActions {
actionMaps = append(actionMaps, maps.Map{
"name": action.Name,
"description": action.Description,
"code": action.Code,
})
}
this.Data["actions"] = actionMaps
// 规则集信息
setConfig, err := models.SharedHTTPFirewallRuleSetDAO.FindRuleSetConfig(this.AdminContext(), params.SetId)
if err != nil {
this.ErrorPage(err)
return
}
if setConfig == nil {
this.NotFound("firewallRuleSet", params.SetId)
return
}
this.Data["setConfig"] = setConfig
this.Show()
}
func (this *UpdateSetPopupAction) RunPost(params struct {
GroupId int64
SetId int64
Name string
RulesJSON []byte
Connector string
Action string
Must *actions.Must
}) {
// 规则集信息
setConfig, err := models.SharedHTTPFirewallRuleSetDAO.FindRuleSetConfig(this.AdminContext(), params.SetId)
if err != nil {
this.ErrorPage(err)
return
}
if setConfig == nil {
this.NotFound("firewallRuleSet", params.SetId)
return
}
params.Must.
Field("name", params.Name).
Require("请输入规则集名称")
if len(params.RulesJSON) == 0 {
this.Fail("请添加至少一个规则")
}
rules := []*firewallconfigs.HTTPFirewallRule{}
err = json.Unmarshal(params.RulesJSON, &rules)
if err != nil {
this.ErrorPage(err)
}
if len(rules) == 0 {
this.Fail("请添加至少一个规则")
}
setConfig.Name = params.Name
setConfig.Connector = params.Connector
setConfig.Rules = rules
setConfig.Action = params.Action
setConfig.ActionOptions = maps.Map{}
for k, v := range this.ParamsMap {
if len(v) == 0 {
continue
}
index := strings.Index(k, "action_")
if index > -1 {
setConfig.ActionOptions[k[len("action_"):]] = v[0]
}
}
setConfigJSON, err := json.Marshal(setConfig)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPFirewallRuleSetRPC().CreateOrUpdateHTTPFirewallRuleSetFromConfig(this.AdminContext(), &pb.CreateOrUpdateHTTPFirewallRuleSetFromConfigRequest{FirewallRuleSetConfigJSON: setConfigJSON})
if err != nil {
this.ErrorPage(err)
return
}
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,39 @@
package models
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
)
var SharedHTTPFirewallRuleGroupDAO = new(HTTPFirewallRuleGroupDAO)
type HTTPFirewallRuleGroupDAO struct {
}
// 查找分组配置
func (this *HTTPFirewallRuleGroupDAO) FindRuleGroupConfig(ctx context.Context, groupId int64) (*firewallconfigs.HTTPFirewallRuleGroup, error) {
client, err := rpc.SharedRPC()
if err != nil {
return nil, err
}
groupResp, err := client.HTTPFirewallRuleGroupRPC().FindHTTPFirewallRuleGroupConfig(ctx, &pb.FindHTTPFirewallRuleGroupConfigRequest{FirewallRuleGroupId: groupId})
if err != nil {
return nil, err
}
if len(groupResp.FirewallRuleGroupJSON) == 0 {
return nil, nil
}
groupConfig := &firewallconfigs.HTTPFirewallRuleGroup{}
err = json.Unmarshal(groupResp.FirewallRuleGroupJSON, groupConfig)
if err != nil {
return nil, err
}
return groupConfig, nil
}

View File

@@ -0,0 +1,35 @@
package models
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
)
var SharedHTTPFirewallRuleSetDAO = new(HTTPFirewallRuleSetDAO)
type HTTPFirewallRuleSetDAO struct {
}
// 查找规则集配置
func (this *HTTPFirewallRuleSetDAO) FindRuleSetConfig(ctx context.Context, setId int64) (*firewallconfigs.HTTPFirewallRuleSet, error) {
client, err := rpc.SharedRPC()
if err != nil {
return nil, err
}
resp, err := client.HTTPFirewallRuleSetRPC().FindHTTPFirewallRuleSetConfig(ctx, &pb.FindHTTPFirewallRuleSetConfigRequest{FirewallRuleSetId: setId})
if err != nil {
return nil, err
}
if len(resp.FirewallRuleSetJSON) == 0 {
return nil, err
}
config := &firewallconfigs.HTTPFirewallRuleSet{}
err = json.Unmarshal(resp.FirewallRuleSetJSON, config)
if err != nil {
return nil, err
}
return config, nil
}

View File

@@ -6,6 +6,9 @@ function sortTable(callback) {
jsFile.addEventListener("load", function () { jsFile.addEventListener("load", function () {
// 初始化 // 初始化
let box = document.querySelector("#sortable-table") let box = document.querySelector("#sortable-table")
if (box == null) {
return
}
Sortable.create(box, { Sortable.create(box, {
draggable: "tbody", draggable: "tbody",
handle: ".icon.handle", handle: ".icon.handle",

View File

@@ -0,0 +1,50 @@
Vue.component("http-firewall-rules-box", {
props: ["v-rules", "v-type"],
data: function () {
let rules = this.vRules
if (rules == null) {
rules = []
}
return {
rules: rules
}
},
methods: {
addRule: function () {
window.UPDATING_RULE = null
let that = this
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
callback: function (resp) {
that.rules.push(resp.data.rule)
}
})
},
updateRule: function (index, rule) {
window.UPDATING_RULE = rule
let that = this
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
callback: function (resp) {
Vue.set(that.rules, index, resp.data.rule)
}
})
},
removeRule: function (index) {
let that = this
teaweb.confirm("确定要删除此规则吗?", function () {
that.rules.$remove(index)
})
}
},
template: `<div>
<input type="hidden" name="rulesJSON" :value="JSON.stringify(rules)"/>
<div v-if="rules.length > 0">
<div v-for="(rule, index) in rules" class="ui label tiny" style="margin-bottom: 0.5em">
<span>{{rule.param}} <var>{{rule.operator}}</var> {{rule.value}}</span>
<a href="" title="修改" @click.prevent="updateRule(index, rule)"><i class="icon pencil small"></i></a>
<a href="" title="删除" @click.prevent="removeRule(index)"><i class="icon remove"></i></a>
</div>
<div class="ui divider"></div>
</div>
<button class="ui button tiny" type="button" @click.prevent="addRule()">+</button>
</div>`
})

View File

@@ -0,0 +1,86 @@
{$layout "layout_popup"}
<h3 v-if="!isUpdating">添加规则</h3>
<h3 v-if="isUpdating">修改规则</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="ruleId" :value="rule.id"/>
<input type="hidden" name="optionsJSON" v-if="checkpoint != null && checkpoint.options != null" :value="JSON.stringify(checkpoint.options)"/>
<table class="ui table definition selectable">
<tr>
<td class="title">参数</td>
<td>
<select name="prefix" class="ui dropdown auto-width" @change="changeCheckpoint()" v-model="rule.checkpointPrefix">
<option value="">[选择参数]</option>
<option v-for="cp in checkpoints" :value="cp.prefix">{{cp.name}} - [ {{cp.prefix}}]</option>
</select>
<p class="comment" v-if="checkpoint != null"><span class="ui label tiny">${<em style="font-style: normal;">{{checkpoint.prefix}}</em>}</span>{{checkpoint.description}}</p>
</td>
</tr>
<tr v-if="checkpoint != null && checkpoint.hasParams">
<td>参数名</td>
<td>
<select name="param" v-model="rule.checkpointParam" class="ui dropdown auto-width" v-if="checkpoint.params != null">
<option v-for="o in checkpoint.params" :value="o.value">{{o.name}}</option>
</select>
<input type="text" maxlength="100" v-model="rule.checkpointParam" v-if="checkpoint.params == null"/>
</td>
</tr>
<!-- 选项 -->
<tbody v-if="checkpoint != null && checkpoint.options != null && checkpoint.options.length > 0">
<tr v-for="option in checkpoint.options">
<td>{{option.name}}</td>
<td>
<div class="ui fields inline" v-if="option.type == 'field'">
<div class="ui field">
<input type="text" name="" :placeholder="option.placeholder" :maxlength="(option.maxLength > 0)?option.maxLength:1024" :size="option.size" v-model="option.value"/>
</div>
<div class="ui field">
{{option.rightLabel}}
</div>
</div>
<div class="ui fields inline" v-if="option.type == 'options'">
<div class="ui field">
<select class="ui dropdown" :style="'width:' + option.size + 'em'" name="" v-model="option.value">
<option v-for="opt in option.options" :value="opt.value">{{opt.name}}</option>
</select>
</div>
<div class="ui field">
{{option.rightLabel}}
</div>
</div>
<p class="comment" v-if="option.comment != null && option.comment.length > 0">{{option.comment}}</p>
</td>
</tr>
</tbody>
<tr>
<td>操作符</td>
<td>
<select class="ui dropdown" name="operator" style="width:10em" v-model="rule.operator" @change="changeOperator()">
<option v-for="op in operators" :value="op.code">{{op.name}}</option>
</select>
<p class="comment" v-if="operator != null" v-html="operator.description"></p>
</td>
</tr>
<tr v-if="operator.case != 'none'">
<td>开启大小写不敏感</td>
<td>
<div class="ui checkbox">
<input name="case" type="checkbox" value="1" v-model="rule.isCaseInsensitive"/>
<label></label>
</div>
<p class="comment">开启后忽略英文字母大小写</p>
</td>
</tr>
<tr>
<td>对比值</td>
<td>
<textarea rows="3" maxlength="4096" name="value" v-model="rule.value"></textarea>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,70 @@
Tea.context(function () {
this.success = NotifyPopup
this.isUpdating = (window.parent.UPDATING_RULE != null)
this.rule = {
id: 0,
param: "",
checkpointPrefix: "",
checkpointParam: "",
value: "",
isCaseInsensitive: false,
operator: "match",
checkpointOptions: null,
description: "",
isOn: true
}
if (window.parent.UPDATING_RULE != null) {
this.rule = window.parent.UPDATING_RULE
let param = this.rule.param.substring(this.rule.param.indexOf("${") + 2, this.rule.param.indexOf("}"))
let index = param.indexOf(".")
if (index > 0) {
this.rule.checkpointPrefix = param.substring(0, index)
this.rule.checkpointParam = param.substring(index + 1)
} else {
this.rule.checkpointPrefix = param
}
this.$delay(function () {
this.changeCheckpoint()
if (this.rule.checkpointOptions != null && this.checkpoint != null && this.checkpoint.options != null) {
let that = this
this.checkpoint.options.forEach(function (option) {
if (typeof (that.rule.checkpointOptions[option.code]) != "undefined") {
option.value = that.rule.checkpointOptions[option.code]
}
})
}
})
}
/**
* checkpoint
*/
this.checkpoint = null
this.changeCheckpoint = function () {
if (this.rule.checkpointPrefix.length == 0) {
this.checkpoint = null
return
}
let that = this
this.checkpoint = this.checkpoints.$find(function (k, v) {
return v.prefix == that.rule.checkpointPrefix
})
}
/**
* operator
*/
this.changeOperator = function () {
let that = this;
this.operator = this.operators.$find(function (k, v) {
return v.code == that.rule.operator
})
if (!this.isUpdating) {
this.rule.isCaseInsensitive = (this.operator.case == "yes")
}
};
this.changeOperator()
})

View File

@@ -0,0 +1,67 @@
{$layout "layout_popup"}
<h3>添加规则集</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="groupId" :value="groupId"/>
<table class="ui table definition selectable">
<tr>
<td class="title">规则集名称 *</td>
<td>
<input type="text" name="name" maxlength="100" ref="focus"/>
</td>
</tr>
<tr>
<td>规则</td>
<td>
<http-firewall-rules-box :v-rules="rules" :v-type="type"></http-firewall-rules-box>
</td>
</tr>
<tr>
<td>规则之间的关系</td>
<td>
<select class="ui dropdown" name="connector" style="width:10em" @change="changeConnector()" v-model="selectedConnector">
<option v-for="connector in connectors" :value="connector.value">{{connector.name}}</option>
</select>
<p class="comment">{{selectedConnectorDescription}}</p>
</td>
</tr>
<tr>
<td :class="{'color-border':action == 'go_group' || action == 'go_set'}">动作</td>
<td>
<select class="ui dropdown auto-width" name="action" v-model="action">
<option v-for="a in actions" :value="a.code">{{a.name}}({{a.code.toUpperCase()}})</option>
</select>
<p class="comment">匹配当前规则集后要执行的动作。</p>
</td>
</tr>
<tr v-if="action == 'go_group'">
<td class="color-border">下一个规则分组</td>
<td>
<select class="ui dropdown" name="action_groupId" style="width:12em" v-model="actionGroupId">
<option v-for="g in firewallPolicy.inbound.groups" :value="g.id">{{g.name}}</option>
</select>
<p class="comment">当动作为"跳到下一个规则分组"时出现此选择。</p>
</td>
</tr>
<tr v-if="action == 'go_set'">
<td class="color-border">下一个规则分组</td>
<td>
<select class="ui dropdown" name="action_groupId" style="width:12em" v-model="actionGroupId">
<option v-for="g in firewallPolicy.inbound.groups" :value="g.id">{{g.name}}</option>
</select>
<p class="comment">当动作为"跳到下一个规则集"时出现此选择。</p>
</td>
</tr>
<tr v-if="action == 'go_set'">
<td class="color-border">下一个规则集</td>
<td>
<select class="ui dropdown" name="action_setId" style="width:12em" v-model="actionSetId">
<option v-for="r in groupSets(actionGroupId)" :value="r.id">{{r.name}}</option>
</select>
<p class="comment">当动作为"跳到下一个规则集"时出现此选择。</p>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,43 @@
Tea.context(function () {
this.success = NotifyPopup
// rules
this.rules = []
// connector
this.selectedConnector = this.connectors[1].value
this.selectedConnectorDescription = ""
this.changeConnector = function () {
let that = this
this.selectedConnectorDescription = this.connectors.$find(function (k, v) {
return v.value == that.selectedConnector
}).description
}
this.changeConnector()
// action
this.action = "block"
// action:go_group
this.actionGroupId = 0
// action:go_set
this.actionSetId = 0
this.groupSets = function (groupId) {
let group = null
this.firewallPolicy.inbound.groups.forEach(function (v) {
if (v.id == groupId) {
group = v
}
})
this.firewallPolicy.outbound.groups.forEach(function (v) {
if (v.id == groupId) {
group = v
}
})
if (group == null) {
return []
}
return group.sets
}
})

View File

@@ -0,0 +1,69 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "waf_menu"}
<h3>分组<a href="" @click.prevent="updateGroup(group.id)">[修改]</a></h3>
<table class="ui table selectable definition">
<tr>
<td class="title">名称</td>
<td>{{group.name}}</td>
</tr>
<tr>
<td>描述</td>
<td>
<span v-if="group.description.length == 0" class="disabled">暂时还没有描述。</span>
<span v-if="group.description.length > 0">{{group.description}}</span>
</td>
</tr>
<tr>
<td>启用状态</td>
<td>
<label-on :v-is-on="group.isOn"></label-on>
</td>
</tr>
</table>
<h3 style="padding-top:0.8em">规则集<a href="" @click.prevent="createSet(group.id)">[添加规则集]</a> </h3>
<p class="comment" v-if="sets == null || sets.length == 0">暂时还没有规则。</p>
<table class="ui table selectable" id="sortable-table" v-if="sets != null && sets.length > 0">
<thead>
<tr>
<th style="width:3em"></th>
<th nowrap="">规则集名称</th>
<th nowrap="">规则</th>
<th nowrap="">关系</th>
<th nowrap="">动作</th>
<th class="three op">操作</th>
</tr>
</thead>
<tbody v-for="set in sets" :data-set-id="set.id">
<tr>
<td style="text-align: center;"><i class="icon bars handle grey"></i> </td>
<td><span :class="{disabled:!set.isOn}">{{set.name}}</span>
<p style="margin-top:0.5em">
<label-on :v-is-on="set.isOn"></label-on>
</p>
</td>
<td class="rules-box">
<div v-for="rule in set.rules" style="margin-top: 0.4em;margin-bottom:0.4em">
<span class="ui label tiny">{{rule.name}}[{{rule.param}}] <var :class="{dash:rule.isCaseInsensitive}" :title="rule.isCaseInsensitive ? '大小写不敏感':''">{{rule.operator}}</var> {{rule.value}}</span>
</div>
<span class="ui disabled" v-if="set.rules.length == 0">暂时还没有规则</span>
</td>
<td>{{set.connector.toUpperCase()}}</td>
<td><span :class="{red:set.action == 'BLOCK' || set.action == 'CAPTCHA', green:set.action != 'BLOCK' && set.action != 'CAPTCHA'}">{{set.actionName}}[{{set.action.toUpperCase()}}]</span>
<div v-if="set.actionLinks != null && set.actionLinks.length > 0" style="margin-top:0.3em">
<span class="disabled">-&gt;</span> <span v-for="link in set.actionLinks"><a :href="link.url"><span class="disabled">[{{link.name}}]</span></a> &nbsp;</span>
</div>
</td>
<td>
<a href="" @click.prevent="updateSet(set.id)">修改</a> &nbsp; <a href="" @click.prevent="updateSetOn(set.id, false)" v-if="set.isOn">停用</a><a href="" @click.prevent="updateSetOn(set.id, true)" v-if="!set.isOn">启用</a> &nbsp; <a href="" @click.prevent="deleteSet(set.id)">删除</a>
</td>
</tr>
</tbody>
</table>
<p class="comment" v-if="group.sets != null && group.sets.length > 1">所有规则匹配顺序为从上到下,可以拖动左侧的<i class="icon bars"></i>排序。</p>
</div>

View File

@@ -0,0 +1,82 @@
Tea.context(function () {
this.$delay(function () {
let that = this
sortTable(function () {
let setIds = []
document
.querySelectorAll("tbody[data-set-id]")
.forEach(function (v) {
setIds.push(v.getAttribute("data-set-id"))
})
that.$post(".sortSets")
.params({
groupId: that.group.id,
setIds: setIds
})
.success(function () {
teaweb.successToast("排序保存成功")
})
})
})
// 更改分组
this.updateGroup = function (groupId) {
teaweb.popup("/servers/components/waf/updateGroupPopup?groupId=" + groupId, {
height: "16em",
callback: function () {
teaweb.success("保存成功", function () {
window.location.reload()
})
}
})
}
// 创建规则集
this.createSet = function (groupId) {
teaweb.popup("/servers/components/waf/createSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + groupId + "&type=" + this.type, {
width: "50em",
height: "30em",
callback: function () {
teaweb.success("保存成功", function () {
window.location.reload()
})
}
})
}
// 修改规则集
this.updateSet = function (setId) {
teaweb.popup("/servers/components/waf/updateSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + this.group.id + "&type=" + this.type + "&setId=" + setId, {
width: "50em",
height: "30em",
callback: function () {
teaweb.success("保存成功", function () {
window.location.reload()
})
}
})
}
// 停用|启用规则集
this.updateSetOn = function (setId, isOn) {
this.$post(".updateSetOn")
.params({
setId: setId,
isOn: isOn ? 1 : 0
})
.refresh()
}
// 删除规则集
this.deleteSet = function (setId) {
let that = this
teaweb.confirm("确定要删除此规则集吗?", function () {
that.$post(".deleteSet")
.params({
groupId: this.group.id,
setId: setId
})
.refresh()
})
}
})

View File

@@ -32,7 +32,7 @@
</p> </p>
</td> </td>
<td> <td>
<a :href="'/proxy/components/waf/sets?firewallPolicyId=' + firewallPolicyId + '&type=' + type + '&groupId=' + group.id">{{group.countSets}}</a> <a :href="'/servers/components/waf/group?firewallPolicyId=' + firewallPolicyId + '&type=' + type + '&groupId=' + group.id">{{group.countSets}}</a>
</td> </td>
<td> <td>
<a :href="'/servers/components/waf/group?firewallPolicyId=' + firewallPolicyId + '&type=' + type + '&groupId=' + group.id">详情</a> &nbsp; <a :href="'/servers/components/waf/group?firewallPolicyId=' + firewallPolicyId + '&type=' + type + '&groupId=' + group.id">详情</a> &nbsp;
@@ -42,4 +42,6 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<p class="comment" v-if="groups.length > 0">所有规则匹配顺序为从上到下,可以拖动左侧的<i class="icon bars"></i>排序。</p>
</div> </div>

View File

@@ -0,0 +1,38 @@
{$layout "layout_popup"}
<h3>修改分组</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="groupId" :value="group.id"/>
<table class="ui table definition selectable">
<tr>
<td class="title">分组名称 *</td>
<td>
<input type="text" name="name" maxlength="100" ref="focus" v-model="group.name"/>
<p class="comment">给分组起一个容易识别的名称</p>
</td>
</tr>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>
<tbody v-show="moreOptionsVisible">
<tr>
<td>分组描述</td>
<td>
<textarea name="description" maxlength="200" rows="3" v-model="group.description"></textarea>
</td>
</tr>
<tr>
<td>是否启用</td>
<td>
<div class="ui checkbox">
<input type="checkbox" name="isOn" value="1" v-model="group.isOn" />
<label></label>
</div>
</td>
</tr>
</tbody>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,3 @@
Tea.context(function () {
this.success = NotifyPopup
})

View File

@@ -0,0 +1,67 @@
{$layout "layout_popup"}
<h3>修改规则集</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="setId" :value="setConfig.id"/>
<table class="ui table definition selectable">
<tr>
<td class="title">规则集名称 *</td>
<td>
<input type="text" name="name" maxlength="100" ref="focus" v-model="setConfig.name"/>
</td>
</tr>
<tr>
<td>规则</td>
<td>
<http-firewall-rules-box :v-rules="rules" :v-type="type"></http-firewall-rules-box>
</td>
</tr>
<tr>
<td>规则之间的关系</td>
<td>
<select class="ui dropdown" name="connector" style="width:10em" @change="changeConnector()" v-model="selectedConnector">
<option v-for="connector in connectors" :value="connector.value">{{connector.name}}</option>
</select>
<p class="comment">{{selectedConnectorDescription}}</p>
</td>
</tr>
<tr>
<td :class="{'color-border':action == 'go_group' || action == 'go_set'}">动作</td>
<td>
<select class="ui dropdown auto-width" name="action" v-model="action">
<option v-for="a in actions" :value="a.code">{{a.name}}({{a.code.toUpperCase()}})</option>
</select>
<p class="comment">匹配当前规则集后要执行的动作。</p>
</td>
</tr>
<tr v-if="action == 'go_group'">
<td class="color-border">下一个规则分组</td>
<td>
<select class="ui dropdown" name="action_groupId" style="width:12em" v-model="actionGroupId">
<option v-for="g in firewallPolicy.inbound.groups" :value="g.id">{{g.name}}</option>
</select>
<p class="comment">当动作为"跳到下一个规则分组"时出现此选择。</p>
</td>
</tr>
<tr v-if="action == 'go_set'">
<td class="color-border">下一个规则分组</td>
<td>
<select class="ui dropdown" name="action_groupId" style="width:12em" v-model="actionGroupId">
<option v-for="g in firewallPolicy.inbound.groups" :value="g.id">{{g.name}}</option>
</select>
<p class="comment">当动作为"跳到下一个规则集"时出现此选择。</p>
</td>
</tr>
<tr v-if="action == 'go_set'">
<td class="color-border">下一个规则集</td>
<td>
<select class="ui dropdown" name="action_setId" style="width:12em" v-model="actionSetId">
<option v-for="r in groupSets(actionGroupId)" :value="r.id">{{r.name}}</option>
</select>
<p class="comment">当动作为"跳到下一个规则集"时出现此选择。</p>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,57 @@
Tea.context(function () {
this.success = NotifyPopup
// rules
this.rules = this.setConfig.rules
// connector
this.selectedConnector = this.setConfig.connector
this.selectedConnectorDescription = ""
this.changeConnector = function () {
let that = this
this.selectedConnectorDescription = this.connectors.$find(function (k, v) {
return v.value == that.selectedConnector
}).description
}
this.changeConnector()
// action
this.action = this.setConfig.action
// action:go_group
this.actionGroupId = 0
if (this.action == "go_group" || this.action == "go_set" && this.setConfig.actionOptions != null) {
this.$delay(function () {
this.actionGroupId = this.setConfig.actionOptions["groupId"]
})
}
// action:go_set
this.actionSetId = 0
if (this.action == "go_set" && this.setConfig.actionOptions != null) {
this.$delay(function () {
this.actionSetId = this.setConfig.actionOptions["setId"]
})
}
this.groupSets = function (groupId) {
if (this.firewallPolicy == null) {
return
}
let group = null
this.firewallPolicy.inbound.groups.forEach(function (v) {
if (v.id == groupId) {
group = v
}
})
this.firewallPolicy.outbound.groups.forEach(function (v) {
if (v.id == groupId) {
group = v
}
})
if (group == null) {
return []
}
return group.sets
}
})