From 99f9aed324c304e1e42b4616aa76a6b418604517 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 20 May 2026 17:34:16 +0800 Subject: [PATCH] feat(provider): support pfx encoder in local/ssh/ftp/s3 deployers --- internal/certificate/service.go | 2 +- internal/certmgmt/deployers/sp_ftp.go | 1 + internal/certmgmt/deployers/sp_local.go | 1 + internal/certmgmt/deployers/sp_s3.go | 1 + internal/certmgmt/deployers/sp_ssh.go | 1 + .../azure-keyvault/azure_keyvault.go | 4 +-- .../providers/baotapanelgo/baotapanelgo.go | 2 +- pkg/core/deployer/providers/ftp/consts.go | 15 ++++++--- pkg/core/deployer/providers/ftp/ftp.go | 11 ++++++- pkg/core/deployer/providers/ftp/ftp_test.go | 8 ++--- pkg/core/deployer/providers/local/consts.go | 7 ++++ pkg/core/deployer/providers/local/local.go | 10 +++++- .../deployer/providers/local/local_test.go | 12 ++++--- .../deployer/providers/local/shared/shared.go | 24 ++++++++++++++ pkg/core/deployer/providers/local/utils.go | 28 ++++++++++++++++ pkg/core/deployer/providers/s3/consts.go | 15 ++++++--- pkg/core/deployer/providers/s3/s3.go | 11 ++++++- pkg/core/deployer/providers/s3/s3_test.go | 32 +++++++++---------- pkg/core/deployer/providers/ssh/consts.go | 15 ++++++--- pkg/core/deployer/providers/ssh/ssh.go | 19 ++++++++--- pkg/core/deployer/providers/ssh/ssh_test.go | 8 ++--- pkg/utils/cert/transformer.go | 11 +++++-- .../BizDeployNodeConfigFieldsProviderFTP.tsx | 22 ++++++++++--- ...BizDeployNodeConfigFieldsProviderLocal.tsx | 22 ++++++++++--- .../BizDeployNodeConfigFieldsProviderS3.tsx | 22 ++++++++++--- .../BizDeployNodeConfigFieldsProviderSSH.tsx | 22 ++++++++++--- .../i18n/resources/en/nls.workflow.nodes.json | 21 ++++++++++-- .../i18n/resources/zh/nls.workflow.nodes.json | 21 ++++++++++-- 28 files changed, 293 insertions(+), 75 deletions(-) create mode 100644 pkg/core/deployer/providers/local/shared/shared.go create mode 100644 pkg/core/deployer/providers/local/utils.go diff --git a/internal/certificate/service.go b/internal/certificate/service.go index 5a2443e0f..8ac828c33 100644 --- a/internal/certificate/service.go +++ b/internal/certificate/service.go @@ -118,7 +118,7 @@ func (s *CertificateService) DownloadCertificate(ctx context.Context, req *dtos. { const pfxPassword = "certimate" - certPFX, err := xcert.TransformCertificateFromPEMToPFX(certificate.Certificate, certificate.PrivateKey, pfxPassword) + certPFX, err := xcert.TransformCertificateFromPEMToPFX(certificate.Certificate, certificate.PrivateKey, pfxPassword, nil) if err != nil { return nil, err } diff --git a/internal/certmgmt/deployers/sp_ftp.go b/internal/certmgmt/deployers/sp_ftp.go index c73f19903..d61a85a60 100644 --- a/internal/certmgmt/deployers/sp_ftp.go +++ b/internal/certmgmt/deployers/sp_ftp.go @@ -27,6 +27,7 @@ func init() { FilePathForCrtOnlyServer: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyServer"), FilePathForCrtOnlyIntermedia: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyIntermedia"), PfxPassword: xmaps.GetString(options.ProviderExtendedConfig, "pfxPassword"), + PfxEncoder: xmaps.GetString(options.ProviderExtendedConfig, "pfxEncoder"), JksAlias: xmaps.GetString(options.ProviderExtendedConfig, "jksAlias"), JksKeypass: xmaps.GetString(options.ProviderExtendedConfig, "jksKeypass"), JksStorepass: xmaps.GetString(options.ProviderExtendedConfig, "jksStorepass"), diff --git a/internal/certmgmt/deployers/sp_local.go b/internal/certmgmt/deployers/sp_local.go index f721eb511..c8fe1cee3 100644 --- a/internal/certmgmt/deployers/sp_local.go +++ b/internal/certmgmt/deployers/sp_local.go @@ -19,6 +19,7 @@ func init() { FilePathForCrtOnlyServer: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyServer"), FilePathForCrtOnlyIntermedia: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyIntermedia"), PfxPassword: xmaps.GetString(options.ProviderExtendedConfig, "pfxPassword"), + PfxEncoder: xmaps.GetString(options.ProviderExtendedConfig, "pfxEncoder"), JksAlias: xmaps.GetString(options.ProviderExtendedConfig, "jksAlias"), JksKeypass: xmaps.GetString(options.ProviderExtendedConfig, "jksKeypass"), JksStorepass: xmaps.GetString(options.ProviderExtendedConfig, "jksStorepass"), diff --git a/internal/certmgmt/deployers/sp_s3.go b/internal/certmgmt/deployers/sp_s3.go index a2494f244..f67118f1d 100644 --- a/internal/certmgmt/deployers/sp_s3.go +++ b/internal/certmgmt/deployers/sp_s3.go @@ -31,6 +31,7 @@ func init() { ObjectKeyForCrtOnlyServer: xmaps.GetString(options.ProviderExtendedConfig, "objectKeyForCrtOnlyServer"), ObjectKeyForCrtOnlyIntermedia: xmaps.GetString(options.ProviderExtendedConfig, "objectKeyForCrtOnlyIntermedia"), PfxPassword: xmaps.GetString(options.ProviderExtendedConfig, "pfxPassword"), + PfxEncoder: xmaps.GetString(options.ProviderExtendedConfig, "pfxEncoder"), JksAlias: xmaps.GetString(options.ProviderExtendedConfig, "jksAlias"), JksKeypass: xmaps.GetString(options.ProviderExtendedConfig, "jksKeypass"), JksStorepass: xmaps.GetString(options.ProviderExtendedConfig, "jksStorepass"), diff --git a/internal/certmgmt/deployers/sp_ssh.go b/internal/certmgmt/deployers/sp_ssh.go index c82500852..c6a3ff90d 100644 --- a/internal/certmgmt/deployers/sp_ssh.go +++ b/internal/certmgmt/deployers/sp_ssh.go @@ -49,6 +49,7 @@ func init() { FilePathForCrtOnlyServer: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyServer"), FilePathForCrtOnlyIntermedia: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyIntermedia"), PfxPassword: xmaps.GetString(options.ProviderExtendedConfig, "pfxPassword"), + PfxEncoder: xmaps.GetString(options.ProviderExtendedConfig, "pfxEncoder"), JksAlias: xmaps.GetString(options.ProviderExtendedConfig, "jksAlias"), JksKeypass: xmaps.GetString(options.ProviderExtendedConfig, "jksKeypass"), JksStorepass: xmaps.GetString(options.ProviderExtendedConfig, "jksStorepass"), diff --git a/pkg/core/certmgr/providers/azure-keyvault/azure_keyvault.go b/pkg/core/certmgr/providers/azure-keyvault/azure_keyvault.go index 2a1572651..3f5fae2a7 100644 --- a/pkg/core/certmgr/providers/azure-keyvault/azure_keyvault.go +++ b/pkg/core/certmgr/providers/azure-keyvault/azure_keyvault.go @@ -136,7 +136,7 @@ func (c *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*cert // Azure Key Vault 不支持导入带有 Certificate Chain 的 PEM 证书。 // Issue Link: https://github.com/Azure/azure-cli/issues/19017 // 暂时的解决方法是,将 PEM 证书转换成 PFX 格式,然后再导入。 - certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, "") + certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, "", nil) if err != nil { return nil, fmt.Errorf("failed to transform certificate from PEM to PFX: %w", err) } @@ -175,7 +175,7 @@ func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, pri } // 转换证书格式 - certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, "") + certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, "", nil) if err != nil { return nil, fmt.Errorf("failed to transform certificate from PEM to PFX: %w", err) } diff --git a/pkg/core/deployer/providers/baotapanelgo/baotapanelgo.go b/pkg/core/deployer/providers/baotapanelgo/baotapanelgo.go index dc15816ef..a7f16395a 100644 --- a/pkg/core/deployer/providers/baotapanelgo/baotapanelgo.go +++ b/pkg/core/deployer/providers/baotapanelgo/baotapanelgo.go @@ -198,7 +198,7 @@ func (d *Deployer) updateSiteCertificate(ctx context.Context, siteType, siteName if pfxRequried { // 转换证书格式 certPFXPassword := "certimate" - certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, certPFXPassword) + certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, certPFXPassword, nil) if err != nil { return fmt.Errorf("failed to transform certificate from PEM to PFX: %w", err) } diff --git a/pkg/core/deployer/providers/ftp/consts.go b/pkg/core/deployer/providers/ftp/consts.go index ba4a439de..bd118dff3 100644 --- a/pkg/core/deployer/providers/ftp/consts.go +++ b/pkg/core/deployer/providers/ftp/consts.go @@ -1,11 +1,18 @@ package ftp import ( - "github.com/certimate-go/certimate/internal/domain" + "github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared" ) const ( - FILE_FORMAT_PEM = string(domain.CertificateFormatTypePEM) - FILE_FORMAT_PFX = string(domain.CertificateFormatTypePFX) - FILE_FORMAT_JKS = string(domain.CertificateFormatTypeJKS) + FILE_FORMAT_PEM = shared.FILE_FORMAT_PEM + FILE_FORMAT_PFX = shared.FILE_FORMAT_PFX + FILE_FORMAT_JKS = shared.FILE_FORMAT_JKS +) + +const ( + PFX_ENCODER_LEGACYRC2 = shared.PFX_ENCODER_LEGACYRC2 + PFX_ENCODER_LEGACYDES = shared.PFX_ENCODER_LEGACYDES + PFX_ENCODER_MODERN2023 = shared.PFX_ENCODER_MODERN2023 + PFX_ENCODER_MODERN2026 = shared.PFX_ENCODER_MODERN2026 ) diff --git a/pkg/core/deployer/providers/ftp/ftp.go b/pkg/core/deployer/providers/ftp/ftp.go index d862f3fd6..8cee82038 100644 --- a/pkg/core/deployer/providers/ftp/ftp.go +++ b/pkg/core/deployer/providers/ftp/ftp.go @@ -8,6 +8,7 @@ import ( "github.com/certimate-go/certimate/internal/tools/ftp" "github.com/certimate-go/certimate/pkg/core/deployer" + shared "github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared" xcert "github.com/certimate-go/certimate/pkg/utils/cert" ) @@ -36,6 +37,9 @@ type DeployerConfig struct { // PFX 导出密码。 // 证书格式为 [FILE_FORMAT_PFX] 时必填。 PfxPassword string `json:"pfxPassword,omitempty"` + // PFX 编码器。 + // 证书格式为 [FILE_FORMAT_PFX] 时可选。 + PfxEncoder string `json:"pfxEncoder,omitempty"` // JKS 别名。 // 证书格式为 [FILE_FORMAT_JKS] 时必填。 JksAlias string `json:"jksAlias,omitempty"` @@ -151,7 +155,12 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*dep return nil, fmt.Errorf("config `pfxPassword` is required") } - pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword) + pfxEncoder, err := shared.ResolvePfxEncoder(d.config.PfxEncoder) + if err != nil { + return nil, fmt.Errorf("config `pfxEncoder` is invalid: %w", err) + } + + pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword, pfxEncoder) if err != nil { return nil, fmt.Errorf("failed to transform certificate to PFX: %w", err) } diff --git a/pkg/core/deployer/providers/ftp/ftp_test.go b/pkg/core/deployer/providers/ftp/ftp_test.go index df56a92a8..2d6eb9069 100644 --- a/pkg/core/deployer/providers/ftp/ftp_test.go +++ b/pkg/core/deployer/providers/ftp/ftp_test.go @@ -26,8 +26,8 @@ func init() { fp.DefineInt64(&fFtpPort, "FTPPORT") fp.DefineString(&fFtpUsername, "FTPUSERNAME") fp.DefineString(&fFtpPassword, "FTPPASSWORD") - fp.DefineString(&fFilePathForCrt, "OUTPUTCERTPATH") - fp.DefineString(&fFilePathForKey, "OUTPUTKEYPATH") + fp.DefineString(&fFilePathForCrt, "FILEPATHFORCRT") + fp.DefineString(&fFilePathForKey, "FILEPATHFORKEY") } /* @@ -40,8 +40,8 @@ Shell command to run this test: --FTP_FTPPORT=21 \ --FTP_FTPUSERNAME="USER" \ --FTP_FTPPASSWORD="PASS" \ - --FTP_OUTPUTCERTPATH="/path/to/your-output-cert.pem" \ - --FTP_OUTPUTKEYPATH="/path/to/your-output-key.pem" + --FTP_FILEPATHFORCRT="/path/to/your-output-cert.pem" \ + --FTP_FILEPATHFORKEY="/path/to/your-output-key.pem" */ func TestProvider(t *testing.T) { fp.Parse() diff --git a/pkg/core/deployer/providers/local/consts.go b/pkg/core/deployer/providers/local/consts.go index d3c3cdae0..1aaf15235 100644 --- a/pkg/core/deployer/providers/local/consts.go +++ b/pkg/core/deployer/providers/local/consts.go @@ -15,3 +15,10 @@ const ( FILE_FORMAT_PFX = string(domain.CertificateFormatTypePFX) FILE_FORMAT_JKS = string(domain.CertificateFormatTypeJKS) ) + +const ( + PFX_ENCODER_LEGACYRC2 = "LegacyRC2" + PFX_ENCODER_LEGACYDES = "LegacyDES" + PFX_ENCODER_MODERN2023 = "Modern2023" + PFX_ENCODER_MODERN2026 = "Modern2026" +) diff --git a/pkg/core/deployer/providers/local/local.go b/pkg/core/deployer/providers/local/local.go index 9052ef99b..1ba1f7301 100644 --- a/pkg/core/deployer/providers/local/local.go +++ b/pkg/core/deployer/providers/local/local.go @@ -37,6 +37,9 @@ type DeployerConfig struct { // PFX 导出密码。 // 证书格式为 [FILE_FORMAT_PFX] 时必填。 PfxPassword string `json:"pfxPassword,omitempty"` + // PFX 编码器。 + // 证书格式为 [FILE_FORMAT_PFX] 时可选。 + PfxEncoder string `json:"pfxEncoder,omitempty"` // JKS 别名。 // 证书格式为 [FILE_FORMAT_JKS] 时必填。 JksAlias string `json:"jksAlias,omitempty"` @@ -139,7 +142,12 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*dep return nil, fmt.Errorf("config `pfxPassword` is required") } - pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword) + pfxEncoder, err := ResolvePfxEncoder(d.config.PfxEncoder) + if err != nil { + return nil, fmt.Errorf("config `pfxEncoder` is invalid: %w", err) + } + + pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword, pfxEncoder) if err != nil { return nil, fmt.Errorf("failed to transform certificate to PFX: %w", err) } diff --git a/pkg/core/deployer/providers/local/local_test.go b/pkg/core/deployer/providers/local/local_test.go index e190985f9..80661dcfd 100644 --- a/pkg/core/deployer/providers/local/local_test.go +++ b/pkg/core/deployer/providers/local/local_test.go @@ -14,6 +14,7 @@ var ( fFilePathForCrt string fFilePathForKey string fPfxPassword string + fPfxEncoder string fJksAlias string fJksKeypass string fJksStorepass string @@ -25,9 +26,10 @@ var ( func init() { fp.DefineString(&fTestCertPath, "TESTCERTPATH") fp.DefineString(&fTestKeyPath, "TESTKEYPATH") - fp.DefineString(&fFilePathForCrt, "OUTPUTCERTPATH") - fp.DefineString(&fFilePathForKey, "OUTPUTKEYPATH") + fp.DefineString(&fFilePathForCrt, "FILEPATHFORCRT") + fp.DefineString(&fFilePathForKey, "FILEPATHFORKEY") fp.DefineString(&fPfxPassword, "PFXPASSWORD") + fp.DefineString(&fPfxEncoder, "PFXENCODER") fp.DefineString(&fJksAlias, "JKSALIAS") fp.DefineString(&fJksKeypass, "JKSKEYPASS") fp.DefineString(&fJksStorepass, "JKSSTOREPASS") @@ -42,9 +44,10 @@ Shell command to run this test: go test -v ./local_test.go -args \ --LOCAL_TESTCERTPATH="/path/to/your-test-cert.pem" \ --LOCAL_TESTKEYPATH="/path/to/your-test-key.pem" \ - --LOCAL_OUTPUTCERTPATH="/path/to/your-output-cert" \ - --LOCAL_OUTPUTKEYPATH="/path/to/your-output-key" \ + --LOCAL_FILEPATHFORCRT="/path/to/your-output-cert" \ + --LOCAL_FILEPATHFORKEY="/path/to/your-output-key" \ --LOCAL_PFXPASSWORD="your-pfx-password" \ + --LOCAL_PFXENCODER="modern2023" \ --LOCAL_JKSALIAS="your-jks-alias" \ --LOCAL_JKSKEYPASS="your-jks-keypass" \ --LOCAL_JKSSTOREPASS="your-jks-storepass" \ @@ -77,6 +80,7 @@ func TestProvider(t *testing.T) { FileFormat: impl.FILE_FORMAT_PFX, FilePathForCrt: fFilePathForCrt + ".pfx", PfxPassword: fPfxPassword, + PfxEncoder: fPfxEncoder, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/pkg/core/deployer/providers/local/shared/shared.go b/pkg/core/deployer/providers/local/shared/shared.go new file mode 100644 index 000000000..e7696ffa8 --- /dev/null +++ b/pkg/core/deployer/providers/local/shared/shared.go @@ -0,0 +1,24 @@ +package shared + +import ( + "software.sslmate.com/src/go-pkcs12" + + "github.com/certimate-go/certimate/pkg/core/deployer/providers/local" +) + +const ( + FILE_FORMAT_PEM = local.FILE_FORMAT_PEM + FILE_FORMAT_PFX = local.FILE_FORMAT_PFX + FILE_FORMAT_JKS = local.FILE_FORMAT_JKS +) + +const ( + PFX_ENCODER_LEGACYRC2 = local.PFX_ENCODER_LEGACYRC2 + PFX_ENCODER_LEGACYDES = local.PFX_ENCODER_LEGACYDES + PFX_ENCODER_MODERN2023 = local.PFX_ENCODER_MODERN2023 + PFX_ENCODER_MODERN2026 = local.PFX_ENCODER_MODERN2026 +) + +func ResolvePfxEncoder(encoderName string) (*pkcs12.Encoder, error) { + return local.ResolvePfxEncoder(encoderName) +} diff --git a/pkg/core/deployer/providers/local/utils.go b/pkg/core/deployer/providers/local/utils.go new file mode 100644 index 000000000..b5dd17a36 --- /dev/null +++ b/pkg/core/deployer/providers/local/utils.go @@ -0,0 +1,28 @@ +package local + +import ( + "fmt" + "strings" + + "software.sslmate.com/src/go-pkcs12" +) + +func ResolvePfxEncoder(encoderName string) (*pkcs12.Encoder, error) { + var encoder *pkcs12.Encoder + + if encoderName != "" { + if strings.EqualFold(encoderName, PFX_ENCODER_LEGACYRC2) { + encoder = pkcs12.LegacyRC2 + } else if strings.EqualFold(encoderName, PFX_ENCODER_LEGACYDES) { + encoder = pkcs12.LegacyDES + } else if strings.EqualFold(encoderName, PFX_ENCODER_MODERN2023) { + encoder = pkcs12.Modern2023 + } else if strings.EqualFold(encoderName, PFX_ENCODER_MODERN2026) { + encoder = pkcs12.Modern2026 + } else { + return nil, fmt.Errorf("unsupported encoder name: '%s'", encoderName) + } + } + + return encoder, nil +} diff --git a/pkg/core/deployer/providers/s3/consts.go b/pkg/core/deployer/providers/s3/consts.go index b9fab2660..1964a9749 100644 --- a/pkg/core/deployer/providers/s3/consts.go +++ b/pkg/core/deployer/providers/s3/consts.go @@ -1,11 +1,18 @@ package s3 import ( - "github.com/certimate-go/certimate/internal/domain" + "github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared" ) const ( - FILE_FORMAT_PEM = string(domain.CertificateFormatTypePEM) - FILE_FORMAT_PFX = string(domain.CertificateFormatTypePFX) - FILE_FORMAT_JKS = string(domain.CertificateFormatTypeJKS) + FILE_FORMAT_PEM = shared.FILE_FORMAT_PEM + FILE_FORMAT_PFX = shared.FILE_FORMAT_PFX + FILE_FORMAT_JKS = shared.FILE_FORMAT_JKS +) + +const ( + PFX_ENCODER_LEGACYRC2 = shared.PFX_ENCODER_LEGACYRC2 + PFX_ENCODER_LEGACYDES = shared.PFX_ENCODER_LEGACYDES + PFX_ENCODER_MODERN2023 = shared.PFX_ENCODER_MODERN2023 + PFX_ENCODER_MODERN2026 = shared.PFX_ENCODER_MODERN2026 ) diff --git a/pkg/core/deployer/providers/s3/s3.go b/pkg/core/deployer/providers/s3/s3.go index d35ab58e8..092a42e96 100644 --- a/pkg/core/deployer/providers/s3/s3.go +++ b/pkg/core/deployer/providers/s3/s3.go @@ -7,6 +7,7 @@ import ( "github.com/certimate-go/certimate/internal/tools/s3" "github.com/certimate-go/certimate/pkg/core/deployer" + "github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared" xcert "github.com/certimate-go/certimate/pkg/utils/cert" ) @@ -44,6 +45,9 @@ type DeployerConfig struct { // PFX 导出密码。 // 证书格式为 [FILE_FORMAT_PFX] 时必填。 PfxPassword string `json:"pfxPassword,omitempty"` + // PFX 编码器。 + // 证书格式为 [FILE_FORMAT_PFX] 时可选。 + PfxEncoder string `json:"pfxEncoder,omitempty"` // JKS 别名。 // 证书格式为 [FILE_FORMAT_JKS] 时必填。 JksAlias string `json:"jksAlias,omitempty"` @@ -133,7 +137,12 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*dep return nil, fmt.Errorf("config `pfxPassword` is required") } - pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword) + pfxEncoder, err := shared.ResolvePfxEncoder(d.config.PfxEncoder) + if err != nil { + return nil, fmt.Errorf("config `pfxEncoder` is invalid: %w", err) + } + + pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword, pfxEncoder) if err != nil { return nil, fmt.Errorf("failed to transform certificate to PFX: %w", err) } diff --git a/pkg/core/deployer/providers/s3/s3_test.go b/pkg/core/deployer/providers/s3/s3_test.go index 3a43a6623..0158b4712 100644 --- a/pkg/core/deployer/providers/s3/s3_test.go +++ b/pkg/core/deployer/providers/s3/s3_test.go @@ -8,16 +8,16 @@ import ( ) var ( - fp = tester.Args("S3_") - fTestCertPath string - fTestKeyPath string - fSshHost string - fAccessKey string - fSecretKey string - fRegion string - fBucket string - fFilePathForCrt string - fFilePathForKey string + fp = tester.Args("S3_") + fTestCertPath string + fTestKeyPath string + fSshHost string + fAccessKey string + fSecretKey string + fRegion string + fBucket string + fObjectKeyForCrt string + fObjectKeyForKey string ) func init() { @@ -28,8 +28,8 @@ func init() { fp.DefineString(&fSecretKey, "SECRETKEY") fp.DefineString(&fRegion, "REGION") fp.DefineString(&fBucket, "BUCKET") - fp.DefineString(&fFilePathForCrt, "OUTPUTCERTPATH") - fp.DefineString(&fFilePathForKey, "OUTPUTKEYPATH") + fp.DefineString(&fObjectKeyForCrt, "OBJECTKEYFORCRT") + fp.DefineString(&fObjectKeyForKey, "OBJECTKEYFORKEY") } /* @@ -43,8 +43,8 @@ Shell command to run this test: --S3_SECRETKEY="your-secret-key" \ --S3_REGION="your-region" \ --S3_BUCKET="your-bucket" \ - --S3_OUTPUTCERTPATH="/path/to/your-output-cert.pem" \ - --S3_OUTPUTKEYPATH="/path/to/your-output-key.pem" + --S3_OBJECTKEYFORCRT="/path/to/your-output-cert.pem" \ + --S3_OBJECTKEYFORKEY="/path/to/your-output-key.pem" */ func TestProvider(t *testing.T) { fp.Parse() @@ -57,8 +57,8 @@ func TestProvider(t *testing.T) { Region: fRegion, Bucket: fBucket, FileFormat: impl.FILE_FORMAT_PEM, - ObjectKeyForCrt: fFilePathForCrt + ".pem", - ObjectKeyForKey: fFilePathForKey + ".pem", + ObjectKeyForCrt: fObjectKeyForCrt + ".pem", + ObjectKeyForKey: fObjectKeyForKey + ".pem", }) if err != nil { t.Errorf("err: %+v", err) diff --git a/pkg/core/deployer/providers/ssh/consts.go b/pkg/core/deployer/providers/ssh/consts.go index 468e9d56a..089f54fca 100644 --- a/pkg/core/deployer/providers/ssh/consts.go +++ b/pkg/core/deployer/providers/ssh/consts.go @@ -1,11 +1,18 @@ package ssh import ( - "github.com/certimate-go/certimate/internal/domain" + "github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared" ) const ( - FILE_FORMAT_PEM = string(domain.CertificateFormatTypePEM) - FILE_FORMAT_PFX = string(domain.CertificateFormatTypePFX) - FILE_FORMAT_JKS = string(domain.CertificateFormatTypeJKS) + FILE_FORMAT_PEM = shared.FILE_FORMAT_PEM + FILE_FORMAT_PFX = shared.FILE_FORMAT_PFX + FILE_FORMAT_JKS = shared.FILE_FORMAT_JKS +) + +const ( + PFX_ENCODER_LEGACYRC2 = shared.PFX_ENCODER_LEGACYRC2 + PFX_ENCODER_LEGACYDES = shared.PFX_ENCODER_LEGACYDES + PFX_ENCODER_MODERN2023 = shared.PFX_ENCODER_MODERN2023 + PFX_ENCODER_MODERN2026 = shared.PFX_ENCODER_MODERN2026 ) diff --git a/pkg/core/deployer/providers/ssh/ssh.go b/pkg/core/deployer/providers/ssh/ssh.go index ffa8cf30b..b12c551b5 100644 --- a/pkg/core/deployer/providers/ssh/ssh.go +++ b/pkg/core/deployer/providers/ssh/ssh.go @@ -8,6 +8,7 @@ import ( "github.com/certimate-go/certimate/internal/tools/ssh" "github.com/certimate-go/certimate/pkg/core/deployer" + "github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared" xcert "github.com/certimate-go/certimate/pkg/utils/cert" xssh "github.com/certimate-go/certimate/pkg/utils/ssh" ) @@ -59,6 +60,9 @@ type DeployerConfig struct { // PFX 导出密码。 // 证书格式为 [FILE_FORMAT_PFX] 时必填。 PfxPassword string `json:"pfxPassword,omitempty"` + // PFX 编码器。 + // 证书格式为 [FILE_FORMAT_PFX] 时可选。 + PfxEncoder string `json:"pfxEncoder,omitempty"` // JKS 别名。 // 证书格式为 [FILE_FORMAT_JKS] 时必填。 JksAlias string `json:"jksAlias,omitempty"` @@ -134,10 +138,6 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*dep switch d.config.FileFormat { case FILE_FORMAT_PEM: { - if d.config.PfxPassword == "" { - return nil, fmt.Errorf("config `pfxPassword` is required") - } - if d.config.FilePathForKey != "" { if err := xssh.WriteRemoteString(sshClient.RawClient(), d.config.FilePathForKey, privkeyPEM, d.config.UseSCP); err != nil { return nil, fmt.Errorf("failed to upload private key file: %w", err) @@ -169,7 +169,16 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*dep case FILE_FORMAT_PFX: { - pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword) + if d.config.PfxPassword == "" { + return nil, fmt.Errorf("config `pfxPassword` is required") + } + + pfxEncoder, err := shared.ResolvePfxEncoder(d.config.PfxEncoder) + if err != nil { + return nil, fmt.Errorf("config `pfxEncoder` is invalid: %w", err) + } + + pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword, pfxEncoder) if err != nil { return nil, fmt.Errorf("failed to transform certificate to PFX: %w", err) } diff --git a/pkg/core/deployer/providers/ssh/ssh_test.go b/pkg/core/deployer/providers/ssh/ssh_test.go index 4123b73e9..0d58b20ce 100644 --- a/pkg/core/deployer/providers/ssh/ssh_test.go +++ b/pkg/core/deployer/providers/ssh/ssh_test.go @@ -26,8 +26,8 @@ func init() { fp.DefineInt64(&fSshPort, "SSHPORT") fp.DefineString(&fSshUsername, "SSHUSERNAME") fp.DefineString(&fSshPassword, "SSHPASSWORD") - fp.DefineString(&fFilePathForCrt, "OUTPUTCERTPATH") - fp.DefineString(&fFilePathForKey, "OUTPUTKEYPATH") + fp.DefineString(&fFilePathForCrt, "FILEPATHFORCRT") + fp.DefineString(&fFilePathForKey, "FILEPATHFORKEY") } /* @@ -40,8 +40,8 @@ Shell command to run this test: --SSH_SSHPORT=22 \ --SSH_SSHUSERNAME="root" \ --SSH_SSHPASSWORD="password" \ - --SSH_OUTPUTCERTPATH="/path/to/your-output-cert.pem" \ - --SSH_OUTPUTKEYPATH="/path/to/your-output-key.pem" + --SSH_FILEPATHFORCRT="/path/to/your-output-cert.pem" \ + --SSH_FILEPATHFORKEY="/path/to/your-output-key.pem" */ func TestProvider(t *testing.T) { fp.Parse() diff --git a/pkg/utils/cert/transformer.go b/pkg/utils/cert/transformer.go index 1b93e8138..86fb273fe 100644 --- a/pkg/utils/cert/transformer.go +++ b/pkg/utils/cert/transformer.go @@ -20,7 +20,7 @@ import ( // 出参: // - data: PFX 格式的证书数据。 // - err: 错误。 -func TransformCertificateFromPEMToPFX(certPEM string, privkeyPEM string, pfxPassword string) ([]byte, error) { +func TransformCertificateFromPEMToPFX(certPEM string, privkeyPEM string, pfxPassword string, pfxEncoder *pkcs12.Encoder) ([]byte, error) { blocks := decodePEMBlocks([]byte(certPEM)) certs := make([]*x509.Certificate, 0, len(blocks)) @@ -41,13 +41,18 @@ func TransformCertificateFromPEMToPFX(certPEM string, privkeyPEM string, pfxPass return nil, err } + encoder := pfxEncoder + if encoder == nil { + encoder = pkcs12.Legacy + } + var pfxData []byte if len(certs) == 0 { return nil, fmt.Errorf("failed to decode certificate PEM") } else if len(certs) == 1 { - pfxData, err = pkcs12.Legacy.Encode(privkey, certs[0], nil, pfxPassword) + pfxData, err = encoder.Encode(privkey, certs[0], nil, pfxPassword) } else { - pfxData, err = pkcs12.Legacy.Encode(privkey, certs[0], certs[1:], pfxPassword) + pfxData, err = encoder.Encode(privkey, certs[0], certs[1:], pfxPassword) } return pfxData, err diff --git a/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProviderFTP.tsx b/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProviderFTP.tsx index 5718438d5..4fc56b21c 100644 --- a/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProviderFTP.tsx +++ b/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProviderFTP.tsx @@ -98,10 +98,7 @@ const BizDeployNodeConfigFieldsProviderFTP = () => { - } - > + @@ -113,6 +110,22 @@ const BizDeployNodeConfigFieldsProviderFTP = () => { + + + @@ -358,6 +355,22 @@ const BizDeployNodeConfigFieldsProviderLocal = () => { + + + @@ -129,6 +126,22 @@ const BizDeployNodeConfigFieldsProviderS3 = () => { + + + @@ -324,6 +321,22 @@ const BizDeployNodeConfigFieldsProviderSSH = () => { + + +