| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- package com.ruoyi.app.utils.omg;
- import org.junit.jupiter.api.Test;
- import java.util.Comparator;
- import java.util.LinkedHashMap;
- import java.util.Map;
- import static org.junit.jupiter.api.Assertions.assertEquals;
- import static org.junit.jupiter.api.Assertions.assertFalse;
- import static org.junit.jupiter.api.Assertions.assertNotEquals;
- import static org.junit.jupiter.api.Assertions.assertTrue;
- class OmgCheckMacValueTest {
- @Test
- void generatesOfficialEcpayLogisticsVector() {
- Map<String, String> params = new LinkedHashMap<>();
- params.put("MerchantID", "2000933");
- params.put("MerchantTradeNo", "A20130312153023");
- params.put("MerchantTradeDate", "2013/03/12 15:30:23");
- params.put("LogisticsType", "CVS");
- params.put("LogisticsSubType", "FAMIC2C");
- params.put("GoodsAmount", "1000");
- params.put("IsCollection", "N");
- params.put("ServerReplyURL", "https://www.ecpay.com.tw/ServerReplyURL");
- params.put("SenderName", "SteveJones");
- params.put("ReceiverName", "MarkHarrison");
- params.put("ReceiverStoreID", "001779");
- assertEquals("754C5D1365035DA34D2CD91CC256F18C",
- OmgCheckMacValue.generate(params, "XBERn1YOvpM9nfZc", "h1ONHk4P4yqbl5LK", "MD5"));
- }
- @Test
- void verifiesSha256WithoutDependingOnHexCase() {
- Map<String, String> params = new LinkedHashMap<>();
- params.put("MerchantID", "2000132");
- params.put("MerchantTradeNo", "OMG12345678901234567");
- String signature = OmgCheckMacValue.generate(params, "5294y06JbISpM5x9", "v77hoKGq4kWxNNIS");
- params.put("CheckMacValue", signature.toLowerCase());
- assertTrue(OmgCheckMacValue.verify(params, "5294y06JbISpM5x9", "v77hoKGq4kWxNNIS"));
- }
- @Test
- void rejectsMalformedOrIncorrectSignature() {
- Map<String, String> params = new LinkedHashMap<>();
- params.put("MerchantID", "2000132");
- params.put("CheckMacValue", "not-a-sha256");
- assertFalse(OmgCheckMacValue.verify(params, "key", "iv"));
- params.put("CheckMacValue", "0".repeat(64));
- assertFalse(OmgCheckMacValue.verify(params, "key", "iv"));
- }
- /**
- * 回归 bugB(2026-08-12):OMG QueryTradeInfo 响应字段大小写混合,服务端 CheckMacValue 按
- * 大小写不敏感排序计算。旧实现用 Comparator.naturalOrder()(ASCII 大小写敏感)排序,混合字段下
- * 与 OMG 分歧 → 验签失败(生产订单 991786433092835 实测 receivedCMV==ci_inc 坐实)。
- *
- * <p>本用例构造同形响应(首字母大写的 AlipayID/CustomField1/MerchantID 与首字母小写的
- * amount/auth_code/card4no/eci/gwsr/process_date/red_dan 并存),先用「大小写不敏感」生成 OMG 侧
- * 签名,再断言 verify() 通过。修复前 verify 走 naturalOrder 会算出不同签名而失败。
- */
- @Test
- void verifiesQueryTradeInfoResponseWithCaseInsensitiveKeyOrder() {
- Map<String, String> resp = new LinkedHashMap<>();
- resp.put("MerchantID", "1000031");
- resp.put("MerchantTradeNo", "OMG10C9AA21B1814EE29");
- resp.put("TradeAmt", "97");
- resp.put("TradeDate", "2026/08/11 17:06:42");
- resp.put("TradeNo", "2608111706428239");
- resp.put("TradeStatus", "10200095");
- resp.put("ItemName", "order 991786433092835");
- resp.put("HandlingCharge", "0");
- resp.put("PaymentTypeChargeFee", "0");
- // §2 额外回传(空值),首字母大小写混合 —— 触发排序分歧的关键
- resp.put("AlipayID", "");
- resp.put("CustomField1", "");
- resp.put("amount", "");
- resp.put("auth_code", "");
- resp.put("card4no", "");
- resp.put("eci", "");
- resp.put("gwsr", "");
- resp.put("process_date", "");
- resp.put("red_dan", "");
- String key = "5294y06JbISpM5x9";
- String iv = "v77hoKGq4kWxNNIS";
- // OMG 侧签名:大小写不敏感排序,保留空值字段
- String omgCmv = OmgCheckMacValue.generate(resp, key, iv,
- String.CASE_INSENSITIVE_ORDER, false);
- // 前置断言:本字段集必须使两种排序产生不同签名,否则用例无法锁定该 bug
- String sensitiveCmv = OmgCheckMacValue.generate(resp, key, iv,
- Comparator.naturalOrder(), false);
- assertNotEquals(sensitiveCmv, omgCmv,
- "测试字段集必须使大小写敏感/不敏感排序产生不同签名,否则用例无效");
- resp.put("CheckMacValue", omgCmv);
- assertTrue(OmgCheckMacValue.verify(resp, key, iv),
- "verify 必须按大小写不敏感排序以匹配 OMG 服务端算法");
- }
- }
|