实现对ACME用户的增删改

This commit is contained in:
刘祥超
2020-11-24 17:36:42 +08:00
parent 169fe50a21
commit 3ba0d58cb8
84 changed files with 497 additions and 174 deletions

View File

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

View File

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

View File

@@ -0,0 +1,46 @@
package users
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
)
type CreatePopupAction struct {
actionutils.ParentAction
}
func (this *CreatePopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreatePopupAction) RunGet(params struct{}) {
this.Show()
}
func (this *CreatePopupAction) RunPost(params struct {
Email string
Description string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("email", params.Email).
Require("请输入邮箱").
Email("请输入正确的邮箱格式")
createResp, err := this.RPC().ACMEUserRPC().CreateACMEUser(this.AdminContext(), &pb.CreateACMEUserRequest{
Email: params.Email,
Description: params.Description,
})
if err != nil {
this.ErrorPage(err)
return
}
// 日志
defer this.CreateLogInfo("创建ACME用户 %d", createResp.AcmeUserId)
this.Success()
}

View File

@@ -0,0 +1,33 @@
package users
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
UserId int64
}) {
defer this.CreateLogInfo("删除ACME用户 %d", params.UserId)
countResp, err := this.RPC().SSLCertRPC().CountSSLCertsWithACMEUserId(this.AdminContext(), &pb.CountSSLCertsWithACMEUserIdRequest{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()
}

View File

@@ -0,0 +1,53 @@
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 {
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),
})
}
this.Data["users"] = userMaps
this.Show()
}

View File

@@ -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()
}

View File

@@ -0,0 +1,60 @@
package users
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type 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
}
this.Data["user"] = maps.Map{
"id": user.Id,
"email": user.Email,
"description": user.Description,
}
this.Show()
}
func (this *UpdatePopupAction) RunPost(params struct {
UserId int64
Description string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改ACME用户 %d", 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()
}

View File

@@ -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{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
certConfig := &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certResp.CertJSON, certConfig)
if err != nil {
this.ErrorPage(err)
return
}
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{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
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()
}

View File

@@ -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")
}
}

View File

@@ -0,0 +1,36 @@
package certs
import (
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
CertId int64
}) {
// 创建日志
defer this.CreateLog(oplogs.LevelInfo, "删除SSL证书 %d", params.CertId)
// 是否正在被使用
countResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
if countResp.Count > 0 {
this.Fail("此证书正在被某些服务引用,请先修改服务后再删除。")
}
_, err = this.RPC().SSLCertRPC().DeleteSSLCert(this.AdminContext(), &pb.DeleteSSLCertRequest{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -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"
"strconv"
)
type DownloadCertAction struct {
actionutils.ParentAction
}
func (this *DownloadCertAction) Init() {
this.Nav("", "", "")
}
func (this *DownloadCertAction) RunGet(params struct {
CertId int64
}) {
defer this.CreateLogInfo("下载SSL证书 %d", params.CertId)
certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
certConfig := &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certResp.CertJSON, 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)
}

View File

@@ -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"
"strconv"
)
type DownloadKeyAction struct {
actionutils.ParentAction
}
func (this *DownloadKeyAction) Init() {
this.Nav("", "", "")
}
func (this *DownloadKeyAction) RunGet(params struct {
CertId int64
}) {
defer this.CreateLogInfo("下载SSL密钥 %d", params.CertId)
certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
certConfig := &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certResp.CertJSON, 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)
}

View File

@@ -0,0 +1,82 @@
package certs
import (
"archive/zip"
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"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("下载SSL证书压缩包 %d", params.CertId)
certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
certConfig := &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certResp.CertJSON, 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
}
}
}

View File

@@ -0,0 +1,35 @@
package certs
import (
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"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["teaMenu"] = "servers"
action.Data["leftMenuItems"] = []maps.Map{
{
"name": "证书",
"url": "/servers/certs",
"isActive": action.Data.GetString("leftMenuItem") == "cert",
},
{
"name": "免费证书",
"url": "/servers/certs/acme",
"isActive": action.Data.GetString("leftMenuItem") == "acme",
},
}
}

View File

