Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8b083c9
feat(core): purger
fudiwei Aug 25, 2026
324101b
feat(provider): new purge provider: aliyun cas
fudiwei Aug 27, 2026
1b7cc3c
feat(provider): new purge provider: aliyun clb
fudiwei Aug 27, 2026
009ca34
feat(provider): new purge provider: aliyun clb
fudiwei Aug 27, 2026
b21823a
feat(provider): new purge provider: tencentcloud ssl
fudiwei Aug 27, 2026
6fd5976
feat(provider): new purge provider: tencentcloud gaap
fudiwei Aug 27, 2026
2131ce2
feat(provider): new purge provider: tencentcloud tse
fudiwei Aug 27, 2026
deb6ff7
feat(provider): new purge provider: tencentcloud tse
fudiwei Aug 27, 2026
ab1b499
feat(provider): new purge provider: huaweicloud scm
fudiwei Aug 27, 2026
b21eb17
refactor: clean code
fudiwei Aug 27, 2026
8761234
feat(provider): new purge provider: huaweicloud elb
fudiwei Aug 27, 2026
4d26e4a
feat(provider): new purge provider: huaweicloud elb
fudiwei Aug 27, 2026
4ded078
feat(provider): new purge provider: ucloud ussl
fudiwei Aug 27, 2026
c6e4881
feat(provider): new purge provider: huaweicloud waf
fudiwei Aug 27, 2026
38099a7
feat(provider): new purge provider: baiducloud cert
fudiwei Aug 27, 2026
f0ec7a1
feat(provider): new purge provider: jdcloud ssl
fudiwei Aug 27, 2026
335f57c
feat(provider): new purge provider: volcengine certcenter
fudiwei Aug 27, 2026
dd84e4e
feat(provider): new purge provider: azure keyvault
fudiwei Aug 27, 2026
ded9cad
feat(provider): new purge provider: aws iam
fudiwei Aug 27, 2026
83bb9a7
feat(provider): new purge provider: aws acm
fudiwei Aug 27, 2026
5ab8ce2
feat(provider): add auto prune option for some deployment providers
fudiwei Aug 27, 2026
d4fe0e5
Merge branch 'next' into next
fudiwei Aug 28, 2026
3141a92
Merge branch 'next' into next
usual2970 Aug 28, 2026
f32170a
Merge branch 'next' into next
usual2970 Aug 28, 2026
6419bd4
fix(provider): fix incorrect certificate validity parsing for some pu…
fudiwei Aug 28, 2026
8ec7724
Merge branch 'next' of github.com:fudiwei/certimate into next
fudiwei Aug 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions internal/certacme/client_obtain.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,34 @@ type ObtainCertificateRequest struct {
NoCommonName bool

// 提供商相关
_ struct{}
ChallengeType string
Provider domain.ACMEChallengeProviderType
ProviderAccessConfig map[string]any
ProviderExtendedConfig map[string]any

// 解析相关
_ struct{}
DisableFollowCNAME bool
Nameservers []string

// DNS-01 质询相关
_ struct{}
DnsPropagationWait int
DnsPropagationTimeout int
DnsTTL int

// HTTP-01 质询相关
_ struct{}
HttpDelayWait int

// ACME 相关
_ struct{}
PreferredChain string
ACMEProfile string

// ARI 相关
_ struct{}
DisableARI bool
ARIReplacesAccountUrl string
ARIReplacesCertId string
Expand Down Expand Up @@ -102,7 +108,8 @@ func (c *ACMEClient) ObtainCertificate(ctx context.Context, request *ObtainCerti
opts := &dns01.Options{}
opts.RecursiveNameservers = request.Nameservers
dns01.SetDefaultClient(dns01.NewClient(opts))
c.client.Challenge.SetDNS01Provider(provider,
c.client.Challenge.SetDNS01Provider(
provider,
dns01.CondOptions(
request.DnsPropagationWait > 0,
dns01.PropagationWait(time.Duration(request.DnsPropagationWait)*time.Second, true),
Expand All @@ -129,7 +136,8 @@ func (c *ACMEClient) ObtainCertificate(ctx context.Context, request *ObtainCerti
return nil, fmt.Errorf("failed to initialize http-01 provider '%s': %w", request.Provider, err)
}

c.client.Challenge.SetHTTP01Provider(provider,
c.client.Challenge.SetHTTP01Provider(
provider,
http01.SetDelay(time.Duration(request.HttpDelayWait)*time.Second),
)
}
Expand Down
2 changes: 2 additions & 0 deletions internal/certmgmt/client_deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import (

type DeployCertificateRequest struct {
// 提供商相关
_ struct{}
Provider domain.DeploymentProviderType
ProviderAccessConfig map[string]any
ProviderExtendedConfig map[string]any

// 证书相关
_ struct{}
CertificatePEM string
PrivateKeyPEM string
}
Expand Down
50 changes: 50 additions & 0 deletions internal/certmgmt/client_purge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package certmgmt

import (
"context"
"fmt"
"time"

"github.com/certimate-go/certimate/internal/certmgmt/purgers"
"github.com/certimate-go/certimate/internal/domain"
)

type PurgeCertificateRequest struct {
// 提供商相关
_ struct{}
Provider domain.PurgeProviderType
ProviderAccessConfig map[string]any
ProviderExtendedConfig map[string]any

// 清理相关
_ struct{}
Expiry time.Duration
}

type PurgeCertificateResponse struct{}

func (c *Client) PurgeCertificate(ctx context.Context, request *PurgeCertificateRequest) (*PurgeCertificateResponse, error) {
if request == nil {
return nil, fmt.Errorf("the request is nil")
}

providerFactory, err := purgers.Registries.Get(request.Provider)
if err != nil {
return nil, err
}

provider, err := providerFactory(&purgers.ProviderFactoryOptions{
ProviderAccessConfig: request.ProviderAccessConfig,
ProviderExtendedConfig: request.ProviderExtendedConfig,
})
if err != nil {
return nil, fmt.Errorf("failed to initialize purge provider '%s': %w", request.Provider, err)
}

provider.SetLogger(c.logger)
if _, err := provider.Purge(ctx, request.Expiry); err != nil {
return nil, err
}

return &PurgeCertificateResponse{}, nil
}
1 change: 1 addition & 0 deletions internal/certmgmt/deployers/sp_aliyun_alb.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func init() {
LoadbalancerId: xmaps.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
ListenerId: xmaps.GetString(options.ProviderExtendedConfig, "listenerId"),
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
AutoPrune: xmaps.GetBool(options.ProviderExtendedConfig, "autoPrune"),
})
return provider, err
})
Expand Down
1 change: 1 addition & 0 deletions internal/certmgmt/deployers/sp_aliyun_esa.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func init() {
AccessKeySecret: credentials.AccessKeySecret,
Region: xmaps.GetString(options.ProviderExtendedConfig, "region"),
SiteId: xmaps.GetInt64(options.ProviderExtendedConfig, "siteId"),
AutoPrune: xmaps.GetBool(options.ProviderExtendedConfig, "autoPrune"),
})
return provider, err
})
Expand Down
1 change: 1 addition & 0 deletions internal/certmgmt/deployers/sp_aws_alb.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func init() {
ListenerArn: xmaps.GetString(options.ProviderExtendedConfig, "listenerArn"),
CertificateSource: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "certificateSource", dplyimpl.CERTIFICATE_SOURCE_ACM),
IsDefault: xmaps.GetBool(options.ProviderExtendedConfig, "isDefault"),
AutoPrune: xmaps.GetBool(options.ProviderExtendedConfig, "autoPrune"),
})
return provider, err
})
Expand Down
1 change: 1 addition & 0 deletions internal/certmgmt/deployers/sp_aws_nlb.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func init() {
ListenerArn: xmaps.GetString(options.ProviderExtendedConfig, "listenerArn"),
CertificateSource: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "certificateSource", dplyimpl.CERTIFICATE_SOURCE_ACM),
IsDefault: xmaps.GetBool(options.ProviderExtendedConfig, "isDefault"),
AutoPrune: xmaps.GetBool(options.ProviderExtendedConfig, "autoPrune"),
})
return provider, err
})
Expand Down
1 change: 1 addition & 0 deletions internal/certmgmt/deployers/sp_tencentcloud_ga2.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func init() {
DeployTarget: xmaps.GetString(options.ProviderExtendedConfig, "deployTarget"),
AcceleratorId: xmaps.GetString(options.ProviderExtendedConfig, "acceleratorId"),
ListenerId: xmaps.GetString(options.ProviderExtendedConfig, "listenerId"),
AutoPrune: xmaps.GetBool(options.ProviderExtendedConfig, "autoPrune"),
})
return provider, err
})
Expand Down
1 change: 1 addition & 0 deletions internal/certmgmt/deployers/sp_ucloud_ualb.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func init() {
LoadbalancerId: xmaps.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
ListenerId: xmaps.GetString(options.ProviderExtendedConfig, "listenerId"),
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
AutoPrune: xmaps.GetBool(options.ProviderExtendedConfig, "autoPrune"),
})
return provider, err
})
Expand Down
54 changes: 54 additions & 0 deletions internal/certmgmt/purgers/registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package purgers

