From 8e0c10419a8b2879956d4f55eb625b3a157debbd Mon Sep 17 00:00:00 2001 From: GoEdgeLab Date: Thu, 8 Oct 2020 11:11:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0WAF=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 1 + go.sum | 1 + internal/rpc/rpc_client.go | 4 + .../servers/components/waf/createRulePopup.go | 104 ++++++++++++ .../servers/components/waf/createSetPopup.go | 159 ++++++++++++++++++ .../servers/components/waf/deleteSet.go | 50 ++++++ .../default/servers/components/waf/group.go | 107 ++++++++++++ .../default/servers/components/waf/init.go | 9 +- .../default/servers/components/waf/sets.go | 15 -- .../servers/components/waf/sortSets.go | 53 ++++++ .../components/waf/updateGroupPopup.go | 66 ++++++++ .../servers/components/waf/updateSetOn.go | 26 +++ .../servers/components/waf/updateSetPopup.go | 152 +++++++++++++++++ .../models/http_firewall_rule_group_dao.go | 39 +++++ .../web/models/http_firewall_rule_set_dao.go | 35 ++++ web/public/js/components/common/sortable.js | 3 + .../server/http-firewall-rules-box.js | 50 ++++++ .../components/waf/createRulePopup.html | 86 ++++++++++ .../servers/components/waf/createRulePopup.js | 70 ++++++++ .../components/waf/createSetPopup.html | 67 ++++++++ .../servers/components/waf/createSetPopup.js | 43 +++++ .../servers/components/waf/group.html | 69 ++++++++ .../@default/servers/components/waf/group.js | 82 +++++++++ .../servers/components/waf/groups.html | 4 +- .../components/waf/updateGroupPopup.html | 38 +++++ .../components/waf/updateGroupPopup.js | 3 + .../components/waf/updateSetPopup.html | 67 ++++++++ .../servers/components/waf/updateSetPopup.js | 57 +++++++ 28 files changed, 1443 insertions(+), 17 deletions(-) create mode 100644 internal/web/actions/default/servers/components/waf/createRulePopup.go create mode 100644 internal/web/actions/default/servers/components/waf/createSetPopup.go create mode 100644 internal/web/actions/default/servers/components/waf/deleteSet.go create mode 100644 internal/web/actions/default/servers/components/waf/group.go delete mode 100644 internal/web/actions/default/servers/components/waf/sets.go create mode 100644 internal/web/actions/default/servers/components/waf/sortSets.go create mode 100644 internal/web/actions/default/servers/components/waf/updateGroupPopup.go create mode 100644 internal/web/actions/default/servers/components/waf/updateSetOn.go create mode 100644 internal/web/actions/default/servers/components/waf/updateSetPopup.go create mode 100644 internal/web/models/http_firewall_rule_group_dao.go create mode 100644 internal/web/models/http_firewall_rule_set_dao.go create mode 100644 web/public/js/components/server/http-firewall-rules-box.js create mode 100644 web/views/@default/servers/components/waf/createRulePopup.html create mode 100644 web/views/@default/servers/components/waf/createRulePopup.js create mode 100644 web/views/@default/servers/components/waf/createSetPopup.html create mode 100644 web/views/@default/servers/components/waf/createSetPopup.js create mode 100644 web/views/@default/servers/components/waf/group.html create mode 100644 web/views/@default/servers/components/waf/group.js create mode 100644 web/views/@default/servers/components/waf/updateGroupPopup.html create mode 100644 web/views/@default/servers/components/waf/updateGroupPopup.js create mode 100644 web/views/@default/servers/components/waf/updateSetPopup.html create mode 100644 web/views/@default/servers/components/waf/updateSetPopup.js diff --git a/go.mod b/go.mod index aab24f69..b2870a80 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // 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/protobuf v1.25.0 // indirect ) diff --git a/go.sum b/go.sum index 007d83c7..1b77d9d5 100644 --- a/go.sum +++ b/go.sum @@ -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-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-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/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go index 6bf66aae..113f0062 100644 --- a/internal/rpc/rpc_client.go +++ b/internal/rpc/rpc_client.go @@ -131,6 +131,10 @@ func (this *RPCClient) HTTPFirewallRuleGroupRPC() pb.HTTPFirewallRuleGroupServic return pb.NewHTTPFirewallRuleGroupServiceClient(this.pickConn()) } +func (this *RPCClient) HTTPFirewallRuleSetRPC() pb.HTTPFirewallRuleSetServiceClient { + return pb.NewHTTPFirewallRuleSetServiceClient(this.pickConn()) +} + func (this *RPCClient) HTTPLocationRPC() pb.HTTPLocationServiceClient { return pb.NewHTTPLocationServiceClient(this.pickConn()) } diff --git a/internal/web/actions/default/servers/components/waf/createRulePopup.go b/internal/web/actions/default/servers/components/waf/createRulePopup.go new file mode 100644 index 00000000..1042c66f --- /dev/null +++ b/internal/web/actions/default/servers/components/waf/createRulePopup.go @@ -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() +} diff --git a/internal/web/actions/default/servers/components/waf/createSetPopup.go b/internal/web/actions/default/servers/components/waf/createSetPopup.go new file mode 100644 index 00000000..c5212138 --- /dev/null +++ b/internal/web/actions/default/servers/components/waf/createSetPopup.go @@ -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() +} diff --git a/internal/web/actions/default/servers/components/waf/deleteSet.go b/internal/web/actions/default/servers/components/waf/deleteSet.go new file mode 100644 index 00000000..f623d0f1 --- /dev/null +++ b/internal/web/actions/default/servers/components/waf/deleteSet.go @@ -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() +} diff --git a/internal/web/actions/default/servers/components/waf/group.go b/internal/web/actions/default/servers/components/waf/group.go new file mode 100644 index 00000000..6b7fe9b8 --- /dev/null +++ b/internal/web/actions/default/servers/components/waf/group.go @@ -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() +} diff --git a/internal/web/actions/default/servers/components/waf/init.go b/internal/web/actions/default/servers/components/waf/init.go index b404a531..88dd4fc5 100644 --- a/internal/web/actions/default/servers/components/waf/init.go +++ b/internal/web/actions/default/servers/components/waf/init.go @@ -18,7 +18,7 @@ func init() { Post("/delete", new(DeleteAction)). Get("/policy", new(PolicyAction)). Get("/groups", new(GroupsAction)). - Get("/sets", new(SetsAction)). + Get("/group", new(GroupAction)). Get("/log", new(LogAction)). GetPost("/update", new(UpdateAction)). GetPost("/test", new(TestAction)). @@ -29,6 +29,13 @@ func init() { GetPost("/ipadmin", new(IpadminAction)). GetPost("/createGroupPopup", new(CreateGroupPopupAction)). 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() }) } diff --git a/internal/web/actions/default/servers/components/waf/sets.go b/internal/web/actions/default/servers/components/waf/sets.go deleted file mode 100644 index 04c2e912..00000000 --- a/internal/web/actions/default/servers/components/waf/sets.go +++ /dev/null @@ -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() -} diff --git a/internal/web/actions/default/servers/components/waf/sortSets.go b/internal/web/actions/default/servers/components/waf/sortSets.go new file mode 100644 index 00000000..65c84fa4 --- /dev/null +++ b/internal/web/actions/default/servers/components/waf/sortSets.go @@ -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() +} diff --git a/internal/web/actions/default/servers/components/waf/updateGroupPopup.go b/internal/web/actions/default/servers/components/waf/updateGroupPopup.go new file mode 100644 index 00000000..0eb2e69b --- /dev/null +++ b/internal/web/actions/default/servers/components/waf/updateGroupPopup.go @@ -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() +} diff --git a/internal/web/actions/default/servers/components/waf/updateSetOn.go b/internal/web/actions/default/servers/components/waf/updateSetOn.go new file mode 100644 index 00000000..18059f5c --- /dev/null +++ b/internal/web/actions/default/servers/components/waf/updateSetOn.go @@ -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() +} diff --git a/internal/web/actions/default/servers/components/waf/updateSetPopup.go b/internal/web/actions/default/servers/components/waf/updateSetPopup.go new file mode 100644 index 00000000..6e14cc5f --- /dev/null +++ b/internal/web/actions/default/servers/components/waf/updateSetPopup.go @@ -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() +} diff --git a/internal/web/models/http_firewall_rule_group_dao.go b/internal/web/models/http_firewall_rule_group_dao.go new file mode 100644 index 00000000..a3e42507 --- /dev/null +++ b/internal/web/models/http_firewall_rule_group_dao.go @@ -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 +} diff --git a/internal/web/models/http_firewall_rule_set_dao.go b/internal/web/models/http_firewall_rule_set_dao.go new file mode 100644 index 00000000..adb0ee42 --- /dev/null +++ b/internal/web/models/http_firewall_rule_set_dao.go @@ -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 +} diff --git a/web/public/js/components/common/sortable.js b/web/public/js/components/common/sortable.js index 45384421..fa431779 100644 --- a/web/public/js/components/common/sortable.js +++ b/web/public/js/components/common/sortable.js @@ -6,6 +6,9 @@ function sortTable(callback) { jsFile.addEventListener("load", function () { // 初始化 let box = document.querySelector("#sortable-table") + if (box == null) { + return + } Sortable.create(box, { draggable: "tbody", handle: ".icon.handle", diff --git a/web/public/js/components/server/http-firewall-rules-box.js b/web/public/js/components/server/http-firewall-rules-box.js new file mode 100644 index 00000000..9ed7a7db --- /dev/null +++ b/web/public/js/components/server/http-firewall-rules-box.js @@ -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: `
+ +
+
+ {{rule.param}} {{rule.operator}} {{rule.value}} + + +
+
+
+ +
` +}) \ No newline at end of file diff --git a/web/views/@default/servers/components/waf/createRulePopup.html b/web/views/@default/servers/components/waf/createRulePopup.html new file mode 100644 index 00000000..e587caab --- /dev/null +++ b/web/views/@default/servers/components/waf/createRulePopup.html @@ -0,0 +1,86 @@ +{$layout "layout_popup"} + +

添加规则

+

修改规则

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数 + +

${{{checkpoint.prefix}}}{{checkpoint.description}}

+
参数名 + + +
{{option.name}} +
+
+ +
+
+ {{option.rightLabel}} +
+
+
+
+ +
+
+ {{option.rightLabel}} +
+
+

{{option.comment}}

+
操作符 + +

+
开启大小写不敏感 +
+ + +
+

开启后忽略英文字母大小写

+
对比值 + +
+ + +
\ No newline at end of file diff --git a/web/views/@default/servers/components/waf/createRulePopup.js b/web/views/@default/servers/components/waf/createRulePopup.js new file mode 100644 index 00000000..d369c378 --- /dev/null +++ b/web/views/@default/servers/components/waf/createRulePopup.js @@ -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() +}) \ No newline at end of file diff --git a/web/views/@default/servers/components/waf/createSetPopup.html b/web/views/@default/servers/components/waf/createSetPopup.html new file mode 100644 index 00000000..bc264a13 --- /dev/null +++ b/web/views/@default/servers/components/waf/createSetPopup.html @@ -0,0 +1,67 @@ +{$layout "layout_popup"} + +

添加规则集

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
规则集名称 * + +
规则 + +
规则之间的关系 + +

{{selectedConnectorDescription}}

+
动作 + +

匹配当前规则集后要执行的动作。

+
下一个规则分组 + +

当动作为"跳到下一个规则分组"时出现此选择。

+
下一个规则分组 + +

当动作为"跳到下一个规则集"时出现此选择。

+
下一个规则集 + +

当动作为"跳到下一个规则集"时出现此选择。

+
+ +
\ No newline at end of file diff --git a/web/views/@default/servers/components/waf/createSetPopup.js b/web/views/@default/servers/components/waf/createSetPopup.js new file mode 100644 index 00000000..ba4be577 --- /dev/null +++ b/web/views/@default/servers/components/waf/createSetPopup.js @@ -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 + } +}) \ No newline at end of file diff --git a/web/views/@default/servers/components/waf/group.html b/web/views/@default/servers/components/waf/group.html new file mode 100644 index 00000000..9ac4c203 --- /dev/null +++ b/web/views/@default/servers/components/waf/group.html @@ -0,0 +1,69 @@ +{$layout} +{$template "/left_menu"} + +
+ {$template "waf_menu"} + +

分组[修改]

+ + + + + + + + + + + + + +
名称{{group.name}}
描述 + 暂时还没有描述。 + {{group.description}} +
启用状态 + +
+ +

规则集[添加规则集]

+

暂时还没有规则。

+ + + + + + + + + + + + + + + + + + + + + +
规则集名称规则关系动作操作
{{set.name}} +

+ +

+
+
+ {{rule.name}}[{{rule.param}}] {{rule.operator}} {{rule.value}} +
+ 暂时还没有规则 +
{{set.connector.toUpperCase()}}{{set.actionName}}[{{set.action.toUpperCase()}}] +
+ -> [{{link.name}}]   +
+
+ 修改   停用启用   删除 +
+ +

所有规则匹配顺序为从上到下,可以拖动左侧的排序。

+
\ No newline at end of file diff --git a/web/views/@default/servers/components/waf/group.js b/web/views/@default/servers/components/waf/group.js new file mode 100644 index 00000000..f5bf9c20 --- /dev/null +++ b/web/views/@default/servers/components/waf/group.js @@ -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() + }) + } +}) \ No newline at end of file diff --git a/web/views/@default/servers/components/waf/groups.html b/web/views/@default/servers/components/waf/groups.html index 99758477..e7f926e2 100644 --- a/web/views/@default/servers/components/waf/groups.html +++ b/web/views/@default/servers/components/waf/groups.html @@ -32,7 +32,7 @@

- {{group.countSets}} + {{group.countSets}} 详情   @@ -42,4 +42,6 @@ + +

所有规则匹配顺序为从上到下,可以拖动左侧的排序。

\ No newline at end of file diff --git a/web/views/@default/servers/components/waf/updateGroupPopup.html b/web/views/@default/servers/components/waf/updateGroupPopup.html new file mode 100644 index 00000000..caadd3e6 --- /dev/null +++ b/web/views/@default/servers/components/waf/updateGroupPopup.html @@ -0,0 +1,38 @@ +{$layout "layout_popup"} + +

修改分组

+ +
+ + + + + + + + + + + + + + + + + + + +
分组名称 * + +

给分组起一个容易识别的名称

+
分组描述 + +
是否启用 +
+ + +
+
+ + +
\ No newline at end of file diff --git a/web/views/@default/servers/components/waf/updateGroupPopup.js b/web/views/@default/servers/components/waf/updateGroupPopup.js new file mode 100644 index 00000000..c8fe9515 --- /dev/null +++ b/web/views/@default/servers/components/waf/updateGroupPopup.js @@ -0,0 +1,3 @@ +Tea.context(function () { + this.success = NotifyPopup +}) \ No newline at end of file diff --git a/web/views/@default/servers/components/waf/updateSetPopup.html b/web/views/@default/servers/components/waf/updateSetPopup.html new file mode 100644 index 00000000..6f6e9b94 --- /dev/null +++ b/web/views/@default/servers/components/waf/updateSetPopup.html @@ -0,0 +1,67 @@ +{$layout "layout_popup"} + +

修改规则集

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
规则集名称 * + +
规则 + +
规则之间的关系 + +

{{selectedConnectorDescription}}

+
动作 + +

匹配当前规则集后要执行的动作。

+
下一个规则分组 + +

当动作为"跳到下一个规则分组"时出现此选择。

+
下一个规则分组 + +

当动作为"跳到下一个规则集"时出现此选择。

+
下一个规则集 + +

当动作为"跳到下一个规则集"时出现此选择。

+
+ +
\ No newline at end of file diff --git a/web/views/@default/servers/components/waf/updateSetPopup.js b/web/views/@default/servers/components/waf/updateSetPopup.js new file mode 100644 index 00000000..e1275b90 --- /dev/null +++ b/web/views/@default/servers/components/waf/updateSetPopup.js @@ -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 + } +}) \ No newline at end of file