feat: 机构证书增加下载功能 (#5676)

Refs #4911
pull/5678/head
zhengkunwang 5 months ago committed by GitHub
parent f370f7eacf
commit 08125b150a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -6,6 +6,9 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/gin-gonic/gin"
"net/http"
"net/url"
"strconv"
)
// @Tags Website CA
@ -142,3 +145,33 @@ func (b *BaseApi) RenewWebsiteCA(c *gin.Context) {
}
helper.SuccessWithOutData(c)
}
// @Tags Website CA
// @Summary Download CA file
// @Description 下载 CA 证书文件
// @Accept json
// @Param request body request.WebsiteResourceReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/ca/download [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_cas","output_column":"name","output_value":"name"}],"formatZH":"下载 CA 证书文件 [name]","formatEN":"download ca file [name]"}
func (b *BaseApi) DownloadCAFile(c *gin.Context) {
var req request.WebsiteResourceReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
file, err := websiteCAService.DownloadFile(req.ID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
defer file.Close()
info, err := file.Stat()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), file)
}

@ -15,6 +15,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
@ -39,6 +40,7 @@ type IWebsiteCAService interface {
GetCA(id uint) (*response.WebsiteCADTO, error)
Delete(id uint) error
ObtainSSL(req request.WebsiteCAObtain) (*model.WebsiteSSL, error)
DownloadFile(id uint) (*os.File, error)
}
func NewIWebsiteCAService() IWebsiteCAService {
@ -414,3 +416,31 @@ func createPrivateKey(keyType string) (privateKey any, publicKey any, privateKey
privateKeyBytes = caPrivateKeyPEM.Bytes()
return
}
func (w WebsiteCAService) DownloadFile(id uint) (*os.File, error) {
ca, err := websiteCARepo.GetFirst(commonRepo.WithByID(id))
if err != nil {
return nil, err
}
fileOp := files.NewFileOp()
dir := path.Join(global.CONF.System.BaseDir, "1panel/tmp/ssl", ca.Name)
if fileOp.Stat(dir) {
if err = fileOp.DeleteDir(dir); err != nil {
return nil, err
}
}
if err = fileOp.CreateDir(dir, 0666); err != nil {
return nil, err
}
if err = fileOp.WriteFile(path.Join(dir, "ca.csr"), strings.NewReader(ca.CSR), 0644); err != nil {
return nil, err
}
if err = fileOp.WriteFile(path.Join(dir, "private.key"), strings.NewReader(ca.PrivateKey), 0644); err != nil {
return nil, err
}
fileName := ca.Name + ".zip"
if err = fileOp.Compress([]string{path.Join(dir, "ca.csr"), path.Join(dir, "private.key")}, dir, fileName, files.SdkZip, ""); err != nil {
return nil, err
}
return os.Open(path.Join(dir, fileName))
}

@ -21,5 +21,6 @@ func (a *WebsiteCARouter) InitRouter(Router *gin.RouterGroup) {
groupRouter.POST("/obtain", baseApi.ObtainWebsiteCA)
groupRouter.POST("/renew", baseApi.RenewWebsiteCA)
groupRouter.GET("/:id", baseApi.GetWebsiteCA)
groupRouter.POST("/download", baseApi.DownloadCAFile)
}
}

@ -276,3 +276,10 @@ export const GetDefaultHtml = (type: string) => {
export const UpdateDefaultHtml = (req: Website.WebsiteHtmlUpdate) => {
return http.post(`/websites/default/html/update`, req);
};
export const DownloadCAFile = (params: Website.SSLDownload) => {
return http.download<BlobPart>(`/websites/ca/download`, params, {
responseType: 'blob',
timeout: TimeoutEnum.T_40S,
});
};

@ -12,7 +12,7 @@ const message = {
false: 'false',
example: 'e.g.:',
button: {
create: 'Create',
create: 'Create ',
add: 'Add ',
save: 'Save ',
set: 'Setting',

@ -13,7 +13,7 @@
<el-row>
<el-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('commons.button.create') }} {{ $t('cronjob.cronTask') }}
{{ $t('commons.button.create') }}{{ $t('cronjob.cronTask') }}
</el-button>
<el-button-group class="ml-4">
<el-button plain :disabled="selects.length === 0" @click="onBatchChangeStatus('enable')">

@ -22,7 +22,7 @@
<el-row>
<el-col :span="16">
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('commons.button.create') }} {{ $t('firewall.forwardRule') }}
{{ $t('commons.button.create') }}{{ $t('firewall.forwardRule') }}
</el-button>
<el-button @click="onDelete(null)" plain :disabled="selects.length === 0">
{{ $t('commons.button.delete') }}

@ -55,7 +55,7 @@
<el-row>
<el-col :span="16">
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('commons.button.create') }} {{ $t('firewall.portRule') }}
{{ $t('commons.button.create') }}{{ $t('firewall.portRule') }}
</el-button>
<el-button @click="onDelete(null)" plain :disabled="selects.length === 0">
{{ $t('commons.button.delete') }}

@ -43,7 +43,7 @@
<script lang="ts" setup>
import DrawerHeader from '@/components/drawer-header/index.vue';
import { Website } from '@/api/interface/website';
import { DeleteCA, SearchCAs } from '@/api/modules/website';
import { DeleteCA, SearchCAs, DownloadCAFile } from '@/api/modules/website';
import i18n from '@/lang';
import { reactive, ref } from 'vue';
import Create from './create/index.vue';
@ -79,6 +79,12 @@ const buttons = [
detailRef.value.acceptParams(row.id);
},
},
{
label: i18n.global.t('commons.button.download'),
click: function (row: Website.CA) {
onDownload(row);
},
},
{
label: i18n.global.t('commons.button.delete'),
click: function (row: Website.CA) {
@ -129,6 +135,23 @@ const deleteCA = async (row: any) => {
});
};
const onDownload = (row: Website.CA) => {
loading.value = true;
DownloadCAFile({ id: row.id })
.then((res) => {
const downloadUrl = window.URL.createObjectURL(new Blob([res]));
const a = document.createElement('a');
a.style.display = 'none';
a.href = downloadUrl;
a.download = row.name + '.zip';
const event = new MouseEvent('click');
a.dispatchEvent(event);
})
.finally(() => {
loading.value = false;
});
};
defineExpose({
acceptParams,
});

Loading…
Cancel
Save