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: `
` +}) \ 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"} + +| 名称 | +{{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/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"} + +