mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-12 19:30:26 +08:00
WAF支持更多动作
This commit is contained in:
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateSetPopupAction struct {
|
||||
@@ -53,6 +52,7 @@ func (this *CreateSetPopupAction) RunGet(params struct {
|
||||
},
|
||||
}
|
||||
|
||||
// 所有可选的动作
|
||||
actionMaps := []maps.Map{}
|
||||
for _, action := range firewallconfigs.AllActions {
|
||||
actionMaps = append(actionMaps, maps.Map{
|
||||
@@ -72,7 +72,7 @@ func (this *CreateSetPopupAction) RunPost(params struct {
|
||||
Name string
|
||||
RulesJSON []byte
|
||||
Connector string
|
||||
Action string
|
||||
ActionsJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -96,11 +96,24 @@ func (this *CreateSetPopupAction) RunPost(params struct {
|
||||
err = json.Unmarshal(params.RulesJSON, &rules)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(rules) == 0 {
|
||||
this.Fail("请添加至少一个规则")
|
||||
}
|
||||
|
||||
var actionConfigs = []*firewallconfigs.HTTPFirewallActionConfig{}
|
||||
if len(params.ActionsJSON) > 0 {
|
||||
err = json.Unmarshal(params.ActionsJSON, &actionConfigs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(actionConfigs) == 0 {
|
||||
this.Fail("请添加至少一个动作")
|
||||
}
|
||||
|
||||
setConfig := &firewallconfigs.HTTPFirewallRuleSet{
|
||||
Id: 0,
|
||||
IsOn: true,
|
||||
@@ -110,18 +123,7 @@ func (this *CreateSetPopupAction) RunPost(params struct {
|
||||
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]
|
||||
}
|
||||
Actions: actionConfigs,
|
||||
}
|
||||
|
||||
setConfigJSON, err := json.Marshal(setConfig)
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -54,32 +53,20 @@ func (this *GroupAction) RunGet(params struct {
|
||||
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),
|
||||
})
|
||||
var actionMaps = []maps.Map{}
|
||||
for _, action := range set.Actions {
|
||||
def := firewallconfigs.FindActionDefinition(action.Code)
|
||||
if def == nil {
|
||||
continue
|
||||
}
|
||||
} 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),
|
||||
actionMaps = append(actionMaps, maps.Map{
|
||||
"code": strings.ToUpper(action.Code),
|
||||
"name": def.Name,
|
||||
"category": def.Category,
|
||||
"options": action.Options,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maps.Map{
|
||||
"id": set.Id,
|
||||
@@ -96,10 +83,7 @@ func (this *GroupAction) RunGet(params struct {
|
||||
}
|
||||
}),
|
||||
"isOn": set.IsOn,
|
||||
"action": strings.ToUpper(set.Action),
|
||||
"actionOptions": set.ActionOptions,
|
||||
"actionName": firewallconfigs.FindActionName(set.Action),
|
||||
"actionLinks": actionLinks,
|
||||
"actions": actionMaps,
|
||||
"connector": strings.ToUpper(set.Connector),
|
||||
}
|
||||
})
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type UpdateSetPopupAction struct {
|
||||
@@ -79,6 +78,14 @@ func (this *UpdateSetPopupAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["setConfig"] = setConfig
|
||||
|
||||
// action configs
|
||||
actionConfigs, err := dao.SharedHTTPFirewallPolicyDAO.FindHTTPFirewallActionConfigs(this.AdminContext(), setConfig.Actions)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["actionConfigs"] = actionConfigs
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -89,7 +96,7 @@ func (this *UpdateSetPopupAction) RunPost(params struct {
|
||||
Name string
|
||||
RulesJSON []byte
|
||||
Connector string
|
||||
Action string
|
||||
ActionsJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -115,26 +122,28 @@ func (this *UpdateSetPopupAction) RunPost(params struct {
|
||||
err = json.Unmarshal(params.RulesJSON, &rules)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(rules) == 0 {
|
||||
this.Fail("请添加至少一个规则")
|
||||
}
|
||||
|
||||
var actionConfigs = []*firewallconfigs.HTTPFirewallActionConfig{}
|
||||
if len(params.ActionsJSON) > 0 {
|
||||
err = json.Unmarshal(params.ActionsJSON, &actionConfigs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(actionConfigs) == 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]
|
||||
}
|
||||
}
|
||||
setConfig.Actions = actionConfigs
|
||||
|
||||
setConfigJSON, err := json.Marshal(setConfig)
|
||||
if err != nil {
|
||||
|
||||
@@ -23,6 +23,7 @@ func init() {
|
||||
GetPost("/test", new(TestAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Get("/items", new(ItemsAction)).
|
||||
Get("/selectPopup", new(SelectPopupAction)).
|
||||
|
||||
// IP相关
|
||||
GetPost("/createIPPopup", new(CreateIPPopupAction)).
|
||||
@@ -34,6 +35,9 @@ func init() {
|
||||
Post("/unbindHTTPFirewall", new(UnbindHTTPFirewallAction)).
|
||||
Post("/httpFirewall", new(HttpFirewallAction)).
|
||||
|
||||
// 选项数据
|
||||
Post("/levelOptions", new(LevelOptionsAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
18
internal/web/actions/default/servers/iplists/levelOptions.go
Normal file
18
internal/web/actions/default/servers/iplists/levelOptions.go
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
)
|
||||
|
||||
type LevelOptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *LevelOptionsAction) RunPost(params struct{}) {
|
||||
this.Data["levels"] = firewallconfigs.FindAllFirewallEventLevels()
|
||||
|
||||
this.Success()
|
||||
}
|
||||
70
internal/web/actions/default/servers/iplists/selectPopup.go
Normal file
70
internal/web/actions/default/servers/iplists/selectPopup.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunGet(params struct {
|
||||
Type string
|
||||
}) {
|
||||
// 公共的名单
|
||||
countResp, err := this.RPC().IPListRPC().CountAllEnabledIPLists(this.AdminContext(), &pb.CountAllEnabledIPListsRequest{
|
||||
Type: params.Type,
|
||||
IsPublic: true,
|
||||
Keyword: "",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
listsResp, err := this.RPC().IPListRPC().ListEnabledIPLists(this.AdminContext(), &pb.ListEnabledIPListsRequest{
|
||||
Type: params.Type,
|
||||
IsPublic: true,
|
||||
Keyword: "",
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var listMaps = []maps.Map{}
|
||||
for _, list := range listsResp.IpLists {
|
||||
// 包含的IP数量
|
||||
countItemsResp, err := this.RPC().IPItemRPC().CountIPItemsWithListId(this.AdminContext(), &pb.CountIPItemsWithListIdRequest{IpListId: list.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countItems = countItemsResp.Count
|
||||
|
||||
listMaps = append(listMaps, maps.Map{
|
||||
"id": list.Id,
|
||||
"isOn": list.IsOn,
|
||||
"name": list.Name,
|
||||
"description": list.Description,
|
||||
"countItems": countItems,
|
||||
"type": list.Type,
|
||||
})
|
||||
}
|
||||
this.Data["lists"] = listMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -55,33 +54,20 @@ func (this *GroupAction) RunGet(params struct {
|
||||
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),
|
||||
})
|
||||
var actionMaps = []maps.Map{}
|
||||
for _, action := range set.Actions {
|
||||
def := firewallconfigs.FindActionDefinition(action.Code)
|
||||
if def == nil {
|
||||
continue
|
||||
}
|
||||
} 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),
|
||||
actionMaps = append(actionMaps, maps.Map{
|
||||
"code": strings.ToUpper(action.Code),
|
||||
"name": def.Name,
|
||||
"category": def.Category,
|
||||
"options": action.Options,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maps.Map{
|
||||
"id": set.Id,
|
||||
@@ -98,10 +84,7 @@ func (this *GroupAction) RunGet(params struct {
|
||||
}
|
||||
}),
|
||||
"isOn": set.IsOn,
|
||||
"action": strings.ToUpper(set.Action),
|
||||
"actionOptions": set.ActionOptions,
|
||||
"actionName": firewallconfigs.FindActionName(set.Action),
|
||||
"actionLinks": actionLinks,
|
||||
"actions": actionMaps,
|
||||
"connector": strings.ToUpper(set.Connector),
|
||||
}
|
||||
})
|
||||
|
||||
@@ -52,6 +52,9 @@ Vue.component("values-box", {
|
||||
this.isUpdating = false;
|
||||
this.isAdding = false;
|
||||
this.value = "";
|
||||
},
|
||||
updateAll: function (values) {
|
||||
this.vValeus = values
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
@@ -78,7 +81,7 @@ Vue.component("values-box", {
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!isAdding && !isUpdating">
|
||||
<button class="ui button small" type="button" @click.prevent="create()">+</button>
|
||||
<button class="ui button tiny" type="button" @click.prevent="create()">+</button>
|
||||
</div>
|
||||
</div>`
|
||||
});
|
||||
589
web/public/js/components/server/http-firewall-actions-box.js
Normal file
589
web/public/js/components/server/http-firewall-actions-box.js
Normal file
@@ -0,0 +1,589 @@
|
||||
// 动作选择
|
||||
Vue.component("http-firewall-actions-box", {
|
||||
props: ["v-actions", "v-firewall-policy", "v-action-configs"],
|
||||
mounted: function () {
|
||||
let that = this
|
||||
Tea.action("/servers/iplists/levelOptions")
|
||||
.success(function (resp) {
|
||||
that.ipListLevels = resp.data.levels
|
||||
})
|
||||
.post()
|
||||
|
||||
this.loadJS(function () {
|
||||
let box = document.getElementById("actions-box")
|
||||
Sortable.create(box, {
|
||||
draggable: ".label",
|
||||
handle: ".icon.handle",
|
||||
onStart: function () {
|
||||
that.cancel()
|
||||
},
|
||||
onUpdate: function (event) {
|
||||
let labels = box.getElementsByClassName("label")
|
||||
let newConfigs = []
|
||||
for (let i = 0; i < labels.length; i++) {
|
||||
let index = parseInt(labels[i].getAttribute("data-index"))
|
||||
newConfigs.push(that.configs[index])
|
||||
}
|
||||
that.configs = newConfigs
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
data: function () {
|
||||
if (this.vFirewallPolicy.inbound == null) {
|
||||
this.vFirewallPolicy.inbound = {}
|
||||
}
|
||||
if (this.vFirewallPolicy.inbound.groups == null) {
|
||||
this.vFirewallPolicy.inbound.groups = []
|
||||
}
|
||||
|
||||
let id = 0
|
||||
let configs = []
|
||||
if (this.vActionConfigs != null) {
|
||||
configs = this.vActionConfigs
|
||||
configs.forEach(function (v) {
|
||||
v.id = (id++)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
id: id,
|
||||
|
||||
actions: this.vActions,
|
||||
configs: configs,
|
||||
isAdding: false,
|
||||
editingIndex: -1,
|
||||
|
||||
action: null,
|
||||
actionCode: "",
|
||||
actionOptions: {},
|
||||
|
||||
// IPList相关
|
||||
ipListLevels: [],
|
||||
|
||||
// 动作参数
|
||||
blockLife: "",
|
||||
captchaLife: "",
|
||||
get302Life: "",
|
||||
post307Life: "",
|
||||
recordIPType: "black",
|
||||
recordIPLevel: "critical",
|
||||
recordIPTimeout: "",
|
||||
recordIPListId: 0,
|
||||
recordIPListName: "",
|
||||
|
||||
tagTags: [],
|
||||
|
||||
goGroupName: "",
|
||||
goGroupId: 0,
|
||||
goGroup: null,
|
||||
|
||||
goSetId: 0,
|
||||
goSetName: ""
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
actionCode: function (code) {
|
||||
this.action = this.actions.$find(function (k, v) {
|
||||
return v.code == code
|
||||
})
|
||||
this.actionOptions = {}
|
||||
},
|
||||
blockLife: function (v) {
|
||||
v = parseInt(v)
|
||||
if (isNaN(v)) {
|
||||
this.actionOptions["life"] = 0
|
||||
} else {
|
||||
this.actionOptions["life"] = v
|
||||
}
|
||||
},
|
||||
captchaLife: function (v) {
|
||||
v = parseInt(v)
|
||||
if (isNaN(v)) {
|
||||
this.actionOptions["life"] = 0
|
||||
} else {
|
||||
this.actionOptions["life"] = v
|
||||
}
|
||||
},
|
||||
get302Life: function (v) {
|
||||
v = parseInt(v)
|
||||
if (isNaN(v)) {
|
||||
this.actionOptions["life"] = 0
|
||||
} else {
|
||||
this.actionOptions["life"] = v
|
||||
}
|
||||
},
|
||||
post307Life: function (v) {
|
||||
v = parseInt(v)
|
||||
if (isNaN(v)) {
|
||||
this.actionOptions["life"] = 0
|
||||
} else {
|
||||
this.actionOptions["life"] = v
|
||||
}
|
||||
},
|
||||
recordIPType: function () {
|
||||
this.recordIPListId = 0
|
||||
},
|
||||
recordIPTimeout: function (v) {
|
||||
v = parseInt(v)
|
||||
if (isNaN(v)) {
|
||||
this.actionOptions["timeout"] = 0
|
||||
} else {
|
||||
this.actionOptions["timeout"] = v
|
||||
}
|
||||
},
|
||||
goGroupId: function (groupId) {
|
||||
let group = this.vFirewallPolicy.inbound.groups.$find(function (k, v) {
|
||||
return v.id == groupId
|
||||
})
|
||||
this.goGroup = group
|
||||
if (group == null) {
|
||||
this.goGroupName = ""
|
||||
} else {
|
||||
this.goGroupName = group.name
|
||||
}
|
||||
this.goSetId = 0
|
||||
this.goSetName = ""
|
||||
},
|
||||
goSetId: function (setId) {
|
||||
if (this.goGroup == null) {
|
||||
return
|
||||
}
|
||||
let set = this.goGroup.sets.$find(function (k, v) {
|
||||
return v.id == setId
|
||||
})
|
||||
if (set == null) {
|
||||
this.goSetId = 0
|
||||
this.goSetName = ""
|
||||
} else {
|
||||
this.goSetName = set.name
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
add: function () {
|
||||
this.action = null
|
||||
this.actionCode = "block"
|
||||
this.isAdding = true
|
||||
this.actionOptions = {}
|
||||
|
||||
// 动作参数
|
||||
this.blockLife = ""
|
||||
this.captchaLife = ""
|
||||
this.get302Life = ""
|
||||
this.post307Life = ""
|
||||
|
||||
this.recordIPLevel = "critical"
|
||||
this.recordIPType = "black"
|
||||
this.recordIPTimeout = ""
|
||||
this.recordIPListId = 0
|
||||
this.recordIPListName = ""
|
||||
|
||||
this.tagTags = []
|
||||
|
||||
this.goGroupName = ""
|
||||
this.goGroupId = 0
|
||||
this.goGroup = null
|
||||
|
||||
this.goSetId = 0
|
||||
this.goSetName = ""
|
||||
|
||||
let that = this
|
||||
this.action = this.vActions.$find(function (k, v) {
|
||||
return v.code == that.actionCode
|
||||
})
|
||||
},
|
||||
remove: function (index) {
|
||||
this.configs.$remove(index)
|
||||
},
|
||||
update: function (index, config) {
|
||||
if (this.isAdding && this.editingIndex == index) {
|
||||
this.cancel()
|
||||
return
|
||||
}
|
||||
|
||||
this.add()
|
||||
|
||||
this.isAdding = true
|
||||
this.editingIndex = index
|
||||
|
||||
this.actionCode = config.code
|
||||
|
||||
switch (config.code) {
|
||||
case "block":
|
||||
this.blockLife = ""
|
||||
if (config.options.life != null || config.options.life > 0) {
|
||||
this.blockLife = config.options.life.toString()
|
||||
}
|
||||
break
|
||||
case "allow":
|
||||
break
|
||||
case "log":
|
||||
break
|
||||
case "captcha":
|
||||
this.captchaLife = ""
|
||||
if (config.options.life != null || config.options.life > 0) {
|
||||
this.captchaLife = config.options.life.toString()
|
||||
}
|
||||
break
|
||||
case "notify":
|
||||
break
|
||||
case "get_302":
|
||||
this.get302Life = ""
|
||||
if (config.options.life != null || config.options.life > 0) {
|
||||
this.get302Life = config.options.life.toString()
|
||||
}
|
||||
break
|
||||
case "post_307":
|
||||
this.post307Life = ""
|
||||
if (config.options.life != null || config.options.life > 0) {
|
||||
this.post307Life = config.options.life.toString()
|
||||
}
|
||||
break;
|
||||
case "record_ip":
|
||||
if (config.options != null) {
|
||||
this.recordIPLevel = config.options.level
|
||||
this.recordIPType = config.options.type
|
||||
if (config.options.timeout > 0) {
|
||||
this.recordIPTimeout = config.options.timeout.toString()
|
||||
}
|
||||
this.recordIPListId = config.options.ipListId
|
||||
this.recordIPListName = config.options.ipListName
|
||||
}
|
||||
break
|
||||
case "tag":
|
||||
this.tagTags = []
|
||||
if (config.options.tags != null) {
|
||||
this.tagTags = config.options.tags
|
||||
}
|
||||
break
|
||||
case "go_group":
|
||||
if (config.options != null) {
|
||||
this.goGroupName = config.options.groupName
|
||||
this.goGroupId = config.options.groupId
|
||||
this.goGroup = this.vFirewallPolicy.inbound.groups.$find(function (k, v) {
|
||||
return v.id == config.options.groupId
|
||||
})
|
||||
}
|
||||
break
|
||||
case "go_set":
|
||||
if (config.options != null) {
|
||||
this.goGroupName = config.options.groupName
|
||||
this.goGroupId = config.options.groupId
|
||||
this.goGroup = this.vFirewallPolicy.inbound.groups.$find(function (k, v) {
|
||||
return v.id == config.options.groupId
|
||||
})
|
||||
|
||||
this.goSetId = config.options.setId
|
||||
if (this.goGroup != null) {
|
||||
let set = this.goGroup.sets.$find(function (k, v) {
|
||||
return v.id == config.options.setId
|
||||
})
|
||||
if (set != null) {
|
||||
this.goSetName = set.name
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
},
|
||||
cancel: function () {
|
||||
this.isAdding = false
|
||||
this.editingIndex = -1
|
||||
},
|
||||
confirm: function () {
|
||||
if (this.action == null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.actionOptions == null) {
|
||||
this.actionOptions = {}
|
||||
}
|
||||
|
||||
// record_ip
|
||||
if (this.actionCode == "record_ip") {
|
||||
let timeout = parseInt(this.recordIPTimeout)
|
||||
if (isNaN(timeout)) {
|
||||
timeout = 0
|
||||
}
|
||||
if (this.recordIPListId <= 0) {
|
||||
return
|
||||
}
|
||||
this.actionOptions = {
|
||||
type: this.recordIPType,
|
||||
level: this.recordIPLevel,
|
||||
timeout: timeout,
|
||||
ipListId: this.recordIPListId,
|
||||
ipListName: this.recordIPListName
|
||||
}
|
||||
} else if (this.actionCode == "tag") { // tag
|
||||
if (this.tagTags == null || this.tagTags.length == 0) {
|
||||
return
|
||||
}
|
||||
this.actionOptions = {
|
||||
tags: this.tagTags
|
||||
}
|
||||
} else if (this.actionCode == "go_group") { // go_group
|
||||
let groupId = this.goGroupId
|
||||
if (typeof (groupId) == "string") {
|
||||
groupId = parseInt(groupId)
|
||||
if (isNaN(groupId)) {
|
||||
groupId = 0
|
||||
}
|
||||
}
|
||||
if (groupId <= 0) {
|
||||
return
|
||||
}
|
||||
this.actionOptions = {
|
||||
groupId: groupId,
|
||||
groupName: this.goGroupName
|
||||
}
|
||||
} else if (this.actionCode == "go_set") { // go_set
|
||||
let groupId = this.goGroupId
|
||||
if (typeof (groupId) == "string") {
|
||||
groupId = parseInt(groupId)
|
||||
if (isNaN(groupId)) {
|
||||
groupId = 0
|
||||
}
|
||||
}
|
||||
|
||||
let setId = this.goSetId
|
||||
if (typeof (setId) == "string") {
|
||||
setId = parseInt(setId)
|
||||
if (isNaN(setId)) {
|
||||
setId = 0
|
||||
}
|
||||
}
|
||||
if (setId <= 0) {
|
||||
return
|
||||
}
|
||||
this.actionOptions = {
|
||||
groupId: groupId,
|
||||
groupName: this.goGroupName,
|
||||
setId: setId,
|
||||
setName: this.goSetName
|
||||
}
|
||||
}
|
||||
|
||||
let options = {}
|
||||
for (let k in this.actionOptions) {
|
||||
if (this.actionOptions.hasOwnProperty(k)) {
|
||||
options[k] = this.actionOptions[k]
|
||||
}
|
||||
}
|
||||
if (this.editingIndex > -1) {
|
||||
this.configs[this.editingIndex] = {
|
||||
id: this.configs[this.editingIndex].id,
|
||||
code: this.actionCode,
|
||||
name: this.action.name,
|
||||
options: options
|
||||
}
|
||||
} else {
|
||||
this.configs.push({
|
||||
id: (this.id++),
|
||||
code: this.actionCode,
|
||||
name: this.action.name,
|
||||
options: options
|
||||
})
|
||||
}
|
||||
|
||||
this.cancel()
|
||||
},
|
||||
removeRecordIPList: function () {
|
||||
this.recordIPListId = 0
|
||||
},
|
||||
selectRecordIPList: function () {
|
||||
let that = this
|
||||
teaweb.popup("/servers/iplists/selectPopup?type=" + this.recordIPType, {
|
||||
width: "50em",
|
||||
height: "30em",
|
||||
callback: function (resp) {
|
||||
that.recordIPListId = resp.data.list.id
|
||||
that.recordIPListName = resp.data.list.name
|
||||
}
|
||||
})
|
||||
},
|
||||
changeTags: function (tags) {
|
||||
this.tagTags = tags
|
||||
},
|
||||
loadJS: function (callback) {
|
||||
if (typeof Sortable != "undefined") {
|
||||
callback()
|
||||
return
|
||||
}
|
||||
|
||||
// 引入js
|
||||
let jsFile = document.createElement("script")
|
||||
jsFile.setAttribute("src", "/js/sortable.min.js")
|
||||
jsFile.addEventListener("load", function () {
|
||||
callback()
|
||||
})
|
||||
document.head.appendChild(jsFile)
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="actionsJSON" :value="JSON.stringify(configs)"/>
|
||||
<div v-show="configs.length > 0" style="margin-bottom: 0.5em" id="actions-box">
|
||||
<div v-for="(config, index) in configs" :data-index="index" :key="config.id" class="ui label small basic" :class="{blue: index == editingIndex}" style="margin-bottom: 0.4em">
|
||||
{{config.name}} ({{config.code.toUpperCase()}})
|
||||
|
||||
<!-- record_ip -->
|
||||
<span v-if="config.code == 'record_ip'">:{{config.options.ipListName}}</span>
|
||||
|
||||
<!-- tag -->
|
||||
<span v-if="config.code == 'tag'">:{{config.options.tags.join(", ")}}</span>
|
||||
|
||||
<!-- go_group -->
|
||||
<span v-if="config.code == 'go_group'">:{{config.options.groupName}}</span>
|
||||
|
||||
<!-- go_set -->
|
||||
<span v-if="config.code == 'go_set'">:{{config.options.groupName}} / {{config.options.setName}}</span>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<a href="" title="修改" @click.prevent="update(index, config)"><i class="icon pencil small"></i></a> <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a> <a href="" title="拖动改变顺序"><i class="icon bars handle"></i></a>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
</div>
|
||||
<div style="margin-bottom: 0.5em" v-if="isAdding">
|
||||
<table class="ui table" :class="{blue: editingIndex > -1}">
|
||||
<tr>
|
||||
<td class="title">动作类型 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" v-model="actionCode">
|
||||
<option v-for="action in actions" :value="action.code">{{action.name}} ({{action.code.toUpperCase()}})</option>
|
||||
</select>
|
||||
<p class="comment" v-if="action != null && action.description.length > 0">{{action.description}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- block -->
|
||||
<tr v-if="actionCode == 'block'">
|
||||
<td>封锁时间</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" style="width: 5em" maxlength="10" v-model="blockLife" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- captcha -->
|
||||
<tr v-if="actionCode == 'captcha'">
|
||||
<td>有效时间</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" style="width: 5em" maxlength="10" v-model="captchaLife" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
<p class="comment">验证通过后在这个时间内不再验证。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- get_302 -->
|
||||
<tr v-if="actionCode == 'get_302'">
|
||||
<td>有效时间</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" style="width: 5em" maxlength="10" v-model="get302Life" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
<p class="comment">验证通过后在这个时间内不再验证。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- post_307 -->
|
||||
<tr v-if="actionCode == 'post_307'">
|
||||
<td>有效时间</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" style="width: 5em" maxlength="10" v-model="post307Life" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
<p class="comment">验证通过后在这个时间内不再验证。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- record_ip -->
|
||||
<tr v-if="actionCode == 'record_ip'">
|
||||
<td>IP名单类型 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" v-model="recordIPType">
|
||||
<option value="black">黑名单</option>
|
||||
<option value="white">白名单</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="actionCode == 'record_ip'">
|
||||
<td>选择IP名单</td>
|
||||
<td>
|
||||
<div v-if="recordIPListId > 0" class="ui label basic small">{{recordIPListName}} <a href="" @click.prevent="removeRecordIPList"><i class="icon remove small"></i></a></div>
|
||||
<button type="button" class="ui button tiny" @click.prevent="selectRecordIPList">+</button>
|
||||
<p class="comment">如不选择,则自动添加到当前策略的IP名单中。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="actionCode == 'record_ip'">
|
||||
<td>级别</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" v-model="recordIPLevel">
|
||||
<option v-for="level in ipListLevels" :value="level.code">{{level.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="actionCode == 'record_ip'">
|
||||
<td>超时时间</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" style="width: 5em" maxlength="10" v-model="recordIPTimeout" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
<p class="comment">0表示不超时。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- tag -->
|
||||
<tr v-if="actionCode == 'tag'">
|
||||
<td>标签 *</td>
|
||||
<td>
|
||||
<values-box @change="changeTags" :values="tagTags"></values-box>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 规则分组 -->
|
||||
<tr v-if="actionCode == 'go_group'">
|
||||
<td>下一个分组 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" v-model="goGroupId">
|
||||
<option value="0">[选择分组]</option>
|
||||
<option v-for="group in vFirewallPolicy.inbound.groups" :value="group.id">{{group.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 规则集 -->
|
||||
<tr v-if="actionCode == 'go_set'">
|
||||
<td>下一个分组 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" v-model="goGroupId">
|
||||
<option value="0">[选择分组]</option>
|
||||
<option v-for="group in vFirewallPolicy.inbound.groups" :value="group.id">{{group.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="actionCode == 'go_set' && goGroup != null">
|
||||
<td>下一个规则集 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" v-model="goSetId">
|
||||
<option value="0">[选择规则集]</option>
|
||||
<option v-for="set in goGroup.sets" :value="set.id">{{set.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirm">确定</button>
|
||||
<a href="" @click.prevent="cancel" title="取消"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
<div v-if="!isAdding">
|
||||
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
// Action列表
|
||||
Vue.component("http-firewall-actions-view", {
|
||||
props: ["v-actions"],
|
||||
template: `<div>
|
||||
<div v-for="action in vActions" style="margin-bottom: 0.3em">
|
||||
<span :class="{red: action.category == 'block', orange: action.category == 'verify', green: action.category == 'allow'}">{{action.name}} ({{action.code.toUpperCase()}})</span>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
@@ -27,39 +27,9 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td :class="{'color-border':action == 'go_group' || action == 'go_set'}">动作</td>
|
||||
<td>执行动作 *</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>
|
||||
<http-firewall-actions-box :v-actions="actions" :v-firewall-policy="firewallPolicy"></http-firewall-actions-box>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<th style="width:3em"></th>
|
||||
<th nowrap="">规则集名称</th>
|
||||
<th nowrap="">规则</th>
|
||||
<th nowrap="" class="center">关系</th>
|
||||
<th nowrap="" class="center one wide">关系</th>
|
||||
<th nowrap="">动作</th>
|
||||
<th class="three op">操作</th>
|
||||
</tr>
|
||||
@@ -50,11 +50,12 @@
|
||||
</div>
|
||||
<span class="ui disabled" v-if="set.rules.length == 0">暂时还没有规则</span>
|
||||
</td>
|
||||
<td class="center">{{set.connector.toUpperCase()}}</td>
|
||||
<td nowrap=""><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">-></span> <span v-for="link in set.actionLinks"><a :href="link.url"><span class="disabled">[{{link.name}}]</span></a> </span>
|
||||
</div>
|
||||
<td class="center">
|
||||
<span v-if="set.connector.toUpperCase() == 'OR'">或</span><span v-else>和</span>
|
||||
<span class="small grey">({{set.connector.toUpperCase()}})</span>
|
||||
</td>
|
||||
<td nowrap="">
|
||||
<http-firewall-actions-view :v-actions="set.actions"></http-firewall-actions-view>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="updateSet(set.id)">修改</a> <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> <a href="" @click.prevent="deleteSet(set.id)">删除</a>
|
||||
|
||||
36
web/views/@default/servers/iplists/selectPopup.html
Normal file
36
web/views/@default/servers/iplists/selectPopup.html
Normal file
@@ -0,0 +1,36 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>选择公用IP名单</h3>
|
||||
|
||||
<p class="comment" v-if="lists.length == 0">暂时还没有可用的公用IP名单。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="lists.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="two wide center">ID</th>
|
||||
<th>名称</th>
|
||||
<th class="two wide center">类型</th>
|
||||
<th>备注</th>
|
||||
<th class="two wide center">IP数量</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="list in lists">
|
||||
<td class="center">{{list.id}}</td>
|
||||
<td>{{list.name}}</td>
|
||||
<td class="center">
|
||||
<span v-if="list.type == 'black'">黑名单</span>
|
||||
<span v-if="list.type == 'white'">白名单</span>
|
||||
</td>
|
||||
<td>{{list.description}}</td>
|
||||
<td class="center">
|
||||
<span v-if="list.countItems > 0">{{list.countItems}}</span>
|
||||
<span v-else class="disabled">0</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="selectList(list)">选择</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
13
web/views/@default/servers/iplists/selectPopup.js
Normal file
13
web/views/@default/servers/iplists/selectPopup.js
Normal file
@@ -0,0 +1,13 @@
|
||||
Tea.context(function () {
|
||||
this.selectList = function (list) {
|
||||
NotifyPopup({
|
||||
code: 200,
|
||||
data: {
|
||||
list: {
|
||||
id: list.id,
|
||||
name: list.name
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user