[关闭]
@leptune 2018-09-12T02:16:48.000000Z 字数 9194 阅读 303

微信机器人-chrome插件版

chrome插件


前言




架构图



插件源码


  1. {
  2. "manifest_version": 2,
  3. "name": "微信机器人",
  4. "description": "chrome微信机器人",
  5. "version": "1.0",
  6. "browser_action": {
  7. "default_icon": "img/icon.png"
  8. },
  9. "devtools_page": "devtools.html",
  10. "background": {
  11. "scripts": ["js/jquery-2.0.3.js", "js/background.js"]
  12. },
  13. "content_scripts": [{
  14. "matches": ["https://wx2.qq.com/*","https://wx.qq.com/*"],
  15. "js": ["js/jquery-2.0.3.js", "js/content.js"]
  16. }
  17. ],
  18. "permissions": [
  19. "activeTab",
  20. "tabs",
  21. "https://login.weixin.qq.com/*",
  22. "https://wx2.qq.com/*",
  23. "http://www.wx-robot.com/*",
  24. "https://wx.qq.com/*"
  25. ]
  26. }

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <script src="js/devtools.js" charset="utf-8" type="text/javascript"></script>
  7. </head>
  8. <body>
  9. </body>
  10. </html>

  1. chrome.extension.sendRequest({tabId: chrome.devtools.inspectedWindow.tabId, action: 'dev_start', msg: 'devtools js start'});
  2. // dev域用于toolbar的网络监听
  3. chrome.devtools.network.onRequestFinished.addListener(function (request) {
  4. // 转发所有微信请求到background页面
  5. if (request.request.url.indexOf('wx2.qq.com') != -1 || request.request.url.indexOf('wx.qq.com') != -1) {
  6. request.getContent(function (body) {
  7. chrome.extension.sendRequest({
  8. tabId: chrome.devtools.inspectedWindow.tabId,
  9. action: 'request',
  10. request: request,
  11. body: body,
  12. });
  13. });
  14. }
  15. return true;
  16. });

  1. console.log('backgroud js start');
  2. // 监听来自content-script的消息
  3. chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  4. // console.log('收到content-js消息');
  5. switch (request.action) {
  6. case 'request':
  7. // console.log(request);
  8. if (request.data.type == 'post') {
  9. $.post(request.data.url, request.data.data, function (data) {
  10. // console.log('post res:', data);
  11. sendResponse(data);
  12. });
  13. } else {
  14. $.get(request.data.url, function (data) {
  15. // console.log('get res:', data);
  16. sendResponse(data);
  17. });
  18. }
  19. break;
  20. }
  21. return true;
  22. });
  23. // 接收来自dev页面的消息
  24. chrome.extension.onRequest.addListener(function (request) {
  25. // 直接转发给content页面
  26. // console.log(request)
  27. chrome.tabs.sendRequest(request.tabId, request);
  28. });

  1. console.log('content js start');
  2. var initGlobals = {
  3. friendsInfo: {},
  4. friends: {},
  5. groupsInfo: {},
  6. groups: {},
  7. myInfo: {},
  8. my: {},
  9. sendBase: {},
  10. notFirst: true,
  11. };
  12. var otherGlobals = {
  13. adminUser: {},
  14. };
  15. String.prototype.trimChars = function (c) {
  16. var re = new RegExp("^[" + c + "]+|[" + c + "]+$", "g");
  17. return this.replace(re, "");
  18. }
  19. function init_globals() {
  20. initGlobals = {
  21. friendsInfo: {},
  22. friends: {},
  23. groupsInfo: {},
  24. groups: {},
  25. myInfo: {},
  26. my: {},
  27. sendBase: {},
  28. notFirst: true,
  29. };
  30. }
  31. function typeOf(obj) {
  32. return {}.toString.call(obj).split(' ')[1].slice(0, -1).toLowerCase();
  33. }
  34. function isEmpty(value) {
  35. if (!value) {
  36. return true;
  37. }
  38. if ('array' == typeOf(value) || 'string' == typeOf(value)) {
  39. return !value.length;
  40. }
  41. if('object' == typeOf(value)){
  42. for(var key in value) {
  43. if(Object.prototype.hasOwnProperty.call(value, key)) {
  44. return false;
  45. }
  46. }
  47. return true;
  48. }
  49. return false;
  50. }
  51. function getNullKeys() {
  52. var nullKeys = [];
  53. for (var key in initGlobals) {
  54. if (isEmpty(initGlobals[key])) {
  55. nullKeys.push(key);
  56. }
  57. }
  58. return nullKeys;
  59. }
  60. function login() {
  61. $('body').append('\
  62. <div class="wx-robot-top">\
  63. <style>\
  64. .wx-robot-zzc {position: fixed; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba(0,0,0,.8); z-index:9998}\
  65. .wx-robot-wrap {width: 100%;text-align: center;position: absolute;top: 20%;background: none;z-index: 9999;}\
  66. .wx-robot-div {width: 60%; text-align: center; background: #f1f1f1; padding: 31px; margin: 0 auto;}\
  67. .wx-robot-btn-user {width: 30%; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; border: 1px solid #ccc; border-radius: 4px;}\
  68. .wx-robot-btn-pwd {width: 30%; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; border: 1px solid #ccc; border-radius: 4px;}\
  69. .wx-robot-btn-login {width: 19%; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; border: 1px solid #ccc; border-radius: 4px;}\
  70. .wx-robot-btn-login:hover {color: #333; background-color: #e6e6e6; border-color: #adadad; }\
  71. </style>\
  72. <div class="wx-robot-wrap">\
  73. <div class="wx-robot-div">\
  74. <h1>微信机器人后台管理系统</h1>\
  75. <br/>\
  76. <div class="my-wx-robot">\
  77. <input class="wx-robot-btn-user" name="robot_user" type="text" placeholder="用户名">\
  78. <input class="wx-robot-btn-pwd" name="robot_pwd" type="password" placeholder="密码">\
  79. <input class="wx-robot-btn-login" type="button" value="登录">\
  80. </div>\
  81. </div>\
  82. </div>\
  83. <div class="wx-robot-zzc"></div>\
  84. </div>\
  85. ');
  86. }
  87. function setInitGlobas(key, value) {
  88. // console.log('get initGlobals.'+key);
  89. initGlobals[key] = value;
  90. //发送消息content层
  91. var nullKeys = getNullKeys();
  92. if (!nullKeys.length) {
  93. console.log('all finished!');
  94. initGlobals.notFirst = false; // 确保初始化程序只运行一次
  95. myRequest({
  96. url: 'http://www.wx-robot.com/index/chrome/isLogin',
  97. callback: function(data) { //检测是否已经登录后台
  98. // console.log(data);
  99. if (data.errcode) {
  100. login();
  101. } else {
  102. otherGlobals.adminUser = data.data;
  103. console.log('开始监听任务...');
  104. listenTask();
  105. }
  106. },
  107. });
  108. } else {
  109. if (nullKeys.length > 1) console.log('nullKeys: ', nullKeys);
  110. }
  111. }
  112. function do_request(request) {
  113. var reqData = request.request.request;
  114. if (-1 != reqData.url.indexOf('&me=me')) { // 避开循环监听
  115. return;
  116. }
  117. // 获取群联系人(不能直接用监听返回的数据,因为中文会乱码)
  118. if (-1 != reqData.url.indexOf('wx2.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact')) {
  119. var tmpData = JSON.parse(reqData.postData.text);
  120. if (!isEmpty(tmpData) && !isEmpty(tmpData.BaseRequest)) {
  121. setInitGlobas('sendBase', tmpData.BaseRequest);
  122. }
  123. $.post(reqData.url+'&me=me', JSON.stringify(JSON.parse(reqData.postData.text)), function (data) {
  124. setInitGlobas('groupsInfo', JSON.parse(data));
  125. var tmpData = {};
  126. initGlobals.groupsInfo.ContactList.forEach(function(e){
  127. tmpData[e.NickName] = e.UserName;
  128. });
  129. setInitGlobas('groups', tmpData);
  130. });
  131. }
  132. if (-1 != reqData.url.indexOf('wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact')) {
  133. // 获取联系人(不能直接用监听返回的数据,因为中文会乱码)
  134. $.get(reqData.url+'&me=me', function (data) {
  135. setInitGlobas('friendsInfo', JSON.parse(data));
  136. var tmpData = {};
  137. initGlobals.friendsInfo.MemberList.forEach(function(e){
  138. tmpData[e.NickName] = e.UserName;
  139. });
  140. setInitGlobas('friends', tmpData);
  141. });
  142. }
  143. if (-1 != reqData.url.indexOf('wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit')) {
  144. var tmpData = JSON.parse(request.body);
  145. if (!isEmpty(tmpData) && !isEmpty(tmpData.User)) {
  146. setInitGlobas('myInfo', tmpData);
  147. setInitGlobas('my', tmpData.User);
  148. }
  149. }
  150. if (-1 != reqData.url.indexOf('wx2.qq.com/cgi-bin/mmwebwx-bin/webwxlogout')) {
  151. // 重新初始化
  152. init_globals();
  153. }
  154. }
  155. function myRequest(param) {
  156. chrome.runtime.sendMessage({
  157. action: 'request',
  158. data: param,
  159. }, function(response) {
  160. if (param.callback) {
  161. param.callback(response);
  162. }
  163. });
  164. }
  165. function sendmsg(data, task_id) {
  166. if (!data.nickname && !data.username) {
  167. return;
  168. }
  169. var Msg = {
  170. Type: 1,
  171. Content: "0",
  172. FromUserName: "0",
  173. ToUserName: "0",
  174. LocalID: "0",
  175. ClientMsgId: "0"
  176. };
  177. var username = data.username;
  178. if (!username) {
  179. if (!data.isGroup && initGlobals.friends[data.nickname]) {
  180. username = initGlobals.friends[data.nickname];
  181. } else if (data.isGroup && initGlobals.groups[data.nickname]) {
  182. username = initGlobals.groups[data.nickname];
  183. }
  184. }
  185. if (!username) {
  186. console.log('没有该用户: ', data.nickname);
  187. return;
  188. }
  189. Msg.Content = data.msg;
  190. Msg.ToUserName = username;
  191. Msg.FromUserName = initGlobals.my.UserName;
  192. var clientMsgId = new Date().getTime() + (Math.random() + "").substring(2, 6);
  193. Msg.LocalID = clientMsgId;
  194. Msg.ClientMsgId = clientMsgId;
  195. $.post("https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&me=me", JSON.stringify({BaseRequest: initGlobals.sendBase, Msg: Msg, Scene: 0}), function (data) {
  196. data = JSON.parse(data);
  197. // console.log(data);
  198. if (data.BaseResponse.Ret) {
  199. console.log('发送消息失败: ', data.BaseResponse.ErrMsg);
  200. return;
  201. }
  202. console.log('发送消息成功!');
  203. if (task_id) {
  204. myRequest({url: 'http://www.wx-robot.com/index/chrome/execReport?is_success=1&task_id='+task_id, callback: function (data) {
  205. console.log(data);
  206. }});
  207. }
  208. });
  209. }
  210. var clickFlag = 0;
  211. function loginSuccess() {
  212. alert('成功,可以关掉开发者工具栏了!');
  213. $('.wx-robot-top').remove();
  214. // 保持在线
  215. (function heartBit() {
  216. //模拟点击
  217. if(clickFlag == 0) {
  218. clickFlag = 1;
  219. $('.web_wechat_tab_chat').click();
  220. }else {
  221. clickFlag = 0;
  222. $('.web_wechat_tab_friends').click();
  223. }
  224. sendmsg({
  225. username: 'filehelper',
  226. msg: "保持在线:" + new Date(),
  227. });
  228. setTimeout(heartBit, 20*1000);
  229. })();
  230. }
  231. // 循环等待服务器的任务
  232. function listenTask() {
  233. myRequest({
  234. url: 'http://www.wx-robot.com/index/chrome/listen',
  235. callback: function(data) {
  236. // console.log(data);
  237. if (!data.errcode) {
  238. console.log('get task: ', data);
  239. data = data.data;
  240. switch (data.action) {
  241. case 'sendmsg':
  242. sendmsg(data.data, data.id);
  243. break;
  244. }
  245. }
  246. setTimeout(listenTask, 1000);
  247. },
  248. });
  249. }
  250. $(document).on('click', '.wx-robot-btn-login', function(event) {
  251. myRequest({
  252. url: 'http://www.wx-robot.com/index/chrome/login',
  253. type: 'post',
  254. data: {
  255. user: $('.wx-robot-btn-user').val(),
  256. pwd: $('.wx-robot-btn-pwd').val(),
  257. },
  258. callback: function(data) {
  259. // console.log('login data:', data);
  260. if (!data.errcode) {
  261. otherGlobals.adminUser = data.data;
  262. loginSuccess();
  263. listenTask();
  264. } else {
  265. alert('用户名或密码错误!');
  266. }
  267. },
  268. });
  269. });
  270. // 接收来自background页面的消息
  271. chrome.extension.onRequest.addListener(function(request) {
  272. // console.log('收到background消息');
  273. switch (request.action) {
  274. case 'dev_start':
  275. console.log('devtools js start');
  276. break;
  277. case 'request':
  278. do_request(request);
  279. break;
  280. }
  281. return true;
  282. });

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注