6

webqqircd——用IRC客户端控制WebQQ

 3 years ago
source link: http://maskray.me/blog/2016-04-11-webqqircd
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

webqqircd——用IRC客户端控制WebQQ

代码:https://github.com/MaskRay/webqqircd

webqqircd

webqqircd类似于bitlbee,在WebQQ(SmartQQ)和IRC间建起桥梁,可以使用IRC客户端收发消息。大部分代码来自wechatircd,为适配QQ做了一些修改,去除了wechatircd中的token,因此只支持单客户端。

修改WebQQ(http://w.qq.com用的JS,通过WebSocket把信息发送到服务端,服务端兼做IRC服务端,把IRC客户端的命令通过WebSocket传送到网页版JS执行。未实现IRC客户端,因此无法把QQ群的消息转发到另一个IRC服务器(打通两个群的bot)。

WebQQ局限

  • WebQQ不支持发送图片,也无法获悉别人发送了图片
  • 消息发送后不知道成功与否,mq.model.chatsendMsg(h)onSuccess为空函数
  • 无法获知群信息变化(如成员变化等)mq.model.chataddGroup(x)只判断群存在与否,不判断信息变化

需要Python 3.5或以上,支持async/await语法
pip install -r requirements.txt安装依赖

Arch Linux可以安装https://aur.archlinux.org/packages/webqqircd-git,会自动在/etc/webqqircd/下生成自签名证书(见下文),导入浏览器即可。

HTTPS、WebSocket over TLS

推荐使用TLS。

  • openssl req -newkey rsa:2048 -nodes -keyout a.key -x509 -out a.crt -subj '/CN=127.0.0.1' -dates 9999创建密钥与证书。
  • Chrome访问chrome://settings/certificates,导入a.crt,在Authorities标签页选择该证书,Edit->Trust this certificate for identifying websites.
  • Chrome安装Switcheroo Redirector扩展,把http://pub.idqqimg.com/smartqq/js/mq.js重定向至https://127.0.0.1:9002/mq.js。若js更新,该路径会变化。
  • ./webqqircd.py --tls-cert a.crt --tls-key a.key,会监听127.1:6668的IRC和127.1:9002的HTTPS与WebSocket over TLS
demo.jpg

HTTP、WebSocket

如果嫌X.509太麻烦的话可以不用TLS,但Chrome会在console里给出警告。

  • 执行./webqqircd.py,会监听127.1:6668的IRC和127.1:9002的HTTP与WebSocket,HTTP用于伺服项目根目录下的mq.js
  • http://pub.idqqimg.com/smartqq/js/mq.js重定向至http://127.0.0.1:9002/mq.js。若js更新,该路径会变化。
  • mq.js var ws = new MyWebSocket('wss://127.0.0.1:9002')行单引号里面的部分修改成ws://127.0.0.1:9002

IRC客户端

  • IRC客户端连接127.1:6668(weechat的话使用/server add qq 127.1/6668),会自动加入+qq channel
  • 登录http://w.qq.com
  • 回到IRC客户端,可以看到QQ朋友加入了+qq channel,在这个channel发信并不会群发,只是为了方便查看有哪些朋友。
  • QQ朋友的nick优先选取备注名(RemarkName),其次为DisplayName(原始JS根据暱称等自动填写的一个名字)

+qq channel可以执行一些命令:

  • help,帮助
  • status,已获取的QQ朋友、群列表
  • eval $password $expr: 如果运行时带上了--password $password选项,这里可以eval,方便调试,比如eval $password client.uin2qq_user

若服务端或客户端重启,刷新WebQQ。

IRC命令

webqqircd是个简单的IRC服务器,可以执行通常的IRC命令,可以对其他客户端私聊。

以下命令会有特殊作用:

  • 程序默认选项为--join auto,收到某个QQ群的第一条消息后会自动加入对应的channel,即开始接收该QQ群的消息。
  • /join [channel]表示开始接收该QQ群的消息
  • /list,列出所有QQ群
  • /names,更新当前群成员列表
  • /part [channel]的IRC原义为离开channel,转换为QQ代表在当前IRC会话中不再接收该QQ群的消息。不用担心,webqqircd并没有主动退出群的功能
  • /query nick打开与$nick的私聊窗口,与之私聊即为在QQ上和他/她/它对话
  • /who channel,查看群成员列表

原始文件mq.js在Chrome DevTools里格式化后得到orig/mq.pretty.js,可以用diff -u orig/mq.pretty.js mq.js查看改动。

修改的地方都有//@标注,结合diff,方便WebQQ更新后重新应用这些修改。增加的代码中大多数地方都用try catch保护,出错则consoleerr(ex.stack)

目前的改动如下:

mq.js开头

创建到服务端的WebSocket连接,若onerror则自动重连。监听onmessage,收到的消息为服务端发来的控制命令:send_text_message等。

定期把通讯录发送到服务端

获取所有联系人(朋友、订阅号、群),deliveredContact记录投递到服务端的联系人,deliveredContact记录同处一群的非直接联系人。

每隔一段时间把未投递过的联系人发送到服务端。

收到QQ服务器消息messageProcess

原有代码会更新未读标记数及声音提醒,现在改为若成功发送到服务端则不再提醒,以免浏览器的这个标签页造成干扰。

Python服务端代码

当前只有一个文件webqqircd.py,从miniircd抄了很多代码,后来自己又搬了好多RFC上的用不到的东西……

├── Web HTTP(s)/WebSocket server
├── Server IRC server
├── Channel
│   ├── StandardChannel `#`开头的IRC channel
│   ├── StatusChannel `+qq`,查看控制当前QQ会话
│   └── QQRoom QQ群对应的channel,仅该客户端可见
├── (User)
│   ├── Client IRC客户端连接
│   ├── QQUser QQ用户对应的user,仅该客户端可见
├── (IRCCommands)
│   ├── UnregisteredCommands 注册前可用命令:NICK USER QUIT
│   ├── RegisteredCommands 注册后可用命令

https://wiki.archlinux.org/index.php/Systemd/User

~/.config/systemd/user/webqqircd.service:

[Unit]
Description=webqqircd
Documentation=https://github.com/MaskRay/webqqircd
After=network.target
[Service]
WorkingDirectory=%h/projects/webqqircd
ExecStart=/home/ray/projects/webqqircd/webqqircd.py --tls-key a.key --tls-cert a.crt --password a --ignore 不想自动加入的群名0 不想自动加入的群名1
[Install]
WantedBy=multi-user.target

WeeChat:

/server add qq 127.1/6668 -autoconnect

Share Comments


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK