node-easywechat 3.1.1 → 3.1.3
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 +12 -0
- package/README.md +2 -0
- package/dist/Core/HttpClient/HttpClient.js +7 -2
- package/dist/Core/Mixins/CacheMixin.js +5 -1
- package/dist/Core/Support/PrivateKey.d.ts +5 -4
- package/dist/Core/Support/PrivateKey.js +2 -3
- package/dist/Core/Support/PublicKey.d.ts +7 -1
- package/dist/Core/Support/PublicKey.js +9 -3
- package/dist/Core/Support/Utils.d.ts +5 -4
- package/dist/Core/Support/Utils.js +10 -10
- package/dist/OfficialAccount/AccessToken.js +7 -6
- package/dist/OfficialAccount/JsApiTicket.js +7 -2
- package/dist/OpenPlatform/ComponentAccessToken.js +7 -6
- package/dist/OpenPlatform/VerifyTicket.js +7 -7
- package/dist/Pay/Application.js +1 -3
- package/dist/Pay/Client.d.ts +12 -0
- package/dist/Pay/Client.js +38 -0
- package/dist/Pay/Merchant.d.ts +3 -3
- package/dist/Pay/Merchant.js +13 -2
- package/dist/Pay/Signature.js +2 -2
- package/package.json +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v3.1.3 (2023-02-01)
|
|
5
|
+
|
|
6
|
+
- Fix: 修复默认的文件缓存配置项不生效问题 (#35)
|
|
7
|
+
|
|
8
|
+
## v3.1.2 (2022-12-06)
|
|
9
|
+
|
|
10
|
+
- Feat: 新作微信支付模块的文件上传方法
|
|
11
|
+
|
|
12
|
+
- Fix: nodejs版本不能低于15.6.0
|
|
13
|
+
- Fix: 更新依赖的nodejs版本
|
|
14
|
+
- Fix: 修复RSA证书使用格式不正确导致的签名异常问题
|
|
15
|
+
|
|
4
16
|
## v3.1.1 (2022-11-15)
|
|
5
17
|
|
|
6
18
|
- Feat: 增加请求失败时的重试机制,具体见配置项http.retry
|
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
`npm install -S node-easywechat@next`
|
|
18
18
|
|
|
19
|
+
**注:3.x 版本需要 Node.js 15.6.0 及以上版本**
|
|
20
|
+
|
|
19
21
|
### 使用说明
|
|
20
22
|
|
|
21
23
|
绝大部分API都可以根据 [EasyWechat 的文档](https://www.easywechat.com/5.x/) 来使用。小部分(如获取请求相关数据、返回响应数据、支付证书等)的操作,由于语言环境的不同,会有不同处理。具体可以查看 [node-easywechat-demo](https://github.com/hpyer/node-easywechat-demo/) 以及下方的[自定义模块说明](#自定义模块模块替换使用方法) 。如果仍有疑问,请提issue,谢谢~
|
|
@@ -79,8 +79,13 @@ class HttpClient {
|
|
|
79
79
|
}
|
|
80
80
|
if (options['formData'] && Object.keys(options['formData']).length > 0) {
|
|
81
81
|
let formData = new form_data_1.default();
|
|
82
|
-
|
|
83
|
-
formData
|
|
82
|
+
if (options['formData'] instanceof form_data_1.default) {
|
|
83
|
+
formData = options['formData'];
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
for (let key in options['formData']) {
|
|
87
|
+
formData.append(key, options['formData'][key]);
|
|
88
|
+
}
|
|
84
89
|
}
|
|
85
90
|
if (options.data)
|
|
86
91
|
for (let key in options.data) {
|
|
@@ -45,7 +45,11 @@ class CacheMixin {
|
|
|
45
45
|
*/
|
|
46
46
|
getCache() {
|
|
47
47
|
if (!this.cache) {
|
|
48
|
-
|
|
48
|
+
let options = null;
|
|
49
|
+
if (typeof this['getConfig'] === 'function') {
|
|
50
|
+
options = this['getConfig']()['get']('file_cache');
|
|
51
|
+
}
|
|
52
|
+
this.cache = new FileCache_1.default(options);
|
|
49
53
|
}
|
|
50
54
|
return this.cache;
|
|
51
55
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
export declare class PrivateKey {
|
|
2
|
-
protected key: string;
|
|
3
3
|
protected passphrase?: string;
|
|
4
|
+
protected key: Buffer;
|
|
4
5
|
constructor(key: string, passphrase?: string);
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
+
* 获取私钥内容
|
|
7
8
|
* @returns
|
|
8
9
|
*/
|
|
9
|
-
getKey():
|
|
10
|
+
getKey(): Buffer;
|
|
10
11
|
/**
|
|
11
12
|
* 获取密码
|
|
12
13
|
* @returns
|
|
@@ -16,5 +17,5 @@ export declare class PrivateKey {
|
|
|
16
17
|
* 转为字符串
|
|
17
18
|
* @returns
|
|
18
19
|
*/
|
|
19
|
-
toString():
|
|
20
|
+
toString(): Buffer;
|
|
20
21
|
}
|
|
@@ -7,14 +7,13 @@ exports.PrivateKey = void 0;
|
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
class PrivateKey {
|
|
9
9
|
constructor(key, passphrase) {
|
|
10
|
-
this.key = key;
|
|
11
10
|
this.passphrase = passphrase;
|
|
12
11
|
if (fs_1.default.existsSync(key)) {
|
|
13
|
-
this.key = fs_1.default.readFileSync(key
|
|
12
|
+
this.key = fs_1.default.readFileSync(key) || Buffer.from('');
|
|
14
13
|
}
|
|
15
14
|
}
|
|
16
15
|
/**
|
|
17
|
-
*
|
|
16
|
+
* 获取私钥内容
|
|
18
17
|
* @returns
|
|
19
18
|
*/
|
|
20
19
|
getKey() {
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
export declare class PublicKey {
|
|
2
|
-
certificate:
|
|
3
|
+
protected certificate: Buffer;
|
|
3
4
|
constructor(certificate: string);
|
|
4
5
|
/**
|
|
5
6
|
* 获取公钥的序列号
|
|
6
7
|
* @returns
|
|
7
8
|
*/
|
|
8
9
|
getSerialNo(): string;
|
|
10
|
+
/**
|
|
11
|
+
* 获取证书内容
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
getValue(): Buffer;
|
|
9
15
|
/**
|
|
10
16
|
* 转为字符串
|
|
11
17
|
* @returns
|
|
@@ -8,9 +8,8 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const crypto_1 = require("crypto");
|
|
9
9
|
class PublicKey {
|
|
10
10
|
constructor(certificate) {
|
|
11
|
-
this.certificate = certificate;
|
|
12
11
|
if (fs_1.default.existsSync(certificate)) {
|
|
13
|
-
this.certificate = fs_1.default.readFileSync(certificate
|
|
12
|
+
this.certificate = fs_1.default.readFileSync(certificate) || Buffer.from('');
|
|
14
13
|
}
|
|
15
14
|
}
|
|
16
15
|
/**
|
|
@@ -25,12 +24,19 @@ class PublicKey {
|
|
|
25
24
|
throw new Error('Read the $certificate failed, please check it whether or nor correct');
|
|
26
25
|
}
|
|
27
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* 获取证书内容
|
|
29
|
+
* @returns
|
|
30
|
+
*/
|
|
31
|
+
getValue() {
|
|
32
|
+
return this.certificate;
|
|
33
|
+
}
|
|
28
34
|
/**
|
|
29
35
|
* 转为字符串
|
|
30
36
|
* @returns
|
|
31
37
|
*/
|
|
32
38
|
toString() {
|
|
33
|
-
return this.certificate;
|
|
39
|
+
return this.certificate.toString();
|
|
34
40
|
}
|
|
35
41
|
}
|
|
36
42
|
exports.PublicKey = PublicKey;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import Crypto from 'crypto';
|
|
1
2
|
import Stream from 'stream';
|
|
2
|
-
export declare const createHash: (str:
|
|
3
|
-
export declare const createHmac: (str:
|
|
3
|
+
export declare const createHash: (str: Crypto.BinaryLike, type?: string, target?: Crypto.BinaryToTextEncoding) => any;
|
|
4
|
+
export declare const createHmac: (str: Crypto.BinaryLike, key: Crypto.BinaryLike, type?: string, target?: Crypto.BinaryToTextEncoding) => any;
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
+
* 计算文件的哈希值
|
|
6
7
|
* @param path 文件路径或文件可读流
|
|
7
8
|
*/
|
|
8
|
-
export declare const
|
|
9
|
+
export declare const createFileHash: (path: string | Stream.Readable, type?: string, target?: Crypto.BinaryToTextEncoding) => Promise<string>;
|
|
9
10
|
export declare const getTimestamp: (datetime?: string) => number;
|
|
10
11
|
export declare const buildQueryString: (data: Record<string, any>, options?: Record<string, any>) => string;
|
|
11
12
|
export declare const parseQueryString: (data: string, options?: Record<string, any>) => Record<string, any>;
|
|
@@ -12,26 +12,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.createUserAgent = exports.buildXml = exports.parseXml = exports.singleItem = exports.strSnake = exports.strCamel = exports.strStudly = exports.strLcwords = exports.strUcwords = exports.rtrim = exports.ltrim = exports.trim = exports.applyMixins = exports.inArray = exports.isIp = exports.isIpv6 = exports.isIpv4 = exports.isFunction = exports.isObject = exports.isNumber = exports.isArray = exports.isString = exports.makeSignature = exports.randomString = exports.parseQueryString = exports.buildQueryString = exports.getTimestamp = exports.
|
|
15
|
+
exports.createUserAgent = exports.buildXml = exports.parseXml = exports.singleItem = exports.strSnake = exports.strCamel = exports.strStudly = exports.strLcwords = exports.strUcwords = exports.rtrim = exports.ltrim = exports.trim = exports.applyMixins = exports.inArray = exports.isIp = exports.isIpv6 = exports.isIpv4 = exports.isFunction = exports.isObject = exports.isNumber = exports.isArray = exports.isString = exports.makeSignature = exports.randomString = exports.parseQueryString = exports.buildQueryString = exports.getTimestamp = exports.createFileHash = exports.createHmac = exports.createHash = void 0;
|
|
16
16
|
const crypto_1 = __importDefault(require("crypto"));
|
|
17
17
|
const qs_1 = __importDefault(require("qs"));
|
|
18
18
|
const xml2js_1 = __importDefault(require("xml2js"));
|
|
19
19
|
const stream_1 = __importDefault(require("stream"));
|
|
20
20
|
const fs_1 = __importDefault(require("fs"));
|
|
21
21
|
const axios_1 = __importDefault(require("axios"));
|
|
22
|
-
const createHash = function (str, type = 'sha1') {
|
|
23
|
-
return crypto_1.default.createHash(type).update(str).digest(
|
|
22
|
+
const createHash = function (str, type = 'sha1', target = 'hex') {
|
|
23
|
+
return crypto_1.default.createHash(type).update(str).digest(target);
|
|
24
24
|
};
|
|
25
25
|
exports.createHash = createHash;
|
|
26
|
-
const createHmac = function (str, key, type = 'sha256') {
|
|
27
|
-
return crypto_1.default.createHmac(type, key).update(str).digest(
|
|
26
|
+
const createHmac = function (str, key, type = 'sha256', target = 'hex') {
|
|
27
|
+
return crypto_1.default.createHmac(type, key).update(str).digest(target);
|
|
28
28
|
};
|
|
29
29
|
exports.createHmac = createHmac;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* 计算文件的哈希值
|
|
32
32
|
* @param path 文件路径或文件可读流
|
|
33
33
|
*/
|
|
34
|
-
const
|
|
34
|
+
const createFileHash = function (path, type = 'sha1', target = 'hex') {
|
|
35
35
|
return new Promise((reslove, reject) => {
|
|
36
36
|
let stream;
|
|
37
37
|
if ((0, exports.isString)(path)) {
|
|
@@ -41,17 +41,17 @@ const md5File = function (path) {
|
|
|
41
41
|
stream = new stream_1.default.PassThrough();
|
|
42
42
|
path.pipe(stream);
|
|
43
43
|
}
|
|
44
|
-
let md5sum = crypto_1.default.createHash(
|
|
44
|
+
let md5sum = crypto_1.default.createHash(type);
|
|
45
45
|
stream.on('data', function (chunk) {
|
|
46
46
|
md5sum.update(chunk);
|
|
47
47
|
});
|
|
48
48
|
stream.on('end', function () {
|
|
49
|
-
let str = md5sum.digest(
|
|
49
|
+
let str = md5sum.digest(target).toUpperCase();
|
|
50
50
|
reslove(str);
|
|
51
51
|
});
|
|
52
52
|
});
|
|
53
53
|
};
|
|
54
|
-
exports.
|
|
54
|
+
exports.createFileHash = createFileHash;
|
|
55
55
|
const getTimestamp = function (datetime = null) {
|
|
56
56
|
let time;
|
|
57
57
|
try {
|
|
@@ -12,7 +12,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
const HttpClient_1 = __importDefault(require("../Core/HttpClient/HttpClient"));
|
|
15
|
-
const FileCache_1 = __importDefault(require("../Core/Cache/FileCache"));
|
|
16
15
|
class AccessToken {
|
|
17
16
|
constructor(appId, secret, key = null, cache = null, httpClient = null) {
|
|
18
17
|
this.appId = appId;
|
|
@@ -20,9 +19,6 @@ class AccessToken {
|
|
|
20
19
|
this.key = key;
|
|
21
20
|
this.cache = cache;
|
|
22
21
|
this.httpClient = httpClient;
|
|
23
|
-
if (!this.cache) {
|
|
24
|
-
this.cache = new FileCache_1.default();
|
|
25
|
-
}
|
|
26
22
|
if (!this.httpClient) {
|
|
27
23
|
this.httpClient = HttpClient_1.default.create({
|
|
28
24
|
baseURL: 'https://api.weixin.qq.com/',
|
|
@@ -50,7 +46,10 @@ class AccessToken {
|
|
|
50
46
|
}
|
|
51
47
|
getToken() {
|
|
52
48
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
-
let token =
|
|
49
|
+
let token = '';
|
|
50
|
+
if (this.cache) {
|
|
51
|
+
token = yield this.cache.get(this.getKey());
|
|
52
|
+
}
|
|
54
53
|
if (!!token && typeof token === 'string') {
|
|
55
54
|
return token;
|
|
56
55
|
}
|
|
@@ -76,7 +75,9 @@ class AccessToken {
|
|
|
76
75
|
if (!response['access_token']) {
|
|
77
76
|
throw new Error('Failed to get access_token: ' + JSON.stringify(response));
|
|
78
77
|
}
|
|
79
|
-
|
|
78
|
+
if (this.cache) {
|
|
79
|
+
yield this.cache.set(this.getKey(), response['access_token'], parseInt(response['expires_in']));
|
|
80
|
+
}
|
|
80
81
|
return response['access_token'];
|
|
81
82
|
});
|
|
82
83
|
}
|
|
@@ -31,7 +31,10 @@ class JsApiTicket extends AccessToken_1.default {
|
|
|
31
31
|
getTicket() {
|
|
32
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
33
33
|
let key = this.getKey();
|
|
34
|
-
let ticket =
|
|
34
|
+
let ticket = '';
|
|
35
|
+
if (this.cache) {
|
|
36
|
+
ticket = yield this.cache.get(key);
|
|
37
|
+
}
|
|
35
38
|
if (!!ticket && typeof ticket === 'string') {
|
|
36
39
|
return ticket;
|
|
37
40
|
}
|
|
@@ -43,7 +46,9 @@ class JsApiTicket extends AccessToken_1.default {
|
|
|
43
46
|
if (!response['ticket']) {
|
|
44
47
|
throw new Error('Failed to get jssdk_ticket: ' + JSON.stringify(response));
|
|
45
48
|
}
|
|
46
|
-
|
|
49
|
+
if (this.cache) {
|
|
50
|
+
yield this.cache.set(key, response['ticket'], parseInt(response['expires_in']));
|
|
51
|
+
}
|
|
47
52
|
return response['ticket'];
|
|
48
53
|
});
|
|
49
54
|
}
|
|
@@ -12,7 +12,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
const HttpClient_1 = __importDefault(require("../Core/HttpClient/HttpClient"));
|
|
15
|
-
const FileCache_1 = __importDefault(require("../Core/Cache/FileCache"));
|
|
16
15
|
class ComponentAccessToken {
|
|
17
16
|
constructor(appId, secret, verifyTicket, key = null, cache = null, httpClient = null) {
|
|
18
17
|
this.appId = appId;
|
|
@@ -21,9 +20,6 @@ class ComponentAccessToken {
|
|
|
21
20
|
this.key = key;
|
|
22
21
|
this.cache = cache;
|
|
23
22
|
this.httpClient = httpClient;
|
|
24
|
-
if (!this.cache) {
|
|
25
|
-
this.cache = new FileCache_1.default();
|
|
26
|
-
}
|
|
27
23
|
if (!this.httpClient) {
|
|
28
24
|
this.httpClient = HttpClient_1.default.create({
|
|
29
25
|
baseURL: 'https://api.weixin.qq.com/',
|
|
@@ -51,7 +47,10 @@ class ComponentAccessToken {
|
|
|
51
47
|
}
|
|
52
48
|
getToken() {
|
|
53
49
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
-
let token =
|
|
50
|
+
let token = '';
|
|
51
|
+
if (this.cache) {
|
|
52
|
+
token = yield this.cache.get(this.getKey());
|
|
53
|
+
}
|
|
55
54
|
if (!!token && typeof token === 'string') {
|
|
56
55
|
return token;
|
|
57
56
|
}
|
|
@@ -77,7 +76,9 @@ class ComponentAccessToken {
|
|
|
77
76
|
if (!response['component_access_token']) {
|
|
78
77
|
throw new Error('Failed to get component_access_token: ' + JSON.stringify(response));
|
|
79
78
|
}
|
|
80
|
-
|
|
79
|
+
if (this.cache) {
|
|
80
|
+
yield this.cache.set(this.getKey(), response['component_access_token'], parseInt(response['expires_in']) - 100);
|
|
81
|
+
}
|
|
81
82
|
return response['component_access_token'];
|
|
82
83
|
});
|
|
83
84
|
}
|
|
@@ -8,16 +8,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
const FileCache_1 = __importDefault(require("../Core/Cache/FileCache"));
|
|
15
11
|
class VerifyTicket {
|
|
16
12
|
constructor(appId, key = null, cache = null) {
|
|
17
13
|
this.appId = appId;
|
|
18
14
|
this.key = key;
|
|
19
15
|
this.cache = cache;
|
|
20
|
-
this.cache = cache !== null && cache !== void 0 ? cache : new FileCache_1.default();
|
|
21
16
|
}
|
|
22
17
|
getKey() {
|
|
23
18
|
if (!this.key) {
|
|
@@ -31,13 +26,18 @@ class VerifyTicket {
|
|
|
31
26
|
}
|
|
32
27
|
setTicket(ticket) {
|
|
33
28
|
return __awaiter(this, void 0, void 0, function* () {
|
|
34
|
-
|
|
29
|
+
if (this.cache) {
|
|
30
|
+
yield this.cache.set(this.getKey(), ticket, 6000);
|
|
31
|
+
}
|
|
35
32
|
return this;
|
|
36
33
|
});
|
|
37
34
|
}
|
|
38
35
|
getTicket() {
|
|
39
36
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
-
let ticket =
|
|
37
|
+
let ticket = '';
|
|
38
|
+
if (this.cache) {
|
|
39
|
+
ticket = yield this.cache.get(this.getKey());
|
|
40
|
+
}
|
|
41
41
|
if (!ticket || typeof ticket != 'string') {
|
|
42
42
|
throw new Error('No component_verify_ticket found.');
|
|
43
43
|
}
|
package/dist/Pay/Application.js
CHANGED
|
@@ -13,8 +13,6 @@ const Merchant_1 = __importDefault(require("./Merchant"));
|
|
|
13
13
|
const Server_1 = __importDefault(require("./Server"));
|
|
14
14
|
const Utils_2 = __importDefault(require("./Utils"));
|
|
15
15
|
const Config_1 = __importDefault(require("../OfficialAccount/Config"));
|
|
16
|
-
const PrivateKey_1 = require("../Core/Support/PrivateKey");
|
|
17
|
-
const PublicKey_1 = require("../Core/Support/PublicKey");
|
|
18
16
|
const Client_1 = __importDefault(require("./Client"));
|
|
19
17
|
/**
|
|
20
18
|
* 微信支付应用
|
|
@@ -34,7 +32,7 @@ class Application {
|
|
|
34
32
|
getMerchant() {
|
|
35
33
|
var _a;
|
|
36
34
|
if (!this.merchant) {
|
|
37
|
-
this.merchant = new Merchant_1.default(this.config.get('mch_id'),
|
|
35
|
+
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 : []);
|
|
38
36
|
}
|
|
39
37
|
return this.merchant;
|
|
40
38
|
}
|
package/dist/Pay/Client.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import fs from 'fs';
|
|
1
3
|
import { Method, AxiosRequestConfig, AxiosInstance } from "axios";
|
|
2
4
|
import HttpClientInterface from "../Core/HttpClient/Contracts/HttpClientInterface";
|
|
3
5
|
import HttpClientMethodsMixin from '../Core/HttpClient/Mixins/HttpClientMethodsMixin';
|
|
@@ -16,6 +18,16 @@ declare class Client implements HttpClientInterface {
|
|
|
16
18
|
setInstance(instance: AxiosInstance): this;
|
|
17
19
|
setLogger(logger: LogHandler): this;
|
|
18
20
|
request(method: Method, url: string, payload?: AxiosRequestConfig<any>): Promise<HttpClientResponse>;
|
|
21
|
+
/**
|
|
22
|
+
* 文件上传
|
|
23
|
+
* @see https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter2_1_1.shtml
|
|
24
|
+
* @param uri 接口地址
|
|
25
|
+
* @param file 文件路径或文件可读流
|
|
26
|
+
* @param meta 文件元信息,包含 filename 和 sha256 两个字段
|
|
27
|
+
* @param filename 文件名,必须以 .jpg、.bmp、.png 为后缀
|
|
28
|
+
* @returns
|
|
29
|
+
*/
|
|
30
|
+
uploadMedia(uri: string, file: string | fs.ReadStream, meta?: Record<string, any>, filename?: string): Promise<HttpClientResponse>;
|
|
19
31
|
/**
|
|
20
32
|
* 判断是否是V3请求
|
|
21
33
|
* @param url 请求地址
|
package/dist/Pay/Client.js
CHANGED
|
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
15
|
const merge_1 = __importDefault(require("merge"));
|
|
15
16
|
const Utils_1 = require("../Core/Support/Utils");
|
|
16
17
|
const HttpClient_1 = __importDefault(require("../Core/HttpClient/HttpClient"));
|
|
@@ -18,6 +19,7 @@ const HttpClientMethodsMixin_1 = __importDefault(require("../Core/HttpClient/Mix
|
|
|
18
19
|
const PresetMixin_1 = __importDefault(require("../Core/HttpClient/Mixins/PresetMixin"));
|
|
19
20
|
const Signature_1 = __importDefault(require("./Signature"));
|
|
20
21
|
const LegacySignature_1 = __importDefault(require("./LegacySignature"));
|
|
22
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
21
23
|
class Client {
|
|
22
24
|
constructor(merchant, client, defaultOptions = {}) {
|
|
23
25
|
var _a;
|
|
@@ -89,6 +91,42 @@ class Client {
|
|
|
89
91
|
return this.client.request(method, (0, Utils_1.ltrim)(url, '\\/+'), payload);
|
|
90
92
|
});
|
|
91
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* 文件上传
|
|
96
|
+
* @see https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter2_1_1.shtml
|
|
97
|
+
* @param uri 接口地址
|
|
98
|
+
* @param file 文件路径或文件可读流
|
|
99
|
+
* @param meta 文件元信息,包含 filename 和 sha256 两个字段
|
|
100
|
+
* @param filename 文件名,必须以 .jpg、.bmp、.png 为后缀
|
|
101
|
+
* @returns
|
|
102
|
+
*/
|
|
103
|
+
uploadMedia(uri, file, meta = null, filename = null) {
|
|
104
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
105
|
+
if (typeof file === 'string') {
|
|
106
|
+
file = fs_1.default.createReadStream(file);
|
|
107
|
+
}
|
|
108
|
+
if (!meta) {
|
|
109
|
+
meta = {
|
|
110
|
+
filename: filename !== null && filename !== void 0 ? filename : 'file.jpg',
|
|
111
|
+
sha256: yield (0, Utils_1.createFileHash)(file, 'sha256'),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
let metaJson = JSON.stringify(meta);
|
|
115
|
+
let formData = new form_data_1.default();
|
|
116
|
+
formData.append('file', file);
|
|
117
|
+
formData.append('meta', metaJson, {
|
|
118
|
+
contentType: 'application/json',
|
|
119
|
+
});
|
|
120
|
+
return this.client.request('POST', (0, Utils_1.ltrim)(uri, '\\/+'), {
|
|
121
|
+
formData,
|
|
122
|
+
headers: {
|
|
123
|
+
'authorization': this.createSignature('POST', uri, {
|
|
124
|
+
data: metaJson,
|
|
125
|
+
}),
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}
|
|
92
130
|
/**
|
|
93
131
|
* 判断是否是V3请求
|
|
94
132
|
* @param url 请求地址
|
package/dist/Pay/Merchant.d.ts
CHANGED
|
@@ -3,12 +3,12 @@ import { PublicKey } from "../Core/Support/PublicKey";
|
|
|
3
3
|
import MerchantInterface from "./Contracts/MerchantInterface";
|
|
4
4
|
declare class Merchant implements MerchantInterface {
|
|
5
5
|
protected mchId: string;
|
|
6
|
-
protected privateKey: PrivateKey;
|
|
7
|
-
protected certificate: PublicKey;
|
|
8
6
|
protected secretKey: string;
|
|
9
7
|
protected v2SecretKey: string;
|
|
10
8
|
protected platformCerts: Record<string, PublicKey>;
|
|
11
|
-
|
|
9
|
+
protected privateKey: PrivateKey;
|
|
10
|
+
protected certificate: PublicKey;
|
|
11
|
+
constructor(mchId: string, privateKey: string | PrivateKey, certificate: string | PublicKey, secretKey: string, v2SecretKey?: string, platformCerts?: Record<string, string | PublicKey> | string[] | PublicKey[]);
|
|
12
12
|
/**
|
|
13
13
|
* 统一规范化平台证书
|
|
14
14
|
* @param platformCerts 平台证书列表
|
package/dist/Pay/Merchant.js
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
const PrivateKey_1 = require("../Core/Support/PrivateKey");
|
|
2
3
|
const PublicKey_1 = require("../Core/Support/PublicKey");
|
|
3
4
|
class Merchant {
|
|
4
5
|
constructor(mchId, privateKey, certificate, secretKey, v2SecretKey = null, platformCerts = []) {
|
|
5
6
|
this.mchId = mchId;
|
|
6
|
-
this.privateKey = privateKey;
|
|
7
|
-
this.certificate = certificate;
|
|
8
7
|
this.secretKey = secretKey;
|
|
9
8
|
this.v2SecretKey = v2SecretKey;
|
|
10
9
|
this.platformCerts = {};
|
|
10
|
+
if (!(privateKey instanceof PrivateKey_1.PrivateKey)) {
|
|
11
|
+
this.privateKey = new PrivateKey_1.PrivateKey(privateKey);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
this.privateKey = privateKey;
|
|
15
|
+
}
|
|
16
|
+
if (!(certificate instanceof PublicKey_1.PublicKey)) {
|
|
17
|
+
this.certificate = new PublicKey_1.PublicKey(certificate);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
this.certificate = certificate;
|
|
21
|
+
}
|
|
11
22
|
this.platformCerts = this.normalizePlatformCerts(platformCerts);
|
|
12
23
|
}
|
|
13
24
|
/**
|
package/dist/Pay/Signature.js
CHANGED
|
@@ -36,8 +36,8 @@ class Signature {
|
|
|
36
36
|
}
|
|
37
37
|
let signString = `${method.toUpperCase()}\n${pathname}\n${timestamp}\n${nonce}\n${body}`;
|
|
38
38
|
let rsa = new RSA_1.default;
|
|
39
|
-
rsa.setPublicKey(this.merchant.getCertificate().
|
|
40
|
-
rsa.setPrivateKey(this.merchant.getPrivateKey().
|
|
39
|
+
rsa.setPublicKey(this.merchant.getCertificate().getValue());
|
|
40
|
+
rsa.setPrivateKey(this.merchant.getPrivateKey().getKey());
|
|
41
41
|
let sign = rsa.sign(signString);
|
|
42
42
|
return `WECHATPAY2-SHA256-RSA2048 mchid="${this.merchant.getMerchantId()}",nonce_str="${nonce}",timestamp="${timestamp}",serial_no="${this.merchant.getCertificate().getSerialNo()}",signature="${sign}"`;
|
|
43
43
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-easywechat",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"description": "EasyWechat SDK for Node.js (NOT OFFICIAL)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
],
|
|
19
19
|
"author": "Hpyer",
|
|
20
20
|
"license": "MIT",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=15.6.0"
|
|
23
|
+
},
|
|
21
24
|
"devDependencies": {
|
|
22
25
|
"@types/node": "^17.0.23",
|
|
23
26
|
"axios-mock-adapter": "^1.21.1",
|