refactor(cert): introducing new management page

1. User can now view the latest renew logs of the certain certificate.

2. Add manually renew button in certificate modify page for managed certificate (auto cert)
This commit is contained in:
0xJacky 2023-12-04 22:14:37 +08:00
parent 7c47f08a72
commit ac68fd05c9
No known key found for this signature in database
GPG key ID: B6E4A6E4A561BAF0
36 changed files with 1908 additions and 1286 deletions

View file

@ -1,61 +1,13 @@
package cert
import (
"fmt"
"github.com/0xJacky/Nginx-UI/internal/logger"
"github.com/0xJacky/Nginx-UI/model"
"github.com/pkg/errors"
"strings"
"time"
)
func handleIssueCertLogChan(logChan chan string) {
defer func() {
if err := recover(); err != nil {
logger.Error(err)
}
}()
for logString := range logChan {
logger.Info("Auto Cert", logString)
}
}
type AutoCertErrorLog struct {
buffer []string
cert *model.Cert
}
func (t *AutoCertErrorLog) SetCertModel(cert *model.Cert) {
t.cert = cert
}
func (t *AutoCertErrorLog) Push(text string, err error) {
t.buffer = append(t.buffer, text+" "+err.Error())
logger.Error("AutoCert", text, err)
}
func (t *AutoCertErrorLog) Exit(text string, err error) {
t.buffer = append(t.buffer, text+" "+err.Error())
logger.Error("AutoCert", text, err)
if t.cert == nil {
return
}
_ = t.cert.Updates(&model.Cert{
Log: t.ToString(),
})
}
func (t *AutoCertErrorLog) ToString() (content string) {
for _, v := range t.buffer {
content += fmt.Sprintf("[Error] %s\n", v)
}
return
}
func AutoObtain() {
defer func() {
if err := recover(); err != nil {
@ -65,64 +17,64 @@ func AutoObtain() {
logger.Info("AutoCert Worker Started")
autoCertList := model.GetAutoCertList()
for _, certModel := range autoCertList {
confName := certModel.Filename
errLog := &AutoCertErrorLog{}
errLog.SetCertModel(certModel)
if len(certModel.Filename) == 0 {
errLog.Exit("", errors.New("filename is empty"))
continue
}
if len(certModel.Domains) == 0 {
errLog.Exit(confName, errors.New("domains list is empty, "+
"try to reopen auto-cert for this config:"+confName))
continue
}
if certModel.SSLCertificatePath != "" {
cert, err := GetCertInfo(certModel.SSLCertificatePath)
if err != nil {
errLog.Push("get cert info", err)
// Get certificate info error, ignore this domain
continue
}
// every week
if time.Now().Sub(cert.NotBefore).Hours()/24 < 7 {
continue
}
}
// after 1 mo, reissue certificate
logChan := make(chan string, 1)
errChan := make(chan error, 1)
// support SAN certification
payload := &ConfigPayload{
ServerName: certModel.Domains,
ChallengeMethod: certModel.ChallengeMethod,
DNSCredentialID: certModel.DnsCredentialID,
}
// logChan and errChan should be closed inside IssueCert
go IssueCert(payload, logChan, errChan)
go handleIssueCertLogChan(logChan)
// block, unless errChan closed
for err := range errChan {
errLog.Push("issue cert", err)
}
logStr := errLog.ToString()
if logStr != "" {
// store error log to db
_ = certModel.Updates(&model.Cert{
Log: errLog.ToString(),
})
} else {
certModel.ClearLog()
}
certModel := certModel
renew(certModel)
}
logger.Info("AutoCert Worker End")
}
func renew(certModel *model.Cert) {
confName := certModel.Filename
log := &Logger{}
log.SetCertModel(certModel)
defer log.Exit()
if len(certModel.Filename) == 0 {
log.Error(errors.New("filename is empty"))
return
}
if len(certModel.Domains) == 0 {
log.Error(errors.New("domains list is empty, " +
"try to reopen auto-cert for this config:" + confName))
return
}
if certModel.SSLCertificatePath != "" {
cert, err := GetCertInfo(certModel.SSLCertificatePath)
if err != nil {
// Get certificate info error, ignore this certificate
log.Error(errors.Wrap(err, "get certificate info error"))
return
}
if time.Now().Sub(cert.NotBefore).Hours()/24 < 7 {
// not between 1 week, ignore this certificate
return
}
}
// after 1 mo, reissue certificate
logChan := make(chan string, 1)
errChan := make(chan error, 1)
// support SAN certification
payload := &ConfigPayload{
ServerName: certModel.Domains,
ChallengeMethod: certModel.ChallengeMethod,
DNSCredentialID: certModel.DnsCredentialID,
}
// errChan will be closed inside IssueCert
go IssueCert(payload, logChan, errChan)
go func() {
for logString := range logChan {
log.Info(strings.TrimSpace(logString))
}
}()
// block, unless errChan closed
for err := range errChan {
log.Error(err)
}
}