mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-08 13:39:53 +00:00
127 lines
3.5 KiB
Go
127 lines
3.5 KiB
Go
package nodeprocessor
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/usual2970/certimate/internal/applicant"
|
|
"github.com/usual2970/certimate/internal/domain"
|
|
"github.com/usual2970/certimate/internal/pkg/utils/x509"
|
|
"github.com/usual2970/certimate/internal/repository"
|
|
)
|
|
|
|
type applyNode struct {
|
|
node *domain.WorkflowNode
|
|
outputRepo WorkflowOutputRepository
|
|
*Logger
|
|
}
|
|
|
|
var validityDuration = time.Hour * 24 * 10
|
|
|
|
func NewApplyNode(node *domain.WorkflowNode) *applyNode {
|
|
return &applyNode{
|
|
node: node,
|
|
Logger: NewLogger(node),
|
|
outputRepo: repository.NewWorkflowOutputRepository(),
|
|
}
|
|
}
|
|
|
|
type WorkflowOutputRepository interface {
|
|
// 查询节点输出
|
|
GetByNodeId(ctx context.Context, nodeId string) (*domain.WorkflowOutput, error)
|
|
|
|
// 查询申请节点的证书
|
|
GetCertificateByNodeId(ctx context.Context, nodeId string) (*domain.Certificate, error)
|
|
|
|
// 保存节点输出
|
|
Save(ctx context.Context, output *domain.WorkflowOutput, certificate *domain.Certificate, cb func(id string) error) error
|
|
}
|
|
|
|
// 申请节点根据申请类型执行不同的操作
|
|
func (a *applyNode) Run(ctx context.Context) error {
|
|
a.AddOutput(ctx, a.node.Name, "开始执行")
|
|
// 查询是否申请过,已申请过则直接返回
|
|
// TODO: 先保持和 v0.2 一致,后续增加是否强制申请的参数
|
|
output, err := a.outputRepo.GetByNodeId(ctx, a.node.Id)
|
|
if err != nil && !domain.IsRecordNotFound(err) {
|
|
a.AddOutput(ctx, a.node.Name, "查询申请记录失败", err.Error())
|
|
return err
|
|
}
|
|
|
|
if output != nil && output.Succeeded {
|
|
lastCertificate, _ := a.outputRepo.GetCertificateByNodeId(ctx, a.node.Id)
|
|
if lastCertificate != nil {
|
|
if time.Until(lastCertificate.ExpireAt) > validityDuration {
|
|
a.AddOutput(ctx, a.node.Name, "已申请过证书,且证书在有效期内")
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取Applicant
|
|
applicant, err := applicant.NewWithApplyNode(a.node)
|
|
if err != nil {
|
|
a.AddOutput(ctx, a.node.Name, "获取申请对象失败", err.Error())
|
|
return err
|
|
}
|
|
|
|
// 申请
|
|
applyResult, err := applicant.Apply()
|
|
if err != nil {
|
|
a.AddOutput(ctx, a.node.Name, "申请失败", err.Error())
|
|
return err
|
|
}
|
|
a.AddOutput(ctx, a.node.Name, "申请成功")
|
|
|
|
// 记录申请结果
|
|
// 保持一个节点只有一个输出
|
|
outputId := ""
|
|
if output != nil {
|
|
outputId = output.Id
|
|
}
|
|
output = &domain.WorkflowOutput{
|
|
Meta: domain.Meta{Id: outputId},
|
|
WorkflowId: GetWorkflowId(ctx),
|
|
NodeId: a.node.Id,
|
|
Node: a.node,
|
|
Succeeded: true,
|
|
Outputs: a.node.Outputs,
|
|
}
|
|
|
|
certX509, err := x509.ParseCertificateFromPEM(applyResult.Certificate)
|
|
if err != nil {
|
|
a.AddOutput(ctx, a.node.Name, "解析证书失败", err.Error())
|
|
return err
|
|
}
|
|
|
|
certificate := &domain.Certificate{
|
|
Source: domain.CertificateSourceTypeWorkflow,
|
|
SubjectAltNames: strings.Join(certX509.DNSNames, ";"),
|
|
Certificate: applyResult.Certificate,
|
|
PrivateKey: applyResult.PrivateKey,
|
|
IssuerCertificate: applyResult.IssuerCertificate,
|
|
ACMECertUrl: applyResult.ACMECertUrl,
|
|
ACMECertStableUrl: applyResult.ACMECertStableUrl,
|
|
EffectAt: certX509.NotBefore,
|
|
ExpireAt: certX509.NotAfter,
|
|
WorkflowId: GetWorkflowId(ctx),
|
|
WorkflowNodeId: a.node.Id,
|
|
}
|
|
|
|
if err := a.outputRepo.Save(ctx, output, certificate, func(id string) error {
|
|
if certificate != nil {
|
|
certificate.WorkflowOutputId = id
|
|
}
|
|
|
|
return nil
|
|
}); err != nil {
|
|
a.AddOutput(ctx, a.node.Name, "保存申请记录失败", err.Error())
|
|
return err
|
|
}
|
|
|
|
a.AddOutput(ctx, a.node.Name, "保存申请记录成功")
|
|
|
|
return nil
|
|
}
|