mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-28 21:39:06 +08:00
feat: 修改菜单位置 证书管理放在二级菜单
This commit is contained in:
parent
681a0c9106
commit
c7e0e3320a
@ -38,6 +38,19 @@ func (b *BaseApi) CreateWebsiteSSL(c *gin.Context) {
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
func (b *BaseApi) RenewWebsiteSSL(c *gin.Context) {
|
||||
var req dto.WebsiteSSLRenew
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := websiteSSLService.Renew(req.SSLID); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) ApplyWebsiteSSL(c *gin.Context) {
|
||||
var req dto.WebsiteSSLApply
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@ -73,10 +86,24 @@ func (b *BaseApi) DeleteWebsiteSSL(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := websiteSSLService.Delete(id); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) GetWebsiteSSL(c *gin.Context) {
|
||||
|
||||
websiteId, err := helper.GetIntParamByKey(c, "websiteId")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
websiteSSL, err := websiteSSLService.GetWebsiteSSL(websiteId)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, websiteSSL)
|
||||
}
|
||||
|
@ -10,15 +10,15 @@ type SSLProvider string
|
||||
|
||||
const (
|
||||
DNSAccount = "dnsAccount"
|
||||
DnsCommon = "dnsCommon"
|
||||
DnsManual = "dnsManual"
|
||||
Http = "http"
|
||||
)
|
||||
|
||||
type WebsiteSSLCreate struct {
|
||||
Domains []string `json:"domains" validate:"required"`
|
||||
PrimaryDomain string `json:"primaryDomain" validate:"required"`
|
||||
OtherDomains string `json:"otherDomains"`
|
||||
Provider SSLProvider `json:"provider" validate:"required"`
|
||||
WebsiteID uint `json:"websiteId" validate:"required"`
|
||||
AcmeAccountID uint `json:"acmeAccountId"`
|
||||
AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
|
||||
DnsAccountID uint `json:"dnsAccountId"`
|
||||
}
|
||||
|
||||
@ -37,3 +37,7 @@ type WebsiteDNSRes struct {
|
||||
Value string `json:"value"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type WebsiteSSLRenew struct {
|
||||
SSLID uint `json:"SSLId" validate:"required"`
|
||||
}
|
||||
|
@ -4,16 +4,18 @@ import "time"
|
||||
|
||||
type WebSiteSSL struct {
|
||||
BaseModel
|
||||
Alias string `gorm:"type:varchar(64);not null" json:"alias"`
|
||||
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
|
||||
Pem string `gorm:"type:longtext;not null" json:"pem"`
|
||||
Domain string `gorm:"type:varchar(256);not null" json:"domain"`
|
||||
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
IssuerName string `gorm:"type:varchar(64);not null" json:"issuerName"`
|
||||
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
StartDate time.Time `json:"startDate"`
|
||||
PrimaryDomain string `gorm:"type:varchar(256);not null" json:"primaryDomain"`
|
||||
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
|
||||
Pem string `gorm:"type:longtext;not null" json:"pem"`
|
||||
Domains string `gorm:"type:varchar(256);not null" json:"domains"`
|
||||
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
Provider string `gorm:"type:varchar(64);not null" json:"provider"`
|
||||
Organization string `gorm:"type:varchar(64);not null" json:"organization"`
|
||||
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
|
||||
AcmeAccountID uint `gorm:"type:integer;not null" json:"acmeAccountId"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
StartDate time.Time `json:"startDate"`
|
||||
}
|
||||
|
||||
func (w WebSiteSSL) TableName() string {
|
||||
|
@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
||||
@ -31,48 +32,59 @@ func (w WebSiteSSLService) Create(create dto.WebsiteSSLCreate) (dto.WebsiteSSLCr
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(create.DnsAccountID))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
client, err := ssl.NewPrivateKeyClient(acmeAccount.Email, acmeAccount.PrivateKey)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
if create.Provider == dto.Http {
|
||||
|
||||
} else {
|
||||
switch create.Provider {
|
||||
case dto.DNSAccount:
|
||||
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(create.DnsAccountID))
|
||||
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if err := client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization); err != nil {
|
||||
return res, err
|
||||
}
|
||||
case dto.Http:
|
||||
case dto.DnsManual:
|
||||
|
||||
}
|
||||
|
||||
resource, err := client.GetSSL(create.Domains)
|
||||
domains := []string{create.PrimaryDomain}
|
||||
otherDomainArray := strings.Split(create.OtherDomains, "\n")
|
||||
if create.OtherDomains != "" {
|
||||
domains = append(otherDomainArray, domains...)
|
||||
}
|
||||
resource, err := client.ObtainSSL(domains)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
var websiteSSL model.WebSiteSSL
|
||||
|
||||
//TODO 判断同一个账号下的证书
|
||||
websiteSSL.Alias = create.Domains[0]
|
||||
websiteSSL.Domain = strings.Join(create.Domains, ",")
|
||||
websiteSSL.DnsAccountID = create.DnsAccountID
|
||||
websiteSSL.AcmeAccountID = acmeAccount.ID
|
||||
websiteSSL.Provider = string(create.Provider)
|
||||
websiteSSL.Domains = strings.Join(otherDomainArray, ",")
|
||||
websiteSSL.PrimaryDomain = create.PrimaryDomain
|
||||
websiteSSL.PrivateKey = string(resource.PrivateKey)
|
||||
websiteSSL.Pem = string(resource.Certificate)
|
||||
websiteSSL.CertURL = resource.CertURL
|
||||
|
||||
cert, err := x509.ParseCertificate([]byte(websiteSSL.Pem))
|
||||
certBlock, _ := pem.Decode(resource.Certificate)
|
||||
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
||||
if err != nil {
|
||||
return dto.WebsiteSSLCreate{}, err
|
||||
}
|
||||
websiteSSL.ExpireDate = cert.NotAfter
|
||||
websiteSSL.StartDate = cert.NotBefore
|
||||
websiteSSL.Type = cert.Issuer.CommonName
|
||||
websiteSSL.IssuerName = cert.Issuer.Organization[0]
|
||||
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||
|
||||
if err := createPemFile(websiteSSL); err != nil {
|
||||
return dto.WebsiteSSLCreate{}, err
|
||||
}
|
||||
//if err := createPemFile(websiteSSL); err != nil {
|
||||
// return dto.WebsiteSSLCreate{}, err
|
||||
//}
|
||||
|
||||
if err := websiteSSLRepo.Create(context.TODO(), &websiteSSL); err != nil {
|
||||
return res, err
|
||||
@ -81,6 +93,55 @@ func (w WebSiteSSLService) Create(create dto.WebsiteSSLCreate) (dto.WebsiteSSLCr
|
||||
return create, nil
|
||||
}
|
||||
|
||||
func (w WebSiteSSLService) Renew(sslId uint) error {
|
||||
|
||||
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(sslId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(websiteSSL.AcmeAccountID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := ssl.NewPrivateKeyClient(acmeAccount.Email, acmeAccount.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch websiteSSL.Provider {
|
||||
case dto.DNSAccount:
|
||||
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(websiteSSL.DnsAccountID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization); err != nil {
|
||||
return err
|
||||
}
|
||||
case dto.Http:
|
||||
case dto.DnsManual:
|
||||
|
||||
}
|
||||
|
||||
resource, err := client.RenewSSL(websiteSSL.CertURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
websiteSSL.PrivateKey = string(resource.PrivateKey)
|
||||
websiteSSL.Pem = string(resource.Certificate)
|
||||
websiteSSL.CertURL = resource.CertURL
|
||||
certBlock, _ := pem.Decode(resource.Certificate)
|
||||
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
websiteSSL.ExpireDate = cert.NotAfter
|
||||
websiteSSL.StartDate = cert.NotBefore
|
||||
websiteSSL.Type = cert.Issuer.CommonName
|
||||
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||
|
||||
return websiteSSLRepo.Save(websiteSSL)
|
||||
}
|
||||
|
||||
func (w WebSiteSSLService) Apply(apply dto.WebsiteSSLApply) (dto.WebsiteSSLApply, error) {
|
||||
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(apply.SSLID))
|
||||
if err != nil {
|
||||
@ -96,10 +157,10 @@ func (w WebSiteSSLService) Apply(apply dto.WebsiteSSLApply) (dto.WebsiteSSLApply
|
||||
nginxParams := getNginxParamsFromStaticFile(dto.SSL)
|
||||
for i, param := range nginxParams {
|
||||
if param.Name == "ssl_certificate" {
|
||||
nginxParams[i].Params = []string{path.Join("/etc/nginx/ssl", websiteSSL.Alias, "fullchain.pem")}
|
||||
nginxParams[i].Params = []string{path.Join("/etc/nginx/ssl", websiteSSL.PrimaryDomain, "fullchain.pem")}
|
||||
}
|
||||
if param.Name == "ssl_certificate_key" {
|
||||
nginxParams[i].Params = []string{path.Join("/etc/nginx/ssl", websiteSSL.Alias, "privkey.pem")}
|
||||
nginxParams[i].Params = []string{path.Join("/etc/nginx/ssl", websiteSSL.PrimaryDomain, "privkey.pem")}
|
||||
}
|
||||
}
|
||||
if err := updateNginxConfig(website, nginxParams, dto.SSL); err != nil {
|
||||
@ -134,6 +195,20 @@ func (w WebSiteSSLService) GetDNSResolve(req dto.WebsiteDNSReq) (dto.WebsiteDNSR
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (w WebSiteSSLService) GetWebsiteSSL(websiteId uint) (dto.WebsiteSSLDTO, error) {
|
||||
var res dto.WebsiteSSLDTO
|
||||
website, err := websiteRepo.GetFirst(commonRepo.WithByID(websiteId))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(website.WebSiteSSLID))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res.WebSiteSSL = websiteSSL
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (w WebSiteSSLService) Delete(id uint) error {
|
||||
return websiteSSLRepo.DeleteBy(commonRepo.WithByID(id))
|
||||
}
|
||||
|
@ -318,7 +318,7 @@ func createPemFile(websiteSSL model.WebSiteSSL) error {
|
||||
return err
|
||||
}
|
||||
|
||||
configDir := path.Join(constant.AppInstallDir, "nginx", nginxInstall.Name, "ssl", websiteSSL.Alias)
|
||||
configDir := path.Join(constant.AppInstallDir, "nginx", nginxInstall.Name, "ssl", websiteSSL.PrimaryDomain)
|
||||
fileOp := files.NewFileOp()
|
||||
|
||||
if !fileOp.Stat(configDir) {
|
||||
|
@ -16,9 +16,11 @@ func (a *WebsiteSSLRouter) InitWebsiteSSLRouter(Router *gin.RouterGroup) {
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
groupRouter.POST("/search", baseApi.PageWebsiteSSL)
|
||||
groupRouter.POST("/renew", baseApi.RenewWebsiteSSL)
|
||||
groupRouter.POST("", baseApi.CreateWebsiteSSL)
|
||||
groupRouter.POST("/apply", baseApi.ApplyWebsiteSSL)
|
||||
groupRouter.POST("/resolve", baseApi.GetDNSResolve)
|
||||
groupRouter.POST("/:id", baseApi.DeleteWebsiteSSL)
|
||||
groupRouter.DELETE("/:id", baseApi.DeleteWebsiteSSL)
|
||||
groupRouter.GET("/:websiteId", baseApi.GetWebsiteSSL)
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ type server interface {
|
||||
func initServer(address string, router *gin.Engine) server {
|
||||
s := endless.NewServer(address, router)
|
||||
s.ReadHeaderTimeout = 20 * time.Second
|
||||
s.WriteTimeout = 20 * time.Second
|
||||
s.WriteTimeout = 60 * time.Second
|
||||
s.MaxHeaderBytes = 1 << 20
|
||||
return s
|
||||
}
|
||||
|
@ -1,27 +1,27 @@
|
||||
-----BEGIN privateKey-----
|
||||
MIIEpAIBAAKCAQEAk+3c1uehn2/YRZI/GVUb0mM51OxGTyiGtaVp9rCCMx9ajvgN
|
||||
eVkF+yBqd7C3B2doKUe4Nprl0j1w3mM1Ol0FisqBjOm7DNq212//CtyjCYrbmCDE
|
||||
DNXDI+3k7SImPGxDoCRQl/4rcRSZGAJe/BdW3U70UZU5203B8AWf5c8basWaB4gU
|
||||
3rGK08f6qqQRGkoEL5W+b5LHxJO1xNrFDdRh0Qi3hzl8c5fIcqCgSQikyGoCSSLh
|
||||
deoiCxl2ASuJ9xgbr7MLP5oN68T5AXduhbo87bsuweKxwe2D0XlM1PbfUGismqjR
|
||||
zD/rPa0QRnRis5e0qxyyi5I8lmODa0kn6tAFsQIDAQABAoIBABCj1Q+nhpq0rhNF
|
||||
XCuxUyvbVYoJ+e61lFGihcTmHf86K6mhZYKc7PtOritAiZYfn6vlEWezDN8VYjjh
|
||||
1/70r8bo+KGtOQk9IQwi4QGLyBsur3zxUpxO/2BvRi0Whk6Nrx24eAhg4uoZcw8s
|
||||
VRruVSsX0ovKyXNNz978AvyKy367B8x3ZWQdjS35qerP23FCPlrEsdQpm531M6L7
|
||||
lihX4oV9EVyRxmZOohR2nPy5TBxE9oQOSGNzsExO6zaOw6uq0MvOhu3ih1foQVA0
|
||||
IilCvJMwzaeufF2u0LKcHmo7OHPNqDwOYWmgf//q3FBkOi05FVI/rO084ENJcJFz
|
||||
5TDtSHECgYEAw9QqMr9p9su4VTFAG3+2+9FnL8Bo6xgUtkeKGJr4PapnVRn28SIS
|
||||
Qv6SupcB/CBNuUX9NV1GbBjL9XJreTWW3FVWiwsBmIoJ+Z1RUn5/WD66jIVHfbzl
|
||||
cpw/yECeoKOJL0QRqPneNBfAYbsw6+PFpybKSCZ3f7adAGhOI3aPk+MCgYEAwWHt
|
||||
cgss3RyFKbG5Tpo87Pf7R/PNOIEhLrXgQr7E+9Iw6YYDy6DMw/3SrH1w5DEr4nc+
|
||||
Pim41TMytdhwiPZXSEppL1lavhU1VGJuiQT59h5bB+XJUVKRf91otat8ILS3n3L5
|
||||
l2Ob3BUEkLSjW4lIcxQxG3c8/rV9UH0zLoNx/FsCgYEAwIGL7hE/MK55ib39oEq/
|
||||
bfMfddC3Ewy8J6hR9/g3uh8Or5jzqX3t58/sG+Mgv2JeJZjI3rHP7am+ro2JW0E0
|
||||
CWsWxV7Pdc2VGr3s2KSjuPMJXeQTMGcGQ9GX3dqwVYgN7toCZlMjfaAvraNf5zQk
|
||||
9DlsttqhtHmnA2SGE9SUNjMCgYBxZ91YkOcpcA1Diz7xso/iI/cPlhEWftuXyf8P
|
||||
BVL9nqEigX3+T3llwpdmolWu7Isgzu8Ig20qUlD9xUURfO1oroKKyurlKAjTSLor
|
||||
zmhMBjc6JW5vK226P3yldUBg6bn5XvKx7i873HOF7PkTuCltmzzFL6LseEBaEGIQ
|
||||
d/NDmwKBgQCKWe1wwyeiqhmJXV/AGMNNECeLdH8G9kBKt6OAPMISxDHQOkP3GDkG
|
||||
HwqE00jCweDdDUHEbZ0gW299KCe8u6kBD5UWKiuUARBpiudlOvoKazCnhNKrCDfz
|
||||
nAQrIod4nus0mRhVTBwxzmBPsdQ/rgmtGUd+RutxPgJJzjCVMAsFeQ==
|
||||
MIIEogIBAAKCAQEAzyO15932XuFy8akJwckUD67T6bJRpRYlobPjmNVGwHWQVWK7
|
||||
UerUE9zWUcqPvI0fcau/llvgihjEbmfDdQEXUOdgLkZTo8xJSh5I0NyuQ69X1ltV
|
||||
f3QxYgmgdOB/xIcIn5RKlkJ2R6BAUNMl523FrEZsDqXrVvNUijy7K+Euc3YjSBQT
|
||||
crEqJy32nrbLfT6WrvoKz0aT7ygzIdbwr3xErQmI3aKv3YRmBYMVRTVYVwFJWnAh
|
||||
+MawfrzW39DCBusNjVSWkuJCeHAUMGsrSJl2dnePR69eyQ4syxS8j6TWjKitqkQ/
|
||||
qH3LJAp6uMnRj2we761R5xH4UU11Go4iGiQZOwIDAQABAoIBACm+IY9bbKXMOxS2
|
||||
IvA5bGCIs83ZkJh7MRQ4IzqOaFaqmm6KmgM1Fo32J/6Nmo+9xMNsgAx18XcC7Lrv
|
||||
EDWJBcDZD8njhEFzDqXwGm50um2LbWEWQNGRgc4m8H39K+JX8AXwpWNIe3uNsMhY
|
||||
9L+BoJ9KBcah6x43pSbCfFmoZGsB27M/smMGM6cLH6b042oLKmvqcpepHkRE8ulg
|
||||
p0AercIWkSPbwKtZPsvT6YOMJaxeM4TXdQ1PYHzHmhozuC7/HrJfD2DrNT8ZXk/9
|
||||
t68d+iMgHT2HUnptkq0FT1gyo1QjBQD3d2vEbuLomOlWlqUNpUw2KCBEvno80vnb
|
||||
dkcRTgECgYEA9ZDvFcKBVGzcMJKbIvNaLqs1V6ZRr6ejgHM7jsvFbIhTEPVZbARr
|
||||
ZmYYw4Ox+SkX10j/49e+33c35t/YvcBdtwOZFZfZb0/nhUA378IgpzGsPCtRJ4kk
|
||||
fryCxJAQ1OOos+HOQcU/Attj7qCN/pZzpGxn9CTomMwjU1+oh72nUjsCgYEA1/DN
|
||||
ndJyHSbfTLQ7Pxy7SNgeb7Pnf7+JrRLoDU25j3WOQyMFUKie6tyErKz+EOriuL14
|
||||
CXfXdU2IBZPjlC911OP8yvfr9ZjehFQVY1K5XybSfVDjCFOgACeTTJQscuJtS/1K
|
||||
qWi+S3c9URyG9Jwx3eVEFJOunw9nKrEFqTLq5QECgYAk8f1GhND4ZrhqBmSYyYwT
|
||||
4WZRHZDEoLAUr0GSpk25mnkE4CTn/3I5IbswDyxDlE8l8LGvEdKBxGoArkTpp3ty
|
||||
AXSSrxnjiV4HyjWgONC41txW4R2AmT2IY8w4zoP5w5aqGZrygj6Mq31JdZZnazNS
|
||||
1Yx+St9DvdLCxG2SnpIB6QKBgEjyXNNysv/sEMT9oYIJd6786xM7B/ocvyqLV36f
|
||||
Ag9XW+6MFxCPVdfrFJqsectHPb3Aq5svM8a5oTiZI+j8O2bmeZArPjeiI5E6Qlti
|
||||
J6LgH30b5QX8EfHbbKQS7g0FNnzUHPOroZUmu7z50REy7pmSCHSXCwdKkcRXNp1Y
|
||||
yQcBAoGAZfeK3WoHce0cTZKdll2Jppl3zG1U8CCUNBS7mL+kJcJNW6kEkvBqhD4q
|
||||
XvRSkLmiEwcz20TyjqTThhuxpL8s1FrfjUtckoQQJHgMr63u/Y8ypAKMLAkwfZsT
|
||||
kjXbp912RYSRhIme/hdrNoDK7BNEFSQ6A78DHZlRL3prGbovwDw=
|
||||
-----END privateKey-----
|
||||
|
@ -85,9 +85,8 @@ func NewPrivateKeyClient(email string, privateKey string) (*AcmeClient, error) {
|
||||
|
||||
func newConfig(user *AcmeUser) *lego.Config {
|
||||
config := lego.NewConfig(user)
|
||||
config.CADirURL = "https://acme-v02.api.letsencrypt.org/directory"
|
||||
config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
config.UserAgent = "acm_go/0.0.1"
|
||||
config.Certificate.KeyType = certcrypto.RSA2048
|
||||
|
||||
return config
|
||||
}
|
||||
|
@ -99,12 +99,12 @@ func (c *AcmeClient) UseDns(dnsType DnsType, params string) error {
|
||||
}
|
||||
}
|
||||
|
||||
return c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(6*time.Minute))
|
||||
return c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(3*time.Minute))
|
||||
}
|
||||
|
||||
func (c *AcmeClient) UseManualDns(domains []string) (*Resolve, error) {
|
||||
p := &manualDnsProvider{}
|
||||
if err := c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(6*time.Minute)); err != nil {
|
||||
if err := c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(3*time.Minute)); err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ func (c *AcmeClient) UseHTTP() {
|
||||
|
||||
}
|
||||
|
||||
func (c *AcmeClient) GetSSL(domains []string) (certificate.Resource, error) {
|
||||
func (c *AcmeClient) ObtainSSL(domains []string) (certificate.Resource, error) {
|
||||
|
||||
request := certificate.ObtainRequest{
|
||||
Domains: domains,
|
||||
@ -139,6 +139,20 @@ func (c *AcmeClient) GetSSL(domains []string) (certificate.Resource, error) {
|
||||
return *certificates, nil
|
||||
}
|
||||
|
||||
func (c *AcmeClient) RenewSSL(certUrl string) (certificate.Resource, error) {
|
||||
|
||||
certificates, err := c.Client.Certificate.Get(certUrl, true)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
}
|
||||
certificates, err = c.Client.Certificate.Renew(*certificates, true, true, "")
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
}
|
||||
|
||||
return *certificates, nil
|
||||
}
|
||||
|
||||
type Resolve struct {
|
||||
Key string
|
||||
Value string
|
||||
|
@ -118,9 +118,10 @@ export namespace WebSite {
|
||||
}
|
||||
|
||||
export interface SSL extends CommonModel {
|
||||
primaryDomain: string;
|
||||
privateKey: string;
|
||||
pem: string;
|
||||
domain: string;
|
||||
otherDomains: string;
|
||||
certURL: string;
|
||||
type: string;
|
||||
issuerName: string;
|
||||
@ -129,9 +130,9 @@ export namespace WebSite {
|
||||
}
|
||||
|
||||
export interface SSLCreate {
|
||||
domains: string[];
|
||||
primaryDomain: string;
|
||||
otherDomains: string;
|
||||
provider: string;
|
||||
websiteId: number;
|
||||
acmeAccountId: number;
|
||||
dnsAccountId: number;
|
||||
}
|
||||
@ -141,6 +142,10 @@ export namespace WebSite {
|
||||
SSLId: number;
|
||||
}
|
||||
|
||||
export interface SSLRenew {
|
||||
SSLId: number;
|
||||
}
|
||||
|
||||
export interface AcmeAccount extends CommonModel {
|
||||
email: string;
|
||||
url: string;
|
||||
|
@ -98,10 +98,18 @@ export const DeleteSSL = (id: number) => {
|
||||
return http.delete<any>(`/websites/ssl/${id}`);
|
||||
};
|
||||
|
||||
export const GetWebsiteSSL = (websiteId: number) => {
|
||||
return http.get<WebSite.SSL>(`/websites/ssl/${websiteId}`);
|
||||
};
|
||||
|
||||
export const ApplySSL = (req: WebSite.SSLApply) => {
|
||||
return http.post<WebSite.SSLApply>(`/websites/ssl/apply`, req);
|
||||
};
|
||||
|
||||
export const RenewSSL = (req: WebSite.SSLRenew) => {
|
||||
return http.post<any>(`/websites/ssl/renew`, req);
|
||||
};
|
||||
|
||||
export const GetDnsResolve = (req: WebSite.DNSResolveReq) => {
|
||||
return http.post<WebSite.DNSResolve>(`/websites/ssl/resolve`, req);
|
||||
};
|
||||
|
@ -37,6 +37,7 @@ export const useDeleteData = <P = any, R = any>(
|
||||
})
|
||||
.finally(() => {
|
||||
loading = false;
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
});
|
||||
};
|
||||
|
@ -131,6 +131,7 @@ export default {
|
||||
project: '项目',
|
||||
config: '配置',
|
||||
firewall: '防火墙',
|
||||
ssl: '证书',
|
||||
database: '数据库',
|
||||
container: '容器',
|
||||
cronjob: '计划任务',
|
||||
@ -704,7 +705,7 @@ export default {
|
||||
manual: '手动解析',
|
||||
key: '密钥',
|
||||
check: '查看',
|
||||
accountManage: '账户管理',
|
||||
acmeAccountManage: 'Acme 账户管理',
|
||||
email: '邮箱',
|
||||
addAccount: '新增账户',
|
||||
acmeAccount: 'Acme 账户',
|
||||
@ -714,5 +715,10 @@ export default {
|
||||
brand: '品牌',
|
||||
deploySSL: '部署',
|
||||
deploySSLHelper: '确定部署证书?',
|
||||
ssl: '证书',
|
||||
dnsAccountManage: 'DNS 账户管理',
|
||||
renewSSL: '续签',
|
||||
renewHelper: '确定续签证书?',
|
||||
renewSuccess: '续签证书',
|
||||
},
|
||||
};
|
||||
|
@ -13,21 +13,29 @@ const webSiteRouter = {
|
||||
{
|
||||
path: '/websites',
|
||||
name: 'Website',
|
||||
component: () => import('@/views/website/project/index.vue'),
|
||||
component: () => import('@/views/website/website/index.vue'),
|
||||
meta: {
|
||||
title: 'menu.project',
|
||||
title: 'menu.website',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/websites/:id/config/:tab',
|
||||
name: 'WebsiteConfig',
|
||||
component: () => import('@/views/website/project/config/index.vue'),
|
||||
component: () => import('@/views/website/website/config/index.vue'),
|
||||
hidden: true,
|
||||
props: true,
|
||||
meta: {
|
||||
activeMenu: '/websites',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/websites/ssl',
|
||||
name: 'SSL',
|
||||
component: () => import('@/views/website/ssl/index.vue'),
|
||||
meta: {
|
||||
title: 'menu.ssl',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/websites/nginx',
|
||||
name: 'Config',
|
||||
@ -36,14 +44,6 @@ const webSiteRouter = {
|
||||
title: 'menu.config',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/websites/firewall',
|
||||
name: 'Firewall',
|
||||
component: () => import('@/views/website/project/index.vue'),
|
||||
meta: {
|
||||
title: 'menu.firewall',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<LayoutContent></LayoutContent>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import LayoutContent from '@/layout/layout-content.vue';
|
||||
</script>
|
@ -1,5 +0,0 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup></script>
|
@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<el-tabs tab-position="left" type="border-card" v-model="index">
|
||||
<el-tab-pane :label="$t('website.currentSSL')">
|
||||
<Current :id="id" v-if="index == '0'"></Current>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.dnsAccount')">
|
||||
<Account :id="id" v-if="index == '1'"></Account>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.applySSL')">
|
||||
<SSL :id="id" v-if="index == '2'"></SSL>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import Current from './current/index.vue';
|
||||
import Account from './account/index.vue';
|
||||
import SSL from './ssl/index.vue';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const id = computed(() => {
|
||||
return props.id;
|
||||
});
|
||||
|
||||
let index = ref('0');
|
||||
</script>
|
@ -1,120 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" plain @click="openSSL()">{{ $t('commons.button.create') }}</el-button>
|
||||
<el-button type="primary" plain @click="openAccount()">{{ $t('website.accountManage') }}</el-button>
|
||||
</template>
|
||||
<el-table-column :label="$t('website.domain')" fix show-overflow-tooltip prop="domain"></el-table-column>
|
||||
<el-table-column :label="$t('website.brand')" fix show-overflow-tooltip prop="type"></el-table-column>
|
||||
<el-table-column
|
||||
prop="expireDate"
|
||||
:label="$t('website.expireDate')"
|
||||
:formatter="dateFromat"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<fu-table-operations
|
||||
:ellipsis="1"
|
||||
:buttons="buttons"
|
||||
:label="$t('commons.table.operate')"
|
||||
fixed="right"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
<Account ref="accountRef"></Account>
|
||||
<Create :id="id" ref="sslCreateRef"></Create>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { ApplySSL, DeleteSSL, SearchSSL } from '@/api/modules/website';
|
||||
import Account from './account/index.vue';
|
||||
import Create from './create/index.vue';
|
||||
import { dateFromat } from '@/utils/util';
|
||||
import i18n from '@/lang';
|
||||
import { WebSite } from '@/api/interface/website';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const id = computed(() => {
|
||||
return props.id;
|
||||
});
|
||||
|
||||
const paginationConfig = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
});
|
||||
const accountRef = ref();
|
||||
const sslCreateRef = ref();
|
||||
let data = ref();
|
||||
let loading = ref(false);
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('website.deploySSL'),
|
||||
click: function (row: WebSite.WebSite) {
|
||||
applySSL(row.id);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('app.delete'),
|
||||
click: function (row: WebSite.WebSite) {
|
||||
deleteSSL(row.id);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const search = () => {
|
||||
const req = {
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
};
|
||||
loading.value = true;
|
||||
SearchSSL(req)
|
||||
.then((res) => {
|
||||
data.value = res.data.items || [];
|
||||
paginationConfig.total = res.data.total;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const openAccount = () => {
|
||||
accountRef.value.acceptParams();
|
||||
};
|
||||
const openSSL = () => {
|
||||
sslCreateRef.value.acceptParams();
|
||||
};
|
||||
|
||||
const deleteSSL = async (id: number) => {
|
||||
loading.value = true;
|
||||
await useDeleteData(DeleteSSL, id, 'commons.msg.delete', false);
|
||||
loading.value = false;
|
||||
search();
|
||||
};
|
||||
|
||||
const applySSL = async (sslId: number) => {
|
||||
loading.value = true;
|
||||
const apply = {
|
||||
websiteId: Number(id.value),
|
||||
SSLId: sslId,
|
||||
};
|
||||
await useDeleteData(ApplySSL, apply, 'website.deploySSLHelper', false);
|
||||
loading.value = false;
|
||||
search();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
</script>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog v-model="open" :title="$t('website.accountManage')">
|
||||
<el-dialog v-model="open" :title="$t('website.acmeAccountManage')">
|
||||
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()" v-loading="loading">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" plain @click="openCreate">{{ $t('commons.button.create') }}</el-button>
|
||||
@ -66,9 +66,7 @@ const openCreate = () => {
|
||||
};
|
||||
|
||||
const deleteAccount = async (id: number) => {
|
||||
loading.value = true;
|
||||
await useDeleteData(DeleteAcmeAccount, id, 'commons.msg.delete', false);
|
||||
loading.value = false;
|
||||
await useDeleteData(DeleteAcmeAccount, id, 'commons.msg.delete', loading.value);
|
||||
search();
|
||||
};
|
||||
|
@ -4,10 +4,16 @@
|
||||
ref="sslForm"
|
||||
label-position="right"
|
||||
:model="ssl"
|
||||
label-width="150px"
|
||||
label-width="125px"
|
||||
:rules="rules"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-form-item :label="$t('website.primaryDomain')" prop="primaryDomain">
|
||||
<el-input v-model="ssl.primaryDomain"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.otherDomains')" prop="otherDomains">
|
||||
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 6 }" v-model="ssl.otherDomains"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.acmeAccount')" prop="acmeAccountId">
|
||||
<el-select v-model="ssl.acmeAccountId">
|
||||
<el-option
|
||||
@ -21,7 +27,7 @@
|
||||
<el-form-item :label="$t('website.provider')" prop="provider">
|
||||
<el-radio-group v-model="ssl.provider">
|
||||
<el-radio label="dnsAccount">{{ $t('website.dnsAccount') }}</el-radio>
|
||||
<el-radio label="dnsCommon">{{ $t('website.dnsCommon') }}</el-radio>
|
||||
<el-radio label="dnsManual">{{ $t('website.dnsCommon') }}</el-radio>
|
||||
<el-radio label="http">HTTP</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
@ -35,18 +41,18 @@
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.domain')" prop="domains">
|
||||
<!-- <el-form-item :label="$t('website.domain')" prop="domains">
|
||||
<el-checkbox-group v-model="ssl.domains">
|
||||
<el-checkbox v-for="domain in domains" :key="domain.domain" :label="domain.domain"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
</el-form-item> -->
|
||||
<!-- <el-form-item>
|
||||
<div>
|
||||
<span>解析域名: {{ dnsResolve.key }}</span>
|
||||
<span>记录值: {{ dnsResolve.value }}</span>
|
||||
<span>类型: {{ dnsResolve.type }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
@ -61,7 +67,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { WebSite } from '@/api/interface/website';
|
||||
import { CreateSSL, GetDnsResolve, GetWebsite, SearchAcmeAccount, SearchDnsAccount } from '@/api/modules/website';
|
||||
import { CreateSSL, SearchAcmeAccount, SearchDnsAccount } from '@/api/modules/website';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElMessage, FormInstance } from 'element-plus';
|
||||
@ -90,26 +96,27 @@ let acmeReq = reactive({
|
||||
});
|
||||
let dnsAccounts = ref<WebSite.DnsAccount[]>();
|
||||
let acmeAccounts = ref<WebSite.AcmeAccount[]>();
|
||||
let domains = ref<WebSite.Domain[]>([]);
|
||||
// let domains = ref<WebSite.Domain[]>([]);
|
||||
let sslForm = ref<FormInstance>();
|
||||
let rules = ref({
|
||||
primaryDomain: [Rules.requiredInput],
|
||||
acmeAccountId: [Rules.requiredSelectBusiness],
|
||||
dnsAccountId: [Rules.requiredSelectBusiness],
|
||||
provider: [Rules.requiredInput],
|
||||
domains: [Rules.requiredSelect],
|
||||
});
|
||||
let ssl = ref({
|
||||
domains: [],
|
||||
primaryDomain: '',
|
||||
otherDomains: '',
|
||||
provider: 'dnsAccount',
|
||||
websiteId: 0,
|
||||
acmeAccountId: 0,
|
||||
dnsAccountId: 0,
|
||||
});
|
||||
let dnsResolve = ref<WebSite.DNSResolve>({
|
||||
key: '',
|
||||
value: '',
|
||||
type: '',
|
||||
});
|
||||
// let dnsResolve = ref<WebSite.DNSResolve>({
|
||||
// key: '',
|
||||
// value: '',
|
||||
// type: '',
|
||||
// });
|
||||
let hasResolve = ref(false);
|
||||
|
||||
const em = defineEmits(['close']);
|
||||
@ -121,7 +128,8 @@ const handleClose = () => {
|
||||
const resetForm = () => {
|
||||
sslForm.value?.resetFields();
|
||||
ssl.value = {
|
||||
domains: [],
|
||||
primaryDomain: '',
|
||||
otherDomains: '',
|
||||
provider: 'dnsAccount',
|
||||
websiteId: 0,
|
||||
acmeAccountId: 0,
|
||||
@ -132,7 +140,7 @@ const resetForm = () => {
|
||||
const acceptParams = () => {
|
||||
resetForm();
|
||||
ssl.value.websiteId = Number(id.value);
|
||||
getWebsite(id.value);
|
||||
// getWebsite(id.value);
|
||||
getAcmeAccounts();
|
||||
getDnsAccounts();
|
||||
open.value = true;
|
||||
@ -154,32 +162,36 @@ const getDnsAccounts = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const getWebsite = async (id: number) => {
|
||||
domains.value = (await GetWebsite(id)).data.domains || [];
|
||||
};
|
||||
// const getWebsite = async (id: number) => {
|
||||
// domains.value = (await GetWebsite(id)).data.domains || [];
|
||||
// };
|
||||
|
||||
const getDnsResolve = async (acmeAccountId: number, domains: string[]) => {
|
||||
hasResolve.value = false;
|
||||
const res = await GetDnsResolve({ acmeAccountId: acmeAccountId, domains: domains });
|
||||
if (res.data) {
|
||||
dnsResolve.value = res.data;
|
||||
hasResolve.value = true;
|
||||
}
|
||||
};
|
||||
// const getDnsResolve = async (acmeAccountId: number, domains: string[]) => {
|
||||
// hasResolve.value = false;
|
||||
// const res = await GetDnsResolve({ acmeAccountId: acmeAccountId, domains: domains });
|
||||
// if (res.data) {
|
||||
// dnsResolve.value = res.data;
|
||||
// hasResolve.value = true;
|
||||
// }
|
||||
// };
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate(async (valid) => {
|
||||
await formEl.validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
if (ssl.value.provider != 'dnsCommon' || hasResolve.value) {
|
||||
if (ssl.value.provider != 'dnsManual' || hasResolve.value) {
|
||||
loading.value = true;
|
||||
await CreateSSL(ssl.value);
|
||||
ElMessage.success(i18n.global.t('commons.msg.createSuccess'));
|
||||
loading.value = false;
|
||||
CreateSSL(ssl.value)
|
||||
.then(() => {
|
||||
ElMessage.success(i18n.global.t('commons.msg.createSuccess'));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
} else {
|
||||
getDnsResolve(ssl.value.acmeAccountId, ssl.value.domains);
|
||||
// getDnsResolve(ssl.value.acmeAccountId, ssl.value.domains);
|
||||
}
|
||||
});
|
||||
};
|
@ -14,7 +14,7 @@
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div v-if="account.type === 'Aliyun'">
|
||||
<div v-if="account.type === 'AliYun'">
|
||||
<el-form-item label="AccessKey" prop="authorization.accessKey">
|
||||
<el-input v-model="account.authorization['accessKey']"></el-input>
|
||||
</el-form-item>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog v-model="open" :title="$t('website.dnsAccountManage')">
|
||||
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" plain @click="openCreate">{{ $t('commons.button.create') }}</el-button>
|
||||
@ -20,7 +20,7 @@
|
||||
/>
|
||||
</ComplexTable>
|
||||
<Create ref="createRef" @close="search()"></Create>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@ -40,6 +40,7 @@ const paginationConfig = reactive({
|
||||
let data = ref<WebSite.DnsAccount[]>();
|
||||
let createRef = ref();
|
||||
let loading = ref(false);
|
||||
let open = ref(false);
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
@ -50,6 +51,11 @@ const buttons = [
|
||||
},
|
||||
];
|
||||
|
||||
const acceptParams = () => {
|
||||
search();
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const search = () => {
|
||||
const req = {
|
||||
page: paginationConfig.currentPage,
|
||||
@ -79,4 +85,8 @@ const deleteAccount = async (id: number) => {
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
151
frontend/src/views/website/ssl/index.vue
Normal file
151
frontend/src/views/website/ssl/index.vue
Normal file
@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<LayoutContent :header="$t('website.ssl')">
|
||||
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" plain @click="openSSL()">{{ $t('commons.button.create') }}</el-button>
|
||||
<el-button type="primary" plain @click="openAcmeAccount()">
|
||||
{{ $t('website.acmeAccountManage') }}
|
||||
</el-button>
|
||||
<el-button type="primary" plain @click="openDnsAccount()">
|
||||
{{ $t('website.dnsAccountManage') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column
|
||||
:label="$t('website.domain')"
|
||||
fix
|
||||
show-overflow-tooltip
|
||||
prop="primaryDomain"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('website.otherDomains')"
|
||||
fix
|
||||
show-overflow-tooltip
|
||||
prop="domains"
|
||||
></el-table-column>
|
||||
<el-table-column :label="$t('website.brand')" fix show-overflow-tooltip prop="type"></el-table-column>
|
||||
<el-table-column
|
||||
prop="expireDate"
|
||||
:label="$t('website.expireDate')"
|
||||
:formatter="dateFromat"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<fu-table-operations
|
||||
:ellipsis="1"
|
||||
:buttons="buttons"
|
||||
:label="$t('commons.table.operate')"
|
||||
fixed="right"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
<DnsAccount ref="dnsAccountRef"></DnsAccount>
|
||||
<AcmeAccount ref="acmeAccountRef"></AcmeAccount>
|
||||
<Create ref="sslCreateRef" @close="search()"></Create>
|
||||
<Renew ref="renewRef" @close="search()"></Renew>
|
||||
</LayoutContent>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import LayoutContent from '@/layout/layout-content.vue';
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { DeleteSSL, SearchSSL } from '@/api/modules/website';
|
||||
import DnsAccount from './dns-account/index.vue';
|
||||
import AcmeAccount from './acme-account/index.vue';
|
||||
import Renew from './renew/index.vue';
|
||||
import Create from './create/index.vue';
|
||||
import { dateFromat } from '@/utils/util';
|
||||
import i18n from '@/lang';
|
||||
import { WebSite } from '@/api/interface/website';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
|
||||
const paginationConfig = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
});
|
||||
const acmeAccountRef = ref();
|
||||
const dnsAccountRef = ref();
|
||||
const sslCreateRef = ref();
|
||||
const renewRef = ref();
|
||||
let data = ref();
|
||||
let loading = ref(false);
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('website.renewSSL'),
|
||||
click: function (row: WebSite.WebSite) {
|
||||
openRenewSSL(row.id);
|
||||
},
|
||||
},
|
||||
// {
|
||||
// label: i18n.global.t('website.deploySSL'),
|
||||
// click: function (row: WebSite.WebSite) {
|
||||
// applySSL(row.id);
|
||||
// },
|
||||
// },
|
||||
{
|
||||
label: i18n.global.t('app.delete'),
|
||||
click: function (row: WebSite.WebSite) {
|
||||
deleteSSL(row.id);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const search = () => {
|
||||
const req = {
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
};
|
||||
loading.value = true;
|
||||
SearchSSL(req)
|
||||
.then((res) => {
|
||||
data.value = res.data.items || [];
|
||||
paginationConfig.total = res.data.total;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const openAcmeAccount = () => {
|
||||
acmeAccountRef.value.acceptParams();
|
||||
};
|
||||
const openDnsAccount = () => {
|
||||
dnsAccountRef.value.acceptParams();
|
||||
};
|
||||
const openSSL = () => {
|
||||
sslCreateRef.value.acceptParams();
|
||||
};
|
||||
const openRenewSSL = (id: number) => {
|
||||
renewRef.value.acceptParams(id);
|
||||
};
|
||||
|
||||
const deleteSSL = async (id: number) => {
|
||||
loading.value = true;
|
||||
await useDeleteData(DeleteSSL, id, 'commons.msg.delete', false);
|
||||
loading.value = false;
|
||||
search();
|
||||
};
|
||||
|
||||
// const renewSSL = async (id: number) => {
|
||||
// loading.value = true;
|
||||
// await useDeleteData(RenewSSL, { SSLId: id }, 'website.renewHelper', false);
|
||||
// loading.value = false;
|
||||
// search();
|
||||
// };
|
||||
|
||||
// const applySSL = async (sslId: number) => {
|
||||
// loading.value = true;
|
||||
// const apply = {
|
||||
// websiteId: 0,
|
||||
// SSLId: sslId,
|
||||
// };
|
||||
// await useDeleteData(ApplySSL, apply, 'website.deploySSLHelper', false);
|
||||
// loading.value = false;
|
||||
// search();
|
||||
// };
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
</script>
|
55
frontend/src/views/website/ssl/renew/index.vue
Normal file
55
frontend/src/views/website/ssl/renew/index.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<el-dialog v-model="open" :title="$t('website.renewSSL')" width="30%" :before-close="handleClose">
|
||||
<div style="text-align: center">
|
||||
<span>是否确定续签?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit()" :disabled="loading" :loading="loading">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { RenewSSL } from '@/api/modules/website';
|
||||
import i18n from '@/lang';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
|
||||
let open = ref(false);
|
||||
let loading = ref(false);
|
||||
let renewReq = reactive({
|
||||
SSLId: 0,
|
||||
});
|
||||
const em = defineEmits(['close']);
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
em('close', false);
|
||||
};
|
||||
|
||||
const acceptParams = async (id: number) => {
|
||||
renewReq.SSLId = id;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
loading.value = true;
|
||||
RenewSSL(renewReq)
|
||||
.then(() => {
|
||||
handleClose();
|
||||
ElMessage.success(i18n.global.t('commons.msg.renewSuccess'));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
@ -4,9 +4,6 @@
|
||||
<el-tab-pane label="基本" name="basic">
|
||||
<Basic :id="id" v-if="index === 'basic'"></Basic>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="证书" name="ssl">
|
||||
<SSL :id="id" v-if="index === 'ssl'"></SSL>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="安全">反代</el-tab-pane>
|
||||
<el-tab-pane label="备份">反代</el-tab-pane>
|
||||
<el-tab-pane label="源文">反代</el-tab-pane>
|
||||
@ -18,7 +15,6 @@
|
||||
import LayoutContent from '@/layout/layout-content.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import Basic from './basic/index.vue';
|
||||
import SSL from './ssl/index.vue';
|
||||
import router from '@/routers';
|
||||
|
||||
const props = defineProps({
|
@ -68,7 +68,7 @@ const search = async () => {
|
||||
};
|
||||
|
||||
const openConfig = (id: number) => {
|
||||
router.push({ name: 'WebsiteConfig', params: { id: id, tab: 'ssl' } });
|
||||
router.push({ name: 'WebsiteConfig', params: { id: id, tab: 'basic' } });
|
||||
};
|
||||
|
||||
const buttons = [
|
Loading…
Reference in New Issue
Block a user