Skip to content

Commit 8fe8e1b

Browse files
authored
Merge pull request #12 from wechatpay-apiv3/v0.1.6
V0.1.6
2 parents 3620c95 + 75beb32 commit 8fe8e1b

File tree

4 files changed

+73
-19
lines changed

4 files changed

+73
-19
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
## 项目状态
1010

11-
当前版本`0.1.5`为测试版本。请商户的专业技术人员在使用时注意系统和软件的正确性和兼容性,以及带来的风险。
11+
当前版本`0.1.6`为测试版本。请商户的专业技术人员在使用时注意系统和软件的正确性和兼容性,以及带来的风险。
1212

1313
## 环境要求
1414

@@ -27,7 +27,7 @@ repositories {
2727
}
2828
...
2929
dependencies {
30-
implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.1.5'
30+
implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.1.6'
3131
...
3232
}
3333
```
@@ -51,7 +51,7 @@ dependencies {
5151
<dependency>
5252
<groupId>com.github.wechatpay-apiv3</groupId>
5353
<artifactId>wechatpay-apache-httpclient</artifactId>
54-
<version>0.1.5</version>
54+
<version>0.1.6</version>
5555
</dependency>
5656
```
5757

build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
}
55

66
group 'com.github.wechatpay-apiv3'
7-
version '0.1.4'
7+
version '0.1.6'
88

99
sourceCompatibility = 1.8
1010
targetCompatibility = 1.8
@@ -14,15 +14,15 @@ repositories {
1414
}
1515

1616
ext {
17-
httpclient_version = "4.5.8"
18-
slf4j_version = "1.7.26"
17+
httpclient_version = "4.5.12"
18+
slf4j_version = "1.7.30"
1919
junit_version = "4.12"
20-
jackson_version = "2.9.7"
20+
jackson_version = "2.9.10"
2121
}
2222

2323
dependencies {
2424
api "org.apache.httpcomponents:httpclient:$httpclient_version"
25-
api "com.fasterxml.jackson.core:jackson-databind:$jackson_version"
25+
implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version"
2626
implementation "org.slf4j:slf4j-api:$slf4j_version"
2727
testImplementation "org.slf4j:slf4j-simple:$slf4j_version"
2828
testImplementation "junit:junit:$junit_version"

src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/AutoUpdateCertificatesVerifier.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.io.IOException;
1111
import java.security.GeneralSecurityException;
1212
import java.security.cert.CertificateExpiredException;
13+
import java.security.cert.CertificateFactory;
1314
import java.security.cert.CertificateNotYetValidException;
1415
import java.security.cert.X509Certificate;
1516
import java.time.Duration;
@@ -143,8 +144,10 @@ private List<X509Certificate> deserializeToCerts(byte[] apiV3Key, String body)
143144
.getBytes("utf-8"),
144145
encryptCertificateNode.get("ciphertext").toString().replaceAll("\"", ""));
145146

