mirror of
https://github.com/usual2970/certimate.git
synced 2025-10-04 21:44:54 +00:00
@@ -26,13 +26,14 @@ import (
|
||||
)
|
||||
|
||||
type ApplyResult struct {
|
||||
CSR string
|
||||
FullChainCertificate string
|
||||
IssuerCertificate string
|
||||
PrivateKey string
|
||||
ACMEAccountUrl string
|
||||
ACMECertUrl string
|
||||
ACMECertStableUrl string
|
||||
CSR string
|
||||
ARIReplaced bool
|
||||
}
|
||||
|
||||
type Applicant interface {
|
||||
@@ -109,7 +110,7 @@ func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, err
|
||||
|
||||
certRepo := repository.NewCertificateRepository()
|
||||
lastCertificate, _ := certRepo.GetByWorkflowNodeId(context.Background(), config.Node.Id)
|
||||
if lastCertificate != nil {
|
||||
if lastCertificate != nil && !lastCertificate.ACMERenewed {
|
||||
newCertSan := slices.Clone(options.Domains)
|
||||
oldCertSan := strings.Split(lastCertificate.SubjectAltNames, ";")
|
||||
slices.Sort(newCertSan)
|
||||
@@ -119,8 +120,8 @@ func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, err
|
||||
lastCertX509, _ := certcrypto.ParsePEMCertificate([]byte(lastCertificate.Certificate))
|
||||
if lastCertX509 != nil {
|
||||
replacedARICertId, _ := certificate.MakeARICertID(lastCertX509)
|
||||
options.ReplacedARIAcct = lastCertificate.ACMEAccountUrl
|
||||
options.ReplacedARICert = replacedARICertId
|
||||
options.ARIReplaceAcct = lastCertificate.ACMEAccountUrl
|
||||
options.ARIReplaceCert = replacedARICertId
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,22 +236,24 @@ func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOpt
|
||||
Domains: options.Domains,
|
||||
Bundle: true,
|
||||
}
|
||||
if options.ReplacedARIAcct == user.Registration.URI {
|
||||
certRequest.ReplacesCertID = options.ReplacedARICert
|
||||
if options.ARIReplaceAcct == user.Registration.URI {
|
||||
certRequest.ReplacesCertID = options.ARIReplaceCert
|
||||
}
|
||||
|
||||
certResource, err := client.Certificate.Obtain(certRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ApplyResult{
|
||||
CSR: strings.TrimSpace(string(certResource.CSR)),
|
||||
FullChainCertificate: strings.TrimSpace(string(certResource.Certificate)),
|
||||
IssuerCertificate: strings.TrimSpace(string(certResource.IssuerCertificate)),
|
||||
PrivateKey: strings.TrimSpace(string(certResource.PrivateKey)),
|
||||
ACMEAccountUrl: user.Registration.URI,
|
||||
ACMECertUrl: certResource.CertURL,
|
||||
ACMECertStableUrl: certResource.CertStableURL,
|
||||
CSR: strings.TrimSpace(string(certResource.CSR)),
|
||||
ARIReplaced: certRequest.ReplacesCertID != "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@@ -57,8 +57,8 @@ type applicantProviderOptions struct {
|
||||
DnsPropagationTimeout int32
|
||||
DnsTTL int32
|
||||
DisableFollowCNAME bool
|
||||
ReplacedARIAcct string
|
||||
ReplacedARICert string
|
||||
ARIReplaceAcct string
|
||||
ARIReplaceCert string
|
||||
}
|
||||
|
||||
func createApplicantProvider(options *applicantProviderOptions) (challenge.Provider, error) {
|
||||
|
@@ -28,6 +28,7 @@ type Certificate struct {
|
||||
ACMEAccountUrl string `json:"acmeAccountUrl" db:"acmeAccountUrl"`
|
||||
ACMECertUrl string `json:"acmeCertUrl" db:"acmeCertUrl"`
|
||||
ACMECertStableUrl string `json:"acmeCertStableUrl" db:"acmeCertStableUrl"`
|
||||
ACMERenewed bool `json:"acmeRenewed" db:"acmeRenewed"`
|
||||
WorkflowId string `json:"workflowId" db:"workflowId"`
|
||||
WorkflowNodeId string `json:"workflowNodeId" db:"workflowNodeId"`
|
||||
WorkflowRunId string `json:"workflowRunId" db:"workflowRunId"`
|
||||
|
@@ -55,9 +55,10 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
ApiUrl: config.ApiUrl,
|
||||
ApiVersion: config.ApiVersion,
|
||||
ApiKey: config.ApiKey,
|
||||
ApiUrl: config.ApiUrl,
|
||||
ApiVersion: config.ApiVersion,
|
||||
ApiKey: config.ApiKey,
|
||||
AllowInsecureConnections: config.AllowInsecureConnections,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
|
@@ -2,6 +2,7 @@ package onepanelssl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
@@ -20,6 +21,8 @@ type UploaderConfig struct {
|
||||
ApiVersion string `json:"apiVersion"`
|
||||
// 1Panel 接口密钥。
|
||||
ApiKey string `json:"apiKey"`
|
||||
// 是否允许不安全的连接。
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
}
|
||||
|
||||
type UploaderProvider struct {
|
||||
@@ -35,7 +38,7 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.ApiUrl, config.ApiVersion, config.ApiKey)
|
||||
client, err := createSdkClient(config.ApiUrl, config.ApiVersion, config.ApiKey, config.AllowInsecureConnections)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
@@ -132,7 +135,7 @@ func (u *UploaderProvider) getCertIfExists(ctx context.Context, certPEM string,
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func createSdkClient(apiUrl, apiVersion, apiKey string) (*onepanelsdk.Client, error) {
|
||||
func createSdkClient(apiUrl, apiVersion, apiKey string, skipTlsVerify bool) (*onepanelsdk.Client, error) {
|
||||
if _, err := url.Parse(apiUrl); err != nil {
|
||||
return nil, errors.New("invalid 1panel api url")
|
||||
}
|
||||
@@ -146,5 +149,9 @@ func createSdkClient(apiUrl, apiVersion, apiKey string) (*onepanelsdk.Client, er
|
||||
}
|
||||
|
||||
client := onepanelsdk.NewClient(apiUrl, apiVersion, apiKey)
|
||||
if skipTlsVerify {
|
||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
@@ -77,6 +77,25 @@ func (r *CertificateRepository) GetByWorkflowNodeId(ctx context.Context, workflo
|
||||
return r.castRecordToModel(records[0])
|
||||
}
|
||||
|
||||
func (r *CertificateRepository) GetByWorkflowRunId(ctx context.Context, workflowRunId string) (*domain.Certificate, error) {
|
||||
records, err := app.GetApp().FindRecordsByFilter(
|
||||
domain.CollectionNameCertificate,
|
||||
"workflowRunId={:workflowRunId} && deleted=null",
|
||||
"-created",
|
||||
1, 0,
|
||||
dbx.Params{"workflowRunId": workflowRunId},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
return nil, domain.ErrRecordNotFound
|
||||
}
|
||||
|
||||
return r.castRecordToModel(records[0])
|
||||
}
|
||||
|
||||
func (r *CertificateRepository) Save(ctx context.Context, certificate *domain.Certificate) (*domain.Certificate, error) {
|
||||
collection, err := app.GetApp().FindCollectionByNameOrId(domain.CollectionNameCertificate)
|
||||
if err != nil {
|
||||
@@ -109,6 +128,7 @@ func (r *CertificateRepository) Save(ctx context.Context, certificate *domain.Ce
|
||||
record.Set("acmeAccountUrl", certificate.ACMEAccountUrl)
|
||||
record.Set("acmeCertUrl", certificate.ACMECertUrl)
|
||||
record.Set("acmeCertStableUrl", certificate.ACMECertStableUrl)
|
||||
record.Set("acmeRenewed", certificate.ACMERenewed)
|
||||
record.Set("workflowId", certificate.WorkflowId)
|
||||
record.Set("workflowRunId", certificate.WorkflowRunId)
|
||||
record.Set("workflowNodeId", certificate.WorkflowNodeId)
|
||||
@@ -170,6 +190,7 @@ func (r *CertificateRepository) castRecordToModel(record *core.Record) (*domain.
|
||||
ACMEAccountUrl: record.GetString("acmeAccountUrl"),
|
||||
ACMECertUrl: record.GetString("acmeCertUrl"),
|
||||
ACMECertStableUrl: record.GetString("acmeCertStableUrl"),
|
||||
ACMERenewed: record.GetBool("acmeRenewed"),
|
||||
WorkflowId: record.GetString("workflowId"),
|
||||
WorkflowRunId: record.GetString("workflowRunId"),
|
||||
WorkflowNodeId: record.GetString("workflowNodeId"),
|
||||
|
@@ -96,6 +96,15 @@ func (n *applyNode) Process(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 保存 ARI 记录
|
||||
if applyResult.ARIReplaced {
|
||||
lastCertificate, _ := n.certRepo.GetByWorkflowRunId(ctx, lastOutput.RunId)
|
||||
if lastCertificate != nil {
|
||||
lastCertificate.ACMERenewed = true
|
||||
n.certRepo.Save(ctx, lastCertificate)
|
||||
}
|
||||
}
|
||||
|
||||
n.logger.Info("apply completed")
|
||||
|
||||
return nil
|
||||
@@ -134,7 +143,7 @@ func (n *applyNode) checkCanSkip(ctx context.Context, lastOutput *domain.Workflo
|
||||
return false, "the configuration item 'KeyAlgorithm' changed"
|
||||
}
|
||||
|
||||
lastCertificate, _ := n.certRepo.GetByWorkflowNodeId(ctx, n.node.Id)
|
||||
lastCertificate, _ := n.certRepo.GetByWorkflowRunId(ctx, lastOutput.RunId)
|
||||
if lastCertificate != nil {
|
||||
renewalInterval := time.Duration(currentNodeConfig.SkipBeforeExpiryDays) * time.Hour * 24
|
||||
expirationTime := time.Until(lastCertificate.ExpireAt)
|
||||
|
@@ -34,6 +34,8 @@ func (n *nodeProcessor) SetLogger(logger *slog.Logger) {
|
||||
|
||||
type certificateRepository interface {
|
||||
GetByWorkflowNodeId(ctx context.Context, workflowNodeId string) (*domain.Certificate, error)
|
||||
GetByWorkflowRunId(ctx context.Context, workflowRunId string) (*domain.Certificate, error)
|
||||
Save(ctx context.Context, certificate *domain.Certificate) (*domain.Certificate, error)
|
||||
}
|
||||
|
||||
type workflowOutputRepository interface {
|
||||
|
@@ -83,7 +83,7 @@ func (n *uploadNode) checkCanSkip(ctx context.Context, lastOutput *domain.Workfl
|
||||
return false, "the configuration item 'PrivateKey' changed"
|
||||
}
|
||||
|
||||
lastCertificate, _ := n.certRepo.GetByWorkflowNodeId(ctx, n.node.Id)
|
||||
lastCertificate, _ := n.certRepo.GetByWorkflowRunId(ctx, lastOutput.RunId)
|
||||
if lastCertificate != nil {
|
||||
return true, "the certificate has already been uploaded"
|
||||
}
|
||||
|
Reference in New Issue
Block a user