Coder Social home page Coder Social logo

wechatircd's Introduction

简体中文

wechatircd IRC Telegram Gitter

wechatircd injects JavaScript (injector.js) to wx.qq.com, which uses WebSocket to communicate with an IRC server (wechatircd.py), thus enable IRC clients connected to the server to send and receive messages from WeChat, set topics, invite/delete members, ...

           IRC               WebSocket                 HTTPS
IRC client --- wechatircd.py --------- browser         ----- wx.qq.com
                                       injector.user.js
                                       injector.js

Discuss wechatircd by joining #wechatircd on freenode, or the user group on Telegram. Video on using WeChat in WeeChat

Installation

Arch Linux

  • yaourt -S wechatircd-git. It will generate a self-signed CA key/certificate pair /etc/wechatircd/ca.{cert,key}.pem and a key/certificate pair {cert,key}.pem (see below).
  • Import the CA certificate /etc/wechatircd/ca.cert.pem to the browser (see below).
  • systemctl start wechatircd, which runs /usr/bin/wechatircd --http-cert /etc/wechatircd/cert.pem --http-key /etc/wechatircd/key.pem --http-root /usr/share/wechatircd. You may want to customize /etc/systemd/system/wechatircd.service.

wechatircd.py (the server) will listen on 127.0.0.1:6667 (IRC) and 127.0.0.1:9000 (HTTPS + WebSocket over TLS).

If you run the server on another machine, it is recommended to set up IRC over TLS and an IRC connection password with a few more options: --irc-cert /path/to/irc.key --irc-key /path/to/irc.cert --irc-password yourpassword. As an alternative to the IRC connection password, you may specify --sasl-password yourpassword and authenticate with SASL PLAIN. You can reuse the HTTPS certificate+key. If you use WeeChat and find it difficult to set up a valid certificate (gnutls checks the hostname), type the following lines in WeeChat:

/set irc.server.wechat.ssl on
/set irc.server.wechat.ssl_verify off
/set irc.server.wechat.password yourpassword

Not Arch Linux

  • python >= 3.5
  • pip install -r requirements.txt
  • openssl req -x509 -newkey rsa:2048 -sha256 -nodes -keyout ca.key.pem -out ca.cert.pem -days 9999 -subj '/CN=127.0.0.1'
    openssl req -new -newkey rsa:2048 -sha256 -nodes -keyout key.pem -subj '/CN=127.0.0.1' |
      openssl x509 -req -out cert.pem -CAkey ca.key.pem -CA ca.cert.pem -set_serial 2 -days 9999 -extfile <(
        printf "subjectAltName = IP:127.0.0.1, DNS:localhost")
  • Import the CA certificate ca.cert.pem to the browser.
  • ./wechatircd.py --http-cert cert.pem --http-key key.pem

The IP address or the domain name used to serve injector.js and injector.user.js should match the subjectAlternativeName fields. Chrome has removed support for commonName matching in certificates since version 58. See https://developers.google.com/web/updates/2017/03/chrome-58-deprecations#remove_support_for_commonname_matching_in_certificates for detail.

Userscript and self-signed CA certificate

Chrome/Chromium

Firefox

  • Install extension Greasemonkey,install the userscript.
  • Visit https://127.0.0.1:9000/injector.js, Firefox will show "Your connection is not secure", Advanced->Add Exception->Confirm Security Exception

The server serves injector.js and WebSocket connections on 127.0.0.1:9000 by default, which can be overriden with --http-listen 0.0.0.0 --http-port 9000.

You can enable HTTPS in two ways:

  • --http-cert cert.pem --http-key key.pem to make wechatircd serve HTTPS
  • Omit --http-cert --http-key to make wechatircd serve HTTP, and use Nginx (with HTTPS enabled) as a reverse proxy. In this case, you need to pass Host: to wechatircd (proxy_set_header Host $http_host;) as it changes the WebSocket URL defined in injector.js according to Host: specified by the browser.

Usage

  • Run wechatircd.py
  • Visit https://wx.qq.com, the injected JavaScript will create a WebSocket connection to the server
  • Open devtools, and run injector.run()
  • Connect to 127.0.0.1:6667 in your IRC client

You will join +wechat channel automatically and find your contact list there. Some commands are available:

  • help
  • eval, eval a Python expression, such as: eval server.nick2special_user eval server.name2special_room
  • status, show contacts/channels
  • reload_contact __all__, reload all contact info in case of no such nick/channel in privmsg

The server can only be bound to one wx.qq.com account, however, you may have more than one IRC clients connected to the server.

