This commit is contained in:
2026-04-27 11:56:41 +08:00
parent a10604178d
commit cef9612526
11 changed files with 298 additions and 86 deletions

View File

@@ -267,12 +267,12 @@ wechat_work:
# 📝 e签宝服务配置 # 📝 e签宝服务配置
# =========================================== # ===========================================
esign: esign:
app_id: "7439073138" app_id: "5112059455"
app_secret: "d76e27fdd169b391e09262a0959dac5c" app_secret: "cacdb6cfca94b74c86bcea277a978884"
server_url: "https://smlopenapi.esign.cn" server_url: "https://smlopenapi.esign.cn"
template_id: "9f7a3f63cc5a48b085b127ba027d234d" template_id: "d8f5db99506f4dab893f629cb1e82497"
contract: contract:
name: "海宇数据API合作协议" name: "海宇数据-合作协议"
expire_days: 7 expire_days: 7
retry_count: 3 retry_count: 3
auth: auth:
@@ -384,6 +384,14 @@ yushan:
# 💰 支付宝支付配置 # 💰 支付宝支付配置
# =========================================== # ===========================================
alipay: 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 is_production: true
notify_url: "https://console.haiyudata.com/api/v1/finance/alipay/callback" notify_url: "https://console.haiyudata.com/api/v1/finance/alipay/callback"
return_url: "https://console.haiyudata.com/api/v1/finance/alipay/return" return_url: "https://console.haiyudata.com/api/v1/finance/alipay/return"

View File

@@ -74,12 +74,12 @@ ocr:
# 📝 e签宝服务配置 # 📝 e签宝服务配置
# =========================================== # ===========================================
esign: esign:
app_id: "5112008003" app_id: "5112059455"
app_secret: "d487672273e7aa70c800804a1d9499b9" app_secret: "cacdb6cfca94b74c86bcea277a978884"
server_url: "https://openapi.esign.cn" server_url: "https://openapi.esign.cn"
template_id: "9f7a3f63cc5a48b085b127ba027d234d" template_id: "d8f5db99506f4dab893f629cb1e82497"
contract: contract:
name: "海宇数据API合作协议" name: "海宇数据-合作协议"
expire_days: 7 expire_days: 7
retry_count: 3 retry_count: 3
auth: auth:
@@ -97,9 +97,6 @@ esign:
# 💰 支付宝支付配置 # 💰 支付宝支付配置
# =========================================== # ===========================================
alipay: 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 is_production: true
notify_url: "https://console.haiyudata.com/api/v1/finance/alipay/callback" notify_url: "https://console.haiyudata.com/api/v1/finance/alipay/callback"
return_url: "https://console.haiyudata.com/api/v1/finance/alipay/return" return_url: "https://console.haiyudata.com/api/v1/finance/alipay/return"

View File

