实现WAF部分功能

This commit is contained in:
GoEdgeLab
2020-10-07 11:18:07 +08:00
parent 5ace29ad42
commit 15d88b71a3
23 changed files with 559 additions and 9 deletions

View File

@@ -127,6 +127,10 @@ func (this *RPCClient) HTTPFirewallPolicyRPC() pb.HTTPFirewallPolicyServiceClien
return pb.NewHTTPFirewallPolicyServiceClient(this.pickConn()) return pb.NewHTTPFirewallPolicyServiceClient(this.pickConn())
} }
func (this *RPCClient) HTTPFirewallRuleGroupRPC() pb.HTTPFirewallRuleGroupServiceClient {
return pb.NewHTTPFirewallRuleGroupServiceClient(this.pickConn())
}
func (this *RPCClient) HTTPLocationRPC() pb.HTTPLocationServiceClient { func (this *RPCClient) HTTPLocationRPC() pb.HTTPLocationServiceClient {
return pb.NewHTTPLocationServiceClient(this.pickConn()) return pb.NewHTTPLocationServiceClient(this.pickConn())
} }

View File

@@ -0,0 +1,98 @@
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/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/iwind/TeaGo/actions"
)
type CreateGroupPopupAction struct {
actionutils.ParentAction
}
func (this *CreateGroupPopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreateGroupPopupAction) RunGet(params struct {
Type string
}) {
this.Data["type"] = params.Type
this.Show()
}
func (this *CreateGroupPopupAction) RunPost(params struct {
FirewallPolicyId int64
Type string
Name string
Description string
IsOn bool
Must *actions.Must
}) {
firewallPolicy, err := models.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
if err != nil {
this.ErrorPage(err)
return
}
if firewallPolicy == nil {
this.NotFound("firewallPolicy", params.FirewallPolicyId)
}
params.Must.
Field("name", params.Name).
Require("请输入分组名称")
createResp, err := this.RPC().HTTPFirewallRuleGroupRPC().CreateHTTPFirewallRuleGroup(this.AdminContext(), &pb.CreateHTTPFirewallRuleGroupRequest{
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
})
if err != nil {
this.ErrorPage(err)
return
}
groupId := createResp.FirewallRuleGroupId
switch params.Type {
case "inbound":
firewallPolicy.Inbound.GroupRefs = append(firewallPolicy.Inbound.GroupRefs, &firewallconfigs.HTTPFirewallRuleGroupRef{
IsOn: true,
GroupId: groupId,
})
default:
firewallPolicy.Outbound.GroupRefs = append(firewallPolicy.Outbound.GroupRefs, &firewallconfigs.HTTPFirewallRuleGroupRef{
IsOn: true,
GroupId: groupId,
})
}
inboundJSON, err := firewallPolicy.InboundJSON()
if err != nil {
this.ErrorPage(err)
return
}
outboundJSON, err := firewallPolicy.OutboundJSON()
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallPolicyGroups(this.AdminContext(), &pb.UpdateHTTPFirewallPolicyGroupsRequest{
FirewallPolicyId: params.FirewallPolicyId,
InboundJSON: inboundJSON,
OutboundJSON: outboundJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,52 @@
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"
)
type DeleteGroupAction struct {
actionutils.ParentAction
}
func (this *DeleteGroupAction) RunPost(params struct {
FirewallPolicyId int64
GroupId int64
}) {
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
}
firewallPolicy.RemoveRuleGroup(params.GroupId)
inboundJSON, err := firewallPolicy.InboundJSON()
if err != nil {
this.ErrorPage(err)
return
}
outboundJSON, err := firewallPolicy.OutboundJSON()
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallPolicyGroups(this.AdminContext(), &pb.UpdateHTTPFirewallPolicyGroupsRequest{
FirewallPolicyId: params.FirewallPolicyId,
InboundJSON: inboundJSON,
OutboundJSON: outboundJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -7,7 +7,7 @@ type ExportAction struct {
} }
func (this *ExportAction) Init() { func (this *ExportAction) Init() {
this.Nav("", "", "") this.Nav("", "", "export")
} }
func (this *ExportAction) RunGet(params struct{}) { func (this *ExportAction) RunGet(params struct{}) {

View File

@@ -1,15 +1,72 @@
package waf package waf
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/models"
"github.com/iwind/TeaGo/maps"
)
type GroupsAction struct { type GroupsAction struct {
actionutils.ParentAction actionutils.ParentAction
} }
func (this *GroupsAction) Init() { func (this *GroupsAction) Init() {
this.Nav("", "", "") this.Nav("", "", this.ParamString("type"))
} }
func (this *GroupsAction) RunGet(params struct{}) { func (this *GroupsAction) RunGet(params struct {
FirewallPolicyId int64
Type string
}) {
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
}
groupMaps := []maps.Map{}
// inbound
if params.Type == "inbound" {
if firewallPolicy.Inbound != nil {
for _, g := range firewallPolicy.Inbound.Groups {
groupMaps = append(groupMaps, maps.Map{
"id": g.Id,
"name": g.Name,
"code": g.Code,
"isOn": g.IsOn,
"description": g.Description,
"countSets": len(g.Sets),
"canDelete": len(g.Code) == 0,
})
}
}
}
// outbound
if params.Type == "outbound" {
if firewallPolicy.Outbound != nil {
for _, g := range firewallPolicy.Outbound.Groups {
groupMaps = append(groupMaps, maps.Map{
"id": g.Id,
"name": g.Name,
"code": g.Code,
"isOn": g.IsOn,
"description": g.Description,
"countSets": len(g.Sets),
"canDelete": len(g.Code) == 0,
})
}
}
}
this.Data["groups"] = groupMaps
this.Show() this.Show()
} }

View File

@@ -7,7 +7,7 @@ type ImportAction struct {
} }
func (this *ImportAction) Init() { func (this *ImportAction) Init() {
this.Nav("", "", "") this.Nav("", "", "import")
} }
func (this *ImportAction) RunGet(params struct{}) { func (this *ImportAction) RunGet(params struct{}) {

View File

@@ -24,6 +24,11 @@ func init() {
GetPost("/test", new(TestAction)). GetPost("/test", new(TestAction)).
GetPost("/export", new(ExportAction)). GetPost("/export", new(ExportAction)).
GetPost("/import", new(ImportAction)). GetPost("/import", new(ImportAction)).
Post("/updateGroupOn", new(UpdateGroupOnAction)).
Post("/deleteGroup", new(DeleteGroupAction)).
GetPost("/ipadmin", new(IpadminAction)).
GetPost("/createGroupPopup", new(CreateGroupPopupAction)).
Post("/sortGroups", new(SortGroupsAction)).
EndAll() EndAll()
}) })
} }

