實現一個「人工智能」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: <密碼> }
相關文章
相關標籤/搜索