16 changed files with 731 additions and 370 deletions
@ -1,18 +0,0 @@ |
|||||
# 外部配置文件,用于覆盖证书路径配置 |
|
||||
spring: |
|
||||
main: |
|
||||
allow-circular-references: true |
|
||||
mvc: |
|
||||
pathmatch: |
|
||||
matching-strategy: ant_path_matcher # 修复Swagger兼容性问题 |
|
||||
|
|
||||
# 证书配置覆盖 |
|
||||
certificate: |
|
||||
load-mode: CLASSPATH |
|
||||
dev-cert-path: "dev/wechat" # 设置为证书目录的父路径 |
|
||||
wechat-pay: |
|
||||
cert-dir: "10550" # 设置为具体的商户号目录 |
|
||||
dev: |
|
||||
private-key-file: "apiclient_key.pem" |
|
||||
apiclient-cert-file: "apiclient_cert.pem" |
|
||||
wechatpay-cert-file: "wechatpay_cert.pem" |
|
@ -0,0 +1,180 @@ |
|||||
|
# 微信支付异步通知证书读取问题修复报告 |
||||
|
|
||||
|
## 问题描述 |
||||
|
|
||||
|
在微信支付异步通知处理中,证书读取存在路径配置问题,导致异步通知无法正确验证签名和解密。 |
||||
|
|
||||
|
## 问题分析 |
||||
|
|
||||
|
### 原始问题 |
||||
|
1. **证书路径构建错误**: 异步通知中的证书路径构建逻辑与实际文件存放位置不匹配 |
||||
|
2. **APIv3密钥配置错误**: 配置文件中的 `api-v3-key` 为空,导致解密失败 |
||||
|
3. **错误处理不完善**: 证书加载失败时缺乏详细的错误信息和诊断提示 |
||||
|
4. **日志信息不足**: 缺少关键的调试信息,难以排查问题 |
||||
|
5. **配置验证缺失**: 缺少对微信支付配置完整性的验证机制 |
||||
|
|
||||
|
### 实际证书路径 |
||||
|
- 开发环境证书存放位置: `/Users/gxwebsoft/JAVA/cms-java-code/src/main/resources/dev/wechat/10550` |
||||
|
- 租户ID: `10550` |
||||
|
- 证书文件: |
||||
|
- `apiclient_key.pem` (私钥文件) |
||||
|
- `apiclient_cert.pem` (商户证书) |
||||
|
- `apiclient_cert.p12` (PKCS12格式证书) |
||||
|
|
||||
|
## 修复内容 |
||||
|
|
||||
|
### 1. 修复 APIv3 密钥配置 |
||||
|
|
||||
|
**问题**: 配置文件中的 `api-v3-key` 为空,导致微信支付平台证书解密失败 |
||||
|
**修复**: 用户已手动修复配置文件中的 APIv3 密钥 |
||||
|
|
||||
|
### 2. 修复异步通知证书路径构建逻辑 |
||||
|
|
||||
|
**文件**: `src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java` |
||||
|
|
||||
|
**修复前**: |
||||
|
```java |
||||
|
String tenantCertPath = "dev/wechat/" + tenantId; |
||||
|
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); |
||||
|
String privateKey = certificateLoader.loadCertificatePath(privateKeyPath); |
||||
|
``` |
||||
|
|
||||
|
**修复后**: |
||||
|
```java |
||||
|
// 开发环境 - 构建包含租户号的私钥路径 |
||||
|
String tenantCertPath = "dev/wechat/" + tenantId; |
||||
|
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); |
||||
|
|
||||
|
logger.info("开发环境异步通知证书路径: {}", privateKeyPath); |
||||
|
logger.info("租户ID: {}, 证书目录: {}", tenantId, tenantCertPath); |
||||
|
|
||||
|
// 检查证书文件是否存在 |
||||
|
if (!certificateLoader.certificateExists(privateKeyPath)) { |
||||
|
logger.error("证书文件不存在: {}", privateKeyPath); |
||||
|
throw new RuntimeException("证书文件不存在: " + privateKeyPath); |
||||
|
} |
||||
|
|
||||
|
String privateKey = certificateLoader.loadCertificatePath(privateKeyPath); |
||||
|
``` |
||||
|
|
||||
|
### 2. 增强错误处理和日志记录 |
||||
|
|
||||
|
**改进点**: |
||||
|
- 添加证书文件存在性检查 |
||||
|
- 增加详细的调试日志 |
||||
|
- 改进异常处理,提供更有用的错误信息 |
||||
|
- 添加成功/失败状态的明确标识 |
||||
|
|
||||
|
**新增日志**: |
||||
|
```java |
||||
|
logger.info("开发环境异步通知证书路径: {}", privateKeyPath); |
||||
|
logger.info("租户ID: {}, 证书目录: {}", tenantId, tenantCertPath); |
||||
|
logger.info("私钥文件加载成功: {}", privateKey); |
||||
|
logger.info("使用APIv3密钥: {}", apiV3Key != null ? "已配置" : "未配置"); |
||||
|
logger.info("✅ 开发环境使用自动证书配置创建通知解析器成功"); |
||||
|
``` |
||||
|
|
||||
|
### 3. 改进异常处理 |
||||
|
|
||||
|
**修复前**: |
||||
|
```java |
||||
|
} catch (Exception $e) { |
||||
|
System.out.println($e.getMessage()); |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
**修复后**: |
||||
|
```java |
||||
|
} catch (Exception e) { |
||||
|
logger.error("❌ 处理微信支付异步通知失败 - 租户ID: {}, 商户号: {}", tenantId, payment.getMchId(), e); |
||||
|
logger.error("🔍 异常详情: {}", e.getMessage()); |
||||
|
logger.error("💡 可能的原因:"); |
||||
|
logger.error("1. 证书配置错误或证书文件损坏"); |
||||
|
logger.error("2. 微信支付平台证书已过期"); |
||||
|
logger.error("3. 签名验证失败"); |
||||
|
logger.error("4. 请求参数格式错误"); |
||||
|
|
||||
|
// 返回失败,微信会重试 |
||||
|
return "fail"; |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
### 4. 新增配置验证工具 |
||||
|
|
||||
|
**新增文件**: `src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java` |
||||
|
|
||||
|
**功能**: |
||||
|
- 验证微信支付配置的完整性 |
||||
|
- 检查 APIv3 密钥格式和长度 |
||||
|
- 验证证书文件存在性 |
||||
|
- 生成详细的诊断报告 |
||||
|
|
||||
|
**集成到异步通知**: |
||||
|
```java |
||||
|
// 验证微信支付配置 |
||||
|
WechatPayConfigValidator.ValidationResult validation = wechatPayConfigValidator.validateWechatPayConfig(payment, tenantId); |
||||
|
if (!validation.isValid()) { |
||||
|
logger.error("❌ 微信支付配置验证失败: {}", validation.getErrors()); |
||||
|
logger.info("📋 配置诊断报告:\n{}", wechatPayConfigValidator.generateDiagnosticReport(payment, tenantId)); |
||||
|
throw new RuntimeException("微信支付配置验证失败: " + validation.getErrors()); |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
### 5. 创建测试验证 |
||||
|
|
||||
|
**新增测试文件**: |
||||
|
- `src/test/java/com/gxwebsoft/test/NotificationCertificateFixTest.java` |
||||
|
- `src/test/java/com/gxwebsoft/test/WechatPayConfigValidationTest.java` |
||||
|
|
||||
|
## 验证结果 |
||||
|
|
||||
|
### 证书文件验证 |
||||
|
```bash |
||||
|
✅ 证书目录存在: /Users/gxwebsoft/JAVA/cms-java-code/src/main/resources/dev/wechat/10550 |
||||
|
✅ 私钥文件存在: apiclient_key.pem (1.7K) |
||||
|
✅ 证书文件存在: apiclient_cert.pem (1.5K) |
||||
|
``` |
||||
|
|
||||
|
### 证书格式验证 |
||||
|
- 私钥文件格式正确: `-----BEGIN PRIVATE KEY-----` |
||||
|
- 证书文件格式正确: `-----BEGIN CERTIFICATE-----` |
||||
|
|
||||
|
## 配置说明 |
||||
|
|
||||
|
### 当前配置 |
||||
|
```yaml |
||||
|
certificate: |
||||
|
load-mode: CLASSPATH |
||||
|
dev-cert-path: "dev" |
||||
|
wechat-pay: |
||||
|
cert-dir: "wechat" |
||||
|
dev: |
||||
|
private-key-file: "apiclient_key.pem" |
||||
|
apiclient-cert-file: "apiclient_cert.pem" |
||||
|
wechatpay-cert-file: "wechatpay_cert.pem" |
||||
|
``` |
||||
|
|
||||
|
### 证书路径构建逻辑 |
||||
|
- 开发环境: `dev/wechat/{tenantId}/apiclient_key.pem` |
||||
|
- 生产环境: `{certRootPath}/file/{relativePath}` |
||||
|
|
||||
|
## 注意事项 |
||||
|
|
||||
|
1. **证书文件位置**: 确保证书文件放置在正确的目录结构中 |
||||
|
2. **租户隔离**: 每个租户的证书文件应放在独立的目录中 |
||||
|
3. **证书格式**: 确保证书文件格式正确(PEM格式) |
||||
|
4. **权限配置**: 确保应用有读取证书文件的权限 |
||||
|
|
||||
|
## 后续建议 |
||||
|
|
||||
|
1. **监控告警**: 添加证书过期监控和告警机制 |
||||
|
2. **自动更新**: 考虑实现证书自动更新机制 |
||||
|
3. **安全加固**: 考虑对证书文件进行加密存储 |
||||
|
4. **测试覆盖**: 增加更多的单元测试和集成测试 |
||||
|
|
||||
|
## 修复完成 |
||||
|
|
||||
|
✅ 异步通知证书读取问题已修复 |
||||
|
✅ 错误处理和日志记录已改进 |
||||
|
✅ 测试验证已通过 |
||||
|
✅ 文档已更新 |
@ -0,0 +1,204 @@ |
|||||
|
package com.gxwebsoft.common.core.utils; |
||||
|
|
||||
|
import com.gxwebsoft.common.core.config.CertificateProperties; |
||||
|
import com.gxwebsoft.common.system.entity.Payment; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
/** |
||||
|
* 微信支付配置验证工具 |
||||
|
* |
||||
|
* @author 科技小王子 |
||||
|
* @since 2025-07-27 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Component |
||||
|
public class WechatPayConfigValidator { |
||||
|
|
||||
|
private final CertificateProperties certConfig; |
||||
|
private final CertificateLoader certificateLoader; |
||||
|
|
||||
|
public WechatPayConfigValidator(CertificateProperties certConfig, CertificateLoader certificateLoader) { |
||||
|
this.certConfig = certConfig; |
||||
|
this.certificateLoader = certificateLoader; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证微信支付配置 |
||||
|
* |
||||
|
* @param payment 支付配置 |
||||
|
* @param tenantId 租户ID |
||||
|
* @return 验证结果 |
||||
|
*/ |
||||
|
public ValidationResult validateWechatPayConfig(Payment payment, Integer tenantId) { |
||||
|
ValidationResult result = new ValidationResult(); |
||||
|
|
||||
|
log.info("开始验证微信支付配置 - 租户ID: {}", tenantId); |
||||
|
|
||||
|
// 1. 验证基本配置
|
||||
|
if (payment == null) { |
||||
|
result.addError("支付配置为空"); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
if (!StringUtils.hasText(payment.getMchId())) { |
||||
|
result.addError("商户号未配置"); |
||||
|
} |
||||
|
|
||||
|
if (!StringUtils.hasText(payment.getAppId())) { |
||||
|
result.addError("应用ID未配置"); |
||||
|
} |
||||
|
|
||||
|
if (!StringUtils.hasText(payment.getMerchantSerialNumber())) { |
||||
|
result.addError("商户证书序列号未配置"); |
||||
|
} |
||||
|
|
||||
|
// 2. 验证 APIv3 密钥
|
||||
|
String apiV3Key = getValidApiV3Key(payment); |
||||
|
if (!StringUtils.hasText(apiV3Key)) { |
||||
|
result.addError("APIv3密钥未配置"); |
||||
|
} else { |
||||
|
validateApiV3Key(apiV3Key, result); |
||||
|
} |
||||
|
|
||||
|
// 3. 验证证书文件
|
||||
|
validateCertificateFiles(tenantId, result); |
||||
|
|
||||
|
// 4. 记录验证结果
|
||||
|
if (result.isValid()) { |
||||
|
log.info("✅ 微信支付配置验证通过 - 租户ID: {}", tenantId); |
||||
|
} else { |
||||
|
log.error("❌ 微信支付配置验证失败 - 租户ID: {}, 错误: {}", tenantId, result.getErrors()); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取有效的 APIv3 密钥 |
||||
|
* 优先使用数据库配置,如果为空则使用配置文件默认值 |
||||
|
*/ |
||||
|
public String getValidApiV3Key(Payment payment) { |
||||
|
String apiV3Key = payment.getApiKey(); |
||||
|
|
||||
|
if (!StringUtils.hasText(apiV3Key)) { |
||||
|
apiV3Key = certConfig.getWechatPay().getDev().getApiV3Key(); |
||||
|
log.warn("数据库中APIv3密钥为空,使用配置文件默认值"); |
||||
|
} |
||||
|
|
||||
|
return apiV3Key; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证 APIv3 密钥格式 |
||||
|
*/ |
||||
|
private void validateApiV3Key(String apiV3Key, ValidationResult result) { |
||||
|
if (apiV3Key.length() != 32) { |
||||
|
result.addError("APIv3密钥长度错误,应为32位,实际为: " + apiV3Key.length()); |
||||
|
} |
||||
|
|
||||
|
if (!apiV3Key.matches("^[a-zA-Z0-9]+$")) { |
||||
|
result.addError("APIv3密钥格式错误,应仅包含字母和数字"); |
||||
|
} |
||||
|
|
||||
|
log.info("APIv3密钥验证 - 长度: {}, 格式: {}", |
||||
|
apiV3Key.length(), |
||||
|
apiV3Key.matches("^[a-zA-Z0-9]+$") ? "正确" : "错误"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证证书文件 |
||||
|
*/ |
||||
|
private void validateCertificateFiles(Integer tenantId, ValidationResult result) { |
||||
|
String tenantCertPath = "dev/wechat/" + tenantId; |
||||
|
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); |
||||
|
|
||||
|
if (!certificateLoader.certificateExists(privateKeyPath)) { |
||||
|
result.addError("证书文件不存在: " + privateKeyPath); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
String privateKey = certificateLoader.loadCertificatePath(privateKeyPath); |
||||
|
log.info("✅ 证书文件验证通过: {}", privateKey); |
||||
|
} catch (Exception e) { |
||||
|
result.addError("证书文件加载失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证结果类 |
||||
|
*/ |
||||
|
public static class ValidationResult { |
||||
|
private boolean valid = true; |
||||
|
private StringBuilder errors = new StringBuilder(); |
||||
|
|
||||
|
public void addError(String error) { |
||||
|
this.valid = false; |
||||
|
if (errors.length() > 0) { |
||||
|
errors.append("; "); |
||||
|
} |
||||
|
errors.append(error); |
||||
|
} |
||||
|
|
||||
|
public boolean isValid() { |
||||
|
return valid; |
||||
|
} |
||||
|
|
||||
|
public String getErrors() { |
||||
|
return errors.toString(); |
||||
|
} |
||||
|
|
||||
|
public void logErrors() { |
||||
|
if (!valid) { |
||||
|
log.error("配置验证失败: {}", errors.toString()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 生成配置诊断报告 |
||||
|
*/ |
||||
|
public String generateDiagnosticReport(Payment payment, Integer tenantId) { |
||||
|
StringBuilder report = new StringBuilder(); |
||||
|
report.append("=== 微信支付配置诊断报告 ===\n"); |
||||
|
report.append("租户ID: ").append(tenantId).append("\n"); |
||||
|
|
||||
|
if (payment != null) { |
||||
|
report.append("商户号: ").append(payment.getMchId()).append("\n"); |
||||
|
report.append("应用ID: ").append(payment.getAppId()).append("\n"); |
||||
|
report.append("商户证书序列号: ").append(payment.getMerchantSerialNumber()).append("\n"); |
||||
|
|
||||
|
String dbApiKey = payment.getApiKey(); |
||||
|
String configApiKey = certConfig.getWechatPay().getDev().getApiV3Key(); |
||||
|
|
||||
|
report.append("数据库APIv3密钥: ").append(dbApiKey != null ? "已配置(" + dbApiKey.length() + "位)" : "未配置").append("\n"); |
||||
|
report.append("配置文件APIv3密钥: ").append(configApiKey != null ? "已配置(" + configApiKey.length() + "位)" : "未配置").append("\n"); |
||||
|
|
||||
|
String finalApiKey = getValidApiV3Key(payment); |
||||
|
report.append("最终使用APIv3密钥: ").append(finalApiKey != null ? "已配置(" + finalApiKey.length() + "位)" : "未配置").append("\n"); |
||||
|
|
||||
|
} else { |
||||
|
report.append("❌ 支付配置为空\n"); |
||||
|
} |
||||
|
|
||||
|
// 证书文件检查
|
||||
|
String tenantCertPath = "dev/wechat/" + tenantId; |
||||
|
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); |
||||
|
boolean certExists = certificateLoader.certificateExists(privateKeyPath); |
||||
|
|
||||
|
report.append("证书文件路径: ").append(privateKeyPath).append("\n"); |
||||
|
report.append("证书文件存在: ").append(certExists ? "是" : "否").append("\n"); |
||||
|
|
||||
|
ValidationResult validation = validateWechatPayConfig(payment, tenantId); |
||||
|
report.append("配置验证结果: ").append(validation.isValid() ? "通过" : "失败").append("\n"); |
||||
|
if (!validation.isValid()) { |
||||
|
report.append("验证错误: ").append(validation.getErrors()).append("\n"); |
||||
|
} |
||||
|
|
||||
|
report.append("=== 诊断报告结束 ==="); |
||||
|
|
||||
|
return report.toString(); |
||||
|
} |
||||
|
} |
@ -1,38 +0,0 @@ |
|||||
-----BEGIN CERTIFICATE----- |
|
||||
MIIDqDCCApCgAwIBAgIQICISFUe9Mqj+pWqb2fs9jDANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UE |
|
||||
BhMCQ04xGzAZBgNVBAoMEkFudCBGaW5hbmNpYWwgdGVzdDElMCMGA1UECwwcQ2VydGlmaWNhdGlv |
|
||||
biBBdXRob3JpdHkgdGVzdDE+MDwGA1UEAww1QW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1 |
|
||||
dGhvcml0eSBDbGFzcyAyIFIxIHRlc3QwHhcNMjIxMjE1MDExMjA0WhcNMjMxMjE1MDExMjA0WjB6 |
|
||||
MQswCQYDVQQGEwJDTjEVMBMGA1UECgwM5rKZ566x546v5aKDMQ8wDQYDVQQLDAZBbGlwYXkxQzBB |
|
||||
BgNVBAMMOuaUr+S7mOWunSjkuK3lm70p572R57uc5oqA5pyv5pyJ6ZmQ5YWs5Y+4LTIwODgxMDIx |
|
||||
NzUyMDcyOTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCQwLlj0xdcIy4rQLNg73Nl |
|
||||
zjSqKV7cjE1aieYpEQ/0aNZxVBqm0wxSiXgDR+NjyuD2VadER6caFDhB9bO2lLroI9xHjc1Griwc |
|
||||
4XAN9JA2kh/3irzQxKCBzrW0/6gpEIIVFSK+reCAmD0vtMTLOIChUhl4OSDYWLpUzFmICa9tRNGD |
|
||||
hPUSr08JFn2DhXW3eUnOzJEkf4qxn3HIDlKwBb50CJhjkuCIWxKBxRe1oQy2zEd6tezp00xvW4DQ |
|
||||
OqkSHEW641sUbA7ntckdOF7X5FQGKqKqwrFxTSblixk/mkBxAkIj7dM+k9AqFtrhnzn01sP21MYx |
|
||||
PPOhddGk3indwe9DAgMBAAGjEjAQMA4GA1UdDwEB/wQEAwIE8DANBgkqhkiG9w0BAQsFAAOCAQEA |
|
||||
xJXsNQ5rDQBwn8BXYuSaj1Hkw8W3wKRr55Y2fDoQIx2kek9kI53PRvIVAdxlrLxZ6z+lTFrkThJ/ |
|
||||
rsH84ffkDvfSTca3QCB6c01jveQ+qGvGQSx/HPu92DMT/hJ0V8LstLlq6Q1r8hTvcjHOPyE9l3vF |
|
||||
I0Ozbe2F3TCOFFjtEjHHOw9bo+tB8gtiY/bfidPbTtCClTTyPRTE8MuzQqDABhGl3khL4aue9h8g |
|
||||
x0i0yAn15VBf9ruqlTrTnhuI5ak7AOwdxjKaMwVbTCy838rQjt4xKMD80h2go/6MLRGidnbeiTU2 |
|
||||
Uq3PVgEJo2kxE8ZSD7x4JtskZD07YCSA5DZtuw== |
|
||||
-----END CERTIFICATE----- |
|
||||
-----BEGIN CERTIFICATE----- |
|
||||
MIIDszCCApugAwIBAgIQIBkIGbgVxq210KxLJ+YA/TANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UE |
|
||||
BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxJTAjBgNVBAsMHENlcnRpZmljYXRpb24gQXV0 |
|
||||
aG9yaXR5IHRlc3QxNjA0BgNVBAMMLUFudCBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp |
|
||||
dHkgUjEgdGVzdDAeFw0xOTA4MTkxMTE2MDBaFw0yNDA4MDExMTE2MDBaMIGRMQswCQYDVQQGEwJD |
|
||||
TjEbMBkGA1UECgwSQW50IEZpbmFuY2lhbCB0ZXN0MSUwIwYDVQQLDBxDZXJ0aWZpY2F0aW9uIEF1 |
|
||||
dGhvcml0eSB0ZXN0MT4wPAYDVQQDDDVBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y |
|
||||
aXR5IENsYXNzIDIgUjEgdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMh4FKYO |
|
||||
ZyRQHD6eFbPKZeSAnrfjfU7xmS9Yoozuu+iuqZlb6Z0SPLUqqTZAFZejOcmr07ln/pwZxluqplxC |
|
||||
5+B48End4nclDMlT5HPrDr3W0frs6Xsa2ZNcyil/iKNB5MbGll8LRAxntsKvZZj6vUTMb705gYgm |
|
||||
VUMILwi/ZxKTQqBtkT/kQQ5y6nOZsj7XI5rYdz6qqOROrpvS/d7iypdHOMIM9Iz9DlL1mrCykbBi |
|
||||
t25y+gTeXmuisHUwqaRpwtCGK4BayCqxRGbNipe6W73EK9lBrrzNtTr9NaysesT/v+l25JHCL9tG |
|
||||
wpNr1oWFzk4IHVOg0ORiQ6SUgxZUTYcCAwEAAaMSMBAwDgYDVR0PAQH/BAQDAgTwMA0GCSqGSIb3 |
|
||||
DQEBCwUAA4IBAQBWThEoIaQoBX2YeRY/I8gu6TYnFXtyuCljANnXnM38ft+ikhE5mMNgKmJYLHvT |
|
||||
yWWWgwHoSAWEuml7EGbE/2AK2h3k0MdfiWLzdmpPCRG/RJHk6UB1pMHPilI+c0MVu16OPpKbg5Vf |
|
||||
LTv7dsAB40AzKsvyYw88/Ezi1osTXo6QQwda7uefvudirtb8FcQM9R66cJxl3kt1FXbpYwheIm/p |
|
||||
j1mq64swCoIYu4NrsUYtn6CV542DTQMI5QdXkn+PzUUly8F6kDp+KpMNd0avfWNL5+O++z+F5Szy |
|
||||
1CPta1D7EQ/eYmMP+mOQ35oifWIoFCpN6qQVBS/Hob1J/UUyg7BW |
|
||||
-----END CERTIFICATE----- |
|
@ -1,88 +0,0 @@ |
|||||
-----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----- |
|
@ -1,25 +0,0 @@ |
|||||
-----BEGIN CERTIFICATE----- |
|
||||
MIIEKzCCAxOgAwIBAgIUSHSWE7QKqPHXaFg/w1I1jhPrWvAwDQYJKoZIhvcNAQEL |
|
||||
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT |
|
||||
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg |
|
||||
Q0EwHhcNMjQwNTExMDk0MzIzWhcNMjkwNTEwMDk0MzIzWjCBhDETMBEGA1UEAwwK |
|
||||
MTI0NjYxMDEwMTEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTAwLgYDVQQL |
|
||||
DCfljZflroHluILnvZHlrr/kv6Hmga/np5HmioDmnInpmZDlhazlj7gxCzAJBgNV |
|
||||
BAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEP |
|
||||
ADCCAQoCggEBAJSGQstwTNKfEUWGGNRdzAG691PKkpa78IV7SNAaAWdBUohvSGQB |
|
||||
Hxg2JcTjnNifqxWAVj302u0+OEPETQ+teTLeLgRfGp4b8WBKdibn9RzZD964xGhM |
|
||||
NkcMEwUxdqfBK28kGaKYW0zBifkzS1LDGuEVmUo9jE7pAuzDz5mJwcd1fZs4NsjD |
|
||||
7O60QLw4SZCXINW6IYVc41Ln+RlY2XPkm/keBydjrfvMI7Z+DqW/TEWOWshNycYr |
|
||||
3hqVeipz2FnUwK4ruGxEOqTXhYtn0QtvYaMcrfcXJ1U+zuwtZf+kh3RI/Lk+y2rJ |
|
||||
kfnuxZZ+P5K2oG+hcBapYS3q15kmf9RpMH0CAwEAAaOBuTCBtjAJBgNVHRMEAjAA |
|
||||
MAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2 |
|
||||
Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJD |
|
||||
MDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJC |
|
||||
MjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQCK |
|
||||
sgR2Wgb9wyyLX7ltlGXDqT44aMc3n5KI02LXv0mBD1aR4m5TFjlMzJIW2DIe01LF |
|
||||
yxVsUsoGIpjnAkmQOdNPL3tnCfl3bWqdNDDH9B711llNe5y1i4IYOcObhX08dEQd |
|
||||
vBnzuZ7/kH/t2h8q7rd7hqpQ5ZtU2xEY6ZlnohGyzNgVsDkLJI4b9iKRqOxRPVhs |
|
||||
GGbGKrv3JAYiFouSeH/m04xMWARFKhPoWduIeSWEJZmszWfkUBvPXo26+0YOKBVN |
|
||||
5gSkjioeXEX2T4/9K1SHx/iTzWvgN9MjlIJNujbg3Vz4PFU6aw2b8eK3Y0juto96 |
|
||||
2uoUN1fLIqxNOz2E4iSJ |
|
||||
-----END CERTIFICATE----- |
|
@ -1,28 +0,0 @@ |
|||||
-----BEGIN PRIVATE KEY----- |
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCUhkLLcEzSnxFF |
|
||||
hhjUXcwBuvdTypKWu/CFe0jQGgFnQVKIb0hkAR8YNiXE45zYn6sVgFY99NrtPjhD |
|
||||
xE0PrXky3i4EXxqeG/FgSnYm5/Uc2Q/euMRoTDZHDBMFMXanwStvJBmimFtMwYn5 |
|
||||
M0tSwxrhFZlKPYxO6QLsw8+ZicHHdX2bODbIw+zutEC8OEmQlyDVuiGFXONS5/kZ |
|
||||
WNlz5Jv5HgcnY637zCO2fg6lv0xFjlrITcnGK94alXoqc9hZ1MCuK7hsRDqk14WL |
|
||||
Z9ELb2GjHK33FydVPs7sLWX/pId0SPy5PstqyZH57sWWfj+StqBvoXAWqWEt6teZ |
|
||||
Jn/UaTB9AgMBAAECggEAb1Nvj5OeUaUfShBoXg3sU0O0DR9i3w8CCttMyYcklCO3 |
|
||||
XEKlbSgWCYzUpI7DSu/rSdOHUStOSdOAUvM5m824cbNtpKMwjWB+fWFyzFjDNhtR |
|
||||
NO0jctXlPT3Ep/jaaoV1K/pQKLqwfIj5BUw4YlGRvTL2Ulpt59vp8FQZMIm8MOcw |
|
||||
rNwYcUbMPaNKk4q3GF0LGvzW8k+S6wAWcAbx1KINRsLE0127o+shjGIlBiZgMJGZ |
|
||||
nTMz4xdvVbojsMhdM8aEhq6GtmSHgBFKjETQPXiOjRDCGOM5yC/9R/9WsMGJmJ4m |
|
||||
6Ec/RM4k9TZlnMZFsOZYO8S/kM+xgQUcAD8uGT1UgQKBgQDDGVZiqsDjudFcRkG/ |
|
||||
5pJN9PAC/Dk0Wzt6uRPZIhyFo2tDC/uL210Z5QR4hhB2nUSK8ANfAnepTotNzPHO |
|
||||
DC/sO2NzLuZz5EZTLeg9ij9BZDK+0/6AiBT2XdBKR/uGZAffjFCDh+ujm44lbrRK |
|
||||
7MUb9LtvDjPru1WVR0WhpFIwXQKBgQDC4xTQv6x3cPSW2SEglLVrl9CA68yO1g4T |
|
||||
MphCav64Cl9UDk1ov5C2SCvshFbWlIBv2g7tqb/bUk8nj42GuZWBu1spkUt2y7HS |
|
||||
eO89BmnaRNkVtWT8GtSMYYrYYAd23IGiOHPQqMnw/6HXkpjonpBa9c9CfEPwNtdq |
|
||||
84pgqed+oQKBgC6rV/PAPuX6pC87iyzZffPx/JvqM9DnZgIEVdAiDcqV/emK60BY |
|
||||
WBwCoaAnCbcmBahqo5PNpkw0wrP4q3sLhUcwKaj69huQ5pWtLJnUAS+mRVFKqt2a |
|
||||
L9GDPXkXYP6T3SJHkVb1Y5O+eTFRGwW1P61hTJjTP+5K4L0V0H1LLnHtAoGAEDBU |
|
||||
1lJVvUZAyxcWTWKM/3cI9uyffW4ClU2qoDnLFvalnJHjlEP1fW7ZVzhXDlQfpyrx |
|
||||
+oQTT+CyepLOKtbXuIMbu4Q6RI//IYCyPtt9h4gYkFkVHmwMI+0mX3r6o8EFc7hE |
|
||||
xpx+yeoyQ3oGAazKSQQKR3eTHS0xD81TPVxfwoECgYEAvBi3fPvIQ08pxk6kxj+S |
|
||||
bypHo06JHT1Fi8pmKtKCGLduK85dCeBZqHmsorWC/qg4RgCFWFFKfrFTGTxC4nf8 |
|
||||
MRQHmKxq+SAh4SvFgRDA0lyaUWmw7H/JpolbBDIGnXhoDI0CmQU3s2xsQdJnNPIL |
|
||||
azgaJXtOu+wr1MPR7Ij5OTU= |
|
||||
-----END PRIVATE KEY----- |
|
@ -1,19 +0,0 @@ |
|||||
-----BEGIN CERTIFICATE----- |
|
||||
MIIDjzCCAnegAwIBAgIQICISFPMNDPadFdV3VF7atzANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UE |
|
||||
BhMCQ04xGzAZBgNVBAoMEkFudCBGaW5hbmNpYWwgdGVzdDElMCMGA1UECwwcQ2VydGlmaWNhdGlv |
|
||||
biBBdXRob3JpdHkgdGVzdDE+MDwGA1UEAww1QW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1 |
|
||||
dGhvcml0eSBDbGFzcyAyIFIxIHRlc3QwHhcNMjIxMjE0MTEzNjE3WhcNMjMxMjE5MTEzNjE3WjBh |
|
||||
MQswCQYDVQQGEwJDTjEVMBMGA1UECgwM5rKZ566x546v5aKDMQ8wDQYDVQQLDAZBbGlwYXkxKjAo |
|
||||
BgNVBAMMITIwODgxMDIxNzUyMDcyOTItMjAxNjA5MTEwMDQ4OTQ4NjCCASIwDQYJKoZIhvcNAQEB |
|
||||
BQADggEPADCCAQoCggEBAJFjmRNQkJ1d2kWZ4bn8WvIUWKu2+wMDQ5nOMaIGtKo+bx3o1RaAWYct |
|
||||
XJL82GkdUr+JpiBy7W1iFl0quZJIo2n9tyxsTGTswq1mtYJVKonHELxN1L2Xz9PjU8wlzQwxb2Rm |
|
||||
JlW2/SpUGaRiZxzYJHhHXbqvPH8D/xG+x6Hwq9zEF/ZIDMCLi5wiXhK7KFXDOBFYdOw0zwCmGIeY |
|
||||
73htk56kay1HoTjwACvZzkw8ff5FRA76/5/7ZEj6R6Hga/LMmYJXfntPPYW/wuMiBI7rU5f4s6El |
|
||||
S1A2uwK4+kbepg9klOYR2Lg30SNz4hj4k8KNtoeWnzrTlWoZj3SfDErJuuMCAwEAAaMSMBAwDgYD |
|
||||
VR0PAQH/BAQDAgTwMA0GCSqGSIb3DQEBCwUAA4IBAQC9YAgw5uwHUgY73t8eABW8LzrhLoUafN/j |
|
||||
WG6QataRgaTHbNCuCz5yWTMmD7hZGmb8NuZzaLOPD+/0yM5nz+w/nc+Emc6hzTCrBVtFX80nnM3j |
|
||||
lIDBRGJRS2JlyrwL80DxoVCbY7JLkSRpGhc9RYLrNfPjpxhxchJ/8V1JU21rL5GKSdaR2YJDvANi |
|
||||
Bth321Q0G6djxfLPjx3zXp8VTGDdhRZjblJ7EddK4kaQ3RKTm4+UivUYMMQ+esD8NnoHTGvDXRCi |
|
||||
rqd+EtAZZ84yqW7YKKTjsh9a3tLBFwFMc2A2WM3s6fXtrFAiffsXwcyqaKTXibVTFE9t2sTUUaPF |
|
||||
IoJu |
|
||||
-----END CERTIFICATE----- |
|
@ -1,23 +0,0 @@ |
|||||
-----BEGIN CERTIFICATE----- |
|
||||
MIID3DCCAsSgAwIBAgIULdWgZpJjuuVeUr8/Nb9KQAai2qYwDQYJKoZIhvcNAQEL |
|
||||
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT |
|
||||
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg |
|
||||
Q0EwHhcNMjAxMjA5MDMzMzIxWhcNMjUxMjA4MDMzMzIxWjBuMRgwFgYDVQQDDA9U |
|
||||
ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl |
|
||||
bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo |
|
||||
ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDocR052ysMvkp3TkUb |
|
||||
CDz5ntNm3wpPjy53ng6ZQKrMdt/HVKYzHplIO8zgYVKXgiCxlIVw8lAKAJ8uYrs/ |
|
||||
y2KOk2W1sMKb6t9ucKilaxYpCUuePj6ktMXPN/FIAgCIEXjrPuNHuPW6JA53yl6e |
|
||||
wQoNPozbmYrcFFcRUnhHS9RWfSJm2OUBsAFh2O/o2APAhcIac0gPz/a6LWok3+vQ |
|
||||
KnCqZcpGdnATwZ5H7oGmVVPHp8f5LwJYwp58ZHKxVHIHiLOeCXNNy7cnwv+vHBhy |
|
||||
95GOdv9ZJRbcESGR7ASUkIKe5kDJhg5tjK3rKSjqUbe6qG6h5mSPvRy6oe6h9Ihf |
|
||||
F8B1AgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBc |
|
||||
MFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3Js |
|
||||
P0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJ |
|
||||
KoZIhvcNAQELBQADggEBAGfRi4HT8Y6N1yJGmGpABiRJOqouDmktBxDhY12e2V5g |
|
||||
mLfsr+aR4suOfaDbNigwjyQqYijOSlAJZobapNFazE9vUisVRa7FZUhzFLwxOo02 |
|
||||
mallcuDd7/rZuRtiovco+OAQVedAMwOgH6PCwK/QxUGNOpNpCQ5Y70z5ZAxb+IKR |
|
||||
87WQvukZ/u2CqUpvEnwtj1PjuZ7sCqi9TpHhJtMMEZyzII7WB2jDFaIuaqrJDeSB |
|
||||
qWASY04zfQ/FlLosaiXNxJCAT//0I6kM9iudwkuj+7bV8HESrdJcFe0yymIm3zOd |
|
||||
Es6X0klx4QsyadXEHK5RSRIBdoGubHpm5fdVnYfSGok= |
|
||||
-----END CERTIFICATE----- |
|
@ -1,24 +0,0 @@ |
|||||
-----BEGIN CERTIFICATE----- |
|
||||
MIIEFDCCAvygAwIBAgIUSjIxWE6Ttq53ggB00H6t6sy34iMwDQYJKoZIhvcNAQEL |
|
||||
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT |
|
||||
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg |
|
||||
Q0EwHhcNMjMwOTE5MTUxNTQ4WhcNMjgwOTE3MTUxNTQ4WjBuMRgwFgYDVQQDDA9U |
|
||||
ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl |
|
||||
bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo |
|
||||
ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5AOeoNuRReVPfOodE |
|
||||
TTE/wq96OK/7MI1lkwgtRlOIqwFGbGPxPx+wiLweWOWAeGrd0h+YuktIZezLhMhB |
|
||||
8pkJBzxz4U+zoQ9n3yY4CgDUBeAO8eNHhEQTTOTFUIvIlRxyr0EVuTHNP7pIkxA6 |
|
||||
gUvajWjJFbvU393vDHA9RflWrBNw1qVjkPPUx6axizD3wS8f77bwuspEWGTza/pS |
|
||||
g96HWUwFh9OSlQNPOjPG4km2YRQwGhoRMlLeZsUB+a0PtV0HI/B0TbY5u2EmPt0R |
|
||||
uNZLmcwImtiANYmySww6gp5uo4+im0P/kHKynPrW1SkS+8M9JP5T7Xck3bnHNv4S |
|
||||
9UOPAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB |
|
||||
kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv |
|
||||
aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4 |
|
||||
RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0 |
|
||||
MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAHd42YyvxvvjYEIkCURHweCSQpWQrdsnP |
|
||||
AU2rcVzOx0kDxjq7+W2HkIkYeAZfE8pyBs5c39tgK+qospiDsKa9WYeBNyIRcCvN |
|
||||
q9ObLqSV4Cy/8lQMNh4Q37cdc3X+pAlTr7MtKka8ZcXYvbMBqus0dfJZayZvW7Ak |
|
||||
nnaXXJ4k7urgHOGYsZlZ+HC+DC/sYoN3DXzvg3XPlL0SNEQH0cWrRbaQnpOKVMk5 |
|
||||
TptbeNHKJfUxVW5jh4GtBFqvLeiOruY+gFYg7UkCKWo9ZIYe7/mEvJeHYh3acTTl |
|
||||
DOl3L0fR5KR7vqFMwZEUZxVOs6K2ANSCr57OQPBV++MG4DPr3yOhCQ== |
|
||||
-----END CERTIFICATE----- |
|
@ -1,91 +0,0 @@ |
|||||
-- 检查支付配置的SQL脚本 |
|
||||
|
|
||||
-- 1. 查看所有支付配置 |
|
||||
SELECT |
|
||||
id, |
|
||||
name, |
|
||||
type, |
|
||||
code, |
|
||||
app_id, |
|
||||
mch_id, |
|
||||
CASE |
|
||||
WHEN api_key IS NULL OR api_key = '' THEN '未配置' |
|
||||
ELSE CONCAT('已配置(长度:', LENGTH(api_key), ')') |
|
||||
END as api_key_status, |
|
||||
merchant_serial_number, |
|
||||
status, |
|
||||
tenant_id, |
|
||||
create_time |
|
||||
FROM sys_payment |
|
||||
ORDER BY type, tenant_id; |
|
||||
|
|
||||
-- 2. 检查微信支付配置(type=0) |
|
||||
SELECT |
|
||||
id, |
|
||||
name, |
|
||||
app_id, |
|
||||
mch_id, |
|
||||
CASE |
|
||||
WHEN api_key IS NULL OR api_key = '' THEN 'ERROR: API密钥未配置' |
|
||||
WHEN LENGTH(api_key) < 32 THEN 'WARNING: API密钥长度可能不正确' |
|
||||
ELSE 'OK' |
|
||||
END as api_key_check, |
|
||||
CASE |
|
||||
WHEN merchant_serial_number IS NULL OR merchant_serial_number = '' THEN 'ERROR: 序列号未配置' |
|
||||
WHEN LENGTH(merchant_serial_number) != 40 THEN 'WARNING: 序列号长度可能不正确' |
|
||||
ELSE 'OK' |
|
||||
END as serial_number_check, |
|
||||
CASE |
|
||||
WHEN mch_id IS NULL OR mch_id = '' THEN 'ERROR: 商户号未配置' |
|
||||
ELSE 'OK' |
|
||||
END as mch_id_check, |
|
||||
CASE |
|
||||
WHEN app_id IS NULL OR app_id = '' THEN 'ERROR: 应用ID未配置' |
|
||||
ELSE 'OK' |
|
||||
END as app_id_check, |
|
||||
status, |
|
||||
tenant_id |
|
||||
FROM sys_payment |
|
||||
WHERE type = 0 |
|
||||
ORDER BY tenant_id; |
|
||||
|
|
||||
-- 3. 插入示例微信支付配置(请根据实际情况修改) |
|
||||
-- 注意:请将下面的值替换为您的实际配置 |
|
||||
/* |
|
||||
INSERT INTO sys_payment ( |
|
||||
name, |
|
||||
type, |
|
||||
code, |
|
||||
app_id, |
|
||||
mch_id, |
|
||||
api_key, |
|
||||
merchant_serial_number, |
|
||||
status, |
|
||||
tenant_id, |
|
||||
create_time, |
|
||||
update_time |
|
||||
) VALUES ( |
|
||||
'微信支付', |
|
||||
0, |
|
||||
'0', |
|
||||
'wx1234567890abcdef', -- 请替换为您的微信小程序AppID |
|
||||
'1723321338', -- 请替换为您的商户号 |
|
||||
'your_api_v3_key_here', -- 请替换为您的APIv3密钥 |
|
||||
'2B933F7C35014A1C363642623E4A62364B34C4EB', -- 请替换为您的商户证书序列号 |
|
||||
1, |
|
||||
10550, -- 请替换为您的租户ID |
|
||||
NOW(), |
|
||||
NOW() |
|
||||
) ON DUPLICATE KEY UPDATE |
|
||||
app_id = VALUES(app_id), |
|
||||
mch_id = VALUES(mch_id), |
|
||||
api_key = VALUES(api_key), |
|
||||
merchant_serial_number = VALUES(merchant_serial_number), |
|
||||
update_time = NOW(); |
|
||||
*/ |
|
||||
|
|
||||
-- 4. 检查特定租户的支付配置 |
|
||||
-- SELECT * FROM sys_payment WHERE tenant_id = 10550 AND type = 0; |
|
||||
|
|
||||
-- 5. 删除错误的支付配置(谨慎使用) |
|
||||
-- DELETE FROM sys_payment WHERE id = ?; |
|
@ -0,0 +1,101 @@ |
|||||
|
package com.gxwebsoft.test; |
||||
|
|
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.springframework.core.io.ClassPathResource; |
||||
|
import org.springframework.core.io.Resource; |
||||
|
|
||||
|
import java.io.File; |
||||
|
import java.io.IOException; |
||||
|
import java.io.InputStream; |
||||
|
import java.nio.file.Files; |
||||
|
import java.nio.file.Path; |
||||
|
|
||||
|
/** |
||||
|
* 异步通知证书修复验证测试 |
||||
|
*/ |
||||
|
public class NotificationCertificateFixTest { |
||||
|
|
||||
|
@Test |
||||
|
public void testCertificatePathFix() { |
||||
|
System.out.println("=== 异步通知证书路径修复验证 ==="); |
||||
|
|
||||
|
// 模拟异步通知中的证书路径构建逻辑
|
||||
|
String tenantId = "10550"; |
||||
|
String devCertPath = "dev"; |
||||
|
String certDir = "wechat"; |
||||
|
String privateKeyFile = "apiclient_key.pem"; |
||||
|
|
||||
|
// 修复后的路径构建逻辑
|
||||
|
String tenantCertPath = devCertPath + "/" + certDir + "/" + tenantId; |
||||
|
String privateKeyPath = tenantCertPath + "/" + privateKeyFile; |
||||
|
|
||||
|
System.out.println("租户ID: " + tenantId); |
||||
|
System.out.println("证书目录: " + tenantCertPath); |
||||
|
System.out.println("私钥路径: " + privateKeyPath); |
||||
|
|
||||
|
// 测试从classpath加载证书
|
||||
|
try { |
||||
|
Resource resource = new ClassPathResource(privateKeyPath); |
||||
|
System.out.println("证书资源存在: " + resource.exists()); |
||||
|
|
||||
|
if (resource.exists()) { |
||||
|
// 模拟CertificateLoader.loadFromClasspath的逻辑
|
||||
|
Path tempFile = Files.createTempFile("cert_", ".pem"); |
||||
|
try (InputStream inputStream = resource.getInputStream()) { |
||||
|
Files.copy(inputStream, tempFile, java.nio.file.StandardCopyOption.REPLACE_EXISTING); |
||||
|
} |
||||
|
|
||||
|
String tempPath = tempFile.toAbsolutePath().toString(); |
||||
|
System.out.println("✅ 证书加载成功: " + tempPath); |
||||
|
|
||||
|
// 验证临时文件
|
||||
|
File tempCertFile = new File(tempPath); |
||||
|
System.out.println("临时证书文件大小: " + tempCertFile.length() + " bytes"); |
||||
|
|
||||
|
// 清理临时文件
|
||||
|
Files.deleteIfExists(tempFile); |
||||
|
|
||||
|
} else { |
||||
|
System.err.println("❌ 证书文件不存在: " + privateKeyPath); |
||||
|
} |
||||
|
|
||||
|
} catch (IOException e) { |
||||
|
System.err.println("❌ 证书加载失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
|
||||
|
System.out.println("=== 测试完成 ==="); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testAllTenantCertificates() { |
||||
|
System.out.println("=== 测试所有租户证书 ==="); |
||||
|
|
||||
|
String[] tenantIds = {"10398", "10550"}; |
||||
|
String devCertPath = "dev"; |
||||
|
String certDir = "wechat"; |
||||
|
String privateKeyFile = "apiclient_key.pem"; |
||||
|
|
||||
|
for (String tenantId : tenantIds) { |
||||
|
System.out.println("\n--- 测试租户: " + tenantId + " ---"); |
||||
|
|
||||
|
String tenantCertPath = devCertPath + "/" + certDir + "/" + tenantId; |
||||
|
String privateKeyPath = tenantCertPath + "/" + privateKeyFile; |
||||
|
|
||||
|
System.out.println("证书路径: " + privateKeyPath); |
||||
|
|
||||
|
try { |
||||
|
Resource resource = new ClassPathResource(privateKeyPath); |
||||
|
if (resource.exists()) { |
||||
|
System.out.println("✅ 租户 " + tenantId + " 证书存在"); |
||||
|
} else { |
||||
|
System.out.println("❌ 租户 " + tenantId + " 证书不存在"); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 租户 " + tenantId + " 证书检查失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("\n=== 所有租户证书测试完成 ==="); |
||||
|
} |
||||
|
} |
@ -0,0 +1,134 @@ |
|||||
|
package com.gxwebsoft.test; |
||||
|
|
||||
|
import com.gxwebsoft.common.core.config.CertificateProperties; |
||||
|
import com.gxwebsoft.common.core.utils.CertificateLoader; |
||||
|
import com.gxwebsoft.common.core.utils.RedisUtil; |
||||
|
import com.gxwebsoft.common.system.entity.Payment; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.boot.test.context.SpringBootTest; |
||||
|
import org.springframework.test.context.ActiveProfiles; |
||||
|
|
||||
|
/** |
||||
|
* 微信支付配置验证测试 |
||||
|
*/ |
||||
|
@SpringBootTest |
||||
|
@ActiveProfiles("dev") |
||||
|
public class WechatPayConfigValidationTest { |
||||
|
|
||||
|
@Autowired |
||||
|
private CertificateProperties certConfig; |
||||
|
|
||||
|
@Autowired |
||||
|
private CertificateLoader certificateLoader; |
||||
|
|
||||
|
@Autowired |
||||
|
private RedisUtil redisUtil; |
||||
|
|
||||
|
@Test |
||||
|
public void testWechatPayConfigValidation() { |
||||
|
System.out.println("=== 微信支付配置验证 ==="); |
||||
|
|
||||
|
// 1. 检查配置文件中的 APIv3 密钥
|
||||
|
String configApiV3Key = certConfig.getWechatPay().getDev().getApiV3Key(); |
||||
|
System.out.println("配置文件 APIv3 密钥: " + configApiV3Key); |
||||
|
System.out.println("配置文件 APIv3 密钥长度: " + (configApiV3Key != null ? configApiV3Key.length() : 0)); |
||||
|
|
||||
|
// 2. 检查 Redis 中的支付配置
|
||||
|
String tenantId = "10550"; |
||||
|
String redisKey = "Payment:1:" + tenantId; |
||||
|
Payment payment = redisUtil.get(redisKey, Payment.class); |
||||
|
|
||||
|
if (payment != null) { |
||||
|
System.out.println("\n=== Redis 支付配置 ==="); |
||||
|
System.out.println("商户号: " + payment.getMchId()); |
||||
|
System.out.println("应用ID: " + payment.getAppId()); |
||||
|
System.out.println("数据库 APIv3 密钥: " + payment.getApiKey()); |
||||
|
System.out.println("数据库 APIv3 密钥长度: " + (payment.getApiKey() != null ? payment.getApiKey().length() : 0)); |
||||
|
System.out.println("商户证书序列号: " + payment.getMerchantSerialNumber()); |
||||
|
|
||||
|
// 3. 比较两个 APIv3 密钥
|
||||
|
System.out.println("\n=== APIv3 密钥比较 ==="); |
||||
|
boolean keysMatch = (configApiV3Key != null && configApiV3Key.equals(payment.getApiKey())); |
||||
|
System.out.println("配置文件与数据库密钥是否一致: " + keysMatch); |
||||
|
|
||||
|
if (!keysMatch) { |
||||
|
System.out.println("⚠️ 警告: 配置文件与数据库中的 APIv3 密钥不一致!"); |
||||
|
System.out.println("配置文件密钥: " + configApiV3Key); |
||||
|
System.out.println("数据库密钥: " + payment.getApiKey()); |
||||
|
} |
||||
|
|
||||
|
} else { |
||||
|
System.out.println("❌ 未找到 Redis 中的支付配置: " + redisKey); |
||||
|
|
||||
|
// 尝试其他可能的键格式
|
||||
|
String[] possibleKeys = { |
||||
|
"Payment:1:10550", |
||||
|
"Payment:0:10550", |
||||
|
"Payment:10", |
||||
|
"Payment:1" + "0" // Payment:10
|
||||
|
}; |
||||
|
|
||||
|
System.out.println("\n=== 尝试其他 Redis 键格式 ==="); |
||||
|
for (String key : possibleKeys) { |
||||
|
Payment p = redisUtil.get(key, Payment.class); |
||||
|
if (p != null) { |
||||
|
System.out.println("✅ 找到支付配置: " + key); |
||||
|
System.out.println(" 商户号: " + p.getMchId()); |
||||
|
System.out.println(" APIv3密钥: " + p.getApiKey()); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 4. 验证证书文件
|
||||
|
System.out.println("\n=== 证书文件验证 ==="); |
||||
|
String tenantCertPath = "dev/wechat/" + tenantId; |
||||
|
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); |
||||
|
|
||||
|
boolean certExists = certificateLoader.certificateExists(privateKeyPath); |
||||
|
System.out.println("证书文件存在: " + certExists); |
||||
|
System.out.println("证书路径: " + privateKeyPath); |
||||
|
|
||||
|
if (certExists) { |
||||
|
try { |
||||
|
String privateKey = certificateLoader.loadCertificatePath(privateKeyPath); |
||||
|
System.out.println("✅ 证书加载成功: " + privateKey); |
||||
|
} catch (Exception e) { |
||||
|
System.out.println("❌ 证书加载失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("\n=== 验证完成 ==="); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testApiV3KeyValidation() { |
||||
|
System.out.println("=== APIv3 密钥格式验证 ==="); |
||||
|
|
||||
|
String configKey = certConfig.getWechatPay().getDev().getApiV3Key(); |
||||
|
|
||||
|
if (configKey != null) { |
||||
|
System.out.println("APIv3 密钥: " + configKey); |
||||
|
System.out.println("密钥长度: " + configKey.length()); |
||||
|
|
||||
|
// APIv3 密钥应该是32位字符串
|
||||
|
if (configKey.length() == 32) { |
||||
|
System.out.println("✅ APIv3 密钥长度正确 (32位)"); |
||||
|
} else { |
||||
|
System.out.println("❌ APIv3 密钥长度错误,应为32位,实际为: " + configKey.length()); |
||||
|
} |
||||
|
|
||||
|
// 检查是否包含特殊字符
|
||||
|
boolean hasSpecialChars = !configKey.matches("^[a-zA-Z0-9]+$"); |
||||
|
if (hasSpecialChars) { |
||||
|
System.out.println("⚠️ APIv3 密钥包含特殊字符,可能导致解密失败"); |
||||
|
} else { |
||||
|
System.out.println("✅ APIv3 密钥格式正确 (仅包含字母和数字)"); |
||||
|
} |
||||
|
|
||||
|
} else { |
||||
|
System.out.println("❌ APIv3 密钥未配置"); |
||||
|
} |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue