From c305dfaae402ad2f7f1c3e4d4985632f20681bf3 Mon Sep 17 00:00:00 2001 From: ziin Date: Mon, 15 Dec 2025 21:21:47 +0800 Subject: [PATCH] =?UTF-8?q?fix(apple):=20=E5=A2=9E=E5=8A=A0=E6=97=A0?= =?UTF-8?q?=E6=95=88=E6=94=B6=E6=8D=AE=E5=8E=9F=E5=9B=A0=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=B9=B6=E8=A1=A5=E5=85=85=E8=AE=A2=E9=98=85=E8=BF=87=E6=9C=9F?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E8=B0=83=E8=AF=95=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yolo/keyborad/config/LLMConfig.java | 4 ++++ .../controller/AppleReceiptController.java | 4 +++- .../service/impl/ApplePurchaseServiceImpl.java | 1 + .../service/impl/AppleReceiptServiceImpl.java | 3 +++ .../java/com/yolo/keyborad/utils/JwtParser.java | 15 +++++++++++++-- 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/yolo/keyborad/config/LLMConfig.java b/src/main/java/com/yolo/keyborad/config/LLMConfig.java index eb08d6f..a8b97ff 100644 --- a/src/main/java/com/yolo/keyborad/config/LLMConfig.java +++ b/src/main/java/com/yolo/keyborad/config/LLMConfig.java @@ -12,6 +12,9 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.util.MultiValueMap; + +import java.util.Map; /* @@ -32,6 +35,7 @@ public class LLMConfig { public OpenAiApi openAiApi() { return OpenAiApi.builder() .apiKey(apiKey) + .headers(MultiValueMap.fromSingleValue(Map.of("X-Title", "key of love"))) .baseUrl(baseUrl) .build(); } diff --git a/src/main/java/com/yolo/keyborad/controller/AppleReceiptController.java b/src/main/java/com/yolo/keyborad/controller/AppleReceiptController.java index c42b9bf..21160cc 100644 --- a/src/main/java/com/yolo/keyborad/controller/AppleReceiptController.java +++ b/src/main/java/com/yolo/keyborad/controller/AppleReceiptController.java @@ -36,6 +36,7 @@ public class AppleReceiptController { private final ApplePurchaseService applePurchaseService; private final SignedDataVerifier signedDataVerifier; + public AppleReceiptController(AppleReceiptService appleReceiptService, ApplePurchaseService applePurchaseService, SignedDataVerifier signedDataVerifier) { @@ -83,12 +84,13 @@ public class AppleReceiptController { */ @PostMapping("/notification") public BaseResponse receiveNotification(@RequestBody Map body, HttpServletRequest request) { + + if (body == null) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "body 不能为空"); } // 从请求体中获取 Apple 签名的载荷 String signedPayload = body.get("signedPayload"); - // 校验 signedPayload 是否为空 if (signedPayload == null || signedPayload.isBlank()) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "signedPayload 不能为空"); diff --git a/src/main/java/com/yolo/keyborad/service/impl/ApplePurchaseServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/ApplePurchaseServiceImpl.java index d3d4c17..ba870f8 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/ApplePurchaseServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/ApplePurchaseServiceImpl.java @@ -70,6 +70,7 @@ public class ApplePurchaseServiceImpl implements ApplePurchaseService { public void processPurchase(Long userId, AppleReceiptValidationResult validationResult) { // 1. 校验收据有效性 if (validationResult == null || !validationResult.isValid()) { + log.error("Invalid receipt, reason={}", validationResult.getReason()); throw new BusinessException(ErrorCode.RECEIPT_INVALID); } diff --git a/src/main/java/com/yolo/keyborad/service/impl/AppleReceiptServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/AppleReceiptServiceImpl.java index 6754eee..0001e2d 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/AppleReceiptServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/AppleReceiptServiceImpl.java @@ -86,6 +86,8 @@ public class AppleReceiptServiceImpl implements AppleReceiptService { try { // 1. 从收据里解析出 transactionId(不做验证,只是解析 ASN.1) String transactionId = receiptUtility.extractTransactionIdFromAppReceipt(appReceipt); +// todo 验证服务器传输的transactionId +// String transactionId = receiptUtility.extractTransactionIdFromTransactionReceipt(appReceipt); if (transactionId == null) { return invalid("no_transaction_id_in_receipt"); } @@ -193,6 +195,7 @@ public class AppleReceiptServiceImpl implements AppleReceiptService { // 有 expiresDate 的一般是订阅(自动续订等),过期就无效 if (payload.getExpiresDate() != null) { long now = System.currentTimeMillis(); + log.error("Now Date:{} ,Expires Date: {}",now, payload.getExpiresDate()); return now < payload.getExpiresDate(); } diff --git a/src/main/java/com/yolo/keyborad/utils/JwtParser.java b/src/main/java/com/yolo/keyborad/utils/JwtParser.java index b6fc4d8..22970c6 100644 --- a/src/main/java/com/yolo/keyborad/utils/JwtParser.java +++ b/src/main/java/com/yolo/keyborad/utils/JwtParser.java @@ -56,9 +56,20 @@ public class JwtParser { // 获取第一个证书(Base64 编码,标准格式非URL安全格式) String certBase64 = x5cArray.getString(0); - + + // 调试信息 + System.out.println("Cert Base64 length: " + certBase64.length()); + System.out.println("First 50 chars: " + certBase64.substring(0, Math.min(50, certBase64.length()))); + // x5c 中的证书使用标准 Base64 编码(非 URL 安全编码) - byte[] certBytes = Base64.getDecoder().decode(certBase64); + byte[] certBytes; + try { + certBytes = Base64.getDecoder().decode(certBase64); // 使用标准 Base64 解码 + System.out.println("Decoded cert bytes length: " + certBytes.length); + } catch (IllegalArgumentException e) { + System.err.println("Base64 decode error: " + e.getMessage()); + throw new Exception("Failed to decode certificate from x5c", e); + } // 生成 X509 证书并提取公钥 CertificateFactory certFactory = CertificateFactory.getInstance("X.509");