From cef9612526445bb22eaae779a75048ca8b4ecf23 Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Mon, 27 Apr 2026 11:56:41 +0800 Subject: [PATCH] f --- config.yaml | 16 +++- configs/env.production.yaml | 11 +-- .../certification_application_service_impl.go | 39 ++++---- internal/config/config.go | 19 ++-- internal/container/container.go | 17 ++-- internal/shared/esign/signflow_service.go | 82 +++++++++-------- internal/shared/esign/types.go | 1 + internal/shared/payment/alipay.go | 44 +++++++--- .../alipay_cert/alipayCertPublicKey_RSA2.crt | 43 +++++++++ resources/etc/alipay_cert/alipayRootCert.crt | 88 +++++++++++++++++++ .../appCertPublicKey_2021006150638319.crt | 24 +++++ 11 files changed, 298 insertions(+), 86 deletions(-) create mode 100644 resources/etc/alipay_cert/alipayCertPublicKey_RSA2.crt create mode 100644 resources/etc/alipay_cert/alipayRootCert.crt create mode 100644 resources/etc/alipay_cert/appCertPublicKey_2021006150638319.crt diff --git a/config.yaml b/config.yaml index 47e5497..e1d6eee 100644 --- a/config.yaml +++ b/config.yaml @@ -267,12 +267,12 @@ wechat_work: # 📝 e签宝服务配置 # =========================================== esign: - app_id: "7439073138" - app_secret: "d76e27fdd169b391e09262a0959dac5c" + app_id: "5112059455" + app_secret: "cacdb6cfca94b74c86bcea277a978884" server_url: "https://smlopenapi.esign.cn" - template_id: "9f7a3f63cc5a48b085b127ba027d234d" + template_id: "d8f5db99506f4dab893f629cb1e82497" contract: - name: "海宇数据API合作协议" + name: "海宇数据-合作协议" expire_days: 7 retry_count: 3 auth: @@ -384,6 +384,14 @@ yushan: # 💰 支付宝支付配置 # =========================================== alipay: + mode: "cert" # key=密钥模式,cert=证书模式 + app_id: "2021006150638319" + private_key: "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCTMiY8fgrW60Mr6NI82Kn6mm3oubEvrYtZ7kADiL/maeh5tzHb0NdtRIElprGQQ7sQhoXgFoDndJ9Ipk1NwVmA/9e0nuPmyEw935KTbFono6pRFBw7+k3bPRFDCbiE1BvsBa7mwJE9H/rV5ry/6H84b49pwC74La7WJhMhRXJVMeapqNyeZ7VgBf/LQ99/Bd0uMdRmcv678qO88E1FKIxtpD0ZVtCmmipzXSf4Wsyq0unoiwHz5fhWlOC+STByUGuuoVMdUKlzNaBQoVMKm4mn96OKFpf5ulLOQNg80XVFy0eq2MJzur0HLWcfMEEMARQ7lXjaS5JZ1RLGe6ki8EyvAgMBAAECggEABvCsYNnIhQ2eoyldEEVe7lPtrrVip07VbS4QkpoWAjUoIuUCUszr+1jphe7wHE81OLg/A6vL9B3JjNFaf7oIEE7/yqJbOHxlK92ouY64SXosA5qhIirRFO8yKykALDMcBerWrkaSEoG5f/BbIelCZlTMPD41eLoerjYpXL47f8zCDH2NLT98mMHKtcjif8VbeKSUsw80HxMlu0w9KSrk+LDFTrqOUC8QeBfSvNOWsIY/TXOkP+fHRtUSPimKv1m4bsILFu/05hLZK66/p+hdQHH+gIxKCl8qgvAfAE0BE1uZRD5Rx1myc2R2ltIFweM1Pk2yn2Ays24zY9e3RvvNoQKBgQDeLXG8Q2vj5lUF9SNMiseNiU7QaFzYJANAFS5Q/E37sy9x7HAty7/cYoCEOwzzRCi/s/wuS09QwYIWRbSEdWWKbw6zQ8GvFIQTav5tMpQxcduDJ3LwoQsWoJJw1P3CzNV67aDqOyBTHaJOr05RZ7CWdmuabYs6P8wAhNr76eFGJwKBgQCpmpIe9q7IV4aaGW7stPWiKRuShU1lNBTFDCv+KAqbCS7exNrzfMoDPb3AWdwOahETh6izOD6SfQTIi9G8+w5bU5UfWrbsnVj3Os+GWUUNlMjeZLpOJbdH7yla8YULFvpjNDjWQpaeg2YllhuM5QWAywz2B8ZNhyd9yhHBDGWiOQKBgHzVfd0w6LMBXO5fATlllKAS8USqDtimy2i7Pe3lBZAR6uuQ1Kr2m1OhyOIDJ9CbkGW+JEiCqgsO3x/ShI4URDxXECRrQq0z0s3yRQhn7domRhdYF/3aDpflGsLo+bf1TVGnqM1S8WOh9+tMFq4om5C+8tCvEhZleCMmgsAediPrAoGANwbWZ8NjW87B9hdQXO4tT8qEjpo/TRmDr5bOYyx8nGZzVYWLADq5lCmg+dptwiN5nNuDyXnzGzYCqkpq5ySROOI6XKzi8ovuhHAJSq6F7+0Y6sbFh3tHJsiao03++2UeIbecxS9fjNhW+NTl5WWczneSofRNy3ORRYedEQRDqUkCgYAHEzWz0L7reU23r7wTTAYe/a5h7FxpbXliWvajicImCATsZMNiuP83N18f4GsAG+E26v2AZ0WqAwm67s6emRnf7q3xXEs5MW/vvMuUoP+d5nmMfYWgjrKzjJBZXCHkcyw0T7J4/pS8DUWWxWEWU2+mqMiJZojU4gmPSuyVyu0y6g==" + alipay_public_key: "" # mode=key 时使用 + app_cert_path: "resources/etc/alipay_cert/appCertPublicKey_2021006150638319.crt" # mode=cert 时使用 + alipay_cert_path: "resources/etc/alipay_cert/alipayCertPublicKey_RSA2.crt" # mode=cert 时使用 + alipay_root_cert_path: "resources/etc/alipay_cert/alipayRootCert.crt" # mode=cert 时使用 + encrypt_key: "YGRGqxlUMNPN389C7h4wLw==" # 可选:AES接口内容加密密钥(16/24/32位) is_production: true notify_url: "https://console.haiyudata.com/api/v1/finance/alipay/callback" return_url: "https://console.haiyudata.com/api/v1/finance/alipay/return" diff --git a/configs/env.production.yaml b/configs/env.production.yaml index 8393e8d..a478c64 100644 --- a/configs/env.production.yaml +++ b/configs/env.production.yaml @@ -74,12 +74,12 @@ ocr: # 📝 e签宝服务配置 # =========================================== esign: - app_id: "5112008003" - app_secret: "d487672273e7aa70c800804a1d9499b9" + app_id: "5112059455" + app_secret: "cacdb6cfca94b74c86bcea277a978884" server_url: "https://openapi.esign.cn" - template_id: "9f7a3f63cc5a48b085b127ba027d234d" + template_id: "d8f5db99506f4dab893f629cb1e82497" contract: - name: "海宇数据API合作协议" + name: "海宇数据-合作协议" expire_days: 7 retry_count: 3 auth: @@ -97,9 +97,6 @@ esign: # 💰 支付宝支付配置 # =========================================== alipay: - app_id: "2021004181633376" - private_key: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCC2GNEWrQUg6FVHBdlDcgL1SA1KmRI8IHgSJGvXEsgfo3g62aa5usFXHVz5bMzpIcDu0N+jGtZQIBuuq7TxGwhDvWBygEDXN17p00uwqik/3TsyFvJ4FfbkaS7pRIGfeO/cBTzjqznanPUdHJZ9L39QmTqTefIQQvGOCvgntKxPa/LdS24+ZLA2RNh3TsRzbSxOOJPmUrwvCX8U13F9jH250hvf+Tewz4hyG8CkiMM4d1UpGMndQNr8oTY0vwFbWAG0ZDGgkxjg0iRJ02fgxwShQS1TgY5NxPhpKBiN5C/WG15qCqEw0F3GlpfWZwzUhv1uMiy+xbZ2bGLo1YCtwUtAgMBAAECggEAQ8uk25T3u61cWYH9qTGT1nWug32ciqJ7WN+hBLCYiJSqJMEz380INzXp8Ywx5u83ubo8xYQyVwNxyG3YCge7UwGyOXaWQczLQbe06SaZRSzLw6gozxf7zdvP9B4akdyGtfl4EZ56fkmNDKbtXSjPjDrrmO+Wyg7R7/nI2lDQsF6dXTKD0YiHtTKz40amKgbIYX+qc3yVS0slkVjcfnRczr+PKM5RMsV3Jk2pr6IYeq3E24LnbuVtV76priTqJN3hVSy2Y6JqmAYkI0HCoCuaFGE8ud3J859jjMcUXTRFJyDsKKooa+FZCoEx2ToVMqnb4vjfr1gZifUrw4ZNd5cPoQKBgQC4v/fNTXuA21pb+l4fnqK0o3wFhiNJh920yIlF4Vd0Nsi2/TwqFK6cVhrUFAmKr88hTzY1vkOhd/HLlkWjNDR5OGx1K1BKUAZjWIfProv8lDSckADEI29lro9WzFGy0o4szlEJ2uuUfO/j9Qn2lmx5oFPsz0TI+HoSNFE0q/SlxQKBgQC1ToMLuh0OkucZm1SL6xcjudBX7U0ElZ/TIxRzfxQ/sN911/BRlxrSdCcDMXNuuFpV2ACjDNWWLJM1sRVsOWNA/oXzZf6VTvUDIAv8XrNUt/B87genBVuMTZ2RYmMWCrgW0PE1OrpKGuQCKVsn242B2Xpmee9OnHhBF2uTASDASQKBgBALvD38iMl8Q7DRYfNlF8SQnmjsaYwtXLgi4qlLFQlm6K/b9qnA+hlh8RqSUvHUqyy9cHvidoVDoaCJAKtYEWal2+WhSWvq32MpgUIsasQZKyid6TMf0MEIFDL5s+7QEsEZejhc5zESWNN3qNHd5rX5ktBygArkadXC7XqhpLHxAoGBAJ0dJEKNTZDLjKiMCoAVgT/cTcdkRFGst4tn4tkTTqDCzWJ5di++Geg173i86aMQ7ndlb2fcP1qb1hW5Fy9pq7Eu3zVFNZB9k6TZqIlSJ2VK4IPiYY9C/UpgGCNcdzEqqMxc1Cmkcrq1AtE8tVmc0Mutgnw7Pj2JKkx91yLU32TBAoGAKxssUdTLuf5Z5oFgzpoSES9qwc1h6jlMfsouDzHcZf0aYintD6Vby7SVul5540qYkDkNs0YZ3uZu74LHfoBaWJjYIIVAMSMX+3AtBpQUyYluex64V/g60t+0sFuDWqMvSPU7mZcv6+KIP6vW56GeYdhHf4JqttdIHm9SgkoJjjY=" - alipay_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2CqoCp95w/JV3RT/gzF4/8QmVT1HQNaeW7yUp+mA7x9AbjvlTW/+eRn6oGAL/XhZLjvHD0XjKLVKX0MJVS1aUQHEHEbOJN4Eu8II45OavD4iZISa7Kp9V6AM+i4qTyaeV2wNDnGxHQBaLVUGCfMR+56EK2YpORdE1H9uy72SSQseVb3bmpsV9EW/IJNmcVL/ut3uA1JWAoRmzlQ7ekxg7p8AYXzYPEHQr1tl7W+M4zv9wO9GKZCxIqMA8U3RP5npPfRaCfIRGzXzCqFEEUvWuidOB7frsvN4jiPD07qpL2Bi9LM1X/ee2kC/oM8Uhd7ERZhG8MbZfijZKxgrsDKBcwIDAQAB" is_production: true notify_url: "https://console.haiyudata.com/api/v1/finance/alipay/callback" return_url: "https://console.haiyudata.com/api/v1/finance/alipay/return" diff --git a/internal/application/certification/certification_application_service_impl.go b/internal/application/certification/certification_application_service_impl.go index 62ab890..7cbc214 100644 --- a/internal/application/certification/certification_application_service_impl.go +++ b/internal/application/certification/certification_application_service_impl.go @@ -716,7 +716,7 @@ func (s *CertificationApplicationServiceImpl) HandleEsignCallback( } // 生成合同 - err = s.generateAndAddContractFile(txCtx, cert, record.CompanyName, record.LegalPersonName, record.UnifiedSocialCode, record.EnterpriseAddress, record.LegalPersonPhone, record.LegalPersonID) + err = s.generateAndAddContractFile(txCtx, cert, record.CompanyName, record.UnifiedSocialCode, record.EnterpriseAddress, pickAuthorizedRepName(record, record.LegalPersonName)) if err != nil { return err } @@ -1351,7 +1351,7 @@ func (s *CertificationApplicationServiceImpl) completeEnterpriseVerification( } // 生成合同 - err = s.generateAndAddContractFile(ctx, cert, record.CompanyName, record.LegalPersonName, record.UnifiedSocialCode, record.EnterpriseAddress, record.LegalPersonPhone, record.LegalPersonID) + err = s.generateAndAddContractFile(ctx, cert, record.CompanyName, record.UnifiedSocialCode, record.EnterpriseAddress, pickAuthorizedRepName(record, record.LegalPersonName)) if err != nil { return err } @@ -1368,32 +1368,33 @@ func (s *CertificationApplicationServiceImpl) completeEnterpriseVerification( return nil } +// pickAuthorizedRepName 合同模板「客户授权代表」: 优先企业提交记录中的授权代表, 否则为法定代表人 +func pickAuthorizedRepName(record *entities.EnterpriseInfoSubmitRecord, legalPersonName string) string { + if record != nil && strings.TrimSpace(record.AuthorizedRepName) != "" { + return strings.TrimSpace(record.AuthorizedRepName) + } + return legalPersonName +} + // generateAndAddContractFile 生成并添加合同文件的公共方法 func (s *CertificationApplicationServiceImpl) generateAndAddContractFile( ctx context.Context, cert *entities.Certification, companyName string, - legalPersonName string, unifiedSocialCode string, enterpriseAddress string, - legalPersonPhone string, - legalPersonID string, + authorizedRepName string, ) error { s.logger.Info("合同生成-步骤1-开始填充合同模板", zap.String("user_id", cert.UserID), zap.String("company_name", companyName)) + // 控件 key 与 e 签宝合同模板中控件名一致(新合同) fileComponent := map[string]string{ - "YFCompanyName": companyName, - "YFCompanyName2": companyName, - "YFLegalPersonName": legalPersonName, - "YFLegalPersonName2": legalPersonName, - "YFUnifiedSocialCode": unifiedSocialCode, - "YFEnterpriseAddress": enterpriseAddress, - "YFContactPerson": legalPersonName, - "YFMobile": legalPersonPhone, - "SignDate": time.Now().Format("2006年01月02日"), - "SignDate2": time.Now().Format("2006年01月02日"), - "SignDate3": time.Now().Format("2006年01月02日"), + "jfqym": companyName, + "jfqym2": companyName, + "jfsqdb": authorizedRepName, + "jftyshxydm": unifiedSocialCode, + "jflxdz": enterpriseAddress, } fillTemplateResp, err := s.esignClient.FillTemplate(fileComponent) if err != nil { @@ -1423,8 +1424,12 @@ func (s *CertificationApplicationServiceImpl) updateContractFile(ctx context.Con return fmt.Errorf("获取企业信息失败: %w", err) } + ei := enterpriseInfo.EnterpriseInfo + submitRec, _ := s.enterpriseInfoSubmitRecordRepo.FindLatestByUserID(ctx, cert.UserID) + authRep := pickAuthorizedRepName(submitRec, ei.LegalPersonName) + // 生成合同 - err = s.generateAndAddContractFile(ctx, cert, enterpriseInfo.EnterpriseInfo.CompanyName, enterpriseInfo.EnterpriseInfo.LegalPersonName, enterpriseInfo.EnterpriseInfo.UnifiedSocialCode, enterpriseInfo.EnterpriseInfo.EnterpriseAddress, enterpriseInfo.EnterpriseInfo.LegalPersonPhone, enterpriseInfo.EnterpriseInfo.LegalPersonID) + err = s.generateAndAddContractFile(ctx, cert, ei.CompanyName, ei.UnifiedSocialCode, ei.EnterpriseAddress, authRep) if err != nil { return err } diff --git a/internal/config/config.go b/internal/config/config.go index e57762a..9350910 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -265,7 +265,7 @@ type SMSConfig struct { type TencentSMSConfig struct { SecretId string `mapstructure:"secret_id"` SecretKey string `mapstructure:"secret_key"` - Region string `mapstructure:"region"` // 如 ap-guangzhou,可空则默认 ap-guangzhou + Region string `mapstructure:"region"` // 如 ap-guangzhou,可空则默认 ap-guangzhou Endpoint string `mapstructure:"endpoint"` // 可空,默认 sms.tencentcloudapi.com SmsSdkAppId string `mapstructure:"sms_sdk_app_id"` // SdkAppId SignName string `mapstructure:"sign_name"` @@ -494,12 +494,17 @@ type MuziLevelFileConfig struct { // AliPayConfig 支付宝配置 type AliPayConfig struct { - AppID string `mapstructure:"app_id"` - PrivateKey string `mapstructure:"private_key"` - AlipayPublicKey string `mapstructure:"alipay_public_key"` - IsProduction bool `mapstructure:"is_production"` - NotifyURL string `mapstructure:"notify_url"` - ReturnURL string `mapstructure:"return_url"` + Mode string `mapstructure:"mode"` + AppID string `mapstructure:"app_id"` + PrivateKey string `mapstructure:"private_key"` + AlipayPublicKey string `mapstructure:"alipay_public_key"` + AppCertPath string `mapstructure:"app_cert_path"` + AlipayCertPath string `mapstructure:"alipay_cert_path"` + AlipayRootCertPath string `mapstructure:"alipay_root_cert_path"` + EncryptKey string `mapstructure:"encrypt_key"` + IsProduction bool `mapstructure:"is_production"` + NotifyURL string `mapstructure:"notify_url"` + ReturnURL string `mapstructure:"return_url"` } // WxpayConfig 微信支付配置 diff --git a/internal/container/container.go b/internal/container/container.go index 473b482..838a951 100644 --- a/internal/container/container.go +++ b/internal/container/container.go @@ -319,12 +319,17 @@ func NewContainer() *Container { // 支付宝支付服务 func(cfg *config.Config) *payment.AliPayService { config := payment.AlipayConfig{ - AppID: cfg.AliPay.AppID, - PrivateKey: cfg.AliPay.PrivateKey, - AlipayPublicKey: cfg.AliPay.AlipayPublicKey, - IsProduction: cfg.AliPay.IsProduction, - NotifyUrl: cfg.AliPay.NotifyURL, - ReturnURL: cfg.AliPay.ReturnURL, + Mode: cfg.AliPay.Mode, + AppID: cfg.AliPay.AppID, + PrivateKey: cfg.AliPay.PrivateKey, + AlipayPublicKey: cfg.AliPay.AlipayPublicKey, + AppCertPath: cfg.AliPay.AppCertPath, + AlipayCertPath: cfg.AliPay.AlipayCertPath, + AlipayRootCertPath: cfg.AliPay.AlipayRootCertPath, + EncryptKey: cfg.AliPay.EncryptKey, + IsProduction: cfg.AliPay.IsProduction, + NotifyUrl: cfg.AliPay.NotifyURL, + ReturnURL: cfg.AliPay.ReturnURL, } return payment.NewAliPayService(config) }, diff --git a/internal/shared/esign/signflow_service.go b/internal/shared/esign/signflow_service.go index 4327d42..9a14d5d 100644 --- a/internal/shared/esign/signflow_service.go +++ b/internal/shared/esign/signflow_service.go @@ -28,13 +28,13 @@ func (s *SignFlowService) UpdateConfig(config *Config) { // 创建包含多个签署人的签署流程,支持自动盖章和手动签署 func (s *SignFlowService) Create(req *CreateSignFlowRequest) (string, error) { fmt.Println("开始创建签署流程...") - fmt.Println("(将创建包含甲方自动盖章和乙方手动签署的流程)") + fmt.Println("(将创建包含甲方手动签署和乙方自动盖章的流程)") - // 构建甲方签署人信息(自动盖章) - partyASigner := s.buildPartyASigner(req.FileID) + // 构建甲方签署人信息(手动签署) + partyASigner := s.buildPartyASigner(req.FileID, req.SignerAccount, req.SignerName, req.TransactorPhone, req.TransactorName, req.TransactorIDCardNum) - // 构建乙方签署人信息(手动签署) - partyBSigner := s.buildPartyBSigner(req.FileID, req.SignerAccount, req.SignerName, req.TransactorPhone, req.TransactorName, req.TransactorIDCardNum) + // 构建乙方签署人信息(自动盖章) + partyBSigner := s.buildPartyBSigner(req.FileID) signers := []SignerInfo{partyASigner, partyBSigner} @@ -128,34 +128,11 @@ func (s *SignFlowService) GetSignURL(signFlowID, psnAccount, orgName string) (st return response.Data.Url, response.Data.ShortUrl, nil } -// buildPartyASigner 构建甲方签署人信息(自动盖章) -func (s *SignFlowService) buildPartyASigner(fileID string) SignerInfo { - return SignerInfo{ - SignConfig: &SignConfig{SignOrder: 1}, - SignerType: SignerTypeOrg, - SignFields: []SignField{ - { - CustomBizNum: "甲方签章", - FileId: fileID, - NormalSignFieldConfig: &NormalSignFieldConfig{ - AutoSign: true, - SignFieldStyle: SignFieldStyleNormal, - SignFieldPosition: &SignFieldPosition{ - PositionPage: "8", - PositionX: 200, - PositionY: 430, - }, - }, - }, - }, - } -} - -// buildPartyBSigner 构建乙方签署人信息(手动签署) -func (s *SignFlowService) buildPartyBSigner(fileID, signerAccount, signerName, transactorPhone, transactorName, transactorIDCardNum string) SignerInfo { +// buildPartyASigner 构建甲方签署人信息(手动签署) +func (s *SignFlowService) buildPartyASigner(fileID, signerAccount, signerName, transactorPhone, transactorName, transactorIDCardNum string) SignerInfo { return SignerInfo{ SignConfig: &SignConfig{ - SignOrder: 2, + SignOrder: 1, }, AuthConfig: &AuthConfig{ PsnAvailableAuthModes: []string{AuthModeMobile3}, @@ -182,15 +159,15 @@ func (s *SignFlowService) buildPartyBSigner(fileID, signerAccount, signerName, t }, SignFields: []SignField{ { - CustomBizNum: "乙方签章", + CustomBizNum: "甲方签章", FileId: fileID, NormalSignFieldConfig: &NormalSignFieldConfig{ AutoSign: false, SignFieldStyle: SignFieldStyleNormal, SignFieldPosition: &SignFieldPosition{ - PositionPage: "8", - PositionX: 450, - PositionY: 430, + PositionPage: "10", + PositionX: 165, + PositionY: 197, }, OrgSealBizTypes: "PUBLIC", }, @@ -199,6 +176,41 @@ func (s *SignFlowService) buildPartyBSigner(fileID, signerAccount, signerName, t } } +// buildPartyBSigner 构建乙方签署人信息(自动盖章) +func (s *SignFlowService) buildPartyBSigner(fileID string) SignerInfo { + return SignerInfo{ + SignConfig: &SignConfig{SignOrder: 2}, + SignerType: SignerTypeOrg, + SignFields: []SignField{ + { + CustomBizNum: "乙方签章", + FileId: fileID, + NormalSignFieldConfig: &NormalSignFieldConfig{ + AutoSign: true, + SignFieldStyle: SignFieldStyleNormal, + SignFieldPosition: &SignFieldPosition{ + PositionPage: "10", + PositionX: 403, + PositionY: 197, + }, + }, + }, + { + CustomBizNum: "乙方骑缝章", // 建议设唯一标识,便于调试 + FileId:fileID, + NormalSignFieldConfig: &NormalSignFieldConfig{ + AutoSign: true, // 骑缝章也支持自动签署 + SignFieldStyle: SignFieldStyleSeam, // 必须为 2(Edges) + SignFieldPosition: &SignFieldPosition{ + AcrossPageMode: "ALL", // 覆盖全部页面(推荐) + PositionY:694.0, // 您指定的 Y 坐标(float64) + }, + }, + }, + }, + } +} + // buildSignFlowConfig 构建签署流程配置 func (s *SignFlowService) buildSignFlowConfig() SignFlowConfig { return SignFlowConfig{ diff --git a/internal/shared/esign/types.go b/internal/shared/esign/types.go index 78b0385..545d12d 100644 --- a/internal/shared/esign/types.go +++ b/internal/shared/esign/types.go @@ -170,6 +170,7 @@ type NormalSignFieldConfig struct { // SignFieldPosition 签署区位置 type SignFieldPosition struct { + AcrossPageMode string `json:"acrossPageMode"` // 跨页模式:ALL-全部页面 PositionPage string `json:"positionPage"` // 页码 PositionX float64 `json:"positionX"` // X坐标 PositionY float64 `json:"positionY"` // Y坐标 diff --git a/internal/shared/payment/alipay.go b/internal/shared/payment/alipay.go index 28e4d62..527807e 100644 --- a/internal/shared/payment/alipay.go +++ b/internal/shared/payment/alipay.go @@ -15,12 +15,17 @@ import ( ) type AlipayConfig struct { - AppID string - PrivateKey string - AlipayPublicKey string - IsProduction bool - NotifyUrl string - ReturnURL string // 同步回调地址 + AppID string + Mode string + PrivateKey string + AlipayPublicKey string + AppCertPath string + AlipayCertPath string + AlipayRootCertPath string + EncryptKey string + IsProduction bool + NotifyUrl string + ReturnURL string // 同步回调地址 } type AliPayService struct { config AlipayConfig @@ -34,11 +39,30 @@ func NewAliPayService(config AlipayConfig) *AliPayService { panic(fmt.Sprintf("创建支付宝客户端失败: %v", err)) } - // 加载支付宝公钥 - err = client.LoadAliPayPublicKey(config.AlipayPublicKey) - if err != nil { - panic(fmt.Sprintf("加载支付宝公钥失败: %v", err)) + if config.Mode == "cert" { + // 证书模式:加载应用公钥证书、支付宝公钥证书、支付宝根证书 + if err = client.LoadAppCertPublicKeyFromFile(config.AppCertPath); err != nil { + panic(fmt.Sprintf("加载应用公钥证书失败: %v", err)) + } + if err = client.LoadAlipayCertPublicKeyFromFile(config.AlipayCertPath); err != nil { + panic(fmt.Sprintf("加载支付宝公钥证书失败: %v", err)) + } + if err = client.LoadAliPayRootCertFromFile(config.AlipayRootCertPath); err != nil { + panic(fmt.Sprintf("加载根证书失败: %v", err)) + } + } else { + // 默认密钥模式:加载支付宝公钥 + err = client.LoadAliPayPublicKey(config.AlipayPublicKey) + if err != nil { + panic(fmt.Sprintf("加载支付宝公钥失败: %v", err)) + } } + + // 可选:开启支付宝接口内容加密(AES) + if config.EncryptKey != "" { + client.SetEncryptKey(config.EncryptKey) + } + return &AliPayService{ config: config, AlipayClient: client, diff --git a/resources/etc/alipay_cert/alipayCertPublicKey_RSA2.crt b/resources/etc/alipay_cert/alipayCertPublicKey_RSA2.crt new file mode 100644 index 0000000..cd9607f --- /dev/null +++ b/resources/etc/alipay_cert/alipayCertPublicKey_RSA2.crt @@ -0,0 +1,43 @@ +-----BEGIN CERTIFICATE----- +MIIDnTCCAoWgAwIBAgIQICYEJzQyjvTjPdqODB2iPzANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MTkwNwYDVQQDDDBBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IENs +YXNzIDIgUjEwHhcNMjYwNDI3MDMzMTU1WhcNMzEwNDI2MDMzMTU1WjB+MQswCQYDVQQGEwJDTjEZ +MBcGA1UECgwQMjA4ODM1MTU3NjgwMzk1NjEPMA0GA1UECwwGQWxpcGF5MUMwQQYDVQQDDDrmlK/k +u5jlrp0o5Lit5Zu9Kee9kee7nOaKgOacr+aciemZkOWFrOWPuC0yMDg4MzUxNTc2ODAzOTU2MIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtdOMS7jgcpbRwNhs/WtWkw7klF8sGWo6xCgV +/7YlPO+ru8bsnF42Nj8RQQ0OS2Tf6ebLNQbrD3R21ne8MkdL2kFUjW5nFN6SvW/g/sr6Q7okZKWK +jontB+9ajMtswdXYcS3FppCT87QltIHDrJcp3LbT6SXRNPqdiuHWv4/aDDfDoPNDRBYVTGK42nEA +PTueSlYxsGJf2ohdLXTlfTwqsvdH5UgmzZQaxDlsVCaqEvBzLoEw63mAXOLyjOUF1yf45hVau3p5 +mS2IPCnx8CzHPLlC1Ot9unXRmVL+Vo9k9Tr5Krs5nzajTJ7BSJGz/nRHNDFrFjQSEfatOcZEPlll +VQIDAQABoxIwEDAOBgNVHQ8BAf8EBAMCA/gwDQYJKoZIhvcNAQELBQADggEBAKIZshIc+fy1kzx3 +QU6O/KgVhHqbYqSCO/SrLc4JCmelQZ0V2B3NRjYAAyZ/RY7wHiZRoCjZKzbJlumEVW2Qvm3KU308 +c29M2vsJ0zDpLhW/D5Vh4/9NS+rLktk221y8CuX4o7Nlp1e+Fo5yaZHxEvnAH8hrSWdDU58T+/7I +lBbl+mau93TmaA6XxNZQ4AZ3emNCABvSkOv5c8LxEyZqIBXh+R1vcwYlCr6QOcEfC++6ZiSmPZue +FrlgmUFWxPF56H+t9Bq1qj53B8QPMBts+7hCXZh5GwOeLYfzskgByp1GaJ9sV+KyycNoRLy1UsoB +hoiJdGNVq009xZAnNUFu3RY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE4jCCAsqgAwIBAgIIYsSr5bKAMl8wDQYJKoZIhvcNAQELBQAwejELMAkGA1UEBhMCQ04xFjAU +BgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEw +LwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMy +MjE0MzQxNVoXDTM3MTEyNjE0MzQxNVowgYIxCzAJBgNVBAYTAkNOMRYwFAYDVQQKDA1BbnQgRmlu +YW5jaWFsMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE5MDcGA1UEAwwwQW50IEZp +bmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDbGFzcyAyIFIxMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAsLMfYaoRoPRbmDcAfXPCmKf43pWRN5yTXa/KJWO0l+mrgQvs89bA +NEvbDUxlkGwycwtwi5DgBuBgVhLliXu+R9CYgr2dXs8D8Hx/gsggDcyGPLmVrDOnL+dyeauheARZ +fA3du60fwEwwbGcVIpIxPa/4n3IS/ElxQa6DNgqxh8J9Xwh7qMGl0JK9+bALuxf7B541Gr4p0WEN +G8fhgjBV4w4ut9eQLOoa1eddOUSZcy46Z7allwowwgt7b5VFfx/P1iKJ3LzBMgkCK7GZ2kiLrL7R +iqV+h482J7hkJD+ardoc6LnrHO/hIZymDxok+VH9fVeUdQa29IZKrIDVj65THQIDAQABo2MwYTAf +BgNVHSMEGDAWgBRfdLQEwE8HWurlsdsio4dBspzhATAdBgNVHQ4EFgQUSqHkYINtUSAtDPnS8Xoy +oP9p7qEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIB +AIQ8TzFy4bVIVb8+WhHKCkKNPcJe2EZuIcqvRoi727lZTJOfYy/JzLtckyZYfEI8J0lasZ29wkTt +a1IjSo+a6XdhudU4ONVBrL70U8Kzntplw/6TBNbLFpp7taRALjUgbCOk4EoBMbeCL0GiYYsTS0mw +7xdySzmGQku4GTyqutIGPQwKxSj9iSFw1FCZqr4VP4tyXzMUgc52SzagA6i7AyLedd3tbS6lnR5B +L+W9Kx9hwT8L7WANAxQzv/jGldeuSLN8bsTxlOYlsdjmIGu/C9OWblPYGpjQQIRyvs4Cc/mNhrh+ +14EQgwuemIIFDLOgcD+iISoN8CqegelNcJndFw1PDN6LkVoiHz9p7jzsge8RKay/QW6C03KNDpWZ +EUCgCUdfHfo8xKeR+LL1cfn24HKJmZt8L/aeRZwZ1jwePXFRVtiXELvgJuM/tJDIFj2KD337iV64 +fWcKQ/ydDVGqfDZAdcU4hQdsrPWENwPTQPfVPq2NNLMyIH9+WKx9Ed6/WzeZmIy5ZWpX1TtTolo6 +OJXQFeItMAjHxW/ZSZTok5IS3FuRhExturaInnzjYpx50a6kS34c5+c8hYq7sAtZ/CNLZmBnBCFD +aMQqT8xFZJ5uolUaSeXxg7JFY1QsYp5RKvj4SjFwCGKJ2+hPPe9UyyltxOidNtxjaknOCeBHytOr +-----END CERTIFICATE----- diff --git a/resources/etc/alipay_cert/alipayRootCert.crt b/resources/etc/alipay_cert/alipayRootCert.crt new file mode 100644 index 0000000..76417c5 --- /dev/null +++ b/resources/etc/alipay_cert/alipayRootCert.crt @@ -0,0 +1,88 @@ +-----BEGIN CERTIFICATE----- +MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG +EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw +MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO +UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE +MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT +V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti +W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ +MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b +53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI +pDoiVhsLwg== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIF0zCCA7ugAwIBAgIIH8+hjWpIDREwDQYJKoZIhvcNAQELBQAwejELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMyMTEzNDg0MFoXDTM4MDIyODEzNDg0 +MFowejELMAkGA1UEBhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNV +BAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEAtytTRcBNuur5h8xuxnlKJetT65cHGemGi8oD+beHFPTk +rUTlFt9Xn7fAVGo6QSsPb9uGLpUFGEdGmbsQ2q9cV4P89qkH04VzIPwT7AywJdt2 +xAvMs+MgHFJzOYfL1QkdOOVO7NwKxH8IvlQgFabWomWk2Ei9WfUyxFjVO1LVh0Bp +dRBeWLMkdudx0tl3+21t1apnReFNQ5nfX29xeSxIhesaMHDZFViO/DXDNW2BcTs6 +vSWKyJ4YIIIzStumD8K1xMsoaZBMDxg4itjWFaKRgNuPiIn4kjDY3kC66Sl/6yTl +YUz8AybbEsICZzssdZh7jcNb1VRfk79lgAprm/Ktl+mgrU1gaMGP1OE25JCbqli1 +Pbw/BpPynyP9+XulE+2mxFwTYhKAwpDIDKuYsFUXuo8t261pCovI1CXFzAQM2w7H +DtA2nOXSW6q0jGDJ5+WauH+K8ZSvA6x4sFo4u0KNCx0ROTBpLif6GTngqo3sj+98 +SZiMNLFMQoQkjkdN5Q5g9N6CFZPVZ6QpO0JcIc7S1le/g9z5iBKnifrKxy0TQjtG +PsDwc8ubPnRm/F82RReCoyNyx63indpgFfhN7+KxUIQ9cOwwTvemmor0A+ZQamRe +9LMuiEfEaWUDK+6O0Gl8lO571uI5onYdN1VIgOmwFbe+D8TcuzVjIZ/zvHrAGUcC +AwEAAaNdMFswCwYDVR0PBAQDAgEGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFF90 +tATATwda6uWx2yKjh0GynOEBMB8GA1UdIwQYMBaAFF90tATATwda6uWx2yKjh0Gy +nOEBMA0GCSqGSIb3DQEBCwUAA4ICAQCVYaOtqOLIpsrEikE5lb+UARNSFJg6tpkf +tJ2U8QF/DejemEHx5IClQu6ajxjtu0Aie4/3UnIXop8nH/Q57l+Wyt9T7N2WPiNq +JSlYKYbJpPF8LXbuKYG3BTFTdOVFIeRe2NUyYh/xs6bXGr4WKTXb3qBmzR02FSy3 +IODQw5Q6zpXj8prYqFHYsOvGCEc1CwJaSaYwRhTkFedJUxiyhyB5GQwoFfExCVHW +05ZFCAVYFldCJvUzfzrWubN6wX0DD2dwultgmldOn/W/n8at52mpPNvIdbZb2F41 +T0YZeoWnCJrYXjq/32oc1cmifIHqySnyMnavi75DxPCdZsCOpSAT4j4lAQRGsfgI +kkLPGQieMfNNkMCKh7qjwdXAVtdqhf0RVtFILH3OyEodlk1HYXqX5iE5wlaKzDop +PKwf2Q3BErq1xChYGGVS+dEvyXc/2nIBlt7uLWKp4XFjqekKbaGaLJdjYP5b2s7N +1dM0MXQ/f8XoXKBkJNzEiM3hfsU6DOREgMc1DIsFKxfuMwX3EkVQM1If8ghb6x5Y +jXayv+NLbidOSzk4vl5QwngO/JYFMkoc6i9LNwEaEtR9PhnrdubxmrtM+RjfBm02 +77q3dSWFESFQ4QxYWew4pHE0DpWbWy/iMIKQ6UZ5RLvB8GEcgt8ON7BBJeMc+Dyi +kT9qhqn+lw== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIICiDCCAgygAwIBAgIIQX76UsB/30owDAYIKoZIzj0EAwMFADB6MQswCQYDVQQG +EwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UECwwXQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNpYWwgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgRTEwHhcNMTkwNDI4MTYyMDQ0WhcNNDkwNDIwMTYyMDQ0 +WjB6MQswCQYDVQQGEwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UE +CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNp +YWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRTEwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAASCCRa94QI0vR5Up9Yr9HEupz6hSoyjySYqo7v837KnmjveUIUNiuC9pWAU +WP3jwLX3HkzeiNdeg22a0IZPoSUCpasufiLAnfXh6NInLiWBrjLJXDSGaY7vaokt +rpZvAdmjXTBbMAsGA1UdDwQEAwIBBjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRZ +4ZTgDpksHL2qcpkFkxD2zVd16TAfBgNVHSMEGDAWgBRZ4ZTgDpksHL2qcpkFkxD2 +zVd16TAMBggqhkjOPQQDAwUAA2gAMGUCMQD4IoqT2hTUn0jt7oXLdMJ8q4vLp6sg +wHfPiOr9gxreb+e6Oidwd2LDnC4OUqCWiF8CMAzwKs4SnDJYcMLf2vpkbuVE4dTH +Rglz+HGcTLWsFs4KxLsq7MuU+vJTBUeDJeDjdA== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIUEMdk6dVgOEIS2cCP0Q43P90Ps5YwDQYJKoZIhvcNAQEF +BQAwajELMAkGA1UEBhMCQ04xEzARBgNVBAoMCmlUcnVzQ2hpbmExHDAaBgNVBAsM +E0NoaW5hIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMMH2lUcnVzQ2hpbmEgQ2xhc3Mg +MiBSb290IENBIC0gRzMwHhcNMTMwNDE4MDkzNjU2WhcNMzMwNDE4MDkzNjU2WjBq +MQswCQYDVQQGEwJDTjETMBEGA1UECgwKaVRydXNDaGluYTEcMBoGA1UECwwTQ2hp +bmEgVHJ1c3QgTmV0d29yazEoMCYGA1UEAwwfaVRydXNDaGluYSBDbGFzcyAyIFJv +b3QgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPPShpV +nJbMqqCw6Bz1kehnoPst9pkr0V9idOwU2oyS47/HjJXk9Rd5a9xfwkPO88trUpz5 +4GmmwspDXjVFu9L0eFaRuH3KMha1Ak01citbF7cQLJlS7XI+tpkTGHEY5pt3EsQg +wykfZl/A1jrnSkspMS997r2Gim54cwz+mTMgDRhZsKK/lbOeBPpWtcFizjXYCqhw +WktvQfZBYi6o4sHCshnOswi4yV1p+LuFcQ2ciYdWvULh1eZhLxHbGXyznYHi0dGN +z+I9H8aXxqAQfHVhbdHNzi77hCxFjOy+hHrGsyzjrd2swVQ2iUWP8BfEQqGLqM1g +KgWKYfcTGdbPB1MCAwEAAaNjMGEwHQYDVR0OBBYEFG/oAMxTVe7y0+408CTAK8hA +uTyRMB8GA1UdIwQYMBaAFG/oAMxTVe7y0+408CTAK8hAuTyRMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBLnUTfW7hp +emMbuUGCk7RBswzOT83bDM6824EkUnf+X0iKS95SUNGeeSWK2o/3ALJo5hi7GZr3 +U8eLaWAcYizfO99UXMRBPw5PRR+gXGEronGUugLpxsjuynoLQu8GQAeysSXKbN1I +UugDo9u8igJORYA+5ms0s5sCUySqbQ2R5z/GoceyI9LdxIVa1RjVX8pYOj8JFwtn +DJN3ftSFvNMYwRuILKuqUYSHc2GPYiHVflDh5nDymCMOQFcFG3WsEuB+EYQPFgIU +1DHmdZcz7Llx8UOZXX2JupWCYzK1XhJb+r4hK5ncf/w8qGtYlmyJpxk3hr1TfUJX +Yf4Zr0fJsGuv +-----END CERTIFICATE----- \ No newline at end of file diff --git a/resources/etc/alipay_cert/appCertPublicKey_2021006150638319.crt b/resources/etc/alipay_cert/appCertPublicKey_2021006150638319.crt new file mode 100644 index 0000000..2a1bfc0 --- /dev/null +++ b/resources/etc/alipay_cert/appCertPublicKey_2021006150638319.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIErTCCA5WgAwIBAgIQICYEJ/tIrGCC6P+fOEl09jANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MTkwNwYDVQQDDDBBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IENs +YXNzIDEgUjEwHhcNMjYwNDI3MDMzMTU0WhcNMzEwNDI2MDMzMTU0WjB0MQswCQYDVQQGEwJDTjE5 +MDcGA1UECgww5rW35a6H5pWw56eR77yI5bm/5Lic5qiq55C077yJ56eR5oqA5pyJ6ZmQ5YWs5Y+4 +MQ8wDQYDVQQLDAZBbGlwYXkxGTAXBgNVBAMMEDIwODgzNTE1NzY4MDM5NTYwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCTMiY8fgrW60Mr6NI82Kn6mm3oubEvrYtZ7kADiL/maeh5tzHb +0NdtRIElprGQQ7sQhoXgFoDndJ9Ipk1NwVmA/9e0nuPmyEw935KTbFono6pRFBw7+k3bPRFDCbiE +1BvsBa7mwJE9H/rV5ry/6H84b49pwC74La7WJhMhRXJVMeapqNyeZ7VgBf/LQ99/Bd0uMdRmcv67 +8qO88E1FKIxtpD0ZVtCmmipzXSf4Wsyq0unoiwHz5fhWlOC+STByUGuuoVMdUKlzNaBQoVMKm4mn +96OKFpf5ulLOQNg80XVFy0eq2MJzur0HLWcfMEEMARQ7lXjaS5JZ1RLGe6ki8EyvAgMBAAGjggEq +MIIBJjAfBgNVHSMEGDAWgBRxB+IEYRbk5fJl6zEPyeD0PJrVkTAdBgNVHQ4EFgQUac276wfYpuP6 +hCH4TFBAYgF/5aEwQAYDVR0gBDkwNzA1BgdggRwBbgEBMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9j +YS5hbGlwYXkuY29tL2Nwcy5wZGYwDgYDVR0PAQH/BAQDAgbAMDAGA1UdHwQpMCcwJaAjoCGGH2h0 +dHA6Ly9jYS5hbGlwYXkuY29tL2NybDExMi5jcmwwYAYIKwYBBQUHAQEEVDBSMCgGCCsGAQUFBzAC +hhxodHRwOi8vY2EuYWxpcGF5LmNvbS9jYTYuY2VyMCYGCCsGAQUFBzABhhpodHRwOi8vY2EuYWxp +cGF5LmNvbTo4MzQwLzANBgkqhkiG9w0BAQsFAAOCAQEAR2aPqmVhUEM4HIpyZdH/K5K1y+8kNXg0 +LRN4Ldf7r7TyDDDF5pG4sJ7MBZ8TRncOxQxDjaCdnfVCqSeqGy9IYJYnt1MtznycdH0u8ITPd8Kx +uRg5Jd9trBrR9bY2WfsRoCR5c0Me2+HPMzcKizfFNo++3thj5Q52T1Knk43nMJ/WVrc1JCMxTcvY +vFZWsU14CLzIlwLiHRRVjGPtYDKAXrf3KCFitATc9LEvMU+v+XZEX9sexas3Xv0qGD1ShoSuIOyV +ICKydYnvSPyknT9w2rks/gZwmbsO9dwGgbFptZk8E5VvO58T37F7zVkIfY5ibh0erg9GdoiyVN88 +HiYugQ== +-----END CERTIFICATE----- \ No newline at end of file