mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-03 12:20:28 +08:00
实现公用的IP名单
This commit is contained in:
3
build/configs/.gitignore
vendored
3
build/configs/.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
api.yaml
|
api.yaml
|
||||||
server.yaml
|
server.yaml
|
||||||
api_db.yaml
|
api_db.yaml
|
||||||
*.pem
|
*.pem
|
||||||
|
tip.json
|
||||||
2
go.mod
2
go.mod
@@ -9,6 +9,7 @@ require (
|
|||||||
github.com/cespare/xxhash v1.1.0
|
github.com/cespare/xxhash v1.1.0
|
||||||
github.com/go-sql-driver/mysql v1.5.0
|
github.com/go-sql-driver/mysql v1.5.0
|
||||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/google/go-cmp v0.5.6 // indirect
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f
|
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f
|
||||||
github.com/miekg/dns v1.1.35
|
github.com/miekg/dns v1.1.35
|
||||||
@@ -20,5 +21,6 @@ require (
|
|||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
|
||||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect
|
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect
|
||||||
google.golang.org/grpc v1.38.0
|
google.golang.org/grpc v1.38.0
|
||||||
|
google.golang.org/protobuf v1.26.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ func (this *ListsAction) RunGet(params struct {
|
|||||||
Type string
|
Type string
|
||||||
}) {
|
}) {
|
||||||
this.Data["subMenuItem"] = params.Type
|
this.Data["subMenuItem"] = params.Type
|
||||||
|
this.Data["type"] = params.Type
|
||||||
|
|
||||||
listId, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyIPListIdWithType(this.AdminContext(), params.FirewallPolicyId, params.Type)
|
listId, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyIPListIdWithType(this.AdminContext(), params.FirewallPolicyId, params.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BindHTTPFirewallPopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BindHTTPFirewallPopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BindHTTPFirewallPopupAction) RunGet(params struct {
|
||||||
|
HttpFirewallPolicyId int64
|
||||||
|
Type string
|
||||||
|
}) {
|
||||||
|
this.Data["httpFirewallPolicyId"] = params.HttpFirewallPolicyId
|
||||||
|
|
||||||
|
// 获取已经选中的名单IDs
|
||||||
|
var selectedIds = []int64{}
|
||||||
|
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if inboundConfig != nil {
|
||||||
|
for _, ref := range inboundConfig.PublicAllowListRefs {
|
||||||
|
selectedIds = append(selectedIds, ref.ListId)
|
||||||
|
}
|
||||||
|
for _, ref := range inboundConfig.PublicDenyListRefs {
|
||||||
|
selectedIds = append(selectedIds, ref.ListId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公共的名单
|
||||||
|
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,
|
||||||
|
"isSelected": lists.ContainsInt64(selectedIds, list.Id),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["lists"] = listMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BindHTTPFirewallPopupAction) RunPost(params struct {
|
||||||
|
HttpFirewallPolicyId int64
|
||||||
|
ListId int64
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
// List类型
|
||||||
|
listResp, err := this.RPC().IPListRPC().FindEnabledIPList(this.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: params.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var list = listResp.IpList
|
||||||
|
if list == nil {
|
||||||
|
this.Fail("找不到要使用的IP名单")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已经绑定的
|
||||||
|
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if inboundConfig == nil {
|
||||||
|
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||||
|
}
|
||||||
|
inboundConfig.AddPublicList(list.Id, list.Type)
|
||||||
|
|
||||||
|
inboundJSON, err := json.Marshal(inboundConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallInboundConfig(this.AdminContext(), &pb.UpdateHTTPFirewallInboundConfigRequest{
|
||||||
|
HttpFirewallPolicyId: params.HttpFirewallPolicyId,
|
||||||
|
InboundJSON: inboundJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
103
internal/web/actions/default/servers/iplists/createIPPopup.go
Normal file
103
internal/web/actions/default/servers/iplists/createIPPopup.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"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 {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
this.Data["listId"] = params.ListId
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateIPPopupAction) RunPost(params struct {
|
||||||
|
ListId int64
|
||||||
|
IpFrom string
|
||||||
|
IpTo string
|
||||||
|
ExpiredAt int64
|
||||||
|
Reason string
|
||||||
|
Type string
|
||||||
|
EventLevel string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
// 校验IPList
|
||||||
|
existsResp, err := this.RPC().IPListRPC().ExistsEnabledIPList(this.AdminContext(), &pb.ExistsEnabledIPListRequest{IpListId: params.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !existsResp.Exists {
|
||||||
|
this.Fail("IP名单不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch params.Type {
|
||||||
|
case "ipv4":
|
||||||
|
params.Must.
|
||||||
|
Field("ipFrom", params.IpFrom).
|
||||||
|
Require("请输入开始IP")
|
||||||
|
|
||||||
|
// 校验IP格式(ipFrom/ipTo)
|
||||||
|
var ipFromLong uint64
|
||||||
|
if !utils.IsIPv4(params.IpFrom) {
|
||||||
|
this.Fail("请输入正确的开始IP")
|
||||||
|
}
|
||||||
|
ipFromLong = utils.IP2Long(params.IpFrom)
|
||||||
|
|
||||||
|
var ipToLong uint64
|
||||||
|
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
|
||||||
|
ipToLong = utils.IP2Long(params.IpTo)
|
||||||
|
this.Fail("请输入正确的结束IP")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
|
||||||
|
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
|
||||||
|
}
|
||||||
|
case "ipv6":
|
||||||
|
params.Must.
|
||||||
|
Field("ipFrom", params.IpFrom).
|
||||||
|
Require("请输入IP")
|
||||||
|
|
||||||
|
// 校验IP格式(ipFrom)
|
||||||
|
if !utils.IsIPv6(params.IpFrom) {
|
||||||
|
this.Fail("请输入正确的IPv6地址")
|
||||||
|
}
|
||||||
|
case "all":
|
||||||
|
params.IpFrom = "0.0.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
createResp, err := this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
|
||||||
|
IpListId: params.ListId,
|
||||||
|
IpFrom: params.IpFrom,
|
||||||
|
IpTo: params.IpTo,
|
||||||
|
ExpiredAt: params.ExpiredAt,
|
||||||
|
Reason: params.Reason,
|
||||||
|
Type: params.Type,
|
||||||
|
EventLevel: params.EventLevel,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
itemId := createResp.IpItemId
|
||||||
|
|
||||||
|
// 日志
|
||||||
|
defer this.CreateLog(oplogs.LevelInfo, "在IP名单中添加IP %d", itemId)
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
64
internal/web/actions/default/servers/iplists/createPopup.go
Normal file
64
internal/web/actions/default/servers/iplists/createPopup.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// 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/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreatePopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunGet(params struct {
|
||||||
|
Type string
|
||||||
|
}) {
|
||||||
|
this.Data["type"] = params.Type
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunPost(params struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Description string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
var listId int64 = 0
|
||||||
|
defer func() {
|
||||||
|
defer this.CreateLogInfo("创建IP名单 %d", listId)
|
||||||
|
}()
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("name", params.Name).
|
||||||
|
Require("请输入名称")
|
||||||
|
|
||||||
|
createResp, err := this.RPC().IPListRPC().CreateIPList(this.AdminContext(), &pb.CreateIPListRequest{
|
||||||
|
Type: params.Type,
|
||||||
|
Name: params.Name,
|
||||||
|
Code: "",
|
||||||
|
TimeoutJSON: nil,
|
||||||
|
IsPublic: true,
|
||||||
|
Description: params.Description,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
listId = createResp.IpListId
|
||||||
|
|
||||||
|
this.Data["list"] = maps.Map{
|
||||||
|
"type": params.Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
27
internal/web/actions/default/servers/iplists/delete.go
Normal file
27
internal/web/actions/default/servers/iplists/delete.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DeleteAction) RunPost(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("删除IP名单 %d", params.ListId)
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
_, err := this.RPC().IPListRPC().DeleteIPList(this.AdminContext(), &pb.DeleteIPListRequest{IpListId: params.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
26
internal/web/actions/default/servers/iplists/deleteIP.go
Normal file
26
internal/web/actions/default/servers/iplists/deleteIP.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
|
"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
|
||||||
|
}) {
|
||||||
|
// 日志
|
||||||
|
defer this.CreateLog(oplogs.LevelInfo, "从IP名单中删除IP %d", params.ItemId)
|
||||||
|
|
||||||
|
_, err := this.RPC().IPItemRPC().DeleteIPItem(this.AdminContext(), &pb.DeleteIPItemRequest{IpItemId: params.ItemId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
25
internal/web/actions/default/servers/iplists/export.go
Normal file
25
internal/web/actions/default/servers/iplists/export.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
|
||||||
|
type ExportAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ExportAction) Init() {
|
||||||
|
this.Nav("", "", "export")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ExportAction) RunGet(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
err := InitIPList(this.Parent(), params.ListId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
57
internal/web/actions/default/servers/iplists/exportData.go
Normal file
57
internal/web/actions/default/servers/iplists/exportData.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExportDataAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ExportDataAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ExportDataAction) RunGet(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("导出IP名单 %d", params.ListId)
|
||||||
|
|
||||||
|
resp := &pb.ListIPItemsWithListIdResponse{}
|
||||||
|
var offset int64 = 0
|
||||||
|
var size int64 = 1000
|
||||||
|
for {
|
||||||
|
itemsResp, err := this.RPC().IPItemRPC().ListIPItemsWithListId(this.AdminContext(), &pb.ListIPItemsWithListIdRequest{
|
||||||
|
IpListId: params.ListId,
|
||||||
|
Offset: offset,
|
||||||
|
Size: size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(itemsResp.IpItems) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, item := range itemsResp.IpItems {
|
||||||
|
resp.IpItems = append(resp.IpItems, item)
|
||||||
|
}
|
||||||
|
offset += size
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := proto.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.AddHeader("Content-Disposition", "attachment; filename=\"ip-list-"+numberutils.FormatInt64(params.ListId)+".data\";")
|
||||||
|
this.AddHeader("Content-Length", strconv.Itoa(len(data)))
|
||||||
|
this.Write(data)
|
||||||
|
}
|
||||||
59
internal/web/actions/default/servers/iplists/httpFirewall.go
Normal file
59
internal/web/actions/default/servers/iplists/httpFirewall.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// 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/dao"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ipconfigs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HttpFirewallAction 显示已经绑定的IP名单
|
||||||
|
type HttpFirewallAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *HttpFirewallAction) RunPost(params struct {
|
||||||
|
HttpFirewallPolicyId int64
|
||||||
|
Type string
|
||||||
|
}) {
|
||||||
|
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if inboundConfig == nil {
|
||||||
|
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||||
|
}
|
||||||
|
var refs []*ipconfigs.IPListRef
|
||||||
|
switch params.Type {
|
||||||
|
case ipconfigs.IPListTypeBlack:
|
||||||
|
refs = inboundConfig.PublicDenyListRefs
|
||||||
|
case ipconfigs.IPListTypeWhite:
|
||||||
|
refs = inboundConfig.PublicAllowListRefs
|
||||||
|
}
|
||||||
|
|
||||||
|
listMaps := []maps.Map{}
|
||||||
|
for _, ref := range refs {
|
||||||
|
listResp, err := this.RPC().IPListRPC().FindEnabledIPList(this.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: ref.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var list = listResp.IpList
|
||||||
|
if list == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
listMaps = append(listMaps, maps.Map{
|
||||||
|
"id": list.Id,
|
||||||
|
"name": list.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["lists"] = listMaps
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
87
internal/web/actions/default/servers/iplists/import.go
Normal file
87
internal/web/actions/default/servers/iplists/import.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
// 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/golang/protobuf/proto"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ImportAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ImportAction) Init() {
|
||||||
|
this.Nav("", "", "import")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ImportAction) RunGet(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
err := InitIPList(this.Parent(), params.ListId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ImportAction) RunPost(params struct {
|
||||||
|
ListId int64
|
||||||
|
File *actions.File
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("导入IP名单 %d", params.ListId)
|
||||||
|
|
||||||
|
existsResp, err := this.RPC().IPListRPC().ExistsEnabledIPList(this.AdminContext(), &pb.ExistsEnabledIPListRequest{IpListId: params.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !existsResp.Exists {
|
||||||
|
this.Fail("IP名单不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.File == nil {
|
||||||
|
this.Fail("请选择要导入的IP文件")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := params.File.Read()
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp := &pb.ListIPItemsWithListIdResponse{}
|
||||||
|
err = proto.Unmarshal(data, resp)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("导入失败,文件格式错误:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var count = 0
|
||||||
|
var countIgnore = 0
|
||||||
|
for _, item := range resp.IpItems {
|
||||||
|
_, err = this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
|
||||||
|
IpListId: params.ListId,
|
||||||
|
IpFrom: item.IpFrom,
|
||||||
|
IpTo: item.IpTo,
|
||||||
|
ExpiredAt: item.ExpiredAt,
|
||||||
|
Reason: item.Reason,
|
||||||
|
Type: item.Type,
|
||||||
|
EventLevel: item.EventLevel,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("导入过程中出错:" + err.Error())
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["count"] = count
|
||||||
|
this.Data["countIgnore"] = countIgnore
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
76
internal/web/actions/default/servers/iplists/index.go
Normal file
76
internal/web/actions/default/servers/iplists/index.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// 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/TeaOSLab/EdgeCommon/pkg/serverconfigs/ipconfigs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "index")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
Type string
|
||||||
|
Keyword string
|
||||||
|
}) {
|
||||||
|
if len(params.Type) == 0 {
|
||||||
|
params.Type = ipconfigs.IPListTypeBlack
|
||||||
|
}
|
||||||
|
this.Data["type"] = params.Type
|
||||||
|
this.Data["keyword"] = params.Keyword
|
||||||
|
|
||||||
|
countResp, err := this.RPC().IPListRPC().CountAllEnabledIPLists(this.AdminContext(), &pb.CountAllEnabledIPListsRequest{
|
||||||
|
Type: params.Type,
|
||||||
|
IsPublic: true,
|
||||||
|
Keyword: params.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: params.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()
|
||||||
|
}
|
||||||
39
internal/web/actions/default/servers/iplists/init.go
Normal file
39
internal/web/actions/default/servers/iplists/init.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
|
"github.com/iwind/TeaGo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
|
server.
|
||||||
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
|
||||||
|
Data("teaMenu", "servers").
|
||||||
|
Data("teaSubMenu", "iplist").
|
||||||
|
Prefix("/servers/iplists").
|
||||||
|
Get("", new(IndexAction)).
|
||||||
|
GetPost("/createPopup", new(CreatePopupAction)).
|
||||||
|
Get("/list", new(ListAction)).
|
||||||
|
GetPost("/import", new(ImportAction)).
|
||||||
|
GetPost("/export", new(ExportAction)).
|
||||||
|
Get("/exportData", new(ExportDataAction)).
|
||||||
|
Post("/delete", new(DeleteAction)).
|
||||||
|
GetPost("/test", new(TestAction)).
|
||||||
|
GetPost("/update", new(UpdateAction)).
|
||||||
|
Get("/items", new(ItemsAction)).
|
||||||
|
|
||||||
|
// IP相关
|
||||||
|
GetPost("/createIPPopup", new(CreateIPPopupAction)).
|
||||||
|
GetPost("/updateIPPopup", new(UpdateIPPopupAction)).
|
||||||
|
Post("/deleteIP", new(DeleteIPAction)).
|
||||||
|
|
||||||
|
// 防火墙
|
||||||
|
GetPost("/bindHTTPFirewallPopup", new(BindHTTPFirewallPopupAction)).
|
||||||
|
Post("/unbindHTTPFirewall", new(UnbindHTTPFirewallAction)).
|
||||||
|
Post("/httpFirewall", new(HttpFirewallAction)).
|
||||||
|
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
71
internal/web/actions/default/servers/iplists/items.go
Normal file
71
internal/web/actions/default/servers/iplists/items.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// 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/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ItemsAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ItemsAction) Init() {
|
||||||
|
this.Nav("", "", "item")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ItemsAction) RunGet(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
err := InitIPList(this.Parent(), params.ListId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数量
|
||||||
|
var listId = params.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,
|
||||||
|
"type": item.Type,
|
||||||
|
"eventLevelName": firewallconfigs.FindFirewallEventLevelName(item.EventLevel),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["items"] = itemMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
25
internal/web/actions/default/servers/iplists/list.go
Normal file
25
internal/web/actions/default/servers/iplists/list.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
|
||||||
|
type ListAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ListAction) Init() {
|
||||||
|
this.Nav("", "", "list")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ListAction) RunGet(params struct{
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
err := InitIPList(this.Parent(), params.ListId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
74
internal/web/actions/default/servers/iplists/test.go
Normal file
74
internal/web/actions/default/servers/iplists/test.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// 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/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TestAction) Init() {
|
||||||
|
this.Nav("", "", "test")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TestAction) RunGet(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
err := InitIPList(this.Parent(), params.ListId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TestAction) RunPost(params struct {
|
||||||
|
ListId int64
|
||||||
|
Ip string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
resp, err := this.RPC().IPItemRPC().CheckIPItemStatus(this.AdminContext(), &pb.CheckIPItemStatusRequest{
|
||||||
|
IpListId: params.ListId,
|
||||||
|
Ip: params.Ip,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resultMap := maps.Map{
|
||||||
|
"isDone": true,
|
||||||
|
"isFound": resp.IsFound,
|
||||||
|
"isOk": resp.IsOk,
|
||||||
|
"error": resp.Error,
|
||||||
|
"isAllowed": resp.IsAllowed,
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.IpItem != nil {
|
||||||
|
resultMap["item"] = maps.Map{
|
||||||
|
"id": resp.IpItem.Id,
|
||||||
|
"ipFrom": resp.IpItem.IpFrom,
|
||||||
|
"ipTo": resp.IpItem.IpTo,
|
||||||
|
"reason": resp.IpItem.Reason,
|
||||||
|
"expiredAt": resp.IpItem.ExpiredAt,
|
||||||
|
"expiredTime": timeutil.FormatTime("Y-m-d H:i:s", resp.IpItem.ExpiredAt),
|
||||||
|
"type": resp.IpItem.Type,
|
||||||
|
"eventLevelName": firewallconfigs.FindFirewallEventLevelName(resp.IpItem.EventLevel),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["result"] = resultMap
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UnbindHTTPFirewallAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UnbindHTTPFirewallAction) RunPost(params struct {
|
||||||
|
HttpFirewallPolicyId int64
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
// List类型
|
||||||
|
listResp, err := this.RPC().IPListRPC().FindEnabledIPList(this.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: params.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var list = listResp.IpList
|
||||||
|
if list == nil {
|
||||||
|
this.Fail("找不到要使用的IP名单")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已经绑定的
|
||||||
|
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if inboundConfig == nil {
|
||||||
|
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||||
|
}
|
||||||
|
inboundConfig.RemovePublicList(list.Id, list.Type)
|
||||||
|
|
||||||
|
inboundJSON, err := json.Marshal(inboundConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallInboundConfig(this.AdminContext(), &pb.UpdateHTTPFirewallInboundConfigRequest{
|
||||||
|
HttpFirewallPolicyId: params.HttpFirewallPolicyId,
|
||||||
|
InboundJSON: inboundJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
58
internal/web/actions/default/servers/iplists/update.go
Normal file
58
internal/web/actions/default/servers/iplists/update.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// 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/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAction) Init() {
|
||||||
|
this.Nav("", "", "update")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAction) RunGet(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
err := InitIPList(this.Parent(), params.ListId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAction) RunPost(params struct {
|
||||||
|
ListId int64
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Description string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("修改IP名单 %d", params.ListId)
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("name", params.Name).
|
||||||
|
Require("请输入名称")
|
||||||
|
|
||||||
|
_, err := this.RPC().IPListRPC().UpdateIPList(this.AdminContext(), &pb.UpdateIPListRequest{
|
||||||
|
IpListId: params.ListId,
|
||||||
|
Name: params.Name,
|
||||||
|
Code: "",
|
||||||
|
TimeoutJSON: nil,
|
||||||
|
Description: params.Description,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
117
internal/web/actions/default/servers/iplists/updateIPPopup.go
Normal file
117
internal/web/actions/default/servers/iplists/updateIPPopup.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
|
"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,
|
||||||
|
"type": item.Type,
|
||||||
|
"eventLevel": item.EventLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["type"] = item.Type
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateIPPopupAction) RunPost(params struct {
|
||||||
|
ItemId int64
|
||||||
|
|
||||||
|
IpFrom string
|
||||||
|
IpTo string
|
||||||
|
ExpiredAt int64
|
||||||
|
Reason string
|
||||||
|
Type string
|
||||||
|
EventLevel string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
// 日志
|
||||||
|
defer this.CreateLog(oplogs.LevelInfo, "修改IP名单中IP %d", params.ItemId)
|
||||||
|
|
||||||
|
// TODO 校验ItemId所属用户
|
||||||
|
|
||||||
|
switch params.Type {
|
||||||
|
case "ipv4":
|
||||||
|
params.Must.
|
||||||
|
Field("ipFrom", params.IpFrom).
|
||||||
|
Require("请输入开始IP")
|
||||||
|
|
||||||
|
// 校验IP格式(ipFrom/ipTo)
|
||||||
|
var ipFromLong uint64
|
||||||
|
if !utils.IsIPv4(params.IpFrom) {
|
||||||
|
this.Fail("请输入正确的开始IP")
|
||||||
|
}
|
||||||
|
ipFromLong = utils.IP2Long(params.IpFrom)
|
||||||
|
|
||||||
|
var ipToLong uint64
|
||||||
|
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
|
||||||
|
ipToLong = utils.IP2Long(params.IpTo)
|
||||||
|
this.Fail("请输入正确的结束IP")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
|
||||||
|
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
|
||||||
|
}
|
||||||
|
case "ipv6":
|
||||||
|
params.Must.
|
||||||
|
Field("ipFrom", params.IpFrom).
|
||||||
|
Require("请输入IP")
|
||||||
|
|
||||||
|
// 校验IP格式(ipFrom)
|
||||||
|
if !utils.IsIPv6(params.IpFrom) {
|
||||||
|
this.Fail("请输入正确的IPv6地址")
|
||||||
|
}
|
||||||
|
case "all":
|
||||||
|
params.IpFrom = "0.0.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := this.RPC().IPItemRPC().UpdateIPItem(this.AdminContext(), &pb.UpdateIPItemRequest{
|
||||||
|
IpItemId: params.ItemId,
|
||||||
|
IpFrom: params.IpFrom,
|
||||||
|
IpTo: params.IpTo,
|
||||||
|
ExpiredAt: params.ExpiredAt,
|
||||||
|
Reason: params.Reason,
|
||||||
|
Type: params.Type,
|
||||||
|
EventLevel: params.EventLevel,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
52
internal/web/actions/default/servers/iplists/utils.go
Normal file
52
internal/web/actions/default/servers/iplists/utils.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitIPList(action *actionutils.ParentAction, listId int64) error {
|
||||||
|
client, err := rpc.SharedRPC()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
listResp, err := client.IPListRPC().FindEnabledIPList(action.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: listId})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
list := listResp.IpList
|
||||||
|
if list == nil {
|
||||||
|
return errors.New("not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var typeName = ""
|
||||||
|
switch list.Type {
|
||||||
|
case "black":
|
||||||
|
typeName = "黑名单"
|
||||||
|
case "white":
|
||||||
|
typeName = "白名单"
|
||||||
|
}
|
||||||
|
|
||||||
|
// IP数量
|
||||||
|
countItemsResp, err := client.IPItemRPC().CountIPItemsWithListId(action.AdminContext(), &pb.CountIPItemsWithListIdRequest{IpListId: listId})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
countItems := countItemsResp.Count
|
||||||
|
|
||||||
|
action.Data["list"] = maps.Map{
|
||||||
|
"id": list.Id,
|
||||||
|
"name": list.Name,
|
||||||
|
"type": list.Type,
|
||||||
|
"typeName": typeName,
|
||||||
|
"description": list.Description,
|
||||||
|
"isOn": list.IsOn,
|
||||||
|
"countItems": countItems,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
30
internal/web/actions/default/ui/hideTip.go
Normal file
30
internal/web/actions/default/ui/hideTip.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HideTipAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *HideTipAction) RunPost(params struct {
|
||||||
|
Code string
|
||||||
|
}) {
|
||||||
|
tipKeyLocker.Lock()
|
||||||
|
tipKeyMap[params.Code] = true
|
||||||
|
tipKeyLocker.Unlock()
|
||||||
|
|
||||||
|
// 保存到文件
|
||||||
|
tipJSON, err := json.Marshal(tipKeyMap)
|
||||||
|
if err == nil {
|
||||||
|
_ = ioutil.WriteFile(Tea.ConfigFile(tipConfigFile), tipJSON, 0666)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -27,6 +27,8 @@ func init() {
|
|||||||
GetPost("/selectProvincesPopup", new(SelectProvincesPopupAction)).
|
GetPost("/selectProvincesPopup", new(SelectProvincesPopupAction)).
|
||||||
GetPost("/selectCountriesPopup", new(SelectCountriesPopupAction)).
|
GetPost("/selectCountriesPopup", new(SelectCountriesPopupAction)).
|
||||||
Post("/eventLevelOptions", new(EventLevelOptionsAction)).
|
Post("/eventLevelOptions", new(EventLevelOptionsAction)).
|
||||||
|
Post("/showTip", new(ShowTipAction)).
|
||||||
|
Post("/hideTip", new(HideTipAction)).
|
||||||
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
|
|||||||
48
internal/web/actions/default/ui/showTip.go
Normal file
48
internal/web/actions/default/ui/showTip.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/iwind/TeaGo"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"io/ioutil"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var tipKeyMap = map[string]bool{}
|
||||||
|
var tipKeyLocker = sync.Mutex{}
|
||||||
|
var tipConfigFile = "tip.json"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
|
// 从配置文件中加载已关闭的tips
|
||||||
|
data, err := ioutil.ReadFile(Tea.ConfigFile(tipConfigFile))
|
||||||
|
if err == nil {
|
||||||
|
var m = map[string]bool{}
|
||||||
|
err = json.Unmarshal(data, &m)
|
||||||
|
if err == nil {
|
||||||
|
tipKeyLocker.Lock()
|
||||||
|
tipKeyMap = m
|
||||||
|
tipKeyLocker.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShowTipAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ShowTipAction) RunPost(params struct {
|
||||||
|
Code string
|
||||||
|
}) {
|
||||||
|
tipKeyLocker.Lock()
|
||||||
|
_, ok := tipKeyMap[params.Code]
|
||||||
|
tipKeyLocker.Unlock()
|
||||||
|
|
||||||
|
this.Data["visible"] = !ok
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -167,6 +167,11 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
|||||||
"url": "/servers/components/waf",
|
"url": "/servers/components/waf",
|
||||||
"code": "waf",
|
"code": "waf",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "IP名单",
|
||||||
|
"url": "/servers/iplists",
|
||||||
|
"code": "iplist",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "证书管理",
|
"name": "证书管理",
|
||||||
"url": "/servers/certs",
|
"url": "/servers/certs",
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ import (
|
|||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/websocket"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/websocket"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/stat"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/stat"
|
||||||
|
|
||||||
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/iplists"
|
||||||
|
|
||||||
// 设置相关
|
// 设置相关
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/authority"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/authority"
|
||||||
|
|||||||
37
web/public/js/components/common/tip-message-box.js
Normal file
37
web/public/js/components/common/tip-message-box.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 信息提示窗口
|
||||||
|
Vue.component("tip-message-box", {
|
||||||
|
props: ["code"],
|
||||||
|
mounted: function () {
|
||||||
|
let that = this
|
||||||
|
Tea.action("/ui/showTip")
|
||||||
|
.params({
|
||||||
|
code: this.code
|
||||||
|
})
|
||||||
|
.success(function (resp) {
|
||||||
|
that.visible = resp.data.visible
|
||||||
|
})
|
||||||
|
.post()
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
close: function () {
|
||||||
|
this.visible = false
|
||||||
|
Tea.action("/ui/hideTip")
|
||||||
|
.params({
|
||||||
|
code: this.code
|
||||||
|
})
|
||||||
|
.post()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div class="ui icon message" v-if="visible">
|
||||||
|
<i class="icon info circle"></i>
|
||||||
|
<i class="close icon" title="取消" @click.prevent="close"></i>
|
||||||
|
<div class="content">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
62
web/public/js/components/iplist/ip-list-bind-box.js
Normal file
62
web/public/js/components/iplist/ip-list-bind-box.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// 绑定IP列表
|
||||||
|
Vue.component("ip-list-bind-box", {
|
||||||
|
props: ["v-http-firewall-policy-id", "v-type"],
|
||||||
|
mounted: function () {
|
||||||
|
this.refresh()
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
policyId: this.vHttpFirewallPolicyId,
|
||||||
|
type: this.vType,
|
||||||
|
lists: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
bind: function () {
|
||||||
|
let that = this
|
||||||
|
teaweb.popup("/servers/iplists/bindHTTPFirewallPopup?httpFirewallPolicyId=" + this.policyId + "&type=" + this.type, {
|
||||||
|
width: "50em",
|
||||||
|
height: "34em",
|
||||||
|
callback: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
onClose: function () {
|
||||||
|
that.refresh()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
remove: function (index, listId) {
|
||||||
|
let that = this
|
||||||
|
teaweb.confirm("确定要删除这个绑定的IP名单吗?", function () {
|
||||||
|
Tea.action("/servers/iplists/unbindHTTPFirewall")
|
||||||
|
.params({
|
||||||
|
httpFirewallPolicyId: that.policyId,
|
||||||
|
listId: listId
|
||||||
|
})
|
||||||
|
.post()
|
||||||
|
.success(function (resp) {
|
||||||
|
that.lists.$remove(index)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refresh: function () {
|
||||||
|
let that = this
|
||||||
|
Tea.action("/servers/iplists/httpFirewall")
|
||||||
|
.params({
|
||||||
|
httpFirewallPolicyId: this.policyId,
|
||||||
|
type: this.vType
|
||||||
|
})
|
||||||
|
.post()
|
||||||
|
.success(function (resp) {
|
||||||
|
that.lists = resp.data.lists
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<a href="" @click.prevent="bind()">绑定+</a> <span v-if="lists.length > 0"><span class="disabled small">| </span> 已绑定:</span>
|
||||||
|
<div class="ui label basic small" v-for="(list, index) in lists">
|
||||||
|
{{list.name}}
|
||||||
|
<a href="" title="删除" @click.prevent="remove(index, list.id)"><i class="icon remove small"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
@@ -34,7 +34,7 @@ Vue.component("http-access-log-box", {
|
|||||||
this.select()
|
this.select()
|
||||||
teaweb.popup("/servers/server/log/viewPopup?requestId=" + requestId, {
|
teaweb.popup("/servers/server/log/viewPopup?requestId=" + requestId, {
|
||||||
width: "50em",
|
width: "50em",
|
||||||
height: "24em",
|
height: "28em",
|
||||||
onClose: function () {
|
onClose: function () {
|
||||||
that.deselect()
|
that.deselect()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,9 +197,6 @@ p.margin {
|
|||||||
padding-top: 2em;
|
padding-top: 2em;
|
||||||
padding-bottom: 2.4em;
|
padding-bottom: 2.4em;
|
||||||
}
|
}
|
||||||
.main-menu .ui.menu .item span {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.main-menu .ui.labeled.icon.menu .item {
|
.main-menu .ui.labeled.icon.menu .item {
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
@@ -214,9 +211,19 @@ p.margin {
|
|||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
color: grey;
|
color: grey;
|
||||||
}
|
}
|
||||||
|
@media screen and (max-width: 512px) {
|
||||||
|
.main-menu .ui.menu .item.expend .subtitle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
.main-menu .ui.menu .sub-items .item {
|
.main-menu .ui.menu .sub-items .item {
|
||||||
padding-left: 2.8em !important;
|
padding-left: 2.8em !important;
|
||||||
}
|
}
|
||||||
|
@media screen and (max-width: 512px) {
|
||||||
|
.main-menu .ui.menu .sub-items .item {
|
||||||
|
padding-left: 1em!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
.main-menu .ui.menu .sub-items .item.active {
|
.main-menu .ui.menu .sub-items .item.active {
|
||||||
background-color: #2185d0 !important;
|
background-color: #2185d0 !important;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -80,7 +80,7 @@
|
|||||||
<span v-if="module.code.length > 0">
|
<span v-if="module.code.length > 0">
|
||||||
<i class="window restore outline icon" v-if="module.icon == null"></i>
|
<i class="window restore outline icon" v-if="module.icon == null"></i>
|
||||||
<i class="ui icon" v-if="module.icon != null" :class="module.icon"></i>
|
<i class="ui icon" v-if="module.icon != null" :class="module.icon"></i>
|
||||||
<span>{{module.name}}</span>
|
<span class="module-name">{{module.name}}</span>
|
||||||
</span>
|
</span>
|
||||||
<div class="subtitle" v-if="module.subtitle != null && module.subtitle.length > 0">{{module.subtitle}}</div>
|
<div class="subtitle" v-if="module.subtitle != null && module.subtitle.length > 0">{{module.subtitle}}</div>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ div.margin, p.margin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main-menu .ui.menu .item span {
|
.main-menu .ui.menu .item span {
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,11 +163,23 @@ div.margin, p.margin {
|
|||||||
color: grey;
|
color: grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 512px) {
|
||||||
|
.item.expend .subtitle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.sub-items {
|
.sub-items {
|
||||||
.item {
|
.item {
|
||||||
padding-left: 2.8em !important;
|
padding-left: 2.8em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 512px) {
|
||||||
|
.item {
|
||||||
|
padding-left: 1em!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.item.active {
|
.item.active {
|
||||||
background-color: #2185d0 !important;
|
background-color: #2185d0 !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,10 +56,13 @@ Tea.context(function () {
|
|||||||
* 添加IP名单菜单
|
* 添加IP名单菜单
|
||||||
*/
|
*/
|
||||||
this.createIP = function (type) {
|
this.createIP = function (type) {
|
||||||
|
let that = this
|
||||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||||
height: "23em",
|
height: "23em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
teaweb.success("保存成功", function () {
|
||||||
|
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
<second-menu style="margin-top: -1em">
|
<second-menu style="margin-top: -1em">
|
||||||
<span class="item">ID: {{listId}} <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
|
<span class="item">ID: {{listId}} <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
|
||||||
|
<span class="item disabled">|</span>
|
||||||
|
<div class="item"><ip-list-bind-box :v-http-firewall-policy-id="firewallPolicyId" :v-type="type"></ip-list-bind-box></div>
|
||||||
</second-menu>
|
</second-menu>
|
||||||
|
|
||||||
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
|
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
|
||||||
|
|||||||
@@ -26,10 +26,13 @@ Tea.context(function () {
|
|||||||
* 添加IP名单菜单
|
* 添加IP名单菜单
|
||||||
*/
|
*/
|
||||||
this.createIP = function (type) {
|
this.createIP = function (type) {
|
||||||
|
let that = this
|
||||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||||
height: "26em",
|
height: "26em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
teaweb.success("保存成功", function () {
|
||||||
|
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,10 +42,13 @@ Tea.context(function () {
|
|||||||
* 添加IP名单菜单
|
* 添加IP名单菜单
|
||||||
*/
|
*/
|
||||||
this.createIP = function (type) {
|
this.createIP = function (type) {
|
||||||
|
let that = this
|
||||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||||
height: "23em",
|
height: "23em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
teaweb.success("保存成功", function () {
|
||||||
|
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,50 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.ip = ""
|
this.ip = ""
|
||||||
this.result = {
|
this.result = {
|
||||||
isDone: false,
|
isDone: false,
|
||||||
isOk: false,
|
isOk: false,
|
||||||
isFound: false,
|
isFound: false,
|
||||||
isAllowed: false,
|
isAllowed: false,
|
||||||
error: "",
|
error: "",
|
||||||
province: null,
|
province: null,
|
||||||
country: null,
|
country: null,
|
||||||
ipItem: null,
|
ipItem: null,
|
||||||
ipList: null
|
ipList: null
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$delay(function () {
|
this.$delay(function () {
|
||||||
this.$watch("ip", function () {
|
this.$watch("ip", function () {
|
||||||
this.result.isDone = false
|
this.result.isDone = false
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
this.success = function (resp) {
|
this.success = function (resp) {
|
||||||
this.result = resp.data.result
|
this.result = resp.data.result
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateItem = function (itemId) {
|
this.updateItem = function (itemId) {
|
||||||
teaweb.popup(Tea.url(".updateIPPopup?firewallPolicyId=" + this.firewallPolicyId, {itemId: itemId}), {
|
teaweb.popup(Tea.url(".updateIPPopup?firewallPolicyId=" + this.firewallPolicyId, {itemId: itemId}), {
|
||||||
height: "26em",
|
height: "26em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
teaweb.reload()
|
teaweb.reload()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加IP名单菜单
|
* 添加IP名单菜单
|
||||||
*/
|
*/
|
||||||
this.createIP = function (type) {
|
this.createIP = function (type) {
|
||||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
let that = this
|
||||||
height: "26em",
|
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||||
callback: function () {
|
height: "26em",
|
||||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
callback: function () {
|
||||||
}
|
teaweb.success("保存成功", function () {
|
||||||
})
|
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
10
web/views/@default/servers/iplists/@list_menu.html
Normal file
10
web/views/@default/servers/iplists/@list_menu.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<first-menu>
|
||||||
|
<menu-item :href="'/servers/iplists?type=' + list.type">{{list.typeName}}</menu-item>
|
||||||
|
<span class="disabled item">|</span>
|
||||||
|
<menu-item :href="'/servers/iplists/list?listId=' + list.id" code="list">"{{list.name}}"详情</menu-item>
|
||||||
|
<menu-item :href="'/servers/iplists/items?listId=' + list.id" code="item">IP({{list.countItems}})</menu-item>
|
||||||
|
<menu-item :href="'/servers/iplists/update?listId=' + list.id" code="update">修改</menu-item>
|
||||||
|
<menu-item :href="'/servers/iplists/test?listId=' + list.id" code="test">IP检查</menu-item>
|
||||||
|
<menu-item :href="'/servers/iplists/export?listId=' + list.id" code="export">导出</menu-item>
|
||||||
|
<menu-item :href="'/servers/iplists/import?listId=' + list.id" code="import">导入</menu-item>
|
||||||
|
</first-menu>
|
||||||
8
web/views/@default/servers/iplists/@menu.html
Normal file
8
web/views/@default/servers/iplists/@menu.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<first-menu>
|
||||||
|
<menu-item href="/servers/iplists" :active="type == 'black'">黑名单</menu-item>
|
||||||
|
<menu-item href="/servers/iplists?type=white" :active="type == 'white'">白名单</menu-item>
|
||||||
|
<span class="item disabled">|</span>
|
||||||
|
<menu-item @click.prevent="createList">[创建]</menu-item>
|
||||||
|
<span class="item disabled">|</span>
|
||||||
|
<span class="item"><tip-icon content="可以在WAF策略里直接引用这些公用名单。"></tip-icon></span>
|
||||||
|
</first-menu>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
{$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">ID</th>
|
||||||
|
<th>名称</th>
|
||||||
|
<th class="two wide">类型</th>
|
||||||
|
<th>备注</th>
|
||||||
|
<th class="two wide">IP数量</th>
|
||||||
|
<th class="two op">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="list in lists">
|
||||||
|
<td>{{list.id}}</td>
|
||||||
|
<td>{{list.name}}</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="list.type == 'black'">黑名单</span>
|
||||||
|
<span v-if="list.type == 'white'">白名单</span>
|
||||||
|
</td>
|
||||||
|
<td>{{list.description}}</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="list.countItems > 0">{{list.countItems}}</span>
|
||||||
|
<span v-else class="disabled">0</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="" @click.prevent="bind(list)" v-if="!list.isSelected">绑定</a>
|
||||||
|
<a href="" style="color: grey" @click.prevent="unbind(list)" v-if="list.isSelected">已绑定</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="page" v-html="page"></div>
|
||||||
23
web/views/@default/servers/iplists/bindHTTPFirewallPopup.js
Normal file
23
web/views/@default/servers/iplists/bindHTTPFirewallPopup.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.bind = function (list) {
|
||||||
|
this.$post("$")
|
||||||
|
.params({
|
||||||
|
httpFirewallPolicyId: this.httpFirewallPolicyId,
|
||||||
|
listId: list.id
|
||||||
|
})
|
||||||
|
.success(function () {
|
||||||
|
list.isSelected = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.unbind = function (list) {
|
||||||
|
this.$post(".unbindHTTPFirewall")
|
||||||
|
.params({
|
||||||
|
httpFirewallPolicyId: this.httpFirewallPolicyId,
|
||||||
|
listId: list.id
|
||||||
|
})
|
||||||
|
.success(function () {
|
||||||
|
list.isSelected = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
76
web/views/@default/servers/iplists/createIPPopup.html
Normal file
76
web/views/@default/servers/iplists/createIPPopup.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
|
<h3>添加IP</h3>
|
||||||
|
|
||||||
|
<form method="post" 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">类型 *</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" name="type" v-model="type">
|
||||||
|
<option value="ipv4">IPv4</option>
|
||||||
|
<option value="ipv6">IPv6</option>
|
||||||
|
<option value="all">所有IP</option>
|
||||||
|
</select>
|
||||||
|
<p class="comment" v-if="type == 'ipv4'">单个IPv4或一个IPv4范围。</p>
|
||||||
|
<p class="comment" v-if="type == 'ipv6'">单个IPv6。</p>
|
||||||
|
<p class="comment" v-if="type == 'all'">允许或禁用所有的IP。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- IPv4 -->
|
||||||
|
<tbody v-if="type == 'ipv4'">
|
||||||
|
<tr>
|
||||||
|
<td>开始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>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
<!-- IPv6 -->
|
||||||
|
<tbody v-if="type == 'ipv6'">
|
||||||
|
<tr>
|
||||||
|
<td>IP *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="ipFrom" maxlength="64" placeholder="x:x:x:x:x:x:x:x" ref="focus"/>
|
||||||
|
<p class="comment">IPv6地址,比如 1406:3c00:0:2409:13:58:103:15</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>级别</td>
|
||||||
|
<td>
|
||||||
|
<firewall-event-level-options :v-value="eventLevel"></firewall-event-level-options>
|
||||||
|
</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>
|
||||||
4
web/views/@default/servers/iplists/createIPPopup.js
Normal file
4
web/views/@default/servers/iplists/createIPPopup.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.type = "ipv4"
|
||||||
|
this.eventLevel = (this.listType == "white") ? "debug" : "critical"
|
||||||
|
})
|
||||||
4
web/views/@default/servers/iplists/createPopup.css
Normal file
4
web/views/@default/servers/iplists/createPopup.css
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
h3 var {
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=createPopup.css.map */
|
||||||
1
web/views/@default/servers/iplists/createPopup.css.map
Normal file
1
web/views/@default/servers/iplists/createPopup.css.map
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["createPopup.less"],"names":[],"mappings":"AAAA,EACC;EACC,kBAAA","file":"createPopup.css"}
|
||||||
31
web/views/@default/servers/iplists/createPopup.html
Normal file
31
web/views/@default/servers/iplists/createPopup.html
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
|
<h3>创建<var v-if="type == 'black'">黑名单</var><var v-if="type == 'white'">白名单</var></h3>
|
||||||
|
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">名称 *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="name" maxlength="100" ref="focus"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>类型</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" name="type" v-model="type">
|
||||||
|
<option value="black">黑名单</option>
|
||||||
|
<option value="white">白名单</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>备注</td>
|
||||||
|
<td>
|
||||||
|
<textarea name="description" rows="2" maxlength="200"></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
5
web/views/@default/servers/iplists/createPopup.less
Normal file
5
web/views/@default/servers/iplists/createPopup.less
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
h3 {
|
||||||
|
var {
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
web/views/@default/servers/iplists/export.html
Normal file
13
web/views/@default/servers/iplists/export.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "list_menu"}
|
||||||
|
|
||||||
|
<div class="margin"></div>
|
||||||
|
<form class="ui form">
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">说明</td>
|
||||||
|
<td>导出所有的IP</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<a :href="'/servers/iplists/exportData?listId=' + list.id" class="ui button primary">导出</a>
|
||||||
|
</form>
|
||||||
19
web/views/@default/servers/iplists/import.html
Normal file
19
web/views/@default/servers/iplists/import.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "list_menu"}
|
||||||
|
|
||||||
|
<div class="margin"></div>
|
||||||
|
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<input type="hidden" name="listId" :value="list.id"/>
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">选择IP文件 *</td>
|
||||||
|
<td>
|
||||||
|
<input type="file" name="file" accept=".data"/>
|
||||||
|
<p class="comment">文件名类似于<code-label>ip-list-123.data</code-label>。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
7
web/views/@default/servers/iplists/import.js
Normal file
7
web/views/@default/servers/iplists/import.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.success = function (resp) {
|
||||||
|
teaweb.success("成功导入" + resp.data.count + "个IP", function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
38
web/views/@default/servers/iplists/index.html
Normal file
38
web/views/@default/servers/iplists/index.html
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "menu"}
|
||||||
|
|
||||||
|
<tip-message-box code="iplist-public-tip">这里是公用的IP名单,可以在WAF策略里直接引用。</tip-message-box>
|
||||||
|
|
||||||
|
<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="one wide">ID</th>
|
||||||
|
<th>名称</th>
|
||||||
|
<th class="one wide">类型</th>
|
||||||
|
<th>备注</th>
|
||||||
|
<th class="one wide">IP数量</th>
|
||||||
|
<th class="two op">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="list in lists">
|
||||||
|
<td>{{list.id}}</td>
|
||||||
|
<td>{{list.name}}</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="list.type == 'black'">黑名单</span>
|
||||||
|
<span v-if="list.type == 'white'">白名单</span>
|
||||||
|
</td>
|
||||||
|
<td>{{list.description}}</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="list.countItems > 0">{{list.countItems}}</span>
|
||||||
|
<span v-else class="disabled">0</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a :href="'/servers/iplists/list?listId=' + list.id">详情</a>
|
||||||
|
<a href="" @click.prevent="deleteList(list.id)">删除</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="page" v-html="page"></div>
|
||||||
26
web/views/@default/servers/iplists/index.js
Normal file
26
web/views/@default/servers/iplists/index.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.createList = function () {
|
||||||
|
teaweb.popup(Tea.url(".createPopup", {type: this.type}), {
|
||||||
|
callback: function (resp) {
|
||||||
|
teaweb.success("保存成功", function () {
|
||||||
|
window.location = "/servers/iplists?type=" + resp.data.list.type
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.deleteList = function (listId) {
|
||||||
|
let that = this
|
||||||
|
teaweb.confirm("确定要删除此IP名单吗?", function () {
|
||||||
|
that.$post(".delete")
|
||||||
|
.params({
|
||||||
|
listId: listId
|
||||||
|
})
|
||||||
|
.success(function () {
|
||||||
|
teaweb.success("删除成功", function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
12
web/views/@default/servers/iplists/items.html
Normal file
12
web/views/@default/servers/iplists/items.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "list_menu"}
|
||||||
|
|
||||||
|
<second-menu>
|
||||||
|
<menu-item @click.prevent="createIP">[创建IP]</menu-item>
|
||||||
|
</second-menu>
|
||||||
|
|
||||||
|
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
|
||||||
|
|
||||||
|
<ip-list-table v-if="items.length > 0" :v-items="items" @update-item="updateItem" @delete-item="deleteItem"></ip-list-table>
|
||||||
|
|
||||||
|
<div class="page" v-html="page"></div>
|
||||||
37
web/views/@default/servers/iplists/items.js
Normal file
37
web/views/@default/servers/iplists/items.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.updateItem = function (itemId) {
|
||||||
|
teaweb.popup(Tea.url(".updateIPPopup", {itemId: itemId}), {
|
||||||
|
height: "26em",
|
||||||
|
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 () {
|
||||||
|
teaweb.popup(Tea.url(".createIPPopup", {listId: this.list.id}), {
|
||||||
|
height: "23em",
|
||||||
|
callback: function () {
|
||||||
|
teaweb.success("保存成功", function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
24
web/views/@default/servers/iplists/list.html
Normal file
24
web/views/@default/servers/iplists/list.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "list_menu"}
|
||||||
|
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">名称</td>
|
||||||
|
<td>
|
||||||
|
{{list.name}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>类型</td>
|
||||||
|
<td>
|
||||||
|
{{list.typeName}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>备注</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="list.description.length > 0">{{list.description}}</span>
|
||||||
|
<span v-else class="disabled">-</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
39
web/views/@default/servers/iplists/test.html
Normal file
39
web/views/@default/servers/iplists/test.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "list_menu"}
|
||||||
|
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<input type="hidden" name="listId" :value="list.id"/>
|
||||||
|
<table class="ui table selectable definition">
|
||||||
|
<tr>
|
||||||
|
<td class="title">IP *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="ip" class="text" maxlength="100" ref="focus" placeholder="x.x.x.x" v-model="ip"/>
|
||||||
|
<p class="comment">要检查的IP</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>检查结果</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="result.isDone">
|
||||||
|
<div v-if="!result.isOk">
|
||||||
|
<span class="red">{{result.error}}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="result.isFound">
|
||||||
|
<div v-if="result.item != null">
|
||||||
|
<div v-if="result.isAllowed">
|
||||||
|
<span class="green">在白名单中 <ip-item-text :v-item="result.item"></ip-item-text> <a href="" @click.prevent="updateItem(result.list.id, result.item.id)" title="查看和修改"><i class="icon pencil small"></i></a></span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<span class="red">在黑名单中 <ip-item-text :v-item="result.item"></ip-item-text> <a href="" @click.prevent="updateItem(result.item.id)" title="查看和修改"><i class="icon pencil small"></i></a></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="!result.isFound">
|
||||||
|
没有找到和{{ip}}匹配的配置。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn>检查IP状态</submit-btn>
|
||||||
|
</form>
|
||||||
33
web/views/@default/servers/iplists/test.js
Normal file
33
web/views/@default/servers/iplists/test.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.ip = ""
|
||||||
|
this.result = {
|
||||||
|
isDone: false,
|
||||||
|
isOk: false,
|
||||||
|
isFound: false,
|
||||||
|
isAllowed: false,
|
||||||
|
error: "",
|
||||||
|
ipItem: null,
|
||||||
|
ipList: null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$delay(function () {
|
||||||
|
this.$watch("ip", function () {
|
||||||
|
this.result.isDone = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.success = function (resp) {
|
||||||
|
this.result = resp.data.result
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateItem = function (itemId) {
|
||||||
|
teaweb.popup(Tea.url(".updateIPPopup", {itemId: itemId}), {
|
||||||
|
height: "26em",
|
||||||
|
callback: function () {
|
||||||
|
teaweb.success("保存成功", function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
28
web/views/@default/servers/iplists/update.html
Normal file
28
web/views/@default/servers/iplists/update.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "list_menu"}
|
||||||
|
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<input type="hidden" name="listId" :value="list.id"/>
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">名称 *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="name" maxlength="100" ref="focus" v-model="list.name"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>类型</td>
|
||||||
|
<td>
|
||||||
|
{{list.typeName}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>备注</td>
|
||||||
|
<td>
|
||||||
|
<textarea name="description" rows="2" maxlength="200" v-model="list.description"></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
3
web/views/@default/servers/iplists/update.js
Normal file
3
web/views/@default/servers/iplists/update.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.success = NotifyReloadSuccess("保存成功")
|
||||||
|
})
|
||||||
76
web/views/@default/servers/iplists/updateIPPopup.html
Normal file
76
web/views/@default/servers/iplists/updateIPPopup.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
|
<h3>修改IP</h3>
|
||||||
|
|
||||||
|
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<input type="hidden" name="itemId" :value="item.id"/>
|
||||||
|
<input type="hidden" name="type" :value="item.type"/>
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">类型 *</td>
|
||||||
|
<td>
|
||||||
|
<!-- 类型不允许修改 -->
|
||||||
|
<span v-if="item.type == 'ipv4'">IPv4</span>
|
||||||
|
<span v-if="item.type == 'ipv6'">IPv6</span>
|
||||||
|
<span v-if="item.type == 'all'">所有IP</span>
|
||||||
|
|
||||||
|
<p class="comment" v-if="type == 'ipv4'">单个IPv4或一个IPv4范围。</p>
|
||||||
|
<p class="comment" v-if="type == 'ipv6'">单个IPv6。</p>
|
||||||
|
<p class="comment" v-if="type == 'all'">允许或禁用所有的IP。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- IPv4 -->
|
||||||
|
<tbody v-if="type == 'ipv4'">
|
||||||
|
<tr>
|
||||||
|
<td>开始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>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>级别</td>
|
||||||
|
<td>
|
||||||
|
<firewall-event-level-options :v-value="item.eventLevel"></firewall-event-level-options>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- IPv6 -->
|
||||||
|
<tbody v-if="type == 'ipv6'">
|
||||||
|
<tr>
|
||||||
|
<td>IP *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="ipFrom" maxlength="64" placeholder="x:x:x:x:x:x:x:x" ref="focus" v-model="item.ipFrom"/>
|
||||||
|
<p class="comment">IPv6地址,比如 1406:3c00:0:2409:13:58:103:15</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<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>
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
<menu-item @click.prevent="createIP('white')">添加IP</menu-item>
|
<menu-item @click.prevent="createIP('white')">添加IP</menu-item>
|
||||||
<span class="item">|</span>
|
<span class="item">|</span>
|
||||||
<span class="item">ID: {{listId}} <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
|
<span class="item">ID: {{listId}} <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
|
||||||
|
<span class="item">|</span>
|
||||||
|
<div class="item"><ip-list-bind-box :v-http-firewall-policy-id="firewallPolicyId" :v-type="'white'"></ip-list-bind-box></div>
|
||||||
</second-menu>
|
</second-menu>
|
||||||
|
|
||||||
<p class="ui message warning" v-if="!wafIsOn">当前WAF未启用,设置将在<a :href="'/servers/server/settings/waf?serverId=' + serverId">[启用]</a>后生效。</p>
|
<p class="ui message warning" v-if="!wafIsOn">当前WAF未启用,设置将在<a :href="'/servers/server/settings/waf?serverId=' + serverId">[启用]</a>后生效。</p>
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ Tea.context(function () {
|
|||||||
teaweb.popup("/servers/server/settings/waf/ipadmin/createIPPopup?listId=" + this.listId + '&type=' + type, {
|
teaweb.popup("/servers/server/settings/waf/ipadmin/createIPPopup?listId=" + this.listId + '&type=' + type, {
|
||||||
height: "26em",
|
height: "26em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
window.location.reload()
|
teaweb.success("保存成功", function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,10 +56,13 @@ Tea.context(function () {
|
|||||||
* 添加IP名单菜单
|
* 添加IP名单菜单
|
||||||
*/
|
*/
|
||||||
this.createIP = function (type) {
|
this.createIP = function (type) {
|
||||||
|
let that = this
|
||||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||||
height: "30em",
|
height: "30em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
teaweb.success("保存成功", function () {
|
||||||
|
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
<menu-item @click.prevent="createIP('black')">添加IP</menu-item>
|
<menu-item @click.prevent="createIP('black')">添加IP</menu-item>
|
||||||
<span class="item">|</span>
|
<span class="item">|</span>
|
||||||
<span class="item">ID: {{listId}} <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
|
<span class="item">ID: {{listId}} <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
|
||||||
|
<span class="item">|</span>
|
||||||
|
<div class="item"><ip-list-bind-box :v-http-firewall-policy-id="firewallPolicyId" :v-type="'black'"></ip-list-bind-box></div>
|
||||||
</second-menu>
|
</second-menu>
|
||||||
|
|
||||||
<p class="ui message warning" v-if="!wafIsOn">当前WAF未启用,设置将在<a :href="'/servers/server/settings/waf?serverId=' + serverId">[启用]</a>后生效。</p>
|
<p class="ui message warning" v-if="!wafIsOn">当前WAF未启用,设置将在<a :href="'/servers/server/settings/waf?serverId=' + serverId">[启用]</a>后生效。</p>
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ Tea.context(function () {
|
|||||||
teaweb.popup("/servers/server/settings/waf/ipadmin/createIPPopup?listId=" + this.listId + '&type=' + type, {
|
teaweb.popup("/servers/server/settings/waf/ipadmin/createIPPopup?listId=" + this.listId + '&type=' + type, {
|
||||||
height: "26em",
|
height: "26em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
window.location.reload()
|
teaweb.success("保存成功", function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,10 +42,13 @@ Tea.context(function () {
|
|||||||
* 添加IP名单菜单
|
* 添加IP名单菜单
|
||||||
*/
|
*/
|
||||||
this.createIP = function (type) {
|
this.createIP = function (type) {
|
||||||
|
let that = this
|
||||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||||
height: "30em",
|
height: "30em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
teaweb.success("保存成功", function () {
|
||||||
|
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 20em;
|
height: 20em;
|
||||||
}
|
}
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
/*# sourceMappingURL=clients.css.map */
|
/*# sourceMappingURL=clients.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["clients.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"clients.css"}
|
{"version":3,"sources":["clients.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"clients.css"}
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
要想查看统计数据,需要先开启统计功能,<a :href="'/servers/server/settings/stat?serverId=' + serverId">[点击这里]</a>修改配置。
|
要想查看统计数据,需要先开启统计功能,<a :href="'/servers/server/settings/stat?serverId=' + serverId">[点击这里]</a>修改配置。
|
||||||
</p>
|
</p>
|
||||||
{$else}
|
{$else}
|
||||||
<h4>操作系统排行</h4>
|
<h4>操作系统排行<span class="small grey">(按月)</span></h4>
|
||||||
<div class="chart-box" id="system-chart"></div>
|
<div class="chart-box" id="system-chart"></div>
|
||||||
|
|
||||||
<h4>浏览器排行</h4>
|
<h4>浏览器排行<span class="small grey">(按月)</span></h4>
|
||||||
<div class="chart-box" id="browser-chart"></div>
|
<div class="chart-box" id="browser-chart"></div>
|
||||||
{$end}
|
{$end}
|
||||||
</div>
|
</div>
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 20em;
|
height: 20em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 21em;
|
height: 21em;
|
||||||
}
|
}
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
/*# sourceMappingURL=dailyRequests.css.map */
|
/*# sourceMappingURL=dailyRequests.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["dailyRequests.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"dailyRequests.css"}
|
{"version":3,"sources":["dailyRequests.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"dailyRequests.css"}
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 21em;
|
height: 21em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 21em;
|
height: 21em;
|
||||||
}
|
}
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
/*# sourceMappingURL=hourlyRequests.css.map */
|
/*# sourceMappingURL=hourlyRequests.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["hourlyRequests.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"hourlyRequests.css"}
|
{"version":3,"sources":["hourlyRequests.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"hourlyRequests.css"}
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 21em;
|
height: 21em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 21em;
|
height: 21em;
|
||||||
}
|
}
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
/*# sourceMappingURL=index.css.map */
|
/*# sourceMappingURL=index.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"index.css"}
|
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"index.css"}
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 21em;
|
height: 21em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 20em;
|
height: 20em;
|
||||||
}
|
}
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
/*# sourceMappingURL=providers.css.map */
|
/*# sourceMappingURL=providers.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["providers.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"providers.css"}
|
{"version":3,"sources":["providers.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"providers.css"}
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
要想查看统计数据,需要先开启统计功能,<a :href="'/servers/server/settings/stat?serverId=' + serverId">[点击这里]</a>修改配置。
|
要想查看统计数据,需要先开启统计功能,<a :href="'/servers/server/settings/stat?serverId=' + serverId">[点击这里]</a>修改配置。
|
||||||
</p>
|
</p>
|
||||||
{$else}
|
{$else}
|
||||||
<h4>运营商排行</h4>
|
<h4>运营商排行<span class="small grey">(按月)</span></h4>
|
||||||
<div class="chart-box" id="provider-chart"></div>
|
<div class="chart-box" id="provider-chart"></div>
|
||||||
{$end}
|
{$end}
|
||||||
</div>
|
</div>
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 20em;
|
height: 20em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 20em;
|
height: 20em;
|
||||||
}
|
}
|
||||||
/*# sourceMappingURL=index.css.map */
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=regions.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"index.css"}
|
{"version":3,"sources":["regions.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"regions.css"}
|
||||||
@@ -12,17 +12,17 @@
|
|||||||
要想查看统计数据,需要先开启统计功能,<a :href="'/servers/server/settings/stat?serverId=' + serverId">[点击这里]</a>修改配置。
|
要想查看统计数据,需要先开启统计功能,<a :href="'/servers/server/settings/stat?serverId=' + serverId">[点击这里]</a>修改配置。
|
||||||
</p>
|
</p>
|
||||||
{$else}
|
{$else}
|
||||||
<h4>地区排行</h4>
|
<h4>地区排行<span class="small grey">(按月)</span></h4>
|
||||||
<div class="chart-box" id="country-chart">
|
<div class="chart-box" id="country-chart">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4>省市排行</h4>
|
<h4>省市排行<span class="small grey">(按月)</span></h4>
|
||||||
<div class="chart-box" id="province-chart">
|
<div class="chart-box" id="province-chart">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4>城市排行</h4>
|
<h4>城市排行<span class="small grey">(按月)</span></h4>
|
||||||
<div class="chart-box" id="city-chart">
|
<div class="chart-box" id="city-chart">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
.chart-box {
|
.chart-box {
|
||||||
height: 20em;
|
height: 20em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 span.small {
|
||||||
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user