IRC features

  • Standard IRC channels have names beginning with #.
  • WeChat groups have names beginning with &. The channel name is generated from the group title. SpecialChannel#update
  • Contacts have modes +v (voice, usually displayed with a prefix +). SpecialChannel#update_detail
  • Multi-line messages: !m line0\nline1
  • Multi-line messages: !html line0<br>line1
  • nick0: nick1: test will be converted to @GroupAlias0 @GroupAlias1 test, where GroupAlias0 is My Alias in Group/Name in profile/WeChat ID set by that user. It corresponds to On-screen names in the mobile application.
  • Reply to the message at 12:34:SS: @1234 !m multi\nline\nreply, which will be sent as 「Re GroupAlias: text」text
  • Reply to the message at 12:34:56: !m @123456 multi\nline\nreply
  • Reply to the penultimate message (your own messages are not counted) in this channel/chat: @2 reply
  • Paste detection. Lines will be hold for up to 0.1 seconds before sending, lines in this interval will be packed to a multiline message
  • --http-url https://127.0.0.1:9000 if you want to shorten media URLs to something like https://127.0.0.1:9000/media/0

!m , @3 , nick: can be arranged in any order.

For WeeChat, its anti-flood mechanism will prevent two user messages sent to IRC server in the same time. Disable anti-flood to enable paste detection.

/set irc.server.wechat.anti_flood_prio_high 0

server-time extension from IRC version 3.1, 3.2. wechatircd.py includes the timestamp (obtained from JavaScript) in messages to tell IRC clients that the message happened at the given time. See http://ircv3.net/irc/. Seehttp://ircv3.net/software/clients.html for Client support of IRCv3.

Configuration for WeeChat:

/set irc.server_default.capabilities "account-notify,away-notify,cap-notify,multi-prefix,server-time,znc.in/server-time-iso,znc.in/self-message"

Supported IRC commands:

  • /cap, supported capabilities.
  • /dcc send $nick/$channel $filename, send image or file。This feature borrows the command /dcc send which is well supported in IRC clients. See https://en.wikipedia.org/wiki/Direct_Client-to-Client#DCC_SEND.
  • /invite $nick [$channel], invite a contact to the group.
  • /kick $nick, delete a group member. You must be the group leader to do this. Due to the defect of the Web client, you may not receive notifcations about the change of members.
  • /kill $nick [$reason], cause the connection of that client to be closed
  • /list, list groups.
  • /mode +m, no rejoin in --join new mode. /mode -m to revert.
  • /motd, view latest 5 commits of this repo
  • /names, update nicks in the channel.
  • /part [$channel], no longer receive messages from the channel. It just borrows the command /part and it will not leave the group.
  • /query $nick, open a chat window with $nick.
  • /squit $any, log out
  • /summon $nick $message,add a contact.
  • /topic topic, change the topic of a group. Because IRC does not support renaming of a channel, you will leave the channel with the old name and join a channel with the new name.
  • /who $channel, see the member list.

Display

  • MSGTYPE_TEXT,text, or invitation of voice/video call
  • MSGTYPE_IMG,image, displayed as [Image] $url
  • MSGTYPE_VOICE,audio, displayed as [Voice] $url
  • MSGTYPE_VIDEO,video, displayed as [Video] $url
  • MSGTYPE_MICROVIDEO,micro video?,displayed as [MicroVideo] $url
  • MSGTYPE_APP,articles from Subscription Accounts, Red Packet, URL, ..., displayed as [App] $title $url

QQ emojis are displayed as <img class="qqemoji qqemoji0" text="[Smile]_web" src="/zh_CN/htmledition/v2/images/spacer.gif">, [Smile] in sent messages will be replaced to emoticon.

Emojis are rendered as <img class="emoji emoji1f604" text="_web" src="/zh_CN/htmledition/v2/images/spacer.gif">. Each emoji will be converted to a single character before delivered to the IRC client. Emojis may overlap as terminal emulators may not know emojis are of width 2,see 终端模拟器下使用双倍宽度多色Emoji字体.

