├── .gitignore ├── .jshintrc ├── Makefile ├── README.md ├── index.js ├── lib └── wechat_push.js ├── package.json └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage.html 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "module", 5 | "require", 6 | "__dirname", 7 | "process", 8 | "console", 9 | "it", 10 | "xit", 11 | "describe", 12 | "xdescribe", 13 | "before", 14 | "beforeEach", 15 | "after", 16 | "afterEach" 17 | ], 18 | "node": true, 19 | "es5": true, 20 | "bitwise": true, 21 | "curly": true, 22 | "eqeqeq": true, 23 | "forin": false, 24 | "immed": true, 25 | "latedef": true, 26 | "newcap": true, 27 | "noarg": true, 28 | "noempty": true, 29 | "nonew": true, 30 | "plusplus": false, 31 | "undef": true, 32 | "strict": false, 33 | "trailing": false, 34 | "globalstrict": true, 35 | "nonstandard": true, 36 | "white": true, 37 | "indent": 2, 38 | "expr": true, 39 | "multistr": true, 40 | "onevar": false, 41 | "unused": "vars", 42 | "swindent": false 43 | } 44 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TESTS = test/test.js 2 | REPORTER = spec 3 | TIMEOUT = 10000 4 | MOCHA_OPTS = 5 | 6 | install-test: 7 | @NODE_ENV=test npm install 8 | 9 | test: install-test 10 | @NODE_ENV=test ./node_modules/mocha/bin/mocha \ 11 | --reporter $(REPORTER) \ 12 | --timeout $(TIMEOUT) \ 13 | $(MOCHA_OPTS) \ 14 | $(TESTS) 15 | 16 | test-cov: 17 | @$(MAKE) test REPORTER=dot 18 | @$(MAKE) test MOCHA_OPTS='--require blanket' REPORTER=html-cov > coverage.html 19 | @$(MAKE) test MOCHA_OPTS='--require blanket' REPORTER=travis-cov 20 | 21 | test-all: test test-cov 22 | 23 | .PHONY: install-test test test-cov test-all 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Wechat Push 2 | ============= 3 | **微信已经提供了客服消息发送的接口,如需调用,请参见[wechat模块](https://github.com/node-webot/wechat)。本模块将不再维护。** 4 | 5 | 使用方式如下: 6 | 7 | ``` 8 | var Pusher = require('wechat_push'); 9 | 10 | var pusher = new Pusher(username, password); 11 | pusher.login(function (err) { 12 | // send的第一个参数为fakeId,请自行搞定 13 | pusher.send('604347680', '搞定push', function (err, data) { 14 | // 发送完成 15 | done(); 16 | }); 17 | }); 18 | ``` 19 | 20 | ## 注意 21 | 由于微信方面没有公开相关API,不能保证本模块能永远正常工作。 22 | 23 | ## License 24 | The MIT License 25 | 26 | ## 捐赠 27 | 如果您觉得本模块对您有帮助,欢迎请作者一杯咖啡: 28 | 29 | [![捐赠Wechat Push](https://img.alipay.com/sys/personalprod/style/mc/btn-index.png)](https://me.alipay.com/jacksontian) 30 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/wechat_push'); 2 | -------------------------------------------------------------------------------- /lib/wechat_push.js: -------------------------------------------------------------------------------- 1 | var crypto = require('crypto'); 2 | var urllib = require('urllib'); 3 | 4 | var md5 = function (input) { 5 | var hash = crypto.createHash('md5'); 6 | return hash.update(input).digest("hex"); 7 | }; 8 | 9 | var PREFIX = 'https://mp.weixin.qq.com/cgi-bin/'; 10 | 11 | var Pusher = function (username, password) { 12 | // 用户ID 13 | this.username = username; 14 | // 用户密码 15 | this.password = password; 16 | // 用户Cookie 17 | this.cookie = null; 18 | this.token = ''; 19 | }; 20 | 21 | Pusher.prototype.login = function (callback) { 22 | var that = this; 23 | var submitUrl = PREFIX + 'login?lang=zh_CN'; 24 | 25 | var data = { 26 | username: this.username, 27 | pwd: md5(this.password), 28 | f: 'json' 29 | }; 30 | 31 | var options = { 32 | data: data, 33 | type: 'POST', 34 | dataType: 'json', 35 | headers: { 36 | 'Referer': PREFIX + 'loginpage?t=wxm2-login&lang=zh_CN', 37 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36' 38 | } 39 | }; 40 | 41 | urllib.request(submitUrl, options, function (err, body, res) { 42 | if (err) { 43 | return callback(err); 44 | } 45 | var fields = res.headers['set-cookie']; 46 | fields = Array.isArray(fields) ? fields : [fields]; 47 | var cookies = fields.map(function (item) { 48 | return item.replace('Path=/; Secure; HttpOnly', '').replace(';', '').trim(); 49 | }); 50 | // record the cookie 51 | that.cookie = cookies.join('; '); 52 | var token = body.ErrMsg.match(/token=(\d*)/); 53 | // record the token 54 | that.token = token[1]; 55 | callback(null); 56 | }); 57 | }; 58 | 59 | Pusher.prototype.send = function (fakeId, content, callback) { 60 | var token = this.token; 61 | var data = { 62 | 'tofakeid': fakeId, 63 | 'type': 1, 64 | 'content': content, 65 | 'error': 'false', 66 | 'imgcode': '', 67 | 'token': token, 68 | 'ajax': 1 69 | }; 70 | 71 | var options = { 72 | headers: { 73 | 'Referer': PREFIX + 'singlemsgpage?token=' + token + '&fromfakeid=' + fakeId + '&msgid=&source=&count=20&t=wxm-singlechat&lang=zh_CN', 74 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36', 75 | 'Cookie': this.cookie 76 | }, 77 | type: 'POST', 78 | dataType: 'json', 79 | data: data 80 | }; 81 | 82 | var url = PREFIX + 'singlesend?t=ajax-response&lang=zh_CN'; 83 | urllib.request(url, options, function (err, body, res) { 84 | if (err) { 85 | return callback(err); 86 | } 87 | if (body.ret !== '0') { 88 | var e = new Error(body.msg); 89 | e.name = 'WechatPushError'; 90 | return callback(e); 91 | } 92 | callback(err, body); 93 | }); 94 | }; 95 | 96 | Pusher.prototype.getAvatar = function (fakeId) { 97 | return PREFIX + 'getheadimg?token=' + this.token + '&fakeid=' + fakeId; 98 | }; 99 | 100 | module.exports = Pusher; 101 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wechat_push", 3 | "version": "0.0.1", 4 | "description": "Wechat Push", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "make test-all", 8 | "blanket": { 9 | "pattern": "wechat_push/lib", 10 | "data-cover-flags": { 11 | "debug": false 12 | } 13 | }, 14 | "travis-cov": { 15 | "threshold": 99 16 | } 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git://github.com/JacksonTian/wechat_push.git" 21 | }, 22 | "keywords": [ 23 | "Wechat", 24 | "Push" 25 | ], 26 | "author": "Jackson Tian", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/JacksonTian/wechat_push/issues" 30 | }, 31 | "dependencies": { 32 | "urllib": "0.3.4" 33 | }, 34 | "devDependencies": { 35 | "mocha": "*", 36 | "should": "*", 37 | "blanket": "*", 38 | "travis-cov": "*" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var Pusher = require('../'); 2 | var should = require('should'); 3 | var username = 'YOUR_USERNAME'; 4 | var password = 'YOUR_PASSWORD'; 5 | 6 | describe('push', function () { 7 | describe('new', function () { 8 | it('should ok', function () { 9 | var pusher = new Pusher(username, password); 10 | pusher.username.should.ok; 11 | pusher.password.should.ok; 12 | }); 13 | }); 14 | 15 | describe('login', function () { 16 | it('should ok', function (done) { 17 | var pusher = new Pusher(username, password); 18 | pusher.login(function (err, cookie) { 19 | should.not.exist(err); 20 | pusher.cookie.should.have.length(249); 21 | pusher.token.should.match(/\d{10}/); 22 | done(); 23 | }); 24 | }); 25 | }); 26 | 27 | describe('send', function () { 28 | it('should ok', function (done) { 29 | var pusher = new Pusher(username, password); 30 | pusher.login(function (err) { 31 | should.not.exist(err); 32 | pusher.send('604347680', '搞定push', function (err, data) { 33 | should.not.exist(err); 34 | data.ret.should.equal('0'); 35 | data.msg.should.equal('ok'); 36 | done(); 37 | }); 38 | }); 39 | }); 40 | }); 41 | }); 42 | --------------------------------------------------------------------------------