View File

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

View File

@@ -7,7 +7,7 @@ type LogAction struct {
} }
func (this *LogAction) Init() { func (this *LogAction) Init() {
this.Nav("", "", "") this.Nav("", "", "log")
} }
func (this *LogAction) RunGet(params struct{}) { func (this *LogAction) RunGet(params struct{}) {

View File

@@ -0,0 +1,82 @@
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/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
)
type SortGroupsAction struct {
actionutils.ParentAction
}
func (this *SortGroupsAction) RunPost(params struct {
FirewallPolicyId int64
Type string
GroupIds []int64
}) {
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
}
switch params.Type {
case "inbound":
refMapping := map[int64]*firewallconfigs.HTTPFirewallRuleGroupRef{}
for _, ref := range firewallPolicy.Inbound.GroupRefs {
refMapping[ref.GroupId] = ref
}
newRefs := []*firewallconfigs.HTTPFirewallRuleGroupRef{}
for _, groupId := range params.GroupIds {
ref, ok := refMapping[groupId]
if ok {
newRefs = append(newRefs, ref)
}
}
firewallPolicy.Inbound.GroupRefs = newRefs
case "outbound":
refMapping := map[int64]*firewallconfigs.HTTPFirewallRuleGroupRef{}
for _, ref := range firewallPolicy.Outbound.GroupRefs {
refMapping[ref.GroupId] = ref
}
newRefs := []*firewallconfigs.HTTPFirewallRuleGroupRef{}
for _, groupId := range params.GroupIds {
ref, ok := refMapping[groupId]
if ok {
newRefs = append(newRefs, ref)
}
}
firewallPolicy.Outbound.GroupRefs = newRefs
}
inboundJSON, err := firewallPolicy.InboundJSON()
if err != nil {
this.ErrorPage(err)
return
}
outboundJSON, err := firewallPolicy.OutboundJSON()
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallPolicyGroups(this.AdminContext(), &pb.UpdateHTTPFirewallPolicyGroupsRequest{
FirewallPolicyId: params.FirewallPolicyId,
InboundJSON: inboundJSON,
OutboundJSON: outboundJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -7,7 +7,7 @@ type TestAction struct {
} }
func (this *TestAction) Init() { func (this *TestAction) Init() {
this.Nav("", "", "") this.Nav("", "", "test")
} }
func (this *TestAction) RunGet(params struct{}) { func (this *TestAction) RunGet(params struct{}) {

View File

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

View File

@@ -158,6 +158,22 @@ window.teaweb = {
} }
}); });
}, },
successToast: function (message, timeout) {
if (timeout == null) {
timeout = 2000
}
var width = "20em";
if (message.length > 30) {
width = "30em";
}
Swal.fire({
text: message,
icon: "success",
width: width,
timer: timeout,
showConfirmButton: false
});
},
warn: function (message, callback) { warn: function (message, callback) {
var width = "20em"; var width = "20em";
if (message.length > 30) { if (message.length > 30) {

View File

@@ -2,8 +2,8 @@
<menu-item href="/servers/components/waf">列表</menu-item> <menu-item href="/servers/components/waf">列表</menu-item>
<span class="item">|</span> <span class="item">|</span>
<menu-item :href="'/servers/components/waf/policy?firewallPolicyId=' + firewallPolicyId" code="index">{{firewallPolicyName}}</menu-item> <menu-item :href="'/servers/components/waf/policy?firewallPolicyId=' + firewallPolicyId" code="index">{{firewallPolicyName}}</menu-item>
<menu-item :href="'/servers/components/waf/groups?type=firewallPolicyId=' + firewallPolicyId + '&type=inbound'" code="inbound">入站规则({{countInboundGroups}})</menu-item> <menu-item :href="'/servers/components/waf/groups?firewallPolicyId=' + firewallPolicyId + '&type=inbound'" code="inbound">入站规则({{countInboundGroups}})</menu-item>
<menu-item :href="'/servers/components/waf/groups?firewallPolicyId=' + firewallPolicyId + '&type=outbound'" code="outbound">出站规则({{countOutboundGroups}})</menu-item> <menu-item :href="'/servers/components/waf/groups?firewallPolicyId=' + firewallPolicyId + '&type=outbound'" code="outbound">出站规则({{countOutboundGroups}})</menu-item>
<menu-item :href="'/servers/components/waf/ipadmin?firewallPolicyId=' + firewallPolicyId" code="ipadmin">IP管理</menu-item> <menu-item :href="'/servers/components/waf/ipadmin?firewallPolicyId=' + firewallPolicyId" code="ipadmin">IP管理</menu-item>
<menu-item :href="'/servers/components/waf/log?firewallPolicyId=' + firewallPolicyId" code="log">拦截日志</menu-item> <menu-item :href="'/servers/components/waf/log?firewallPolicyId=' + firewallPolicyId" code="log">拦截日志</menu-item>
<menu-item :href="'/servers/components/waf/test?firewallPolicyId=' + firewallPolicyId" code="test">测试</menu-item> <menu-item :href="'/servers/components/waf/test?firewallPolicyId=' + firewallPolicyId" code="test">测试</menu-item>

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "waf_menu"}
<p class="ui message">此功能暂未开放,敬请期待。</p>
</div>

View File

@@ -0,0 +1,45 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "waf_menu"}
<second-menu style="margin-top:-1em">
<a href="" class="item" @click.prevent="createGroup(type)">[添加分组]</a>
</second-menu>
<p class="comment" v-if="groups.length == 0">暂时还没有规则分组。</p>
<table class="ui table selectable" v-if="groups.length > 0" id="sortable-table">
<thead>
<tr>
<th style="width:3em"></th>
<th>规则分组</th>
<th>规则集</th>
<th class="three op">操作</th>
</tr>
</thead>
<tbody v-for="group in groups" :data-group-id="group.id">
<tr>
<td style="text-align: center;"><i class="icon bars handle grey" title="拖动排序"></i> </td>
<td><span :class="{disabled:!group.isOn}">{{group.name}}</span>
<p class="comment" v-if="group.description.length > 0" style="padding-bottom:0">{{group.description}}</p>
<p>
<span v-if="group.isOn" class="ui label tiny green">启用</span>
<span v-if="!group.isOn" class="ui label tiny red">停用</span>
<span v-if="group.code.length > 0" class="ui label tiny">预置</span>
<span v-if="group.code.length == 0" class="ui label tiny">自定义</span>
</p>
</td>
<td>
<a :href="'/proxy/components/waf/sets?firewallPolicyId=' + firewallPolicyId + '&type=' + type + '&groupId=' + group.id">{{group.countSets}}</a>
</td>
<td>
<a :href="'/servers/components/waf/group?firewallPolicyId=' + firewallPolicyId + '&type=' + type + '&groupId=' + group.id">详情</a> &nbsp;
<a href="" v-if="!group.isOn" @click.prevent="enableGroup(group.id)">启用</a><a href="" v-if="group.isOn" @click.prevent="disableGroup(group.id)">停用</a> &nbsp;
<a href="" @click.prevent="deleteGroup(group.id)" v-if="group.canDelete">删除</a>
</td>
</tr>
</tbody>
</table>
</div>

View File

@@ -0,0 +1,68 @@
Tea.context(function () {
// 排序
this.$delay(function () {
let that = this
sortTable(function () {
let groupIds = []
document.querySelectorAll("tbody[data-group-id]")
.forEach(function (v) {
groupIds.push(v.getAttribute("data-group-id"))
})
that.$post(".sortGroups")
.params({
firewallPolicyId: that.firewallPolicyId,
type: that.type,
groupIds: groupIds
})
.success(function () {
teaweb.successToast("排序保存成功")
})
})
})
// 启用
this.enableGroup = function (groupId) {
this.$post(".updateGroupOn")
.params({
groupId: groupId,
isOn: 1
})
.refresh()
}
// 停用
this.disableGroup = function (groupId) {
this.$post(".updateGroupOn")
.params({
groupId: groupId,
isOn: 0
})
.refresh()
}
// 删除
this.deleteGroup = function (groupId) {
teaweb.confirm("确定要删除此规则分组吗?", function () {
this.$post(".deleteGroup")
.params({
firewallPolicyId: this.firewallPolicyId,
groupId: groupId
})
.refresh()
})
}
// 添加分组
this.createGroup = function (type) {
teaweb.popup("/servers/components/waf/createGroupPopup?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type, {
height: "16em",
callback: function () {
teaweb.success("保存成功", function () {
window.location.reload()
})
}
})
}
})

View File

@@ -0,0 +1,8 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "waf_menu"}
<p class="ui message">此功能暂未开放,敬请期待。</p>
</div>

View File

@@ -0,0 +1,8 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "waf_menu"}
<p class="ui message">此功能暂未开放,敬请期待。</p>
</div>

View File

@@ -0,0 +1,8 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "waf_menu"}
<p class="ui message">此功能暂未开放,敬请期待。</p>
</div>

View File

@@ -0,0 +1,8 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "waf_menu"}
<p class="ui message">此功能暂未开放,敬请期待。</p>
</div>