Server options

  • --config, short option -c, config file path, see config
  • HTTP/WebSocket related options
    • --http-cert cert.pem, TLS certificate for HTTPS/WebSocket. You may concatenate certificate+key, specify a single PEM file and omit --http-key. Use HTTP if neither --http-cert nor --http-key is specified.
    • --http-key key.pem, TLS key for HTTPS/WebSocket
    • --http-listen 127.1 ::1, change HTTPS/WebSocket listen address to 127.1 and ::1, overriding --listen
    • --http-port 9000, change HTTPS/WebSocket listen port to 9000
    • --http-root ., the root directory to serve injector.js
    • --http-url https://127.0.0.1:9000, if specified, display media links as https://127.0.0.1:9000/document/$id ; if not, https://wx.qq.com/cgi-bin/...
  • Groups that should not join automatically. This feature supplements join mode.
    • --ignore '&fo[o]' '&bar', do not auto join channels whose names(generated from Group Name) partially match regex &fo[o] or &bar
    • --ignore-display-name 'fo[o]' bar, short option -I, do not auto join channels whose Group Name partially match regex fo[o] or bar
  • --ignore-brand, ignore messages from subscription accounts (MM_USERATTRVERIFYFALG_BIZ_BRAND)
  • IRC related options
    • --irc-cert cert.pem, TLS certificate for IRC over TLS. You may concatenate certificate+key, specify a single PEM file and omit --irc-key. Use plain IRC if neither --irc-cert nor --irc-key is specified.
    • --irc-key key.pem, TLS key for IRC over TLS.
    • --irc-listen 127.1 ::1, change IRC listen address to 127.1 and ::1, overriding --listen.
    • --irc-nicks ray ray1, reverved nicks for clients. SpecialUser will not have these nicks.
    • --irc-password pass, set the connection password to pass.
    • --irc-port 6667, IRC server listen port.
  • Join mode, short option -j
    • --join auto, default: join the channel upon receiving the first message, no rejoin after issuing /part and receiving messages later
    • --join all: join all the channels
    • --join manual: no automatic join
    • --join new: like auto, but rejoin when new messages arrive even if after /part
  • --listen 127.0.0.1, short option -l, change IRC/HTTP/WebSocket listen address to 127.0.0.1.
  • Server side log
    • --logger-ignore '&test0' '&test1', list of ignored regex, do not log contacts/groups whose names partially match
    • --logger-mask '/tmp/wechat/$channel/%Y-%m-%d.log', format of log filenames
    • --logger-time-format %H:%M, time format of entries of server side log
  • --paste-wait 0.1, lines will be hold for up to 0.1 seconds before sending, lines in this interval will be packed to a multiline message
  • --sasl-password pass, set the SASL password to pass.
  • --special-channel-prefix, choices: &, !, #, ##, prefix for SpecialChannel. Quassel does not seem to support channels with prefixes &, --special-channel-prefix '##' to make Quassel happy

See wechatircd.service for a template of /etc/systemd/system/wechatircd.service.

Changes in injector.js

  • Create a WebSocket connection to the server and retry on failures.
  • Hook contactFactory#{addContact,deleteContact} to watch changes to the contacts.
  • CtrlServer#onmessage, handle commands (text/file messages, invite someone to the group, ...) from the server.
  • CtrlServer#seenLocalID, prevent the client from receiving messages sent by itself.

wechatircd.py

.
├── Web                      HTTP(s)/WebSocket server
├── Server                   IRC server
├── Channel
│   ├── StandardChannel      IRC channels
│   ├── StatusChannel        `+wechat`
│   └── SpecialChannel       WeChat groups
├── (User)
│   ├── Client               IRC clients
│   ├── SpecialUser          WeChat users
├── (IRCCommands)
│   ├── UnregisteredCommands available commands: CAP NICK PASS USER QUIT
│   ├── RegisteredCommands

FAQ

Motivation

If you cannot tolerant scanning QR codes with your phone everyday, see 无需每日扫码的IRC版微信和QQ:wechatircd、webqqircd.

Fetch data & control wx.qq.com

Some special accounts' UserName do not have the @ prefix: newsapp,fmessage,filehelper,weibo,qqmail,fmessage。Standard accounts' UserName start with @; Groups' UserName start with @@UserName are different among sessions. Uin looks like an unique identifier, but most of the time its value is 0. A group's OwnerUin is the owners's Uin,but most of the time Uin is 0.

My account

angular.element(document.body).scope().account

List of all contacts

angular.element($('#navContact')[0]).scope().allContacts

Delete a member from a group

