mirror of
https://github.com/woodchen-ink/certimate.git
synced 2025-07-18 17:31:55 +08:00
refactor: clean code
This commit is contained in:
parent
034bb71b10
commit
2d17501072
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -22,7 +23,7 @@ import (
|
||||
"github.com/usual2970/certimate/internal/repository"
|
||||
)
|
||||
|
||||
type ApplyCertResult struct {
|
||||
type ApplyResult struct {
|
||||
CertificateFullChain string
|
||||
IssuerCertificate string
|
||||
PrivateKey string
|
||||
@ -33,34 +34,24 @@ type ApplyCertResult struct {
|
||||
}
|
||||
|
||||
type Applicant interface {
|
||||
Apply() (*ApplyCertResult, error)
|
||||
Apply(ctx context.Context) (*ApplyResult, error)
|
||||
}
|
||||
|
||||
type applicantOptions struct {
|
||||
Domains []string
|
||||
ContactEmail string
|
||||
Provider domain.ApplyDNSProviderType
|
||||
ProviderAccessConfig map[string]any
|
||||
ProviderExtendedConfig map[string]any
|
||||
CAProvider domain.ApplyCAProviderType
|
||||
CAProviderAccessConfig map[string]any
|
||||
CAProviderExtendedConfig map[string]any
|
||||
KeyAlgorithm string
|
||||
Nameservers []string
|
||||
DnsPropagationTimeout int32
|
||||
DnsTTL int32
|
||||
DisableFollowCNAME bool
|
||||
ReplacedARIAcct string
|
||||
ReplacedARICert string
|
||||
type ApplicantWithWorkflowNodeConfig struct {
|
||||
Node *domain.WorkflowNode
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
||||
if node.Type != domain.WorkflowNodeTypeApply {
|
||||
func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, error) {
|
||||
if config.Node == nil {
|
||||
return nil, fmt.Errorf("node is nil")
|
||||
}
|
||||
if config.Node.Type != domain.WorkflowNodeTypeApply {
|
||||
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeApply))
|
||||
}
|
||||
|
||||
nodeConfig := node.GetConfigForApply()
|
||||
options := &applicantOptions{
|
||||
nodeConfig := config.Node.GetConfigForApply()
|
||||
options := &applicantProviderOptions{
|
||||
Domains: sliceutil.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }),
|
||||
ContactEmail: nodeConfig.ContactEmail,
|
||||
Provider: domain.ApplyDNSProviderType(nodeConfig.Provider),
|
||||
@ -113,7 +104,7 @@ func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
||||
}
|
||||
|
||||
certRepo := repository.NewCertificateRepository()
|
||||
lastCertificate, _ := certRepo.GetByWorkflowNodeId(context.Background(), node.Id)
|
||||
lastCertificate, _ := certRepo.GetByWorkflowNodeId(context.Background(), config.Node.Id)
|
||||
if lastCertificate != nil {
|
||||
newCertSan := slices.Clone(options.Domains)
|
||||
oldCertSan := strings.Split(lastCertificate.SubjectAltNames, ";")
|
||||
@ -130,18 +121,46 @@ func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
||||
}
|
||||
}
|
||||
|
||||
applicant, err := createApplicant(options)
|
||||
applicant, err := createApplicantProvider(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &proxyApplicant{
|
||||
return &applicantImpl{
|
||||
applicant: applicant,
|
||||
options: options,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func apply(challengeProvider challenge.Provider, options *applicantOptions) (*ApplyCertResult, error) {
|
||||
type applicantImpl struct {
|
||||
applicant challenge.Provider
|
||||
options *applicantProviderOptions
|
||||
}
|
||||
|
||||
var _ Applicant = (*applicantImpl)(nil)
|
||||
|
||||
func (d *applicantImpl) Apply(ctx context.Context) (*ApplyResult, error) {
|
||||
limiter := getLimiter(fmt.Sprintf("apply_%s", d.options.ContactEmail))
|
||||
if err := limiter.Wait(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return applyUseLego(d.applicant, d.options)
|
||||
}
|
||||
|
||||
const (
|
||||
limitBurst = 300
|
||||
limitRate float64 = float64(1) / float64(36)
|
||||
)
|
||||
|
||||
var limiters sync.Map
|
||||
|
||||
func getLimiter(key string) *rate.Limiter {
|
||||
limiter, _ := limiters.LoadOrStore(key, rate.NewLimiter(rate.Limit(limitRate), 300))
|
||||
return limiter.(*rate.Limiter)
|
||||
}
|
||||
|
||||
func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOptions) (*ApplyResult, error) {
|
||||
user, err := newAcmeUser(string(options.CAProvider), options.ContactEmail)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -153,7 +172,7 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
|
||||
|
||||
// Create an ACME client config
|
||||
config := lego.NewConfig(user)
|
||||
config.Certificate.KeyType = parseKeyAlgorithm(domain.CertificateKeyAlgorithmType(options.KeyAlgorithm))
|
||||
config.Certificate.KeyType = parseLegoKeyAlgorithm(domain.CertificateKeyAlgorithmType(options.KeyAlgorithm))
|
||||
config.CADirURL = sslProviderUrls[user.CA]
|
||||
if user.CA == sslProviderSSLCom {
|
||||
if strings.HasPrefix(options.KeyAlgorithm, "RSA") {
|
||||
@ -175,7 +194,7 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
|
||||
challengeOptions = append(challengeOptions, dns01.AddRecursiveNameservers(dns01.ParseNameservers(options.Nameservers)))
|
||||
challengeOptions = append(challengeOptions, dns01.DisableAuthoritativeNssPropagationRequirement())
|
||||
}
|
||||
client.Challenge.SetDNS01Provider(challengeProvider, challengeOptions...)
|
||||
client.Challenge.SetDNS01Provider(legoProvider, challengeOptions...)
|
||||
|
||||
// New users need to register first
|
||||
if !user.hasRegistration() {
|
||||
@ -199,7 +218,7 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ApplyCertResult{
|
||||
return &ApplyResult{
|
||||
CertificateFullChain: strings.TrimSpace(string(certResource.Certificate)),
|
||||
IssuerCertificate: strings.TrimSpace(string(certResource.IssuerCertificate)),
|
||||
PrivateKey: strings.TrimSpace(string(certResource.PrivateKey)),
|
||||
@ -210,47 +229,20 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseKeyAlgorithm(algo domain.CertificateKeyAlgorithmType) certcrypto.KeyType {
|
||||
switch algo {
|
||||
case domain.CertificateKeyAlgorithmTypeRSA2048:
|
||||
return certcrypto.RSA2048
|
||||
case domain.CertificateKeyAlgorithmTypeRSA3072:
|
||||
return certcrypto.RSA3072
|
||||
case domain.CertificateKeyAlgorithmTypeRSA4096:
|
||||
return certcrypto.RSA4096
|
||||
case domain.CertificateKeyAlgorithmTypeRSA8192:
|
||||
return certcrypto.RSA8192
|
||||
case domain.CertificateKeyAlgorithmTypeEC256:
|
||||
return certcrypto.EC256
|
||||
case domain.CertificateKeyAlgorithmTypeEC384:
|
||||
return certcrypto.EC384
|
||||
case domain.CertificateKeyAlgorithmTypeEC512:
|
||||
return certcrypto.KeyType("P512")
|
||||
func parseLegoKeyAlgorithm(algo domain.CertificateKeyAlgorithmType) certcrypto.KeyType {
|
||||
alogMap := map[domain.CertificateKeyAlgorithmType]certcrypto.KeyType{
|
||||
domain.CertificateKeyAlgorithmTypeRSA2048: certcrypto.RSA2048,
|
||||
domain.CertificateKeyAlgorithmTypeRSA3072: certcrypto.RSA3072,
|
||||
domain.CertificateKeyAlgorithmTypeRSA4096: certcrypto.RSA4096,
|
||||
domain.CertificateKeyAlgorithmTypeRSA8192: certcrypto.RSA8192,
|
||||
domain.CertificateKeyAlgorithmTypeEC256: certcrypto.EC256,
|
||||
domain.CertificateKeyAlgorithmTypeEC384: certcrypto.EC384,
|
||||
domain.CertificateKeyAlgorithmTypeEC512: certcrypto.KeyType("P512"),
|
||||
}
|
||||
|
||||
if keyType, ok := alogMap[algo]; ok {
|
||||
return keyType
|
||||
}
|
||||
|
||||
return certcrypto.RSA2048
|
||||
}
|
||||
|
||||
// TODO: 暂时使用代理模式以兼容之前版本代码,后续重新实现此处逻辑
|
||||
type proxyApplicant struct {
|
||||
applicant challenge.Provider
|
||||
options *applicantOptions
|
||||
}
|
||||
|
||||
var limiters sync.Map
|
||||
|
||||
const (
|
||||
limitBurst = 300
|
||||
limitRate float64 = float64(1) / float64(36)
|
||||
)
|
||||
|
||||
func getLimiter(key string) *rate.Limiter {
|
||||
limiter, _ := limiters.LoadOrStore(key, rate.NewLimiter(rate.Limit(limitRate), 300))
|
||||
return limiter.(*rate.Limiter)
|
||||
}
|
||||
|
||||
func (d *proxyApplicant) Apply() (*ApplyCertResult, error) {
|
||||
limiter := getLimiter(fmt.Sprintf("apply_%s", d.options.ContactEmail))
|
||||
limiter.Wait(context.Background())
|
||||
return apply(d.applicant, d.options)
|
||||
}
|
||||
|
@ -38,7 +38,25 @@ import (
|
||||
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
|
||||
)
|
||||
|
||||
func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
type applicantProviderOptions struct {
|
||||
Domains []string
|
||||
ContactEmail string
|
||||
Provider domain.ApplyDNSProviderType
|
||||
ProviderAccessConfig map[string]any
|
||||
ProviderExtendedConfig map[string]any
|
||||
CAProvider domain.ApplyCAProviderType
|
||||
CAProviderAccessConfig map[string]any
|
||||
CAProviderExtendedConfig map[string]any
|
||||
KeyAlgorithm string
|
||||
Nameservers []string
|
||||
DnsPropagationTimeout int32
|
||||
DnsTTL int32
|
||||
DisableFollowCNAME bool
|
||||
ReplacedARIAcct string
|
||||
ReplacedARICert string
|
||||
}
|
||||
|
||||
func createApplicantProvider(options *applicantProviderOptions) (challenge.Provider, error) {
|
||||
/*
|
||||
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||
NOTICE: If you add new constant, please keep ASCII order.
|
||||
|
@ -11,28 +11,26 @@ import (
|
||||
)
|
||||
|
||||
type Deployer interface {
|
||||
SetLogger(*slog.Logger)
|
||||
|
||||
Deploy(ctx context.Context) error
|
||||
}
|
||||
|
||||
type deployerOptions struct {
|
||||
Provider domain.DeployProviderType
|
||||
ProviderAccessConfig map[string]any
|
||||
ProviderDeployConfig map[string]any
|
||||
type DeployerWithWorkflowNodeConfig struct {
|
||||
Node *domain.WorkflowNode
|
||||
Logger *slog.Logger
|
||||
CertificatePEM string
|
||||
PrivateKeyPEM string
|
||||
}
|
||||
|
||||
func NewWithDeployNode(node *domain.WorkflowNode, certdata struct {
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
},
|
||||
) (Deployer, error) {
|
||||
if node.Type != domain.WorkflowNodeTypeDeploy {
|
||||
func NewWithWorkflowNode(config DeployerWithWorkflowNodeConfig) (Deployer, error) {
|
||||
if config.Node == nil {
|
||||
return nil, fmt.Errorf("node is nil")
|
||||
}
|
||||
if config.Node.Type != domain.WorkflowNodeTypeDeploy {
|
||||
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeDeploy))
|
||||
}
|
||||
|
||||
nodeConfig := node.GetConfigForDeploy()
|
||||
options := &deployerOptions{
|
||||
nodeConfig := config.Node.GetConfigForDeploy()
|
||||
options := &deployerProviderOptions{
|
||||
Provider: domain.DeployProviderType(nodeConfig.Provider),
|
||||
ProviderAccessConfig: make(map[string]any),
|
||||
ProviderDeployConfig: nodeConfig.ProviderConfig,
|
||||
@ -48,34 +46,27 @@ func NewWithDeployNode(node *domain.WorkflowNode, certdata struct {
|
||||
}
|
||||
}
|
||||
|
||||
deployer, err := createDeployer(options)
|
||||
deployerProvider, err := createDeployerProvider(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &proxyDeployer{
|
||||
deployer: deployer,
|
||||
deployCertificate: certdata.Certificate,
|
||||
deployPrivateKey: certdata.PrivateKey,
|
||||
return &deployerImpl{
|
||||
provider: deployerProvider.WithLogger(config.Logger),
|
||||
certPEM: config.CertificatePEM,
|
||||
privkeyPEM: config.PrivateKeyPEM,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TODO: 暂时使用代理模式以兼容之前版本代码,后续重新实现此处逻辑
|
||||
type proxyDeployer struct {
|
||||
deployer deployer.Deployer
|
||||
deployCertificate string
|
||||
deployPrivateKey string
|
||||
type deployerImpl struct {
|
||||
provider deployer.Deployer
|
||||
certPEM string
|
||||
privkeyPEM string
|
||||
}
|
||||
|
||||
func (d *proxyDeployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
panic("logger is nil")
|
||||
}
|
||||
var _ Deployer = (*deployerImpl)(nil)
|
||||
|
||||
d.deployer.WithLogger(logger)
|
||||
}
|
||||
|
||||
func (d *proxyDeployer) Deploy(ctx context.Context) error {
|
||||
_, err := d.deployer.Deploy(ctx, d.deployCertificate, d.deployPrivateKey)
|
||||
func (d *deployerImpl) Deploy(ctx context.Context) error {
|
||||
_, err := d.provider.Deploy(ctx, d.certPEM, d.privkeyPEM)
|
||||
return err
|
||||
}
|
||||
|
@ -82,7 +82,13 @@ import (
|
||||
sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
|
||||
)
|
||||
|
||||
func createDeployer(options *deployerOptions) (deployer.Deployer, error) {
|
||||
type deployerProviderOptions struct {
|
||||
Provider domain.DeployProviderType
|
||||
ProviderAccessConfig map[string]any
|
||||
ProviderDeployConfig map[string]any
|
||||
}
|
||||
|
||||
func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer, error) {
|
||||
/*
|
||||
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||
NOTICE: If you add new constant, please keep ASCII order.
|
||||
|
Loading…
x
Reference in New Issue
Block a user