1.4.5.2
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/cmd"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
this.Data["types"] = serverconfigs.FindAllAccessLogStorageTypes()
|
||||
this.Data["syslogPriorities"] = serverconfigs.AccessLogSyslogStoragePriorities
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
Type string
|
||||
|
||||
// file
|
||||
FilePath string
|
||||
FileAutoCreate bool
|
||||
|
||||
// es
|
||||
EsEndpoint string
|
||||
EsIndex string
|
||||
EsIsDataStream bool
|
||||
EsMappingType string
|
||||
EsUsername string
|
||||
EsPassword string
|
||||
|
||||
// mysql
|
||||
MysqlHost string
|
||||
MysqlPort int
|
||||
MysqlUsername string
|
||||
MysqlPassword string
|
||||
MysqlDatabase string
|
||||
MysqlTable string
|
||||
MysqlLogField string
|
||||
|
||||
// tcp
|
||||
TcpNetwork string
|
||||
TcpAddr string
|
||||
|
||||
// syslog
|
||||
SyslogProtocol string
|
||||
SyslogServerAddr string
|
||||
SyslogServerPort int
|
||||
SyslogSocket string
|
||||
SyslogTag string
|
||||
SyslogPriority int
|
||||
|
||||
// command
|
||||
CommandCommand string
|
||||
CommandArgs string
|
||||
CommandDir string
|
||||
|
||||
IsPublic bool
|
||||
FirewallOnly bool
|
||||
DisableDefaultDB bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var policyId int64 = 0
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.HTTPAccessLogPolicy_LogCreateHTTPAccessLogPolicy, policyId)
|
||||
}()
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入日志策略的名称").
|
||||
Field("type", params.Type).
|
||||
Require("请选择存储类型")
|
||||
|
||||
var options any = nil
|
||||
switch params.Type {
|
||||
case serverconfigs.AccessLogStorageTypeFile:
|
||||
params.Must.
|
||||
Field("filePath", params.FilePath).
|
||||
Require("请输入日志文件路径")
|
||||
|
||||
var storage = new(serverconfigs.AccessLogFileStorageConfig)
|
||||
storage.Path = params.FilePath
|
||||
storage.AutoCreate = params.FileAutoCreate
|
||||
options = storage
|
||||
case serverconfigs.AccessLogStorageTypeES:
|
||||
params.Must.
|
||||
Field("esEndpoint", params.EsEndpoint).
|
||||
Require("请输入Endpoint").
|
||||
Field("esIndex", params.EsIndex).
|
||||
Require("请输入Index名称")
|
||||
if !params.EsIsDataStream {
|
||||
params.Must.
|
||||
Field("esMappingType", params.EsMappingType).
|
||||
Require("请输入Mapping名称")
|
||||
}
|
||||
|
||||
var storage = new(serverconfigs.AccessLogESStorageConfig)
|
||||
storage.Endpoint = params.EsEndpoint
|
||||
storage.Index = params.EsIndex
|
||||
storage.IsDataStream = params.EsIsDataStream
|
||||
storage.MappingType = params.EsMappingType
|
||||
storage.Username = params.EsUsername
|
||||
storage.Password = params.EsPassword
|
||||
options = storage
|
||||
case serverconfigs.AccessLogStorageTypeTCP:
|
||||
params.Must.
|
||||
Field("tcpNetwork", params.TcpNetwork).
|
||||
Require("请选择网络协议").
|
||||
Field("tcpAddr", params.TcpAddr).
|
||||
Require("请输入网络地址")
|
||||
|
||||
var storage = new(serverconfigs.AccessLogTCPStorageConfig)
|
||||
storage.Network = params.TcpNetwork
|
||||
storage.Addr = params.TcpAddr
|
||||
options = storage
|
||||
case serverconfigs.AccessLogStorageTypeSyslog:
|
||||
switch params.SyslogProtocol {
|
||||
case serverconfigs.AccessLogSyslogStorageProtocolTCP, serverconfigs.AccessLogSyslogStorageProtocolUDP:
|
||||
params.Must.
|
||||
Field("syslogServerAddr", params.SyslogServerAddr).
|
||||
Require("请输入网络地址")
|
||||
case serverconfigs.AccessLogSyslogStorageProtocolSocket:
|
||||
params.Must.
|
||||
Field("syslogSocket", params.SyslogSocket).
|
||||
Require("请输入Socket路径")
|
||||
}
|
||||
|
||||
var storage = new(serverconfigs.AccessLogSyslogStorageConfig)
|
||||
storage.Protocol = params.SyslogProtocol
|
||||
storage.ServerAddr = params.SyslogServerAddr
|
||||
storage.ServerPort = params.SyslogServerPort
|
||||
storage.Socket = params.SyslogSocket
|
||||
storage.Tag = params.SyslogTag
|
||||
storage.Priority = params.SyslogPriority
|
||||
options = storage
|
||||
case serverconfigs.AccessLogStorageTypeCommand:
|
||||
params.Must.
|
||||
Field("commandCommand", params.CommandCommand).
|
||||
Require("请输入可执行命令")
|
||||
|
||||
var storage = new(serverconfigs.AccessLogCommandStorageConfig)
|
||||
storage.Command = params.CommandCommand
|
||||
storage.Args = cmd.ParseArgs(params.CommandArgs)
|
||||
storage.Dir = params.CommandDir
|
||||
options = storage
|
||||
}
|
||||
|
||||
if options == nil {
|
||||
this.Fail("找不到选择的存储类型")
|
||||
}
|
||||
|
||||
optionsJSON, err := json.Marshal(options)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
createResp, err := this.RPC().HTTPAccessLogPolicyRPC().CreateHTTPAccessLogPolicy(this.AdminContext(), &pb.CreateHTTPAccessLogPolicyRequest{
|
||||
Name: params.Name,
|
||||
Type: params.Type,
|
||||
OptionsJSON: optionsJSON,
|
||||
CondsJSON: nil, // TODO
|
||||
IsPublic: params.IsPublic,
|
||||
FirewallOnly: params.FirewallOnly,
|
||||
DisableDefaultDB: params.DisableDefaultDB,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
policyId = createResp.HttpAccessLogPolicyId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
PolicyId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.HTTPAccessLogPolicy_LogDeleteHTTPAccessLogPolicy, params.PolicyId)
|
||||
|
||||
_, err := this.RPC().HTTPAccessLogPolicyRPC().DeleteHTTPAccessLogPolicy(this.AdminContext(), &pb.DeleteHTTPAccessLogPolicyRequest{HttpAccessLogPolicyId: params.PolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().HTTPAccessLogPolicyRPC().CountAllHTTPAccessLogPolicies(this.AdminContext(), &pb.CountAllHTTPAccessLogPoliciesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var page = this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
policiesResp, err := this.RPC().HTTPAccessLogPolicyRPC().ListHTTPAccessLogPolicies(this.AdminContext(), &pb.ListHTTPAccessLogPoliciesRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var policyMaps = []maps.Map{}
|
||||
for _, policy := range policiesResp.HttpAccessLogPolicies {
|
||||
var optionsMap = maps.Map{}
|
||||
if len(policy.OptionsJSON) > 0 {
|
||||
err = json.Unmarshal(policy.OptionsJSON, &optionsMap)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
policyMaps = append(policyMaps, maps.Map{
|
||||
"id": policy.Id,
|
||||
"name": policy.Name,
|
||||
"type": policy.Type,
|
||||
"typeName": serverconfigs.FindAccessLogStorageTypeName(policy.Type),
|
||||
"isOn": policy.IsOn,
|
||||
"isPublic": policy.IsPublic,
|
||||
"firewallOnly": policy.FirewallOnly,
|
||||
"disableDefaultDB": policy.DisableDefaultDB,
|
||||
"options": optionsMap,
|
||||
})
|
||||
}
|
||||
this.Data["policies"] = policyMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/plus"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(plus.NewHelper(plus.ComponentCodeLog)).
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
|
||||
Prefix("/servers/accesslogs").
|
||||
Data("teaMenu", "servers").
|
||||
Data("teaSubMenu", "accesslog").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
Get("/policy", new(PolicyAction)).
|
||||
GetPost("/test", new(TestAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/accesslogs/policyutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
)
|
||||
|
||||
type PolicyAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *PolicyAction) Init() {
|
||||
this.Nav("", "", "policy")
|
||||
}
|
||||
|
||||
func (this *PolicyAction) RunGet(params struct {
|
||||
PolicyId int64
|
||||
}) {
|
||||
err := policyutils.InitPolicy(this.Parent(), params.PolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var policyMap = this.Data.GetMap("policy")
|
||||
if policyMap.GetString("type") == serverconfigs.AccessLogStorageTypeSyslog {
|
||||
this.Data["syslogPriorityName"] = serverconfigs.FindAccessLogSyslogStoragePriorityName(policyMap.GetMap("options").GetInt("priority"))
|
||||
} else {
|
||||
this.Data["syslogPriorityName"] = ""
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package policyutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
// InitPolicy 初始化访问日志策略
|
||||
func InitPolicy(parent *actionutils.ParentAction, policyId int64) error {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
policyResp, err := rpcClient.HTTPAccessLogPolicyRPC().FindHTTPAccessLogPolicy(parent.AdminContext(), &pb.FindHTTPAccessLogPolicyRequest{HttpAccessLogPolicyId: policyId})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var policy = policyResp.HttpAccessLogPolicy
|
||||
if policy == nil {
|
||||
return errors.New("can not find policy '" + types.String(policyId) + "'")
|
||||
}
|
||||
|
||||
var options = maps.Map{}
|
||||
if len(policy.OptionsJSON) > 0 {
|
||||
err = json.Unmarshal(policy.OptionsJSON, &options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
parent.Data["policy"] = maps.Map{
|
||||
"id": policy.Id,
|
||||
"name": policy.Name,
|
||||
"type": policy.Type,
|
||||
"typeName": serverconfigs.FindAccessLogStorageTypeName(policy.Type),
|
||||
"isOn": policy.IsOn,
|
||||
"isPublic": policy.IsPublic,
|
||||
"firewallOnly": policy.FirewallOnly,
|
||||
"disableDefaultDB": policy.DisableDefaultDB,
|
||||
"options": options,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/accesslogs/policyutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) Init() {
|
||||
this.Nav("", "", "test")
|
||||
}
|
||||
|
||||
func (this *TestAction) RunGet(params struct {
|
||||
PolicyId int64
|
||||
}) {
|
||||
err := policyutils.InitPolicy(this.Parent(), params.PolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var now = time.Now()
|
||||
|
||||
var uri = "/doc.html"
|
||||
testJSON, err := json.MarshalIndent(&pb.HTTPAccessLog{
|
||||
RequestId: types.String(time.Now().UnixMilli()) + "1" + strconv.Itoa(1),
|
||||
UserAgent: this.Request.UserAgent(),
|
||||
Request: "GET " + uri + " HTTP/1.1",
|
||||
RequestPath: uri,
|
||||
Referer: "https://example.com/",
|
||||
RemoteAddr: "8.8.8.8",
|
||||
Timestamp: now.Unix(),
|
||||
TimeISO8601: now.Format("2006-01-02T15:04:05.000Z07:00"),
|
||||
TimeLocal: now.Format("2/Jan/2006:15:04:05 -0700"),
|
||||
}, "", " ")
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["testJSON"] = string(testJSON)
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
PolicyId int64
|
||||
BodyJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.HTTPAccessLogPolicy_LogTestHTTPAccessLogPolicy, params.PolicyId)
|
||||
|
||||
var accessLog = &pb.HTTPAccessLog{}
|
||||
err := json.Unmarshal(params.BodyJSON, accessLog)
|
||||
if err != nil {
|
||||
this.Fail("发送内容不是有效的JSON:" + err.Error())
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPAccessLogPolicyRPC().WriteHTTPAccessLogPolicy(this.AdminContext(), &pb.WriteHTTPAccessLogPolicyRequest{
|
||||
HttpAccessLogPolicyId: params.PolicyId,
|
||||
HttpAccessLog: accessLog,
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("发送失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/accesslogs/policyutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/cmd"
|
||||
)
|
||||
|
||||
type UpdateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunGet(params struct {
|
||||
PolicyId int64
|
||||
}) {
|
||||
err := policyutils.InitPolicy(this.Parent(), params.PolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["types"] = serverconfigs.FindAllAccessLogStorageTypes()
|
||||
this.Data["syslogPriorities"] = serverconfigs.AccessLogSyslogStoragePriorities
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
PolicyId int64
|
||||
Name string
|
||||
|
||||
// file
|
||||
FilePath string
|
||||
FileAutoCreate bool
|
||||
|
||||
// es
|
||||
EsEndpoint string
|
||||
EsIndex string
|
||||
EsIsDataStream bool
|
||||
EsMappingType string
|
||||
EsUsername string
|
||||
EsPassword string
|
||||
|
||||
// mysql
|
||||
MysqlHost string
|
||||
MysqlPort int
|
||||
MysqlUsername string
|
||||
MysqlPassword string
|
||||
MysqlDatabase string
|
||||
MysqlTable string
|
||||
MysqlLogField string
|
||||
|
||||
// tcp
|
||||
TcpNetwork string
|
||||
TcpAddr string
|
||||
|
||||
// syslog
|
||||
SyslogProtocol string
|
||||
SyslogServerAddr string
|
||||
SyslogServerPort int
|
||||
SyslogSocket string
|
||||
SyslogTag string
|
||||
SyslogPriority int
|
||||
|
||||
// command
|
||||
CommandCommand string
|
||||
CommandArgs string
|
||||
CommandDir string
|
||||
|
||||
IsOn bool
|
||||
IsPublic bool
|
||||
FirewallOnly bool
|
||||
DisableDefaultDB bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.HTTPAccessLogPolicy_LogUpdateHTTPAccessLogPolicy, params.PolicyId)
|
||||
|
||||
policyResp, err := this.RPC().HTTPAccessLogPolicyRPC().FindHTTPAccessLogPolicy(this.AdminContext(), &pb.FindHTTPAccessLogPolicyRequest{HttpAccessLogPolicyId: params.PolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var policy = policyResp.HttpAccessLogPolicy
|
||||
if policy == nil {
|
||||
this.Fail("找不到要修改的策略")
|
||||
return
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入日志策略的名称")
|
||||
|
||||
var options interface{} = nil
|
||||
switch policy.Type {
|
||||
case serverconfigs.AccessLogStorageTypeFile:
|
||||
params.Must.
|
||||
Field("filePath", params.FilePath).
|
||||
Require("请输入日志文件路径")
|
||||
|
||||
var storage = new(serverconfigs.AccessLogFileStorageConfig)
|
||||
storage.Path = params.FilePath
|
||||
storage.AutoCreate = params.FileAutoCreate
|
||||
options = storage
|
||||
case serverconfigs.AccessLogStorageTypeES:
|
||||
params.Must.
|
||||
Field("esEndpoint", params.EsEndpoint).
|
||||
Require("请输入Endpoint").
|
||||
Field("esIndex", params.EsIndex).
|
||||
Require("请输入Index名称")
|
||||
|
||||
if !params.EsIsDataStream {
|
||||
params.Must.
|
||||
Field("esMappingType", params.EsMappingType).
|
||||
Require("请输入Mapping名称")
|
||||
}
|
||||
|
||||
var storage = new(serverconfigs.AccessLogESStorageConfig)
|
||||
storage.Endpoint = params.EsEndpoint
|
||||
storage.Index = params.EsIndex
|
||||
storage.IsDataStream = params.EsIsDataStream
|
||||
storage.MappingType = params.EsMappingType
|
||||
storage.Username = params.EsUsername
|
||||
storage.Password = params.EsPassword
|
||||
options = storage
|
||||
case serverconfigs.AccessLogStorageTypeTCP:
|
||||
params.Must.
|
||||
Field("tcpNetwork", params.TcpNetwork).
|
||||
Require("请选择网络协议").
|
||||
Field("tcpAddr", params.TcpAddr).
|
||||
Require("请输入网络地址")
|
||||
|
||||
var storage = new(serverconfigs.AccessLogTCPStorageConfig)
|
||||
storage.Network = params.TcpNetwork
|
||||
storage.Addr = params.TcpAddr
|
||||
options = storage
|
||||
case serverconfigs.AccessLogStorageTypeSyslog:
|
||||
switch params.SyslogProtocol {
|
||||
case serverconfigs.AccessLogSyslogStorageProtocolTCP, serverconfigs.AccessLogSyslogStorageProtocolUDP:
|
||||
params.Must.
|
||||
Field("syslogServerAddr", params.SyslogServerAddr).
|
||||
Require("请输入网络地址")
|
||||
case serverconfigs.AccessLogSyslogStorageProtocolSocket:
|
||||
params.Must.
|
||||
Field("syslogSocket", params.SyslogSocket).
|
||||
Require("请输入Socket路径")
|
||||
}
|
||||
|
||||
var storage = new(serverconfigs.AccessLogSyslogStorageConfig)
|
||||
storage.Protocol = params.SyslogProtocol
|
||||
storage.ServerAddr = params.SyslogServerAddr
|
||||
storage.ServerPort = params.SyslogServerPort
|
||||
storage.Socket = params.SyslogSocket
|
||||
storage.Tag = params.SyslogTag
|
||||
storage.Priority = params.SyslogPriority
|
||||
options = storage
|
||||
case serverconfigs.AccessLogStorageTypeCommand:
|
||||
params.Must.
|
||||
Field("commandCommand", params.CommandCommand).
|
||||
Require("请输入可执行命令")
|
||||
|
||||
var storage = new(serverconfigs.AccessLogCommandStorageConfig)
|
||||
storage.Command = params.CommandCommand
|
||||
storage.Args = cmd.ParseArgs(params.CommandArgs)
|
||||
storage.Dir = params.CommandDir
|
||||
options = storage
|
||||
}
|
||||
|
||||
if options == nil {
|
||||
this.Fail("找不到选择的存储类型")
|
||||
}
|
||||
|
||||
optionsJSON, err := json.Marshal(options)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().HTTPAccessLogPolicyRPC().UpdateHTTPAccessLogPolicy(this.AdminContext(), &pb.UpdateHTTPAccessLogPolicyRequest{
|
||||
HttpAccessLogPolicyId: params.PolicyId,
|
||||
Name: params.Name,
|
||||
OptionsJSON: optionsJSON,
|
||||
CondsJSON: nil, // TODO
|
||||
IsOn: params.IsOn,
|
||||
IsPublic: params.IsPublic,
|
||||
FirewallOnly: params.FirewallOnly,
|
||||
DisableDefaultDB: params.DisableDefaultDB,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
187
EdgeAdmin/internal/web/actions/default/servers/addOriginPopup.go
Normal file
187
EdgeAdmin/internal/web/actions/default/servers/addOriginPopup.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AddOriginPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *AddOriginPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *AddOriginPopupAction) RunGet(params struct {
|
||||
ServerType string
|
||||
}) {
|
||||
this.Data["serverType"] = params.ServerType
|
||||
|
||||
this.getOSSHook()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *AddOriginPopupAction) RunPost(params struct {
|
||||
Protocol string
|
||||
Addr string
|
||||
|
||||
DomainsJSON []byte
|
||||
Host string
|
||||
FollowPort bool
|
||||
Http2Enabled bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
ossConfig, goNext, err := this.postOSSHook(params.Protocol)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !goNext {
|
||||
return
|
||||
}
|
||||
|
||||
// 初始化
|
||||
var pbAddr = &pb.NetworkAddress{
|
||||
Protocol: params.Protocol,
|
||||
}
|
||||
var addrConfig = &serverconfigs.NetworkAddressConfig{
|
||||
Protocol: serverconfigs.Protocol(params.Protocol),
|
||||
}
|
||||
var ossJSON []byte
|
||||
|
||||
if ossConfig != nil { // OSS
|
||||
ossJSON, err = json.Marshal(ossConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
err = ossConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验OSS配置时出错:" + err.Error())
|
||||
return
|
||||
}
|
||||
} else { // 普通源站
|
||||
params.Must.
|
||||
Field("addr", params.Addr).
|
||||
Require("请输入源站地址")
|
||||
|
||||
var addr = params.Addr
|
||||
|
||||
// 是否是完整的地址
|
||||
if (params.Protocol == "http" || params.Protocol == "https") && regexp.MustCompile(`^(http|https)://`).MatchString(addr) {
|
||||
u, err := url.Parse(addr)
|
||||
if err == nil {
|
||||
addr = u.Host
|
||||
}
|
||||
}
|
||||
|
||||
addr = regexp.MustCompile(`\s+`).ReplaceAllString(addr, "")
|
||||
var portIndex = strings.LastIndex(addr, ":")
|
||||
if portIndex < 0 {
|
||||
if params.Protocol == "http" {
|
||||
addr += ":80"
|
||||
} else if params.Protocol == "https" {
|
||||
addr += ":443"
|
||||
} else {
|
||||
this.Fail("地址中需要带有端口")
|
||||
}
|
||||
portIndex = strings.LastIndex(addr, ":")
|
||||
}
|
||||
var host = addr[:portIndex]
|
||||
var port = addr[portIndex+1:]
|
||||
|
||||
// 检查端口号
|
||||
if port == "0" {
|
||||
this.Fail("端口号不能为0")
|
||||
}
|
||||
if !configutils.HasVariables(port) {
|
||||
// 必须是整数
|
||||
if !regexp.MustCompile(`^\d+$`).MatchString(port) {
|
||||
this.Fail("端口号只能为整数")
|
||||
}
|
||||
var portInt = types.Int(port)
|
||||
if portInt == 0 {
|
||||
this.Fail("端口号不能为0")
|
||||
}
|
||||
if portInt > 65535 {
|
||||
this.Fail("端口号不能大于65535")
|
||||
}
|
||||
}
|
||||
|
||||
pbAddr = &pb.NetworkAddress{
|
||||
Protocol: params.Protocol,
|
||||
Host: host,
|
||||
PortRange: port,
|
||||
}
|
||||
|
||||
addrConfig = &serverconfigs.NetworkAddressConfig{
|
||||
Protocol: serverconfigs.Protocol(params.Protocol),
|
||||
Host: host,
|
||||
PortRange: port,
|
||||
}
|
||||
}
|
||||
|
||||
// 专属域名
|
||||
var domains = []string{}
|
||||
if len(params.DomainsJSON) > 0 {
|
||||
err := json.Unmarshal(params.DomainsJSON, &domains)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 去除可能误加的斜杠
|
||||
for index, domain := range domains {
|
||||
domains[index] = strings.TrimSuffix(domain, "/")
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := this.RPC().OriginRPC().CreateOrigin(this.AdminContext(), &pb.CreateOriginRequest{
|
||||
Name: "",
|
||||
Addr: pbAddr,
|
||||
OssJSON: ossJSON,
|
||||
Description: "",
|
||||
Weight: 10,
|
||||
IsOn: true,
|
||||
Domains: domains,
|
||||
Host: params.Host,
|
||||
FollowPort: params.FollowPort,
|
||||
Http2Enabled: params.Http2Enabled,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var origin = &serverconfigs.OriginConfig{
|
||||
Id: resp.OriginId,
|
||||
IsOn: true,
|
||||
Addr: addrConfig,
|
||||
OSS: ossConfig,
|
||||
}
|
||||
|
||||
this.Data["origin"] = maps.Map{
|
||||
"id": resp.OriginId,
|
||||
"isOn": true,
|
||||
"addr": addrConfig,
|
||||
"addrSummary": origin.AddrSummary(),
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.ServerOrigin_LogCreateOrigin, resp.OriginId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
|
||||
package servers
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ossconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
func (this *AddOriginPopupAction) getOSSHook() {
|
||||
this.Data["ossTypes"] = []maps.Map{}
|
||||
this.Data["ossBucketParams"] = []maps.Map{}
|
||||
this.Data["ossForm"] = ""
|
||||
}
|
||||
|
||||
func (this *AddOriginPopupAction) postOSSHook(protocol string) (config *ossconfigs.OSSConfig, goNext bool, err error) {
|
||||
goNext = true
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package servers
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/origins/originutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ossconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"os"
|
||||
)
|
||||
|
||||
func (this *AddOriginPopupAction) getOSSHook() {
|
||||
if !teaconst.IsPlus {
|
||||
this.Data["ossTypes"] = []maps.Map{}
|
||||
this.Data["ossBucketParams"] = []maps.Map{}
|
||||
} else {
|
||||
this.Data["ossTypes"] = ossconfigs.FindAllOSSTypes()
|
||||
this.Data["ossBucketParams"] = ossconfigs.FindAllOSSBucketParamDefinitions()
|
||||
}
|
||||
|
||||
// 表单
|
||||
var formFile = originutils.OSSTemplateFile("addPopup_oss_plus.html")
|
||||
formData, _ := os.ReadFile(formFile)
|
||||
this.Data["ossForm"] = string(formData)
|
||||
}
|
||||
|
||||
func (this *AddOriginPopupAction) postOSSHook(protocol string) (config *ossconfigs.OSSConfig, goNext bool, err error) {
|
||||
return originutils.ParseOSSFromRequest(protocol, this.Object())
|
||||
}
|
||||
124
EdgeAdmin/internal/web/actions/default/servers/addPortPopup.go
Normal file
124
EdgeAdmin/internal/web/actions/default/servers/addPortPopup.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AddPortPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *AddPortPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *AddPortPopupAction) RunGet(params struct {
|
||||
ServerType string
|
||||
Protocol string
|
||||
From string
|
||||
SupportRange bool
|
||||
}) {
|
||||
this.Data["from"] = params.From
|
||||
|
||||
protocols := serverconfigs.FindAllServerProtocolsForType(params.ServerType)
|
||||
if len(params.Protocol) > 0 {
|
||||
result := []maps.Map{}
|
||||
for _, p := range protocols {
|
||||
if p.GetString("code") == params.Protocol {
|
||||
result = append(result, p)
|
||||
}
|
||||
}
|
||||
protocols = result
|
||||
}
|
||||
this.Data["protocols"] = protocols
|
||||
|
||||
this.Data["supportRange"] = params.SupportRange
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *AddPortPopupAction) RunPost(params struct {
|
||||
SupportRange bool
|
||||
|
||||
Protocol string
|
||||
Address string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 校验地址
|
||||
addr := maps.Map{
|
||||
"protocol": params.Protocol,
|
||||
"host": "",
|
||||
"portRange": "",
|
||||
"minPort": 0,
|
||||
"maxPort": 0,
|
||||
}
|
||||
|
||||
var portRegexp = regexp.MustCompile(`^\d+$`)
|
||||
if portRegexp.MatchString(params.Address) { // 单个端口
|
||||
addr["portRange"] = this.checkPort(params.Address)
|
||||
} else if params.SupportRange && regexp.MustCompile(`^\d+\s*-\s*\d+$`).MatchString(params.Address) { // Port1-Port2
|
||||
addr["portRange"], addr["minPort"], addr["maxPort"] = this.checkPortRange(params.Address)
|
||||
} else if strings.Contains(params.Address, ":") { // IP:Port
|
||||
index := strings.LastIndex(params.Address, ":")
|
||||
addr["host"] = strings.TrimSpace(params.Address[:index])
|
||||
port := strings.TrimSpace(params.Address[index+1:])
|
||||
if portRegexp.MatchString(port) {
|
||||
addr["portRange"] = this.checkPort(port)
|
||||
} else if params.SupportRange && regexp.MustCompile(`^\d+\s*-\s*\d+$`).MatchString(port) { // Port1-Port2
|
||||
addr["portRange"], addr["minPort"], addr["maxPort"] = this.checkPortRange(port)
|
||||
} else {
|
||||
this.FailField("address", "请输入正确的端口或者网络地址")
|
||||
}
|
||||
} else {
|
||||
this.FailField("address", "请输入正确的端口或者网络地址")
|
||||
}
|
||||
|
||||
this.Data["address"] = addr
|
||||
this.Success()
|
||||
}
|
||||
|
||||
func (this *AddPortPopupAction) checkPort(port string) (portRange string) {
|
||||
var intPort = types.Int(port)
|
||||
if intPort < 1 {
|
||||
this.FailField("address", "端口号不能小于1")
|
||||
}
|
||||
if intPort > 65535 {
|
||||
this.FailField("address", "端口号不能大于65535")
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
func (this *AddPortPopupAction) checkPortRange(port string) (portRange string, minPort int, maxPort int) {
|
||||
var pieces = strings.Split(port, "-")
|
||||
var piece1 = strings.TrimSpace(pieces[0])
|
||||
var piece2 = strings.TrimSpace(pieces[1])
|
||||
var port1 = types.Int(piece1)
|
||||
var port2 = types.Int(piece2)
|
||||
|
||||
if port1 < 1 {
|
||||
this.FailField("address", "端口号不能小于1")
|
||||
}
|
||||
if port1 > 65535 {
|
||||
this.FailField("address", "端口号不能大于65535")
|
||||
}
|
||||
|
||||
if port2 < 1 {
|
||||
this.FailField("address", "端口号不能小于1")
|
||||
}
|
||||
if port2 > 65535 {
|
||||
this.FailField("address", "端口号不能大于65535")
|
||||
}
|
||||
|
||||
if port1 > port2 {
|
||||
port1, port2 = port2, port1
|
||||
}
|
||||
|
||||
return types.String(port1) + "-" + types.String(port2), port1, port2
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AddServerNamePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *AddServerNamePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *AddServerNamePopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *AddServerNamePopupAction) RunPost(params struct {
|
||||
Mode string
|
||||
|
||||
ServerName string
|
||||
ServerNames string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
if params.Mode == "single" {
|
||||
var serverName = strings.ToLower(params.ServerName)
|
||||
|
||||
// 去除空格
|
||||
serverName = regexp.MustCompile(`\s+`).ReplaceAllString(serverName, "")
|
||||
|
||||
// 是否包含了多个域名
|
||||
var splitReg = regexp.MustCompile(`([,、|,;|])`)
|
||||
if splitReg.MatchString(serverName) {
|
||||
params.ServerNames = strings.Join(splitReg.Split(serverName, -1), "\n")
|
||||
params.Mode = "multiple"
|
||||
} else {
|
||||
// 处理URL
|
||||
if regexp.MustCompile(`^(?i)(http|https|ftp)://`).MatchString(serverName) {
|
||||
u, err := url.Parse(serverName)
|
||||
if err == nil && len(u.Host) > 0 {
|
||||
serverName = u.Host
|
||||
}
|
||||
}
|
||||
|
||||
// 去除端口
|
||||
if regexp.MustCompile(`:\d+$`).MatchString(serverName) {
|
||||
host, _, err := net.SplitHostPort(serverName)
|
||||
if err == nil && len(host) > 0 {
|
||||
serverName = host
|
||||
}
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("serverName", serverName).
|
||||
Require("请输入域名")
|
||||
|
||||
this.Data["serverName"] = maps.Map{
|
||||
"name": serverName,
|
||||
"type": "full",
|
||||
}
|
||||
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if params.Mode == "multiple" {
|
||||
if len(params.ServerNames) == 0 {
|
||||
this.FailField("serverNames", "请输入至少域名")
|
||||
}
|
||||
|
||||
var serverNames = []string{}
|
||||
for _, line := range strings.Split(params.ServerNames, "\n") {
|
||||
var serverName = strings.TrimSpace(line)
|
||||
serverName = regexp.MustCompile(`\s+`).ReplaceAllString(serverName, "")
|
||||
if len(serverName) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 处理URL
|
||||
if regexp.MustCompile(`^(?i)(http|https|ftp)://`).MatchString(serverName) {
|
||||
u, err := url.Parse(serverName)
|
||||
if err == nil && len(u.Host) > 0 {
|
||||
serverName = u.Host
|
||||
}
|
||||
}
|
||||
|
||||
// 去除端口
|
||||
if regexp.MustCompile(`:\d+$`).MatchString(serverName) {
|
||||
host, _, err := net.SplitHostPort(serverName)
|
||||
if err == nil && len(host) > 0 {
|
||||
serverName = host
|
||||
}
|
||||
}
|
||||
|
||||
// 转成小写
|
||||
serverName = strings.ToLower(serverName)
|
||||
|
||||
serverNames = append(serverNames, serverName)
|
||||
}
|
||||
this.Data["serverName"] = maps.Map{
|
||||
"name": "",
|
||||
"type": "full",
|
||||
"subNames": serverNames,
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"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 {
|
||||
ProviderCode string
|
||||
}) {
|
||||
this.Data["providerCode"] = params.ProviderCode
|
||||
|
||||
// 服务商列表
|
||||
providersResp, err := this.RPC().ACMEProviderRPC().FindAllACMEProviders(this.AdminContext(), &pb.FindAllACMEProvidersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var providerMaps = []maps.Map{}
|
||||
for _, provider := range providersResp.AcmeProviders {
|
||||
providerMaps = append(providerMaps, maps.Map{
|
||||
"name": provider.Name,
|
||||
"code": provider.Code,
|
||||
"description": provider.Description,
|
||||
"requireEAB": provider.RequireEAB,
|
||||
"eabDescription": provider.EabDescription,
|
||||
})
|
||||
}
|
||||
|
||||
this.Data["providers"] = providerMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
ProviderCode string
|
||||
EabKid string
|
||||
EabKey string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var accountId int64
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.ACMEProviderAccount_LogCreateACMEProviderAccount, accountId)
|
||||
}()
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入账号名称").
|
||||
Field("providerCode", params.ProviderCode).
|
||||
Require("请选择服务商")
|
||||
|
||||
providerResp, err := this.RPC().ACMEProviderRPC().FindACMEProviderWithCode(this.AdminContext(), &pb.FindACMEProviderWithCodeRequest{AcmeProviderCode: params.ProviderCode})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var provider = providerResp.AcmeProvider
|
||||
if provider == nil {
|
||||
this.Fail("请选择服务商")
|
||||
}
|
||||
|
||||
if provider.RequireEAB {
|
||||
params.Must.
|
||||
Field("eabKid", params.EabKid).
|
||||
Require("请输入EAB Kid").
|
||||
Field("eabKey", params.EabKey).
|
||||
Require("请输入EAB HMAC Key")
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().ACMEProviderAccountRPC().CreateACMEProviderAccount(this.AdminContext(), &pb.CreateACMEProviderAccountRequest{
|
||||
Name: params.Name,
|
||||
ProviderCode: params.ProviderCode,
|
||||
EabKid: params.EabKid,
|
||||
EabKey: params.EabKey,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
accountId = createResp.AcmeProviderAccountId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
AccountId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ACMEProviderAccount_LogDeleteACMEProviderAccount, params.AccountId)
|
||||
|
||||
_, err := this.RPC().ACMEProviderAccountRPC().DeleteACMEProviderAccount(this.AdminContext(), &pb.DeleteACMEProviderAccountRequest{AcmeProviderAccountId: params.AccountId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "account")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().ACMEProviderAccountRPC().CountAllEnabledACMEProviderAccounts(this.AdminContext(), &pb.CountAllEnabledACMEProviderAccountsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
accountsResp, err := this.RPC().ACMEProviderAccountRPC().ListEnabledACMEProviderAccounts(this.AdminContext(), &pb.ListEnabledACMEProviderAccountsRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var accountMaps = []maps.Map{}
|
||||
for _, account := range accountsResp.AcmeProviderAccounts {
|
||||
var providerMap maps.Map
|
||||
if account.AcmeProvider != nil {
|
||||
providerMap = maps.Map{
|
||||
"name": account.AcmeProvider.Name,
|
||||
"code": account.AcmeProvider.Code,
|
||||
"requireEAB": account.AcmeProvider.RequireEAB,
|
||||
}
|
||||
}
|
||||
|
||||
accountMaps = append(accountMaps, maps.Map{
|
||||
"id": account.Id,
|
||||
"isOn": account.IsOn,
|
||||
"name": account.Name,
|
||||
"eabKid": account.EabKid,
|
||||
"eabKey": account.EabKey,
|
||||
"provider": providerMap,
|
||||
})
|
||||
}
|
||||
this.Data["accounts"] = accountMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
AccountId int64
|
||||
}) {
|
||||
// 账号信息
|
||||
accountResp, err := this.RPC().ACMEProviderAccountRPC().FindEnabledACMEProviderAccount(this.AdminContext(), &pb.FindEnabledACMEProviderAccountRequest{AcmeProviderAccountId: params.AccountId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var account = accountResp.AcmeProviderAccount
|
||||
if account == nil {
|
||||
this.NotFound("ACMEProviderAccount", params.AccountId)
|
||||
return
|
||||
}
|
||||
|
||||
var providerMap maps.Map
|
||||
if account.AcmeProvider != nil {
|
||||
providerMap = maps.Map{
|
||||
"name": account.AcmeProvider.Name,
|
||||
"code": account.AcmeProvider.Code,
|
||||
"description": account.AcmeProvider.Description,
|
||||
"eabDescription": account.AcmeProvider.EabDescription,
|
||||
"requireEAB": account.AcmeProvider.RequireEAB,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["account"] = maps.Map{
|
||||
"id": account.Id,
|
||||
"name": account.Name,
|
||||
"isOn": account.IsOn,
|
||||
"providerCode": account.ProviderCode,
|
||||
"eabKid": account.EabKid,
|
||||
"eabKey": account.EabKey,
|
||||
"provider": providerMap,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
AccountId int64
|
||||
Name string
|
||||
ProviderCode string
|
||||
EabKid string
|
||||
EabKey string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ACMEProviderAccount_LogUpdateACMEProviderAccount, params.AccountId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入账号名称").
|
||||
Field("providerCode", params.ProviderCode).
|
||||
Require("请选择服务商")
|
||||
|
||||
providerResp, err := this.RPC().ACMEProviderRPC().FindACMEProviderWithCode(this.AdminContext(), &pb.FindACMEProviderWithCodeRequest{AcmeProviderCode: params.ProviderCode})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var provider = providerResp.AcmeProvider
|
||||
if provider == nil {
|
||||
this.Fail("请选择服务商")
|
||||
}
|
||||
|
||||
if provider.RequireEAB {
|
||||
params.Must.
|
||||
Field("eabKid", params.EabKid).
|
||||
Require("请输入EAB Kid").
|
||||
Field("eabKey", params.EabKey).
|
||||
Require("请输入EAB HMAC Key")
|
||||
}
|
||||
|
||||
_, err = this.RPC().ACMEProviderAccountRPC().UpdateACMEProviderAccount(this.AdminContext(), &pb.UpdateACMEProviderAccountRequest{
|
||||
AcmeProviderAccountId: params.AccountId,
|
||||
Name: params.Name,
|
||||
EabKid: params.EabKid,
|
||||
EabKey: params.EabKey,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateAction) Init() {
|
||||
this.Nav("", "", "create")
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunGet(params struct{}) {
|
||||
// 证书服务商
|
||||
providersResp, err := this.RPC().ACMEProviderRPC().FindAllACMEProviders(this.AdminContext(), &pb.FindAllACMEProvidersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var providerMaps = []maps.Map{}
|
||||
for _, provider := range providersResp.AcmeProviders {
|
||||
providerMaps = append(providerMaps, maps.Map{
|
||||
"name": provider.Name,
|
||||
"code": provider.Code,
|
||||
})
|
||||
}
|
||||
this.Data["providers"] = providerMaps
|
||||
|
||||
// 域名解析服务商
|
||||
dnsProvidersResp, err := this.RPC().DNSProviderRPC().FindAllEnabledDNSProviders(this.AdminContext(), &pb.FindAllEnabledDNSProvidersRequest{
|
||||
AdminId: this.AdminId(),
|
||||
UserId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
dnsProviderMaps := []maps.Map{}
|
||||
for _, provider := range dnsProvidersResp.DnsProviders {
|
||||
dnsProviderMaps = append(dnsProviderMaps, maps.Map{
|
||||
"id": provider.Id,
|
||||
"name": provider.Name,
|
||||
"typeName": provider.TypeName,
|
||||
})
|
||||
}
|
||||
this.Data["dnsProviders"] = dnsProviderMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunPost(params struct {
|
||||
PlatformUserId int64
|
||||
TaskId int64
|
||||
AuthType string
|
||||
AcmeUserId int64
|
||||
DnsProviderId int64
|
||||
DnsDomain string
|
||||
Domains []string
|
||||
AutoRenew bool
|
||||
AuthURL string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
if params.AuthType != "dns" && params.AuthType != "http" {
|
||||
this.Fail("无法识别的认证方式'" + params.AuthType + "'")
|
||||
}
|
||||
|
||||
if params.AcmeUserId <= 0 {
|
||||
this.Fail("请选择一个申请证书的用户")
|
||||
}
|
||||
|
||||
// 校验DNS相关信息
|
||||
dnsDomain := strings.ToLower(params.DnsDomain)
|
||||
if params.AuthType == "dns" {
|
||||
if params.DnsProviderId <= 0 {
|
||||
this.Fail("请选择DNS服务商")
|
||||
}
|
||||
if len(params.DnsDomain) == 0 {
|
||||
this.Fail("请输入顶级域名")
|
||||
}
|
||||
if !domainutils.ValidateDomainFormat(dnsDomain) {
|
||||
this.Fail("请输入正确的顶级域名")
|
||||
}
|
||||
}
|
||||
|
||||
if len(params.Domains) == 0 {
|
||||
this.Fail("请输入证书域名列表")
|
||||
}
|
||||
var realDomains = []string{}
|
||||
for _, domain := range params.Domains {
|
||||
domain = strings.ToLower(domain)
|
||||
if params.AuthType == "dns" { // DNS认证
|
||||
if !strings.HasSuffix(domain, "."+dnsDomain) && domain != dnsDomain {
|
||||
this.Fail("证书域名中的" + domain + "和顶级域名不一致")
|
||||
}
|
||||
} else if params.AuthType == "http" { // HTTP认证
|
||||
if strings.Contains(domain, "*") {
|
||||
this.Fail("在HTTP认证时域名" + domain + "不能包含通配符")
|
||||
}
|
||||
}
|
||||
realDomains = append(realDomains, domain)
|
||||
}
|
||||
|
||||
if params.TaskId == 0 {
|
||||
createResp, err := this.RPC().ACMETaskRPC().CreateACMETask(this.AdminContext(), &pb.CreateACMETaskRequest{
|
||||
UserId: params.PlatformUserId,
|
||||
AuthType: params.AuthType,
|
||||
AcmeUserId: params.AcmeUserId,
|
||||
DnsProviderId: params.DnsProviderId,
|
||||
DnsDomain: dnsDomain,
|
||||
Domains: realDomains,
|
||||
AutoRenew: params.AutoRenew,
|
||||
AuthURL: params.AuthURL,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
params.TaskId = createResp.AcmeTaskId
|
||||
defer this.CreateLogInfo(codes.ACMETask_LogCreateACMETask, createResp.AcmeTaskId)
|
||||
} else {
|
||||
_, err := this.RPC().ACMETaskRPC().UpdateACMETask(this.AdminContext(), &pb.UpdateACMETaskRequest{
|
||||
AcmeTaskId: params.TaskId,
|
||||
AcmeUserId: params.AcmeUserId,
|
||||
DnsProviderId: params.DnsProviderId,
|
||||
DnsDomain: dnsDomain,
|
||||
Domains: realDomains,
|
||||
AutoRenew: params.AutoRenew,
|
||||
AuthURL: params.AuthURL,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo(codes.ACMETask_LogUpdateACMETask, params.TaskId)
|
||||
}
|
||||
|
||||
this.Data["taskId"] = params.TaskId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteTaskAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteTaskAction) RunPost(params struct {
|
||||
TaskId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ACMETask_LogDeleteACMETask, params.TaskId)
|
||||
|
||||
_, err := this.RPC().ACMETaskRPC().DeleteACMETask(this.AdminContext(), &pb.DeleteACMETaskRequest{AcmeTaskId: params.TaskId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "task")
|
||||
this.SecondMenu("list")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
UserId int64
|
||||
Type string
|
||||
Keyword string
|
||||
UserType string
|
||||
}) {
|
||||
this.Data["type"] = params.Type
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["userType"] = params.UserType
|
||||
|
||||
var userOnly = params.UserId > 0 || params.UserType == "user"
|
||||
|
||||
// 当前用户
|
||||
this.Data["searchingUserId"] = params.UserId
|
||||
var userMap = maps.Map{
|
||||
"id": 0,
|
||||
"username": "",
|
||||
"fullname": "",
|
||||
}
|
||||
if params.UserId > 0 {
|
||||
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.AdminContext(), &pb.FindEnabledUserRequest{UserId: params.UserId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var user = userResp.User
|
||||
if user != nil {
|
||||
userMap = maps.Map{
|
||||
"id": user.Id,
|
||||
"username": user.Username,
|
||||
"fullname": user.Fullname,
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["user"] = userMap
|
||||
|
||||
var countAll int64
|
||||
var countAvailable int64
|
||||
var countExpired int64
|
||||
var count7Days int64
|
||||
var count30Days int64
|
||||
|
||||
// 计算数量
|
||||
{
|
||||
// all
|
||||
resp, err := this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countAll = resp.Count
|
||||
|
||||
// available
|
||||
resp, err = this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
IsAvailable: true,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countAvailable = resp.Count
|
||||
|
||||
// expired
|
||||
resp, err = this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
IsExpired: true,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countExpired = resp.Count
|
||||
|
||||
// expire in 7 days
|
||||
resp, err = this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 7,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count7Days = resp.Count
|
||||
|
||||
// expire in 30 days
|
||||
resp, err = this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 30,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count30Days = resp.Count
|
||||
}
|
||||
|
||||
this.Data["countAll"] = countAll
|
||||
this.Data["countAvailable"] = countAvailable
|
||||
this.Data["countExpired"] = countExpired
|
||||
this.Data["count7Days"] = count7Days
|
||||
this.Data["count30Days"] = count30Days
|
||||
|
||||
// 分页
|
||||
var page *actionutils.Page
|
||||
var tasksResp *pb.ListEnabledACMETasksResponse
|
||||
var err error
|
||||
switch params.Type {
|
||||
case "":
|
||||
page = this.NewPage(countAll)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "available":
|
||||
page = this.NewPage(countAvailable)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
IsAvailable: true,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "expired":
|
||||
page = this.NewPage(countExpired)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
IsExpired: true,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "7days":
|
||||
page = this.NewPage(count7Days)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 7,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "30days":
|
||||
page = this.NewPage(count30Days)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 30,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
default:
|
||||
page = this.NewPage(countAll)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
var taskMaps = []maps.Map{}
|
||||
for _, task := range tasksResp.AcmeTasks {
|
||||
if task.AcmeUser == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// 服务商
|
||||
var providerMap maps.Map
|
||||
if task.AcmeUser.AcmeProvider != nil {
|
||||
providerMap = maps.Map{
|
||||
"name": task.AcmeUser.AcmeProvider.Name,
|
||||
"code": task.AcmeUser.AcmeProvider.Code,
|
||||
}
|
||||
}
|
||||
|
||||
// 账号
|
||||
var accountMap maps.Map
|
||||
if task.AcmeUser.AcmeProviderAccount != nil {
|
||||
accountMap = maps.Map{
|
||||
"id": task.AcmeUser.AcmeProviderAccount.Id,
|
||||
"name": task.AcmeUser.AcmeProviderAccount.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// DNS服务商
|
||||
dnsProviderMap := maps.Map{}
|
||||
if task.AuthType == "dns" && task.DnsProvider != nil {
|
||||
dnsProviderMap = maps.Map{
|
||||
"id": task.DnsProvider.Id,
|
||||
"name": task.DnsProvider.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// 证书
|
||||
var certMap maps.Map = nil
|
||||
if task.SslCert != nil {
|
||||
certMap = maps.Map{
|
||||
"id": task.SslCert.Id,
|
||||
"name": task.SslCert.Name,
|
||||
"beginTime": timeutil.FormatTime("Y-m-d", task.SslCert.TimeBeginAt),
|
||||
"endTime": timeutil.FormatTime("Y-m-d", task.SslCert.TimeEndAt),
|
||||
}
|
||||
}
|
||||
|
||||
// 日志
|
||||
var logMap maps.Map = nil
|
||||
if task.LatestACMETaskLog != nil {
|
||||
logMap = maps.Map{
|
||||
"id": task.LatestACMETaskLog.Id,
|
||||
"isOk": task.LatestACMETaskLog.IsOk,
|
||||
"error": task.LatestACMETaskLog.Error,
|
||||
"createdTime": timeutil.FormatTime("m-d", task.CreatedAt),
|
||||
}
|
||||
}
|
||||
|
||||
// user
|
||||
userResp, err := this.RPC().ACMETaskRPC().FindACMETaskUser(this.AdminContext(), &pb.FindACMETaskUserRequest{AcmeTaskId: task.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var taskUserMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userResp.User != nil {
|
||||
taskUserMap = maps.Map{
|
||||
"id": userResp.User.Id,
|
||||
"username": userResp.User.Username,
|
||||
"fullname": userResp.User.Fullname,
|
||||
}
|
||||
}
|
||||
|
||||
taskMaps = append(taskMaps, maps.Map{
|
||||
"id": task.Id,
|
||||
"authType": task.AuthType,
|
||||
"acmeUser": maps.Map{
|
||||
"id": task.AcmeUser.Id,
|
||||
"email": task.AcmeUser.Email,
|
||||
"provider": providerMap,
|
||||
"account": accountMap,
|
||||
},
|
||||
"dnsProvider": dnsProviderMap,
|
||||
"dnsDomain": task.DnsDomain,
|
||||
"domains": task.Domains,
|
||||
"autoRenew": task.AutoRenew,
|
||||
"cert": certMap,
|
||||
"log": logMap,
|
||||
"user": taskUserMap,
|
||||
})
|
||||
}
|
||||
this.Data["tasks"] = taskMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type RunAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *RunAction) RunPost(params struct {
|
||||
TaskId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ACMETask_LogRunACMETask, params.TaskId)
|
||||
|
||||
runResp, err := this.RPC().ACMETaskRPC().RunACMETask(this.AdminContext(), &pb.RunACMETaskRequest{AcmeTaskId: params.TaskId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if runResp.IsOk {
|
||||
this.Data["certId"] = runResp.SslCertId
|
||||
this.Success()
|
||||
} else {
|
||||
this.Fail(runResp.Error)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type UpdateTaskPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateTaskPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdateTaskPopupAction) RunGet(params struct {
|
||||
TaskId int64
|
||||
}) {
|
||||
taskResp, err := this.RPC().ACMETaskRPC().FindEnabledACMETask(this.AdminContext(), &pb.FindEnabledACMETaskRequest{AcmeTaskId: params.TaskId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var task = taskResp.AcmeTask
|
||||
if task == nil {
|
||||
this.NotFound("acmeTask", params.TaskId)
|
||||
return
|
||||
}
|
||||
|
||||
var dnsProviderMap maps.Map
|
||||
if task.DnsProvider != nil {
|
||||
dnsProviderMap = maps.Map{
|
||||
"id": task.DnsProvider.Id,
|
||||
}
|
||||
} else {
|
||||
dnsProviderMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
}
|
||||
|
||||
var acmeUserMap maps.Map
|
||||
if task.AcmeUser != nil {
|
||||
acmeUserMap = maps.Map{
|
||||
"id": task.AcmeUser.Id,
|
||||
}
|
||||
} else {
|
||||
acmeUserMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["task"] = maps.Map{
|
||||
"id": task.Id,
|
||||
"authType": task.AuthType,
|
||||
"acmeUser": acmeUserMap,
|
||||
"dnsDomain": task.DnsDomain,
|
||||
"domains": task.Domains,
|
||||
"autoRenew": task.AutoRenew,
|
||||
"isOn": task.IsOn,
|
||||
"authURL": task.AuthURL,
|
||||
"dnsProvider": dnsProviderMap,
|
||||
}
|
||||
|
||||
// 域名解析服务商
|
||||
providersResp, err := this.RPC().DNSProviderRPC().FindAllEnabledDNSProviders(this.AdminContext(), &pb.FindAllEnabledDNSProvidersRequest{
|
||||
AdminId: this.AdminId(),
|
||||
UserId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var providerMaps = []maps.Map{}
|
||||
for _, provider := range providersResp.DnsProviders {
|
||||
providerMaps = append(providerMaps, maps.Map{
|
||||
"id": provider.Id,
|
||||
"name": provider.Name,
|
||||
"typeName": provider.TypeName,
|
||||
})
|
||||
}
|
||||
this.Data["providers"] = providerMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateTaskPopupAction) RunPost(params struct {
|
||||
TaskId int64
|
||||
AuthType string
|
||||
AcmeUserId int64
|
||||
DnsProviderId int64
|
||||
DnsDomain string
|
||||
DomainsJSON []byte
|
||||
AutoRenew bool
|
||||
AuthURL string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ACMETask_LogUpdateACMETask, params.TaskId)
|
||||
|
||||
if params.AuthType != "dns" && params.AuthType != "http" {
|
||||
this.Fail("无法识别的认证方式'" + params.AuthType + "'")
|
||||
}
|
||||
|
||||
if params.AcmeUserId <= 0 {
|
||||
this.Fail("请选择一个申请证书的用户")
|
||||
}
|
||||
|
||||
dnsDomain := strings.ToLower(params.DnsDomain)
|
||||
if params.AuthType == "dns" {
|
||||
if params.DnsProviderId <= 0 {
|
||||
this.Fail("请选择DNS服务商")
|
||||
}
|
||||
if len(params.DnsDomain) == 0 {
|
||||
this.Fail("请输入顶级域名")
|
||||
}
|
||||
if !domainutils.ValidateDomainFormat(dnsDomain) {
|
||||
this.Fail("请输入正确的顶级域名")
|
||||
}
|
||||
}
|
||||
|
||||
var domains = []string{}
|
||||
if len(params.DomainsJSON) > 0 {
|
||||
err := json.Unmarshal(params.DomainsJSON, &domains)
|
||||
if err != nil {
|
||||
this.Fail("解析域名数据失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(domains) == 0 {
|
||||
this.Fail("请输入证书域名列表")
|
||||
}
|
||||
var realDomains = []string{}
|
||||
for _, domain := range domains {
|
||||
domain = strings.ToLower(domain)
|
||||
if params.AuthType == "dns" {
|
||||
if !strings.HasSuffix(domain, "."+dnsDomain) && domain != dnsDomain {
|
||||
this.Fail("证书域名中的" + domain + "和顶级域名不一致")
|
||||
}
|
||||
} else if params.AuthType == "http" { // HTTP认证
|
||||
if strings.Contains(domain, "*") {
|
||||
this.Fail("在HTTP认证时域名" + domain + "不能包含通配符")
|
||||
}
|
||||
}
|
||||
realDomains = append(realDomains, domain)
|
||||
}
|
||||
|
||||
_, err := this.RPC().ACMETaskRPC().UpdateACMETask(this.AdminContext(), &pb.UpdateACMETaskRequest{
|
||||
AcmeTaskId: params.TaskId,
|
||||
AcmeUserId: params.AcmeUserId,
|
||||
DnsProviderId: params.DnsProviderId,
|
||||
DnsDomain: dnsDomain,
|
||||
Domains: realDomains,
|
||||
AutoRenew: params.AutoRenew,
|
||||
AuthURL: params.AuthURL,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package acme
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UserOptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UserOptionsAction) RunPost(params struct {
|
||||
PlatformUserId int64
|
||||
}) {
|
||||
// 获取所有可用的用户
|
||||
usersResp, err := this.RPC().ACMEUserRPC().FindAllACMEUsers(this.AdminContext(), &pb.FindAllACMEUsersRequest{
|
||||
AdminId: 0,
|
||||
UserId: params.PlatformUserId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var userMaps = []maps.Map{}
|
||||
for _, user := range usersResp.AcmeUsers {
|
||||
description := user.Description
|
||||
if len(description) > 0 {
|
||||
description = "(" + description + ")"
|
||||
}
|
||||
|
||||
userMaps = append(userMaps, maps.Map{
|
||||
"id": user.Id,
|
||||
"description": description,
|
||||
"email": user.Email,
|
||||
"providerCode": user.AcmeProviderCode,
|
||||
})
|
||||
}
|
||||
this.Data["users"] = userMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type AccountsWithCodeAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *AccountsWithCodeAction) RunPost(params struct {
|
||||
Code string
|
||||
}) {
|
||||
accountsResp, err := this.RPC().ACMEProviderAccountRPC().FindAllACMEProviderAccountsWithProviderCode(this.AdminContext(), &pb.FindAllACMEProviderAccountsWithProviderCodeRequest{AcmeProviderCode: params.Code})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var accountMaps = []maps.Map{}
|
||||
for _, account := range accountsResp.AcmeProviderAccounts {
|
||||
accountMaps = append(accountMaps, maps.Map{
|
||||
"id": account.Id,
|
||||
"name": account.Name,
|
||||
})
|
||||
}
|
||||
this.Data["accounts"] = accountMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"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 {
|
||||
PlatformUserId int64
|
||||
ProviderCode string
|
||||
}) {
|
||||
this.Data["platformUserId"] = params.PlatformUserId
|
||||
this.Data["providerCode"] = params.ProviderCode
|
||||
|
||||
// 平台用户信息
|
||||
this.Data["platformUser"] = nil
|
||||
if params.PlatformUserId > 0 {
|
||||
platformUserResp, err := this.RPC().UserRPC().FindEnabledUser(this.AdminContext(), &pb.FindEnabledUserRequest{UserId: params.PlatformUserId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var platformUser = platformUserResp.User
|
||||
if platformUser != nil {
|
||||
this.Data["platformUser"] = maps.Map{
|
||||
"id": platformUser.Id,
|
||||
"username": platformUser.Username,
|
||||
"fullname": platformUser.Fullname,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 服务商
|
||||
providersResp, err := this.RPC().ACMEProviderRPC().FindAllACMEProviders(this.AdminContext(), &pb.FindAllACMEProvidersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var providerMaps = []maps.Map{}
|
||||
for _, provider := range providersResp.AcmeProviders {
|
||||
providerMaps = append(providerMaps, maps.Map{
|
||||
"code": provider.Code,
|
||||
"name": provider.Name,
|
||||
"requireEAB": provider.RequireEAB,
|
||||
})
|
||||
}
|
||||
this.Data["providers"] = providerMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
PlatformUserId int64
|
||||
Email string
|
||||
ProviderCode string
|
||||
AccountId int64
|
||||
Description string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("email", params.Email).
|
||||
Require("请输入邮箱").
|
||||
Email("请输入正确的邮箱格式").
|
||||
Field("providerCode", params.ProviderCode).
|
||||
Require("请选择所属服务商")
|
||||
|
||||
providerResp, err := this.RPC().ACMEProviderRPC().FindACMEProviderWithCode(this.AdminContext(), &pb.FindACMEProviderWithCodeRequest{
|
||||
AcmeProviderCode: params.ProviderCode,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if providerResp.AcmeProvider == nil {
|
||||
this.Fail("找不到要选择的证书")
|
||||
}
|
||||
if providerResp.AcmeProvider.RequireEAB {
|
||||
if params.AccountId <= 0 {
|
||||
this.Fail("此服务商要求必须选择或创建服务商账号")
|
||||
}
|
||||
|
||||
// 同一个账号只能有一个用户
|
||||
countResp, err := this.RPC().ACMEUserRPC().
|
||||
CountACMEUsers(this.AdminContext(), &pb.CountAcmeUsersRequest{
|
||||
AcmeProviderAccountId: params.AccountId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("此服务商账号已被别的用户使用,请换成别的账号")
|
||||
}
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().ACMEUserRPC().CreateACMEUser(this.AdminContext(), &pb.CreateACMEUserRequest{
|
||||
UserId: params.PlatformUserId,
|
||||
Email: params.Email,
|
||||
Description: params.Description,
|
||||
AcmeProviderCode: params.ProviderCode,
|
||||
AcmeProviderAccountId: params.AccountId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 返回数据
|
||||
this.Data["acmeUser"] = maps.Map{
|
||||
"id": createResp.AcmeUserId,
|
||||
"description": params.Description,
|
||||
"email": params.Email,
|
||||
"providerCode": params.ProviderCode,
|
||||
}
|
||||
|
||||
// 日志
|
||||
defer this.CreateLogInfo(codes.ACMEUser_LogCreateACMEUser, createResp.AcmeUserId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
UserId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ACMEUser_LogDeleteACMEUser, params.UserId)
|
||||
|
||||
countResp, err := this.RPC().ACMETaskRPC().CountAllEnabledACMETasksWithACMEUserId(this.AdminContext(), &pb.CountAllEnabledACMETasksWithACMEUserIdRequest{AcmeUserId: params.UserId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("有任务正在和这个用户关联,所以不能删除")
|
||||
}
|
||||
|
||||
_, err = this.RPC().ACMEUserRPC().DeleteACMEUser(this.AdminContext(), &pb.DeleteACMEUserRequest{AcmeUserId: params.UserId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "user")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().ACMEUserRPC().CountACMEUsers(this.AdminContext(), &pb.CountAcmeUsersRequest{
|
||||
AdminId: this.AdminId(),
|
||||
UserId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
usersResp, err := this.RPC().ACMEUserRPC().ListACMEUsers(this.AdminContext(), &pb.ListACMEUsersRequest{
|
||||
AdminId: this.AdminId(),
|
||||
UserId: 0,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
userMaps := []maps.Map{}
|
||||
for _, user := range usersResp.AcmeUsers {
|
||||
// 服务商
|
||||
var providerMap maps.Map
|
||||
if user.AcmeProvider != nil {
|
||||
providerMap = maps.Map{
|
||||
"name": user.AcmeProvider.Name,
|
||||
"code": user.AcmeProvider.Code,
|
||||
}
|
||||
}
|
||||
|
||||
// 账号
|
||||
var accountMap maps.Map
|
||||
if user.AcmeProviderAccount != nil {
|
||||
accountMap = maps.Map{
|
||||
"id": user.AcmeProviderAccount.Id,
|
||||
"name": user.AcmeProviderAccount.Name,
|
||||
}
|
||||
}
|
||||
|
||||
userMaps = append(userMaps, maps.Map{
|
||||
"id": user.Id,
|
||||
"email": user.Email,
|
||||
"description": user.Description,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", user.CreatedAt),
|
||||
"provider": providerMap,
|
||||
"account": accountMap,
|
||||
})
|
||||
}
|
||||
this.Data["users"] = userMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package users
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
UserId int64
|
||||
}) {
|
||||
userResp, err := this.RPC().ACMEUserRPC().FindEnabledACMEUser(this.AdminContext(), &pb.FindEnabledACMEUserRequest{AcmeUserId: params.UserId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
user := userResp.AcmeUser
|
||||
if user == nil {
|
||||
this.NotFound("acmeUser", params.UserId)
|
||||
return
|
||||
}
|
||||
|
||||
// 服务商
|
||||
var providerMap maps.Map
|
||||
if user.AcmeProvider != nil {
|
||||
providerMap = maps.Map{
|
||||
"name": user.AcmeProvider.Name,
|
||||
"code": user.AcmeProvider.Code,
|
||||
}
|
||||
}
|
||||
|
||||
// 账号
|
||||
var accountMap maps.Map
|
||||
if user.AcmeProviderAccount != nil {
|
||||
accountMap = maps.Map{
|
||||
"id": user.AcmeProviderAccount.Id,
|
||||
"name": user.AcmeProviderAccount.Name,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["user"] = maps.Map{
|
||||
"id": user.Id,
|
||||
"email": user.Email,
|
||||
"description": user.Description,
|
||||
"provider": providerMap,
|
||||
"account": accountMap,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
UserId int64
|
||||
Description string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ACMEUser_LogUpdateACMEUser, params.UserId)
|
||||
|
||||
_, err := this.RPC().ACMEUserRPC().UpdateACMEUser(this.AdminContext(), &pb.UpdateACMEUserRequest{
|
||||
AcmeUserId: params.UserId,
|
||||
Description: params.Description,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CertPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CertPopupAction) Init() {
|
||||
}
|
||||
|
||||
func (this *CertPopupAction) RunGet(params struct {
|
||||
CertId int64
|
||||
}) {
|
||||
certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var certConfig = &sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(certResp.SslCertJSON, certConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var reverseCommonNames = []string{}
|
||||
for i := len(certConfig.CommonNames) - 1; i >= 0; i-- {
|
||||
reverseCommonNames = append(reverseCommonNames, certConfig.CommonNames[i])
|
||||
}
|
||||
|
||||
this.Data["info"] = maps.Map{
|
||||
"id": certConfig.Id,
|
||||
"name": certConfig.Name,
|
||||
"description": certConfig.Description,
|
||||
"isOn": certConfig.IsOn,
|
||||
"isAvailable": certConfig.TimeEndAt >= time.Now().Unix(),
|
||||
"commonNames": reverseCommonNames,
|
||||
"dnsNames": certConfig.DNSNames,
|
||||
|
||||
// TODO 检查是否为7天或30天内过期
|
||||
"beginTime": timeutil.FormatTime("Y-m-d H:i:s", certConfig.TimeBeginAt),
|
||||
"endTime": timeutil.FormatTime("Y-m-d H:i:s", certConfig.TimeEndAt),
|
||||
|
||||
"isCA": certConfig.IsCA,
|
||||
"certString": string(certConfig.CertData),
|
||||
"keyString": string(certConfig.KeyData),
|
||||
}
|
||||
|
||||
// 引入的服务
|
||||
serversResp, err := this.RPC().ServerRPC().FindAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.FindAllEnabledServersWithSSLCertIdRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var serverMaps = []maps.Map{}
|
||||
for _, server := range serversResp.Servers {
|
||||
serverMaps = append(serverMaps, maps.Map{
|
||||
"id": server.Id,
|
||||
"isOn": server.IsOn,
|
||||
"name": server.Name,
|
||||
"type": server.Type,
|
||||
})
|
||||
}
|
||||
this.Data["servers"] = serverMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
)
|
||||
|
||||
// 所有相关数据
|
||||
type DatajsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DatajsAction) Init() {
|
||||
}
|
||||
|
||||
func (this *DatajsAction) RunGet(params struct{}) {
|
||||
this.AddHeader("Content-Type", "text/javascript; charset=utf-8")
|
||||
|
||||
{
|
||||
cipherSuitesJSON, err := json.Marshal(sslconfigs.AllTLSCipherSuites)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.WriteString("window.SSL_ALL_CIPHER_SUITES = " + string(cipherSuitesJSON) + ";\n")
|
||||
}
|
||||
{
|
||||
modernCipherSuitesJSON, err := json.Marshal(sslconfigs.TLSModernCipherSuites)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.WriteString("window.SSL_MODERN_CIPHER_SUITES = " + string(modernCipherSuitesJSON) + ";\n")
|
||||
}
|
||||
{
|
||||
intermediateCipherSuitesJSON, err := json.Marshal(sslconfigs.TLSIntermediateCipherSuites)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.WriteString("window.SSL_INTERMEDIATE_CIPHER_SUITES = " + string(intermediateCipherSuitesJSON) + ";\n")
|
||||
}
|
||||
{
|
||||
sslVersionsJSON, err := json.Marshal(sslconfigs.AllTlsVersions)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.WriteString("window.SSL_ALL_VERSIONS = " + string(sslVersionsJSON) + ";\n")
|
||||
}
|
||||
{
|
||||
clientAuthTypesJSON, err := json.Marshal(sslconfigs.AllSSLClientAuthTypes())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.WriteString("window.SSL_ALL_CLIENT_AUTH_TYPES = " + string(clientAuthTypesJSON) + ";\n")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
CertId int64
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.SSLCert_LogDeleteSSLCert, params.CertId)
|
||||
|
||||
// 是否正在被服务使用
|
||||
countResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("此证书正在被某些服务引用,请先修改服务后再删除。")
|
||||
}
|
||||
|
||||
// 是否正在被API节点使用
|
||||
countResp, err = this.RPC().APINodeRPC().CountAllEnabledAPINodesWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledAPINodesWithSSLCertIdRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("此证书正在被某些API节点引用,请先修改API节点后再删除")
|
||||
}
|
||||
|
||||
err = this.filterDelete(params.CertId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().SSLCertRPC().DeleteSSLCert(this.AdminContext(), &pb.DeleteSSLCertRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
|
||||
package certs
|
||||
|
||||
func (this *DeleteAction) filterDelete(certId int64) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package certs
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
func (this *DeleteAction) filterDelete(certId int64) error {
|
||||
// 是否正在被用户节点使用
|
||||
if teaconst.IsPlus {
|
||||
countResp, err := this.RPC().UserNodeRPC().CountAllEnabledUserNodesWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledUserNodesWithSSLCertIdRequest{SslCertId: certId})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("此证书正在被某些用户节点引用,请先修改相关用户节点后再删除")
|
||||
}
|
||||
}
|
||||
|
||||
// 是否正在被NS集群使用
|
||||
if teaconst.IsPlus {
|
||||
countResp, err := this.RPC().NSClusterRPC().CountAllNSClustersWithSSLCertId(this.AdminContext(), &pb.CountAllNSClustersWithSSLCertIdRequest{SslCertId: certId})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("此证书正在被某些DNS集群节点引用,请先修改相关DNS集群设置后再删除")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type DownloadCertAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DownloadCertAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *DownloadCertAction) RunGet(params struct {
|
||||
CertId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.SSLCert_LogDownloadSSLCert, params.CertId)
|
||||
|
||||
certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
certConfig := &sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(certResp.SslCertJSON, certConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"cert-"+strconv.FormatInt(params.CertId, 10)+".pem\";")
|
||||
_, _ = this.Write(certConfig.CertData)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type DownloadKeyAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DownloadKeyAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *DownloadKeyAction) RunGet(params struct {
|
||||
CertId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.SSLCert_LogDownloadSSLCertKey, params.CertId)
|
||||
|
||||
certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
certConfig := &sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(certResp.SslCertJSON, certConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"key-"+strconv.FormatInt(params.CertId, 10)+".pem\";")
|
||||
_, _ = this.Write(certConfig.KeyData)
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type DownloadZipAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DownloadZipAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *DownloadZipAction) RunGet(params struct {
|
||||
CertId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.SSLCert_LogDownloadSSLCertZip, params.CertId)
|
||||
|
||||
certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
certConfig := &sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(certResp.SslCertJSON, certConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
z := zip.NewWriter(this.ResponseWriter)
|
||||
defer func() {
|
||||
_ = z.Close()
|
||||
}()
|
||||
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"cert-"+strconv.FormatInt(params.CertId, 10)+".zip\";")
|
||||
|
||||
// cert
|
||||
{
|
||||
w, err := z.Create("cert.pem")
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = w.Write(certConfig.CertData)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
err = z.Flush()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// key
|
||||
if !certConfig.IsCA {
|
||||
w, err := z.Create("key.pem")
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = w.Write(certConfig.KeyData)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
err = z.Flush()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
helpers.LangHelper
|
||||
}
|
||||
|
||||
func NewHelper() *Helper {
|
||||
return &Helper{}
|
||||
}
|
||||
|
||||
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) {
|
||||
var action = actionPtr.Object()
|
||||
if action.Request.Method != http.MethodGet {
|
||||
return
|
||||
}
|
||||
|
||||
action.Data["teaMenu"] = "servers"
|
||||
|
||||
var countOCSP int64 = 0
|
||||
parentAction, ok := actionPtr.(actionutils.ActionInterface)
|
||||
if ok {
|
||||
countOCSPResp, err := parentAction.RPC().SSLCertRPC().CountAllSSLCertsWithOCSPError(parentAction.AdminContext(), &pb.CountAllSSLCertsWithOCSPErrorRequest{})
|
||||
if err == nil {
|
||||
countOCSP = countOCSPResp.Count
|
||||
}
|
||||
}
|
||||
|
||||
var ocspMenuName = this.Lang(actionPtr, codes.SSLCert_MenuOCSP)
|
||||
if countOCSP > 0 {
|
||||
ocspMenuName += "(" + types.String(countOCSP) + ")"
|
||||
}
|
||||
|
||||
var menu = []maps.Map{
|
||||
{
|
||||
"name": this.Lang(actionPtr, codes.SSLCert_MenuCerts),
|
||||
"url": "/servers/certs",
|
||||
"isActive": action.Data.GetString("leftMenuItem") == "cert",
|
||||
},
|
||||
{
|
||||
"name": this.Lang(actionPtr, codes.SSLCert_MenuApply),
|
||||
"url": "/servers/certs/acme",
|
||||
"isActive": action.Data.GetString("leftMenuItem") == "acme",
|
||||
},
|
||||
{
|
||||
"name": ocspMenuName,
|
||||
"url": "/servers/certs/ocsp",
|
||||
"isActive": action.Data.GetString("leftMenuItem") == "ocsp",
|
||||
},
|
||||
}
|
||||
action.Data["leftMenuItems"] = menu
|
||||
}
|
||||
285
EdgeAdmin/internal/web/actions/default/servers/certs/index.go
Normal file
285
EdgeAdmin/internal/web/actions/default/servers/certs/index.go
Normal file
@@ -0,0 +1,285 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.FirstMenu("index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
UserId int64
|
||||
Type string // [empty] | ca | 7days | ...
|
||||
Keyword string
|
||||
UserType string
|
||||
}) {
|
||||
this.Data["type"] = params.Type
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
if params.UserId > 0 {
|
||||
params.UserType = "user"
|
||||
}
|
||||
this.Data["userType"] = params.UserType
|
||||
|
||||
// 当前用户
|
||||
this.Data["searchingUserId"] = params.UserId
|
||||
var userMap = maps.Map{
|
||||
"id": 0,
|
||||
"username": "",
|
||||
"fullname": "",
|
||||
}
|
||||
if params.UserId > 0 {
|
||||
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.AdminContext(), &pb.FindEnabledUserRequest{UserId: params.UserId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var user = userResp.User
|
||||
if user != nil {
|
||||
userMap = maps.Map{
|
||||
"id": user.Id,
|
||||
"username": user.Username,
|
||||
"fullname": user.Fullname,
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["user"] = userMap
|
||||
|
||||
var countAll int64
|
||||
var countCA int64
|
||||
var countAvailable int64
|
||||
var countExpired int64
|
||||
var count7Days int64
|
||||
var count30Days int64
|
||||
|
||||
var userOnly = params.UserType == "user" || params.UserId > 0
|
||||
|
||||
// 计算数量
|
||||
{
|
||||
// all
|
||||
resp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countAll = resp.Count
|
||||
|
||||
// CA
|
||||
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
UserId: params.UserId,
|
||||
IsCA: true,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countCA = resp.Count
|
||||
|
||||
// available
|
||||
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
UserId: params.UserId,
|
||||
IsAvailable: true,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countAvailable = resp.Count
|
||||
|
||||
// expired
|
||||
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
UserId: params.UserId,
|
||||
IsExpired: true,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countExpired = resp.Count
|
||||
|
||||
// expire in 7 days
|
||||
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 7,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count7Days = resp.Count
|
||||
|
||||
// expire in 30 days
|
||||
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 30,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count30Days = resp.Count
|
||||
}
|
||||
|
||||
this.Data["countAll"] = countAll
|
||||
this.Data["countCA"] = countCA
|
||||
this.Data["countAvailable"] = countAvailable
|
||||
this.Data["countExpired"] = countExpired
|
||||
this.Data["count7Days"] = count7Days
|
||||
this.Data["count30Days"] = count30Days
|
||||
|
||||
// 分页
|
||||
var page *actionutils.Page
|
||||
var listResp *pb.ListSSLCertsResponse
|
||||
var err error
|
||||
switch params.Type {
|
||||
case "":
|
||||
page = this.NewPage(countAll)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "ca":
|
||||
page = this.NewPage(countCA)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
IsCA: true,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "available":
|
||||
page = this.NewPage(countAvailable)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
IsAvailable: true,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "expired":
|
||||
page = this.NewPage(countExpired)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
IsExpired: true,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "7days":
|
||||
page = this.NewPage(count7Days)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 7,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
case "30days":
|
||||
page = this.NewPage(count30Days)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 30,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
default:
|
||||
page = this.NewPage(countAll)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var certConfigs = []*sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(listResp.SslCertsJSON, &certConfigs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["certs"] = certConfigs
|
||||
|
||||
var certMaps = []maps.Map{}
|
||||
var nowTime = time.Now().Unix()
|
||||
for _, certConfig := range certConfigs {
|
||||
// count servers
|
||||
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{
|
||||
SslCertId: certConfig.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// user
|
||||
userResp, err := this.RPC().SSLCertRPC().FindSSLCertUser(this.AdminContext(), &pb.FindSSLCertUserRequest{SslCertId: certConfig.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var certUserMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userResp.User != nil {
|
||||
certUserMap = maps.Map{
|
||||
"id": userResp.User.Id,
|
||||
"username": userResp.User.Username,
|
||||
"fullname": userResp.User.Fullname,
|
||||
}
|
||||
}
|
||||
|
||||
certMaps = append(certMaps, maps.Map{
|
||||
"isOn": certConfig.IsOn,
|
||||
"beginDay": timeutil.FormatTime("Y-m-d", certConfig.TimeBeginAt),
|
||||
"endDay": timeutil.FormatTime("Y-m-d", certConfig.TimeEndAt),
|
||||
"isExpired": nowTime > certConfig.TimeEndAt,
|
||||
"isAvailable": nowTime <= certConfig.TimeEndAt,
|
||||
"countServers": countServersResp.Count,
|
||||
"user": certUserMap,
|
||||
})
|
||||
}
|
||||
this.Data["certInfos"] = certMaps
|
||||
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
73
EdgeAdmin/internal/web/actions/default/servers/certs/init.go
Normal file
73
EdgeAdmin/internal/web/actions/default/servers/certs/init.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/accounts"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/users"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/ocsp"
|
||||
"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)).
|
||||
Helper(NewHelper()).
|
||||
Data("teaMenu", "servers").
|
||||
Data("teaSubMenu", "cert").
|
||||
Prefix("/servers/certs").
|
||||
Data("leftMenuItem", "cert").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/uploadPopup", new(UploadPopupAction)).
|
||||
GetPost("/uploadBatchPopup", new(UploadBatchPopupAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
GetPost("/updatePopup", new(UpdatePopupAction)).
|
||||
Get("/certPopup", new(CertPopupAction)).
|
||||
Get("/viewKey", new(ViewKeyAction)).
|
||||
Get("/viewCert", new(ViewCertAction)).
|
||||
Get("/downloadKey", new(DownloadKeyAction)).
|
||||
Get("/downloadCert", new(DownloadCertAction)).
|
||||
Get("/downloadZip", new(DownloadZipAction)).
|
||||
Get("/selectPopup", new(SelectPopupAction)).
|
||||
Get("/datajs", new(DatajsAction)).
|
||||
|
||||
// ACME任务
|
||||
Prefix("/servers/certs/acme").
|
||||
Data("leftMenuItem", "acme").
|
||||
Get("", new(acme.IndexAction)).
|
||||
GetPost("/create", new(acme.CreateAction)).
|
||||
Post("/run", new(acme.RunAction)).
|
||||
GetPost("/updateTaskPopup", new(acme.UpdateTaskPopupAction)).
|
||||
Post("/deleteTask", new(acme.DeleteTaskAction)).
|
||||
Post("/userOptions", new(acme.UserOptionsAction)).
|
||||
|
||||
// ACME用户
|
||||
Prefix("/servers/certs/acme/users").
|
||||
Get("", new(users.IndexAction)).
|
||||
GetPost("/createPopup", new(users.CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(users.UpdatePopupAction)).
|
||||
Post("/delete", new(users.DeleteAction)).
|
||||
GetPost("/selectPopup", new(users.SelectPopupAction)).
|
||||
Post("/accountsWithCode", new(users.AccountsWithCodeAction)).
|
||||
|
||||
// ACME账号
|
||||
Prefix("/servers/certs/acme/accounts").
|
||||
Get("", new(accounts.IndexAction)).
|
||||
GetPost("/createPopup", new(accounts.CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(accounts.UpdatePopupAction)).
|
||||
Post("/delete", new(accounts.DeleteAction)).
|
||||
|
||||
// OCSP
|
||||
Prefix("/servers/certs/ocsp").
|
||||
Data("leftMenuItem", "ocsp").
|
||||
Get("", new(ocsp.IndexAction)).
|
||||
Post("/reset", new(ocsp.ResetAction)).
|
||||
Post("/resetAll", new(ocsp.ResetAllAction)).
|
||||
Post("/ignore", new(ocsp.IgnoreAction)).
|
||||
|
||||
//
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ocsp
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type IgnoreAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IgnoreAction) RunPost(params struct {
|
||||
CertIds []int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.SSLCert_LogOCSPIgnoreOCSPStatus)
|
||||
|
||||
_, err := this.RPC().SSLCertRPC().IgnoreSSLCertsWithOCSPError(this.AdminContext(), &pb.IgnoreSSLCertsWithOCSPErrorRequest{SslCertIds: params.CertIds})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ocsp
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.SecondMenu("ocsp")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Keyword string
|
||||
}) {
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
countResp, err := this.RPC().SSLCertRPC().CountAllSSLCertsWithOCSPError(this.AdminContext(), &pb.CountAllSSLCertsWithOCSPErrorRequest{Keyword: params.Keyword})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
certsResp, err := this.RPC().SSLCertRPC().ListSSLCertsWithOCSPError(this.AdminContext(), &pb.ListSSLCertsWithOCSPErrorRequest{
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var certMaps = []maps.Map{}
|
||||
for _, cert := range certsResp.SslCerts {
|
||||
certMaps = append(certMaps, maps.Map{
|
||||
"id": cert.Id,
|
||||
"isOn": cert.IsOn,
|
||||
"dnsNames": cert.DnsNames,
|
||||
"commonNames": cert.CommonNames,
|
||||
"hasOCSP": len(cert.Ocsp) > 0,
|
||||
"ocspIsUpdated": cert.OcspIsUpdated,
|
||||
"ocspError": cert.OcspError,
|
||||
"isCA": cert.IsCA,
|
||||
"isACME": cert.IsACME,
|
||||
"name": cert.Name,
|
||||
"isExpired": cert.TimeEndAt < time.Now().Unix(),
|
||||
"beginDay": timeutil.FormatTime("Y-m-d", cert.TimeBeginAt),
|
||||
"endDay": timeutil.FormatTime("Y-m-d", cert.TimeEndAt),
|
||||
})
|
||||
}
|
||||
this.Data["certs"] = certMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ocsp
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type ResetAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ResetAction) RunPost(params struct {
|
||||
CertIds []int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.SSLCert_LogOCSPResetOCSPStatus)
|
||||
|
||||
_, err := this.RPC().SSLCertRPC().ResetSSLCertsWithOCSPError(this.AdminContext(), &pb.ResetSSLCertsWithOCSPErrorRequest{SslCertIds: params.CertIds})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ocsp
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type ResetAllAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ResetAllAction) RunPost(params struct{}) {
|
||||
defer this.CreateLogInfo(codes.SSLCert_LogOCSPResetAllOCSPStatus)
|
||||
|
||||
_, err := this.RPC().SSLCertRPC().ResetAllSSLCertsWithOCSPError(this.AdminContext(), &pb.ResetAllSSLCertsWithOCSPErrorRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SelectPopupAction 选择证书
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunGet(params struct {
|
||||
ServerId int64 // 搜索的服务
|
||||
UserId int64 // 搜索的用户名
|
||||
SearchingDomains string // 搜索的域名
|
||||
SearchingType string // 搜索类型:match|all
|
||||
|
||||
ViewSize string
|
||||
SelectedCertIds string
|
||||
Keyword string
|
||||
}) {
|
||||
this.Data["searchingServerId"] = params.ServerId
|
||||
|
||||
// 服务相关
|
||||
if params.ServerId > 0 {
|
||||
serverResp, err := this.RPC().ServerRPC().FindEnabledUserServerBasic(this.AdminContext(), &pb.FindEnabledUserServerBasicRequest{ServerId: params.ServerId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var server = serverResp.Server
|
||||
if server != nil {
|
||||
if server.UserId > 0 {
|
||||
params.UserId = server.UserId
|
||||
}
|
||||
|
||||
// 读取所有ServerNames
|
||||
serverNamesResp, err := this.RPC().ServerRPC().FindServerNames(this.AdminContext(), &pb.FindServerNamesRequest{ServerId: params.ServerId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(serverNamesResp.ServerNamesJSON) > 0 {
|
||||
var serverNames = []*serverconfigs.ServerNameConfig{}
|
||||
err = json.Unmarshal(serverNamesResp.ServerNamesJSON, &serverNames)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
params.SearchingDomains = strings.Join(serverconfigs.PlainServerNames(serverNames), ",")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 用户相关
|
||||
this.Data["userId"] = params.UserId // 可变
|
||||
this.Data["searchingUserId"] = params.UserId
|
||||
|
||||
// 域名搜索相关
|
||||
var url = this.Request.URL.Path
|
||||
var query = this.Request.URL.Query()
|
||||
query.Del("searchingType")
|
||||
this.Data["baseURL"] = url + "?" + query.Encode()
|
||||
|
||||
var searchingDomains = []string{}
|
||||
if len(params.SearchingDomains) > 0 {
|
||||
searchingDomains = strings.Split(params.SearchingDomains, ",")
|
||||
}
|
||||
const maxDomains = 2_000 // 限制搜索的域名数量
|
||||
if len(searchingDomains) > maxDomains {
|
||||
searchingDomains = searchingDomains[:maxDomains]
|
||||
}
|
||||
this.Data["allSearchingDomains"] = params.SearchingDomains
|
||||
this.Data["searchingDomains"] = searchingDomains
|
||||
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["selectedCertIds"] = params.SelectedCertIds
|
||||
|
||||
var searchingType = params.SearchingType
|
||||
if len(searchingType) == 0 {
|
||||
if len(params.SearchingDomains) == 0 {
|
||||
searchingType = "all"
|
||||
} else {
|
||||
searchingType = "match"
|
||||
}
|
||||
}
|
||||
if searchingType != "all" && searchingType != "match" {
|
||||
this.ErrorPage(errors.New("invalid searching type '" + searchingType + "'"))
|
||||
return
|
||||
}
|
||||
this.Data["searchingType"] = searchingType
|
||||
|
||||
// 已经选择的证书
|
||||
var selectedCertIds = []string{}
|
||||
if len(params.SelectedCertIds) > 0 {
|
||||
selectedCertIds = strings.Split(params.SelectedCertIds, ",")
|
||||
}
|
||||
|
||||
if len(params.ViewSize) == 0 {
|
||||
params.ViewSize = "normal"
|
||||
}
|
||||
this.Data["viewSize"] = params.ViewSize
|
||||
|
||||
// 全部证书数量
|
||||
countAllResp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var totalAll = countAllResp.Count
|
||||
this.Data["totalAll"] = totalAll
|
||||
|
||||
// 已匹配证书数量
|
||||
var totalMatch int64 = 0
|
||||
if len(searchingDomains) > 0 {
|
||||
countMatchResp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
Domains: searchingDomains,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
totalMatch = countMatchResp.Count
|
||||
}
|
||||
this.Data["totalMatch"] = totalMatch
|
||||
|
||||
var totalCerts int64
|
||||
if searchingType == "all" {
|
||||
totalCerts = totalAll
|
||||
} else if searchingType == "match" {
|
||||
totalCerts = totalMatch
|
||||
}
|
||||
|
||||
var page = this.NewPage(totalCerts)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
var listResp *pb.ListSSLCertsResponse
|
||||
if searchingType == "all" {
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
} else if searchingType == "match" {
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
Domains: searchingDomains,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if listResp == nil {
|
||||
this.ErrorPage(errors.New("'listResp' should not be nil"))
|
||||
return
|
||||
}
|
||||
|
||||
var certConfigs = []*sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(listResp.SslCertsJSON, &certConfigs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["certs"] = certConfigs
|
||||
|
||||
var certMaps = []maps.Map{}
|
||||
var nowTime = time.Now().Unix()
|
||||
for _, certConfig := range certConfigs {
|
||||
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{SslCertId: certConfig.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
certMaps = append(certMaps, maps.Map{
|
||||
"beginDay": timeutil.FormatTime("Y-m-d", certConfig.TimeBeginAt),
|
||||
"endDay": timeutil.FormatTime("Y-m-d", certConfig.TimeEndAt),
|
||||
"isExpired": nowTime > certConfig.TimeEndAt,
|
||||
"isAvailable": nowTime <= certConfig.TimeEndAt,
|
||||
"countServers": countServersResp.Count,
|
||||
"isSelected": lists.ContainsString(selectedCertIds, numberutils.FormatInt64(certConfig.Id)),
|
||||
})
|
||||
}
|
||||
this.Data["certInfos"] = certMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
CertId int64
|
||||
}) {
|
||||
certConfigResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var certConfigJSON = certConfigResp.SslCertJSON
|
||||
if len(certConfigJSON) == 0 {
|
||||
this.NotFound("cert", params.CertId)
|
||||
return
|
||||
}
|
||||
|
||||
var certConfig = &sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(certConfigJSON, certConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
certConfig.CertData = nil // cert & key 不需要在界面上显示
|
||||
certConfig.KeyData = nil
|
||||
this.Data["certConfig"] = certConfig
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
CertId int64
|
||||
|
||||
TextMode bool
|
||||
|
||||
Name string
|
||||
IsCA bool
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
CertFile *actions.File
|
||||
KeyFile *actions.File
|
||||
|
||||
CertText string
|
||||
KeyText string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.SSLCert_LogUpdateSSLCert, params.CertId)
|
||||
|
||||
// 查询Cert
|
||||
certConfigResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var certConfigJSON = certConfigResp.SslCertJSON
|
||||
if len(certConfigJSON) == 0 {
|
||||
this.NotFound("cert", params.CertId)
|
||||
return
|
||||
}
|
||||
|
||||
var certConfig = &sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(certConfigJSON, certConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 校验参数
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入证书说明")
|
||||
|
||||
if params.TextMode {
|
||||
if len(params.CertText) > 0 {
|
||||
certConfig.CertData = []byte(params.CertText)
|
||||
}
|
||||
|
||||
if !params.IsCA {
|
||||
if len(params.KeyText) > 0 {
|
||||
certConfig.KeyData = []byte(params.KeyText)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if params.CertFile != nil {
|
||||
certConfig.CertData, err = params.CertFile.Read()
|
||||
if err != nil {
|
||||
this.FailField("certFile", "读取证书文件内容错误,请重新上传")
|
||||
}
|
||||
}
|
||||
|
||||
if !params.IsCA {
|
||||
if params.KeyFile != nil {
|
||||
certConfig.KeyData, err = params.KeyFile.Read()
|
||||
if err != nil {
|
||||
this.FailField("keyFile", "读取私钥文件内容错误,请重新上传")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 校验
|
||||
certConfig.IsCA = params.IsCA
|
||||
err = certConfig.Init(context.TODO())
|
||||
if err != nil {
|
||||
if params.IsCA {
|
||||
this.Fail("证书校验错误:" + err.Error())
|
||||
} else {
|
||||
this.Fail("证书或密钥校验错误:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if len(timeutil.Format("Y", certConfig.TimeEnd())) != 4 {
|
||||
this.Fail("证书格式错误:无法读取到证书有效期")
|
||||
}
|
||||
|
||||
if certConfig.TimeBeginAt < 0 {
|
||||
this.Fail("证书校验错误:有效期开始时间过小,不能小于1970年1月1日")
|
||||
}
|
||||
if certConfig.TimeEndAt < 0 {
|
||||
this.Fail("证书校验错误:有效期结束时间过小,不能小于1970年1月1日")
|
||||
}
|
||||
|
||||
// 保存
|
||||
_, err = this.RPC().SSLCertRPC().UpdateSSLCert(this.AdminContext(), &pb.UpdateSSLCertRequest{
|
||||
SslCertId: params.CertId,
|
||||
IsOn: params.IsOn,
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
ServerName: "",
|
||||
IsCA: params.IsCA,
|
||||
CertData: certConfig.CertData,
|
||||
KeyData: certConfig.KeyData,
|
||||
TimeBeginAt: certConfig.TimeBeginAt,
|
||||
TimeEndAt: certConfig.TimeEndAt,
|
||||
DnsNames: certConfig.DNSNames,
|
||||
CommonNames: certConfig.CommonNames,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package certs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UploadBatchPopupAction 批量上传证书
|
||||
type UploadBatchPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UploadBatchPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UploadBatchPopupAction) RunGet(params struct {
|
||||
ServerId int64
|
||||
UserId int64
|
||||
}) {
|
||||
// 读取服务用户
|
||||
if params.ServerId > 0 {
|
||||
serverResp, err := this.RPC().ServerRPC().FindEnabledUserServerBasic(this.AdminContext(), &pb.FindEnabledUserServerBasicRequest{ServerId: params.ServerId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var server = serverResp.Server
|
||||
if server != nil {
|
||||
params.UserId = server.UserId
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["userId"] = params.UserId
|
||||
this.Data["maxFiles"] = this.maxFiles()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UploadBatchPopupAction) RunPost(params struct {
|
||||
UserId int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.SSLCert_LogUploadSSLCertBatch)
|
||||
|
||||
var files = this.Request.MultipartForm.File["certFiles"]
|
||||
if len(files) == 0 {
|
||||
this.Fail("请选择要上传的证书和私钥文件")
|
||||
return
|
||||
}
|
||||
|
||||
// 限制每次上传的文件数量
|
||||
var maxFiles = this.maxFiles()
|
||||
if len(files) > maxFiles {
|
||||
this.Fail("每次上传最多不能超过" + types.String(maxFiles) + "个文件")
|
||||
return
|
||||
}
|
||||
|
||||
type certInfo struct {
|
||||
filename string
|
||||
data []byte
|
||||
}
|
||||
|
||||
var certDataList = []*certInfo{}
|
||||
var keyDataList = [][]byte{}
|
||||
|
||||
var failMessages = []string{}
|
||||
for _, file := range files {
|
||||
func(file *multipart.FileHeader) {
|
||||
fp, err := file.Open()
|
||||
if err != nil {
|
||||
failMessages = append(failMessages, "文件"+file.Filename+"读取失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = fp.Close()
|
||||
}()
|
||||
|
||||
data, err := io.ReadAll(fp)
|
||||
if err != nil {
|
||||
failMessages = append(failMessages, "文件"+file.Filename+"读取失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Contains(data, []byte("CERTIFICATE-")) {
|
||||
certDataList = append(certDataList, &certInfo{
|
||||
filename: file.Filename,
|
||||
data: data,
|
||||
})
|
||||
} else if bytes.Contains(data, []byte("PRIVATE KEY-")) {
|
||||
keyDataList = append(keyDataList, data)
|
||||
} else {
|
||||
failMessages = append(failMessages, "文件"+file.Filename+"读取失败:文件格式错误,无法识别是证书还是私钥")
|
||||
return
|
||||
}
|
||||
}(file)
|
||||
}
|
||||
|
||||
if len(failMessages) > 0 {
|
||||
this.Fail("发生了错误:" + strings.Join(failMessages, ";"))
|
||||
return
|
||||
}
|
||||
|
||||
// 对比证书和私钥数量是否一致
|
||||
if len(certDataList) != len(keyDataList) {
|
||||
this.Fail("证书文件数量(" + types.String(len(certDataList)) + ")和私钥文件数量(" + types.String(len(keyDataList)) + ")不一致")
|
||||
return
|
||||
}
|
||||
|
||||
// 自动匹配
|
||||
var pairs = [][2][]byte{} // [] { cert, key }
|
||||
var keyIndexMap = map[int]bool{} // 方便下面跳过已匹配的Key
|
||||
for _, cert := range certDataList {
|
||||
var found = false
|
||||
for keyIndex, keyData := range keyDataList {
|
||||
if keyIndexMap[keyIndex] {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := tls.X509KeyPair(cert.data, keyData)
|
||||
if err == nil {
|
||||
found = true
|
||||
pairs = append(pairs, [2][]byte{cert.data, keyData})
|
||||
keyIndexMap[keyIndex] = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
this.Fail("找不到" + cert.filename + "对应的私钥")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 组织 CertConfig
|
||||
var pbCerts = []*pb.CreateSSLCertsRequestCert{}
|
||||
var certConfigs = []*sslconfigs.SSLCertConfig{}
|
||||
for _, pair := range pairs {
|
||||
certData, keyData := pair[0], pair[1]
|
||||
|
||||
var certConfig = &sslconfigs.SSLCertConfig{
|
||||
IsCA: false,
|
||||
CertData: certData,
|
||||
KeyData: keyData,
|
||||
}
|
||||
err := certConfig.Init(context.TODO())
|
||||
if err != nil {
|
||||
this.Fail("证书验证失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
certConfigs = append(certConfigs, certConfig)
|
||||
|
||||
var certName = ""
|
||||
if len(certConfig.DNSNames) > 0 {
|
||||
certName = certConfig.DNSNames[0]
|
||||
if len(certConfig.DNSNames) > 1 {
|
||||
certName += "等" + types.String(len(certConfig.DNSNames)) + "个域名"
|
||||
}
|
||||
}
|
||||
certConfig.Name = certName
|
||||
|
||||
pbCerts = append(pbCerts, &pb.CreateSSLCertsRequestCert{
|
||||
IsOn: true,
|
||||
Name: certName,
|
||||
Description: "",
|
||||
ServerName: "",
|
||||
IsCA: false,
|
||||
CertData: certData,
|
||||
KeyData: keyData,
|
||||
TimeBeginAt: certConfig.TimeBeginAt,
|
||||
TimeEndAt: certConfig.TimeEndAt,
|
||||
DnsNames: certConfig.DNSNames,
|
||||
CommonNames: certConfig.CommonNames,
|
||||
})
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().SSLCertRPC().CreateSSLCerts(this.AdminContext(), &pb.CreateSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
SSLCerts: pbCerts,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var certIds = createResp.SslCertIds
|
||||
if len(certIds) != len(certConfigs) {
|
||||
this.Fail("上传成功但API返回的证书ID数量错误,请反馈给开发者")
|
||||
return
|
||||
}
|
||||
|
||||
// 返回数据
|
||||
this.Data["count"] = len(pbCerts)
|
||||
|
||||
var certRefs = []*sslconfigs.SSLCertRef{}
|
||||
for index, cert := range certConfigs {
|
||||
// ID
|
||||
cert.Id = certIds[index]
|
||||
|
||||
// 减少不必要的数据
|
||||
cert.CertData = nil
|
||||
cert.KeyData = nil
|
||||
|
||||
certRefs = append(certRefs, &sslconfigs.SSLCertRef{
|
||||
IsOn: true,
|
||||
CertId: cert.Id,
|
||||
})
|
||||
}
|
||||
this.Data["certs"] = certConfigs
|
||||
this.Data["certRefs"] = certRefs
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
|
||||
package certs
|
||||
|
||||
func (this *UploadBatchPopupAction) maxFiles() int {
|
||||
return 20
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package certs
|
||||
|
||||
import teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
|
||||
func (this *UploadBatchPopupAction) maxFiles() int {
|
||||
if !teaconst.IsPlus {
|
||||
return 20
|
||||
}
|
||||
return 10_000
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type UploadPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UploadPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UploadPopupAction) RunGet(params struct {
|
||||
ServerId int64
|
||||
UserId int64
|
||||
}) {
|
||||
// 读取服务用户
|
||||
if params.ServerId > 0 {
|
||||
serverResp, err := this.RPC().ServerRPC().FindEnabledUserServerBasic(this.AdminContext(), &pb.FindEnabledUserServerBasicRequest{ServerId: params.ServerId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var server = serverResp.Server
|
||||
if server != nil {
|
||||
params.UserId = server.UserId
|
||||
}
|
||||
}
|
||||
this.Data["userId"] = params.UserId
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UploadPopupAction) RunPost(params struct {
|
||||
UserId int64
|
||||
|
||||
TextMode bool
|
||||
Name string
|
||||
IsCA bool
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
CertFile *actions.File
|
||||
KeyFile *actions.File
|
||||
|
||||
CertText string
|
||||
KeyText string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入证书说明")
|
||||
|
||||
var certData []byte
|
||||
var keyData []byte
|
||||
|
||||
if params.TextMode {
|
||||
if len(params.CertText) == 0 {
|
||||
this.FailField("certText", "请输入证书内容")
|
||||
}
|
||||
|
||||
if !params.IsCA {
|
||||
if len(params.KeyText) == 0 {
|
||||
this.FailField("keyText", "请输入私钥内容")
|
||||
}
|
||||
}
|
||||
|
||||
certData = []byte(params.CertText)
|
||||
keyData = []byte(params.KeyText)
|
||||
} else {
|
||||
if params.CertFile == nil {
|
||||
this.FailField("certFile", "请选择要上传的证书文件")
|
||||
}
|
||||
var err error
|
||||
certData, err = params.CertFile.Read()
|
||||
if err != nil {
|
||||
this.FailField("certFile", "读取证书文件内容错误,请重新上传")
|
||||
}
|
||||
|
||||
if !params.IsCA {
|
||||
if params.KeyFile == nil {
|
||||
this.FailField("keyFile", "请选择要上传的私钥文件")
|
||||
} else {
|
||||
keyData, err = params.KeyFile.Read()
|
||||
if err != nil {
|
||||
this.FailField("keyFile", "读取密钥文件内容错误,请重新上传")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 校验
|
||||
var certConfig = &sslconfigs.SSLCertConfig{
|
||||
IsCA: params.IsCA,
|
||||
CertData: certData,
|
||||
KeyData: keyData,
|
||||
}
|
||||
err := certConfig.Init(context.TODO())
|
||||
if err != nil {
|
||||
if params.IsCA {
|
||||
this.Fail("证书校验错误:" + err.Error())
|
||||
} else {
|
||||
this.Fail("证书或密钥校验错误:" + err.Error())
|
||||
}
|
||||
}
|
||||
if len(timeutil.Format("Y", certConfig.TimeEnd())) != 4 {
|
||||
this.Fail("证书格式错误:无法读取到证书有效期")
|
||||
}
|
||||
|
||||
if certConfig.TimeBeginAt < 0 {
|
||||
this.Fail("证书校验错误:有效期开始时间过小,不能小于1970年1月1日")
|
||||
}
|
||||
if certConfig.TimeEndAt < 0 {
|
||||
this.Fail("证书校验错误:有效期结束时间过小,不能小于1970年1月1日")
|
||||
}
|
||||
|
||||
// 保存
|
||||
createResp, err := this.RPC().SSLCertRPC().CreateSSLCert(this.AdminContext(), &pb.CreateSSLCertRequest{
|
||||
IsOn: params.IsOn,
|
||||
UserId: params.UserId,
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
ServerName: "",
|
||||
IsCA: params.IsCA,
|
||||
CertData: certData,
|
||||
KeyData: keyData,
|
||||
TimeBeginAt: certConfig.TimeBeginAt,
|
||||
TimeEndAt: certConfig.TimeEndAt,
|
||||
DnsNames: certConfig.DNSNames,
|
||||
CommonNames: certConfig.CommonNames,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 查询已创建的证书并返回,方便调用者进行后续处理
|
||||
var certId = createResp.SslCertId
|
||||
configResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: certId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
certConfig = &sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(configResp.SslCertJSON, certConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
certConfig.CertData = nil // 去掉不必要的数据
|
||||
certConfig.KeyData = nil // 去掉不必要的数据
|
||||
this.Data["cert"] = certConfig
|
||||
this.Data["certRef"] = &sslconfigs.SSLCertRef{
|
||||
IsOn: true,
|
||||
CertId: certId,
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.SSLCert_LogUploadSSLCert, certId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
)
|
||||
|
||||
type ViewCertAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ViewCertAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *ViewCertAction) RunGet(params struct {
|
||||
CertId int64
|
||||
}) {
|
||||
certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(certResp.SslCertJSON) == 0 {
|
||||
this.NotFound("sslCert", params.CertId)
|
||||
return
|
||||
}
|
||||
|
||||
certConfig := &sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(certResp.SslCertJSON, certConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, _ = this.Write(certConfig.CertData)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
)
|
||||
|
||||
type ViewKeyAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ViewKeyAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *ViewKeyAction) RunGet(params struct {
|
||||
CertId int64
|
||||
}) {
|
||||
certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: params.CertId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
certConfig := &sslconfigs.SSLCertConfig{}
|
||||
err = json.Unmarshal(certResp.SslCertJSON, certConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, _ = this.Write(certConfig.KeyData)
|
||||
}
|
||||
29
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/deleteTask.go
vendored
Normal file
29
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/deleteTask.go
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteTaskAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteTaskAction) RunPost(params struct {
|
||||
TaskId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.HTTPCacheTask_LogDeleteHTTPCacheTask, params.TaskId)
|
||||
|
||||
_, err := this.RPC().HTTPCacheTaskRPC().DeleteHTTPCacheTask(this.AdminContext(), &pb.DeleteHTTPCacheTaskRequest{
|
||||
HttpCacheTaskId: params.TaskId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
98
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/fetch.go
vendored
Normal file
98
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/fetch.go
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FetchAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *FetchAction) Init() {
|
||||
this.Nav("", "", "fetch")
|
||||
}
|
||||
|
||||
func (this *FetchAction) RunGet(params struct{}) {
|
||||
// 初始化菜单数据
|
||||
err := InitMenu(this.Parent())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *FetchAction) RunPost(params struct {
|
||||
Keys string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.HTTPCacheTask_LogCreateHTTPCacheTaskFetch)
|
||||
|
||||
if len(params.Keys) == 0 {
|
||||
this.Fail("请输入要预热的Key列表")
|
||||
}
|
||||
|
||||
// 检查Key
|
||||
var realKeys = []string{}
|
||||
for _, key := range strings.Split(params.Keys, "\n") {
|
||||
key = strings.TrimSpace(key)
|
||||
if len(key) == 0 {
|
||||
continue
|
||||
}
|
||||
if lists.ContainsString(realKeys, key) {
|
||||
continue
|
||||
}
|
||||
realKeys = append(realKeys, key)
|
||||
}
|
||||
|
||||
if len(realKeys) == 0 {
|
||||
this.Fail("请输入要预热的Key列表")
|
||||
}
|
||||
|
||||
// 校验Key
|
||||
validateResp, err := this.RPC().HTTPCacheTaskKeyRPC().ValidateHTTPCacheTaskKeys(this.AdminContext(), &pb.ValidateHTTPCacheTaskKeysRequest{Keys: realKeys})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var failKeyMaps = []maps.Map{}
|
||||
if len(validateResp.FailKeys) > 0 {
|
||||
for _, key := range validateResp.FailKeys {
|
||||
failKeyMaps = append(failKeyMaps, maps.Map{
|
||||
"key": key.Key,
|
||||
"reason": cacheutils.KeyFailReason(key.ReasonCode),
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["failKeys"] = failKeyMaps
|
||||
if len(failKeyMaps) > 0 {
|
||||
this.Fail("有" + types.String(len(failKeyMaps)) + "个Key无法完成操作,请删除后重试")
|
||||
}
|
||||
|
||||
// 提交任务
|
||||
_, err = this.RPC().HTTPCacheTaskRPC().CreateHTTPCacheTask(this.AdminContext(), &pb.CreateHTTPCacheTaskRequest{
|
||||
Type: "fetch",
|
||||
KeyType: "key",
|
||||
Keys: realKeys,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
103
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/index.go
vendored
Normal file
103
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/index.go
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "purge")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
KeyType string
|
||||
}) {
|
||||
// 初始化菜单数据
|
||||
err := InitMenu(this.Parent())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["keyType"] = params.KeyType
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
KeyType string
|
||||
Keys string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.HTTPCacheTask_LogCreateHTTPCacheTaskPurge)
|
||||
|
||||
if len(params.Keys) == 0 {
|
||||
this.Fail("请输入要刷新的Key列表")
|
||||
}
|
||||
|
||||
// 检查Key
|
||||
var realKeys = []string{}
|
||||
for _, key := range strings.Split(params.Keys, "\n") {
|
||||
key = strings.TrimSpace(key)
|
||||
if len(key) == 0 {
|
||||
continue
|
||||
}
|
||||
if lists.ContainsString(realKeys, key) {
|
||||
continue
|
||||
}
|
||||
realKeys = append(realKeys, key)
|
||||
}
|
||||
|
||||
if len(realKeys) == 0 {
|
||||
this.Fail("请输入要刷新的Key列表")
|
||||
}
|
||||
|
||||
// 校验Key
|
||||
validateResp, err := this.RPC().HTTPCacheTaskKeyRPC().ValidateHTTPCacheTaskKeys(this.AdminContext(), &pb.ValidateHTTPCacheTaskKeysRequest{Keys: realKeys})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var failKeyMaps = []maps.Map{}
|
||||
if len(validateResp.FailKeys) > 0 {
|
||||
for _, key := range validateResp.FailKeys {
|
||||
failKeyMaps = append(failKeyMaps, maps.Map{
|
||||
"key": key.Key,
|
||||
"reason": cacheutils.KeyFailReason(key.ReasonCode),
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["failKeys"] = failKeyMaps
|
||||
if len(failKeyMaps) > 0 {
|
||||
this.Fail("有" + types.String(len(failKeyMaps)) + "个Key无法完成操作,请删除后重试")
|
||||
}
|
||||
|
||||
// 提交任务
|
||||
_, err = this.RPC().HTTPCacheTaskRPC().CreateHTTPCacheTask(this.AdminContext(), &pb.CreateHTTPCacheTaskRequest{
|
||||
Type: "purge",
|
||||
KeyType: params.KeyType,
|
||||
Keys: realKeys,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
24
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/init.go
vendored
Normal file
24
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/init.go
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package cache
|
||||
|
||||
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", "cacheBatch").
|
||||
Prefix("/servers/components/cache/batch").
|
||||
GetPost("", new(IndexAction)).
|
||||
GetPost("/fetch", new(FetchAction)).
|
||||
Get("/tasks", new(TasksAction)).
|
||||
GetPost("/task", new(TaskAction)).
|
||||
Post("/deleteTask", new(DeleteTaskAction)).
|
||||
Post("/resetTask", new(ResetTaskAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
27
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/resetTask.go
vendored
Normal file
27
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/resetTask.go
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type ResetTaskAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ResetTaskAction) RunPost(params struct {
|
||||
TaskId int64
|
||||
}) {
|
||||
this.CreateLogInfo(codes.HTTPCacheTask_LogResetHTTPCacheTask, params.TaskId)
|
||||
|
||||
_, err := this.RPC().HTTPCacheTaskRPC().ResetHTTPCacheTask(this.AdminContext(), &pb.ResetHTTPCacheTaskRequest{HttpCacheTaskId: params.TaskId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
137
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/task.go
vendored
Normal file
137
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/task.go
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type TaskAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TaskAction) Init() {
|
||||
this.Nav("", "", "task")
|
||||
}
|
||||
|
||||
func (this *TaskAction) RunGet(params struct {
|
||||
TaskId int64
|
||||
}) {
|
||||
// 初始化菜单数据
|
||||
err := InitMenu(this.Parent())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !this.readTask(params.TaskId) {
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *TaskAction) RunPost(params struct {
|
||||
TaskId int64
|
||||
}) {
|
||||
if !this.readTask(params.TaskId) {
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
|
||||
// 读取任务信息
|
||||
func (this *TaskAction) readTask(taskId int64) (ok bool) {
|
||||
taskResp, err := this.RPC().HTTPCacheTaskRPC().FindEnabledHTTPCacheTask(this.AdminContext(), &pb.FindEnabledHTTPCacheTaskRequest{HttpCacheTaskId: taskId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var task = taskResp.HttpCacheTask
|
||||
if task == nil {
|
||||
this.NotFound("HTTPCacheTask", taskId)
|
||||
return
|
||||
}
|
||||
|
||||
// 用户
|
||||
var userMap = maps.Map{"id": 0, "username": "", "fullname": ""}
|
||||
if task.User != nil {
|
||||
userMap = maps.Map{
|
||||
"id": task.User.Id,
|
||||
"username": task.User.Username,
|
||||
"fullname": task.User.Fullname,
|
||||
}
|
||||
}
|
||||
|
||||
// keys
|
||||
var keyMaps = []maps.Map{}
|
||||
for _, key := range task.HttpCacheTaskKeys {
|
||||
// 错误信息
|
||||
var errorMaps = []maps.Map{}
|
||||
|
||||
if len(key.ErrorsJSON) > 0 {
|
||||
var m = map[int64]string{}
|
||||
err = json.Unmarshal(key.ErrorsJSON, &m)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for nodeId, errString := range m {
|
||||
errorMaps = append(errorMaps, maps.Map{
|
||||
"nodeId": nodeId,
|
||||
"error": errString,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 错误信息排序
|
||||
if len(errorMaps) > 0 {
|
||||
sort.Slice(errorMaps, func(i, j int) bool {
|
||||
var m1 = errorMaps[i]
|
||||
var m2 = errorMaps[j]
|
||||
|
||||
return m1.GetInt64("nodeId") < m2.GetInt64("nodeId")
|
||||
})
|
||||
}
|
||||
|
||||
// 集群信息
|
||||
var clusterMap = maps.Map{
|
||||
"id": 0,
|
||||
"name": "",
|
||||
}
|
||||
if key.NodeCluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": key.NodeCluster.Id,
|
||||
"name": key.NodeCluster.Name,
|
||||
}
|
||||
}
|
||||
|
||||
keyMaps = append(keyMaps, maps.Map{
|
||||
"key": key.Key,
|
||||
"isDone": key.IsDone,
|
||||
"isDoing": key.IsDoing,
|
||||
"errors": errorMaps,
|
||||
"cluster": clusterMap,
|
||||
})
|
||||
}
|
||||
|
||||
this.Data["task"] = maps.Map{
|
||||
"id": task.Id,
|
||||
"type": task.Type,
|
||||
"keyType": task.KeyType,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", task.CreatedAt),
|
||||
"doneTime": timeutil.FormatTime("Y-m-d H:i:s", task.DoneAt),
|
||||
"isDone": task.IsDone,
|
||||
"isOk": task.IsOk,
|
||||
"keys": keyMaps,
|
||||
"user": userMap,
|
||||
}
|
||||
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
73
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/tasks.go
vendored
Normal file
73
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/tasks.go
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type TasksAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TasksAction) Init() {
|
||||
this.Nav("", "", "task")
|
||||
}
|
||||
|
||||
func (this *TasksAction) RunGet(params struct{}) {
|
||||
// 初始化菜单数据
|
||||
err := InitMenu(this.Parent())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 任务数量
|
||||
countResp, err := this.RPC().HTTPCacheTaskRPC().CountHTTPCacheTasks(this.AdminContext(), &pb.CountHTTPCacheTasksRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
// 任务列表
|
||||
var taskMaps = []maps.Map{}
|
||||
tasksResp, err := this.RPC().HTTPCacheTaskRPC().ListHTTPCacheTasks(this.AdminContext(), &pb.ListHTTPCacheTasksRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, task := range tasksResp.HttpCacheTasks {
|
||||
var userMap = maps.Map{"id": 0, "username": "", "fullname": ""}
|
||||
if task.User != nil {
|
||||
userMap = maps.Map{
|
||||
"id": task.User.Id,
|
||||
"username": task.User.Username,
|
||||
"fullname": task.User.Fullname,
|
||||
}
|
||||
}
|
||||
|
||||
taskMaps = append(taskMaps, maps.Map{
|
||||
"id": task.Id,
|
||||
"type": task.Type,
|
||||
"keyType": task.KeyType,
|
||||
"isDone": task.IsDone,
|
||||
"isOk": task.IsOk,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", task.CreatedAt),
|
||||
"description": task.Description,
|
||||
"user": userMap,
|
||||
})
|
||||
}
|
||||
|
||||
this.Data["tasks"] = taskMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
24
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/utils.go
vendored
Normal file
24
EdgeAdmin/internal/web/actions/default/servers/components/cache/batch/utils.go
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
func InitMenu(parent *actionutils.ParentAction) error {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
countTasksResp, err := rpcClient.HTTPCacheTaskRPC().CountDoingHTTPCacheTasks(parent.AdminContext(), &pb.CountDoingHTTPCacheTasksRequest{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parent.Data["countDoingTasks"] = countTasksResp.Count
|
||||
return nil
|
||||
}
|
||||
56
EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils/utils.go
vendored
Normal file
56
EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils/utils.go
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package cacheutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
)
|
||||
|
||||
// FindCachePolicyNameWithoutError 查找缓存策略名称并忽略错误
|
||||
func FindCachePolicyNameWithoutError(parent *actionutils.ParentAction, cachePolicyId int64) string {
|
||||
policy, err := FindCachePolicy(parent, cachePolicyId)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if policy == nil {
|
||||
return ""
|
||||
}
|
||||
return policy.Name
|
||||
}
|
||||
|
||||
// FindCachePolicy 查找缓存策略配置
|
||||
func FindCachePolicy(parent *actionutils.ParentAction, cachePolicyId int64) (*serverconfigs.HTTPCachePolicy, error) {
|
||||
resp, err := parent.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(parent.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{HttpCachePolicyId: cachePolicyId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(resp.HttpCachePolicyJSON) == 0 {
|
||||
return nil, errors.New("cache policy not found")
|
||||
}
|
||||
var config = &serverconfigs.HTTPCachePolicy{}
|
||||
err = json.Unmarshal(resp.HttpCachePolicyJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// KeyFailReason Key相关失败原因
|
||||
func KeyFailReason(reasonCode string) string {
|
||||
switch reasonCode {
|
||||
case "requireKey":
|
||||
return "空的Key"
|
||||
case "requireDomain":
|
||||
return "找不到Key对应的域名"
|
||||
case "requireServer":
|
||||
return "找不到Key对应的网站"
|
||||
case "requireUser":
|
||||
return "该域名不属于当前用户"
|
||||
case "requireClusterId":
|
||||
return "该网站没有部署到集群"
|
||||
}
|
||||
return "未知错误"
|
||||
}
|
||||
98
EdgeAdmin/internal/web/actions/default/servers/components/cache/clean.go
vendored
Normal file
98
EdgeAdmin/internal/web/actions/default/servers/components/cache/clean.go
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type CleanAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CleanAction) Init() {
|
||||
this.Nav("", "", "clean")
|
||||
}
|
||||
|
||||
func (this *CleanAction) RunGet(params struct {
|
||||
CachePolicyId int64
|
||||
}) {
|
||||
// 默认的集群ID
|
||||
cookie, err := this.Request.Cookie("cache_cluster_id")
|
||||
if cookie != nil && err == nil {
|
||||
this.Data["clusterId"] = types.Int64(cookie.Value)
|
||||
}
|
||||
|
||||
// 集群列表
|
||||
clustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClustersWithHTTPCachePolicyId(this.AdminContext(), &pb.FindAllEnabledNodeClustersWithHTTPCachePolicyIdRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
clusterMaps := []maps.Map{}
|
||||
for _, cluster := range clustersResp.NodeClusters {
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
this.Data["clusters"] = clusterMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CleanAction) RunPost(params struct {
|
||||
CachePolicyId int64
|
||||
ClusterId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 记录clusterId
|
||||
this.AddCookie(&http.Cookie{
|
||||
Name: "cache_cluster_id",
|
||||
Value: strconv.FormatInt(params.ClusterId, 10),
|
||||
})
|
||||
|
||||
cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cachePolicyJSON := cachePolicyResp.HttpCachePolicyJSON
|
||||
if len(cachePolicyJSON) == 0 {
|
||||
this.Fail("找不到要操作的缓存策略")
|
||||
}
|
||||
|
||||
// 发送命令
|
||||
msg := &messageconfigs.CleanCacheMessage{
|
||||
CachePolicyJSON: cachePolicyJSON,
|
||||
}
|
||||
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeCleanCache, msg, 60, false)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
isAllOk := true
|
||||
for _, result := range results {
|
||||
if !result.IsOK {
|
||||
isAllOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["isAllOk"] = isAllOk
|
||||
this.Data["results"] = results
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.ServerCachePolicy_LogCleanAll, params.CachePolicyId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
22
EdgeAdmin/internal/web/actions/default/servers/components/cache/count.go
vendored
Normal file
22
EdgeAdmin/internal/web/actions/default/servers/components/cache/count.go
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
// 计算可用缓存策略数量
|
||||
type CountAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CountAction) RunPost(params struct{}) {
|
||||
countResp, err := this.RPC().HTTPCachePolicyRPC().CountAllEnabledHTTPCachePolicies(this.AdminContext(), &pb.CountAllEnabledHTTPCachePoliciesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["count"] = countResp.Count
|
||||
|
||||
this.Success()
|
||||
}
|
||||
142
EdgeAdmin/internal/web/actions/default/servers/components/cache/createPopup.go
vendored
Normal file
142
EdgeAdmin/internal/web/actions/default/servers/components/cache/createPopup.go
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"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{}) {
|
||||
this.Data["types"] = serverconfigs.AllCachePolicyStorageTypes
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
Type string
|
||||
|
||||
// file
|
||||
FileDir string
|
||||
FileMemoryCapacityJSON []byte
|
||||
FileOpenFileCacheMax int
|
||||
FileEnableSendfile bool
|
||||
FileMinFreeSizeJSON []byte
|
||||
|
||||
CapacityJSON []byte
|
||||
MaxSizeJSON []byte
|
||||
FetchTimeoutJSON []byte
|
||||
SyncCompressionCache bool
|
||||
EnableMMAP bool
|
||||
EnableIncompletePartialContent bool
|
||||
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入策略名称")
|
||||
|
||||
// 校验选项
|
||||
var options any
|
||||
switch params.Type {
|
||||
case serverconfigs.CachePolicyStorageFile:
|
||||
params.Must.
|
||||
Field("fileDir", params.FileDir).
|
||||
Require("请输入缓存目录")
|
||||
|
||||
var memoryCapacity = &shared.SizeCapacity{}
|
||||
if len(params.FileMemoryCapacityJSON) > 0 {
|
||||
err := json.Unmarshal(params.FileMemoryCapacityJSON, memoryCapacity)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var openFileCacheConfig *serverconfigs.OpenFileCacheConfig
|
||||
if params.FileOpenFileCacheMax > 0 {
|
||||
openFileCacheConfig = &serverconfigs.OpenFileCacheConfig{
|
||||
IsOn: true,
|
||||
Max: params.FileOpenFileCacheMax,
|
||||
}
|
||||
}
|
||||
|
||||
var minFreeSize = &shared.SizeCapacity{}
|
||||
var minFreeSizeJSON = params.FileMinFreeSizeJSON
|
||||
if !utils.JSONIsNull(minFreeSizeJSON) {
|
||||
_, err := utils.JSONDecodeConfig(minFreeSizeJSON, minFreeSize)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if minFreeSize.Count < 0 {
|
||||
minFreeSize.Count = 0
|
||||
}
|
||||
}
|
||||
|
||||
options = &serverconfigs.HTTPFileCacheStorage{
|
||||
Dir: params.FileDir,
|
||||
MemoryPolicy: &serverconfigs.HTTPCachePolicy{
|
||||
Capacity: memoryCapacity,
|
||||
},
|
||||
OpenFileCache: openFileCacheConfig,
|
||||
EnableSendfile: params.FileEnableSendfile,
|
||||
MinFreeSize: minFreeSize,
|
||||
EnableMMAP: params.EnableMMAP,
|
||||
EnableIncompletePartialContent: params.EnableIncompletePartialContent,
|
||||
}
|
||||
case serverconfigs.CachePolicyStorageMemory:
|
||||
options = &serverconfigs.HTTPMemoryCacheStorage{}
|
||||
default:
|
||||
this.Fail("请选择正确的缓存类型")
|
||||
}
|
||||
|
||||
optionsJSON, err := json.Marshal(options)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
createResp, err := this.RPC().HTTPCachePolicyRPC().CreateHTTPCachePolicy(this.AdminContext(), &pb.CreateHTTPCachePolicyRequest{
|
||||
IsOn: params.IsOn,
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
CapacityJSON: params.CapacityJSON,
|
||||
MaxSizeJSON: params.MaxSizeJSON,
|
||||
FetchTimeoutJSON: params.FetchTimeoutJSON,
|
||||
Type: params.Type,
|
||||
OptionsJSON: optionsJSON,
|
||||
SyncCompressionCache: params.SyncCompressionCache,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 返回数据
|
||||
this.Data["cachePolicy"] = maps.Map{
|
||||
"id": createResp.HttpCachePolicyId,
|
||||
"name": params.Name,
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.ServerCachePolicy_LogCreateCachePolicy, createResp.HttpCachePolicyId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
36
EdgeAdmin/internal/web/actions/default/servers/components/cache/delete.go
vendored
Normal file
36
EdgeAdmin/internal/web/actions/default/servers/components/cache/delete.go
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
CachePolicyId int64
|
||||
}) {
|
||||
// 检查是否被引用
|
||||
countResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClustersWithHTTPCachePolicyId(this.AdminContext(), &pb.CountAllEnabledNodeClustersWithHTTPCachePolicyIdRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("此缓存策略正在被有些集群引用,请修改后再删除。")
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPCachePolicyRPC().DeleteHTTPCachePolicy(this.AdminContext(), &pb.DeleteHTTPCachePolicyRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.ServerCachePolicy_LogDeleteCachePolicy, params.CachePolicyId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
128
EdgeAdmin/internal/web/actions/default/servers/components/cache/fetch.go
vendored
Normal file
128
EdgeAdmin/internal/web/actions/default/servers/components/cache/fetch.go
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FetchAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *FetchAction) Init() {
|
||||
this.Nav("", "", "fetch")
|
||||
}
|
||||
|
||||
func (this *FetchAction) RunGet(params struct {
|
||||
CachePolicyId int64
|
||||
}) {
|
||||
// 默认的集群ID
|
||||
cookie, err := this.Request.Cookie("cache_cluster_id")
|
||||
if cookie != nil && err == nil {
|
||||
this.Data["clusterId"] = types.Int64(cookie.Value)
|
||||
}
|
||||
|
||||
// 集群列表
|
||||
clustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClustersWithHTTPCachePolicyId(this.AdminContext(), &pb.FindAllEnabledNodeClustersWithHTTPCachePolicyIdRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
clusterMaps := []maps.Map{}
|
||||
for _, cluster := range clustersResp.NodeClusters {
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
this.Data["clusters"] = clusterMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *FetchAction) RunPost(params struct {
|
||||
CachePolicyId int64
|
||||
ClusterId int64
|
||||
Keys string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.ServerCachePolicy_LogFetchCaches, params.CachePolicyId)
|
||||
|
||||
// 记录clusterId
|
||||
this.AddCookie(&http.Cookie{
|
||||
Name: "cache_cluster_id",
|
||||
Value: strconv.FormatInt(params.ClusterId, 10),
|
||||
})
|
||||
|
||||
cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cachePolicyJSON := cachePolicyResp.HttpCachePolicyJSON
|
||||
if len(cachePolicyJSON) == 0 {
|
||||
this.Fail("找不到要操作的缓存策略")
|
||||
}
|
||||
|
||||
if len(params.Keys) == 0 {
|
||||
this.Fail("请输入要预热的Key列表")
|
||||
}
|
||||
|
||||
realKeys := []string{}
|
||||
for _, key := range strings.Split(params.Keys, "\n") {
|
||||
key = strings.TrimSpace(key)
|
||||
if len(key) == 0 {
|
||||
continue
|
||||
}
|
||||
if lists.ContainsString(realKeys, key) {
|
||||
continue
|
||||
}
|
||||
realKeys = append(realKeys, key)
|
||||
}
|
||||
|
||||
// 校验Key
|
||||
// 这里暂时不校验服务ID
|
||||
validateResp, err := this.RPC().HTTPCacheTaskKeyRPC().ValidateHTTPCacheTaskKeys(this.AdminContext(), &pb.ValidateHTTPCacheTaskKeysRequest{Keys: realKeys})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var failKeyMaps = []maps.Map{}
|
||||
if len(validateResp.FailKeys) > 0 {
|
||||
for _, key := range validateResp.FailKeys {
|
||||
failKeyMaps = append(failKeyMaps, maps.Map{
|
||||
"key": key.Key,
|
||||
"reason": cacheutils.KeyFailReason(key.ReasonCode),
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["failKeys"] = failKeyMaps
|
||||
if len(failKeyMaps) > 0 {
|
||||
this.Fail("有" + types.String(len(failKeyMaps)) + "个Key无法完成操作,请删除后重试")
|
||||
}
|
||||
|
||||
// 提交任务
|
||||
_, err = this.RPC().HTTPCacheTaskRPC().CreateHTTPCacheTask(this.AdminContext(), &pb.CreateHTTPCacheTaskRequest{
|
||||
Type: "fetch",
|
||||
KeyType: "key",
|
||||
Keys: realKeys,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
36
EdgeAdmin/internal/web/actions/default/servers/components/cache/helper.go
vendored
Normal file
36
EdgeAdmin/internal/web/actions/default/servers/components/cache/helper.go
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
}
|
||||
|
||||
func NewHelper() *Helper {
|
||||
return &Helper{}
|
||||
}
|
||||
|
||||
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) {
|
||||
action := actionPtr.Object()
|
||||
if action.Request.Method != http.MethodGet {
|
||||
return
|
||||
}
|
||||
|
||||
action.Data["mainTab"] = "component"
|
||||
action.Data["secondMenuItem"] = "cache"
|
||||
|
||||
cachePolicyId := action.ParamInt64("cachePolicyId")
|
||||
action.Data["cachePolicyId"] = cachePolicyId
|
||||
|
||||
parentActionObj, ok := actionPtr.(interface {
|
||||
Parent() *actionutils.ParentAction
|
||||
})
|
||||
if ok {
|
||||
var parentAction = parentActionObj.Parent()
|
||||
action.Data["cachePolicyName"] = cacheutils.FindCachePolicyNameWithoutError(parentAction, cachePolicyId)
|
||||
}
|
||||
}
|
||||
81
EdgeAdmin/internal/web/actions/default/servers/components/cache/index.go
vendored
Normal file
81
EdgeAdmin/internal/web/actions/default/servers/components/cache/index.go
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.FirstMenu("index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
Keyword string
|
||||
StorageType string
|
||||
}) {
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["storageType"] = params.StorageType
|
||||
|
||||
countResp, err := this.RPC().HTTPCachePolicyRPC().CountAllEnabledHTTPCachePolicies(this.AdminContext(), &pb.CountAllEnabledHTTPCachePoliciesRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Keyword: params.Keyword,
|
||||
Type: params.StorageType,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
listResp, err := this.RPC().HTTPCachePolicyRPC().ListEnabledHTTPCachePolicies(this.AdminContext(), &pb.ListEnabledHTTPCachePoliciesRequest{
|
||||
Keyword: params.Keyword,
|
||||
NodeClusterId: params.ClusterId,
|
||||
Type: params.StorageType,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cachePoliciesJSON := listResp.HttpCachePoliciesJSON
|
||||
cachePolicies := []*serverconfigs.HTTPCachePolicy{}
|
||||
err = json.Unmarshal(cachePoliciesJSON, &cachePolicies)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["cachePolicies"] = cachePolicies
|
||||
|
||||
infos := []maps.Map{}
|
||||
for _, cachePolicy := range cachePolicies {
|
||||
countClustersResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClustersWithHTTPCachePolicyId(this.AdminContext(), &pb.CountAllEnabledNodeClustersWithHTTPCachePolicyIdRequest{HttpCachePolicyId: cachePolicy.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countClusters := countClustersResp.Count
|
||||
|
||||
infos = append(infos, maps.Map{
|
||||
"typeName": serverconfigs.FindCachePolicyStorageName(cachePolicy.Type),
|
||||
"countClusters": countClusters,
|
||||
})
|
||||
}
|
||||
this.Data["infos"] = infos
|
||||
|
||||
// 所有的存储类型
|
||||
this.Data["storageTypes"] = serverconfigs.AllCachePolicyStorageTypes
|
||||
|
||||
this.Show()
|
||||
}
|
||||
34
EdgeAdmin/internal/web/actions/default/servers/components/cache/init.go
vendored
Normal file
34
EdgeAdmin/internal/web/actions/default/servers/components/cache/init.go
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package cache
|
||||
|
||||
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)).
|
||||
Helper(NewHelper()).
|
||||
Data("teaMenu", "servers").
|
||||
Data("teaSubMenu", "cache").
|
||||
Prefix("/servers/components/cache").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
Get("/policy", new(PolicyAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
GetPost("/clean", new(CleanAction)).
|
||||
GetPost("/fetch", new(FetchAction)).
|
||||
GetPost("/purge", new(PurgeAction)).
|
||||
GetPost("/stat", new(StatAction)).
|
||||
GetPost("/test", new(TestAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Post("/testRead", new(TestReadAction)).
|
||||
Post("/testWrite", new(TestWriteAction)).
|
||||
Get("/selectPopup", new(SelectPopupAction)).
|
||||
Post("/count", new(CountAction)).
|
||||
Post("/updateRefs", new(UpdateRefsAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
53
EdgeAdmin/internal/web/actions/default/servers/components/cache/policy.go
vendored
Normal file
53
EdgeAdmin/internal/web/actions/default/servers/components/cache/policy.go
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type PolicyAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *PolicyAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *PolicyAction) RunGet(params struct {
|
||||
CachePolicyId int64
|
||||
}) {
|
||||
cachePolicy, err := cacheutils.FindCachePolicy(this.Parent(), params.CachePolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["cachePolicy"] = cachePolicy
|
||||
|
||||
// 预热超时时间
|
||||
this.Data["fetchTimeoutString"] = ""
|
||||
if cachePolicy.FetchTimeout != nil && cachePolicy.FetchTimeout.Count > 0 {
|
||||
this.Data["fetchTimeoutString"] = cachePolicy.FetchTimeout.Description()
|
||||
}
|
||||
|
||||
this.Data["typeName"] = serverconfigs.FindCachePolicyStorageName(cachePolicy.Type)
|
||||
|
||||
// 正在使用此策略的集群
|
||||
clustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClustersWithHTTPCachePolicyId(this.AdminContext(), &pb.FindAllEnabledNodeClustersWithHTTPCachePolicyIdRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var clusterMaps = []maps.Map{}
|
||||
for _, cluster := range clustersResp.NodeClusters {
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
this.Data["clusters"] = clusterMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
126
EdgeAdmin/internal/web/actions/default/servers/components/cache/purge.go
vendored
Normal file
126
EdgeAdmin/internal/web/actions/default/servers/components/cache/purge.go
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type PurgeAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *PurgeAction) Init() {
|
||||
this.Nav("", "", "purge")
|
||||
}
|
||||
|
||||
func (this *PurgeAction) RunGet(params struct {
|
||||
CachePolicyId int64
|
||||
}) {
|
||||
// 默认的集群ID
|
||||
cookie, err := this.Request.Cookie("cache_cluster_id")
|
||||
if cookie != nil && err == nil {
|
||||
this.Data["clusterId"] = types.Int64(cookie.Value)
|
||||
}
|
||||
|
||||
// 集群列表
|
||||
clustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClustersWithHTTPCachePolicyId(this.AdminContext(), &pb.FindAllEnabledNodeClustersWithHTTPCachePolicyIdRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
clusterMaps := []maps.Map{}
|
||||
for _, cluster := range clustersResp.NodeClusters {
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
this.Data["clusters"] = clusterMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *PurgeAction) RunPost(params struct {
|
||||
CachePolicyId int64
|
||||
ClusterId int64
|
||||
KeyType string
|
||||
Keys string
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.ServerCachePolicy_LogPurgeCaches, params.CachePolicyId)
|
||||
|
||||
// 记录clusterId
|
||||
this.AddCookie(&http.Cookie{
|
||||
Name: "cache_cluster_id",
|
||||
Value: strconv.FormatInt(params.ClusterId, 10),
|
||||
})
|
||||
|
||||
cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cachePolicyJSON := cachePolicyResp.HttpCachePolicyJSON
|
||||
if len(cachePolicyJSON) == 0 {
|
||||
this.Fail("找不到要操作的缓存策略")
|
||||
}
|
||||
|
||||
if len(params.Keys) == 0 {
|
||||
this.Fail("请输入要删除的Key列表")
|
||||
}
|
||||
|
||||
realKeys := []string{}
|
||||
for _, key := range strings.Split(params.Keys, "\n") {
|
||||
key = strings.TrimSpace(key)
|
||||
if len(key) == 0 {
|
||||
continue
|
||||
}
|
||||
if lists.ContainsString(realKeys, key) {
|
||||
continue
|
||||
}
|
||||
realKeys = append(realKeys, key)
|
||||
}
|
||||
// 校验Key
|
||||
validateResp, err := this.RPC().HTTPCacheTaskKeyRPC().ValidateHTTPCacheTaskKeys(this.AdminContext(), &pb.ValidateHTTPCacheTaskKeysRequest{Keys: realKeys})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var failKeyMaps = []maps.Map{}
|
||||
if len(validateResp.FailKeys) > 0 {
|
||||
for _, key := range validateResp.FailKeys {
|
||||
failKeyMaps = append(failKeyMaps, maps.Map{
|
||||
"key": key.Key,
|
||||
"reason": cacheutils.KeyFailReason(key.ReasonCode),
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["failKeys"] = failKeyMaps
|
||||
if len(failKeyMaps) > 0 {
|
||||
this.Fail("有" + types.String(len(failKeyMaps)) + "个Key无法完成操作,请删除后重试")
|
||||
}
|
||||
|
||||
// 提交任务
|
||||
_, err = this.RPC().HTTPCacheTaskRPC().CreateHTTPCacheTask(this.AdminContext(), &pb.CreateHTTPCacheTaskRequest{
|
||||
Type: "purge",
|
||||
KeyType: params.KeyType,
|
||||
Keys: realKeys,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
60
EdgeAdmin/internal/web/actions/default/servers/components/cache/selectPopup.go
vendored
Normal file
60
EdgeAdmin/internal/web/actions/default/servers/components/cache/selectPopup.go
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().HTTPCachePolicyRPC().CountAllEnabledHTTPCachePolicies(this.AdminContext(), &pb.CountAllEnabledHTTPCachePoliciesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
cachePoliciesResp, err := this.RPC().HTTPCachePolicyRPC().ListEnabledHTTPCachePolicies(this.AdminContext(), &pb.ListEnabledHTTPCachePoliciesRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cachePolicies := []*serverconfigs.HTTPCachePolicy{}
|
||||
if len(cachePoliciesResp.HttpCachePoliciesJSON) > 0 {
|
||||
err = json.Unmarshal(cachePoliciesResp.HttpCachePoliciesJSON, &cachePolicies)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
policyMaps := []maps.Map{}
|
||||
for _, cachePolicy := range cachePolicies {
|
||||
policyMaps = append(policyMaps, maps.Map{
|
||||
"id": cachePolicy.Id,
|
||||
"name": cachePolicy.Name,
|
||||
"description": cachePolicy.Description,
|
||||
"isOn": cachePolicy.IsOn,
|
||||
})
|
||||
}
|
||||
|
||||
this.Data["cachePolicies"] = policyMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
98
EdgeAdmin/internal/web/actions/default/servers/components/cache/stat.go
vendored
Normal file
98
EdgeAdmin/internal/web/actions/default/servers/components/cache/stat.go
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type StatAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StatAction) Init() {
|
||||
this.Nav("", "", "stat")
|
||||
}
|
||||
|
||||
func (this *StatAction) RunGet(params struct {
|
||||
CachePolicyId int64
|
||||
}) {
|
||||
// 默认的集群ID
|
||||
cookie, err := this.Request.Cookie("cache_cluster_id")
|
||||
if cookie != nil && err == nil {
|
||||
this.Data["clusterId"] = types.Int64(cookie.Value)
|
||||
}
|
||||
|
||||
// 集群列表
|
||||
clustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClustersWithHTTPCachePolicyId(this.AdminContext(), &pb.FindAllEnabledNodeClustersWithHTTPCachePolicyIdRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
clusterMaps := []maps.Map{}
|
||||
for _, cluster := range clustersResp.NodeClusters {
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
this.Data["clusters"] = clusterMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *StatAction) RunPost(params struct {
|
||||
CachePolicyId int64
|
||||
ClusterId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 记录clusterId
|
||||
this.AddCookie(&http.Cookie{
|
||||
Name: "cache_cluster_id",
|
||||
Value: strconv.FormatInt(params.ClusterId, 10),
|
||||
})
|
||||
|
||||
cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cachePolicyJSON := cachePolicyResp.HttpCachePolicyJSON
|
||||
if len(cachePolicyJSON) == 0 {
|
||||
this.Fail("找不到要操作的缓存策略")
|
||||
}
|
||||
|
||||
// 发送命令
|
||||
msg := &messageconfigs.StatCacheMessage{
|
||||
CachePolicyJSON: cachePolicyJSON,
|
||||
}
|
||||
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeStatCache, msg, 10, false)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
isAllOk := true
|
||||
for _, result := range results {
|
||||
if !result.IsOK {
|
||||
isAllOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["isAllOk"] = isAllOk
|
||||
this.Data["results"] = results
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.ServerCachePolicy_LogStatCaches, params.CachePolicyId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
43
EdgeAdmin/internal/web/actions/default/servers/components/cache/test.go
vendored
Normal file
43
EdgeAdmin/internal/web/actions/default/servers/components/cache/test.go
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) Init() {
|
||||
this.Nav("", "", "test")
|
||||
}
|
||||
|
||||
func (this *TestAction) RunGet(params struct {
|
||||
CachePolicyId int64
|
||||
}) {
|
||||
// 默认的集群ID
|
||||
cookie, err := this.Request.Cookie("cache_cluster_id")
|
||||
if cookie != nil && err == nil {
|
||||
this.Data["clusterId"] = types.Int64(cookie.Value)
|
||||
}
|
||||
|
||||
// 集群列表
|
||||
clustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClustersWithHTTPCachePolicyId(this.AdminContext(), &pb.FindAllEnabledNodeClustersWithHTTPCachePolicyIdRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
clusterMaps := []maps.Map{}
|
||||
for _, cluster := range clustersResp.NodeClusters {
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
this.Data["clusters"] = clusterMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
64
EdgeAdmin/internal/web/actions/default/servers/components/cache/testRead.go
vendored
Normal file
64
EdgeAdmin/internal/web/actions/default/servers/components/cache/testRead.go
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type TestReadAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestReadAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
CachePolicyId int64
|
||||
Key string
|
||||
}) {
|
||||
// 记录clusterId
|
||||
this.AddCookie(&http.Cookie{
|
||||
Name: "cache_cluster_id",
|
||||
Value: strconv.FormatInt(params.ClusterId, 10),
|
||||
})
|
||||
|
||||
cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cachePolicyJSON := cachePolicyResp.HttpCachePolicyJSON
|
||||
if len(cachePolicyJSON) == 0 {
|
||||
this.Fail("找不到要操作的缓存策略")
|
||||
}
|
||||
|
||||
// 发送命令
|
||||
msg := &messageconfigs.ReadCacheMessage{
|
||||
CachePolicyJSON: cachePolicyJSON,
|
||||
Key: params.Key,
|
||||
}
|
||||
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeReadCache, msg, 10, false)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
isAllOk := true
|
||||
for _, result := range results {
|
||||
if !result.IsOK {
|
||||
isAllOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["isAllOk"] = isAllOk
|
||||
this.Data["results"] = results
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.ServerCachePolicy_LogTestReading, params.CachePolicyId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
67
EdgeAdmin/internal/web/actions/default/servers/components/cache/testWrite.go
vendored
Normal file
67
EdgeAdmin/internal/web/actions/default/servers/components/cache/testWrite.go
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type TestWriteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestWriteAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
CachePolicyId int64
|
||||
Key string
|
||||
Value string
|
||||
}) {
|
||||
// 记录clusterId
|
||||
this.AddCookie(&http.Cookie{
|
||||
Name: "cache_cluster_id",
|
||||
Value: strconv.FormatInt(params.ClusterId, 10),
|
||||
})
|
||||
|
||||
cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cachePolicyJSON := cachePolicyResp.HttpCachePolicyJSON
|
||||
if len(cachePolicyJSON) == 0 {
|
||||
this.Fail("找不到要操作的缓存策略")
|
||||
}
|
||||
|
||||
// 发送命令
|
||||
msg := &messageconfigs.WriteCacheMessage{
|
||||
CachePolicyJSON: cachePolicyJSON,
|
||||
Key: params.Key,
|
||||
Value: []byte(params.Value),
|
||||
LifeSeconds: 3600,
|
||||
}
|
||||
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeWriteCache, msg, 10, false)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
isAllOk := true
|
||||
for _, result := range results {
|
||||
if !result.IsOK {
|
||||
isAllOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["isAllOk"] = isAllOk
|
||||
this.Data["results"] = results
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.ServerCachePolicy_LogTestWriting, params.CachePolicyId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
219
EdgeAdmin/internal/web/actions/default/servers/components/cache/update.go
vendored
Normal file
219
EdgeAdmin/internal/web/actions/default/servers/components/cache/update.go
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type UpdateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunGet(params struct {
|
||||
CachePolicyId int64
|
||||
}) {
|
||||
configResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{HttpCachePolicyId: params.CachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var configJSON = configResp.HttpCachePolicyJSON
|
||||
if len(configJSON) == 0 {
|
||||
this.NotFound("cachePolicy", params.CachePolicyId)
|
||||
return
|
||||
}
|
||||
|
||||
var cachePolicy = &serverconfigs.HTTPCachePolicy{}
|
||||
err = json.Unmarshal(configJSON, cachePolicy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if cachePolicy.Type == serverconfigs.CachePolicyStorageFile && cachePolicy.Options != nil {
|
||||
// fix min free size
|
||||
{
|
||||
_, ok := cachePolicy.Options["minFreeSize"]
|
||||
if !ok {
|
||||
cachePolicy.Options["minFreeSize"] = &shared.SizeCapacity{
|
||||
Count: 0,
|
||||
Unit: shared.SizeCapacityUnitGB,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fix enableMMAP
|
||||
{
|
||||
_, ok := cachePolicy.Options["enableMMAP"]
|
||||
if !ok {
|
||||
cachePolicy.Options["enableMMAP"] = false
|
||||
}
|
||||
}
|
||||
|
||||
// fix enableIncompletePartialContent
|
||||
{
|
||||
_, ok := cachePolicy.Options["enableIncompletePartialContent"]
|
||||
if !ok {
|
||||
cachePolicy.Options["enableIncompletePartialContent"] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["cachePolicy"] = cachePolicy
|
||||
|
||||
// 其他选项
|
||||
this.Data["types"] = serverconfigs.AllCachePolicyStorageTypes
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
CachePolicyId int64
|
||||
|
||||
Name string
|
||||
Type string
|
||||
|
||||
// file
|
||||
FileDir string
|
||||
FileMemoryCapacityJSON []byte
|
||||
FileOpenFileCacheMax int
|
||||
FileEnableSendfile bool
|
||||
FileMinFreeSizeJSON []byte
|
||||
|
||||
CapacityJSON []byte
|
||||
MaxSizeJSON []byte
|
||||
SyncCompressionCache bool
|
||||
FetchTimeoutJSON []byte
|
||||
|
||||
EnableMMAP bool
|
||||
EnableIncompletePartialContent bool
|
||||
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
RefsJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.ServerCachePolicy_LogUpdateCachePolicy, params.CachePolicyId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入策略名称")
|
||||
|
||||
// 校验选项
|
||||
var options interface{}
|
||||
switch params.Type {
|
||||
case serverconfigs.CachePolicyStorageFile:
|
||||
params.Must.
|
||||
Field("fileDir", params.FileDir).
|
||||
Require("请输入缓存目录")
|
||||
|
||||
var memoryCapacity = &shared.SizeCapacity{}
|
||||
if len(params.FileMemoryCapacityJSON) > 0 {
|
||||
err := json.Unmarshal(params.FileMemoryCapacityJSON, memoryCapacity)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var openFileCacheConfig *serverconfigs.OpenFileCacheConfig
|
||||
if params.FileOpenFileCacheMax > 0 {
|
||||
openFileCacheConfig = &serverconfigs.OpenFileCacheConfig{
|
||||
IsOn: true,
|
||||
Max: params.FileOpenFileCacheMax,
|
||||
}
|
||||
}
|
||||
|
||||
var minFreeSize = &shared.SizeCapacity{}
|
||||
var minFreeSizeJSON = params.FileMinFreeSizeJSON
|
||||
if !utils.JSONIsNull(minFreeSizeJSON) {
|
||||
_, err := utils.JSONDecodeConfig(minFreeSizeJSON, minFreeSize)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if minFreeSize.Count < 0 {
|
||||
minFreeSize.Count = 0
|
||||
}
|
||||
}
|
||||
|
||||
options = &serverconfigs.HTTPFileCacheStorage{
|
||||
Dir: params.FileDir,
|
||||
MemoryPolicy: &serverconfigs.HTTPCachePolicy{
|
||||
Capacity: memoryCapacity,
|
||||
},
|
||||
OpenFileCache: openFileCacheConfig,
|
||||
EnableSendfile: params.FileEnableSendfile,
|
||||
MinFreeSize: minFreeSize,
|
||||
EnableMMAP: params.EnableMMAP,
|
||||
EnableIncompletePartialContent: params.EnableIncompletePartialContent,
|
||||
}
|
||||
case serverconfigs.CachePolicyStorageMemory:
|
||||
options = &serverconfigs.HTTPMemoryCacheStorage{}
|
||||
default:
|
||||
this.Fail("请选择正确的缓存类型")
|
||||
}
|
||||
|
||||
optionsJSON, err := json.Marshal(options)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 校验缓存条件
|
||||
var refs = []*serverconfigs.HTTPCacheRef{}
|
||||
if len(params.RefsJSON) > 0 {
|
||||
err = json.Unmarshal(params.RefsJSON, &refs)
|
||||
if err != nil {
|
||||
this.Fail("缓存条件解析失败:" + err.Error())
|
||||
}
|
||||
for _, ref := range refs {
|
||||
err = ref.Init()
|
||||
if err != nil {
|
||||
this.Fail("缓存条件校验失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicy(this.AdminContext(), &pb.UpdateHTTPCachePolicyRequest{
|
||||
HttpCachePolicyId: params.CachePolicyId,
|
||||
IsOn: params.IsOn,
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
CapacityJSON: params.CapacityJSON,
|
||||
MaxSizeJSON: params.MaxSizeJSON,
|
||||
Type: params.Type,
|
||||
OptionsJSON: optionsJSON,
|
||||
SyncCompressionCache: params.SyncCompressionCache,
|
||||
FetchTimeoutJSON: params.FetchTimeoutJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 修改缓存条件
|
||||
_, err = this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicyRefs(this.AdminContext(), &pb.UpdateHTTPCachePolicyRefsRequest{
|
||||
HttpCachePolicyId: params.CachePolicyId,
|
||||
RefsJSON: params.RefsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
35
EdgeAdmin/internal/web/actions/default/servers/components/cache/updateRefs.go
vendored
Normal file
35
EdgeAdmin/internal/web/actions/default/servers/components/cache/updateRefs.go
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type UpdateRefsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateRefsAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdateRefsAction) RunPost(params struct {
|
||||
CachePolicyId int64
|
||||
RefsJSON []byte
|
||||
}) {
|
||||
// 修改缓存条件
|
||||
if params.CachePolicyId > 0 && len(params.RefsJSON) > 0 {
|
||||
_, err := this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicyRefs(this.AdminContext(), &pb.UpdateHTTPCachePolicyRefsRequest{
|
||||
HttpCachePolicyId: params.CachePolicyId,
|
||||
RefsJSON: params.RefsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
}
|
||||
|
||||
func NewHelper() *Helper {
|
||||
return &Helper{}
|
||||
}
|
||||
|
||||
func (this *Helper) BeforeAction(action *actions.ActionObject) {
|
||||
if action.Request.Method != http.MethodGet {
|
||||
return
|
||||
}
|
||||
|
||||
action.Data["mainTab"] = "component"
|
||||
action.Data["secondMenuItem"] = "log"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.FirstMenu("index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package log
|
||||
|
||||
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)).
|
||||
Helper(NewHelper()).
|
||||
Prefix("/servers/components/log").
|
||||
Get("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type CountAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CountAction) RunPost(params struct{}) {
|
||||
countResp, err := this.RPC().HTTPFirewallPolicyRPC().CountAllEnabledHTTPFirewallPolicies(this.AdminContext(), &pb.CountAllEnabledHTTPFirewallPoliciesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["count"] = countResp.Count
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"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"
|
||||
)
|
||||
|
||||
type CreateGroupPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateGroupPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreateGroupPopupAction) RunGet(params struct {
|
||||
Type string
|
||||
}) {
|
||||
this.Data["type"] = params.Type
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateGroupPopupAction) RunPost(params struct {
|
||||
FirewallPolicyId int64
|
||||
Type string
|
||||
|
||||
Name string
|
||||
Code string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
firewallPolicy, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if firewallPolicy == nil {
|
||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
|
||||
createResp, err := this.RPC().HTTPFirewallRuleGroupRPC().CreateHTTPFirewallRuleGroup(this.AdminContext(), &pb.CreateHTTPFirewallRuleGroupRequest{
|
||||
IsOn: params.IsOn,
|
||||
Name: params.Name,
|
||||
Code: params.Code,
|
||||
Description: params.Description,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
groupId := createResp.FirewallRuleGroupId
|
||||
|
||||
switch params.Type {
|
||||
case "inbound":
|
||||
firewallPolicy.Inbound.GroupRefs = append(firewallPolicy.Inbound.GroupRefs, &firewallconfigs.HTTPFirewallRuleGroupRef{
|
||||
IsOn: true,
|
||||
GroupId: groupId,
|
||||
})
|
||||
default:
|
||||
firewallPolicy.Outbound.GroupRefs = append(firewallPolicy.Outbound.GroupRefs, &firewallconfigs.HTTPFirewallRuleGroupRef{
|
||||
IsOn: true,
|
||||
GroupId: groupId,
|
||||
})
|
||||
}
|
||||
|
||||
inboundJSON, err := firewallPolicy.InboundJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
outboundJSON, err := firewallPolicy.OutboundJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallPolicyGroups(this.AdminContext(), &pb.UpdateHTTPFirewallPolicyGroupsRequest{
|
||||
HttpFirewallPolicyId: params.FirewallPolicyId,
|
||||
InboundJSON: inboundJSON,
|
||||
OutboundJSON: outboundJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 日志
|
||||
defer this.CreateLogInfo(codes.WAFRuleGroup_LogCreateRuleGroup, groupId, params.Name)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"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{}) {
|
||||
// 预置分组
|
||||
groups := []maps.Map{}
|
||||
templatePolicy := firewallconfigs.HTTPFirewallTemplate()
|
||||
for _, group := range templatePolicy.AllRuleGroups() {
|
||||
groups = append(groups, maps.Map{
|
||||
"code": group.Code,
|
||||
"name": group.Name,
|
||||
"isOn": group.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groups
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
GroupCodes []string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入策略名称")
|
||||
|
||||
createResp, err := this.RPC().HTTPFirewallPolicyRPC().CreateHTTPFirewallPolicy(this.AdminContext(), &pb.CreateHTTPFirewallPolicyRequest{
|
||||
IsOn: params.IsOn,
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
HttpFirewallGroupCodes: params.GroupCodes,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 返回数据
|
||||
this.Data["firewallPolicy"] = maps.Map{
|
||||
"id": createResp.HttpFirewallPolicyId,
|
||||
"name": params.Name,
|
||||
"description": params.Description,
|
||||
}
|
||||
|
||||
// 日志
|
||||
defer this.CreateLogInfo(codes.WAFPolicy_LogCreateWAFPolicy, createResp.HttpFirewallPolicyId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type CreateRulePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateRulePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreateRulePopupAction) RunGet(params struct {
|
||||
Type string
|
||||
}) {
|
||||
// check points
|
||||
var checkpointList = []maps.Map{}
|
||||
for _, checkpoint := range firewallconfigs.AllCheckpoints {
|
||||
if (params.Type == "inbound" && checkpoint.IsRequest) || params.Type == "outbound" {
|
||||
checkpointList = append(checkpointList, maps.Map{
|
||||
"name": checkpoint.Name,
|
||||
"prefix": checkpoint.Prefix,
|
||||
"description": checkpoint.Description,
|
||||
"hasParams": checkpoint.HasParams,
|
||||
"params": checkpoint.Params,
|
||||
"options": checkpoint.Options,
|
||||
"isComposed": checkpoint.IsComposed,
|
||||
"dataType": checkpoint.DataType,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// operators
|
||||
var operatorMaps = []maps.Map{}
|
||||
for _, operator := range firewallconfigs.AllRuleOperators {
|
||||
operatorMaps = append(operatorMaps, maps.Map{
|
||||
"name": operator.Name,
|
||||
"code": operator.Code,
|
||||
"description": operator.Description,
|
||||
"case": operator.CaseInsensitive,
|
||||
"dataType": operator.DataType,
|
||||
})
|
||||
}
|
||||
this.Data["operators"] = operatorMaps
|
||||
|
||||
this.Data["checkpoints"] = checkpointList
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateRulePopupAction) RunPost(params struct {
|
||||
RuleId int64
|
||||
Prefix string
|
||||
Operator string
|
||||
Param string
|
||||
ParamFiltersJSON []byte
|
||||
OptionsJSON []byte
|
||||
Value string
|
||||
Case bool
|
||||
Description string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("prefix", params.Prefix).
|
||||
Require("请选择参数")
|
||||
|
||||
if len(params.Value) > 4096 {
|
||||
this.FailField("value", "对比值内容长度不能超过4096个字符")
|
||||
return
|
||||
}
|
||||
|
||||
var rule = &firewallconfigs.HTTPFirewallRule{
|
||||
Id: params.RuleId,
|
||||
IsOn: true,
|
||||
}
|
||||
if len(params.Param) > 0 {
|
||||
rule.Param = "${" + params.Prefix + "." + params.Param + "}"
|
||||
} else {
|
||||
rule.Param = "${" + params.Prefix + "}"
|
||||
}
|
||||
|
||||
var paramFilters = []*firewallconfigs.ParamFilter{}
|
||||
if len(params.ParamFiltersJSON) > 0 {
|
||||
err := json.Unmarshal(params.ParamFiltersJSON, ¶mFilters)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
rule.ParamFilters = paramFilters
|
||||
|
||||
rule.Operator = params.Operator
|
||||
rule.Value = params.Value
|
||||
rule.IsCaseInsensitive = params.Case
|
||||
rule.Description = params.Description
|
||||
|
||||
if len(params.OptionsJSON) > 0 {
|
||||
options := []maps.Map{}
|
||||
err := json.Unmarshal(params.OptionsJSON, &options)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
rule.CheckpointOptions = map[string]interface{}{}
|
||||
for _, option := range options {
|
||||
rule.CheckpointOptions[option.GetString("code")] = option.Get("value")
|
||||
}
|
||||
}
|
||||
|
||||
// 校验
|
||||
err := rule.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验规则 '" + rule.Param + " " + rule.Operator + " " + rule.Value + "' 失败,原因:" + err.Error())
|
||||
}
|
||||
|
||||
this.Data["rule"] = rule
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"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/maps"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type CreateSetPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateSetPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreateSetPopupAction) RunGet(params struct {
|
||||
FirewallPolicyId int64
|
||||
GroupId int64
|
||||
Type string
|
||||
}) {
|
||||
this.Data["groupId"] = params.GroupId
|
||||
this.Data["type"] = params.Type
|
||||
|
||||
firewallPolicy, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if firewallPolicy == nil {
|
||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||
return
|
||||
}
|
||||
this.Data["firewallPolicy"] = firewallPolicy
|
||||
|
||||
// 一些配置
|
||||
this.Data["connectors"] = []maps.Map{
|
||||
{
|
||||
"name": this.Lang(codes.WAF_ConnectorAnd),
|
||||
"value": firewallconfigs.HTTPFirewallRuleConnectorAnd,
|
||||
"description": this.Lang(codes.WAF_ConnectorAndDescription),
|
||||
},
|
||||
{
|
||||
"name": this.Lang(codes.WAF_ConnectorOr),
|
||||
"value": firewallconfigs.HTTPFirewallRuleConnectorOr,
|
||||
"description": this.Lang(codes.WAF_ConnectorOrDescription),
|
||||
},
|
||||
}
|
||||
|
||||
// 所有可选的动作
|
||||
var actionMaps = []maps.Map{}
|
||||
for _, action := range firewallconfigs.AllActions {
|
||||
actionMaps = append(actionMaps, maps.Map{
|
||||
"name": action.Name,
|
||||
"description": action.Description,
|
||||
"code": action.Code,
|
||||
})
|
||||
}
|
||||
this.Data["actions"] = actionMaps
|
||||
|
||||
// 是否为全局
|
||||
this.Data["isGlobalPolicy"] = firewallPolicy.ServerId == 0
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateSetPopupAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
|
||||
Name string
|
||||
|
||||
FormType string
|
||||
|
||||
// normal
|
||||
RulesJSON []byte
|
||||
Connector string
|
||||
ActionsJSON []byte
|
||||
IgnoreLocal bool
|
||||
IgnoreSearchEngine bool
|
||||
|
||||
// code
|
||||
Code string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
groupConfig, err := dao.SharedHTTPFirewallRuleGroupDAO.FindRuleGroupConfig(this.AdminContext(), params.GroupId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if groupConfig == nil {
|
||||
this.Fail("找不到分组,Id:" + strconv.FormatInt(params.GroupId, 10))
|
||||
return
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入规则集名称")
|
||||
|
||||
var setConfigJSON []byte
|
||||
if params.FormType == "normal" {
|
||||
if len(params.RulesJSON) == 0 {
|
||||
this.Fail("请添加至少一个规则")
|
||||
return
|
||||
}
|
||||
var rules = []*firewallconfigs.HTTPFirewallRule{}
|
||||
err = json.Unmarshal(params.RulesJSON, &rules)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(rules) == 0 {
|
||||
this.Fail("请添加至少一个规则")
|
||||
return
|
||||
}
|
||||
|
||||
var actionConfigs = []*firewallconfigs.HTTPFirewallActionConfig{}
|
||||
if len(params.ActionsJSON) > 0 {
|
||||
err = json.Unmarshal(params.ActionsJSON, &actionConfigs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(actionConfigs) == 0 {
|
||||
this.Fail("请添加至少一个动作")
|
||||
return
|
||||
}
|
||||
|
||||
var setConfig = &firewallconfigs.HTTPFirewallRuleSet{
|
||||
Id: 0,
|
||||
IsOn: true,
|
||||
Name: params.Name,
|
||||
Code: "",
|
||||
Description: "",
|
||||
Connector: params.Connector,
|
||||
RuleRefs: nil,
|
||||
Rules: rules,
|
||||
Actions: actionConfigs,
|
||||
IgnoreLocal: params.IgnoreLocal,
|
||||
IgnoreSearchEngine: params.IgnoreSearchEngine,
|
||||
}
|
||||
|
||||
setConfigJSON, err = json.Marshal(setConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
} else if params.FormType == "code" {
|
||||
var codeJSON = []byte(params.Code)
|
||||
if len(codeJSON) == 0 {
|
||||
this.FailField("code", "请输入规则集代码")
|
||||
return
|
||||
}
|
||||
|
||||
var setConfig = &firewallconfigs.HTTPFirewallRuleSet{}
|
||||
err = json.Unmarshal(codeJSON, setConfig)
|
||||
if err != nil {
|
||||
this.FailField("code", "解析规则集代码失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(setConfig.Rules) == 0 {
|
||||
this.FailField("code", "规则集代码中必须包含至少一个规则")
|
||||
return
|
||||
}
|
||||
|
||||
if len(setConfig.Actions) == 0 {
|
||||
this.FailField("code", "规则集代码中必须包含至少一个动作")
|
||||
return
|
||||
}
|
||||
|
||||
setConfig.Name = params.Name
|
||||
setConfig.IsOn = true
|
||||
|
||||
// 重置ID
|
||||
setConfig.Id = 0
|
||||
|
||||
setConfig.RuleRefs = nil
|
||||
for _, rule := range setConfig.Rules {
|
||||
rule.Id = 0
|
||||
}
|
||||
|
||||
err = setConfig.Init()
|
||||
if err != nil {
|
||||
this.FailField("code", "校验规则集代码失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
setConfigJSON, err = json.Marshal(setConfig)
|
||||
} else {
|
||||
this.Fail("错误的参数'formType': " + params.FormType)
|
||||
return
|
||||
}
|
||||
|
||||
createUpdateResp, err := this.RPC().HTTPFirewallRuleSetRPC().CreateOrUpdateHTTPFirewallRuleSetFromConfig(this.AdminContext(), &pb.CreateOrUpdateHTTPFirewallRuleSetFromConfigRequest{FirewallRuleSetConfigJSON: setConfigJSON})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
groupConfig.SetRefs = append(groupConfig.SetRefs, &firewallconfigs.HTTPFirewallRuleSetRef{
|
||||
IsOn: true,
|
||||
SetId: createUpdateResp.FirewallRuleSetId,
|
||||
})
|
||||
|
||||
setRefsJSON, err := json.Marshal(groupConfig.SetRefs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPFirewallRuleGroupRPC().UpdateHTTPFirewallRuleGroupSets(this.AdminContext(), &pb.UpdateHTTPFirewallRuleGroupSetsRequest{
|
||||
FirewallRuleGroupId: params.GroupId,
|
||||
FirewallRuleSetsJSON: setRefsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["setId"] = createUpdateResp.FirewallRuleSetId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
FirewallPolicyId int64
|
||||
}) {
|
||||
// 日志
|
||||
defer this.CreateLogInfo(codes.WAFPolicy_LogDeleteWAFPolicy, params.FirewallPolicyId)
|
||||
|
||||
countResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClustersWithHTTPFirewallPolicyId(this.AdminContext(), &pb.CountAllEnabledNodeClustersWithHTTPFirewallPolicyIdRequest{HttpFirewallPolicyId: params.FirewallPolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("此WAF策略正在被有些集群引用,请修改后再删除。")
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPFirewallPolicyRPC().DeleteHTTPFirewallPolicy(this.AdminContext(), &pb.DeleteHTTPFirewallPolicyRequest{HttpFirewallPolicyId: params.FirewallPolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteGroupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteGroupAction) RunPost(params struct {
|
||||
FirewallPolicyId int64
|
||||
GroupId int64
|
||||
}) {
|
||||
// 日志
|
||||
defer this.CreateLogInfo(codes.WAFRuleGroup_LogDeleteRuleGroup, params.FirewallPolicyId, params.GroupId)
|
||||
|
||||
firewallPolicy, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if firewallPolicy == nil {
|
||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||
return
|
||||
}
|
||||
firewallPolicy.RemoveRuleGroup(params.GroupId)
|
||||
|
||||
inboundJSON, err := firewallPolicy.InboundJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
outboundJSON, err := firewallPolicy.OutboundJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallPolicyGroups(this.AdminContext(), &pb.UpdateHTTPFirewallPolicyGroupsRequest{
|
||||
HttpFirewallPolicyId: params.FirewallPolicyId,
|
||||
InboundJSON: inboundJSON,
|
||||
OutboundJSON: outboundJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
)
|
||||
|
||||
type DeleteSetAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteSetAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
SetId int64
|
||||
}) {
|
||||
// 日志
|
||||
defer this.CreateLogInfo(codes.WAFRuleSet_LogDeleteRuleSet, params.GroupId, params.SetId)
|
||||
|
||||
groupConfig, err := dao.SharedHTTPFirewallRuleGroupDAO.FindRuleGroupConfig(this.AdminContext(), params.GroupId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if groupConfig == nil {
|
||||
this.NotFound("firewallRuleGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
newRefs := []*firewallconfigs.HTTPFirewallRuleSetRef{}
|
||||
for _, ref := range groupConfig.SetRefs {
|
||||
if ref.SetId != params.SetId {
|
||||
newRefs = append(newRefs, ref)
|
||||
}
|
||||
}
|
||||
newRefsJSON, err := json.Marshal(newRefs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().HTTPFirewallRuleGroupRPC().UpdateHTTPFirewallRuleGroupSets(this.AdminContext(), &pb.UpdateHTTPFirewallRuleGroupSetsRequest{
|
||||
FirewallRuleGroupId: params.GroupId,
|
||||
FirewallRuleSetsJSON: newRefsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/ttlcache"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ExportAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ExportAction) Init() {
|
||||
this.Nav("", "", "export")
|
||||
}
|
||||
|
||||
func (this *ExportAction) RunGet(params struct {
|
||||
FirewallPolicyId int64
|
||||
}) {
|
||||
policy, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if policy == nil {
|
||||
this.NotFound("firewallPolicy", policy.Id)
|
||||
return
|
||||
}
|
||||
|
||||
enabledInboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
|
||||
enabledOutboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
|
||||
|
||||
disabledInboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
|
||||
disabledOutboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
|
||||
|
||||
if policy.Inbound != nil {
|
||||
for _, g := range policy.Inbound.Groups {
|
||||
if g.IsOn {
|
||||
enabledInboundGroups = append(enabledInboundGroups, g)
|
||||
} else {
|
||||
disabledInboundGroups = append(disabledInboundGroups, g)
|
||||
}
|
||||
}
|
||||
}
|
||||
if policy.Outbound != nil {
|
||||
for _, g := range policy.Outbound.Groups {
|
||||
if g.IsOn {
|
||||
enabledOutboundGroups = append(enabledOutboundGroups, g)
|
||||
} else {
|
||||
disabledOutboundGroups = append(disabledOutboundGroups, g)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["enabledInboundGroups"] = enabledInboundGroups
|
||||
this.Data["enabledOutboundGroups"] = enabledOutboundGroups
|
||||
|
||||
this.Data["disabledInboundGroups"] = disabledInboundGroups
|
||||
this.Data["disabledOutboundGroups"] = disabledOutboundGroups
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *ExportAction) RunPost(params struct {
|
||||
FirewallPolicyId int64
|
||||
InboundGroupIds []int64
|
||||
OutboundGroupIds []int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.WAFPolicy_LogExportWAFPolicy, params.FirewallPolicyId)
|
||||
|
||||
policy, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if policy == nil {
|
||||
this.NotFound("firewallPolicy", policy.Id)
|
||||
return
|
||||
}
|
||||
|
||||
// inbound
|
||||
newInboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
|
||||
for _, inboundGroupId := range params.InboundGroupIds {
|
||||
group := policy.FindRuleGroup(inboundGroupId)
|
||||
if group != nil {
|
||||
newInboundGroups = append(newInboundGroups, group)
|
||||
}
|
||||
}
|
||||
if policy.Inbound == nil {
|
||||
policy.Inbound = &firewallconfigs.HTTPFirewallInboundConfig{
|
||||
IsOn: true,
|
||||
}
|
||||
}
|
||||
policy.Inbound.Groups = newInboundGroups
|
||||
policy.Inbound.GroupRefs = nil
|
||||
|
||||
// outbound
|
||||
newOutboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
|
||||
for _, outboundGroupId := range params.OutboundGroupIds {
|
||||
group := policy.FindRuleGroup(outboundGroupId)
|
||||
if group != nil {
|
||||
newOutboundGroups = append(newOutboundGroups, group)
|
||||
}
|
||||
}
|
||||
if policy.Outbound == nil {
|
||||
policy.Outbound = &firewallconfigs.HTTPFirewallOutboundConfig{
|
||||
IsOn: true,
|
||||
}
|
||||
}
|
||||
policy.Outbound.Groups = newOutboundGroups
|
||||
policy.Outbound.GroupRefs = nil
|
||||
|
||||
configJSON, err := json.Marshal(policy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
key := "waf." + rands.HexString(32)
|
||||
ttlcache.DefaultCache.Write(key, configJSON, time.Now().Unix()+600)
|
||||
|
||||
this.Data["key"] = key
|
||||
this.Data["id"] = params.FirewallPolicyId
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/ttlcache"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ExportDownloadAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ExportDownloadAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *ExportDownloadAction) RunGet(params struct {
|
||||
Key string
|
||||
PolicyId int64
|
||||
}) {
|
||||
item := ttlcache.DefaultCache.Read(params.Key)
|
||||
if item == nil || item.Value == nil {
|
||||
this.WriteString("找不到要导出的内容")
|
||||
return
|
||||
}
|
||||
|
||||
ttlcache.DefaultCache.Delete(params.Key)
|
||||
|
||||
data, ok := item.Value.([]byte)
|
||||
if ok {
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"WAF-"+types.String(params.PolicyId)+".json\";")
|
||||
this.AddHeader("Content-Length", strconv.Itoa(len(data)))
|
||||
_, _ = this.Write(data)
|
||||
} else {
|
||||
this.WriteString("找不到要导出的内容")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type GroupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *GroupAction) Init() {
|
||||
this.Nav("", "", this.ParamString("type"))
|
||||
}
|
||||
|
||||
func (this *GroupAction) RunGet(params struct {
|
||||
FirewallPolicyId int64
|
||||
GroupId int64
|
||||
Type string
|
||||
}) {
|
||||
this.Data["type"] = params.Type
|
||||
//stime := time.Now()
|
||||
|
||||
// policy
|
||||
firewallPolicy, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if firewallPolicy == nil {
|
||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||
return
|
||||
}
|
||||
//fmt.Printf("调用 FindEnabledHTTPFirewallPolicyConfig 方法 耗时: %v\n", time.Now().Sub(stime))
|
||||
// group config
|
||||
groupConfig, err := dao.SharedHTTPFirewallRuleGroupDAO.FindRuleGroupConfig(this.AdminContext(), params.GroupId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if groupConfig == nil {
|
||||
this.NotFound("firewallRuleGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
//fmt.Printf("调用 FindRuleGroupConfig 方法 耗时: %v\n", time.Now().Sub(stime))
|
||||
this.Data["group"] = groupConfig
|
||||
|
||||
// rule sets
|
||||
this.Data["sets"] = lists.Map(groupConfig.Sets, func(k int, v interface{}) interface{} {
|
||||
set := v.(*firewallconfigs.HTTPFirewallRuleSet)
|
||||
|
||||
// 动作说明
|
||||
var actionMaps = []maps.Map{}
|
||||
for _, action := range set.Actions {
|
||||
def := firewallconfigs.FindActionDefinition(action.Code)
|
||||
if def == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
actionMaps = append(actionMaps, maps.Map{
|
||||
"code": strings.ToUpper(action.Code),
|
||||
"name": def.Name,
|
||||
"category": def.Category,
|
||||
"options": action.Options,
|
||||
})
|
||||
}
|
||||
|
||||
return maps.Map{
|
||||
"id": set.Id,
|
||||
"name": set.Name,
|
||||
"rules": lists.Map(set.Rules, func(k int, v interface{}) interface{} {
|
||||
rule := v.(*firewallconfigs.HTTPFirewallRule)
|
||||
|
||||
// 校验
|
||||
var errString = ""
|
||||
var err = rule.Init()
|
||||
if err != nil {
|
||||
errString = err.Error()
|
||||
}
|
||||
|
||||
return maps.Map{
|
||||
"param": rule.Param,
|
||||
"paramFilters": rule.ParamFilters,
|
||||
"operator": rule.Operator,
|
||||
"value": rule.Value,
|
||||
"isCaseInsensitive": rule.IsCaseInsensitive,
|
||||
"description": rule.Description,
|
||||
"isComposed": firewallconfigs.CheckCheckpointIsComposed(rule.Prefix()),
|
||||
"checkpointOptions": rule.CheckpointOptions,
|
||||
"err": errString,
|
||||
}
|
||||
}),
|
||||
"isOn": set.IsOn,
|
||||
"actions": actionMaps,
|
||||
"connector": strings.ToUpper(set.Connector),
|
||||
}
|
||||
})
|
||||
//fmt.Printf("调用 list.map 方法 耗时: %v\n", time.Now().Sub(stime))
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type GroupsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *GroupsAction) Init() {
|
||||
this.Nav("", "", this.ParamString("type"))
|
||||
}
|
||||
|
||||
func (this *GroupsAction) RunGet(params struct {
|
||||
FirewallPolicyId int64
|
||||
Type string
|
||||
}) {
|
||||
this.Data["type"] = params.Type
|
||||
|
||||
firewallPolicy, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if firewallPolicy == nil {
|
||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||
return
|
||||
}
|
||||
|
||||
groupMaps := []maps.Map{}
|
||||
|
||||
// inbound
|
||||
if params.Type == "inbound" {
|
||||
if firewallPolicy.Inbound != nil {
|
||||
for _, g := range firewallPolicy.Inbound.Groups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": g.Id,
|
||||
"name": g.Name,
|
||||
"code": g.Code,
|
||||
"isOn": g.IsOn,
|
||||
"description": g.Description,
|
||||
"countSets": len(g.Sets),
|
||||
"isTemplate": g.IsTemplate,
|
||||
"canDelete": true, //!g.IsTemplate,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// outbound
|
||||
if params.Type == "outbound" {
|
||||
if firewallPolicy.Outbound != nil {
|
||||
for _, g := range firewallPolicy.Outbound.Groups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": g.Id,
|
||||
"name": g.Name,
|
||||
"code": g.Code,
|
||||
"isOn": g.IsOn,
|
||||
"description": g.Description,
|
||||
"countSets": len(g.Sets),
|
||||
"isTemplate": g.IsTemplate,
|
||||
"canDelete": true, //!g.IsTemplate,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
}
|
||||
|
||||
func NewHelper() *Helper {
|
||||
return &Helper{}
|
||||
}
|
||||
|
||||
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
|
||||
action := actionPtr.Object()
|
||||
if action.Request.Method != http.MethodGet {
|
||||
return true
|
||||
}
|
||||
|
||||
action.Data["mainTab"] = "component"
|
||||
action.Data["secondMenuItem"] = "waf"
|
||||
|
||||
// 显示当前的防火墙名称
|
||||
firewallPolicyId := action.ParamInt64("firewallPolicyId")
|
||||
if firewallPolicyId > 0 {
|
||||
action.Data["firewallPolicyId"] = firewallPolicyId
|
||||
action.Data["countInboundGroups"] = 0
|
||||
action.Data["countOutboundGroups"] = 0
|
||||
parentAction := actionutils.FindParentAction(actionPtr)
|
||||
if parentAction != nil {
|
||||
firewallPolicy, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicy(parentAction.AdminContext(), firewallPolicyId)
|
||||
if err != nil {
|
||||
parentAction.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if firewallPolicy == nil {
|
||||
action.WriteString("can not find firewall policy")
|
||||
return
|
||||
}
|
||||
action.Data["firewallPolicyName"] = firewallPolicy.Name
|
||||
|
||||
// inbound
|
||||
if len(firewallPolicy.InboundJSON) > 0 {
|
||||
inboundConfig := &firewallconfigs.HTTPFirewallInboundConfig{}
|
||||
err = json.Unmarshal(firewallPolicy.InboundJSON, inboundConfig)
|
||||
if err != nil {
|
||||
parentAction.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
action.Data["countInboundGroups"] = len(inboundConfig.GroupRefs)
|
||||
}
|
||||
|
||||
// outbound
|
||||
if len(firewallPolicy.OutboundJSON) > 0 {
|
||||
outboundConfig := &firewallconfigs.HTTPFirewallOutboundConfig{}
|
||||
err = json.Unmarshal(firewallPolicy.OutboundJSON, outboundConfig)
|
||||
if err != nil {
|
||||
parentAction.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
action.Data["countOutboundGroups"] = len(outboundConfig.GroupRefs)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/exce"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"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/Tea"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||
"os"
|
||||
)
|
||||
|
||||
type ImportAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ImportAction) Init() {
|
||||
this.Nav("", "", "import")
|
||||
}
|
||||
|
||||
func (this *ImportAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *ImportAction) RunPost(params struct {
|
||||
FirewallPolicyId int64
|
||||
File *actions.File
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.WAFPolicy_LogImportWAFPolicy, params.FirewallPolicyId)
|
||||
if params.File == nil {
|
||||
this.Fail("请上传要导入的文件")
|
||||
}
|
||||
if params.File.Ext != ".json" {
|
||||
this.Fail("规则文件的扩展名只能是.json")
|
||||
}
|
||||
|
||||
data, err := params.File.Read()
|
||||
if err != nil {
|
||||
this.Fail("读取文件时发生错误:" + err.Error())
|
||||
}
|
||||
|
||||
config := &firewallconfigs.HTTPFirewallPolicy{}
|
||||
err = json.Unmarshal(data, config)
|
||||
if err != nil {
|
||||
this.Fail("解析文件时发生错误:" + err.Error())
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPFirewallPolicyRPC().ImportHTTPFirewallPolicy(this.AdminContext(), &pb.ImportHTTPFirewallPolicyRequest{
|
||||
HttpFirewallPolicyId: params.FirewallPolicyId,
|
||||
HttpFirewallPolicyJSON: data,
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("导入失败:" + err.Error())
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
|
||||
func (this *ImportAction) importXlsxWAFRules(data []byte, firewallPolicyId int64) {
|
||||
// 解析文件
|
||||
errRulesBuff, rules, err := exce.ParseRules(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
this.Fail("导入失败:" + err.Error())
|
||||
}
|
||||
groupSetMaps := map[int64]map[string]int64{}
|
||||
inboundGroupNameMaps := map[string]int64{}
|
||||
outboundGroupNameMaps := map[string]int64{}
|
||||
newInboundGroup := []int64{}
|
||||
newOutboundGroup := []int64{}
|
||||
// 批量加入waf规则
|
||||
firewallPolicy, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), firewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if firewallPolicy == nil {
|
||||
this.NotFound("firewallPolicy", firewallPolicyId)
|
||||
}
|
||||
for _, g := range firewallPolicy.Inbound.GroupRefs {
|
||||
// 查询group 下的规则集
|
||||
group, err := dao.SharedHTTPFirewallRuleGroupDAO.FindRuleGroupConfig(this.AdminContext(), g.GroupId)
|
||||
if err != nil {
|
||||
this.Fail("获取策略下规则分组信息失败:" + err.Error())
|
||||
}
|
||||
inboundGroupNameMaps[group.Name] = group.Id
|
||||
groupSetMaps[g.GroupId] = make(map[string]int64, len(group.Sets))
|
||||
for _, set := range group.Sets {
|
||||
groupSetMaps[g.GroupId][set.Name] = set.Id
|
||||
}
|
||||
|
||||
}
|
||||
for _, g := range firewallPolicy.Outbound.GroupRefs {
|
||||
// 查询group 下的规则集
|
||||
group, err := dao.SharedHTTPFirewallRuleGroupDAO.FindRuleGroupConfig(this.AdminContext(), g.GroupId)
|
||||
if err != nil {
|
||||
this.Fail("获取策略下规则分组信息失败:" + err.Error())
|
||||
}
|
||||
outboundGroupNameMaps[group.Name] = group.Id
|
||||
groupSetMaps[g.GroupId] = make(map[string]int64, len(group.Sets))
|
||||
for _, set := range group.Sets {
|
||||
groupSetMaps[g.GroupId][set.Name] = set.Id
|
||||
}
|
||||
}
|
||||
for _, rule := range rules {
|
||||
|
||||
var inboundGroupId int64
|
||||
var outboundGroupId int64
|
||||
var ok bool
|
||||
if rule.Inbound {
|
||||
inboundGroupId, ok = inboundGroupNameMaps[rule.Type]
|
||||
if !ok { // 如果不存在 则创建新的入站规则分组
|
||||
createResp, err := this.RPC().HTTPFirewallRuleGroupRPC().CreateHTTPFirewallRuleGroup(this.AdminContext(), &pb.CreateHTTPFirewallRuleGroupRequest{
|
||||
IsOn: true,
|
||||
Name: rule.Type,
|
||||
Code: rule.Type,
|
||||
Description: "WAF规则导入:" + rule.Type,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
inboundGroupId = createResp.FirewallRuleGroupId
|
||||
newInboundGroup = append(newInboundGroup, inboundGroupId)
|
||||
inboundGroupNameMaps[rule.Type] = inboundGroupId
|
||||
}
|
||||
}
|
||||
if rule.Outbound {
|
||||
outboundGroupId, ok = outboundGroupNameMaps[rule.Type]
|
||||
if !ok { // 如果不存在 则创建新的入站规则分组
|
||||
createResp, err := this.RPC().HTTPFirewallRuleGroupRPC().CreateHTTPFirewallRuleGroup(this.AdminContext(), &pb.CreateHTTPFirewallRuleGroupRequest{
|
||||
IsOn: true,
|
||||
Name: rule.Type,
|
||||
Code: rule.Type,
|
||||
Description: "WAF规则导入:" + rule.Type,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
outboundGroupId = createResp.FirewallRuleGroupId
|
||||
newOutboundGroup = append(newOutboundGroup, outboundGroupId)
|
||||
outboundGroupNameMaps[rule.Type] = outboundGroupId
|
||||
}
|
||||
}
|
||||
|
||||
// 往规则分组中加入新规则集
|
||||
var rs = []*firewallconfigs.HTTPFirewallRule{} //入站规则
|
||||
var outRs = make([]*firewallconfigs.HTTPFirewallRule, 1) // 出站规则
|
||||
for idx, arg := range rule.Position {
|
||||
if arg == "" {
|
||||
continue
|
||||
}
|
||||
if arg == "${responseBody}" { // 出站规则
|
||||
outRs[0] = &firewallconfigs.HTTPFirewallRule{
|
||||
Id: 0,
|
||||
IsOn: true,
|
||||
Param: "{responseBody}",
|
||||
Operator: "match",
|
||||
Value: rule.Regular,
|
||||
IsCaseInsensitive: true,
|
||||
IsComposed: false,
|
||||
}
|
||||
} else {
|
||||
// 入站规则才支持多规则
|
||||
if rule.IsAnd {
|
||||
rs = append(rs, &firewallconfigs.HTTPFirewallRule{
|
||||
Id: 0,
|
||||
IsOn: true,
|
||||
Param: arg,
|
||||
Operator: "match",
|
||||
Value: rule.Regulars[idx],
|
||||
IsCaseInsensitive: true,
|
||||
IsComposed: false,
|
||||
})
|
||||
} else {
|
||||
rs = append(rs, &firewallconfigs.HTTPFirewallRule{
|
||||
Id: 0,
|
||||
IsOn: true,
|
||||
Param: arg,
|
||||
Operator: "match",
|
||||
Value: rule.Regular,
|
||||
IsCaseInsensitive: true,
|
||||
IsComposed: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
var set = &firewallconfigs.HTTPFirewallRuleSet{
|
||||
Id: 0,
|
||||
IsOn: true,
|
||||
Name: rule.Name,
|
||||
Code: "",
|
||||
Description: rule.Description,
|
||||
Connector: "or",
|
||||
RuleRefs: nil,
|
||||
Level: rule.Level,
|
||||
CVE: rule.CVE,
|
||||
// 默认动作为403显示网页
|
||||
Actions: []*firewallconfigs.HTTPFirewallActionConfig{
|
||||
{
|
||||
Code: firewallconfigs.HTTPFirewallActionPage,
|
||||
Options: map[string]interface{}{
|
||||
"useDefault": true,
|
||||
"status": 403,
|
||||
"body": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<title>403 Forbidden</title>\n\t<style>\n\t\taddress { line-height: 1.8; }\n\t</style>\n</head>\n<body>\n<h1>403 Forbidden</h1>\n<address>Connection: ${remoteAddr} (Client) -> ${serverAddr} (Server)</address>\n<address>Request ID: ${requestId}</address>\n</body>\n</html>",
|
||||
},
|
||||
},
|
||||
},
|
||||
IgnoreLocal: false,
|
||||
}
|
||||
if rule.IsAnd {
|
||||
set.Connector = "and"
|
||||
}
|
||||
// 判断规则集中是否存在相同的规则集名字 如果有替换
|
||||
// 如果是已存在的分组则判断
|
||||
|
||||
if rule.Inbound {
|
||||
if ok {
|
||||
set.Id, ok = groupSetMaps[inboundGroupId][set.Name]
|
||||
}
|
||||
set.Rules = rs
|
||||
setConfigJSON, err := json.Marshal(set)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if ok { // 替换
|
||||
_, err = this.RPC().HTTPFirewallRuleSetRPC().CreateOrUpdateHTTPFirewallRuleSetFromConfig(this.AdminContext(), &pb.CreateOrUpdateHTTPFirewallRuleSetFromConfigRequest{
|
||||
FirewallRuleSetConfigJSON: setConfigJSON,
|
||||
})
|
||||
} else {
|
||||
_, err = this.RPC().HTTPFirewallRuleGroupRPC().AddHTTPFirewallRuleGroupSet(this.AdminContext(), &pb.AddHTTPFirewallRuleGroupSetRequest{
|
||||
FirewallRuleGroupId: inboundGroupId,
|
||||
FirewallRuleSetConfigJSON: setConfigJSON,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if rule.Outbound {
|
||||
if ok {
|
||||
set.Id, ok = groupSetMaps[outboundGroupId][set.Name]
|
||||
}
|
||||
set.Rules = outRs
|
||||
setConfigJSON, err := json.Marshal(set)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if ok { // 替换
|
||||
_, err = this.RPC().HTTPFirewallRuleSetRPC().CreateOrUpdateHTTPFirewallRuleSetFromConfig(this.AdminContext(), &pb.CreateOrUpdateHTTPFirewallRuleSetFromConfigRequest{
|
||||
FirewallRuleSetConfigJSON: setConfigJSON,
|
||||
})
|
||||
} else {
|
||||
_, err = this.RPC().HTTPFirewallRuleGroupRPC().AddHTTPFirewallRuleGroupSet(this.AdminContext(), &pb.AddHTTPFirewallRuleGroupSetRequest{
|
||||
FirewallRuleGroupId: outboundGroupId,
|
||||
FirewallRuleSetConfigJSON: setConfigJSON,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 修改策略 当前的入站规则分组
|
||||
for _, groupId := range newInboundGroup {
|
||||
firewallPolicy.Inbound.GroupRefs = append(firewallPolicy.Inbound.GroupRefs, &firewallconfigs.HTTPFirewallRuleGroupRef{
|
||||
IsOn: true,
|
||||
GroupId: groupId,
|
||||
})
|
||||
}
|
||||
// 修改策略 当前的出站规则分组
|
||||
for _, groupId := range newOutboundGroup {
|
||||
firewallPolicy.Outbound.GroupRefs = append(firewallPolicy.Outbound.GroupRefs, &firewallconfigs.HTTPFirewallRuleGroupRef{
|
||||
IsOn: true,
|
||||
GroupId: groupId,
|
||||
})
|
||||
}
|
||||
|
||||
inboundJSON, err := firewallPolicy.InboundJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
outboundJSON, err := firewallPolicy.OutboundJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallPolicyGroups(this.AdminContext(), &pb.UpdateHTTPFirewallPolicyGroupsRequest{
|
||||
HttpFirewallPolicyId: firewallPolicyId,
|
||||
InboundJSON: inboundJSON,
|
||||
OutboundJSON: outboundJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if errRulesBuff != nil { // 导入规则中存在无法分析的规则,将其统计并返回给客户
|
||||
md := stringutil.Md5(errRulesBuff.String())
|
||||
_ = os.MkdirAll(Tea.TmpDir(), 0755)
|
||||
_ = os.WriteFile(Tea.TmpFile(md+".xlsx"), errRulesBuff.Bytes(), 0755)
|
||||
//this.AddHeader("Content-Disposition", "attachment; filename=\"WAF-ALL-Error.xlsx\";")
|
||||
//this.AddHeader("Content-Length", strconv.Itoa(errRulesBuff.Len()))
|
||||
//this.AddHeader("Content-Type", "application/vnd.ms-excel; charset=utf-8")
|
||||
//this.AddHeader("Content-Transfer-Encoding", "binary")
|
||||
//_, _ = this.Write(errRulesBuff.Bytes())
|
||||
this.Data["key"] = md
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
@Author: dp
|
||||
@Description:
|
||||
@File: importErr
|
||||
@Version: 1.0.0
|
||||
@Date: 2025-03-24 17:23
|
||||
*/
|
||||
|
||||
/*
|
||||
@Author: 1usir
|
||||
@Description:
|
||||
@File: importErr.go
|
||||
@Version: 1.0.0
|
||||
@Date: 2024/2/28 14:58
|
||||
*/
|
||||
package waf
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ImportErrAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ImportErrAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *ImportErrAction) RunGet(params struct {
|
||||
Key string
|
||||
}) {
|
||||
filename := Tea.TmpFile(params.Key + ".xlsx")
|
||||
fs, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
this.WriteString("找不到要导出的内容")
|
||||
return
|
||||
}
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"WAF-ALL-Error.xlsx\";")
|
||||
this.AddHeader("Content-Length", strconv.Itoa(len(fs)))
|
||||
this.AddHeader("Content-Type", "application/vnd.ms-excel; charset=utf-8")
|
||||
this.AddHeader("Content-Transfer-Encoding", "binary")
|
||||
_, _ = this.Write(fs)
|
||||
_ = os.RemoveAll(filename)
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"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"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.FirstMenu("index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Keyword string
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
|
||||
countResp, err := this.RPC().HTTPFirewallPolicyRPC().CountAllEnabledHTTPFirewallPolicies(this.AdminContext(), &pb.CountAllEnabledHTTPFirewallPoliciesRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
|
||||
listResp, err := this.RPC().HTTPFirewallPolicyRPC().ListEnabledHTTPFirewallPolicies(this.AdminContext(), &pb.ListEnabledHTTPFirewallPoliciesRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var policyMaps = []maps.Map{}
|
||||
for _, policy := range listResp.HttpFirewallPolicies {
|
||||
var countInbound = 0
|
||||
var countOutbound = 0
|
||||
if len(policy.InboundJSON) > 0 {
|
||||
inboundConfig := &firewallconfigs.HTTPFirewallInboundConfig{}
|
||||
err = json.Unmarshal(policy.InboundJSON, inboundConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countInbound = len(inboundConfig.GroupRefs)
|
||||
}
|
||||
if len(policy.OutboundJSON) > 0 {
|
||||
outboundConfig := &firewallconfigs.HTTPFirewallInboundConfig{}
|
||||
err = json.Unmarshal(policy.OutboundJSON, outboundConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countOutbound = len(outboundConfig.GroupRefs)
|
||||
}
|
||||
|
||||
countClustersResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClustersWithHTTPFirewallPolicyId(this.AdminContext(), &pb.CountAllEnabledNodeClustersWithHTTPFirewallPolicyIdRequest{HttpFirewallPolicyId: policy.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countClusters = countClustersResp.Count
|
||||
|
||||
// mode
|
||||
if len(policy.Mode) == 0 {
|
||||
policy.Mode = firewallconfigs.FirewallModeDefend
|
||||
}
|
||||
|
||||
policyMaps = append(policyMaps, maps.Map{
|
||||
"id": policy.Id,
|
||||
"isOn": policy.IsOn,
|
||||
"name": policy.Name,
|
||||
"mode": policy.Mode,
|
||||
"modeInfo": firewallconfigs.FindFirewallMode(policy.Mode),
|
||||
"countInbound": countInbound,
|
||||
"countOutbound": countOutbound,
|
||||
"countClusters": countClusters,
|
||||
})
|
||||
}
|
||||
|
||||
this.Data["policies"] = policyMaps
|
||||
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/waf/ipadmin"
|
||||
"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)).
|
||||
Helper(NewHelper()).
|
||||
Data("teaMenu", "servers").
|
||||
Data("teaSubMenu", "waf").
|
||||
Prefix("/servers/components/waf").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Get("/policy", new(PolicyAction)).
|
||||
Post("/upgradeTemplate", new(UpgradeTemplateAction)).
|
||||
Get("/groups", new(GroupsAction)).
|
||||
Get("/group", new(GroupAction)).
|
||||
Get("/log", new(LogAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
GetPost("/test", new(TestAction)).
|
||||
GetPost("/export", new(ExportAction)).
|
||||
Get("/exportDownload", new(ExportDownloadAction)).
|
||||
GetPost("/import", new(ImportAction)).
|
||||
Get("/importErr", new(ImportErrAction)).
|
||||
Post("/updateGroupOn", new(UpdateGroupOnAction)).
|
||||
Post("/deleteGroup", new(DeleteGroupAction)).
|
||||
GetPost("/createGroupPopup", new(CreateGroupPopupAction)).
|
||||
Post("/sortGroups", new(SortGroupsAction)).
|
||||
GetPost("/updateGroupPopup", new(UpdateGroupPopupAction)).
|
||||
GetPost("/createSetPopup", new(CreateSetPopupAction)).
|
||||
GetPost("/createRulePopup", new(CreateRulePopupAction)).
|
||||
Post("/sortSets", new(SortSetsAction)).
|
||||
Post("/updateSetOn", new(UpdateSetOnAction)).
|
||||
Post("/deleteSet", new(DeleteSetAction)).
|
||||
GetPost("/updateSetPopup", new(UpdateSetPopupAction)).
|
||||
Get("/setCodePopup", new(SetCodePopupAction)).
|
||||
Post("/count", new(CountAction)).
|
||||
Get("/selectPopup", new(SelectPopupAction)).
|
||||
Post("/testRegexp", new(TestRegexpAction)).
|
||||
|
||||
// IP管理
|
||||
GetPost("/ipadmin", new(ipadmin.IndexAction)).
|
||||
GetPost("/ipadmin/provinces", new(ipadmin.ProvincesAction)).
|
||||
Get("/ipadmin/lists", new(ipadmin.ListsAction)).
|
||||
GetPost("/ipadmin/updateIPPopup", new(ipadmin.UpdateIPPopupAction)).
|
||||
Post("/ipadmin/deleteIP", new(ipadmin.DeleteIPAction)).
|
||||
GetPost("/ipadmin/test", new(ipadmin.TestAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package ipadmin
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteIPAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteIPAction) RunPost(params struct {
|
||||
FirewallPolicyId int64
|
||||
ItemId int64
|
||||
}) {
|
||||
// 日志
|
||||
defer this.CreateLogInfo(codes.WAF_LogDeleteIPFromWAFPolicy, params.FirewallPolicyId, params.ItemId)
|
||||
|
||||
// TODO 判断权限
|
||||
|
||||
_, err := this.RPC().IPItemRPC().DeleteIPItem(this.AdminContext(), &pb.DeleteIPItemRequest{IpItemId: params.ItemId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package ipadmin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"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/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "ipadmin")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
FirewallPolicyId int64
|
||||
}) {
|
||||
this.Data["subMenuItem"] = "region"
|
||||
|
||||
// 当前选中的地区
|
||||
policyConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if policyConfig == nil {
|
||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||
return
|
||||
}
|
||||
|
||||
var deniedCountryIds = []int64{}
|
||||
var allowedCountryIds = []int64{}
|
||||
var countryHTML string
|
||||
var allowSearchEngine bool
|
||||
if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
|
||||
deniedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
||||
allowedCountryIds = policyConfig.Inbound.Region.AllowCountryIds
|
||||
countryHTML = policyConfig.Inbound.Region.CountryHTML
|
||||
allowSearchEngine = policyConfig.Inbound.Region.AllowSearchEngine
|
||||
}
|
||||
this.Data["countryHTML"] = countryHTML
|
||||
this.Data["allowSearchEngine"] = allowSearchEngine
|
||||
|
||||
countriesResp, err := this.RPC().RegionCountryRPC().FindAllRegionCountries(this.AdminContext(), &pb.FindAllRegionCountriesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var deniesCountryMaps = []maps.Map{}
|
||||
var allowedCountryMaps = []maps.Map{}
|
||||
for _, country := range countriesResp.RegionCountries {
|
||||
var countryMap = maps.Map{
|
||||
"id": country.Id,
|
||||
"name": country.DisplayName,
|
||||
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
||||
}
|
||||
if lists.ContainsInt64(deniedCountryIds, country.Id) {
|
||||
deniesCountryMaps = append(deniesCountryMaps, countryMap)
|
||||
}
|
||||
if lists.ContainsInt64(allowedCountryIds, country.Id) {
|
||||
allowedCountryMaps = append(allowedCountryMaps, countryMap)
|
||||
}
|
||||
}
|
||||
this.Data["deniedCountries"] = deniesCountryMaps
|
||||
this.Data["allowedCountries"] = allowedCountryMaps
|
||||
|
||||
// except & only URL Patterns
|
||||
this.Data["exceptURLPatterns"] = []*shared.URLPattern{}
|
||||
this.Data["onlyURLPatterns"] = []*shared.URLPattern{}
|
||||
if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
|
||||
if len(policyConfig.Inbound.Region.CountryExceptURLPatterns) > 0 {
|
||||
this.Data["exceptURLPatterns"] = policyConfig.Inbound.Region.CountryExceptURLPatterns
|
||||
}
|
||||
if len(policyConfig.Inbound.Region.CountryOnlyURLPatterns) > 0 {
|
||||
this.Data["onlyURLPatterns"] = policyConfig.Inbound.Region.CountryOnlyURLPatterns
|
||||
}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
FirewallPolicyId int64
|
||||
DenyCountryIds []int64
|
||||
AllowCountryIds []int64
|
||||
|
||||
ExceptURLPatternsJSON []byte
|
||||
OnlyURLPatternsJSON []byte
|
||||
|
||||
CountryHTML string
|
||||
AllowSearchEngine bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 日志
|
||||
defer this.CreateLogInfo(codes.WAF_LogUpdateForbiddenCountries, params.FirewallPolicyId)
|
||||
|
||||
policyConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if policyConfig == nil {
|
||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||
return
|
||||
}
|
||||
|
||||
if policyConfig.Inbound == nil {
|
||||
policyConfig.Inbound = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||
}
|
||||
if policyConfig.Inbound.Region == nil {
|
||||
policyConfig.Inbound.Region = &firewallconfigs.HTTPFirewallRegionConfig{
|
||||
IsOn: true,
|
||||
}
|
||||
}
|
||||
policyConfig.Inbound.Region.DenyCountryIds = params.DenyCountryIds
|
||||
policyConfig.Inbound.Region.AllowCountryIds = params.AllowCountryIds
|
||||
|
||||
// 例外URL
|
||||
var exceptURLPatterns = []*shared.URLPattern{}
|
||||
if len(params.ExceptURLPatternsJSON) > 0 {
|
||||
err = json.Unmarshal(params.ExceptURLPatternsJSON, &exceptURLPatterns)
|
||||
if err != nil {
|
||||
this.Fail("校验例外URL参数失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
policyConfig.Inbound.Region.CountryExceptURLPatterns = exceptURLPatterns
|
||||
|
||||
// 自定义提示
|
||||
if len(params.CountryHTML) > 32<<10 {
|
||||
this.Fail("提示内容长度不能超出32K")
|
||||
return
|
||||
}
|
||||
policyConfig.Inbound.Region.CountryHTML = params.CountryHTML
|
||||
policyConfig.Inbound.Region.AllowSearchEngine = params.AllowSearchEngine
|
||||
|
||||
// 限制URL
|
||||
var onlyURLPatterns = []*shared.URLPattern{}
|
||||
if len(params.OnlyURLPatternsJSON) > 0 {
|
||||
err = json.Unmarshal(params.OnlyURLPatternsJSON, &onlyURLPatterns)
|
||||
if err != nil {
|
||||
this.Fail("校验限制URL参数失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
policyConfig.Inbound.Region.CountryOnlyURLPatterns = onlyURLPatterns
|
||||
|
||||
inboundJSON, err := json.Marshal(policyConfig.Inbound)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallInboundConfig(this.AdminContext(), &pb.UpdateHTTPFirewallInboundConfigRequest{
|
||||
HttpFirewallPolicyId: params.FirewallPolicyId,
|
||||
InboundJSON: inboundJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user