OmgStoreCredentialVerifierTest.java 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package com.ruoyi.app.omgpay;
  2. import org.junit.jupiter.api.BeforeEach;
  3. import org.junit.jupiter.api.Test;
  4. import java.net.URLEncoder;
  5. import java.nio.charset.StandardCharsets;
  6. import java.time.Clock;
  7. import java.time.Instant;
  8. import java.time.ZoneOffset;
  9. import java.util.LinkedHashMap;
  10. import java.util.Map;
  11. import java.util.Set;
  12. import static org.junit.jupiter.api.Assertions.assertEquals;
  13. import static org.junit.jupiter.api.Assertions.assertThrows;
  14. import static org.mockito.ArgumentMatchers.anyMap;
  15. import static org.mockito.Mockito.mock;
  16. import static org.mockito.Mockito.verify;
  17. import static org.mockito.Mockito.when;
  18. class OmgStoreCredentialVerifierTest {
  19. private static final String HASH_KEY = "5294y06JbISpM5x9";
  20. private static final String HASH_IV = "v77hoKGq4kWxNNIS";
  21. private OmgPaymentQueryGateway gateway;
  22. private OmgCheckMacSigner signer;
  23. private OmgStoreCredentialVerifier verifier;
  24. @BeforeEach
  25. void setUp() {
  26. gateway = mock(OmgPaymentQueryGateway.class);
  27. signer = new OmgCheckMacSigner();
  28. verifier = new OmgStoreCredentialVerifier(gateway, new OmgQueryResponseParser(), signer,
  29. Clock.fixed(Instant.ofEpochSecond(1_786_598_400L), ZoneOffset.UTC));
  30. }
  31. @Test
  32. void signsAStageProbeAndVerifiesEveryReturnedField() {
  33. when(gateway.query(anyMap())).thenAnswer(invocation -> signedResponse(invocation.getArgument(0)));
  34. Map<String, String> response = verifier.verify("1000031", HASH_KEY, HASH_IV);
  35. assertEquals("0", response.get("TradeStatus"));
  36. @SuppressWarnings("unchecked")
  37. var request = org.mockito.ArgumentCaptor.forClass(Map.class);
  38. verify(gateway).query(request.capture());
  39. assertEquals(Set.of("MerchantID", "MerchantTradeNo", "TimeStamp", "CheckMacValue"),
  40. request.getValue().keySet());
  41. assertEquals("1000031", request.getValue().get("MerchantID"));
  42. assertEquals("OMGVERIFY1786598400", request.getValue().get("MerchantTradeNo"));
  43. assertEquals("1786598400", request.getValue().get("TimeStamp"));
  44. LinkedHashMap<String, String> signingFields = new LinkedHashMap<>(request.getValue());
  45. String actual = signingFields.remove("CheckMacValue");
  46. assertEquals(signer.sign(signingFields, HASH_KEY, HASH_IV), actual);
  47. }
  48. @Test
  49. void rejectsAnyTamperedExtraResponseField() {
  50. when(gateway.query(anyMap())).thenAnswer(invocation ->
  51. signedResponse(invocation.getArgument(0)).replace("FutureEmptyField=", "FutureEmptyField=tampered"));
  52. assertThrows(IllegalArgumentException.class,
  53. () -> verifier.verify("1000031", HASH_KEY, HASH_IV));
  54. }
  55. private String signedResponse(Map<String, String> request) {
  56. LinkedHashMap<String, String> fields = new LinkedHashMap<>();
  57. fields.put("MerchantID", request.get("MerchantID"));
  58. fields.put("MerchantTradeNo", request.get("MerchantTradeNo"));
  59. fields.put("TradeStatus", "0");
  60. fields.put("RtnMsg", "Not found");
  61. fields.put("FutureEmptyField", "");
  62. fields.put("CheckMacValue", signer.sign(fields, HASH_KEY, HASH_IV));
  63. return fields.entrySet().stream()
  64. .map(entry -> encode(entry.getKey()) + "=" + encode(entry.getValue()))
  65. .collect(java.util.stream.Collectors.joining("&"));
  66. }
  67. private static String encode(String value) {
  68. return URLEncoder.encode(value, StandardCharsets.UTF_8);
  69. }
  70. }