mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 16:29:17 +08:00
feat: 增加证书推送到本地目录功能 (#3070)
This commit is contained in:
parent
9cd7f0d681
commit
fdb6242d03
@ -16,6 +16,8 @@ type WebsiteSSLCreate struct {
|
|||||||
AutoRenew bool `json:"autoRenew"`
|
AutoRenew bool `json:"autoRenew"`
|
||||||
KeyType string `json:"keyType"`
|
KeyType string `json:"keyType"`
|
||||||
Apply bool `json:"apply"`
|
Apply bool `json:"apply"`
|
||||||
|
PushDir bool `json:"pushDir"`
|
||||||
|
Dir string `json:"dir"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebsiteDNSReq struct {
|
type WebsiteDNSReq struct {
|
||||||
@ -91,4 +93,6 @@ type WebsiteCAObtain struct {
|
|||||||
KeyType string `json:"keyType" validate:"required,oneof=P256 P384 2048 3072 4096 8192"`
|
KeyType string `json:"keyType" validate:"required,oneof=P256 P384 2048 3072 4096 8192"`
|
||||||
Time int `json:"time" validate:"required"`
|
Time int `json:"time" validate:"required"`
|
||||||
Unit string `json:"unit" validate:"required"`
|
Unit string `json:"unit" validate:"required"`
|
||||||
|
PushDir bool `json:"pushDir"`
|
||||||
|
Dir string `json:"dir"`
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,11 @@ type WebsiteSSL struct {
|
|||||||
Status string `gorm:"not null;default:ready" json:"status"`
|
Status string `gorm:"not null;default:ready" json:"status"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
KeyType string `gorm:"not null;default:2048" json:"keyType"`
|
KeyType string `gorm:"not null;default:2048" json:"keyType"`
|
||||||
|
PushDir bool `gorm:"not null;default:0" json:"pushDir"`
|
||||||
|
Dir string `json:"dir"`
|
||||||
|
|
||||||
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount" gorm:"-:migration"`
|
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount" gorm:"-:migration"`
|
||||||
|
DnsAccount WebsiteDnsAccount `json:"dnsAccount" gorm:"-:migration"`
|
||||||
Websites []Website `json:"websites" gorm:"-:migration"`
|
Websites []Website `json:"websites" gorm:"-:migration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,14 +48,14 @@ func (w WebsiteSSLRepo) Page(page, size int, opts ...DBOption) (int64, []model.W
|
|||||||
db := getDb(opts...).Model(&model.WebsiteSSL{})
|
db := getDb(opts...).Model(&model.WebsiteSSL{})
|
||||||
count := int64(0)
|
count := int64(0)
|
||||||
db = db.Count(&count)
|
db = db.Count(&count)
|
||||||
err := db.Limit(size).Offset(size * (page - 1)).Preload("AcmeAccount").Preload("Websites").Find(&sslList).Error
|
err := db.Limit(size).Offset(size * (page - 1)).Preload("AcmeAccount").Preload("DnsAccount").Preload("Websites").Find(&sslList).Error
|
||||||
return count, sslList, err
|
return count, sslList, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w WebsiteSSLRepo) GetFirst(opts ...DBOption) (model.WebsiteSSL, error) {
|
func (w WebsiteSSLRepo) GetFirst(opts ...DBOption) (model.WebsiteSSL, error) {
|
||||||
var website model.WebsiteSSL
|
var website model.WebsiteSSL
|
||||||
db := getDb(opts...).Model(&model.WebsiteSSL{})
|
db := getDb(opts...).Model(&model.WebsiteSSL{})
|
||||||
if err := db.Preload("AcmeAccount").First(&website).Error; err != nil {
|
if err := db.Preload("AcmeAccount").Preload("DnsAccount").First(&website).Error; err != nil {
|
||||||
return website, err
|
return website, err
|
||||||
}
|
}
|
||||||
return website, nil
|
return website, nil
|
||||||
@ -64,7 +64,7 @@ func (w WebsiteSSLRepo) GetFirst(opts ...DBOption) (model.WebsiteSSL, error) {
|
|||||||
func (w WebsiteSSLRepo) List(opts ...DBOption) ([]model.WebsiteSSL, error) {
|
func (w WebsiteSSLRepo) List(opts ...DBOption) ([]model.WebsiteSSL, error) {
|
||||||
var websites []model.WebsiteSSL
|
var websites []model.WebsiteSSL
|
||||||
db := getDb(opts...).Model(&model.WebsiteSSL{})
|
db := getDb(opts...).Model(&model.WebsiteSSL{})
|
||||||
if err := db.Preload("AcmeAccount").Find(&websites).Error; err != nil {
|
if err := db.Preload("AcmeAccount").Preload("DnsAccount").Find(&websites).Error; err != nil {
|
||||||
return websites, err
|
return websites, err
|
||||||
}
|
}
|
||||||
return websites, nil
|
return websites, nil
|
||||||
|
@ -9,16 +9,22 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -154,6 +160,13 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
|
|||||||
newSSL := &model.WebsiteSSL{
|
newSSL := &model.WebsiteSSL{
|
||||||
Provider: constant.SelfSigned,
|
Provider: constant.SelfSigned,
|
||||||
KeyType: req.KeyType,
|
KeyType: req.KeyType,
|
||||||
|
PushDir: req.PushDir,
|
||||||
|
}
|
||||||
|
if req.PushDir {
|
||||||
|
if !files.NewFileOp().Stat(req.Dir) {
|
||||||
|
return buserr.New(constant.ErrLinkPathNotFound)
|
||||||
|
}
|
||||||
|
newSSL.Dir = req.Dir
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -274,7 +287,15 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) error {
|
|||||||
newSSL.Type = cert.Issuer.CommonName
|
newSSL.Type = cert.Issuer.CommonName
|
||||||
newSSL.Organization = rootCsr.Subject.Organization[0]
|
newSSL.Organization = rootCsr.Subject.Organization[0]
|
||||||
|
|
||||||
return websiteSSLRepo.Create(context.Background(), newSSL)
|
if err := websiteSSLRepo.Create(context.Background(), newSSL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logFile, _ := os.OpenFile(path.Join(constant.SSLLogDir, fmt.Sprintf("%s-ssl-%d.log", newSSL.PrimaryDomain, newSSL.ID)), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
|
||||||
|
defer logFile.Close()
|
||||||
|
logger := log.New(logFile, "", log.LstdFlags)
|
||||||
|
logger.Println(i18n.GetMsgWithMap("ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}))
|
||||||
|
saveCertificateFile(*newSSL, logger)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPrivateKey(keyType string) (privateKey any, publicKey any, privateKeyBytes []byte, err error) {
|
func createPrivateKey(keyType string) (privateKey any, publicKey any, privateKeyBytes []byte, err error) {
|
||||||
|
@ -114,6 +114,13 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
|||||||
PrimaryDomain: create.PrimaryDomain,
|
PrimaryDomain: create.PrimaryDomain,
|
||||||
ExpireDate: time.Now(),
|
ExpireDate: time.Now(),
|
||||||
KeyType: create.KeyType,
|
KeyType: create.KeyType,
|
||||||
|
PushDir: create.PushDir,
|
||||||
|
}
|
||||||
|
if create.PushDir {
|
||||||
|
if !files.NewFileOp().Stat(create.Dir) {
|
||||||
|
return res, buserr.New(constant.ErrLinkPathNotFound)
|
||||||
|
}
|
||||||
|
websiteSSL.Dir = create.Dir
|
||||||
}
|
}
|
||||||
|
|
||||||
var domains []string
|
var domains []string
|
||||||
@ -240,6 +247,7 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
|||||||
websiteSSL.Organization = cert.Issuer.Organization[0]
|
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||||
websiteSSL.Status = constant.SSLReady
|
websiteSSL.Status = constant.SSLReady
|
||||||
legoLogger.Logger.Println(i18n.GetMsgWithMap("ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}))
|
legoLogger.Logger.Println(i18n.GetMsgWithMap("ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}))
|
||||||
|
saveCertificateFile(websiteSSL, logger)
|
||||||
err = websiteSSLRepo.Save(websiteSSL)
|
err = websiteSSLRepo.Save(websiteSSL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
"log"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -748,3 +749,26 @@ func getWebsiteDomains(domains string, defaultPort int, websiteID uint) (domainM
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func saveCertificateFile(websiteSSL model.WebsiteSSL, logger *log.Logger) {
|
||||||
|
if websiteSSL.PushDir {
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
var (
|
||||||
|
pushErr error
|
||||||
|
MsgMap = map[string]interface{}{"path": websiteSSL.Dir, "status": i18n.GetMsgByKey("Success")}
|
||||||
|
)
|
||||||
|
if pushErr = fileOp.SaveFile(path.Join(websiteSSL.Dir, "privkey.pem"), websiteSSL.PrivateKey, 0666); pushErr != nil {
|
||||||
|
MsgMap["status"] = i18n.GetMsgByKey("Failed")
|
||||||
|
logger.Println(i18n.GetMsgWithMap("PushDirLog", MsgMap))
|
||||||
|
logger.Println("Push dir failed:" + pushErr.Error())
|
||||||
|
}
|
||||||
|
if pushErr = fileOp.SaveFile(path.Join(websiteSSL.Dir, "fullchain.pem"), websiteSSL.Pem, 0666); pushErr != nil {
|
||||||
|
MsgMap["status"] = i18n.GetMsgByKey("Failed")
|
||||||
|
logger.Println(i18n.GetMsgWithMap("PushDirLog", MsgMap))
|
||||||
|
logger.Println("Push dir failed:" + pushErr.Error())
|
||||||
|
}
|
||||||
|
if pushErr == nil {
|
||||||
|
logger.Println(i18n.GetMsgWithMap("PushDirLog", MsgMap))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,6 +20,8 @@ TYPE_RUNTIME: "Runtime environment"
|
|||||||
TYPE_DOMAIN: "Domain name"
|
TYPE_DOMAIN: "Domain name"
|
||||||
ErrTypePort: 'Port {{ .name }} format error'
|
ErrTypePort: 'Port {{ .name }} format error'
|
||||||
ErrTypePortRange: 'Port range needs to be between 1-65535'
|
ErrTypePortRange: 'Port range needs to be between 1-65535'
|
||||||
|
Success: "Success"
|
||||||
|
Failed: "Failed"
|
||||||
|
|
||||||
#app
|
#app
|
||||||
ErrPortInUsed: "{{ .detail }} port already in use"
|
ErrPortInUsed: "{{ .detail }} port already in use"
|
||||||
@ -100,7 +102,7 @@ http: "HTTP"
|
|||||||
ApplySSLFailed: 'Application for [{{ .domain }}] certificate failed, {{.detail}} '
|
ApplySSLFailed: 'Application for [{{ .domain }}] certificate failed, {{.detail}} '
|
||||||
ApplySSLSuccess: 'Application for [{{ .domain }}] certificate successful! ! '
|
ApplySSLSuccess: 'Application for [{{ .domain }}] certificate successful! ! '
|
||||||
DNSAccountName: 'DNS account [{{ .name }}] manufacturer [{{.type}}]'
|
DNSAccountName: 'DNS account [{{ .name }}] manufacturer [{{.type}}]'
|
||||||
|
PushDirLog: 'Certificate pushed to directory [{{ .path }}] {{ .status }}'
|
||||||
|
|
||||||
#mysql
|
#mysql
|
||||||
ErrUserIsExist: "The current user already exists. Please enter a new user"
|
ErrUserIsExist: "The current user already exists. Please enter a new user"
|
||||||
|
@ -20,6 +20,8 @@ TYPE_RUNTIME: "運作環境"
|
|||||||
TYPE_DOMAIN: "網域名稱"
|
TYPE_DOMAIN: "網域名稱"
|
||||||
ErrTypePort: '埠 {{ .name }} 格式錯誤'
|
ErrTypePort: '埠 {{ .name }} 格式錯誤'
|
||||||
ErrTypePortRange: '連接埠範圍需要在 1-65535 之間'
|
ErrTypePortRange: '連接埠範圍需要在 1-65535 之間'
|
||||||
|
Success: "成功"
|
||||||
|
Failed: "失敗"
|
||||||
|
|
||||||
#app
|
#app
|
||||||
ErrPortInUsed: "{{ .detail }} 端口已被佔用!"
|
ErrPortInUsed: "{{ .detail }} 端口已被佔用!"
|
||||||
@ -100,6 +102,8 @@ http: "HTTP"
|
|||||||
ApplySSLFailed: '申請 [{{ .domain }}] 憑證失敗, {{.detail}} '
|
ApplySSLFailed: '申請 [{{ .domain }}] 憑證失敗, {{.detail}} '
|
||||||
ApplySSLSuccess: '申請 [{{ .domain }}] 憑證成功! ! '
|
ApplySSLSuccess: '申請 [{{ .domain }}] 憑證成功! ! '
|
||||||
DNSAccountName: 'DNS 帳號 [{{ .name }}] 廠商 [{{.type}}]'
|
DNSAccountName: 'DNS 帳號 [{{ .name }}] 廠商 [{{.type}}]'
|
||||||
|
PushDirLog: '憑證推送到目錄 [{{ .path }}] {{ .status }}'
|
||||||
|
|
||||||
|
|
||||||
#mysql
|
#mysql
|
||||||
ErrUserIsExist: "當前用戶已存在,請重新輸入"
|
ErrUserIsExist: "當前用戶已存在,請重新輸入"
|
||||||
|
@ -20,6 +20,8 @@ TYPE_RUNTIME: "运行环境"
|
|||||||
TYPE_DOMAIN: "域名"
|
TYPE_DOMAIN: "域名"
|
||||||
ErrTypePort: '端口 {{ .name }} 格式错误'
|
ErrTypePort: '端口 {{ .name }} 格式错误'
|
||||||
ErrTypePortRange: '端口范围需要在 1-65535 之间'
|
ErrTypePortRange: '端口范围需要在 1-65535 之间'
|
||||||
|
Success: "成功"
|
||||||
|
Failed: "失败"
|
||||||
|
|
||||||
#app
|
#app
|
||||||
ErrPortInUsed: "{{ .detail }} 端口已被占用!"
|
ErrPortInUsed: "{{ .detail }} 端口已被占用!"
|
||||||
@ -100,6 +102,7 @@ http: "HTTP"
|
|||||||
ApplySSLFailed: '申请 [{{ .domain }}] 证书失败, {{.detail}} '
|
ApplySSLFailed: '申请 [{{ .domain }}] 证书失败, {{.detail}} '
|
||||||
ApplySSLSuccess: '申请 [{{ .domain }}] 证书成功!!'
|
ApplySSLSuccess: '申请 [{{ .domain }}] 证书成功!!'
|
||||||
DNSAccountName: 'DNS 账号 [{{ .name }}] 厂商 [{{.type}}]'
|
DNSAccountName: 'DNS 账号 [{{ .name }}] 厂商 [{{.type}}]'
|
||||||
|
PushDirLog: '证书推送到目录 [{{ .path }}] {{ .status }}'
|
||||||
|
|
||||||
#mysql
|
#mysql
|
||||||
ErrUserIsExist: "当前用户已存在,请重新输入"
|
ErrUserIsExist: "当前用户已存在,请重新输入"
|
||||||
|
@ -16,16 +16,6 @@ var UpdateAcmeAccount = &gormigrate.Migration{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var UpdateWebsiteSSL = &gormigrate.Migration{
|
|
||||||
ID: "20231119-update-website-ssl",
|
|
||||||
Migrate: func(tx *gorm.DB) error {
|
|
||||||
if err := tx.AutoMigrate(&model.WebsiteSSL{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var AddWebsiteCA = &gormigrate.Migration{
|
var AddWebsiteCA = &gormigrate.Migration{
|
||||||
ID: "20231125-add-website-ca",
|
ID: "20231125-add-website-ca",
|
||||||
Migrate: func(tx *gorm.DB) error {
|
Migrate: func(tx *gorm.DB) error {
|
||||||
@ -35,3 +25,13 @@ var AddWebsiteCA = &gormigrate.Migration{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var UpdateWebsiteSSL = &gormigrate.Migration{
|
||||||
|
ID: "20231126-update-website-ssl",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.AutoMigrate(&model.WebsiteSSL{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -16934,17 +16934,11 @@ const docTemplate = `{
|
|||||||
"dto.SwapHelper": {
|
"dto.SwapHelper": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"operate",
|
|
||||||
"path"
|
"path"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"operate": {
|
"isNew": {
|
||||||
"type": "string",
|
"type": "boolean"
|
||||||
"enum": [
|
|
||||||
"create",
|
|
||||||
"delete",
|
|
||||||
"update"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"path": {
|
"path": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -17468,6 +17462,26 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"model.WebsiteDnsAccount": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"model.WebsiteDomain": {
|
"model.WebsiteDomain": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -17509,6 +17523,12 @@ const docTemplate = `{
|
|||||||
"createdAt": {
|
"createdAt": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"dir": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"dnsAccount": {
|
||||||
|
"$ref": "#/definitions/model.WebsiteDnsAccount"
|
||||||
|
},
|
||||||
"dnsAccountId": {
|
"dnsAccountId": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -17542,6 +17562,9 @@ const docTemplate = `{
|
|||||||
"provider": {
|
"provider": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"pushDir": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"startDate": {
|
"startDate": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -18942,6 +18965,9 @@ const docTemplate = `{
|
|||||||
"unit"
|
"unit"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"dir": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"domains": {
|
"domains": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -18959,6 +18985,9 @@ const docTemplate = `{
|
|||||||
"8192"
|
"8192"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"pushDir": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -19471,6 +19500,9 @@ const docTemplate = `{
|
|||||||
"autoRenew": {
|
"autoRenew": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"dir": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"dnsAccountId": {
|
"dnsAccountId": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -19485,6 +19517,9 @@ const docTemplate = `{
|
|||||||
},
|
},
|
||||||
"provider": {
|
"provider": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pushDir": {
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -16927,17 +16927,11 @@
|
|||||||
"dto.SwapHelper": {
|
"dto.SwapHelper": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"operate",
|
|
||||||
"path"
|
"path"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"operate": {
|
"isNew": {
|
||||||
"type": "string",
|
"type": "boolean"
|
||||||
"enum": [
|
|
||||||
"create",
|
|
||||||
"delete",
|
|
||||||
"update"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"path": {
|
"path": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -17461,6 +17455,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"model.WebsiteDnsAccount": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"model.WebsiteDomain": {
|
"model.WebsiteDomain": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -17502,6 +17516,12 @@
|
|||||||
"createdAt": {
|
"createdAt": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"dir": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"dnsAccount": {
|
||||||
|
"$ref": "#/definitions/model.WebsiteDnsAccount"
|
||||||
|
},
|
||||||
"dnsAccountId": {
|
"dnsAccountId": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -17535,6 +17555,9 @@
|
|||||||
"provider": {
|
"provider": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"pushDir": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"startDate": {
|
"startDate": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -18935,6 +18958,9 @@
|
|||||||
"unit"
|
"unit"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"dir": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"domains": {
|
"domains": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -18952,6 +18978,9 @@
|
|||||||
"8192"
|
"8192"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"pushDir": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -19464,6 +19493,9 @@
|
|||||||
"autoRenew": {
|
"autoRenew": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"dir": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"dnsAccountId": {
|
"dnsAccountId": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -19478,6 +19510,9 @@
|
|||||||
},
|
},
|
||||||
"provider": {
|
"provider": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pushDir": {
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2409,12 +2409,8 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
dto.SwapHelper:
|
dto.SwapHelper:
|
||||||
properties:
|
properties:
|
||||||
operate:
|
isNew:
|
||||||
enum:
|
type: boolean
|
||||||
- create
|
|
||||||
- delete
|
|
||||||
- update
|
|
||||||
type: string
|
|
||||||
path:
|
path:
|
||||||
type: string
|
type: string
|
||||||
size:
|
size:
|
||||||
@ -2422,7 +2418,6 @@ definitions:
|
|||||||
used:
|
used:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- operate
|
|
||||||
- path
|
- path
|
||||||
type: object
|
type: object
|
||||||
dto.TreeChild:
|
dto.TreeChild:
|
||||||
@ -2761,6 +2756,19 @@ definitions:
|
|||||||
url:
|
url:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
model.WebsiteDnsAccount:
|
||||||
|
properties:
|
||||||
|
createdAt:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
updatedAt:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
model.WebsiteDomain:
|
model.WebsiteDomain:
|
||||||
properties:
|
properties:
|
||||||
createdAt:
|
createdAt:
|
||||||
@ -2788,6 +2796,10 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
createdAt:
|
createdAt:
|
||||||
type: string
|
type: string
|
||||||
|
dir:
|
||||||
|
type: string
|
||||||
|
dnsAccount:
|
||||||
|
$ref: '#/definitions/model.WebsiteDnsAccount'
|
||||||
dnsAccountId:
|
dnsAccountId:
|
||||||
type: integer
|
type: integer
|
||||||
domains:
|
domains:
|
||||||
@ -2810,6 +2822,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
provider:
|
provider:
|
||||||
type: string
|
type: string
|
||||||
|
pushDir:
|
||||||
|
type: boolean
|
||||||
startDate:
|
startDate:
|
||||||
type: string
|
type: string
|
||||||
status:
|
status:
|
||||||
@ -3747,6 +3761,8 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
request.WebsiteCAObtain:
|
request.WebsiteCAObtain:
|
||||||
properties:
|
properties:
|
||||||
|
dir:
|
||||||
|
type: string
|
||||||
domains:
|
domains:
|
||||||
type: string
|
type: string
|
||||||
id:
|
id:
|
||||||
@ -3760,6 +3776,8 @@ definitions:
|
|||||||
- "4096"
|
- "4096"
|
||||||
- "8192"
|
- "8192"
|
||||||
type: string
|
type: string
|
||||||
|
pushDir:
|
||||||
|
type: boolean
|
||||||
time:
|
time:
|
||||||
type: integer
|
type: integer
|
||||||
unit:
|
unit:
|
||||||
@ -4106,6 +4124,8 @@ definitions:
|
|||||||
type: boolean
|
type: boolean
|
||||||
autoRenew:
|
autoRenew:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
dir:
|
||||||
|
type: string
|
||||||
dnsAccountId:
|
dnsAccountId:
|
||||||
type: integer
|
type: integer
|
||||||
keyType:
|
keyType:
|
||||||
@ -4116,6 +4136,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
provider:
|
provider:
|
||||||
type: string
|
type: string
|
||||||
|
pushDir:
|
||||||
|
type: boolean
|
||||||
required:
|
required:
|
||||||
- acmeAccountId
|
- acmeAccountId
|
||||||
- primaryDomain
|
- primaryDomain
|
||||||
|
@ -482,5 +482,7 @@ export namespace Website {
|
|||||||
keyType: string;
|
keyType: string;
|
||||||
time: number;
|
time: number;
|
||||||
unit: string;
|
unit: string;
|
||||||
|
pushDir: boolean;
|
||||||
|
dir: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1836,6 +1836,10 @@ const message = {
|
|||||||
selfSign: 'Issue certificate',
|
selfSign: 'Issue certificate',
|
||||||
days: 'validity period',
|
days: 'validity period',
|
||||||
domainHelper: 'One domain name per line, supports * and IP address',
|
domainHelper: 'One domain name per line, supports * and IP address',
|
||||||
|
pushDir: 'Push the certificate to the local directory',
|
||||||
|
dir: 'directory',
|
||||||
|
pushDirHelper:
|
||||||
|
'Two files will be generated in this directory, the certificate file: fullchain.pem and the key file: privkey.pem',
|
||||||
},
|
},
|
||||||
firewall: {
|
firewall: {
|
||||||
create: 'Create rule',
|
create: 'Create rule',
|
||||||
|
@ -1724,6 +1724,9 @@ const message = {
|
|||||||
selfSign: '簽發證書',
|
selfSign: '簽發證書',
|
||||||
days: '有效期限',
|
days: '有效期限',
|
||||||
domainHelper: '一行一個網域名稱,支援*和IP位址',
|
domainHelper: '一行一個網域名稱,支援*和IP位址',
|
||||||
|
pushDir: '推送憑證到本機目錄',
|
||||||
|
dir: '目錄',
|
||||||
|
pushDirHelper: '會在此目錄下產生兩個文件,憑證檔案:fullchain.pem 金鑰檔案:privkey.pem',
|
||||||
},
|
},
|
||||||
firewall: {
|
firewall: {
|
||||||
create: '創建規則',
|
create: '創建規則',
|
||||||
|
@ -1724,6 +1724,9 @@ const message = {
|
|||||||
selfSign: '签发证书',
|
selfSign: '签发证书',
|
||||||
days: '有效期',
|
days: '有效期',
|
||||||
domainHelper: '一行一个域名,支持*和IP地址',
|
domainHelper: '一行一个域名,支持*和IP地址',
|
||||||
|
pushDir: '推送证书到本地目录',
|
||||||
|
dir: '目录',
|
||||||
|
pushDirHelper: '会在此目录下生成两个文件,证书文件:fullchain.pem 密钥文件:privkey.pem',
|
||||||
},
|
},
|
||||||
firewall: {
|
firewall: {
|
||||||
create: '创建规则',
|
create: '创建规则',
|
||||||
|
@ -37,6 +37,19 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="''" prop="pushDir">
|
||||||
|
<el-checkbox v-model="obtain.pushDir" :label="$t('ssl.pushDir')" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('ssl.dir')" prop="dir" v-if="obtain.pushDir">
|
||||||
|
<el-input v-model.trim="obtain.dir">
|
||||||
|
<template #prepend>
|
||||||
|
<FileList :path="obtain.dir" @choose="getPath" :dir="true"></FileList>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<span class="input-help">
|
||||||
|
{{ $t('ssl.pushDirHelper') }}
|
||||||
|
</span>
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -69,6 +82,7 @@ const rules = ref({
|
|||||||
keyType: [Rules.requiredSelect],
|
keyType: [Rules.requiredSelect],
|
||||||
domains: [Rules.requiredInput],
|
domains: [Rules.requiredInput],
|
||||||
time: [Rules.requiredInput, checkNumberRange(1, 1000)],
|
time: [Rules.requiredInput, checkNumberRange(1, 1000)],
|
||||||
|
dir: [Rules.requiredInput],
|
||||||
});
|
});
|
||||||
|
|
||||||
const initData = () => ({
|
const initData = () => ({
|
||||||
@ -77,6 +91,8 @@ const initData = () => ({
|
|||||||
id: 0,
|
id: 0,
|
||||||
time: 0,
|
time: 0,
|
||||||
unit: 'day',
|
unit: 'day',
|
||||||
|
pushDir: false,
|
||||||
|
dir: '',
|
||||||
});
|
});
|
||||||
const obtain = ref(initData());
|
const obtain = ref(initData());
|
||||||
|
|
||||||
@ -96,6 +112,10 @@ const resetForm = () => {
|
|||||||
obtain.value = initData();
|
obtain.value = initData();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getPath = (dir: string) => {
|
||||||
|
obtain.value.dir = dir;
|
||||||
|
};
|
||||||
|
|
||||||
const submit = async (formEl: FormInstance | undefined) => {
|
const submit = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
await formEl.validate((valid) => {
|
await formEl.validate((valid) => {
|
||||||
|
@ -71,6 +71,19 @@
|
|||||||
<el-form-item :label="''" prop="autoRenew" v-if="ssl.provider !== 'dnsManual'">
|
<el-form-item :label="''" prop="autoRenew" v-if="ssl.provider !== 'dnsManual'">
|
||||||
<el-checkbox v-model="ssl.autoRenew" :label="$t('ssl.autoRenew')" />
|
<el-checkbox v-model="ssl.autoRenew" :label="$t('ssl.autoRenew')" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="''" prop="pushDir">
|
||||||
|
<el-checkbox v-model="ssl.pushDir" :label="$t('ssl.pushDir')" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('ssl.dir')" prop="dir" v-if="ssl.pushDir">
|
||||||
|
<el-input v-model.trim="ssl.dir">
|
||||||
|
<template #prepend>
|
||||||
|
<FileList :path="ssl.dir" @choose="getPath" :dir="true"></FileList>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<span class="input-help">
|
||||||
|
{{ $t('ssl.pushDirHelper') }}
|
||||||
|
</span>
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -127,6 +140,7 @@ const rules = ref({
|
|||||||
provider: [Rules.requiredInput],
|
provider: [Rules.requiredInput],
|
||||||
autoRenew: [Rules.requiredInput],
|
autoRenew: [Rules.requiredInput],
|
||||||
keyType: [Rules.requiredInput],
|
keyType: [Rules.requiredInput],
|
||||||
|
dir: [Rules.requiredInput],
|
||||||
});
|
});
|
||||||
|
|
||||||
const initData = () => ({
|
const initData = () => ({
|
||||||
@ -138,6 +152,8 @@ const initData = () => ({
|
|||||||
dnsAccountId: undefined,
|
dnsAccountId: undefined,
|
||||||
autoRenew: true,
|
autoRenew: true,
|
||||||
keyType: 'P256',
|
keyType: 'P256',
|
||||||
|
pushDir: false,
|
||||||
|
dir: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const ssl = ref(initData());
|
const ssl = ref(initData());
|
||||||
@ -163,6 +179,10 @@ const acceptParams = () => {
|
|||||||
open.value = true;
|
open.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getPath = (dir: string) => {
|
||||||
|
ssl.value.dir = dir;
|
||||||
|
};
|
||||||
|
|
||||||
const getAcmeAccounts = async () => {
|
const getAcmeAccounts = async () => {
|
||||||
const res = await SearchAcmeAccount(acmeReq);
|
const res = await SearchAcmeAccount(acmeReq);
|
||||||
acmeAccounts.value = res.data.items || [];
|
acmeAccounts.value = res.data.items || [];
|
||||||
|
@ -19,15 +19,6 @@
|
|||||||
<el-descriptions-item :label="$t('website.otherDomains')">
|
<el-descriptions-item :label="$t('website.otherDomains')">
|
||||||
{{ ssl.domains }}
|
{{ ssl.domains }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item :label="$t('ssl.applyType')">
|
|
||||||
{{ getProvider(ssl.provider) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item
|
|
||||||
:label="$t('ssl.acmeAccount')"
|
|
||||||
v-if="ssl.acmeAccount && ssl.provider !== 'manual'"
|
|
||||||
>
|
|
||||||
{{ ssl.acmeAccount.email }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item :label="$t('ssl.commonName')">
|
<el-descriptions-item :label="$t('ssl.commonName')">
|
||||||
{{ ssl.type }}
|
{{ ssl.type }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
@ -40,6 +31,25 @@
|
|||||||
<el-descriptions-item :label="$t('website.expireDate')">
|
<el-descriptions-item :label="$t('website.expireDate')">
|
||||||
{{ dateFormatSimple(ssl.expireDate) }}
|
{{ dateFormatSimple(ssl.expireDate) }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item :label="$t('ssl.applyType')">
|
||||||
|
{{ getProvider(ssl.provider) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item
|
||||||
|
:label="$t('website.dnsAccount')"
|
||||||
|
v-if="ssl.dnsAccount && ssl.dnsAccount.id > 0"
|
||||||
|
>
|
||||||
|
{{ ssl.dnsAccount.name }}
|
||||||
|
<el-tag type="info">{{ ssl.dnsAccount.type }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item
|
||||||
|
:label="$t('ssl.acmeAccount')"
|
||||||
|
v-if="ssl.acmeAccount && ssl.acmeAccount.id > 0"
|
||||||
|
>
|
||||||
|
{{ ssl.acmeAccount.email }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item :label="$t('ssl.pushDir')" v-if="ssl.pushDir">
|
||||||
|
{{ ssl.dir }}
|
||||||
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="curr === 'ssl'">
|
<div v-else-if="curr === 'ssl'">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user