var injector = angular.element(document).injector()
# 这里获取了chatroomFactory,还可用于获取其他factory、service、controller等
var chatroomFactory = injector.get('chatroomFactory')
# 设置其中的`room``userToRemove`
chatroomFactory.delMember(room.UserName, userToRemove.UserName)`

Send a message to the current chat

angular.element('pre:last').scope().editAreaCtn = "Hello,微信";
angular.element('pre:last').scope().sendTextMessage();

Headless browser on Linux

If you cannot tolerant scanning QR codes with your phone everyday, you can run the browser and wechatircd on a server.

  • Create a new browser user profile with chromium --user-data-dir=$HOME/.config/chromium-wechatircd, and do the aforementioned configuration (certificate for injector.js, Tampermonkey, injector.user.js), then close the browser.
  • Install xvfb (xorg-server-xvfb on Arch Linux)
  • xvfb-run -n 99 chromium --user-data-dir=$HOME/.config/chromium-wechatircd https://wx.qq.com
  • Wait a few seconds for the QR code. DISPLAY=:99 import -window root /tmp/a.jpg && $your_image_viewer /tmp/a.jpg, take a screenshot and scan the QR code with your mobile application.

You can interact with the browser using VNC:

  • x11vnc -localhost -display :99
  • In another terminal, vncviewer localhost

An alternative is x2go, see 无需每日扫码的IRC版微信和QQ:wechatircd、webqqircd.

How are nicks generated?

On the mobile application, users' On-screen Names are resolved in this order:

  • Set Remark and Tag if set
  • My Alias in Group(Group Alias) if set
  • Name in his/her profile
  • WeChat ID

Contact information is given in APIs batchgetcontact and webwxsync. The JSON serialization uses misleading field names.

WeChat friend in contactFactory#addContact:

  • .Alias: Name in his/her profile
  • .NickName: WeChat ID
  • .RemarkName: Set Remark and Tag

WeChat friend/non-contact in .MemberList:

  • .DisplayName: My Alias in Group
  • .NickName: Name in his/her profile or WeChat ID

JSON for one user may be returned repeatedly and all these fields may be empty. Users' nicks are generated by looking for the first non-empty value from these fields: .RemarkName, .NickName, .DisplayName. You may see xx now known as yy in your IRC client if a room contact shares multple rooms with you.

Known issues

Uncaught TypeError: angular.extend is not a function

You may see these messages in the DevTools console:

Uncaught TypeError: angular.extend is not a function
    at Object.setUserInfo (index_0c7087d.js:4)
    at index_0c7087d.js:2
    at c (vendor_2de5d3a.js:11)
    at vendor_2de5d3a.js:11
    at c.$eval (vendor_2de5d3a.js:11)
    at c.$digest (vendor_2de5d3a.js:11)
    at c.$apply (vendor_2de5d3a.js:11)
    at l (vendor_2de5d3a.js:11)
    at m (vendor_2de5d3a.js:11)
    at XMLHttpRequest.C.onreadystatechange (vendor_2de5d3a.js:11)
Uncaught TypeError: angular.forEach is not a function

injector.js should be executed after vendor_*.js and before index_*.js. However, TamperMonkey cannot finely control the execution time due to the limitation of Chrome.

Cannot send/receive new messages when the webpage disconnects from wx.qq.com

The WebSocket connection to wechatircd.py should be closed in this case, let users know they should reload the webpage.

Others

  • Log filenames may contain invalid filenames (:) on Windows
  • Stable channel names. This makes server-side log coherent and users will not be distracted by PART (Change name) JOIN messages. Channel names are generated from .NickName (Group Name) and Group Name may change. I do not know any persistent ID of an account/group because UserName changes in each new session.

References

wechatircd's People

Contributors

bigeagle avatar maskray avatar myf avatar ppwwyyxx avatar try-ice avatar x1a0 avatar ztrix avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wechatircd's Issues

Uncaught error in room name handling

Error handling request
Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/aiohttp/server.py", line 285, in start
    yield from self.handle_request(message, payload)
  File "/usr/lib/python3.5/site-packages/aiohttp/web.py", line 90, in handle_request
    resp = yield from handler(request)
  File "/usr/bin/wechatircd", line 65, in handle_web_socket
    Server.instance.on_websocket(data)
  File "/usr/bin/wechatircd", line 1464, in on_websocket
    client.on_websocket(data)
  File "/usr/bin/wechatircd", line 1266, in on_websocket
    getattr(WeChatCommands, command)(self, data)
  File "/usr/bin/wechatircd", line 472, in room
    room = client.ensure_wechat_room(record)
  File "/usr/bin/wechatircd", line 1032, in ensure_wechat_room
    del self.name2wechat_room[irc_lower(room.name)]
KeyError: '&'

I have a chatroom whose name is consisting of emojis only. Maybe that's the cause.

Parse XML for emojis

<img class="qqemoji qqemoji5" text="[流泪]_web" src="/zh_CN/htmledition/v2/images/spacer.gif" />

should be replaced by, for example, [流泪]

解决脚本执行顺序的一种思路

我看文档中有如下的声明:

injector.js得在vendor_.js后index_.js前执行。但TamperMonkey无法精细控制script的运行时机。

我在做 tiny-wechat-robot时使用了一种方式,劫持 index js 的资源请求,把它转发为本机脚本,然后在其中再加载原始的 index js 资源。在phantomjs中工作得很好(目前只需要特殊处理一个 ECMA6 的语法问题)。具体参见:https://github.com/dongyuwei/tiny-wechat-robot/blob/master/src/wechat_injection.js#L92

no friends after following README

I am using Arch Linux, followed the instruction (the one installs wechatircd using yaourt), used greasemonkey to inject using firefox, used weechat as irc server connected to 127.1/6667.

The problem is that I can only see myself on the raster without any friends. The weechat message i got was the following

         │19:08:45  wechat   -- | Hi, welcome to IRC
         │19:08:45  wechat   -- | Your host is wechatircd.maskray.me
         │19:08:45  wechat   -- | There are 1 users and 0 WeChat users (local to you) on 1 server

how should I debug from here? am I missing something crucial?

真的可以做到永远保持登录不再扫码?

看到文档里有这么一句:

If you cannot tolerant scanning QR codes with your phone everyday, see 无需每日扫码的IRC版微信和QQ:wechatircd、webqqircd.

真的可以做到永远保持登录不再扫码?

osx, No module called aiohttp 以及 module 'ssl' has no attribute 'PROTOCOL_TLSv1_2'

试了几次都不行,我试过pip uninstall aiohttp 然后pip install --user aiohtto, 这个模组可以被载入了。然后别的模组又认不出来。我试了把所有模组用--user安装了一边,./wechatircd.py --tle-cert a.crt --tls-key a.key总算能运行了,但是出现错误:module 'ssl' has no attribute 'PROTOCOL_TLSv1_2'。找不到解决这个问题的办法

aiohttp: No module named 'async_timeout'

using python-aiohttp from aur version 1.2.0-2, wechatircd fails to start at

Traceback (most recent call last):
  File "/usr/bin/wechatircd", line 3, in <module>
    from aiohttp import web
  File "/usr/lib/python3.6/site-packages/aiohttp/__init__.py", line 11, in <module>
    from .connector import *  # noqa
  File "/usr/lib/python3.6/site-packages/aiohttp/connector.py", line 18, in <module>
    from . import hdrs, helpers
  File "/usr/lib/python3.6/site-packages/aiohttp/helpers.py", line 19, in <module>
    from async_timeout import timeout
ModuleNotFoundError: No module named 'async_timeout'

cannot send message

it seems that I cannot successfully send messages through wechatircd anymore although I can receive, and whatever I send on wechat app do appear on wechatircd. this starts yesterday and I wonder if anyone else has the same issue.

微信上的中文昵称怎么在irc上显示

想起来个问题,现在流行的irc服务器都不支持中文昵称,不知道这个项目里的的irc是否支持中文昵称
如果不支持,微信上的群名称、好友名称等是怎么在irc上对应的

Got error in google chrome

Got following error message in google chrome. it works before. But not recently

I am using the latest code + google chrome 55 + archlinux

webwxApp31e225.js:3 Uncaught TypeError: angular.extend is not a function
    at Object.setUserInfo (webwxApp31e225.js:3)
    at webwxApp31e225.js:1
    at c (libs31e225.js:5)
    at libs31e225.js:5
    at c.$eval (libs31e225.js:5)
    at c.$digest (libs31e225.js:5)
    at c.$apply (libs31e225.js:5)
    at u (libs31e225.js:5)
    at m (libs31e225.js:5)
    at XMLHttpRequest.w.onreadystatechange (libs31e225.js:5)

请问应当如何使用文档中那个.service文件?

要连微信的话我现在是先运行wechatircd.py然后从新开窗口运行irc。请问是否有办法在irc中自动运行这个监听程序?我看到文档最后有一个.service文件的介绍,可惜我用的是osx,没有systemd。请问你知道怎么写launchd的脚本吗?不然的话我就自己去看看怎么写吧。谢谢!

Unable to login WeChat Web anymore.

I suddenly lost my wechatircd channels today. It resulted in being unabe to login my account even directly through WeChat Web: "Your login may be compromised. For account security, you cannot log in to Web WeChat. You can try mobile WeChat or Windows WeChat".

Any way to resolve this? I guess some behavior of wechatircd caused the WeChat to suspect and revoke my web access permission.

似乎需要浏览器一直运行?

如果没理解错的话这个方案需要一个浏览器一直运行着?
(最近也在研究打造类似的通道,还没什么好想法)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.