import (
"fmt"

"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
)

type ProviderFactoryFunc func(options *ProviderFactoryOptions) (core.Purger, error)

type ProviderFactoryOptions struct {
ProviderAccessConfig map[string]any
ProviderExtendedConfig map[string]any
}

type Registry[T comparable] interface {
Register(T, ProviderFactoryFunc) error
MustRegister(T, ProviderFactoryFunc)
Get(T) (ProviderFactoryFunc, error)
}

type registry[T comparable] struct {
factories map[T]ProviderFactoryFunc
}

func (r *registry[T]) Register(name T, factory ProviderFactoryFunc) error {
if _, exists := r.factories[name]; exists {
return fmt.Errorf("provider '%v' already registered", name)
}

r.factories[name] = factory
return nil
}

func (r *registry[T]) MustRegister(name T, factory ProviderFactoryFunc) {
if err := r.Register(name, factory); err != nil {
panic(err)
}
}

func (r *registry[T]) Get(name T) (ProviderFactoryFunc, error) {
if factory, exists := r.factories[name]; exists {
return factory, nil
}

return nil, fmt.Errorf("provider '%v' not registered", name)
}

func newRegistry[T comparable]() Registry[T] {
return &registry[T]{factories: make(map[T]ProviderFactoryFunc)}
}

