mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-11 07:55:59 +08:00
feat: 证书页面增加上传证书功能 (#2735)
Refs https://github.com/1Panel-dev/1Panel/issues/1323
This commit is contained in:
parent
c526e7a5ac
commit
d43bc3e427
15 changed files with 440 additions and 34 deletions
|
@ -192,3 +192,24 @@ func (b *BaseApi) UpdateWebsiteSSL(c *gin.Context) {
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Website SSL
|
||||||
|
// @Summary Upload ssl
|
||||||
|
// @Description 上传 ssl
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsiteSSLUpload true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/ssl/upload [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"上传 ssl [type]","formatEN":"Upload ssl [type]"}
|
||||||
|
func (b *BaseApi) UploadWebsiteSSL(c *gin.Context) {
|
||||||
|
var req request.WebsiteSSLUpload
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteSSLService.Upload(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
|
@ -50,3 +50,11 @@ type WebsiteSSLUpdate struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
AutoRenew bool `json:"autoRenew" validate:"required"`
|
AutoRenew bool `json:"autoRenew" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsiteSSLUpload struct {
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
Certificate string `json:"certificate"`
|
||||||
|
PrivateKeyPath string `json:"privateKeyPath"`
|
||||||
|
CertificatePath string `json:"certificatePath"`
|
||||||
|
Type string `json:"type" validate:"required,oneof=paste local"`
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"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/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -30,6 +31,7 @@ type IWebsiteSSLService interface {
|
||||||
GetWebsiteSSL(websiteId uint) (response.WebsiteSSLDTO, error)
|
GetWebsiteSSL(websiteId uint) (response.WebsiteSSLDTO, error)
|
||||||
Delete(id uint) error
|
Delete(id uint) error
|
||||||
Update(update request.WebsiteSSLUpdate) error
|
Update(update request.WebsiteSSLUpdate) error
|
||||||
|
Upload(req request.WebsiteSSLUpload) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIWebsiteSSLService() IWebsiteSSLService {
|
func NewIWebsiteSSLService() IWebsiteSSLService {
|
||||||
|
@ -289,3 +291,60 @@ func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error {
|
||||||
websiteSSL.AutoRenew = update.AutoRenew
|
websiteSSL.AutoRenew = update.AutoRenew
|
||||||
return websiteSSLRepo.Save(websiteSSL)
|
return websiteSSLRepo.Save(websiteSSL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w WebsiteSSLService) Upload(req request.WebsiteSSLUpload) error {
|
||||||
|
newSSL := &model.WebsiteSSL{
|
||||||
|
Provider: constant.Manual,
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Type == "local" {
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
if !fileOp.Stat(req.PrivateKeyPath) {
|
||||||
|
return buserr.New("ErrSSLKeyNotFound")
|
||||||
|
}
|
||||||
|
if !fileOp.Stat(req.CertificatePath) {
|
||||||
|
return buserr.New("ErrSSLCertificateNotFound")
|
||||||
|
}
|
||||||
|
if content, err := fileOp.GetContent(req.PrivateKeyPath); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
newSSL.PrivateKey = string(content)
|
||||||
|
}
|
||||||
|
if content, err := fileOp.GetContent(req.CertificatePath); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
newSSL.Pem = string(content)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newSSL.PrivateKey = req.PrivateKey
|
||||||
|
newSSL.Pem = req.Certificate
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKeyCertBlock, _ := pem.Decode([]byte(newSSL.PrivateKey))
|
||||||
|
if privateKeyCertBlock == nil {
|
||||||
|
return buserr.New("ErrSSLKeyFormat")
|
||||||
|
}
|
||||||
|
|
||||||
|
certBlock, _ := pem.Decode([]byte(newSSL.Pem))
|
||||||
|
if certBlock == nil {
|
||||||
|
return buserr.New("ErrSSLCertificateFormat")
|
||||||
|
}
|
||||||
|
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newSSL.ExpireDate = cert.NotAfter
|
||||||
|
newSSL.StartDate = cert.NotBefore
|
||||||
|
newSSL.Type = cert.Issuer.CommonName
|
||||||
|
if len(cert.Issuer.Organization) > 0 {
|
||||||
|
newSSL.Organization = cert.Issuer.Organization[0]
|
||||||
|
} else {
|
||||||
|
newSSL.Organization = cert.Issuer.CommonName
|
||||||
|
}
|
||||||
|
if len(cert.DNSNames) > 0 {
|
||||||
|
newSSL.PrimaryDomain = cert.DNSNames[0]
|
||||||
|
newSSL.Domains = strings.Join(cert.DNSNames, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
return websiteSSLRepo.Create(context.Background(), newSSL)
|
||||||
|
}
|
||||||
|
|
|
@ -23,5 +23,6 @@ func (a *WebsiteSSLRouter) InitWebsiteSSLRouter(Router *gin.RouterGroup) {
|
||||||
groupRouter.GET("/website/:websiteId", baseApi.GetWebsiteSSLByWebsiteId)
|
groupRouter.GET("/website/:websiteId", baseApi.GetWebsiteSSLByWebsiteId)
|
||||||
groupRouter.GET("/:id", baseApi.GetWebsiteSSLById)
|
groupRouter.GET("/:id", baseApi.GetWebsiteSSLById)
|
||||||
groupRouter.POST("/update", baseApi.UpdateWebsiteSSL)
|
groupRouter.POST("/update", baseApi.UpdateWebsiteSSL)
|
||||||
|
groupRouter.POST("/upload", baseApi.UploadWebsiteSSL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by swaggo/swag. DO NOT EDIT.
|
// Package docs GENERATED BY SWAG; DO NOT EDIT
|
||||||
|
// This file was generated by swaggo/swag
|
||||||
package docs
|
package docs
|
||||||
|
|
||||||
import "github.com/swaggo/swag"
|
import "github.com/swaggo/swag"
|
||||||
|
@ -12234,6 +12234,48 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/websites/ssl/upload": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "上传 ssl",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Website SSL"
|
||||||
|
],
|
||||||
|
"summary": "Upload ssl",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/request.WebsiteSSLUpload"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFunctions": [],
|
||||||
|
"bodyKeys": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"formatEN": "Upload ssl [type]",
|
||||||
|
"formatZH": "上传 ssl [type]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/websites/ssl/website/:websiteId": {
|
"/websites/ssl/website/:websiteId": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -16861,19 +16903,10 @@ const docTemplate = `{
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"sortBy": {
|
"sortBy": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"enum": [
|
|
||||||
"name",
|
|
||||||
"size",
|
|
||||||
"modTime"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"sortOrder": {
|
"sortOrder": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"enum": [
|
|
||||||
"ascending",
|
|
||||||
"descending"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -18160,6 +18193,33 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"request.WebsiteSSLUpload": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"certificate": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"certificatePath": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"privateKeyPath": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"paste",
|
||||||
|
"local"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"request.WebsiteSearch": {
|
"request.WebsiteSearch": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
@ -12227,6 +12227,48 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/websites/ssl/upload": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "上传 ssl",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Website SSL"
|
||||||
|
],
|
||||||
|
"summary": "Upload ssl",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/request.WebsiteSSLUpload"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFunctions": [],
|
||||||
|
"bodyKeys": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"formatEN": "Upload ssl [type]",
|
||||||
|
"formatZH": "上传 ssl [type]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/websites/ssl/website/:websiteId": {
|
"/websites/ssl/website/:websiteId": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -16854,19 +16896,10 @@
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"sortBy": {
|
"sortBy": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"enum": [
|
|
||||||
"name",
|
|
||||||
"size",
|
|
||||||
"modTime"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"sortOrder": {
|
"sortOrder": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"enum": [
|
|
||||||
"ascending",
|
|
||||||
"descending"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -18153,6 +18186,33 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"request.WebsiteSSLUpload": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"certificate": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"certificatePath": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"privateKeyPath": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"paste",
|
||||||
|
"local"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"request.WebsiteSearch": {
|
"request.WebsiteSearch": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
@ -2963,15 +2963,8 @@ definitions:
|
||||||
showHidden:
|
showHidden:
|
||||||
type: boolean
|
type: boolean
|
||||||
sortBy:
|
sortBy:
|
||||||
enum:
|
|
||||||
- name
|
|
||||||
- size
|
|
||||||
- modTime
|
|
||||||
type: string
|
type: string
|
||||||
sortOrder:
|
sortOrder:
|
||||||
enum:
|
|
||||||
- ascending
|
|
||||||
- descending
|
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
request.FilePathCheck:
|
request.FilePathCheck:
|
||||||
|
@ -3838,6 +3831,24 @@ definitions:
|
||||||
- autoRenew
|
- autoRenew
|
||||||
- id
|
- id
|
||||||
type: object
|
type: object
|
||||||
|
request.WebsiteSSLUpload:
|
||||||
|
properties:
|
||||||
|
certificate:
|
||||||
|
type: string
|
||||||
|
certificatePath:
|
||||||
|
type: string
|
||||||
|
privateKey:
|
||||||
|
type: string
|
||||||
|
privateKeyPath:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- paste
|
||||||
|
- local
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
request.WebsiteSearch:
|
request.WebsiteSearch:
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
|
@ -12080,6 +12091,33 @@ paths:
|
||||||
formatEN: Update ssl config [domain]
|
formatEN: Update ssl config [domain]
|
||||||
formatZH: 更新证书设置 [domain]
|
formatZH: 更新证书设置 [domain]
|
||||||
paramKeys: []
|
paramKeys: []
|
||||||
|
/websites/ssl/upload:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 上传 ssl
|
||||||
|
parameters:
|
||||||
|
- description: request
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/request.WebsiteSSLUpload'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: Upload ssl
|
||||||
|
tags:
|
||||||
|
- Website SSL
|
||||||
|
x-panel-log:
|
||||||
|
BeforeFunctions: []
|
||||||
|
bodyKeys:
|
||||||
|
- type
|
||||||
|
formatEN: Upload ssl [type]
|
||||||
|
formatZH: 上传 ssl [type]
|
||||||
|
paramKeys: []
|
||||||
/websites/ssl/website/:websiteId:
|
/websites/ssl/website/:websiteId:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
@ -439,4 +439,12 @@ export namespace Website {
|
||||||
userGroup: string;
|
userGroup: string;
|
||||||
msg: string;
|
msg: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SSLUpload {
|
||||||
|
privateKey: string;
|
||||||
|
certificate: string;
|
||||||
|
privateKeyPath: string;
|
||||||
|
certificatePath: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,3 +239,7 @@ export const ChangePHPVersion = (req: Website.PHPVersionChange) => {
|
||||||
export const GetDirConfig = (req: Website.ProxyReq) => {
|
export const GetDirConfig = (req: Website.ProxyReq) => {
|
||||||
return http.post<Website.DirConfig>(`/websites/dir`, req);
|
return http.post<Website.DirConfig>(`/websites/dir`, req);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const UploadSSL = (req: Website.SSLUpload) => {
|
||||||
|
return http.post<any>(`/websites/ssl/upload`, req);
|
||||||
|
};
|
||||||
|
|
|
@ -1715,6 +1715,7 @@ const message = {
|
||||||
'This certificate has been associated with the following websites, and the renewal will be applied to these websites simultaneously',
|
'This certificate has been associated with the following websites, and the renewal will be applied to these websites simultaneously',
|
||||||
createAcme: 'Create Account',
|
createAcme: 'Create Account',
|
||||||
acmeHelper: 'Acme account is used to apply for free certificates',
|
acmeHelper: 'Acme account is used to apply for free certificates',
|
||||||
|
upload: 'Upload Certificate',
|
||||||
},
|
},
|
||||||
firewall: {
|
firewall: {
|
||||||
create: 'Create rule',
|
create: 'Create rule',
|
||||||
|
|
|
@ -1626,6 +1626,7 @@ const message = {
|
||||||
renewWebsite: '該證書已經和以下網站關聯,續簽會同步應用到這些網站',
|
renewWebsite: '該證書已經和以下網站關聯,續簽會同步應用到這些網站',
|
||||||
createAcme: '創建賬戶',
|
createAcme: '創建賬戶',
|
||||||
acmeHelper: 'Acme 賬戶用於申請免費證書',
|
acmeHelper: 'Acme 賬戶用於申請免費證書',
|
||||||
|
upload: '上傳證書',
|
||||||
},
|
},
|
||||||
firewall: {
|
firewall: {
|
||||||
create: '創建規則',
|
create: '創建規則',
|
||||||
|
|
|
@ -1626,6 +1626,7 @@ const message = {
|
||||||
renewWebsite: '该证书已经和以下网站关联,续签会同步应用到这些网站',
|
renewWebsite: '该证书已经和以下网站关联,续签会同步应用到这些网站',
|
||||||
createAcme: '创建账户',
|
createAcme: '创建账户',
|
||||||
acmeHelper: 'Acme 账户用于申请免费证书',
|
acmeHelper: 'Acme 账户用于申请免费证书',
|
||||||
|
upload: '上传证书',
|
||||||
},
|
},
|
||||||
firewall: {
|
firewall: {
|
||||||
create: '创建规则',
|
create: '创建规则',
|
||||||
|
|
|
@ -28,9 +28,12 @@
|
||||||
>
|
>
|
||||||
{{ ssl.acmeAccount.email }}
|
{{ ssl.acmeAccount.email }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item :label="$t('website.brand')">
|
<el-descriptions-item :label="$t('commons.table.type')">
|
||||||
{{ ssl.type }}
|
{{ ssl.type }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item :label="$t('website.brand')">
|
||||||
|
{{ ssl.organization }}
|
||||||
|
</el-descriptions-item>
|
||||||
<el-descriptions-item :label="$t('ssl.startDate')">
|
<el-descriptions-item :label="$t('ssl.startDate')">
|
||||||
{{ dateFormatSimple(ssl.startDate) }}
|
{{ dateFormatSimple(ssl.startDate) }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
<el-button type="primary" @click="openSSL()">
|
<el-button type="primary" @click="openSSL()">
|
||||||
{{ $t('ssl.create') }}
|
{{ $t('ssl.create') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button type="primary" @click="openUpload()">
|
||||||
|
{{ $t('ssl.upload') }}
|
||||||
|
</el-button>
|
||||||
<el-button type="primary" plain @click="openAcmeAccount()">
|
<el-button type="primary" plain @click="openAcmeAccount()">
|
||||||
{{ $t('website.acmeAccountManage') }}
|
{{ $t('website.acmeAccountManage') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
@ -79,6 +82,7 @@
|
||||||
<Create ref="sslCreateRef" @close="search()"></Create>
|
<Create ref="sslCreateRef" @close="search()"></Create>
|
||||||
<Renew ref="renewRef" @close="search()"></Renew>
|
<Renew ref="renewRef" @close="search()"></Renew>
|
||||||
<Detail ref="detailRef"></Detail>
|
<Detail ref="detailRef"></Detail>
|
||||||
|
<SSLUpload ref="sslUploadRef" @close="search()"></SSLUpload>
|
||||||
</LayoutContent>
|
</LayoutContent>
|
||||||
|
|
||||||
<OpDialog ref="opRef" @search="search" />
|
<OpDialog ref="opRef" @search="search" />
|
||||||
|
@ -99,6 +103,7 @@ import i18n from '@/lang';
|
||||||
import { Website } from '@/api/interface/website';
|
import { Website } from '@/api/interface/website';
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
import { GlobalStore } from '@/store';
|
import { GlobalStore } from '@/store';
|
||||||
|
import SSLUpload from './upload/index.vue';
|
||||||
const globalStore = GlobalStore();
|
const globalStore = GlobalStore();
|
||||||
|
|
||||||
const paginationConfig = reactive({
|
const paginationConfig = reactive({
|
||||||
|
@ -112,9 +117,10 @@ const dnsAccountRef = ref();
|
||||||
const sslCreateRef = ref();
|
const sslCreateRef = ref();
|
||||||
const renewRef = ref();
|
const renewRef = ref();
|
||||||
const detailRef = ref();
|
const detailRef = ref();
|
||||||
let data = ref();
|
const data = ref();
|
||||||
let loading = ref(false);
|
const loading = ref(false);
|
||||||
const opRef = ref();
|
const opRef = ref();
|
||||||
|
const sslUploadRef = ref();
|
||||||
|
|
||||||
const routerButton = [
|
const routerButton = [
|
||||||
{
|
{
|
||||||
|
@ -187,6 +193,9 @@ const openDnsAccount = () => {
|
||||||
const openSSL = () => {
|
const openSSL = () => {
|
||||||
sslCreateRef.value.acceptParams();
|
sslCreateRef.value.acceptParams();
|
||||||
};
|
};
|
||||||
|
const openUpload = () => {
|
||||||
|
sslUploadRef.value.acceptParams();
|
||||||
|
};
|
||||||
const openRenewSSL = (id: number, websites: Website.Website[]) => {
|
const openRenewSSL = (id: number, websites: Website.Website[]) => {
|
||||||
renewRef.value.acceptParams({ id: id, websites: websites });
|
renewRef.value.acceptParams({ id: id, websites: websites });
|
||||||
};
|
};
|
||||||
|
|
132
frontend/src/views/website/ssl/upload/index.vue
Normal file
132
frontend/src/views/website/ssl/upload/index.vue
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
<template>
|
||||||
|
<el-drawer :close-on-click-modal="false" v-model="open" size="50%">
|
||||||
|
<template #header>
|
||||||
|
<DrawerHeader :header="$t('ssl.upload')" :back="handleClose" />
|
||||||
|
</template>
|
||||||
|
<el-row v-loading="loading">
|
||||||
|
<el-col :span="22" :offset="1">
|
||||||
|
<el-form ref="sslForm" label-position="top" :model="ssl" label-width="100px" :rules="rules">
|
||||||
|
<el-form-item :label="$t('website.importType')" prop="type">
|
||||||
|
<el-select v-model="ssl.type">
|
||||||
|
<el-option :label="$t('website.pasteSSL')" :value="'paste'"></el-option>
|
||||||
|
<el-option :label="$t('website.localSSL')" :value="'local'"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<div v-if="ssl.type === 'paste'">
|
||||||
|
<el-form-item :label="$t('website.privateKey')" prop="privateKey">
|
||||||
|
<el-input v-model="ssl.privateKey" :rows="6" type="textarea" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('website.certificate')" prop="certificate">
|
||||||
|
<el-input v-model="ssl.certificate" :rows="6" type="textarea" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<div v-if="ssl.type === 'local'">
|
||||||
|
<el-form-item :label="$t('website.privateKeyPath')" prop="privateKeyPath">
|
||||||
|
<el-input v-model="ssl.privateKeyPath">
|
||||||
|
<template #prepend>
|
||||||
|
<FileList @choose="getPrivateKeyPath" :dir="false"></FileList>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('website.certificatePath')" prop="certificatePath">
|
||||||
|
<el-input v-model="ssl.certificatePath">
|
||||||
|
<template #prepend>
|
||||||
|
<FileList @choose="getCertificatePath" :dir="false"></FileList>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
|
<el-button type="primary" @click="submit(sslForm)" :disabled="loading">
|
||||||
|
{{ $t('commons.button.confirm') }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||||
|
import { UploadSSL } from '@/api/modules/website';
|
||||||
|
import { Rules } from '@/global/form-rules';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
import { FormInstance } from 'element-plus';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { MsgSuccess } from '@/utils/message';
|
||||||
|
|
||||||
|
const open = ref(false);
|
||||||
|
const loading = ref(false);
|
||||||
|
const sslForm = ref<FormInstance>();
|
||||||
|
|
||||||
|
const rules = ref({
|
||||||
|
privateKey: [Rules.requiredInput],
|
||||||
|
certificate: [Rules.requiredInput],
|
||||||
|
privateKeyPath: [Rules.requiredInput],
|
||||||
|
certificatePath: [Rules.requiredInput],
|
||||||
|
type: [Rules.requiredSelect],
|
||||||
|
});
|
||||||
|
const ssl = ref({
|
||||||
|
privateKey: '',
|
||||||
|
certificate: '',
|
||||||
|
privateKeyPath: '',
|
||||||
|
certificatePath: '',
|
||||||
|
type: 'paste',
|
||||||
|
});
|
||||||
|
|
||||||
|
const em = defineEmits(['close']);
|
||||||
|
const handleClose = () => {
|
||||||
|
resetForm();
|
||||||
|
open.value = false;
|
||||||
|
em('close', false);
|
||||||
|
};
|
||||||
|
const resetForm = () => {
|
||||||
|
sslForm.value?.resetFields();
|
||||||
|
ssl.value = {
|
||||||
|
privateKey: '',
|
||||||
|
certificate: '',
|
||||||
|
privateKeyPath: '',
|
||||||
|
certificatePath: '',
|
||||||
|
type: 'paste',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const acceptParams = () => {
|
||||||
|
resetForm();
|
||||||
|
open.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPrivateKeyPath = (path: string) => {
|
||||||
|
ssl.value.privateKeyPath = path;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCertificatePath = (path: string) => {
|
||||||
|
ssl.value.certificatePath = path;
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (!valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loading.value = true;
|
||||||
|
UploadSSL(ssl.value)
|
||||||
|
.then(() => {
|
||||||
|
handleClose();
|
||||||
|
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
acceptParams,
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Reference in a new issue