diff --git a/build/configs/.gitignore b/build/configs/.gitignore index e7e34747..f839cc86 100644 --- a/build/configs/.gitignore +++ b/build/configs/.gitignore @@ -1,4 +1,5 @@ api.yaml server.yaml api_db.yaml -*.pem \ No newline at end of file +*.pem +tip.json \ No newline at end of file diff --git a/go.mod b/go.mod index 13eccfe2..7e07d604 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/cespare/xxhash v1.1.0 github.com/go-sql-driver/mysql v1.5.0 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/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f github.com/miekg/dns v1.1.35 @@ -20,5 +21,6 @@ require ( golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect google.golang.org/grpc v1.38.0 + google.golang.org/protobuf v1.26.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 ) diff --git a/internal/web/actions/default/servers/components/waf/ipadmin/lists.go b/internal/web/actions/default/servers/components/waf/ipadmin/lists.go index ac01eee1..d3e300bb 100644 --- a/internal/web/actions/default/servers/components/waf/ipadmin/lists.go +++ b/internal/web/actions/default/servers/components/waf/ipadmin/lists.go @@ -22,6 +22,7 @@ func (this *ListsAction) RunGet(params struct { Type string }) { this.Data["subMenuItem"] = params.Type + this.Data["type"] = params.Type listId, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyIPListIdWithType(this.AdminContext(), params.FirewallPolicyId, params.Type) if err != nil { diff --git a/internal/web/actions/default/servers/iplists/bindHTTPFirewallPopup.go b/internal/web/actions/default/servers/iplists/bindHTTPFirewallPopup.go new file mode 100644 index 00000000..2e8dd9b5 --- /dev/null +++ b/internal/web/actions/default/servers/iplists/bindHTTPFirewallPopup.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/createIPPopup.go b/internal/web/actions/default/servers/iplists/createIPPopup.go new file mode 100644 index 00000000..0f1e6479 --- /dev/null +++ b/internal/web/actions/default/servers/iplists/createIPPopup.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/createPopup.go b/internal/web/actions/default/servers/iplists/createPopup.go new file mode 100644 index 00000000..2365b1c6 --- /dev/null +++ b/internal/web/actions/default/servers/iplists/createPopup.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/delete.go b/internal/web/actions/default/servers/iplists/delete.go new file mode 100644 index 00000000..0f6ed18f --- /dev/null +++ b/internal/web/actions/default/servers/iplists/delete.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/deleteIP.go b/internal/web/actions/default/servers/iplists/deleteIP.go new file mode 100644 index 00000000..7730e2eb --- /dev/null +++ b/internal/web/actions/default/servers/iplists/deleteIP.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/export.go b/internal/web/actions/default/servers/iplists/export.go new file mode 100644 index 00000000..3cd96cff --- /dev/null +++ b/internal/web/actions/default/servers/iplists/export.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/exportData.go b/internal/web/actions/default/servers/iplists/exportData.go new file mode 100644 index 00000000..d0159877 --- /dev/null +++ b/internal/web/actions/default/servers/iplists/exportData.go @@ -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) +} diff --git a/internal/web/actions/default/servers/iplists/httpFirewall.go b/internal/web/actions/default/servers/iplists/httpFirewall.go new file mode 100644 index 00000000..511b5f90 --- /dev/null +++ b/internal/web/actions/default/servers/iplists/httpFirewall.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/import.go b/internal/web/actions/default/servers/iplists/import.go new file mode 100644 index 00000000..930114fa --- /dev/null +++ b/internal/web/actions/default/servers/iplists/import.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/index.go b/internal/web/actions/default/servers/iplists/index.go new file mode 100644 index 00000000..d0b72e55 --- /dev/null +++ b/internal/web/actions/default/servers/iplists/index.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/init.go b/internal/web/actions/default/servers/iplists/init.go new file mode 100644 index 00000000..62b1436e --- /dev/null +++ b/internal/web/actions/default/servers/iplists/init.go @@ -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() + }) +} diff --git a/internal/web/actions/default/servers/iplists/items.go b/internal/web/actions/default/servers/iplists/items.go new file mode 100644 index 00000000..b67d3af6 --- /dev/null +++ b/internal/web/actions/default/servers/iplists/items.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/list.go b/internal/web/actions/default/servers/iplists/list.go new file mode 100644 index 00000000..05e89ace --- /dev/null +++ b/internal/web/actions/default/servers/iplists/list.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/test.go b/internal/web/actions/default/servers/iplists/test.go new file mode 100644 index 00000000..cade249f --- /dev/null +++ b/internal/web/actions/default/servers/iplists/test.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/unbindHTTPFirewall.go b/internal/web/actions/default/servers/iplists/unbindHTTPFirewall.go new file mode 100644 index 00000000..dfff9d3d --- /dev/null +++ b/internal/web/actions/default/servers/iplists/unbindHTTPFirewall.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/update.go b/internal/web/actions/default/servers/iplists/update.go new file mode 100644 index 00000000..dcd40e59 --- /dev/null +++ b/internal/web/actions/default/servers/iplists/update.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/updateIPPopup.go b/internal/web/actions/default/servers/iplists/updateIPPopup.go new file mode 100644 index 00000000..8c4aff1c --- /dev/null +++ b/internal/web/actions/default/servers/iplists/updateIPPopup.go @@ -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() +} diff --git a/internal/web/actions/default/servers/iplists/utils.go b/internal/web/actions/default/servers/iplists/utils.go new file mode 100644 index 00000000..aabffa2d --- /dev/null +++ b/internal/web/actions/default/servers/iplists/utils.go @@ -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 +} diff --git a/internal/web/actions/default/ui/hideTip.go b/internal/web/actions/default/ui/hideTip.go new file mode 100644 index 00000000..5ca9681a --- /dev/null +++ b/internal/web/actions/default/ui/hideTip.go @@ -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() +} diff --git a/internal/web/actions/default/ui/init.go b/internal/web/actions/default/ui/init.go index 89f2111d..17fb1f7f 100644 --- a/internal/web/actions/default/ui/init.go +++ b/internal/web/actions/default/ui/init.go @@ -27,6 +27,8 @@ func init() { GetPost("/selectProvincesPopup", new(SelectProvincesPopupAction)). GetPost("/selectCountriesPopup", new(SelectCountriesPopupAction)). Post("/eventLevelOptions", new(EventLevelOptionsAction)). + Post("/showTip", new(ShowTipAction)). + Post("/hideTip", new(HideTipAction)). EndAll() }) diff --git a/internal/web/actions/default/ui/showTip.go b/internal/web/actions/default/ui/showTip.go new file mode 100644 index 00000000..24355d30 --- /dev/null +++ b/internal/web/actions/default/ui/showTip.go @@ -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() +} diff --git a/internal/web/helpers/user_must_auth.go b/internal/web/helpers/user_must_auth.go index 49d27bf5..0fe92b5c 100644 --- a/internal/web/helpers/user_must_auth.go +++ b/internal/web/helpers/user_must_auth.go @@ -167,6 +167,11 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map { "url": "/servers/components/waf", "code": "waf", }, + { + "name": "IP名单", + "url": "/servers/iplists", + "code": "iplist", + }, { "name": "证书管理", "url": "/servers/certs", diff --git a/internal/web/import.go b/internal/web/import.go index 72419d93..5ae82605 100644 --- a/internal/web/import.go +++ b/internal/web/import.go @@ -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/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/authority" diff --git a/web/public/js/components/common/tip-message-box.js b/web/public/js/components/common/tip-message-box.js new file mode 100644 index 00000000..bf5a14fd --- /dev/null +++ b/web/public/js/components/common/tip-message-box.js @@ -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: `
+ + +
+ +
+
` +}) \ No newline at end of file diff --git a/web/public/js/components/iplist/ip-list-bind-box.js b/web/public/js/components/iplist/ip-list-bind-box.js new file mode 100644 index 00000000..97203f8c --- /dev/null +++ b/web/public/js/components/iplist/ip-list-bind-box.js @@ -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: `
+ 绑定+   已绑定: +
+ {{list.name}} + +
+
` +}) \ No newline at end of file diff --git a/web/public/js/components/server/http-access-log-box.js b/web/public/js/components/server/http-access-log-box.js index ac239342..62b5e645 100644 --- a/web/public/js/components/server/http-access-log-box.js +++ b/web/public/js/components/server/http-access-log-box.js @@ -34,7 +34,7 @@ Vue.component("http-access-log-box", { this.select() teaweb.popup("/servers/server/log/viewPopup?requestId=" + requestId, { width: "50em", - height: "24em", + height: "28em", onClose: function () { that.deselect() } diff --git a/web/views/@default/@layout.css b/web/views/@default/@layout.css index 21890903..7ccfa5eb 100644 --- a/web/views/@default/@layout.css +++ b/web/views/@default/@layout.css @@ -197,9 +197,6 @@ p.margin { padding-top: 2em; padding-bottom: 2.4em; } - .main-menu .ui.menu .item span { - display: none; - } } .main-menu .ui.labeled.icon.menu .item { font-size: 0.9em; @@ -214,9 +211,19 @@ p.margin { margin-top: 0.5em; color: grey; } +@media screen and (max-width: 512px) { + .main-menu .ui.menu .item.expend .subtitle { + display: none; + } +} .main-menu .ui.menu .sub-items .item { 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 { background-color: #2185d0 !important; } diff --git a/web/views/@default/@layout.css.map b/web/views/@default/@layout.css.map index a04a42a6..6b5b0aee 100644 --- a/web/views/@default/@layout.css.map +++ b/web/views/@default/@layout.css.map @@ -1 +1 @@ -{"version":3,"sources":["@left_menu.less","@layout.less"],"names":[],"mappings":"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","file":"@layout.css"} \ No newline at end of file +{"version":3,"sources":["@left_menu.less","@layout.less"],"names":[],"mappings":"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","file":"@layout.css"} \ No newline at end of file diff --git a/web/views/@default/@layout.html b/web/views/@default/@layout.html index caf17b4c..8ae86d22 100644 --- a/web/views/@default/@layout.html +++ b/web/views/@default/@layout.html @@ -80,7 +80,7 @@ - {{module.name}} + {{module.name}}
{{module.subtitle}}
diff --git a/web/views/@default/@layout.less b/web/views/@default/@layout.less index 209466ae..e87dfa61 100644 --- a/web/views/@default/@layout.less +++ b/web/views/@default/@layout.less @@ -139,7 +139,7 @@ div.margin, p.margin { } .main-menu .ui.menu .item span { - display: none; + } } @@ -163,11 +163,23 @@ div.margin, p.margin { color: grey; } + @media screen and (max-width: 512px) { + .item.expend .subtitle { + display: none; + } + } + .sub-items { .item { padding-left: 2.8em !important; } + @media screen and (max-width: 512px) { + .item { + padding-left: 1em!important; + } + } + .item.active { background-color: #2185d0 !important; } diff --git a/web/views/@default/servers/components/waf/ipadmin/index.js b/web/views/@default/servers/components/waf/ipadmin/index.js index 450fcf99..4c67a251 100644 --- a/web/views/@default/servers/components/waf/ipadmin/index.js +++ b/web/views/@default/servers/components/waf/ipadmin/index.js @@ -56,10 +56,13 @@ Tea.context(function () { * 添加IP名单菜单 */ this.createIP = function (type) { + let that = this teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, { height: "23em", callback: function () { - window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type + teaweb.success("保存成功", function () { + window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type + }) } }) } diff --git a/web/views/@default/servers/components/waf/ipadmin/lists.html b/web/views/@default/servers/components/waf/ipadmin/lists.html index 4403bb2f..e20c4cdf 100644 --- a/web/views/@default/servers/components/waf/ipadmin/lists.html +++ b/web/views/@default/servers/components/waf/ipadmin/lists.html @@ -4,6 +4,8 @@ ID: {{listId}}   + | +

暂时还没有IP。

diff --git a/web/views/@default/servers/components/waf/ipadmin/lists.js b/web/views/@default/servers/components/waf/ipadmin/lists.js index 2919324b..8713af3a 100644 --- a/web/views/@default/servers/components/waf/ipadmin/lists.js +++ b/web/views/@default/servers/components/waf/ipadmin/lists.js @@ -26,10 +26,13 @@ Tea.context(function () { * 添加IP名单菜单 */ this.createIP = function (type) { + let that = this teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, { height: "26em", 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 + }) } }) } diff --git a/web/views/@default/servers/components/waf/ipadmin/provinces.js b/web/views/@default/servers/components/waf/ipadmin/provinces.js index 31eff506..7f3eb2fd 100644 --- a/web/views/@default/servers/components/waf/ipadmin/provinces.js +++ b/web/views/@default/servers/components/waf/ipadmin/provinces.js @@ -42,10 +42,13 @@ Tea.context(function () { * 添加IP名单菜单 */ this.createIP = function (type) { + let that = this teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, { height: "23em", callback: function () { - window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type + teaweb.success("保存成功", function () { + window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type + }) } }) } diff --git a/web/views/@default/servers/components/waf/ipadmin/test.js b/web/views/@default/servers/components/waf/ipadmin/test.js index 4d083e9b..55d7900f 100644 --- a/web/views/@default/servers/components/waf/ipadmin/test.js +++ b/web/views/@default/servers/components/waf/ipadmin/test.js @@ -1,47 +1,50 @@ Tea.context(function () { - this.ip = "" - this.result = { - isDone: false, - isOk: false, - isFound: false, - isAllowed: false, - error: "", - province: null, - country: null, - ipItem: null, - ipList: null - } + this.ip = "" + this.result = { + isDone: false, + isOk: false, + isFound: false, + isAllowed: false, + error: "", + province: null, + country: null, + ipItem: null, + ipList: null + } - this.$delay(function () { - this.$watch("ip", function () { - this.result.isDone = false - }) - }) + this.$delay(function () { + this.$watch("ip", function () { + this.result.isDone = false + }) + }) - this.success = function (resp) { - this.result = resp.data.result - } + this.success = function (resp) { + this.result = resp.data.result + } - this.updateItem = function (itemId) { - teaweb.popup(Tea.url(".updateIPPopup?firewallPolicyId=" + this.firewallPolicyId, {itemId: itemId}), { - height: "26em", - callback: function () { - teaweb.success("保存成功", function () { - teaweb.reload() - }) - } - }) - } + this.updateItem = function (itemId) { + teaweb.popup(Tea.url(".updateIPPopup?firewallPolicyId=" + this.firewallPolicyId, {itemId: itemId}), { + height: "26em", + callback: function () { + teaweb.success("保存成功", function () { + teaweb.reload() + }) + } + }) + } - /** - * 添加IP名单菜单 - */ - this.createIP = function (type) { - teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, { - height: "26em", - callback: function () { - window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type - } - }) - } + /** + * 添加IP名单菜单 + */ + this.createIP = function (type) { + let that = this + teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, { + height: "26em", + callback: function () { + teaweb.success("保存成功", function () { + window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type + }) + } + }) + } }) \ No newline at end of file diff --git a/web/views/@default/servers/iplists/@list_menu.html b/web/views/@default/servers/iplists/@list_menu.html new file mode 100644 index 00000000..b20d33a8 --- /dev/null +++ b/web/views/@default/servers/iplists/@list_menu.html @@ -0,0 +1,10 @@ + + {{list.typeName}} + | + "{{list.name}}"详情 + IP({{list.countItems}}) + 修改 + IP检查 + 导出 + 导入 + \ No newline at end of file diff --git a/web/views/@default/servers/iplists/@menu.html b/web/views/@default/servers/iplists/@menu.html new file mode 100644 index 00000000..d40f58eb --- /dev/null +++ b/web/views/@default/servers/iplists/@menu.html @@ -0,0 +1,8 @@ + + 黑名单 + 白名单 + | + [创建] + | + + \ No newline at end of file diff --git a/web/views/@default/servers/iplists/bindHTTPFirewallPopup.html b/web/views/@default/servers/iplists/bindHTTPFirewallPopup.html new file mode 100644 index 00000000..083977b1 --- /dev/null +++ b/web/views/@default/servers/iplists/bindHTTPFirewallPopup.html @@ -0,0 +1,38 @@ +{$layout "layout_popup"} + +

绑定公用IP名单

+ + +

暂时还没有可用的公用IP名单。

+ + + + + + + + + + + + + + + + + + + + +
ID名称类型备注IP数量操作
{{list.id}}{{list.name}} + 黑名单 + 白名单 + {{list.description}} + {{list.countItems}} + 0 + + 绑定 + 已绑定 +
+ +
\ No newline at end of file diff --git a/web/views/@default/servers/iplists/bindHTTPFirewallPopup.js b/web/views/@default/servers/iplists/bindHTTPFirewallPopup.js new file mode 100644 index 00000000..06a79b91 --- /dev/null +++ b/web/views/@default/servers/iplists/bindHTTPFirewallPopup.js @@ -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 + }) + } +}) \ No newline at end of file diff --git a/web/views/@default/servers/iplists/createIPPopup.html b/web/views/@default/servers/iplists/createIPPopup.html new file mode 100644 index 00000000..bb9e6901 --- /dev/null +++ b/web/views/@default/servers/iplists/createIPPopup.html @@ -0,0 +1,76 @@ +{$layout "layout_popup"} + +

添加IP

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
类型 * + +

单个IPv4或一个IPv4范围。

+

单个IPv6。

+

允许或禁用所有的IP。

+
开始IP * + +
结束IP + +

表示IP段的时候需要填写此项。

+
IP * + +

IPv6地址,比如 1406:3c00:0:2409:13:58:103:15

+
级别 + +
过期时间 + +

在加入名单某一段时间后会失效,留空表示永久有效。

+
备注
+ +
\ No newline at end of file diff --git a/web/views/@default/servers/iplists/createIPPopup.js b/web/views/@default/servers/iplists/createIPPopup.js new file mode 100644 index 00000000..cf56518b --- /dev/null +++ b/web/views/@default/servers/iplists/createIPPopup.js @@ -0,0 +1,4 @@ +Tea.context(function () { + this.type = "ipv4" + this.eventLevel = (this.listType == "white") ? "debug" : "critical" +}) \ No newline at end of file diff --git a/web/views/@default/servers/iplists/createPopup.css b/web/views/@default/servers/iplists/createPopup.css new file mode 100644 index 00000000..a5698255 --- /dev/null +++ b/web/views/@default/servers/iplists/createPopup.css @@ -0,0 +1,4 @@ +h3 var { + font-style: normal; +} +/*# sourceMappingURL=createPopup.css.map */ \ No newline at end of file diff --git a/web/views/@default/servers/iplists/createPopup.css.map b/web/views/@default/servers/iplists/createPopup.css.map new file mode 100644 index 00000000..6a762c47 --- /dev/null +++ b/web/views/@default/servers/iplists/createPopup.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["createPopup.less"],"names":[],"mappings":"AAAA,EACC;EACC,kBAAA","file":"createPopup.css"} \ No newline at end of file diff --git a/web/views/@default/servers/iplists/createPopup.html b/web/views/@default/servers/iplists/createPopup.html new file mode 100644 index 00000000..ca3ed2e8 --- /dev/null +++ b/web/views/@default/servers/iplists/createPopup.html @@ -0,0 +1,31 @@ +{$layout "layout_popup"} + +

创建黑名单白名单

+ +
+ + + + + + + + + + + + + + +
名称 * + +
类型 + +
备注 + +
+ +
\ No newline at end of file diff --git a/web/views/@default/servers/iplists/createPopup.less b/web/views/@default/servers/iplists/createPopup.less new file mode 100644 index 00000000..562afb12 --- /dev/null +++ b/web/views/@default/servers/iplists/createPopup.less @@ -0,0 +1,5 @@ +h3 { + var { + font-style: normal; + } +} \ No newline at end of file diff --git a/web/views/@default/servers/iplists/export.html b/web/views/@default/servers/iplists/export.html new file mode 100644 index 00000000..816fb722 --- /dev/null +++ b/web/views/@default/servers/iplists/export.html @@ -0,0 +1,13 @@ +{$layout} +{$template "list_menu"} + +
+
+ + + + + +
说明导出所有的IP
+ 导出 +
\ No newline at end of file diff --git a/web/views/@default/servers/iplists/import.html b/web/views/@default/servers/iplists/import.html new file mode 100644 index 00000000..c3b86cc9 --- /dev/null +++ b/web/views/@default/servers/iplists/import.html @@ -0,0 +1,19 @@ +{$layout} +{$template "list_menu"} + +
+ +
+ + + + + + + +
选择IP文件 * + +

文件名类似于ip-list-123.data

+
+ +
\ No newline at end of file diff --git a/web/views/@default/servers/iplists/import.js b/web/views/@default/servers/iplists/import.js new file mode 100644 index 00000000..9c911bd9 --- /dev/null +++ b/web/views/@default/servers/iplists/import.js @@ -0,0 +1,7 @@ +Tea.context(function () { + this.success = function (resp) { + teaweb.success("成功导入" + resp.data.count + "个IP", function () { + teaweb.reload() + }) + } +}) \ No newline at end of file diff --git a/web/views/@default/servers/iplists/index.html b/web/views/@default/servers/iplists/index.html new file mode 100644 index 00000000..8e56e425 --- /dev/null +++ b/web/views/@default/servers/iplists/index.html @@ -0,0 +1,38 @@ +{$layout} +{$template "menu"} + +这里是公用的IP名单,可以在WAF策略里直接引用。 + +

暂时还没有公用IP名单。

+ + + + + + + + + + + + + + + + + + + + +
ID名称类型备注IP数量操作
{{list.id}}{{list.name}} + 黑名单 + 白名单 + {{list.description}} + {{list.countItems}} + 0 + + 详情   + 删除 +
+ +
\ No newline at end of file diff --git a/web/views/@default/servers/iplists/index.js b/web/views/@default/servers/iplists/index.js new file mode 100644 index 00000000..59f57130 --- /dev/null +++ b/web/views/@default/servers/iplists/index.js @@ -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() + }) + }) + }) + } +}) \ No newline at end of file diff --git a/web/views/@default/servers/iplists/items.html b/web/views/@default/servers/iplists/items.html new file mode 100644 index 00000000..c7492ba3 --- /dev/null +++ b/web/views/@default/servers/iplists/items.html @@ -0,0 +1,12 @@ +{$layout} +{$template "list_menu"} + + + [创建IP] + + +

暂时还没有IP。

+ + + +
\ No newline at end of file diff --git a/web/views/@default/servers/iplists/items.js b/web/views/@default/servers/iplists/items.js new file mode 100644 index 00000000..a25d5be7 --- /dev/null +++ b/web/views/@default/servers/iplists/items.js @@ -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() + }) + } + }) + } +}) \ No newline at end of file diff --git a/web/views/@default/servers/iplists/list.html b/web/views/@default/servers/iplists/list.html new file mode 100644 index 00000000..12663699 --- /dev/null +++ b/web/views/@default/servers/iplists/list.html @@ -0,0 +1,24 @@ +{$layout} +{$template "list_menu"} + + + + + + + + + + + + + + +
名称 + {{list.name}} +
类型 + {{list.typeName}} +
备注 + {{list.description}} + - +
\ No newline at end of file diff --git a/web/views/@default/servers/iplists/test.html b/web/views/@default/servers/iplists/test.html new file mode 100644 index 00000000..ff9d9798 --- /dev/null +++ b/web/views/@default/servers/iplists/test.html @@ -0,0 +1,39 @@ +{$layout} +{$template "list_menu"} +
+ + + + + + + + + + + +
IP * + +

要检查的IP

+
检查结果 +
+
+ {{result.error}} +
+
+
+
+ 在白名单中   +
+
+ 在黑名单中   +
+
+
+
+ 没有找到和{{ip}}匹配的配置。 +
+
+
+ 检查IP状态 +
\ No newline at end of file diff --git a/web/views/@default/servers/iplists/test.js b/web/views/@default/servers/iplists/test.js new file mode 100644 index 00000000..9b49d937 --- /dev/null +++ b/web/views/@default/servers/iplists/test.js @@ -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() + }) + } + }) + } +}) \ No newline at end of file diff --git a/web/views/@default/servers/iplists/update.html b/web/views/@default/servers/iplists/update.html new file mode 100644 index 00000000..9690ba17 --- /dev/null +++ b/web/views/@default/servers/iplists/update.html @@ -0,0 +1,28 @@ +{$layout} +{$template "list_menu"} + +
+ + + + + + + + + + + + + + + +
名称 * + +
类型 + {{list.typeName}} +
备注 + +
+ +
\ No newline at end of file diff --git a/web/views/@default/servers/iplists/update.js b/web/views/@default/servers/iplists/update.js new file mode 100644 index 00000000..295a9aaf --- /dev/null +++ b/web/views/@default/servers/iplists/update.js @@ -0,0 +1,3 @@ +Tea.context(function () { + this.success = NotifyReloadSuccess("保存成功") +}) \ No newline at end of file diff --git a/web/views/@default/servers/iplists/updateIPPopup.html b/web/views/@default/servers/iplists/updateIPPopup.html new file mode 100644 index 00000000..96f93695 --- /dev/null +++ b/web/views/@default/servers/iplists/updateIPPopup.html @@ -0,0 +1,76 @@ +{$layout "layout_popup"} + +

修改IP

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
类型 * + + IPv4 + IPv6 + 所有IP + +

单个IPv4或一个IPv4范围。

+

单个IPv6。

+

允许或禁用所有的IP。

+
开始IP * + +
结束IP + +

表示IP段的时候需要填写此项。

+
级别 + +
IP * + +

IPv6地址,比如 1406:3c00:0:2409:13:58:103:15

+
过期时间 + +

在加入名单某一段时间后会失效,留空表示永久有效。

+
备注
+ +
\ No newline at end of file diff --git a/web/views/@default/servers/server/settings/waf/ipadmin/allowList.html b/web/views/@default/servers/server/settings/waf/ipadmin/allowList.html index 227567bf..b7a071e6 100644 --- a/web/views/@default/servers/server/settings/waf/ipadmin/allowList.html +++ b/web/views/@default/servers/server/settings/waf/ipadmin/allowList.html @@ -11,6 +11,8 @@ 添加IP | ID: {{listId}}   + | +

当前WAF未启用,设置将在[启用]后生效。

diff --git a/web/views/@default/servers/server/settings/waf/ipadmin/allowList.js b/web/views/@default/servers/server/settings/waf/ipadmin/allowList.js index 69eb2cd6..5b51e718 100644 --- a/web/views/@default/servers/server/settings/waf/ipadmin/allowList.js +++ b/web/views/@default/servers/server/settings/waf/ipadmin/allowList.js @@ -29,7 +29,9 @@ Tea.context(function () { teaweb.popup("/servers/server/settings/waf/ipadmin/createIPPopup?listId=" + this.listId + '&type=' + type, { height: "26em", callback: function () { - window.location.reload() + teaweb.success("保存成功", function () { + teaweb.reload() + }) } }) } diff --git a/web/views/@default/servers/server/settings/waf/ipadmin/countries.js b/web/views/@default/servers/server/settings/waf/ipadmin/countries.js index 930a7a44..01c395d7 100644 --- a/web/views/@default/servers/server/settings/waf/ipadmin/countries.js +++ b/web/views/@default/servers/server/settings/waf/ipadmin/countries.js @@ -56,10 +56,13 @@ Tea.context(function () { * 添加IP名单菜单 */ this.createIP = function (type) { + let that = this teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, { height: "30em", 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 + }) } }) } diff --git a/web/views/@default/servers/server/settings/waf/ipadmin/denyList.html b/web/views/@default/servers/server/settings/waf/ipadmin/denyList.html index 64748c35..1b89c431 100644 --- a/web/views/@default/servers/server/settings/waf/ipadmin/denyList.html +++ b/web/views/@default/servers/server/settings/waf/ipadmin/denyList.html @@ -11,6 +11,8 @@ 添加IP | ID: {{listId}}   + | +

当前WAF未启用,设置将在[启用]后生效。

diff --git a/web/views/@default/servers/server/settings/waf/ipadmin/denyList.js b/web/views/@default/servers/server/settings/waf/ipadmin/denyList.js index 69eb2cd6..5b51e718 100644 --- a/web/views/@default/servers/server/settings/waf/ipadmin/denyList.js +++ b/web/views/@default/servers/server/settings/waf/ipadmin/denyList.js @@ -29,7 +29,9 @@ Tea.context(function () { teaweb.popup("/servers/server/settings/waf/ipadmin/createIPPopup?listId=" + this.listId + '&type=' + type, { height: "26em", callback: function () { - window.location.reload() + teaweb.success("保存成功", function () { + teaweb.reload() + }) } }) } diff --git a/web/views/@default/servers/server/settings/waf/ipadmin/provinces.js b/web/views/@default/servers/server/settings/waf/ipadmin/provinces.js index ea0ae250..1927a0bb 100644 --- a/web/views/@default/servers/server/settings/waf/ipadmin/provinces.js +++ b/web/views/@default/servers/server/settings/waf/ipadmin/provinces.js @@ -42,10 +42,13 @@ Tea.context(function () { * 添加IP名单菜单 */ this.createIP = function (type) { + let that = this teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, { height: "30em", 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 + }) } }) } diff --git a/web/views/@default/servers/server/stat/clients.css b/web/views/@default/servers/server/stat/clients.css index 933bb2da..3950346a 100644 --- a/web/views/@default/servers/server/stat/clients.css +++ b/web/views/@default/servers/server/stat/clients.css @@ -1,4 +1,7 @@ .chart-box { height: 20em; } +h4 span.small { + font-size: 0.8em; +} /*# sourceMappingURL=clients.css.map */ \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/clients.css.map b/web/views/@default/servers/server/stat/clients.css.map index 3b35a86a..9c0dbe46 100644 --- a/web/views/@default/servers/server/stat/clients.css.map +++ b/web/views/@default/servers/server/stat/clients.css.map @@ -1 +1 @@ -{"version":3,"sources":["clients.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"clients.css"} \ No newline at end of file +{"version":3,"sources":["clients.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"clients.css"} \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/clients.html b/web/views/@default/servers/server/stat/clients.html index 79d934e7..d75001c7 100644 --- a/web/views/@default/servers/server/stat/clients.html +++ b/web/views/@default/servers/server/stat/clients.html @@ -12,10 +12,10 @@ 要想查看统计数据,需要先开启统计功能,[点击这里]修改配置。

{$else} -

操作系统排行

+

操作系统排行(按月)

-

浏览器排行

+

浏览器排行(按月)

{$end} \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/clients.less b/web/views/@default/servers/server/stat/clients.less index bed0b0ae..4be79844 100644 --- a/web/views/@default/servers/server/stat/clients.less +++ b/web/views/@default/servers/server/stat/clients.less @@ -1,3 +1,7 @@ .chart-box { height: 20em; +} + +h4 span.small { + font-size: 0.8em; } \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/dailyRequests.css b/web/views/@default/servers/server/stat/dailyRequests.css index 6f542920..b8866585 100644 --- a/web/views/@default/servers/server/stat/dailyRequests.css +++ b/web/views/@default/servers/server/stat/dailyRequests.css @@ -1,4 +1,7 @@ .chart-box { height: 21em; } +h4 span.small { + font-size: 0.8em; +} /*# sourceMappingURL=dailyRequests.css.map */ \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/dailyRequests.css.map b/web/views/@default/servers/server/stat/dailyRequests.css.map index 63b04196..6035c241 100644 --- a/web/views/@default/servers/server/stat/dailyRequests.css.map +++ b/web/views/@default/servers/server/stat/dailyRequests.css.map @@ -1 +1 @@ -{"version":3,"sources":["dailyRequests.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"dailyRequests.css"} \ No newline at end of file +{"version":3,"sources":["dailyRequests.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"dailyRequests.css"} \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/dailyRequests.less b/web/views/@default/servers/server/stat/dailyRequests.less index b66f238c..833d52f5 100644 --- a/web/views/@default/servers/server/stat/dailyRequests.less +++ b/web/views/@default/servers/server/stat/dailyRequests.less @@ -1,3 +1,7 @@ .chart-box { height: 21em; +} + +h4 span.small { + font-size: 0.8em; } \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/hourlyRequests.css b/web/views/@default/servers/server/stat/hourlyRequests.css index 1542b847..7f389e0e 100644 --- a/web/views/@default/servers/server/stat/hourlyRequests.css +++ b/web/views/@default/servers/server/stat/hourlyRequests.css @@ -1,4 +1,7 @@ .chart-box { height: 21em; } +h4 span.small { + font-size: 0.8em; +} /*# sourceMappingURL=hourlyRequests.css.map */ \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/hourlyRequests.css.map b/web/views/@default/servers/server/stat/hourlyRequests.css.map index 23d2fc46..8336ad9b 100644 --- a/web/views/@default/servers/server/stat/hourlyRequests.css.map +++ b/web/views/@default/servers/server/stat/hourlyRequests.css.map @@ -1 +1 @@ -{"version":3,"sources":["hourlyRequests.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"hourlyRequests.css"} \ No newline at end of file +{"version":3,"sources":["hourlyRequests.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"hourlyRequests.css"} \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/hourlyRequests.less b/web/views/@default/servers/server/stat/hourlyRequests.less index b66f238c..833d52f5 100644 --- a/web/views/@default/servers/server/stat/hourlyRequests.less +++ b/web/views/@default/servers/server/stat/hourlyRequests.less @@ -1,3 +1,7 @@ .chart-box { height: 21em; +} + +h4 span.small { + font-size: 0.8em; } \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/index.css b/web/views/@default/servers/server/stat/index.css index 35958bdb..0414eb18 100644 --- a/web/views/@default/servers/server/stat/index.css +++ b/web/views/@default/servers/server/stat/index.css @@ -1,4 +1,7 @@ .chart-box { height: 21em; } +h4 span.small { + font-size: 0.8em; +} /*# sourceMappingURL=index.css.map */ \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/index.css.map b/web/views/@default/servers/server/stat/index.css.map index 8c66954e..77e183ce 100644 --- a/web/views/@default/servers/server/stat/index.css.map +++ b/web/views/@default/servers/server/stat/index.css.map @@ -1 +1 @@ -{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"index.css"} \ No newline at end of file +{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"index.css"} \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/index.less b/web/views/@default/servers/server/stat/index.less index b66f238c..833d52f5 100644 --- a/web/views/@default/servers/server/stat/index.less +++ b/web/views/@default/servers/server/stat/index.less @@ -1,3 +1,7 @@ .chart-box { height: 21em; +} + +h4 span.small { + font-size: 0.8em; } \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/providers.css b/web/views/@default/servers/server/stat/providers.css index 6bd265a1..d3c7d5f0 100644 --- a/web/views/@default/servers/server/stat/providers.css +++ b/web/views/@default/servers/server/stat/providers.css @@ -1,4 +1,7 @@ .chart-box { height: 20em; } +h4 span.small { + font-size: 0.8em; +} /*# sourceMappingURL=providers.css.map */ \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/providers.css.map b/web/views/@default/servers/server/stat/providers.css.map index 8f48bbe0..98521dba 100644 --- a/web/views/@default/servers/server/stat/providers.css.map +++ b/web/views/@default/servers/server/stat/providers.css.map @@ -1 +1 @@ -{"version":3,"sources":["providers.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"providers.css"} \ No newline at end of file +{"version":3,"sources":["providers.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"providers.css"} \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/providers.html b/web/views/@default/servers/server/stat/providers.html index fef3db9a..b26cb358 100644 --- a/web/views/@default/servers/server/stat/providers.html +++ b/web/views/@default/servers/server/stat/providers.html @@ -12,7 +12,7 @@ 要想查看统计数据,需要先开启统计功能,[点击这里]修改配置。

{$else} -

运营商排行

+

运营商排行(按月)

{$end} \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/providers.less b/web/views/@default/servers/server/stat/providers.less index bed0b0ae..4be79844 100644 --- a/web/views/@default/servers/server/stat/providers.less +++ b/web/views/@default/servers/server/stat/providers.less @@ -1,3 +1,7 @@ .chart-box { height: 20em; +} + +h4 span.small { + font-size: 0.8em; } \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/regions.css b/web/views/@default/servers/server/stat/regions.css index 3007cba5..041b6176 100644 --- a/web/views/@default/servers/server/stat/regions.css +++ b/web/views/@default/servers/server/stat/regions.css @@ -1,4 +1,7 @@ .chart-box { height: 20em; } -/*# sourceMappingURL=index.css.map */ \ No newline at end of file +h4 span.small { + font-size: 0.8em; +} +/*# sourceMappingURL=regions.css.map */ \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/regions.css.map b/web/views/@default/servers/server/stat/regions.css.map index 8c66954e..ae184d01 100644 --- a/web/views/@default/servers/server/stat/regions.css.map +++ b/web/views/@default/servers/server/stat/regions.css.map @@ -1 +1 @@ -{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"index.css"} \ No newline at end of file +{"version":3,"sources":["regions.less"],"names":[],"mappings":"AAAA;EACC,YAAA;;AAGD,EAAG,KAAI;EACN,gBAAA","file":"regions.css"} \ No newline at end of file diff --git a/web/views/@default/servers/server/stat/regions.html b/web/views/@default/servers/server/stat/regions.html index 4116bc50..a89a1b0d 100644 --- a/web/views/@default/servers/server/stat/regions.html +++ b/web/views/@default/servers/server/stat/regions.html @@ -12,17 +12,17 @@ 要想查看统计数据,需要先开启统计功能,[点击这里]修改配置。

{$else} -

地区排行

+

地区排行(按月)

-

省市排行

+

省市排行(按月)

-

城市排行

+

城市排行(按月)

diff --git a/web/views/@default/servers/server/stat/regions.less b/web/views/@default/servers/server/stat/regions.less index bed0b0ae..4be79844 100644 --- a/web/views/@default/servers/server/stat/regions.less +++ b/web/views/@default/servers/server/stat/regions.less @@ -1,3 +1,7 @@ .chart-box { height: 20em; +} + +h4 span.small { + font-size: 0.8em; } \ No newline at end of file