node-easywechat 3.5.10 → 3.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/dist/Pay/Application.d.ts +0 -5
- package/dist/Pay/Application.js +1 -34
- package/dist/Pay/Contracts/MerchantInterface.d.ts +18 -4
- package/dist/Pay/Contracts/MerchantInterface.js +16 -2
- package/dist/Pay/Contracts/ValidatorInterface.d.ts +1 -1
- package/dist/Pay/Contracts/ValidatorInterface.js +1 -1
- package/dist/Pay/Merchant.d.ts +9 -3
- package/dist/Pay/Merchant.js +59 -3
- package/dist/Pay/Signature.js +12 -1
- package/dist/Pay/Validator.d.ts +1 -1
- package/dist/Pay/Validator.js +38 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -60,11 +60,6 @@ declare class Application implements ApplicationInterface {
|
|
|
60
60
|
* @returns
|
|
61
61
|
*/
|
|
62
62
|
protected getHttpClientDefaultOptions(): Record<string, any>;
|
|
63
|
-
/**
|
|
64
|
-
* 如果未配置平台证书,则尝试从接口读取
|
|
65
|
-
* @param force 是否强制读取,默认:false
|
|
66
|
-
*/
|
|
67
|
-
loadPlatformCerts(force?: boolean): Promise<void>;
|
|
68
63
|
}
|
|
69
64
|
interface Application extends ConfigMixin, CacheMixin, ServerRequestMixin, HttpClientMixin {
|
|
70
65
|
}
|
package/dist/Pay/Application.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
4
|
};
|
|
@@ -24,8 +15,6 @@ const Utils_2 = __importDefault(require("./Utils"));
|
|
|
24
15
|
const Config_1 = __importDefault(require("../OfficialAccount/Config"));
|
|
25
16
|
const Client_1 = __importDefault(require("./Client"));
|
|
26
17
|
const Validator_1 = __importDefault(require("./Validator"));
|
|
27
|
-
const PublicKey_1 = require("../Core/Support/PublicKey");
|
|
28
|
-
const AES_1 = require("../Core/Support/AES");
|
|
29
18
|
/**
|
|
30
19
|
* 微信支付应用
|
|
31
20
|
*/
|
|
@@ -47,7 +36,7 @@ class Application {
|
|
|
47
36
|
getMerchant() {
|
|
48
37
|
var _a;
|
|
49
38
|
if (!this.merchant) {
|
|
50
|
-
this.merchant = new Merchant_1.default(this.config.get('mch_id'), this.config.get('private_key'), this.config.get('certificate'), this.config.get('secret_key'), this.config.get('v2_secret_key'), (_a = this.config.get('platform_certs')) !== null && _a !== void 0 ? _a : []);
|
|
39
|
+
this.merchant = new Merchant_1.default(this.config.get('mch_id'), this.config.get('private_key'), this.config.get('certificate'), this.config.get('secret_key'), this.config.get('v2_secret_key'), (_a = this.config.get('platform_certs')) !== null && _a !== void 0 ? _a : [], this);
|
|
51
40
|
}
|
|
52
41
|
return this.merchant;
|
|
53
42
|
}
|
|
@@ -128,28 +117,6 @@ class Application {
|
|
|
128
117
|
baseURL: 'https://api.mch.weixin.qq.com',
|
|
129
118
|
}, this.getConfig().get('http'));
|
|
130
119
|
}
|
|
131
|
-
/**
|
|
132
|
-
* 如果未配置平台证书,则尝试从接口读取
|
|
133
|
-
* @param force 是否强制读取,默认:false
|
|
134
|
-
*/
|
|
135
|
-
loadPlatformCerts(force = false) {
|
|
136
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
137
|
-
let exists_certs = this.config.get('platform_certs', []);
|
|
138
|
-
if (force || !exists_certs || exists_certs.length === 0) {
|
|
139
|
-
let response = yield this.getClient().get('/v3/certificates');
|
|
140
|
-
let data = response.toObject();
|
|
141
|
-
if (data.data && data.data.length > 0) {
|
|
142
|
-
let certs = {};
|
|
143
|
-
let key = this.config.get('secret_key');
|
|
144
|
-
data.data.forEach((item) => {
|
|
145
|
-
let content = AES_1.AES_GCM.decrypt(item.encrypt_certificate.ciphertext, key, item.encrypt_certificate.nonce, item.encrypt_certificate.associated_data).toString();
|
|
146
|
-
certs[item.serial_no] = PublicKey_1.PublicKey.createByCertificateContent(content, item.serial_no);
|
|
147
|
-
});
|
|
148
|
-
this.getMerchant().setPlatformCerts(certs);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
120
|
}
|
|
154
121
|
;
|
|
155
122
|
;
|
|
@@ -26,15 +26,29 @@ declare abstract class MerchantInterface {
|
|
|
26
26
|
*/
|
|
27
27
|
getCertificate(): PublicKey;
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
29
|
+
* 获取平台证书缓存名称
|
|
30
|
+
*/
|
|
31
|
+
getPlatformCertKey(): string;
|
|
32
|
+
/**
|
|
33
|
+
* 设置平台证书缓存名称
|
|
34
|
+
* @param key
|
|
35
|
+
*/
|
|
36
|
+
setPlatformCertKey(key: string): this;
|
|
37
|
+
/**
|
|
38
|
+
* 更具证书序列号获取平台证书
|
|
30
39
|
* @param serial
|
|
31
40
|
* @returns
|
|
32
41
|
*/
|
|
33
|
-
getPlatformCert(serial: string): PublicKey
|
|
42
|
+
getPlatformCert(serial: string): Promise<PublicKey>;
|
|
43
|
+
/**
|
|
44
|
+
* 获取平台证书
|
|
45
|
+
* @param force 是否强制刷新缓存
|
|
46
|
+
*/
|
|
47
|
+
loadPlatformCerts(force: boolean): void;
|
|
34
48
|
/**
|
|
35
49
|
* 设置平台证书
|
|
36
|
-
* @param certs 键名:序列号,键值:PublicKey
|
|
50
|
+
* @param certs 键名:序列号,键值:PublicKey实例或者文件内容字符串
|
|
37
51
|
*/
|
|
38
|
-
setPlatformCerts(certs: Record<string, PublicKey>): void;
|
|
52
|
+
setPlatformCerts(certs: Record<string, PublicKey | string>): void;
|
|
39
53
|
}
|
|
40
54
|
export = MerchantInterface;
|
|
@@ -25,14 +25,28 @@ class MerchantInterface {
|
|
|
25
25
|
*/
|
|
26
26
|
getCertificate() { return null; }
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* 获取平台证书缓存名称
|
|
29
|
+
*/
|
|
30
|
+
getPlatformCertKey() { return null; }
|
|
31
|
+
/**
|
|
32
|
+
* 设置平台证书缓存名称
|
|
33
|
+
* @param key
|
|
34
|
+
*/
|
|
35
|
+
setPlatformCertKey(key) { return this; }
|
|
36
|
+
/**
|
|
37
|
+
* 更具证书序列号获取平台证书
|
|
29
38
|
* @param serial
|
|
30
39
|
* @returns
|
|
31
40
|
*/
|
|
32
41
|
getPlatformCert(serial) { return null; }
|
|
42
|
+
/**
|
|
43
|
+
* 获取平台证书
|
|
44
|
+
* @param force 是否强制刷新缓存
|
|
45
|
+
*/
|
|
46
|
+
loadPlatformCerts(force) { }
|
|
33
47
|
/**
|
|
34
48
|
* 设置平台证书
|
|
35
|
-
* @param certs 键名:序列号,键值:PublicKey
|
|
49
|
+
* @param certs 键名:序列号,键值:PublicKey实例或者文件内容字符串
|
|
36
50
|
*/
|
|
37
51
|
setPlatformCerts(certs) { }
|
|
38
52
|
}
|
package/dist/Pay/Merchant.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { PrivateKey } from "../Core/Support/PrivateKey";
|
|
2
2
|
import { PublicKey } from "../Core/Support/PublicKey";
|
|
3
|
+
import Application from "./Application";
|
|
3
4
|
import MerchantInterface from "./Contracts/MerchantInterface";
|
|
4
5
|
declare class Merchant implements MerchantInterface {
|
|
5
6
|
protected mchId: string;
|
|
6
7
|
protected secretKey: string;
|
|
7
8
|
protected v2SecretKey: string;
|
|
9
|
+
protected app: Application;
|
|
8
10
|
protected platformCerts: Record<string, PublicKey>;
|
|
9
11
|
protected privateKey: PrivateKey;
|
|
10
12
|
protected certificate: PublicKey;
|
|
11
|
-
|
|
13
|
+
protected cacheKeyPlatformCert: string;
|
|
14
|
+
constructor(mchId: string, privateKey: string | PrivateKey, certificate: string | PublicKey, secretKey: string, v2SecretKey: string, platformCerts?: Record<string, string | PublicKey> | string[] | PublicKey[], app?: Application);
|
|
12
15
|
/**
|
|
13
16
|
* 统一规范化平台证书
|
|
14
17
|
* @param platformCerts 平台证书列表
|
|
@@ -20,7 +23,10 @@ declare class Merchant implements MerchantInterface {
|
|
|
20
23
|
getSecretKey(): string;
|
|
21
24
|
getV2SecretKey(): string;
|
|
22
25
|
getCertificate(): PublicKey;
|
|
23
|
-
getPlatformCert(serial: string): PublicKey
|
|
24
|
-
setPlatformCerts(certs: Record<string, PublicKey>): void;
|
|
26
|
+
getPlatformCert(serial: string): Promise<PublicKey>;
|
|
27
|
+
setPlatformCerts(certs: Record<string, PublicKey | string>): void;
|
|
28
|
+
getPlatformCertKey(): string;
|
|
29
|
+
setPlatformCertKey(key: string): this;
|
|
30
|
+
loadPlatformCerts(force?: boolean): Promise<Record<string, string>>;
|
|
25
31
|
}
|
|
26
32
|
export = Merchant;
|
package/dist/Pay/Merchant.js
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
const AES_1 = require("../Core/Support/AES");
|
|
2
12
|
const PrivateKey_1 = require("../Core/Support/PrivateKey");
|
|
3
13
|
const PublicKey_1 = require("../Core/Support/PublicKey");
|
|
4
14
|
class Merchant {
|
|
5
|
-
constructor(mchId, privateKey, certificate, secretKey, v2SecretKey, platformCerts = []) {
|
|
15
|
+
constructor(mchId, privateKey, certificate, secretKey, v2SecretKey, platformCerts = [], app = null) {
|
|
6
16
|
this.mchId = mchId;
|
|
7
17
|
this.secretKey = secretKey;
|
|
8
18
|
this.v2SecretKey = v2SecretKey;
|
|
19
|
+
this.app = app;
|
|
9
20
|
this.platformCerts = {};
|
|
10
21
|
if (!(privateKey instanceof PrivateKey_1.PrivateKey)) {
|
|
11
22
|
this.privateKey = new PrivateKey_1.PrivateKey(privateKey);
|
|
@@ -58,10 +69,55 @@ class Merchant {
|
|
|
58
69
|
}
|
|
59
70
|
getPlatformCert(serial) {
|
|
60
71
|
var _a;
|
|
61
|
-
return (
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
if (!this.platformCerts || Object.keys(this.platformCerts).length === 0) {
|
|
74
|
+
yield this.loadPlatformCerts();
|
|
75
|
+
}
|
|
76
|
+
return (_a = this.platformCerts[serial]) !== null && _a !== void 0 ? _a : null;
|
|
77
|
+
});
|
|
62
78
|
}
|
|
63
79
|
setPlatformCerts(certs) {
|
|
64
|
-
|
|
80
|
+
let newCerts = {};
|
|
81
|
+
for (let key of Object.keys(certs)) {
|
|
82
|
+
let cert = certs[key];
|
|
83
|
+
if (typeof cert === 'string') {
|
|
84
|
+
newCerts[key] = PublicKey_1.PublicKey.createByCertificateContent(cert, key);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
newCerts[key] = cert;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this.platformCerts = newCerts;
|
|
91
|
+
}
|
|
92
|
+
getPlatformCertKey() {
|
|
93
|
+
if (!this.cacheKeyPlatformCert) {
|
|
94
|
+
this.cacheKeyPlatformCert = `pay.platform_certs.${this.mchId}`;
|
|
95
|
+
}
|
|
96
|
+
return this.cacheKeyPlatformCert;
|
|
97
|
+
}
|
|
98
|
+
setPlatformCertKey(key) {
|
|
99
|
+
this.cacheKeyPlatformCert = key;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
loadPlatformCerts(force = false) {
|
|
103
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
+
let cacheKey = this.getPlatformCertKey();
|
|
105
|
+
let cache = this.app.getCache();
|
|
106
|
+
let certs = yield cache.get(cacheKey);
|
|
107
|
+
if (force || !certs || Object.keys(certs).length === 0) {
|
|
108
|
+
certs = {};
|
|
109
|
+
let response = yield this.app.getClient().get('/v3/certificates');
|
|
110
|
+
let data = response.toObject();
|
|
111
|
+
if (!data || !data.data || data.data.length === 0)
|
|
112
|
+
return certs;
|
|
113
|
+
data.data.forEach((item) => {
|
|
114
|
+
let content = AES_1.AES_GCM.decrypt(item.encrypt_certificate.ciphertext, this.app.getConfig().get('secret_key'), item.encrypt_certificate.nonce, item.encrypt_certificate.associated_data).toString();
|
|
115
|
+
certs[item.serial_no] = content;
|
|
116
|
+
});
|
|
117
|
+
yield cache.set(cacheKey, certs, 36000); // 缓存10小时
|
|
118
|
+
}
|
|
119
|
+
this.setPlatformCerts(certs);
|
|
120
|
+
});
|
|
65
121
|
}
|
|
66
122
|
}
|
|
67
123
|
module.exports = Merchant;
|
package/dist/Pay/Signature.js
CHANGED
|
@@ -26,7 +26,18 @@ class Signature {
|
|
|
26
26
|
pathname = urlObj.pathname + (search ? '?' + search : '');
|
|
27
27
|
}
|
|
28
28
|
else {
|
|
29
|
-
|
|
29
|
+
let search = '';
|
|
30
|
+
if (payload.params) {
|
|
31
|
+
if (typeof payload.params === 'string') {
|
|
32
|
+
search = payload.params.replace(/^\?|&/, '');
|
|
33
|
+
}
|
|
34
|
+
else if (Object.keys(payload.params).length > 0) {
|
|
35
|
+
search = (0, Utils_1.buildQueryString)(payload.params);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (search) {
|
|
39
|
+
pathname += (pathname.indexOf('?') > -1 ? '&' : '?') + search;
|
|
40
|
+
}
|
|
30
41
|
}
|
|
31
42
|
if (!nonce)
|
|
32
43
|
nonce = (0, Utils_1.randomString)();
|
package/dist/Pay/Validator.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ declare class Validator implements ValidatorInterface {
|
|
|
10
10
|
static HEADER_SERIAL: string;
|
|
11
11
|
static HEADER_SIGNATURE: string;
|
|
12
12
|
constructor(merchant: MerchantInterface);
|
|
13
|
-
validate(request: MessageInterface): boolean
|
|
13
|
+
validate(request: MessageInterface): Promise<boolean>;
|
|
14
14
|
validateV2(message: Message): boolean;
|
|
15
15
|
}
|
|
16
16
|
export = Validator;
|
package/dist/Pay/Validator.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
13
|
};
|
|
@@ -10,35 +19,37 @@ class Validator {
|
|
|
10
19
|
this.merchant = merchant;
|
|
11
20
|
}
|
|
12
21
|
validate(request) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
[
|
|
24
|
+
Validator.HEADER_TIMESTAMP,
|
|
25
|
+
Validator.HEADER_NONCE,
|
|
26
|
+
Validator.HEADER_SERIAL,
|
|
27
|
+
Validator.HEADER_SIGNATURE,
|
|
28
|
+
].forEach(key => {
|
|
29
|
+
if (!request.hasHeader(key)) {
|
|
30
|
+
throw new Error(`Missing Header: ${key}`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
let timestamp = request.getHeader(Validator.HEADER_TIMESTAMP) || '';
|
|
34
|
+
let nonce = request.getHeader(Validator.HEADER_NONCE) || '';
|
|
35
|
+
let serial = request.getHeader(Validator.HEADER_SERIAL) || '';
|
|
36
|
+
let signature = request.getHeader(Validator.HEADER_SIGNATURE) || '';
|
|
37
|
+
let body = request.getBody().toString();
|
|
38
|
+
let message = `${timestamp}\n${nonce}\n${body}\n`;
|
|
39
|
+
if ((0, Utils_1.getTimestamp)() - parseInt(timestamp) > Validator.MAX_ALLOWED_CLOCK_OFFSET) {
|
|
40
|
+
throw new Error('Clock Offset Exceeded');
|
|
41
|
+
}
|
|
42
|
+
let publicKey = yield this.merchant.getPlatformCert(serial);
|
|
43
|
+
if (!publicKey) {
|
|
44
|
+
throw new Error(`No platform certs found for serial: ${serial}, please download from wechat pay and set it in merchant config with key \`platform_certs\`.`);
|
|
21
45
|
}
|
|
46
|
+
let rsa = new RSA_1.default;
|
|
47
|
+
rsa.setPublicKey(publicKey.getValue());
|
|
48
|
+
if (false === rsa.verify(signature, message)) {
|
|
49
|
+
throw new Error('Invalid Signature');
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
22
52
|
});
|
|
23
|
-
let timestamp = request.getHeader(Validator.HEADER_TIMESTAMP) || '';
|
|
24
|
-
let nonce = request.getHeader(Validator.HEADER_NONCE) || '';
|
|
25
|
-
let serial = request.getHeader(Validator.HEADER_SERIAL) || '';
|
|
26
|
-
let signature = request.getHeader(Validator.HEADER_SIGNATURE) || '';
|
|
27
|
-
let body = request.getBody().toString();
|
|
28
|
-
let message = `${timestamp}\n${nonce}\n${body}\n`;
|
|
29
|
-
if ((0, Utils_1.getTimestamp)() - parseInt(timestamp) > Validator.MAX_ALLOWED_CLOCK_OFFSET) {
|
|
30
|
-
throw new Error('Clock Offset Exceeded');
|
|
31
|
-
}
|
|
32
|
-
let publicKey = this.merchant.getPlatformCert(serial);
|
|
33
|
-
if (!publicKey) {
|
|
34
|
-
throw new Error(`No platform certs found for serial: ${serial}, please download from wechat pay and set it in merchant config with key \`platform_certs\`.`);
|
|
35
|
-
}
|
|
36
|
-
let rsa = new RSA_1.default;
|
|
37
|
-
rsa.setPublicKey(publicKey.getValue());
|
|
38
|
-
if (false === rsa.verify(signature, message)) {
|
|
39
|
-
throw new Error('Invalid Signature');
|
|
40
|
-
}
|
|
41
|
-
return true;
|
|
42
53
|
}
|
|
43
54
|
validateV2(message) {
|
|
44
55
|
let messageSign = (message.get('sign') + '' || '').toUpperCase();
|