From 491c3fdaef273dad2dfaa2d27e0ac4c3206574c1 Mon Sep 17 00:00:00 2001 From: xy-peng Date: Tue, 12 May 2020 11:42:42 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=AA=8C=E7=AD=BE?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E6=88=B3HTTP=E5=A4=B4=E6=8B=BC=E5=86=99,=20f?= =?UTF-8?q?ixes=20https://github.com/wechatpay-apiv3/wechatpay-apache-http?= =?UTF-8?q?client/issues/10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pay/contrib/apache/httpclient/auth/WechatPay2Validator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java b/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java index b0c6f9b..c6077a4 100644 --- a/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java +++ b/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java @@ -36,7 +36,7 @@ public final boolean validate(CloseableHttpResponse response) throws IOException } protected final String buildMessage(CloseableHttpResponse response) throws IOException { - String timestamp = response.getFirstHeader("Wechatpay-TimeStamp").getValue(); + String timestamp = response.getFirstHeader("Wechatpay-Timestamp").getValue(); String nonce = response.getFirstHeader("Wechatpay-Nonce").getValue(); String body = getResponseBody(response); From 0865ea971d701167adc41b199ebb0716593cd552 Mon Sep 17 00:00:00 2001 From: xy-peng Date: Tue, 12 May 2020 15:29:46 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BD=BF=E7=94=A8CertificateFactory?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=9B=B4=E6=96=B0=E7=9A=84=E8=AF=81=E4=B9=A6?= =?UTF-8?q?,=20fixes=20https://github.com/wechatpay-apiv3/wechatpay-apache?= =?UTF-8?q?-httpclient/issues/9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../httpclient/auth/AutoUpdateCertificatesVerifier.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/AutoUpdateCertificatesVerifier.java b/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/AutoUpdateCertificatesVerifier.java index b1d5b78..40ff0a8 100644 --- a/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/AutoUpdateCertificatesVerifier.java +++ b/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/AutoUpdateCertificatesVerifier.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.security.GeneralSecurityException; import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.time.Duration; @@ -143,8 +144,10 @@ private List deserializeToCerts(byte[] apiV3Key, String body) .getBytes("utf-8"), encryptCertificateNode.get("ciphertext").toString().replaceAll("\"", "")); - X509Certificate x509Cert = PemUtil - .loadCertificate(new ByteArrayInputStream(cert.getBytes("utf-8"))); + CertificateFactory cf = CertificateFactory.getInstance("X509"); + X509Certificate x509Cert = (X509Certificate) cf.generateCertificate( + new ByteArrayInputStream(cert.getBytes("utf-8")) + ); try { x509Cert.checkValidity(); } catch (CertificateExpiredException | CertificateNotYetValidException e) { From e87f47656912ca0d44219f7c836d9ea86e127d90 Mon Sep 17 00:00:00 2001 From: xy-peng Date: Thu, 14 May 2020 11:59:01 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=E9=AA=8C=E7=AD=BE=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0log=EF=BC=8C=20=E5=A2=9E=E5=8A=A0=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=88=B35=E5=88=86=E9=92=9F=E8=BF=87=E6=9C=9F=E6=8B=92?= =?UTF-8?q?=E7=BB=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../httpclient/auth/WechatPay2Validator.java | 67 ++++++++++++++++--- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java b/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java index c6077a4..533b3b3 100644 --- a/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java +++ b/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java @@ -2,6 +2,9 @@ import com.wechat.pay.contrib.apache.httpclient.Validator; import java.io.IOException; +import java.time.DateTimeException; +import java.time.Duration; +import java.time.Instant; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; @@ -19,20 +22,68 @@ public WechatPay2Validator(Verifier verifier) { this.verifier = verifier; } + static RuntimeException parameterError(String message, Object... args) { + message = String.format(message, args); + return new IllegalArgumentException("parameter error: " + message); + } + + static RuntimeException verifyFail(String message, Object... args) { + message = String.format(message, args); + return new IllegalArgumentException("signature verify fail: " + message); + } + @Override public final boolean validate(CloseableHttpResponse response) throws IOException { - Header serialNo = response.getFirstHeader("Wechatpay-Serial"); - Header sign = response.getFirstHeader("Wechatpay-Signature"); - Header timestamp = response.getFirstHeader("Wechatpay-TimeStamp"); - Header nonce = response.getFirstHeader("Wechatpay-Nonce"); + try { + validateParameters(response); + + String message = buildMessage(response); + String serial = response.getFirstHeader("Wechatpay-Serial").getValue(); + String signature = response.getFirstHeader("Wechatpay-Signature").getValue(); - // todo: check timestamp - if (timestamp == null || nonce == null || serialNo == null || sign == null) { + if (!verifier.verify(serial, message.getBytes("utf-8"), signature)) { + throw verifyFail("serial=[%s] message=[%s] sign=[%s], request-id=[%s]", + serial, message, signature, + response.getFirstHeader("Request-ID").getValue()); + } + } catch (IllegalArgumentException e) { + log.warn(e.getMessage()); return false; } - String message = buildMessage(response); - return verifier.verify(serialNo.getValue(), message.getBytes("utf-8"), sign.getValue()); + return true; + } + + protected final void validateParameters(CloseableHttpResponse response) { + String requestId; + if (!response.containsHeader("Request-ID")) { + throw parameterError("empty Request-ID"); + } else { + requestId = response.getFirstHeader("Request-ID").getValue(); + } + + if (!response.containsHeader("Wechatpay-Serial")) { + throw parameterError("empty Wechatpay-Serial, request-id=[%s]", requestId); + } else if (!response.containsHeader("Wechatpay-Signature")){ + throw parameterError("empty Wechatpay-Signature, request-id=[%s]", requestId); + } else if (!response.containsHeader("Wechatpay-Timestamp")) { + throw parameterError("empty Wechatpay-Timestamp, request-id=[%s]", requestId); + } else if (!response.containsHeader("Wechatpay-Nonce")) { + throw parameterError("empty Wechatpay-Nonce, request-id=[%s]", requestId); + } else { + Header timestamp = response.getFirstHeader("Wechatpay-Timestamp"); + try { + Instant instant = Instant.ofEpochSecond(Integer.parseInt(timestamp.getValue())); + // 拒绝5分钟之前的应答 + if (Duration.between(instant, Instant.now()).toMinutes() >= 5) { + throw parameterError("timestamp=[%s] expires, request-id=[%s]", + timestamp.getValue(), requestId); + } + } catch (DateTimeException | NumberFormatException e) { + throw parameterError("invalid timestamp=[%s], request-id=[%s]", + timestamp.getValue(), requestId); + } + } } protected final String buildMessage(CloseableHttpResponse response) throws IOException { From e63efacc6dd7a02ae86783651b60bc88864b08a9 Mon Sep 17 00:00:00 2001 From: xy-peng Date: Thu, 14 May 2020 15:42:30 +0800 Subject: [PATCH 4/5] update version to 0.1.6 --- README.md | 6 +++--- build.gradle | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index faa6104..0ab44c5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ## 项目状态 -当前版本`0.1.5`为测试版本。请商户的专业技术人员在使用时注意系统和软件的正确性和兼容性,以及带来的风险。 +当前版本`0.1.6`为测试版本。请商户的专业技术人员在使用时注意系统和软件的正确性和兼容性,以及带来的风险。 ## 环境要求 @@ -27,7 +27,7 @@ repositories { } ... dependencies { - implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.1.5' + implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.1.6' ... } ``` @@ -51,7 +51,7 @@ dependencies { com.github.wechatpay-apiv3 wechatpay-apache-httpclient - 0.1.5 + 0.1.6 ``` diff --git a/build.gradle b/build.gradle index 44ffd11..c8bed7c 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { } group 'com.github.wechatpay-apiv3' -version '0.1.4' +version '0.1.6' sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -14,15 +14,15 @@ repositories { } ext { - httpclient_version = "4.5.8" - slf4j_version = "1.7.26" + httpclient_version = "4.5.12" + slf4j_version = "1.7.30" junit_version = "4.12" - jackson_version = "2.9.7" + jackson_version = "2.9.10" } dependencies { api "org.apache.httpcomponents:httpclient:$httpclient_version" - api "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" implementation "org.slf4j:slf4j-api:$slf4j_version" testImplementation "org.slf4j:slf4j-simple:$slf4j_version" testImplementation "junit:junit:$junit_version" From 75beb3284659c27d65a1add320140d51ed84db8c Mon Sep 17 00:00:00 2001 From: xy-peng Date: Thu, 14 May 2020 17:56:19 +0800 Subject: [PATCH 5/5] =?UTF-8?q?Long.ParseLong(timestamp);=20=E6=8B=92?= =?UTF-8?q?=E7=BB=9D5=E5=88=86=E9=92=9F=E4=B9=8B=E5=A4=96=E7=9A=84?= =?UTF-8?q?=E5=BA=94=E7=AD=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../contrib/apache/httpclient/auth/WechatPay2Validator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java b/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java index 533b3b3..d9835d6 100644 --- a/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java +++ b/src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java @@ -73,9 +73,9 @@ protected final void validateParameters(CloseableHttpResponse response) { } else { Header timestamp = response.getFirstHeader("Wechatpay-Timestamp"); try { - Instant instant = Instant.ofEpochSecond(Integer.parseInt(timestamp.getValue())); - // 拒绝5分钟之前的应答 - if (Duration.between(instant, Instant.now()).toMinutes() >= 5) { + Instant instant = Instant.ofEpochSecond(Long.parseLong(timestamp.getValue())); + // 拒绝5分钟之外的应答 + if (Duration.between(instant, Instant.now()).abs().toMinutes() >= 5) { throw parameterError("timestamp=[%s] expires, request-id=[%s]", timestamp.getValue(), requestId); }