var Registries = newRegistry[domain.PurgeProviderType]()
27 changes: 27 additions & 0 deletions internal/certmgmt/purgers/sp_aliyun_cas.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package purgers

import (
"fmt"

"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
prgimpl "github.com/certimate-go/certimate/pkg/core/purger/providers/aliyun-cas"
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
)

func init() {
Registries.MustRegister(domain.PurgeProviderTypeAliyunCAS, func(options *ProviderFactoryOptions) (core.Purger, error) {
credentials := domain.AccessConfigForAliyun{}
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}

provider, err := prgimpl.NewPurger(&prgimpl.PurgerConfig{
AccessKeyId: credentials.AccessKeyId,
AccessKeySecret: credentials.AccessKeySecret,
ResourceGroupId: credentials.ResourceGroupId,
Region: xmaps.GetString(options.ProviderExtendedConfig, "region"),
})
return provider, err
})
}
27 changes: 27 additions & 0 deletions internal/certmgmt/purgers/sp_aliyun_clb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package purgers

import (
"fmt"

"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
prgimpl "github.com/certimate-go/certimate/pkg/core/purger/providers/aliyun-clb"
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
)

func init() {
Registries.MustRegister(domain.PurgeProviderTypeAliyunCLB, func(options *ProviderFactoryOptions) (core.Purger, error) {
credentials := domain.AccessConfigForAliyun{}
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}

provider, err := prgimpl.NewPurger(&prgimpl.PurgerConfig{
AccessKeyId: credentials.AccessKeyId,
AccessKeySecret: credentials.AccessKeySecret,
ResourceGroupId: credentials.ResourceGroupId,
Region: xmaps.GetString(options.ProviderExtendedConfig, "region"),
})
return provider, err
})
}
27 changes: 27 additions & 0 deletions internal/certmgmt/purgers/sp_aliyun_esa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package purgers