@@ -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 { if err != nil {
return err 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 { if err != nil {
return err return err
} }
@@ -1368,32 +1368,33 @@ func (s *CertificationApplicationServiceImpl) completeEnterpriseVerification(
return nil 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 生成并添加合同文件的公共方法 // generateAndAddContractFile 生成并添加合同文件的公共方法
func (s *CertificationApplicationServiceImpl) generateAndAddContractFile( func (s *CertificationApplicationServiceImpl) generateAndAddContractFile(
ctx context.Context, ctx context.Context,
cert *entities.Certification, cert *entities.Certification,
companyName string, companyName string,
legalPersonName string,
unifiedSocialCode string, unifiedSocialCode string,
enterpriseAddress string, enterpriseAddress string,
legalPersonPhone string, authorizedRepName string,
legalPersonID string,
) error { ) error {
s.logger.Info("合同生成-步骤1-开始填充合同模板", s.logger.Info("合同生成-步骤1-开始填充合同模板",
zap.String("user_id", cert.UserID), zap.String("user_id", cert.UserID),
zap.String("company_name", companyName)) zap.String("company_name", companyName))
// 控件 key 与 e 签宝合同模板中控件名一致(新合同)
fileComponent := map[string]string{ fileComponent := map[string]string{
"YFCompanyName": companyName, "jfqym": companyName,
"YFCompanyName2": companyName, "jfqym2": companyName,
"YFLegalPersonName": legalPersonName, "jfsqdb": authorizedRepName,
"YFLegalPersonName2": legalPersonName, "jftyshxydm": unifiedSocialCode,
"YFUnifiedSocialCode": unifiedSocialCode, "jflxdz": enterpriseAddress,
"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日"),
} }
fillTemplateResp, err := s.esignClient.FillTemplate(fileComponent) fillTemplateResp, err := s.esignClient.FillTemplate(fileComponent)
if err != nil { if err != nil {
@@ -1423,8 +1424,12 @@ func (s *CertificationApplicationServiceImpl) updateContractFile(ctx context.Con
return fmt.Errorf("获取企业信息失败: %w", err) 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 { if err != nil {
return err return err
} }

View File

@@ -494,9 +494,14 @@ type MuziLevelFileConfig struct {
// AliPayConfig 支付宝配置 // AliPayConfig 支付宝配置
type AliPayConfig struct { type AliPayConfig struct {
Mode string `mapstructure:"mode"`
AppID string `mapstructure:"app_id"` AppID string `mapstructure:"app_id"`
PrivateKey string `mapstructure:"private_key"` PrivateKey string `mapstructure:"private_key"`
AlipayPublicKey string `mapstructure:"alipay_public_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"` IsProduction bool `mapstructure:"is_production"`
NotifyURL string `mapstructure:"notify_url"` NotifyURL string `mapstructure:"notify_url"`
ReturnURL string `mapstructure:"return_url"` ReturnURL string `mapstructure:"return_url"`

View File

@@ -319,9 +319,14 @@ func NewContainer() *Container {
// 支付宝支付服务 // 支付宝支付服务
func(cfg *config.Config) *payment.AliPayService { func(cfg *config.Config) *payment.AliPayService {
config := payment.AlipayConfig{ config := payment.AlipayConfig{
Mode: cfg.AliPay.Mode,
AppID: cfg.AliPay.AppID, AppID: cfg.AliPay.AppID,
PrivateKey: cfg.AliPay.PrivateKey, PrivateKey: cfg.AliPay.PrivateKey,
AlipayPublicKey: cfg.AliPay.AlipayPublicKey, AlipayPublicKey: cfg.AliPay.AlipayPublicKey,
AppCertPath: cfg.AliPay.AppCertPath,
AlipayCertPath: cfg.AliPay.AlipayCertPath,
AlipayRootCertPath: cfg.AliPay.AlipayRootCertPath,
EncryptKey: cfg.AliPay.EncryptKey,
IsProduction: cfg.AliPay.IsProduction, IsProduction: cfg.AliPay.IsProduction,
NotifyUrl: cfg.AliPay.NotifyURL, NotifyUrl: cfg.AliPay.NotifyURL,
ReturnURL: cfg.AliPay.ReturnURL, ReturnURL: cfg.AliPay.ReturnURL,

View File

@@ -28,13 +28,13 @@ func (s *SignFlowService) UpdateConfig(config *Config) {
// 创建包含多个签署人的签署流程,支持自动盖章和手动签署 // 创建包含多个签署人的签署流程,支持自动盖章和手动签署
func (s *SignFlowService) Create(req *CreateSignFlowRequest) (string, error) { func (s *SignFlowService) Create(req *CreateSignFlowRequest) (string, error) {
fmt.Println("开始创建签署流程...") 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} 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 return response.Data.Url, response.Data.ShortUrl, nil
} }
// buildPartyASigner 构建甲方签署人信息(自动盖章 // buildPartyASigner 构建甲方签署人信息(手动签署
func (s *SignFlowService) buildPartyASigner(fileID string) SignerInfo { func (s *SignFlowService) buildPartyASigner(fileID, signerAccount, signerName, transactorPhone, transactorName, transactorIDCardNum 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 {
return SignerInfo{ return SignerInfo{
SignConfig: &SignConfig{ SignConfig: &SignConfig{
SignOrder: 2, SignOrder: 1,
}, },
AuthConfig: &AuthConfig{ AuthConfig: &AuthConfig{
PsnAvailableAuthModes: []string{AuthModeMobile3}, PsnAvailableAuthModes: []string{AuthModeMobile3},
@@ -182,15 +159,15 @@ func (s *SignFlowService) buildPartyBSigner(fileID, signerAccount, signerName, t
}, },
SignFields: []SignField{ SignFields: []SignField{
{ {
CustomBizNum: "方签章", CustomBizNum: "方签章",
FileId: fileID, FileId: fileID,
NormalSignFieldConfig: &NormalSignFieldConfig{ NormalSignFieldConfig: &NormalSignFieldConfig{
AutoSign: false, AutoSign: false,
SignFieldStyle: SignFieldStyleNormal, SignFieldStyle: SignFieldStyleNormal,
SignFieldPosition: &SignFieldPosition{ SignFieldPosition: &SignFieldPosition{
PositionPage: "8", PositionPage: "10",
PositionX: 450, PositionX: 165,
PositionY: 430, PositionY: 197,
}, },
OrgSealBizTypes: "PUBLIC", 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, // 必须为 2Edges
SignFieldPosition: &SignFieldPosition{
AcrossPageMode: "ALL", // 覆盖全部页面(推荐)
PositionY:694.0, // 您指定的 Y 坐标float64
},
},
},
},
}
}
// buildSignFlowConfig 构建签署流程配置 // buildSignFlowConfig 构建签署流程配置
func (s *SignFlowService) buildSignFlowConfig() SignFlowConfig { func (s *SignFlowService) buildSignFlowConfig() SignFlowConfig {
return SignFlowConfig{ return SignFlowConfig{

View File

@@ -170,6 +170,7 @@ type NormalSignFieldConfig struct {
// SignFieldPosition 签署区位置 // SignFieldPosition 签署区位置
type SignFieldPosition struct { type SignFieldPosition struct {
AcrossPageMode string `json:"acrossPageMode"` // 跨页模式ALL-全部页面
PositionPage string `json:"positionPage"` // 页码 PositionPage string `json:"positionPage"` // 页码
PositionX float64 `json:"positionX"` // X坐标 PositionX float64 `json:"positionX"` // X坐标
PositionY float64 `json:"positionY"` // Y坐标 PositionY float64 `json:"positionY"` // Y坐标

View File

@@ -16,8 +16,13 @@ import (
type AlipayConfig struct { type AlipayConfig struct {
AppID string AppID string
Mode string
PrivateKey string PrivateKey string
AlipayPublicKey string AlipayPublicKey string
AppCertPath string
AlipayCertPath string
AlipayRootCertPath string
EncryptKey string
IsProduction bool IsProduction bool
NotifyUrl string NotifyUrl string
ReturnURL string // 同步回调地址 ReturnURL string // 同步回调地址
@@ -34,11 +39,30 @@ func NewAliPayService(config AlipayConfig) *AliPayService {
panic(fmt.Sprintf("创建支付宝客户端失败: %v", err)) 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) err = client.LoadAliPayPublicKey(config.AlipayPublicKey)
if err != nil { if err != nil {
panic(fmt.Sprintf("加载支付宝公钥失败: %v", err)) panic(fmt.Sprintf("加载支付宝公钥失败: %v", err))
} }
}
// 可选开启支付宝接口内容加密AES
if config.EncryptKey != "" {
client.SetEncryptKey(config.EncryptKey)
}
return &AliPayService{ return &AliPayService{
config: config, config: config,
AlipayClient: client, AlipayClient: client,

View File

@@ -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-----

View File

@@ -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-----

View File

@@ -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-----