mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-16 05:30:27 +08:00
实现IP名单管理
This commit is contained in:
@@ -176,6 +176,14 @@ func (this *RPCClient) IPLibraryRPC() pb.IPLibraryServiceClient {
|
|||||||
return pb.NewIPLibraryServiceClient(this.pickConn())
|
return pb.NewIPLibraryServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) IPListRPC() pb.IPListServiceClient {
|
||||||
|
return pb.NewIPListServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) IPItemRPC() pb.IPItemServiceClient {
|
||||||
|
return pb.NewIPItemServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) FileRPC() pb.FileServiceClient {
|
func (this *RPCClient) FileRPC() pb.FileServiceClient {
|
||||||
return pb.NewFileServiceClient(this.pickConn())
|
return pb.NewFileServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ func init() {
|
|||||||
GetPost("/ipadmin", new(ipadmin.IndexAction)).
|
GetPost("/ipadmin", new(ipadmin.IndexAction)).
|
||||||
GetPost("/ipadmin/provinces", new(ipadmin.ProvincesAction)).
|
GetPost("/ipadmin/provinces", new(ipadmin.ProvincesAction)).
|
||||||
Get("/ipadmin/lists", new(ipadmin.ListsAction)).
|
Get("/ipadmin/lists", new(ipadmin.ListsAction)).
|
||||||
|
GetPost("/ipadmin/createIPPopup", new(ipadmin.CreateIPPopupAction)).
|
||||||
|
GetPost("/ipadmin/updateIPPopup", new(ipadmin.UpdateIPPopupAction)).
|
||||||
|
Post("/ipadmin/deleteIP", new(ipadmin.DeleteIPAction)).
|
||||||
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package ipadmin
|
||||||
|
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateIPPopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateIPPopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateIPPopupAction) RunGet(params struct {
|
||||||
|
FirewallPolicyId int64
|
||||||
|
Type string
|
||||||
|
}) {
|
||||||
|
this.Data["type"] = params.Type
|
||||||
|
|
||||||
|
listId, err := models.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyIPListIdWithType(this.AdminContext(), params.FirewallPolicyId, params.Type)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["listId"] = listId
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateIPPopupAction) RunPost(params struct {
|
||||||
|
ListId int64
|
||||||
|
IpFrom string
|
||||||
|
IpTo string
|
||||||
|
ExpiredAt int64
|
||||||
|
Reason string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
// TODO 校验ListId所属用户
|
||||||
|
// TODO 校验IP格式(ipFrom/ipTo)
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("ipFrom", params.IpFrom).
|
||||||
|
Require("请输入开始IP")
|
||||||
|
|
||||||
|
_, err := this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
|
||||||
|
IpListId: params.ListId,
|
||||||
|
IpFrom: params.IpFrom,
|
||||||
|
IpTo: params.IpTo,
|
||||||
|
ExpiredAt: params.ExpiredAt,
|
||||||
|
Reason: params.Reason,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package ipadmin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteIPAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DeleteIPAction) RunPost(params struct {
|
||||||
|
ItemId int64
|
||||||
|
}) {
|
||||||
|
// TODO 判断权限
|
||||||
|
|
||||||
|
_, err := this.RPC().IPItemRPC().DeleteIPItem(this.AdminContext(), &pb.DeleteIPItemRequest{IpItemId: params.ItemId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
package ipadmin
|
package ipadmin
|
||||||
|
|
||||||
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/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
type ListsAction struct {
|
type ListsAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
@@ -10,8 +16,56 @@ func (this *ListsAction) Init() {
|
|||||||
this.Nav("", "", "ipadmin")
|
this.Nav("", "", "ipadmin")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *ListsAction) RunGet(params struct{}) {
|
func (this *ListsAction) RunGet(params struct {
|
||||||
this.Data["subMenuItem"] = "list"
|
FirewallPolicyId int64
|
||||||
|
Type string
|
||||||
|
}) {
|
||||||
|
this.Data["subMenuItem"] = params.Type
|
||||||
|
|
||||||
|
listId, err := models.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyIPListIdWithType(this.AdminContext(), params.FirewallPolicyId, params.Type)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["listId"] = listId
|
||||||
|
|
||||||
|
// 数量
|
||||||
|
countResp, err := this.RPC().IPItemRPC().CountIPItemsWithListId(this.AdminContext(), &pb.CountIPItemsWithListIdRequest{IpListId: listId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
count := countResp.Count
|
||||||
|
page := this.NewPage(count)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
// 列表
|
||||||
|
itemsResp, err := this.RPC().IPItemRPC().ListIPItemsWithListId(this.AdminContext(), &pb.ListIPItemsWithListIdRequest{
|
||||||
|
IpListId: listId,
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
itemMaps := []maps.Map{}
|
||||||
|
for _, item := range itemsResp.IpItems {
|
||||||
|
expiredTime := ""
|
||||||
|
if item.ExpiredAt > 0 {
|
||||||
|
expiredTime = timeutil.FormatTime("Y-m-d H:i:s", item.ExpiredAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemMaps = append(itemMaps, maps.Map{
|
||||||
|
"id": item.Id,
|
||||||
|
"ipFrom": item.IpFrom,
|
||||||
|
"ipTo": item.IpTo,
|
||||||
|
"expiredTime": expiredTime,
|
||||||
|
"reason": item.Reason,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["items"] = itemMaps
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package ipadmin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateIPPopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateIPPopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateIPPopupAction) RunGet(params struct {
|
||||||
|
ItemId int64
|
||||||
|
}) {
|
||||||
|
itemResp, err := this.RPC().IPItemRPC().FindEnabledIPItem(this.AdminContext(), &pb.FindEnabledIPItemRequest{IpItemId: params.ItemId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
item := itemResp.IpItem
|
||||||
|
if item == nil {
|
||||||
|
this.NotFound("ipItem", params.ItemId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["item"] = maps.Map{
|
||||||
|
"id": item.Id,
|
||||||
|
"ipFrom": item.IpFrom,
|
||||||
|
"ipTo": item.IpTo,
|
||||||
|
"expiredAt": item.ExpiredAt,
|
||||||
|
"reason": item.Reason,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateIPPopupAction) RunPost(params struct {
|
||||||
|
ItemId int64
|
||||||
|
|
||||||
|
IpFrom string
|
||||||
|
IpTo string
|
||||||
|
ExpiredAt int64
|
||||||
|
Reason string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
// TODO 校验ItemId所属用户
|
||||||
|
// TODO 校验IP格式(ipFrom/ipTo)
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("ipFrom", params.IpFrom).
|
||||||
|
Require("请输入开始IP")
|
||||||
|
|
||||||
|
_, err := this.RPC().IPItemRPC().UpdateIPItem(this.AdminContext(), &pb.UpdateIPItemRequest{
|
||||||
|
IpItemId: params.ItemId,
|
||||||
|
IpFrom: params.IpFrom,
|
||||||
|
IpTo: params.IpTo,
|
||||||
|
ExpiredAt: params.ExpiredAt,
|
||||||
|
Reason: params.Reason,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -3,17 +3,20 @@ package models
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/errors"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ipconfigs"
|
||||||
)
|
)
|
||||||
|
|
||||||
var SharedHTTPFirewallPolicyDAO = new(HTTPFirewallPolicyDAO)
|
var SharedHTTPFirewallPolicyDAO = new(HTTPFirewallPolicyDAO)
|
||||||
|
|
||||||
|
// WAF策略相关
|
||||||
type HTTPFirewallPolicyDAO struct {
|
type HTTPFirewallPolicyDAO struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找缓存策略基本信息
|
// 查找WAF策略基本信息
|
||||||
func (this *HTTPFirewallPolicyDAO) FindEnabledPolicy(ctx context.Context, policyId int64) (*pb.HTTPFirewallPolicy, error) {
|
func (this *HTTPFirewallPolicyDAO) FindEnabledPolicy(ctx context.Context, policyId int64) (*pb.HTTPFirewallPolicy, error) {
|
||||||
client, err := rpc.SharedRPC()
|
client, err := rpc.SharedRPC()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -26,7 +29,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledPolicy(ctx context.Context, policy
|
|||||||
return resp.FirewallPolicy, nil
|
return resp.FirewallPolicy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找缓存策略配置
|
// 查找WAF策略配置
|
||||||
func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyConfig(ctx context.Context, policyId int64) (*firewallconfigs.HTTPFirewallPolicy, error) {
|
func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyConfig(ctx context.Context, policyId int64) (*firewallconfigs.HTTPFirewallPolicy, error) {
|
||||||
client, err := rpc.SharedRPC()
|
client, err := rpc.SharedRPC()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -46,3 +49,125 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyConfig(ctx context.Context,
|
|||||||
}
|
}
|
||||||
return firewallPolicy, nil
|
return firewallPolicy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查找WAF的Inbound
|
||||||
|
func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyInboundConfig(ctx context.Context, policyId int64) (*firewallconfigs.HTTPFirewallInboundConfig, error) {
|
||||||
|
config, err := this.FindEnabledPolicyConfig(ctx, policyId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("not found")
|
||||||
|
}
|
||||||
|
return config.Inbound, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据类型查找WAF的IP名单
|
||||||
|
func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyIPListIdWithType(ctx context.Context, policyId int64, listType ipconfigs.IPListType) (int64, error) {
|
||||||
|
switch listType {
|
||||||
|
case ipconfigs.IPListTypeWhite:
|
||||||
|
return this.FindEnabledPolicyWhiteIPListId(ctx, policyId)
|
||||||
|
case ipconfigs.IPListTypeBlack:
|
||||||
|
return this.FindEnabledPolicyBlackIPListId(ctx, policyId)
|
||||||
|
default:
|
||||||
|
return 0, errors.New("invalid ip list type '" + listType + "'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找WAF的白名单
|
||||||
|
func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyWhiteIPListId(ctx context.Context, policyId int64) (int64, error) {
|
||||||
|
client, err := rpc.SharedRPC()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := this.FindEnabledPolicyConfig(ctx, policyId)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if config == nil {
|
||||||
|
return 0, errors.New("not found")
|
||||||
|
}
|
||||||
|
if config.Inbound == nil {
|
||||||
|
config.Inbound = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||||
|
}
|
||||||
|
if config.Inbound.WhiteListRef == nil || config.Inbound.WhiteListRef.ListId == 0 {
|
||||||
|
createResp, err := client.IPListRPC().CreateIPList(ctx, &pb.CreateIPListRequest{
|
||||||
|
Type: "white",
|
||||||
|
Name: "白名单",
|
||||||
|
Code: "white",
|
||||||
|
TimeoutJSON: nil,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
listId := createResp.IpListId
|
||||||
|
config.Inbound.WhiteListRef = &ipconfigs.IPListRef{
|
||||||
|
IsOn: true,
|
||||||
|
ListId: listId,
|
||||||
|
}
|
||||||
|
inboundJSON, err := json.Marshal(config.Inbound)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
_, err = client.HTTPFirewallPolicyRPC().UpdateHTTPFirewallInboundConfig(ctx, &pb.UpdateHTTPFirewallInboundConfigRequest{
|
||||||
|
FirewallPolicyId: policyId,
|
||||||
|
InboundJSON: inboundJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return listId, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.Inbound.WhiteListRef.ListId, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找WAF的黑名单
|
||||||
|
func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyBlackIPListId(ctx context.Context, policyId int64) (int64, error) {
|
||||||
|
client, err := rpc.SharedRPC()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := this.FindEnabledPolicyConfig(ctx, policyId)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if config == nil {
|
||||||
|
return 0, errors.New("not found")
|
||||||
|
}
|
||||||
|
if config.Inbound == nil {
|
||||||
|
config.Inbound = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||||
|
}
|
||||||
|
if config.Inbound.BlackListRef == nil || config.Inbound.BlackListRef.ListId == 0 {
|
||||||
|
createResp, err := client.IPListRPC().CreateIPList(ctx, &pb.CreateIPListRequest{
|
||||||
|
Type: "black",
|
||||||
|
Name: "黑名单",
|
||||||
|
Code: "black",
|
||||||
|
TimeoutJSON: nil,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
listId := createResp.IpListId
|
||||||
|
config.Inbound.BlackListRef = &ipconfigs.IPListRef{
|
||||||
|
IsOn: true,
|
||||||
|
ListId: listId,
|
||||||
|
}
|
||||||
|
inboundJSON, err := json.Marshal(config.Inbound)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
_, err = client.HTTPFirewallPolicyRPC().UpdateHTTPFirewallInboundConfig(ctx, &pb.UpdateHTTPFirewallInboundConfigRequest{
|
||||||
|
FirewallPolicyId: policyId,
|
||||||
|
InboundJSON: inboundJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return listId, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.Inbound.BlackListRef.ListId, nil
|
||||||
|
}
|
||||||
|
|||||||
150
web/public/js/components/common/datetime-input.js
Normal file
150
web/public/js/components/common/datetime-input.js
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
Vue.component("datetime-input", {
|
||||||
|
props: ["v-name", "v-timestamp"],
|
||||||
|
data: function () {
|
||||||
|
let timestamp = this.vTimestamp
|
||||||
|
if (timestamp != null) {
|
||||||
|
timestamp = parseInt(timestamp)
|
||||||
|
if (isNaN(timestamp)) {
|
||||||
|
timestamp = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
timestamp = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
let day = ""
|
||||||
|
let hour = ""
|
||||||
|
let minute = ""
|
||||||
|
let second = ""
|
||||||
|
|
||||||
|
if (timestamp > 0) {
|
||||||
|
let date = new Date()
|
||||||
|
date.setTime(timestamp * 1000)
|
||||||
|
|
||||||
|
let year = date.getFullYear().toString()
|
||||||
|
let month = this.leadingZero((date.getMonth() + 1).toString(), 2)
|
||||||
|
day = year + "-" + month + "-" + this.leadingZero(date.getDate().toString(), 2)
|
||||||
|
|
||||||
|
hour = this.leadingZero(date.getHours().toString(), 2)
|
||||||
|
minute = this.leadingZero(date.getMinutes().toString(), 2)
|
||||||
|
second = this.leadingZero(date.getSeconds().toString(), 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
timestamp: timestamp,
|
||||||
|
day: day,
|
||||||
|
hour: hour,
|
||||||
|
minute: minute,
|
||||||
|
second: second,
|
||||||
|
|
||||||
|
hasDayError: false,
|
||||||
|
hasHourError: false,
|
||||||
|
hasMinuteError: false,
|
||||||
|
hasSecondError: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
change: function () {
|
||||||
|
let date = new Date()
|
||||||
|
|
||||||
|
// day
|
||||||
|
if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(this.day)) {
|
||||||
|
this.hasDayError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let pieces = this.day.split("-")
|
||||||
|
let year = parseInt(pieces[0])
|
||||||
|
date.setFullYear(year)
|
||||||
|
|
||||||
|
let month = parseInt(pieces[1])
|
||||||
|
if (month < 1 || month > 12) {
|
||||||
|
this.hasDayError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
date.setMonth(month - 1)
|
||||||
|
|
||||||
|
let day = parseInt(pieces[2])
|
||||||
|
if (day < 1 || day > 32) {
|
||||||
|
this.hasDayError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
date.setDate(day)
|
||||||
|
|
||||||
|
this.hasDayError = false
|
||||||
|
|
||||||
|
// hour
|
||||||
|
if (!/^\d+$/.test(this.hour)) {
|
||||||
|
this.hasHourError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let hour = parseInt(this.hour)
|
||||||
|
if (isNaN(hour)) {
|
||||||
|
this.hasHourError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (hour < 0 || hour >= 24) {
|
||||||
|
this.hasHourError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.hasHourError = false
|
||||||
|
date.setHours(hour)
|
||||||
|
|
||||||
|
// minute
|
||||||
|
if (!/^\d+$/.test(this.minute)) {
|
||||||
|
this.hasMinuteError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let minute = parseInt(this.minute)
|
||||||
|
if (isNaN(minute)) {
|
||||||
|
this.hasMinuteError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (minute < 0 || minute >= 60) {
|
||||||
|
this.hasMinuteError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.hasMinuteError = false
|
||||||
|
date.setMinutes(minute)
|
||||||
|
|
||||||
|
// second
|
||||||
|
if (!/^\d+$/.test(this.second)) {
|
||||||
|
this.hasSecondError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let second = parseInt(this.second)
|
||||||
|
if (isNaN(second)) {
|
||||||
|
this.hasSecondError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (second < 0 || second >= 60) {
|
||||||
|
this.hasSecondError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.hasSecondError = false
|
||||||
|
date.setSeconds(second)
|
||||||
|
|
||||||
|
this.timestamp = Math.ceil(date.getTime() / 1000)
|
||||||
|
},
|
||||||
|
leadingZero: function (s, l) {
|
||||||
|
if (l <= s.length) {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
for (let i = 0; i < l - s.length; i++) {
|
||||||
|
s = "0" + s
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" :name="vName" :value="timestamp"/>
|
||||||
|
<div class="ui fields inline" style="padding: 0; margin:0">
|
||||||
|
<div class="ui field" :class="{error: hasDayError}">
|
||||||
|
<input type="text" v-model="day" placeholder="YYYY-mm-dd" style="width:8em" maxlength="10" @input="change"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui field" :class="{error: hasHourError}"><input type="text" v-model="hour" maxlength="2" style="width:4em" placeholder="时" @input="change"/></div>
|
||||||
|
<div class="ui field">:</div>
|
||||||
|
<div class="ui field" :class="{error: hasMinuteError}"><input type="text" v-model="minute" maxlength="2" style="width:4em" placeholder="分" @input="change"/></div>
|
||||||
|
<div class="ui field">:</div>
|
||||||
|
<div class="ui field" :class="{error: hasSecondError}"><input type="text" v-model="second" maxlength="2" style="width:4em" placeholder="秒" @input="change"/></div>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
@@ -35,7 +35,7 @@ Vue.component("time-duration-box", {
|
|||||||
this.$emit("change", this.duration)
|
this.$emit("change", this.duration)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div class="ui fields inline">
|
template: `<div class="ui fields inline" style="padding-bottom: 0; margin-bottom: 0">
|
||||||
<input type="hidden" :name="vName" :value="JSON.stringify(duration)"/>
|
<input type="hidden" :name="vName" :value="JSON.stringify(duration)"/>
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<input type="text" v-model="countString" maxlength="11" size="11"/>
|
<input type="text" v-model="countString" maxlength="11" size="11"/>
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
<second-menu style="margin-top:-1em">
|
<second-menu style="margin-top:-1em">
|
||||||
<menu-item :href="'/servers/components/waf/ipadmin?firewallPolicyId=' + firewallPolicyId" :active="subMenuItem == 'region'">国家/地区封禁</menu-item>
|
<menu-item :href="'/servers/components/waf/ipadmin?firewallPolicyId=' + firewallPolicyId" :active="subMenuItem == 'region'">国家/地区封禁</menu-item>
|
||||||
<menu-item :href="'/servers/components/waf/ipadmin/provinces?firewallPolicyId=' + firewallPolicyId" :active="subMenuItem == 'province'">省份封禁</menu-item>
|
<menu-item :href="'/servers/components/waf/ipadmin/provinces?firewallPolicyId=' + firewallPolicyId" :active="subMenuItem == 'province'">省份封禁</menu-item>
|
||||||
<menu-item :href="'/servers/components/waf/ipadmin/lists?firewallPolicyId=' + firewallPolicyId" :active="subMenuItem == 'list'">IP名单</menu-item>
|
<span class="item">|</span>
|
||||||
|
<menu-item :href="'/servers/components/waf/ipadmin/lists?firewallPolicyId=' + firewallPolicyId + '&type=white'" :active="subMenuItem == 'white'">白名单</menu-item>
|
||||||
|
<a href="" class="item" @click.prevent="createIP('white')"><span style="font-size: 0.9em">[添加IP]</span></a>
|
||||||
|
<span class="item">|</span>
|
||||||
|
<menu-item :href="'/servers/components/waf/ipadmin/lists?firewallPolicyId=' + firewallPolicyId + '&type=black'" :active="subMenuItem == 'black'">黑名单</menu-item>
|
||||||
|
<a href="" class="item" @click.prevent="createIP('black')"><span style="font-size: 0.9em">[添加IP]</span></a>
|
||||||
</second-menu>
|
</second-menu>
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
|
<h3 v-if="type == 'white'">添加IP到白名单</h3>
|
||||||
|
<h3 v-if="type == 'black'">添加IP到黑名单</h3>
|
||||||
|
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<input type="hidden" name="listId" :value="listId"/>
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">开始IP *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="ipFrom" maxlength="64" placeholder="x.x.x.x" ref="focus"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>结束IP</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="ipTo" maxlength="64" placeholder="x.x.x.x"/>
|
||||||
|
<p class="comment">表示IP段的时候需要填写此项。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||||
|
</tr>
|
||||||
|
<tbody v-show="moreOptionsVisible">
|
||||||
|
<tr>
|
||||||
|
<td>过期时间</td>
|
||||||
|
<td>
|
||||||
|
<datetime-input :v-name="'expiredAt'"></datetime-input>
|
||||||
|
<p class="comment">在加入名单某一段时间后会失效,留空表示永久有效。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>备注</td>
|
||||||
|
<td><input type="text" name="reason" maxlength="100"/></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.success = NotifyPopup
|
||||||
|
})
|
||||||
@@ -36,4 +36,17 @@ Tea.context(function () {
|
|||||||
this.success = function () {
|
this.success = function () {
|
||||||
teaweb.successToast("保存成功")
|
teaweb.successToast("保存成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加IP名单菜单
|
||||||
|
*/
|
||||||
|
this.createIP = function (type) {
|
||||||
|
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||||
|
height: "23em",
|
||||||
|
callback: function () {
|
||||||
|
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
@@ -4,4 +4,34 @@
|
|||||||
<div class="right-box">
|
<div class="right-box">
|
||||||
{$template "../waf_menu"}
|
{$template "../waf_menu"}
|
||||||
{$template "menu"}
|
{$template "menu"}
|
||||||
|
|
||||||
|
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
|
||||||
|
|
||||||
|
<table class="ui table selectable" v-if="items.length > 0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>IP</th>
|
||||||
|
<th>过期时间</th>
|
||||||
|
<th>备注</th>
|
||||||
|
<th class="two op">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="item in items">
|
||||||
|
<td>{{item.ipFrom}}<span v-if="item.ipTo.length > 0"> - {{item.ipTo}}</span></td>
|
||||||
|
<td>
|
||||||
|
<span v-if="item.expiredTime.length > 0">{{item.expiredTime}}</span>
|
||||||
|
<span v-else class="disabled">不过期</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="item.reason.length > 0">{{item.reason}}</span>
|
||||||
|
<span v-else class="disabled">-</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="" @click.prevent="updateItem(item.id)">修改</a>
|
||||||
|
<a href="" @click.prevent="deleteItem(item.id)">删除</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="page" v-html="page"></div>
|
||||||
</div>
|
</div>
|
||||||
35
web/views/@default/servers/components/waf/ipadmin/lists.js
Normal file
35
web/views/@default/servers/components/waf/ipadmin/lists.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.updateItem = function (itemId) {
|
||||||
|
teaweb.popup(Tea.url(".updateIPPopup", {itemId: itemId}), {
|
||||||
|
height: "23em",
|
||||||
|
callback: function () {
|
||||||
|
teaweb.success("保存成功", function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.deleteItem = function (itemId) {
|
||||||
|
let that = this
|
||||||
|
teaweb.confirm("确定要删除这个IP吗?", function () {
|
||||||
|
that.$post(".deleteIP")
|
||||||
|
.params({
|
||||||
|
"itemId": itemId
|
||||||
|
})
|
||||||
|
.refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加IP名单菜单
|
||||||
|
*/
|
||||||
|
this.createIP = function (type) {
|
||||||
|
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||||
|
height: "23em",
|
||||||
|
callback: function () {
|
||||||
|
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<more-options-indicator>选择省份/自治区</more-options-indicator>
|
<more-options-indicator>选择省份/自治区</more-options-indicator>
|
||||||
|
|
||||||
<div class="province-list" v-show="moreOptionsVisible">
|
<div class="province-list" v-show="moreOptionsVisible" style="margin-top:0.5em">
|
||||||
<div class="item" v-for="province in provinces">
|
<div class="item" v-for="province in provinces">
|
||||||
<div class="ui checkbox" @click.prevent="selectProvince(province)">
|
<div class="ui checkbox" @click.prevent="selectProvince(province)">
|
||||||
<input type="checkbox" v-model="province.isChecked"/>
|
<input type="checkbox" v-model="province.isChecked"/>
|
||||||
|
|||||||
@@ -20,4 +20,16 @@ Tea.context(function () {
|
|||||||
this.success = function () {
|
this.success = function () {
|
||||||
teaweb.successToast("保存成功")
|
teaweb.successToast("保存成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加IP名单菜单
|
||||||
|
*/
|
||||||
|
this.createIP = function (type) {
|
||||||
|
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||||
|
height: "23em",
|
||||||
|
callback: function () {
|
||||||
|
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
|
<h3>修改IP</h3>
|
||||||
|
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<input type="hidden" name="itemId" :value="item.id"/>
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">开始IP *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="ipFrom" maxlength="64" placeholder="x.x.x.x" ref="focus" v-model="item.ipFrom"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>结束IP</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="ipTo" maxlength="64" placeholder="x.x.x.x" v-model="item.ipTo"/>
|
||||||
|
<p class="comment">表示IP段的时候需要填写此项。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||||
|
</tr>
|
||||||
|
<tbody v-show="moreOptionsVisible">
|
||||||
|
<tr>
|
||||||
|
<td>过期时间</td>
|
||||||
|
<td>
|
||||||
|
<datetime-input :v-name="'expiredAt'" :v-timestamp="item.expiredAt"></datetime-input>
|
||||||
|
<p class="comment">在加入名单某一段时间后会失效,留空表示永久有效。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>备注</td>
|
||||||
|
<td><input type="text" name="reason" maxlength="100" v-model="item.reason"/></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.success = NotifyPopup
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user