mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 14:08: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)
|
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) {
|
func (b *BaseApi) ApplyWebsiteSSL(c *gin.Context) {
|
||||||
var req dto.WebsiteSSLApply
|
var req dto.WebsiteSSLApply
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
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)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := websiteSSLService.Delete(id); err != nil {
|
if err := websiteSSLService.Delete(id); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
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 (
|
const (
|
||||||
DNSAccount = "dnsAccount"
|
DNSAccount = "dnsAccount"
|
||||||
DnsCommon = "dnsCommon"
|
DnsManual = "dnsManual"
|
||||||
Http = "http"
|
Http = "http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebsiteSSLCreate struct {
|
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"`
|
Provider SSLProvider `json:"provider" validate:"required"`
|
||||||
WebsiteID uint `json:"websiteId" validate:"required"`
|
AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
|
||||||
AcmeAccountID uint `json:"acmeAccountId"`
|
|
||||||
DnsAccountID uint `json:"dnsAccountId"`
|
DnsAccountID uint `json:"dnsAccountId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,3 +37,7 @@ type WebsiteDNSRes struct {
|
|||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsiteSSLRenew struct {
|
||||||
|
SSLID uint `json:"SSLId" validate:"required"`
|
||||||
|
}
|
||||||
|
@ -4,16 +4,18 @@ import "time"
|
|||||||
|
|
||||||
type WebSiteSSL struct {
|
type WebSiteSSL struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Alias string `gorm:"type:varchar(64);not null" json:"alias"`
|
PrimaryDomain string `gorm:"type:varchar(256);not null" json:"primaryDomain"`
|
||||||
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
|
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
|
||||||
Pem string `gorm:"type:longtext;not null" json:"pem"`
|
Pem string `gorm:"type:longtext;not null" json:"pem"`
|
||||||
Domain string `gorm:"type:varchar(256);not null" json:"domain"`
|
Domains string `gorm:"type:varchar(256);not null" json:"domains"`
|
||||||
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
|
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
|
||||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||||
IssuerName string `gorm:"type:varchar(64);not null" json:"issuerName"`
|
Provider string `gorm:"type:varchar(64);not null" json:"provider"`
|
||||||
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
|
Organization string `gorm:"type:varchar(64);not null" json:"organization"`
|
||||||
ExpireDate time.Time `json:"expireDate"`
|
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
|
||||||
StartDate time.Time `json:"startDate"`
|
AcmeAccountID uint `gorm:"type:integer;not null" json:"acmeAccountId"`
|
||||||
|
ExpireDate time.Time `json:"expireDate"`
|
||||||
|
StartDate time.Time `json:"startDate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w WebSiteSSL) TableName() string {
|
func (w WebSiteSSL) TableName() string {
|
||||||
|
@ -3,6 +3,7 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
||||||
@ -31,48 +32,59 @@ func (w WebSiteSSLService) Create(create dto.WebsiteSSLCreate) (dto.WebsiteSSLCr
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
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)
|
client, err := ssl.NewPrivateKeyClient(acmeAccount.Email, acmeAccount.PrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
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 {
|
if err := client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization); err != nil {
|
||||||
return res, err
|
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 {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var websiteSSL model.WebSiteSSL
|
var websiteSSL model.WebSiteSSL
|
||||||
|
websiteSSL.DnsAccountID = create.DnsAccountID
|
||||||
//TODO 判断同一个账号下的证书
|
websiteSSL.AcmeAccountID = acmeAccount.ID
|
||||||
websiteSSL.Alias = create.Domains[0]
|
websiteSSL.Provider = string(create.Provider)
|
||||||
websiteSSL.Domain = strings.Join(create.Domains, ",")
|
websiteSSL.Domains = strings.Join(otherDomainArray, ",")
|
||||||
|
websiteSSL.PrimaryDomain = create.PrimaryDomain
|
||||||
websiteSSL.PrivateKey = string(resource.PrivateKey)
|
websiteSSL.PrivateKey = string(resource.PrivateKey)
|
||||||
websiteSSL.Pem = string(resource.Certificate)
|
websiteSSL.Pem = string(resource.Certificate)
|
||||||
websiteSSL.CertURL = resource.CertURL
|
websiteSSL.CertURL = resource.CertURL
|
||||||
|
certBlock, _ := pem.Decode(resource.Certificate)
|
||||||
cert, err := x509.ParseCertificate([]byte(websiteSSL.Pem))
|
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dto.WebsiteSSLCreate{}, err
|
return dto.WebsiteSSLCreate{}, err
|
||||||
}
|
}
|
||||||
websiteSSL.ExpireDate = cert.NotAfter
|
websiteSSL.ExpireDate = cert.NotAfter
|
||||||
websiteSSL.StartDate = cert.NotBefore
|
websiteSSL.StartDate = cert.NotBefore
|
||||||
websiteSSL.Type = cert.Issuer.CommonName
|
websiteSSL.Type = cert.Issuer.CommonName
|
||||||
websiteSSL.IssuerName = cert.Issuer.Organization[0]
|
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||||
|
|
||||||
if err := createPemFile(websiteSSL); err != nil {
|
//if err := createPemFile(websiteSSL); err != nil {
|
||||||
return dto.WebsiteSSLCreate{}, err
|
// return dto.WebsiteSSLCreate{}, err
|
||||||
}
|
//}
|
||||||
|
|
||||||
if err := websiteSSLRepo.Create(context.TODO(), &websiteSSL); err != nil {
|
if err := websiteSSLRepo.Create(context.TODO(), &websiteSSL); err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
@ -81,6 +93,55 @@ func (w WebSiteSSLService) Create(create dto.WebsiteSSLCreate) (dto.WebsiteSSLCr
|
|||||||
return create, nil
|
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) {
|
func (w WebSiteSSLService) Apply(apply dto.WebsiteSSLApply) (dto.WebsiteSSLApply, error) {
|
||||||
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(apply.SSLID))
|
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(apply.SSLID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -96,10 +157,10 @@ func (w WebSiteSSLService) Apply(apply dto.WebsiteSSLApply) (dto.WebsiteSSLApply
|
|||||||
nginxParams := getNginxParamsFromStaticFile(dto.SSL)
|
nginxParams := getNginxParamsFromStaticFile(dto.SSL)
|
||||||
for i, param := range nginxParams {
|
for i, param := range nginxParams {
|
||||||
if param.Name == "ssl_certificate" {
|
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" {
|
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 {
|
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
|
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 {
|
func (w WebSiteSSLService) Delete(id uint) error {
|
||||||
return websiteSSLRepo.DeleteBy(commonRepo.WithByID(id))
|
return websiteSSLRepo.DeleteBy(commonRepo.WithByID(id))
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,7 @@ func createPemFile(websiteSSL model.WebSiteSSL) error {
|
|||||||
return err
|
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()
|
fileOp := files.NewFileOp()
|
||||||
|
|
||||||
if !fileOp.Stat(configDir) {
|
if !fileOp.Stat(configDir) {
|
||||||
|
@ -16,9 +16,11 @@ func (a *WebsiteSSLRouter) InitWebsiteSSLRouter(Router *gin.RouterGroup) {
|
|||||||
baseApi := v1.ApiGroupApp.BaseApi
|
baseApi := v1.ApiGroupApp.BaseApi
|
||||||
{
|
{
|
||||||
groupRouter.POST("/search", baseApi.PageWebsiteSSL)
|
groupRouter.POST("/search", baseApi.PageWebsiteSSL)
|
||||||
|
groupRouter.POST("/renew", baseApi.RenewWebsiteSSL)
|
||||||
groupRouter.POST("", baseApi.CreateWebsiteSSL)
|
groupRouter.POST("", baseApi.CreateWebsiteSSL)
|
||||||
groupRouter.POST("/apply", baseApi.ApplyWebsiteSSL)
|
groupRouter.POST("/apply", baseApi.ApplyWebsiteSSL)
|
||||||
groupRouter.POST("/resolve", baseApi.GetDNSResolve)
|
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 {
|
func initServer(address string, router *gin.Engine) server {
|
||||||
s := endless.NewServer(address, router)
|
s := endless.NewServer(address, router)
|
||||||
s.ReadHeaderTimeout = 20 * time.Second
|
s.ReadHeaderTimeout = 20 * time.Second
|
||||||
s.WriteTimeout = 20 * time.Second
|
s.WriteTimeout = 60 * time.Second
|
||||||
s.MaxHeaderBytes = 1 << 20
|
s.MaxHeaderBytes = 1 << 20
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
-----BEGIN privateKey-----
|
-----BEGIN privateKey-----
|
||||||
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
|
||||||
-----END privateKey-----
|
-----END privateKey-----
|
||||||
|
@ -85,9 +85,8 @@ func NewPrivateKeyClient(email string, privateKey string) (*AcmeClient, error) {
|
|||||||
|
|
||||||
func newConfig(user *AcmeUser) *lego.Config {
|
func newConfig(user *AcmeUser) *lego.Config {
|
||||||
config := lego.NewConfig(user)
|
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.UserAgent = "acm_go/0.0.1"
|
||||||
config.Certificate.KeyType = certcrypto.RSA2048
|
config.Certificate.KeyType = certcrypto.RSA2048
|
||||||
|
|
||||||
return config
|
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) {
|
func (c *AcmeClient) UseManualDns(domains []string) (*Resolve, error) {
|
||||||
p := &manualDnsProvider{}
|
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
|
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{
|
request := certificate.ObtainRequest{
|
||||||
Domains: domains,
|
Domains: domains,
|
||||||
@ -139,6 +139,20 @@ func (c *AcmeClient) GetSSL(domains []string) (certificate.Resource, error) {
|
|||||||
return *certificates, nil
|
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 {
|
type Resolve struct {
|
||||||
Key string
|
Key string
|
||||||
Value string
|
Value string
|
||||||
|
@ -118,9 +118,10 @@ export namespace WebSite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SSL extends CommonModel {
|
export interface SSL extends CommonModel {
|
||||||
|
primaryDomain: string;
|
||||||
privateKey: string;
|
privateKey: string;
|
||||||
pem: string;
|
pem: string;
|
||||||
domain: string;
|
otherDomains: string;
|
||||||
certURL: string;
|
certURL: string;
|
||||||
type: string;
|
type: string;
|
||||||
issuerName: string;
|
issuerName: string;
|
||||||
@ -129,9 +130,9 @@ export namespace WebSite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SSLCreate {
|
export interface SSLCreate {
|
||||||
domains: string[];
|
primaryDomain: string;
|
||||||
|
otherDomains: string;
|
||||||
provider: string;
|
provider: string;
|
||||||
websiteId: number;
|
|
||||||
acmeAccountId: number;
|
acmeAccountId: number;
|
||||||
dnsAccountId: number;
|
dnsAccountId: number;
|
||||||
}
|
}
|
||||||
@ -141,6 +142,10 @@ export namespace WebSite {
|
|||||||
SSLId: number;
|
SSLId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SSLRenew {
|
||||||
|
SSLId: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AcmeAccount extends CommonModel {
|
export interface AcmeAccount extends CommonModel {
|
||||||
email: string;
|
email: string;
|
||||||
url: string;
|
url: string;
|
||||||
|
@ -98,10 +98,18 @@ export const DeleteSSL = (id: number) => {
|
|||||||
return http.delete<any>(`/websites/ssl/${id}`);
|
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) => {
|
export const ApplySSL = (req: WebSite.SSLApply) => {
|
||||||
return http.post<WebSite.SSLApply>(`/websites/ssl/apply`, req);
|
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) => {
|
export const GetDnsResolve = (req: WebSite.DNSResolveReq) => {
|
||||||
return http.post<WebSite.DNSResolve>(`/websites/ssl/resolve`, req);
|
return http.post<WebSite.DNSResolve>(`/websites/ssl/resolve`, req);
|
||||||
};
|
};
|
||||||
|
@ -37,6 +37,7 @@ export const useDeleteData = <P = any, R = any>(
|
|||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
loading = false;
|
loading = false;
|
||||||
});
|
})
|
||||||
|
.catch(() => {});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -131,6 +131,7 @@ export default {
|
|||||||
project: '项目',
|
project: '项目',
|
||||||
config: '配置',
|
config: '配置',
|
||||||
firewall: '防火墙',
|
firewall: '防火墙',
|
||||||
|
ssl: '证书',
|
||||||
database: '数据库',
|
database: '数据库',
|
||||||
container: '容器',
|
container: '容器',
|
||||||
cronjob: '计划任务',
|
cronjob: '计划任务',
|
||||||
@ -704,7 +705,7 @@ export default {
|
|||||||
manual: '手动解析',
|
manual: '手动解析',
|
||||||
key: '密钥',
|
key: '密钥',
|
||||||
check: '查看',
|
check: '查看',
|
||||||
accountManage: '账户管理',
|
acmeAccountManage: 'Acme 账户管理',
|
||||||
email: '邮箱',
|
email: '邮箱',
|
||||||
addAccount: '新增账户',
|
addAccount: '新增账户',
|
||||||
acmeAccount: 'Acme 账户',
|
acmeAccount: 'Acme 账户',
|
||||||
@ -714,5 +715,10 @@ export default {
|
|||||||
brand: '品牌',
|
brand: '品牌',
|
||||||
deploySSL: '部署',
|
deploySSL: '部署',
|
||||||
deploySSLHelper: '确定部署证书?',
|
deploySSLHelper: '确定部署证书?',
|
||||||
|
ssl: '证书',
|
||||||
|
dnsAccountManage: 'DNS 账户管理',
|
||||||
|
renewSSL: '续签',
|
||||||
|
renewHelper: '确定续签证书?',
|
||||||
|
renewSuccess: '续签证书',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -13,21 +13,29 @@ const webSiteRouter = {
|
|||||||
{
|
{
|
||||||
path: '/websites',
|
path: '/websites',
|
||||||
name: 'Website',
|
name: 'Website',
|
||||||
component: () => import('@/views/website/project/index.vue'),
|
component: () => import('@/views/website/website/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'menu.project',
|
title: 'menu.website',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/websites/:id/config/:tab',
|
path: '/websites/:id/config/:tab',
|
||||||
name: 'WebsiteConfig',
|
name: 'WebsiteConfig',
|
||||||
component: () => import('@/views/website/project/config/index.vue'),
|
component: () => import('@/views/website/website/config/index.vue'),
|
||||||
hidden: true,
|
hidden: true,
|
||||||
props: true,
|
props: true,
|
||||||
meta: {
|
meta: {
|
||||||
activeMenu: '/websites',
|
activeMenu: '/websites',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/websites/ssl',
|
||||||
|
name: 'SSL',
|
||||||
|
component: () => import('@/views/website/ssl/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'menu.ssl',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/websites/nginx',
|
path: '/websites/nginx',
|
||||||
name: 'Config',
|
name: 'Config',
|
||||||
@ -36,14 +44,6 @@ const webSiteRouter = {
|
|||||||
title: 'menu.config',
|
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>
|
<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">
|
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()" v-loading="loading">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-button type="primary" plain @click="openCreate">{{ $t('commons.button.create') }}</el-button>
|
<el-button type="primary" plain @click="openCreate">{{ $t('commons.button.create') }}</el-button>
|
||||||
@ -66,9 +66,7 @@ const openCreate = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const deleteAccount = async (id: number) => {
|
const deleteAccount = async (id: number) => {
|
||||||
loading.value = true;
|
await useDeleteData(DeleteAcmeAccount, id, 'commons.msg.delete', loading.value);
|
||||||
await useDeleteData(DeleteAcmeAccount, id, 'commons.msg.delete', false);
|
|
||||||
loading.value = false;
|
|
||||||
search();
|
search();
|
||||||
};
|
};
|
||||||
|
|
@ -4,10 +4,16 @@
|
|||||||
ref="sslForm"
|
ref="sslForm"
|
||||||
label-position="right"
|
label-position="right"
|
||||||
:model="ssl"
|
:model="ssl"
|
||||||
label-width="150px"
|
label-width="125px"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
v-loading="loading"
|
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-form-item :label="$t('website.acmeAccount')" prop="acmeAccountId">
|
||||||
<el-select v-model="ssl.acmeAccountId">
|
<el-select v-model="ssl.acmeAccountId">
|
||||||
<el-option
|
<el-option
|
||||||
@ -21,7 +27,7 @@
|
|||||||
<el-form-item :label="$t('website.provider')" prop="provider">
|
<el-form-item :label="$t('website.provider')" prop="provider">
|
||||||
<el-radio-group v-model="ssl.provider">
|
<el-radio-group v-model="ssl.provider">
|
||||||
<el-radio label="dnsAccount">{{ $t('website.dnsAccount') }}</el-radio>
|
<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 label="http">HTTP</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -35,18 +41,18 @@
|
|||||||
></el-option>
|
></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</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-group v-model="ssl.domains">
|
||||||
<el-checkbox v-for="domain in domains" :key="domain.domain" :label="domain.domain"></el-checkbox>
|
<el-checkbox v-for="domain in domains" :key="domain.domain" :label="domain.domain"></el-checkbox>
|
||||||
</el-checkbox-group>
|
</el-checkbox-group>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
<el-form-item>
|
<!-- <el-form-item>
|
||||||
<div>
|
<div>
|
||||||
<span>解析域名: {{ dnsResolve.key }}</span>
|
<span>解析域名: {{ dnsResolve.key }}</span>
|
||||||
<span>记录值: {{ dnsResolve.value }}</span>
|
<span>记录值: {{ dnsResolve.value }}</span>
|
||||||
<span>类型: {{ dnsResolve.type }}</span>
|
<span>类型: {{ dnsResolve.type }}</span>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
@ -61,7 +67,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { WebSite } from '@/api/interface/website';
|
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 { Rules } from '@/global/form-rules';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElMessage, FormInstance } from 'element-plus';
|
import { ElMessage, FormInstance } from 'element-plus';
|
||||||
@ -90,26 +96,27 @@ let acmeReq = reactive({
|
|||||||
});
|
});
|
||||||
let dnsAccounts = ref<WebSite.DnsAccount[]>();
|
let dnsAccounts = ref<WebSite.DnsAccount[]>();
|
||||||
let acmeAccounts = ref<WebSite.AcmeAccount[]>();
|
let acmeAccounts = ref<WebSite.AcmeAccount[]>();
|
||||||
let domains = ref<WebSite.Domain[]>([]);
|
// let domains = ref<WebSite.Domain[]>([]);
|
||||||
let sslForm = ref<FormInstance>();
|
let sslForm = ref<FormInstance>();
|
||||||
let rules = ref({
|
let rules = ref({
|
||||||
|
primaryDomain: [Rules.requiredInput],
|
||||||
acmeAccountId: [Rules.requiredSelectBusiness],
|
acmeAccountId: [Rules.requiredSelectBusiness],
|
||||||
dnsAccountId: [Rules.requiredSelectBusiness],
|
dnsAccountId: [Rules.requiredSelectBusiness],
|
||||||
provider: [Rules.requiredInput],
|
provider: [Rules.requiredInput],
|
||||||
domains: [Rules.requiredSelect],
|
|
||||||
});
|
});
|
||||||
let ssl = ref({
|
let ssl = ref({
|
||||||
domains: [],
|
primaryDomain: '',
|
||||||
|
otherDomains: '',
|
||||||
provider: 'dnsAccount',
|
provider: 'dnsAccount',
|
||||||
websiteId: 0,
|
websiteId: 0,
|
||||||
acmeAccountId: 0,
|
acmeAccountId: 0,
|
||||||
dnsAccountId: 0,
|
dnsAccountId: 0,
|
||||||
});
|
});
|
||||||
let dnsResolve = ref<WebSite.DNSResolve>({
|
// let dnsResolve = ref<WebSite.DNSResolve>({
|
||||||
key: '',
|
// key: '',
|
||||||
value: '',
|
// value: '',
|
||||||
type: '',
|
// type: '',
|
||||||
});
|
// });
|
||||||
let hasResolve = ref(false);
|
let hasResolve = ref(false);
|
||||||
|
|
||||||
const em = defineEmits(['close']);
|
const em = defineEmits(['close']);
|
||||||
@ -121,7 +128,8 @@ const handleClose = () => {
|
|||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
sslForm.value?.resetFields();
|
sslForm.value?.resetFields();
|
||||||
ssl.value = {
|
ssl.value = {
|
||||||
domains: [],
|
primaryDomain: '',
|
||||||
|
otherDomains: '',
|
||||||
provider: 'dnsAccount',
|
provider: 'dnsAccount',
|
||||||
websiteId: 0,
|
websiteId: 0,
|
||||||
acmeAccountId: 0,
|
acmeAccountId: 0,
|
||||||
@ -132,7 +140,7 @@ const resetForm = () => {
|
|||||||
const acceptParams = () => {
|
const acceptParams = () => {
|
||||||
resetForm();
|
resetForm();
|
||||||
ssl.value.websiteId = Number(id.value);
|
ssl.value.websiteId = Number(id.value);
|
||||||
getWebsite(id.value);
|
// getWebsite(id.value);
|
||||||
getAcmeAccounts();
|
getAcmeAccounts();
|
||||||
getDnsAccounts();
|
getDnsAccounts();
|
||||||
open.value = true;
|
open.value = true;
|
||||||
@ -154,32 +162,36 @@ const getDnsAccounts = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getWebsite = async (id: number) => {
|
// const getWebsite = async (id: number) => {
|
||||||
domains.value = (await GetWebsite(id)).data.domains || [];
|
// domains.value = (await GetWebsite(id)).data.domains || [];
|
||||||
};
|
// };
|
||||||
|
|
||||||
const getDnsResolve = async (acmeAccountId: number, domains: string[]) => {
|
// const getDnsResolve = async (acmeAccountId: number, domains: string[]) => {
|
||||||
hasResolve.value = false;
|
// hasResolve.value = false;
|
||||||
const res = await GetDnsResolve({ acmeAccountId: acmeAccountId, domains: domains });
|
// const res = await GetDnsResolve({ acmeAccountId: acmeAccountId, domains: domains });
|
||||||
if (res.data) {
|
// if (res.data) {
|
||||||
dnsResolve.value = res.data;
|
// dnsResolve.value = res.data;
|
||||||
hasResolve.value = true;
|
// hasResolve.value = true;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const submit = async (formEl: FormInstance | undefined) => {
|
const submit = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
await formEl.validate(async (valid) => {
|
await formEl.validate((valid) => {
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ssl.value.provider != 'dnsCommon' || hasResolve.value) {
|
if (ssl.value.provider != 'dnsManual' || hasResolve.value) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await CreateSSL(ssl.value);
|
CreateSSL(ssl.value)
|
||||||
ElMessage.success(i18n.global.t('commons.msg.createSuccess'));
|
.then(() => {
|
||||||
loading.value = false;
|
ElMessage.success(i18n.global.t('commons.msg.createSuccess'));
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
getDnsResolve(ssl.value.acmeAccountId, ssl.value.domains);
|
// getDnsResolve(ssl.value.acmeAccountId, ssl.value.domains);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
@ -14,7 +14,7 @@
|
|||||||
></el-option>
|
></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div v-if="account.type === 'Aliyun'">
|
<div v-if="account.type === 'AliYun'">
|
||||||
<el-form-item label="AccessKey" prop="authorization.accessKey">
|
<el-form-item label="AccessKey" prop="authorization.accessKey">
|
||||||
<el-input v-model="account.authorization['accessKey']"></el-input>
|
<el-input v-model="account.authorization['accessKey']"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<el-dialog v-model="open" :title="$t('website.dnsAccountManage')">
|
||||||
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()">
|
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-button type="primary" plain @click="openCreate">{{ $t('commons.button.create') }}</el-button>
|
<el-button type="primary" plain @click="openCreate">{{ $t('commons.button.create') }}</el-button>
|
||||||
@ -20,7 +20,7 @@
|
|||||||
/>
|
/>
|
||||||
</ComplexTable>
|
</ComplexTable>
|
||||||
<Create ref="createRef" @close="search()"></Create>
|
<Create ref="createRef" @close="search()"></Create>
|
||||||
</div>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -40,6 +40,7 @@ const paginationConfig = reactive({
|
|||||||
let data = ref<WebSite.DnsAccount[]>();
|
let data = ref<WebSite.DnsAccount[]>();
|
||||||
let createRef = ref();
|
let createRef = ref();
|
||||||
let loading = ref(false);
|
let loading = ref(false);
|
||||||
|
let open = ref(false);
|
||||||
|
|
||||||
const buttons = [
|
const buttons = [
|
||||||
{
|
{
|
||||||
@ -50,6 +51,11 @@ const buttons = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const acceptParams = () => {
|
||||||
|
search();
|
||||||
|
open.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
const search = () => {
|
const search = () => {
|
||||||
const req = {
|
const req = {
|
||||||
page: paginationConfig.currentPage,
|
page: paginationConfig.currentPage,
|
||||||
@ -79,4 +85,8 @@ const deleteAccount = async (id: number) => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
search();
|
search();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
acceptParams,
|
||||||
|
});
|
||||||
</script>
|
</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">
|
<el-tab-pane label="基本" name="basic">
|
||||||
<Basic :id="id" v-if="index === 'basic'"></Basic>
|
<Basic :id="id" v-if="index === 'basic'"></Basic>
|
||||||
</el-tab-pane>
|
</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>
|
<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 LayoutContent from '@/layout/layout-content.vue';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import Basic from './basic/index.vue';
|
import Basic from './basic/index.vue';
|
||||||
import SSL from './ssl/index.vue';
|
|
||||||
import router from '@/routers';
|
import router from '@/routers';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
@ -68,7 +68,7 @@ const search = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const openConfig = (id: number) => {
|
const openConfig = (id: number) => {
|
||||||
router.push({ name: 'WebsiteConfig', params: { id: id, tab: 'ssl' } });
|
router.push({ name: 'WebsiteConfig', params: { id: id, tab: 'basic' } });
|
||||||
};
|
};
|
||||||
|
|
||||||
const buttons = [
|
const buttons = [
|
Loading…
x
Reference in New Issue
Block a user