146-
X509Certificate x509Cert = PemUtil
147-
.loadCertificate(new ByteArrayInputStream(cert.getBytes("utf-8")));
147+
CertificateFactory cf = CertificateFactory.getInstance("X509");
148+
X509Certificate x509Cert = (X509Certificate) cf.generateCertificate(
149+
new ByteArrayInputStream(cert.getBytes("utf-8"))
150+
);
148151
try {
149152
x509Cert.checkValidity();
150153
} catch (CertificateExpiredException | CertificateNotYetValidException e) {

src/main/java/com/wechat/pay/contrib/apache/httpclient/auth/WechatPay2Validator.java

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import com.wechat.pay.contrib.apache.httpclient.Validator;
44
import java.io.IOException;
5+
import java.time.DateTimeException;
6+
import java.time.Duration;
7+
import java.time.Instant;
58
import org.apache.http.Header;
69
import org.apache.http.HttpEntity;
710
import org.apache.http.client.methods.CloseableHttpResponse;
@@ -19,24 +22,72 @@ public WechatPay2Validator(Verifier verifier) {
1922
this.verifier = verifier;
2023
}
2124

25+
static RuntimeException parameterError(String message, Object... args) {
26+
message = String.format(message, args);
27+
return new IllegalArgumentException("parameter error: " + message);
28+
}
29+
30+
static RuntimeException verifyFail(String message, Object... args) {
31+
message = String.format(message, args);
32+
return new IllegalArgumentException("signature verify fail: " + message);
33+
}
34+
2235
@Override
2336
public final boolean validate(CloseableHttpResponse response) throws IOException {
24-
Header serialNo = response.getFirstHeader("Wechatpay-Serial");
25-
Header sign = response.getFirstHeader("Wechatpay-Signature");
26-
Header timestamp = response.getFirstHeader("Wechatpay-TimeStamp");
27-
Header nonce = response.getFirstHeader("Wechatpay-Nonce");
37+
try {
38+
validateParameters(response);
39+
40+
String message = buildMessage(response);
41+
String serial = response.getFirstHeader("Wechatpay-Serial").getValue();
42+
String signature = response.getFirstHeader("Wechatpay-Signature").getValue();
2843

29-
// todo: check timestamp
30-
if (timestamp == null || nonce == null || serialNo == null || sign == null) {
44+
if (!verifier.verify(serial, message.getBytes("utf-8"), signature)) {
45+
throw verifyFail("serial=[%s] message=[%s] sign=[%s], request-id=[%s]",
46+
serial, message, signature,
47+
response.getFirstHeader("Request-ID").getValue());
48+
}
49+
} catch (IllegalArgumentException e) {
50+
log.warn(e.getMessage());
3151
return false;
3252
}
3353

34-
String message = buildMessage(response);
35-
return verifier.verify(serialNo.getValue(), message.getBytes("utf-8"), sign.getValue());
54+
return true;
55+
}
56+
57+
protected final void validateParameters(CloseableHttpResponse response) {
58+
String requestId;
59+
if (!response.containsHeader("Request-ID")) {
60+
throw parameterError("empty Request-ID");
61+
} else {
62+
requestId = response.getFirstHeader("Request-ID").getValue();
63+
}
64+
65+
if (!response.containsHeader("Wechatpay-Serial")) {
66+
throw parameterError("empty Wechatpay-Serial, request-id=[%s]", requestId);
67+
} else if (!response.containsHeader("Wechatpay-Signature")){
68+
throw parameterError("empty Wechatpay-Signature, request-id=[%s]", requestId);
69+
} else if (!response.containsHeader("Wechatpay-Timestamp")) {
70+
throw parameterError("empty Wechatpay-Timestamp, request-id=[%s]", requestId);
71+
} else if (!response.containsHeader("Wechatpay-Nonce")) {
72+
throw parameterError("empty Wechatpay-Nonce, request-id=[%s]", requestId);
73+
} else {
74+
Header timestamp = response.getFirstHeader("Wechatpay-Timestamp");
75+
try {
76+
Instant instant = Instant.ofEpochSecond(Long.parseLong(timestamp.getValue()));
77+
// 拒绝5分钟之外的应答
78+
if (Duration.between(instant, Instant.now()).abs().toMinutes() >= 5) {
79+
throw parameterError("timestamp=[%s] expires, request-id=[%s]",
80+
timestamp.getValue(), requestId);
81+
}
82+
} catch (DateTimeException | NumberFormatException e) {
83+
throw parameterError("invalid timestamp=[%s], request-id=[%s]",
84+
timestamp.getValue(), requestId);
85+
}
86+
}
3687
}
3788

3889
protected final String buildMessage(CloseableHttpResponse response) throws IOException {
39-
String timestamp = response.getFirstHeader("Wechatpay-TimeStamp").getValue();
90+
String timestamp = response.getFirstHeader("Wechatpay-Timestamp").getValue();
4091
String nonce = response.getFirstHeader("Wechatpay-Nonce").getValue();
4192

4293
String body = getResponseBody(response);

0 commit comments

Comments
 (0)