实现一个“人工智能”QQ机器人!

参考

前言

如今WebQQ已经凉了,网上那些基于WebQQ协议的框架也随之而去。
如今想基于QQ作些自动化的能够考虑IOTQQ,这是一款基于MacQQ逆向的QQ机器人框架。java

服务器部署

其实IOTQQ项目主页的步骤介绍已经很清晰,这里只说一些注意点吧:node

  • 如今腾讯对这类基于逆向破解协议的野生机器人封杀的仍是很厉害的,安全起见,建议注册新QQ号进行测试
  • 直接部署在服务器上反而要简单些,由于不须要进行frp内网穿透部署,不过建议不要浪,尽可能用固定的一台服务器IP,不然说不定腾讯会由于异地登陆封杀你的QQ号
  • 用下面的命令后台启动IOTQQ:nginx

    nohup /path/to/IOTQQ >> /path/to/IOTQQ/log.txt 2>&1 &
  • 头一次启动IOTQQ会自动下载一些Lua脚本文件,若是没有,关了从新启动
  • 启动之后浏览器访问http://<host>:<port>/v1/InstallService执行初始化,若是没有看到提示Auth初始化完成,那么说明没成功,须要登陆你的Github帐号,删除Bot-Notify仓库,以后重复初始化过程
  • 初始化成功之后就能够访问/Login/GetQRcode获取二维码,而后用手机QQ扫码登陆便可

WEB_API的调用

  • IOTQQ提供Web API供外部调用,只要知道接口地址,能够用任何http工具或者编程语言调用
  • IOTQQ项目中有个WebAPI.json,能够直接导入Chrome插件RestletClient,既能够直接调用测试,也能够做为文档参考,很方便
  • 这个插件在Chrome商店里也能搜索到,新版本叫Talend API Tester
  • 把WebAPI.json导入以前,能够找个文本编辑器修改一下,主要是把接口地址和QQ号批量替换一下,这样导入后能够直接用
  • 下面是使用request调用Web API的例子:git

    const rp = require('request-promise').defaults({ json: true, gzip: true })
    async function callApi (name, params) {
      const url = `${WEB_API}/LuaApiCaller?qq=${LOGIN_QQ}&funcname=${name}&timeout=10`
      if (params) return rp.post(url, { body: params })
      return rp.get(url)
    }

WebSocket接口的使用

  • WebAPI是用来发消息、发指令的,对应的收消息、收事件则须要使用IOTQQ的websocket接口
  • IOTQQ的websocket是基于socket.io实现的,不能直接用ws://...方式访问,所以网上的一些websocket测试工具都没法使用,只能用兼容socket.io的客户端访问
  • nodejs开发须要引入socket.io-client
  • 简单代码以下:github

    const io = require('socket.io-client')
    const socket = io(WS_API, { transports: ['websocket'] })
    socket.on('connect', e => {
      console.log('WS已链接')
      socket.emit('GetWebConn', '' + LOGIN_QQ, (data) => console.log(data))
    })
    socket.on('disconnect', e => console.log('WS已断开', e))
    socket.on('OnGroupMsgs', async data => {
      console.log('>>OnGroupMsgs', JSON.stringify(data, null, 2))
    })
    socket.on('OnFriendMsgs', async data => {
      console.log('>>OnFriendMsgs', JSON.stringify(data, null, 2))
      const { FromUin, MsgType, Content } = data.CurrentPacket.Data
      if (MsgType !== 'TextMsg') return
      const reply = Content.replace(/你/g, '我').replace(/(?:么?|么\?|吗?|吗\?|?|\?)?$/, '!')
      const params = { toUser: FromUin, sendToType: 1, sendMsgType: 'TextMsg', content: reply, groupid: 0, atUser: 0, replayInfo: null }
      const resp = await callApi('SendMsg', params)
      console.log('callApi.result', resp)
    })
    socket.on('OnEvents', async data => {
      console.log('>>OnEvents', JSON.stringify(data, null, 2))
    })

    比较关键的有两点:web

    1. 调用io函数建立链接时须要提供{ transports: ['websocket'] }参数
    2. 链接上以后,须要先向服务器发送GetWebConn事件,不然收不到事件
  • 上面代码会打印输出收到的全部群消息、好友消息和事件,对于好友消息,会自动回复
  • IOTQQ 2.0.1版已经简化了ws部分,如今很清晰,只有上面代码里的OnGroupMsgs, OnFriendMsgs, OnEvents三种事件,其它功能都需经过调用web api实现

服务安全性考虑

  • 你们应该注意到了,IOTQQ的Web API是赤裸裸的暴露在公网上的,这意味着,若是有人知道了你的API地址和当前登陆的QQ号,他就能够用你的QQ来群发消息了,所以若是不仅是玩玩的话,咱们须要慎重考虑安全性问题
  • 能够修改IOTQQ/CoreConf.conf里的Port配置项为127.0.0.1:xxx来仅容许本地访问,而后用nginx反向代理来控制外网访问权限
  • IOTQQ要接受来自Github的WebHook推送,所以要把/Github/WebHook经过nginx代理直接放出去
  • websocket接口能够一样经过nginx代理直接放到公网,ws是安全的的,由于恶意者即便连上了你的ws也作不了什么坏事
  • 全部的Web api,加上Basic Auth验证,即须要客户端请求中包括Authorization请求头,能够自行设定用户名密码
  • 综上,在nginx.conf中加上下面配置便可:算法

    location /v1/Github/WebHook {
      proxy_pass http://localhost:8888;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    location /v1/ {
      proxy_http_version 1.1;
      if ($http_authorization != "Basic aW90cXE6MTIzNDU2Nzg=") {
        return 401;
      }
      proxy_pass http://localhost:8888;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    location / {
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_http_version 1.1;
      proxy_pass http://localhost:8888;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    说明: if ($http_authorization != "Basic aW90cXE6MTIzNDU2Nzg=") 这一段进行用户名密码的比对,其中Basic后面的字符串的算法为BASE64(<用户名> + ':' + <密码>)shell

  • 通过以上配置后,对于node.js端的Web API请求,只要给request的options参数中添加以下字段便可正常交互:auth: { user: <用户名>, pass: <密码> }
相关文章
相关标签/搜索