@@ -0,0 +1,164 @@
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 {
Type string
}) {
this.Data["type"] = params.Type
countAll := int64(0)
countCA := int64(0)
countAvailable := int64(0)
countExpired := int64(0)
count7Days := int64(0)
count30Days := int64(0)
// 计算数量
{
// all
resp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{})
if err != nil {
this.ErrorPage(err)
return
}
countAll = resp.Count
// CA
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
IsCA: true,
})
if err != nil {
this.ErrorPage(err)
return
}
countCA = resp.Count
// available
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
IsAvailable: true,
})
if err != nil {
this.ErrorPage(err)
return
}
countAvailable = resp.Count
// expired
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
IsExpired: true,
})
if err != nil {
this.ErrorPage(err)
return
}
countExpired = resp.Count
// expire in 7 days
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
ExpiringDays: 7,
})
if err != nil {
this.ErrorPage(err)
return
}
count7Days = resp.Count
// expire in 30 days
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
ExpiringDays: 30,
})
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{Offset: page.Offset, Size: page.Size})
case "ca":
page = this.NewPage(countCA)
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{IsCA: true, Offset: page.Offset, Size: page.Size})
case "available":
page = this.NewPage(countAvailable)
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{IsAvailable: true, Offset: page.Offset, Size: page.Size})
case "expired":
page = this.NewPage(countExpired)
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{IsExpired: true, Offset: page.Offset, Size: page.Size})
case "7days":
page = this.NewPage(count7Days)
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{ExpiringDays: 7, Offset: page.Offset, Size: page.Size})
case "30days":
page = this.NewPage(count30Days)
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{ExpiringDays: 30, Offset: page.Offset, Size: page.Size})
default:
page = this.NewPage(countAll)
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{})
}
if err != nil {
this.ErrorPage(err)
return
}
certConfigs := []*sslconfigs.SSLCertConfig{}
err = json.Unmarshal(listResp.CertsJSON, &certConfigs)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["certs"] = certConfigs
certMaps := []maps.Map{}
nowTime := time.Now().Unix()
for _, certConfig := range certConfigs {
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{CertId: certConfig.Id})
if err != nil {
this.ErrorPage(err)
return
}
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,
})
}
this.Data["certInfos"] = certMaps
this.Data["page"] = page.AsHTML()
this.Show()
}

View File

@@ -0,0 +1,48 @@
package certs
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/users"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth()).
Helper(NewHelper()).
Data("teaSubMenu", "cert").
Prefix("/servers/certs").
Data("leftMenuItem", "cert").
Get("", new(IndexAction)).
GetPost("/uploadPopup", new(UploadPopupAction)).
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)).
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)).
EndAll()
})
}

View File

@@ -0,0 +1,75 @@
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 SelectPopupAction struct {
actionutils.ParentAction
}
func (this *SelectPopupAction) Init() {
this.Nav("", "", "")
}
func (this *SelectPopupAction) RunGet(params struct {
ViewSize string
}) {
// TODO 支持关键词搜索
// TODO 列出常用的证书供用户选择
if len(params.ViewSize) == 0 {
params.ViewSize = "normal"
}
this.Data["viewSize"] = params.ViewSize
countResp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{})
if err != nil {
this.ErrorPage(err)
return
}
page := this.NewPage(countResp.Count)
this.Data["page"] = page.AsHTML()
listResp, err := this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
Offset: page.Offset,
Size: page.Size,
})
certConfigs := []*sslconfigs.SSLCertConfig{}
err = json.Unmarshal(listResp.CertsJSON, &certConfigs)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["certs"] = certConfigs
certMaps := []maps.Map{}
nowTime := time.Now().Unix()
for _, certConfig := range certConfigs {
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{CertId: 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,
})
}
this.Data["certInfos"] = certMaps
this.Show()
}

View File