import (
"fmt"

"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
prgimpl "github.com/certimate-go/certimate/pkg/core/purger/providers/aliyun-esa"
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
)

func init() {
Registries.MustRegister(domain.PurgeProviderTypeAliyunESA, func(options *ProviderFactoryOptions) (core.Purger, error) {
credentials := domain.AccessConfigForAliyun{}
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}

provider, err := prgimpl.NewPurger(&prgimpl.PurgerConfig{
AccessKeyId: credentials.AccessKeyId,
AccessKeySecret: credentials.AccessKeySecret,
Region: xmaps.GetString(options.ProviderExtendedConfig, "region"),
SiteId: xmaps.GetInt64(options.ProviderExtendedConfig, "siteId"),
})
return provider, err
})
}
27 changes: 27 additions & 0 deletions internal/certmgmt/purgers/sp_aws_acm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package purgers

import (
"fmt"

"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
pgrimpl "github.com/certimate-go/certimate/pkg/core/purger/providers/aws-acm"
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
)

func init() {
Registries.MustRegister(domain.PurgeProviderTypeAWSACM, func(options *ProviderFactoryOptions) (core.Purger, error) {
credentials := domain.AccessConfigForAWS{}
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}

provider, err := pgrimpl.NewPurger(&pgrimpl.PurgerConfig{
AuthMethod: credentials.AuthMethod,
AccessKeyId: credentials.AccessKeyId,
SecretAccessKey: credentials.SecretAccessKey,
Region: xmaps.GetString(options.ProviderExtendedConfig, "region"),
})
return provider, err
})
}
28 changes: 28 additions & 0 deletions internal/certmgmt/purgers/sp_aws_iam.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package purgers

import (
"fmt"

"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
pgrimpl "github.com/certimate-go/certimate/pkg/core/purger/providers/aws-iam"
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
)

func init() {
Registries.MustRegister(domain.PurgeProviderTypeAWSIAM, func(options *ProviderFactoryOptions) (core.Purger, error) {
credentials := domain.AccessConfigForAWS{}
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}

provider, err := pgrimpl.NewPurger(&pgrimpl.PurgerConfig{
AuthMethod: credentials.AuthMethod,
AccessKeyId: credentials.AccessKeyId,
SecretAccessKey: credentials.SecretAccessKey,
Region: xmaps.GetString(options.ProviderExtendedConfig, "region"),
CertificatePath: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "certificatePath", "/"),
})
return provider, err
})
}
28 changes: 28 additions & 0 deletions internal/certmgmt/purgers/sp_azure_keyvault.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package purgers

import (
"fmt"

"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
pgrimpl "github.com/certimate-go/certimate/pkg/core/purger/providers/azure-keyvault"
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
)

func init() {
Registries.MustRegister(domain.PurgeProviderTypeAzureKeyVault, func(options *ProviderFactoryOptions) (core.Purger, error) {
credentials := domain.AccessConfigForAzure{}
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}

provider, err := pgrimpl.NewPurger(&pgrimpl.PurgerConfig{
TenantId: credentials.TenantId,
ClientId: credentials.ClientId,
ClientSecret: credentials.ClientSecret,
CloudName: credentials.CloudName,
KeyVaultName: xmaps.GetString(options.ProviderExtendedConfig, "keyvaultName"),
})
return provider, err
})
}
Loading