mirror of
https://gitee.com/fit2cloud-feizhiyun/1Panel.git
synced 2024-12-05 13:29:11 +08:00
feat: 证书增加申请日志 (#3002)
This commit is contained in:
parent
cda900e04a
commit
52b16f0cb4
@ -4,6 +4,7 @@ import "github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
|
||||
type WebsiteSSLDTO struct {
|
||||
model.WebsiteSSL
|
||||
LogPath string `json:"logPath"`
|
||||
}
|
||||
|
||||
type WebsiteDNSRes struct {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"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/model"
|
||||
@ -11,11 +12,15 @@ import (
|
||||
"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/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
legoLogger "github.com/go-acme/lego/v4/log"
|
||||
"github.com/jinzhu/gorm"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -37,6 +42,7 @@ type IWebsiteSSLService interface {
|
||||
Update(update request.WebsiteSSLUpdate) error
|
||||
Upload(req request.WebsiteSSLUpload) error
|
||||
ObtainSSL(apply request.WebsiteSSLApply) error
|
||||
SyncForRestart() error
|
||||
}
|
||||
|
||||
func NewIWebsiteSSLService() IWebsiteSSLService {
|
||||
@ -51,9 +57,10 @@ func (w WebsiteSSLService) Page(search request.WebsiteSSLSearch) (int64, []respo
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
for _, sslModel := range sslList {
|
||||
for _, model := range sslList {
|
||||
result = append(result, response.WebsiteSSLDTO{
|
||||
WebsiteSSL: sslModel,
|
||||
WebsiteSSL: model,
|
||||
LogPath: path.Join(constant.SSLLogDir, fmt.Sprintf("%s-ssl-%d.log", model.PrimaryDomain, model.ID)),
|
||||
})
|
||||
}
|
||||
return total, result, err
|
||||
@ -141,11 +148,19 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(apply.ID))
|
||||
|
||||
var (
|
||||
err error
|
||||
websiteSSL model.WebsiteSSL
|
||||
acmeAccount *model.WebsiteAcmeAccount
|
||||
dnsAccount *model.WebsiteDnsAccount
|
||||
)
|
||||
|
||||
websiteSSL, err = websiteSSLRepo.GetFirst(commonRepo.WithByID(apply.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(websiteSSL.AcmeAccountID))
|
||||
acmeAccount, err = websiteAcmeRepo.GetFirst(commonRepo.WithByID(websiteSSL.AcmeAccountID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -156,11 +171,11 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
|
||||
switch websiteSSL.Provider {
|
||||
case constant.DNSAccount:
|
||||
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(websiteSSL.DnsAccountID))
|
||||
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 {
|
||||
if err = client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization); err != nil {
|
||||
return err
|
||||
}
|
||||
case constant.Http:
|
||||
@ -181,7 +196,9 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
}
|
||||
|
||||
domains := []string{websiteSSL.PrimaryDomain}
|
||||
domains = append(domains, domains...)
|
||||
if websiteSSL.Domains != "" {
|
||||
domains = append(domains, strings.Split(websiteSSL.Domains, ",")...)
|
||||
}
|
||||
|
||||
privateKey, err := certcrypto.GeneratePrivateKey(ssl.KeyType(websiteSSL.KeyType))
|
||||
if err != nil {
|
||||
@ -195,6 +212,15 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
}
|
||||
|
||||
go func() {
|
||||
logFile, _ := os.OpenFile(path.Join(constant.SSLLogDir, fmt.Sprintf("%s-ssl-%d.log", websiteSSL.PrimaryDomain, websiteSSL.ID)), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
defer logFile.Close()
|
||||
logger := log.New(logFile, "", log.LstdFlags)
|
||||
legoLogger.Logger = logger
|
||||
startMsg := i18n.GetMsgWithMap("ApplySSLStart", map[string]interface{}{"domain": strings.Join(domains, ","), "type": i18n.GetMsgByKey(websiteSSL.Provider)})
|
||||
if websiteSSL.Provider == constant.DNSAccount {
|
||||
startMsg = startMsg + i18n.GetMsgWithMap("DNSAccountName", map[string]interface{}{"name": dnsAccount.Name, "type": dnsAccount.Type})
|
||||
}
|
||||
legoLogger.Logger.Println(startMsg)
|
||||
resource, err := client.ObtainSSL(domains, privateKey)
|
||||
if err != nil {
|
||||
handleError(websiteSSL, err)
|
||||
@ -214,6 +240,7 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
websiteSSL.Type = cert.Issuer.CommonName
|
||||
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||
websiteSSL.Status = constant.SSLReady
|
||||
legoLogger.Logger.Println(i18n.GetMsgWithMap("ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}))
|
||||
err = websiteSSLRepo.Save(websiteSSL)
|
||||
if err != nil {
|
||||
return
|
||||
@ -230,6 +257,7 @@ func handleError(websiteSSL model.WebsiteSSL, err error) {
|
||||
websiteSSL.Status = constant.SSLApplyError
|
||||
}
|
||||
websiteSSL.Message = err.Error()
|
||||
legoLogger.Logger.Println(i18n.GetErrMsg("ApplySSLFailed", map[string]interface{}{"domain": websiteSSL.PrimaryDomain, "err": err.Error()}))
|
||||
_ = websiteSSLRepo.Save(websiteSSL)
|
||||
}
|
||||
|
||||
@ -425,3 +453,18 @@ func (w WebsiteSSLService) Upload(req request.WebsiteSSLUpload) error {
|
||||
|
||||
return websiteSSLRepo.Create(context.Background(), newSSL)
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) SyncForRestart() error {
|
||||
sslList, err := websiteSSLRepo.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ssl := range sslList {
|
||||
if ssl.Status == constant.SSLApply {
|
||||
ssl.Status = constant.SystemRestart
|
||||
ssl.Message = "System restart causing interrupt"
|
||||
_ = websiteSSLRepo.Save(ssl)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -16,4 +16,5 @@ var (
|
||||
RemoteAppResourceDir = path.Join(AppResourceDir, "remote")
|
||||
RuntimeDir = path.Join(DataDir, "runtime")
|
||||
RecycleBinDir = "/.1panel_clash"
|
||||
SSLLogDir = path.Join(global.CONF.System.DataDir, "log", "ssl")
|
||||
)
|
||||
|
@ -23,7 +23,7 @@ func (ssl *ssl) Run() {
|
||||
global.LOG.Info("The scheduled certificate update task is currently in progress ...")
|
||||
now := time.Now().Add(10 * time.Second)
|
||||
for _, s := range sslList {
|
||||
if !s.AutoRenew || s.Provider == "manual" || s.Provider == "dnsManual" {
|
||||
if !s.AutoRenew || s.Provider == "manual" || s.Provider == "dnsManual" || s.Status == "applying" {
|
||||
continue
|
||||
}
|
||||
expireDate := s.ExpireDate.In(nyc)
|
||||
|
@ -93,6 +93,13 @@ ErrSSLKeyFormat: 'Private key file verification error'
|
||||
ErrSSLCertificateFormat: 'Certificate file format error, please use pem format'
|
||||
ErrEabKidOrEabHmacKeyCannotBlank: 'EabKid or EabHmacKey cannot be empty'
|
||||
ErrOpenrestyNotFound: 'Http mode requires Openresty to be installed first'
|
||||
ApplySSLStart: 'Start applying for certificate, domain name [{{ .domain }}] application method [{{ .type }}] '
|
||||
dnsAccount: "DNS Automatic"
|
||||
dnsManual: "DNS Manual"
|
||||
http: "HTTP"
|
||||
ApplySSLFailed: 'Application for [{{ .domain }}] certificate failed, {{.detail}} '
|
||||
ApplySSLSuccess: 'Application for [{{ .domain }}] certificate successful! ! '
|
||||
DNSAccountName: 'DNS account [{{ .name }}] manufacturer [{{.type}}]'
|
||||
|
||||
|
||||
#mysql
|
||||
|
@ -93,6 +93,13 @@ ErrSSLKeyFormat: '私鑰文件校驗錯誤'
|
||||
ErrSSLCertificateFormat: '證書文件格式錯誤,請使用 pem 格式'
|
||||
ErrEabKidOrEabHmacKeyCannotBlank: 'EabKid 或 EabHmacKey 不能為空'
|
||||
ErrOpenrestyNotFound: 'Http 模式需要先安裝 Openresty'
|
||||
ApplySSLStart: '開始申請憑證,網域 [{{ .domain }}] 申請方式 [{{ .type }}] '
|
||||
dnsAccount: "DNS 自動"
|
||||
dnsManual: "DNS 手排"
|
||||
http: "HTTP"
|
||||
ApplySSLFailed: '申請 [{{ .domain }}] 憑證失敗, {{.detail}} '
|
||||
ApplySSLSuccess: '申請 [{{ .domain }}] 憑證成功! ! '
|
||||
DNSAccountName: 'DNS 帳號 [{{ .name }}] 廠商 [{{.type}}]'
|
||||
|
||||
#mysql
|
||||
ErrUserIsExist: "當前用戶已存在,請重新輸入"
|
||||
|
@ -93,6 +93,13 @@ ErrSSLKeyFormat: '私钥文件校验失败'
|
||||
ErrSSLCertificateFormat: '证书文件格式错误,请使用 pem 格式'
|
||||
ErrEabKidOrEabHmacKeyCannotBlank: 'EabKid 或 EabHmacKey 不能为空'
|
||||
ErrOpenrestyNotFound: 'Http 模式需要首先安装 Openresty'
|
||||
ApplySSLStart: '开始申请证书,域名 [{{ .domain }}] 申请方式 [{{ .type }}] '
|
||||
dnsAccount: "DNS 自动"
|
||||
dnsManual: "DNS 手动"
|
||||
http: "HTTP"
|
||||
ApplySSLFailed: '申请 [{{ .domain }}] 证书失败, {{.detail}} '
|
||||
ApplySSLSuccess: '申请 [{{ .domain }}] 证书成功!!'
|
||||
DNSAccountName: 'DNS 账号 [{{ .name }}] 厂商 [{{.type}}]'
|
||||
|
||||
#mysql
|
||||
ErrUserIsExist: "当前用户已存在,请重新输入"
|
||||
|
@ -20,8 +20,10 @@ func Init() {
|
||||
constant.LocalAppInstallDir = path.Join(constant.AppInstallDir, "local")
|
||||
constant.RemoteAppResourceDir = path.Join(constant.AppResourceDir, "remote")
|
||||
|
||||
constant.SSLLogDir = path.Join(global.CONF.System.DataDir, "log", "ssl")
|
||||
|
||||
dirs := []string{constant.DataDir, constant.ResourceDir, constant.AppResourceDir, constant.AppInstallDir,
|
||||
global.CONF.System.Backup, constant.RuntimeDir, constant.LocalAppResourceDir, constant.RemoteAppResourceDir}
|
||||
global.CONF.System.Backup, constant.RuntimeDir, constant.LocalAppResourceDir, constant.RemoteAppResourceDir, constant.SSLLogDir}
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
for _, dir := range dirs {
|
||||
|
@ -10,6 +10,7 @@ func Init() {
|
||||
go syncApp()
|
||||
go syncInstalledApp()
|
||||
go syncRuntime()
|
||||
go syncSSL()
|
||||
}
|
||||
|
||||
func syncApp() {
|
||||
@ -31,3 +32,9 @@ func syncRuntime() {
|
||||
global.LOG.Errorf("sync runtime status error : %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func syncSSL() {
|
||||
if err := service.NewIWebsiteSSLService().SyncForRestart(); err != nil {
|
||||
global.LOG.Errorf("sync ssl status error : %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +165,11 @@ export namespace Website {
|
||||
autoRenew: boolean;
|
||||
acmeAccountId?: number;
|
||||
status: string;
|
||||
domains?: string;
|
||||
}
|
||||
|
||||
export interface SSLDTO extends SSL {
|
||||
domains: string;
|
||||
logPath: string;
|
||||
}
|
||||
|
||||
export interface SSLCreate {
|
||||
|
@ -93,11 +93,11 @@ export const DeleteAcmeAccount = (req: Website.DelReq) => {
|
||||
};
|
||||
|
||||
export const SearchSSL = (req: ReqPage) => {
|
||||
return http.post<ResPage<Website.SSL>>(`/websites/ssl/search`, req);
|
||||
return http.post<ResPage<Website.SSLDTO>>(`/websites/ssl/search`, req);
|
||||
};
|
||||
|
||||
export const ListSSL = (req: Website.SSLReq) => {
|
||||
return http.post<Website.SSL[]>(`/websites/ssl/search`, req);
|
||||
return http.post<Website.SSLDTO[]>(`/websites/ssl/search`, req);
|
||||
};
|
||||
|
||||
export const CreateSSL = (req: Website.SSLCreate) => {
|
||||
|
@ -1765,7 +1765,7 @@ const message = {
|
||||
saveAndReload: 'Save and Reload',
|
||||
},
|
||||
ssl: {
|
||||
create: 'Create Certificate',
|
||||
create: 'Apply Certificate',
|
||||
provider: 'Type',
|
||||
manualCreate: 'manually created',
|
||||
acmeAccount: 'Acme Account',
|
||||
|
@ -1662,7 +1662,7 @@ const message = {
|
||||
saveAndReload: '保存並重載',
|
||||
},
|
||||
ssl: {
|
||||
create: '創建證書',
|
||||
create: '申請證書',
|
||||
provider: '類型',
|
||||
manualCreate: '手動創建',
|
||||
acmeAccount: 'Acme 賬號',
|
||||
|
@ -1662,7 +1662,7 @@ const message = {
|
||||
saveAndReload: '保存并重载',
|
||||
},
|
||||
ssl: {
|
||||
create: '创建证书',
|
||||
create: '申请证书',
|
||||
provider: '类型',
|
||||
manualCreate: '手动创建',
|
||||
acmeAccount: 'Acme 账号',
|
||||
|
@ -87,7 +87,7 @@ import CreateRuntime from '@/views/website/runtime/php/create/index.vue';
|
||||
import Status from '@/components/status/index.vue';
|
||||
import i18n from '@/lang';
|
||||
import RouterMenu from '../index.vue';
|
||||
import Log from '@/views/website/runtime/php/log/index.vue';
|
||||
import Log from '@/components/log/index.vue';
|
||||
|
||||
const paginationConfig = reactive({
|
||||
cacheSizeKey: 'runtime-page-size',
|
||||
|
@ -81,6 +81,11 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('website.log')" prop="">
|
||||
<template #default="{ row }">
|
||||
<el-button @click="openLog(row)" link type="primary">{{ $t('website.check') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('website.brand')"
|
||||
fix
|
||||
@ -118,6 +123,7 @@
|
||||
<SSLUpload ref="sslUploadRef" @close="search()"></SSLUpload>
|
||||
<Apply ref="applyRef" @search="search" />
|
||||
<OpDialog ref="opRef" @search="search" />
|
||||
<Log ref="logRef" @close="search()" />
|
||||
</LayoutContent>
|
||||
</div>
|
||||
</template>
|
||||
@ -137,6 +143,7 @@ import { MsgSuccess } from '@/utils/message';
|
||||
import { GlobalStore } from '@/store';
|
||||
import SSLUpload from './upload/index.vue';
|
||||
import Apply from './apply/index.vue';
|
||||
import Log from '@/components/log/index.vue';
|
||||
|
||||
const globalStore = GlobalStore();
|
||||
const paginationConfig = reactive({
|
||||
@ -148,13 +155,13 @@ const paginationConfig = reactive({
|
||||
const acmeAccountRef = ref();
|
||||
const dnsAccountRef = ref();
|
||||
const sslCreateRef = ref();
|
||||
const renewRef = ref();
|
||||
const detailRef = ref();
|
||||
const data = ref();
|
||||
const loading = ref(false);
|
||||
const opRef = ref();
|
||||
const sslUploadRef = ref();
|
||||
const applyRef = ref();
|
||||
const logRef = ref();
|
||||
|
||||
const routerButton = [
|
||||
{
|
||||
@ -166,19 +173,19 @@ const routerButton = [
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('ssl.detail'),
|
||||
disabled: function (row: Website.SSL) {
|
||||
disabled: function (row: Website.SSLDTO) {
|
||||
return row.status === 'init' || row.status === 'error';
|
||||
},
|
||||
click: function (row: Website.SSL) {
|
||||
click: function (row: Website.SSLDTO) {
|
||||
openDetail(row.id);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('ssl.apply'),
|
||||
disabled: function (row: Website.SSL) {
|
||||
disabled: function (row: Website.SSLDTO) {
|
||||
return row.status === 'applying';
|
||||
},
|
||||
click: function (row: Website.SSL) {
|
||||
click: function (row: Website.SSLDTO) {
|
||||
if (row.provider === 'dnsManual') {
|
||||
applyRef.value.acceptParams({ ssl: row });
|
||||
} else {
|
||||
@ -188,7 +195,7 @@ const buttons = [
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: function (row: Website.SSL) {
|
||||
click: function (row: Website.SSLDTO) {
|
||||
deleteSSL(row);
|
||||
},
|
||||
},
|
||||
@ -214,7 +221,7 @@ const search = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const updateConfig = (row: Website.SSL) => {
|
||||
const updateConfig = (row: Website.SSLDTO) => {
|
||||
loading.value = true;
|
||||
UpdateSSL({ id: row.id, autoRenew: row.autoRenew })
|
||||
.then(() => {
|
||||
@ -237,27 +244,23 @@ const openSSL = () => {
|
||||
const openUpload = () => {
|
||||
sslUploadRef.value.acceptParams();
|
||||
};
|
||||
const openRenewSSL = (id: number, websites: Website.Website[]) => {
|
||||
renewRef.value.acceptParams({ id: id, websites: websites });
|
||||
};
|
||||
const openDetail = (id: number) => {
|
||||
detailRef.value.acceptParams(id);
|
||||
};
|
||||
const openLog = (row: Website.SSLDTO) => {
|
||||
logRef.value.acceptParams({ path: row.logPath });
|
||||
};
|
||||
|
||||
const applySSL = (row: Website.SSL) => {
|
||||
if (row.status === 'init' || row.status === 'error') {
|
||||
loading.value = true;
|
||||
ObtainSSL({ ID: row.id })
|
||||
.then(() => {
|
||||
MsgSuccess(i18n.global.t('ssl.applyStart'));
|
||||
search();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
} else {
|
||||
openRenewSSL(row.id, row.websites);
|
||||
}
|
||||
const applySSL = (row: Website.SSLDTO) => {
|
||||
loading.value = true;
|
||||
ObtainSSL({ ID: row.id })
|
||||
.then(() => {
|
||||
MsgSuccess(i18n.global.t('ssl.applyStart'));
|
||||
search();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const deleteSSL = async (row: any) => {
|
||||
|
Loading…
Reference in New Issue
Block a user