From 48e738b6a937a05d11fdbd39bd24cf76cfb590c3 Mon Sep 17 00:00:00 2001
From: Jackson Tian
Date: Mon, 8 Jan 2018 11:52:50 +0800
Subject: [PATCH 1/3] =?UTF-8?q?=E5=88=86=E7=A6=BB=20get/post=20=E9=80=BB?=
=?UTF-8?q?=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
lib/wechat.js | 228 ++++++++++++++++++++++++++++----------------------
1 file changed, 129 insertions(+), 99 deletions(-)
diff --git a/lib/wechat.js b/lib/wechat.js
index 80b29e5..5da332c 100644
--- a/lib/wechat.js
+++ b/lib/wechat.js
@@ -112,19 +112,20 @@ var tpl = ['',
*/
var compiled = ejs.compile(tpl);
-var wrapTpl = '' +
- ']]>' +
- ']]>' +
- '<%-timestamp%>' +
- ']]>' +
-'';
-
-var encryptWrap = ejs.compile(wrapTpl);
+var encryptWrap = (function () {
+ var tpl = '' +
+ '' +
+ '' +
+ '${locals.timestamp}' +
+ '' +
+ '';
+ return new Function ('locals', 'return `' + tpl + '`;');
+}());
function reply2CustomerService (fromUsername, toUsername, kfAccount) {
var info = {};
info.msgType = 'transfer_customer_service';
- info.createTime = new Date().getTime();
+ info.createTime = Date.now();
info.toUsername = toUsername;
info.fromUsername = fromUsername;
info.content = {};
@@ -155,7 +156,7 @@ function reply (content, fromUsername, toUsername) {
}
}
info.msgType = type;
- info.createTime = new Date().getTime();
+ info.createTime = Date.now();
info.toUsername = toUsername;
info.fromUsername = fromUsername;
return compiled(info);
@@ -169,124 +170,153 @@ class Wechat {
this.token = config.token;
this.appid = config.appid || '';
this.encodingAESKey = config.encodingAESKey || '';
+ this.cryptor = new WXBizMsgCrypt(this.token, this.encodingAESKey, this.appid);
} else {
throw new TypeError('please check your config');
}
}
- middleware(handle) {
-
- if (this.encodingAESKey) {
- this.cryptor = new WXBizMsgCrypt(this.token, this.encodingAESKey, this.appid);
- }
-
+ get() {
return async (ctx, next) => {
+ const method = ctx.method;
+ if (method !== 'GET') {
+ throw new Error('The wechat.get handle only support GET method');
+ }
+
const query = ctx.query;
+ const {timestamp, nonce, echostr} = query;
+
// 加密模式
const encrypted = !!(query.encrypt_type && query.encrypt_type === 'aes' && query.msg_signature);
- const timestamp = query.timestamp;
- const nonce = query.nonce;
- const echostr = query.echostr;
- const method = ctx.method;
const TOKEN = ctx.wx_token || this.token;
const CRYPTOR = ctx.wx_cryptor || this.cryptor;
- if (method === 'GET') {
- var valid = false;
+ var valid = false;
+ if (encrypted) {
+ if (!CRYPTOR) {
+ throw new Error(`In encrypt mode, must configure 'encodingAESKey' and 'appid'`);
+ }
+ var signature = query.msg_signature;
+ valid = signature === CRYPTOR.getSignature(timestamp, nonce, echostr);
+ } else {
+ // 校验
+ valid = query.signature === getSignature(timestamp, nonce, TOKEN);
+ }
+
+ if (!valid) {
+ ctx.status = 401;
+ ctx.body = 'Invalid signature';
+ } else {
if (encrypted) {
- var signature = query.msg_signature;
- valid = signature === CRYPTOR.getSignature(timestamp, nonce, echostr);
+ var decrypted = CRYPTOR.decrypt(echostr);
+ // TODO 检查appId的正确性
+ ctx.body = decrypted.message;
} else {
- // 校验
- valid = query.signature === getSignature(timestamp, nonce, TOKEN);
+ ctx.body = echostr;
}
+ }
+ };
+ }
- if (!valid) {
+ post(handle) {
+ return async (ctx, next) => {
+ const method = ctx.method;
+ if (method !== 'POST') {
+ throw new Error('The wechat.post handle only support POST method');
+ }
+
+ const query = ctx.query;
+ const {timestamp, nonce} = query;
+
+ const TOKEN = ctx.wx_token || this.token;
+ const CRYPTOR = ctx.wx_cryptor || this.cryptor;
+
+ // 加密模式
+ const encrypted = !!(query.encrypt_type && query.encrypt_type === 'aes' && query.msg_signature);
+
+ if (!encrypted) {
+ // 校验
+ if (query.signature !== getSignature(timestamp, nonce, TOKEN)) {
ctx.status = 401;
ctx.body = 'Invalid signature';
- } else {
- if (encrypted) {
- var decrypted = CRYPTOR.decrypt(echostr);
- // TODO 检查appId的正确性
- ctx.body = decrypted.message;
- } else {
- ctx.body = echostr;
- }
- }
- } else if (method === 'POST') {
- if (!encrypted) {
- // 校验
- if (query.signature !== getSignature(timestamp, nonce, TOKEN)) {
- ctx.status = 401;
- ctx.body = 'Invalid signature';
- return;
- }
+ return;
}
+ }
- var xml;
- if (ctx.request.body && typeof ctx.request.body === 'string') {
- xml = ctx.request.body;
- } else {
- // 取原始数据
- xml = await getRawBody(ctx.req, {
- length: ctx.request.length,
- limit: '1mb',
- encoding: ctx.request.charset || 'utf-8'
- });
- }
+ var xml;
+ if (ctx.request.body && typeof ctx.request.body === 'string') {
+ xml = ctx.request.body;
+ } else {
+ // 取原始数据
+ xml = await getRawBody(ctx.req, {
+ length: ctx.request.length,
+ limit: '1mb',
+ encoding: ctx.request.charset || 'utf-8'
+ });
+ }
- // 保存原始xml
- ctx.weixin_xml = xml;
- // 解析xml
- var result = await parseXML(xml);
- var formatted = formatMessage(result.xml);
- if (encrypted) {
- var encryptMessage = formatted.Encrypt;
- if (query.msg_signature !== CRYPTOR.getSignature(timestamp, nonce, encryptMessage)) {
- ctx.status = 401;
- ctx.body = 'Invalid signature';
- return;
- }
- var decryptedXML = CRYPTOR.decrypt(encryptMessage);
- var messageWrapXml = decryptedXML.message;
- if (messageWrapXml === '') {
- ctx.status = 401;
- ctx.body = 'Invalid signature';
- return;
- }
- var decodedXML = await parseXML(messageWrapXml);
- formatted = formatMessage(decodedXML.xml);
+ // 保存原始xml
+ ctx.weixin_xml = xml;
+ // 解析xml
+ var result = await parseXML(xml);
+ var formatted = formatMessage(result.xml);
+ if (encrypted) {
+ var encryptMessage = formatted.Encrypt;
+ if (query.msg_signature !== CRYPTOR.getSignature(timestamp, nonce, encryptMessage)) {
+ ctx.status = 401;
+ ctx.body = 'Invalid signature';
+ return;
}
-
- // 业务逻辑处理
- // 注意不要在业务逻辑中操作 body、type
- const body = await handle(formatted, ctx);
-
- /*
- * 假如服务器无法保证在五秒内处理并回复,可以直接回复空串。
- * 微信服务器不会对此作任何处理,并且不会发起重试。
- */
- if (body === '') {
- ctx.body = '';
+ var decryptedXML = CRYPTOR.decrypt(encryptMessage);
+ var messageWrapXml = decryptedXML.message;
+ if (messageWrapXml === '') {
+ ctx.status = 401;
+ ctx.body = 'Invalid signature';
return;
}
+ var decodedXML = await parseXML(messageWrapXml);
+ formatted = formatMessage(decodedXML.xml);
+ }
- var replyMessageXml = reply(body, formatted.ToUserName, formatted.FromUserName);
+ // 业务逻辑处理
+ // 注意不要在业务逻辑中操作 body、type
+ const body = await handle(formatted, ctx);
- if (!query.encrypt_type || query.encrypt_type === 'raw') {
- ctx.body = replyMessageXml;
- } else {
- var wrap = {};
- wrap.encrypt = CRYPTOR.encrypt(replyMessageXml);
- wrap.nonce = parseInt((Math.random() * 100000000000), 10);
- wrap.timestamp = new Date().getTime();
- wrap.signature = CRYPTOR.getSignature(wrap.timestamp, wrap.nonce, wrap.encrypt);
- ctx.body = encryptWrap(wrap);
- }
+ /*
+ * 假如服务器无法保证在五秒内处理并回复,可以直接回复空串。
+ * 微信服务器不会对此作任何处理,并且不会发起重试。
+ */
+ if (body === '') {
+ ctx.body = '';
+ return;
+ }
+
+ var replyMessageXml = reply(body, formatted.ToUserName, formatted.FromUserName);
+
+ if (!query.encrypt_type || query.encrypt_type === 'raw') {
+ ctx.body = replyMessageXml;
+ } else {
+ var wrap = {};
+ wrap.encrypt = CRYPTOR.encrypt(replyMessageXml);
+ wrap.nonce = parseInt((Math.random() * 100000000000), 10);
+ wrap.timestamp = Date.now();
+ wrap.signature = CRYPTOR.getSignature(wrap.timestamp, wrap.nonce, wrap.encrypt);
+ ctx.body = encryptWrap(wrap);
+ }
- ctx.type = 'application/xml';
+ ctx.type = 'application/xml';
+ };
+ }
+
+ middleware(handle) {
+ return async (ctx, next) => {
+ const method = ctx.method;
+ if (method === 'GET') {
+ this.get()(ctx, next);
+ } else if (method === 'POST') {
+ this.post(handle)(ctx, next);
} else {
ctx.status = 501;
ctx.body = 'Not Implemented';
From 59d6c2736562a4b2308d0012ce400600c2b83c1f Mon Sep 17 00:00:00 2001
From: Jackson Tian
Date: Mon, 8 Jan 2018 12:02:56 +0800
Subject: [PATCH 2/3] refine test case
---
lib/wechat.js | 7 +++----
test/wechat.test.js | 8 ++++----
2 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/lib/wechat.js b/lib/wechat.js
index 5da332c..003abf8 100644
--- a/lib/wechat.js
+++ b/lib/wechat.js
@@ -195,7 +195,7 @@ class Wechat {
var valid = false;
if (encrypted) {
if (!CRYPTOR) {
- throw new Error(`In encrypt mode, must configure 'encodingAESKey' and 'appid'`);
+ throw new Error('In encrypt mode, must configure \'encodingAESKey\' and \'appid\'');
}
var signature = query.msg_signature;
valid = signature === CRYPTOR.getSignature(timestamp, nonce, echostr);
@@ -282,7 +282,6 @@ class Wechat {
// 业务逻辑处理
// 注意不要在业务逻辑中操作 body、type
const body = await handle(formatted, ctx);
-
/*
* 假如服务器无法保证在五秒内处理并回复,可以直接回复空串。
* 微信服务器不会对此作任何处理,并且不会发起重试。
@@ -314,9 +313,9 @@ class Wechat {
const method = ctx.method;
if (method === 'GET') {
- this.get()(ctx, next);
+ await this.get()(ctx, next);
} else if (method === 'POST') {
- this.post(handle)(ctx, next);
+ await this.post(handle)(ctx, next);
} else {
ctx.status = 501;
ctx.body = 'Not Implemented';
diff --git a/test/wechat.test.js b/test/wechat.test.js
index 2e2fbc7..911ae43 100644
--- a/test/wechat.test.js
+++ b/test/wechat.test.js
@@ -69,7 +69,7 @@ describe('wechat.js', function () {
it('should 200', function (done) {
var q = {
- timestamp: new Date().getTime(),
+ timestamp: Date.now(),
nonce: parseInt((Math.random() * 10e10), 10)
};
var s = ['some token', q.timestamp, q.nonce].sort().join('');
@@ -83,7 +83,7 @@ describe('wechat.js', function () {
it('should 401 invalid signature', function (done) {
var q = {
- timestamp: new Date().getTime(),
+ timestamp: Date.now(),
nonce: parseInt((Math.random() * 10e10), 10)
};
q.signature = 'invalid_signature';
@@ -105,7 +105,7 @@ describe('wechat.js', function () {
it('should 401 invalid signature', function (done) {
var q = {
- timestamp: new Date().getTime(),
+ timestamp: Date.now(),
nonce: parseInt((Math.random() * 10e10), 10)
};
q.signature = 'invalid_signature';
@@ -120,7 +120,7 @@ describe('wechat.js', function () {
describe('valid other method', function () {
it('should 200', function (done) {
var q = {
- timestamp: new Date().getTime(),
+ timestamp: Date.now(),
nonce: parseInt((Math.random() * 10e10), 10)
};
var s = ['some token', q.timestamp, q.nonce].sort().join('');
From 3078d6c824ac66a939c1bd3380b01d0d9abc3c41 Mon Sep 17 00:00:00 2001
From: Jackson Tian
Date: Mon, 8 Jan 2018 12:27:00 +0800
Subject: [PATCH 3/3] remove useless dependencies
---
.travis.yml | 1 +
package.json | 2 -
test/wechat.test.js | 135 ++++++++++++++++++++++----------------------
3 files changed, 69 insertions(+), 69 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 63b5649..55f12a9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,5 @@
language: node_js
node_js:
- "8"
+ - "9"
script: make test-coveralls
diff --git a/package.json b/package.json
index 5c46cc8..bea59c2 100644
--- a/package.json
+++ b/package.json
@@ -26,13 +26,11 @@
"coveralls": "*",
"expect.js": "*",
"koa": "^2.0.0",
- "koa-generic-session": "*",
"mocha": "*",
"mocha-lcov-reporter": "*",
"muk": "*",
"nyc": "^10.2.0",
"rewire": "*",
- "should": "~3.0.0",
"supertest": "*",
"travis-cov": "*"
},
diff --git a/test/wechat.test.js b/test/wechat.test.js
index 911ae43..ba828ef 100644
--- a/test/wechat.test.js
+++ b/test/wechat.test.js
@@ -1,12 +1,12 @@
'use strict';
-require('should');
+const querystring = require('querystring');
const Koa = require('koa');
-const querystring = require('querystring');
+const expect = require('expect.js');
const request = require('supertest');
-const template = require('./support').template;
-const tail = require('./support').tail;
+
+const { template, tail } = require('./support');
const wechat = require('../');
@@ -148,11 +148,12 @@ describe('wechat.js', function () {
.end(function(err, res){
if (err) {return done(err);}
var body = res.text.toString();
- body.should.include('');
- body.should.include('');
- body.should.match(/\d{13}<\/CreateTime>/);
- body.should.include('');
- body.should.include('');
+
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.match(/\d{13}<\/CreateTime>/);
+ expect(body).to.contain('');
+ expect(body).to.contain('');
done();
});
});
@@ -172,11 +173,11 @@ describe('wechat.js', function () {
.end(function(err, res){
if (err) {return done(err);}
var body = res.text.toString();
- body.should.include('');
- body.should.include('');
- body.should.match(/\d{13}<\/CreateTime>/);
- body.should.include('');
- body.should.include('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.match(/\d{13}<\/CreateTime>/);
+ expect(body).to.contain('');
+ expect(body).to.contain('');
done();
});
});
@@ -196,15 +197,15 @@ describe('wechat.js', function () {
.end(function(err, res){
if (err) {return done(err);}
var body = res.text.toString();
- body.should.include('');
- body.should.include('');
- body.should.match(/\d{13}<\/CreateTime>/);
- body.should.include('');
- body.should.include('1');
- body.should.include('<![CDATA[你来我家接我吧]]>');
- body.should.include('');
- body.should.include('');
- body.should.include('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.match(/\d{13}<\/CreateTime>/);
+ expect(body).to.contain('');
+ expect(body).to.contain('1');
+ expect(body).to.contain('<![CDATA[你来我家接我吧]]>');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
done();
});
});
@@ -224,16 +225,16 @@ describe('wechat.js', function () {
.end(function(err, res){
if (err) {return done(err);}
var body = res.text.toString();
- body.should.include('');
- body.should.include('');
- body.should.match(/\d{13}<\/CreateTime>/);
- body.should.include('');
- body.should.include('');
- body.should.include('');
- body.should.include('<![CDATA[来段音乐吧<]]>');
- body.should.include(']]>');
- body.should.include('');
- body.should.include('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.match(/\d{13}<\/CreateTime>/);
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.contain('<![CDATA[来段音乐吧<]]>');
+ expect(body).to.contain(']]>');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
done();
});
});
@@ -258,11 +259,11 @@ describe('wechat.js', function () {
.end(function(err, res){
if (err) {return done(err);}
var body = res.text.toString();
- body.should.include('');
- body.should.include('');
- body.should.match(/\d{13}<\/CreateTime>/);
- body.should.include('');
- body.should.include('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.match(/\d{13}<\/CreateTime>/);
+ expect(body).to.contain('');
+ expect(body).to.contain('');
done();
});
});
@@ -284,11 +285,11 @@ describe('wechat.js', function () {
.end(function(err, res){
if (err) {return done(err);}
var body = res.text.toString();
- body.should.include('');
- body.should.include('');
- body.should.match(/\d{13}<\/CreateTime>/);
- body.should.include('');
- body.should.include('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.match(/\d{13}<\/CreateTime>/);
+ expect(body).to.contain('');
+ expect(body).to.contain('');
done();
});
});
@@ -308,10 +309,10 @@ describe('wechat.js', function () {
.end(function(err, res){
if (err) {return done(err);}
var body = res.text.toString();
- body.should.include('');
- body.should.include('');
- body.should.match(/\d{13}<\/CreateTime>/);
- body.should.include('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.match(/\d{13}<\/CreateTime>/);
+ expect(body).to.contain('');
done();
});
});
@@ -331,11 +332,11 @@ describe('wechat.js', function () {
.end(function(err, res) {
if (err) {return done(err);}
var body = res.text.toString();
- body.should.include('');
- body.should.include('');
- body.should.match(/\d{13}<\/CreateTime>/);
- body.should.include('');
- body.should.include('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.match(/\d{13}<\/CreateTime>/);
+ expect(body).to.contain('');
+ expect(body).to.contain('');
done();
});
});
@@ -355,11 +356,11 @@ describe('wechat.js', function () {
.end(function(err, res){
if (err) {return done(err);}
var body = res.text.toString();
- body.should.include('');
- body.should.include('');
- body.should.match(/\d{13}<\/CreateTime>/);
- body.should.include('');
- body.should.include('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.match(/\d{13}<\/CreateTime>/);
+ expect(body).to.contain('');
+ expect(body).to.contain('');
done();
});
});
@@ -379,16 +380,16 @@ describe('wechat.js', function () {
.end(function(err, res){
if (err) {return done(err);}
var body = res.text.toString();
- body.should.include('');
- body.should.include('');
- body.should.match(/\d{13}<\/CreateTime>/);
- body.should.include('');
- body.should.include('');
- body.should.include('');
- body.should.include('<![CDATA[来段音乐吧<]]>');
- body.should.include(']]>');
- body.should.include('');
- body.should.include('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.match(/\d{13}<\/CreateTime>/);
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
+ expect(body).to.contain('<![CDATA[来段音乐吧<]]>');
+ expect(body).to.contain(']]>');
+ expect(body).to.contain('');
+ expect(body).to.contain('');
done();
});
});