@@ -0,0 +1,133 @@
package certs
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"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/actions"
)
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{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
certConfigJSON := certConfigResp.CertJSON
if len(certConfigJSON) == 0 {
this.NotFound("cert", params.CertId)
return
}
certConfig := &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certConfigJSON, certConfig)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["certConfig"] = certConfig
this.Show()
}
func (this *UpdatePopupAction) RunPost(params struct {
CertId int64
Name string
IsCA bool
Description string
IsOn bool
CertFile *actions.File
KeyFile *actions.File
Must *actions.Must
}) {
// 创建日志
defer this.CreateLog(oplogs.LevelInfo, "修改SSL证书 %d", params.CertId)
// 查询Cert
certConfigResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
certConfigJSON := certConfigResp.CertJSON
if len(certConfigJSON) == 0 {
this.NotFound("cert", params.CertId)
return
}
certConfig := &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certConfigJSON, certConfig)
if err != nil {
this.ErrorPage(err)
return
}
// 校验参数
params.Must.
Field("name", params.Name).
Require("请输入证书说明")
if params.CertFile != nil {
certConfig.CertData, err = params.CertFile.Read()
if err != nil {
this.Fail("读取证书文件内容错误,请重新上传")
}
}
if !params.IsCA {
if params.KeyFile != nil {
certConfig.KeyData, err = params.KeyFile.Read()
if err != nil {
this.Fail("读取密钥文件内容错误,请重新上传")
}
}
}
// 校验
certConfig.IsCA = params.IsCA
err = certConfig.Init()
if err != nil {
if params.IsCA {
this.Fail("证书校验错误:" + err.Error())
} else {
this.Fail("证书或密钥校验错误:" + err.Error())
}
}
// 保存
_, err = this.RPC().SSLCertRPC().UpdateSSLCert(this.AdminContext(), &pb.UpdateSSLCertRequest{
CertId: 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()
}

View File

@@ -0,0 +1,121 @@
package certs
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"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/actions"
)
type UploadPopupAction struct {
actionutils.ParentAction
}
func (this *UploadPopupAction) Init() {
this.Nav("", "", "")
}
func (this *UploadPopupAction) RunGet(params struct{}) {
this.Show()
}
func (this *UploadPopupAction) RunPost(params struct {
Name string
IsCA bool
Description string
IsOn bool
CertFile *actions.File
KeyFile *actions.File
Must *actions.Must
}) {
params.Must.
Field("name", params.Name).
Require("请输入证书说明")
certData := []byte{}
keyData := []byte{}
if params.CertFile == nil {
this.Fail("请选择要上传的证书文件")
}
var err error
certData, err = params.CertFile.Read()
if err != nil {
this.Fail("读取证书文件内容错误,请重新上传")
}
if !params.IsCA {
if params.KeyFile == nil {
this.Fail("请选择要上传的私钥文件")
} else {
keyData, err = params.KeyFile.Read()
if err != nil {
this.Fail("读取密钥文件内容错误,请重新上传")
}
}
}
// 校验
sslConfig := &sslconfigs.SSLCertConfig{
IsCA: params.IsCA,
CertData: certData,
KeyData: keyData,
}
err = sslConfig.Init()
if err != nil {
if params.IsCA {
this.Fail("证书校验错误:" + err.Error())
} else {
this.Fail("证书或密钥校验错误:" + err.Error())
}
}
// 保存
createResp, err := this.RPC().SSLCertRPC().CreateSSLCert(this.AdminContext(), &pb.CreateSSLCertRequest{
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
ServerName: "",
IsCA: params.IsCA,
CertData: certData,
KeyData: keyData,
TimeBeginAt: sslConfig.TimeBeginAt,
TimeEndAt: sslConfig.TimeEndAt,
DnsNames: sslConfig.DNSNames,
CommonNames: sslConfig.CommonNames,
})
if err != nil {
this.ErrorPage(err)
return
}
// 查询已创建的证书并返回,方便调用者进行后续处理
certId := createResp.CertId
configResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: certId})
if err != nil {
this.ErrorPage(err)
return
}
certConfig := &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(configResp.CertJSON, 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.CreateLog(oplogs.LevelInfo, "上传SSL证书 %d", certId)
this.Success()
}

View File

@@ -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 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{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
certConfig := &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certResp.CertJSON, certConfig)
if err != nil {
this.ErrorPage(err)
return
}
this.Write(certConfig.CertData)
}

View File

@@ -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{CertId: params.CertId})
if err != nil {
this.ErrorPage(err)
return
}
certConfig := &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certResp.CertJSON, certConfig)
if err != nil {
this.ErrorPage(err)
return
}
this.Write(certConfig.KeyData)
}