Этот проект намеревается предоставить полное описание и повторное внедрение веб-API WhatsApp, что в конечном итоге приведет к пользовательскому клиенту. WhatsApp Web внутренне работает с использованием веб -питания; Этот проект делает также.
Нет необходимости устанавливать или управлять версиями Python и Node, File shell.nix определяет среду со всеми зависимостями, включенными для запуска этого проекта.
В папке nix корневой cd direnv файл .envrc
> cd ~ /dev/whatsapp
Installing node modules
npm WARN prepare removing existing node_modules/ before installation
> [email protected] install /home/rainy/dev/whatsapp/node_modules/fsevents
> node-gyp rebuild
make: Entering directory ' /home/rainy/dev/whatsapp/node_modules/fsevents/build '
SOLINK_MODULE(target) Release/obj.target/.node
COPY Release/.node
make: Leaving directory ' /home/rainy/dev/whatsapp/node_modules/fsevents/build '
> [email protected] postinstall /home/rainy/dev/whatsapp/node_modules/nodemon
> node bin/postinstall || exit 0
added 310 packages in 3.763s
Done.
$$ $$ $$ $$
$$ | $ $$ | $$ | $$ |
$$ | $$ $ $$ | $$$$$$ $ $$$$$$ $$$$$$ $$$$$$ $ $$$$$$ $$$$$$ $$$$$$
$$ $$ $$ $ $ | $$ __ $$ _ ___ $$ \ _ $$ _ | $$ _____ | _ ___ $$ $$ __ $$ $$ __ $$
$$$$ _ $$$$ | $$ | $$ | $$$$$$ $ | $$ | $ $$$$ $ $$$$$$ $ | $$ / $$ | $$ / $$ |
$$ $ / $ $$ | $$ | $$ | $$ __ $$ | $$ | $$ _ ___ $$ $$ __ $$ | $$ | $$ | $$ | $$ |
$$ / $ $ | $$ | $$ | $ $$$$$$ | $ $$ $ | $$$$$$ $ | $ $$$$$$ | $$$$$$ $ | $$$$$$ $ |
_ _/ _ _ | _ _ | _ _ | _ ______ | _ ___/ _ ______/ _ ______ | $$ ____/ $$ ____/
$$ | $$ |
$$ | $$ |
_ _ | _ _ |
Node v13.13.0
Python 2.7.17
Try running server with: npm start
[nix-shell: ~ /dev/whatsapp]$ Если вы не используете direnv или просто хотите вручную попасть в среду сборки:
nix-shellв корне проекта
Прежде чем вы сможете запустить приложение, убедитесь, что у вас установлено следующее программное обеспечение:
async await )pip -пакетами:websocket-client и git+https://github.com/dpallot/simple-websocket-server.git для выступления в качестве сервера и клиента WebSocket.curve25519-donna и pycrypto для шифрования.pyqrcode для QR -кода.protobuf для чтения и написания формата бинарного разговора.curve25519-donna требуется Microsoft Visual C ++ 9.0, и вам необходимо скопировать stdint.h в C:UsersYOUR USERNAMEAppDataLocalProgramsCommonMicrosoftVisual C++ for Python9.0VCinclude . Перед началом приложения в первый раз запустите npm install -f , чтобы установить все узлы и pip install -r requirements.txt для всех зависимостей Python.
Наконец, чтобы, наконец, запустить его, просто запустите npm start OS на базе Linux и npm run win в Windows. Используя фантазию concurrently и магию nodemon , все три локальных компонента будут запущены друг за другом, и при редактировании файла измененный модуль автоматически перезагрузится, чтобы применить изменения.
Недавнее дополнение-это версия подпрограммы дешифрования, переведенная в JavaScript в браузере. Запустите node index_jsdemo.js (просто необходимо, потому что браузеры не позволяют изменять заголовки HTTP для веб-питания), а затем откройте client/login-via-js-demo.html в качестве обычного файла в любом браузере. Вывод консоли должен показывать расшифрованные двоичные сообщения после сканирования QR -кода.
Adiwajshing создал Baileys, библиотеку узлов, которая реализует веб -API WhatsApp.
Ndunks сделали повторную массу типографии в Wajs.
P4KL0NC4T создал Kyros, пакет Python, который реализует веб -API WhatsApp.
С WhatsAppweb-RS Wiomoc создал веб-клиент WhatsApp в Rust.
Rhymen создал Go-Whatsapp, пакет GO, который реализует веб-API WhatsApp.
Vzaramel создал WhatsAppweb-Clj, библиотеку Clojure, реализует веб-API WhatsApp.
Проект организован следующим образом. Обратите внимание на использованные порты и убедитесь, что они не используются в другом месте перед началом приложения.
WhatsApp Web шифрует данные, используя несколько разных алгоритмов. К ним относятся AES 256 CBC, Curve25519 в качестве схемы ключевых соглашений Diffie-Hellman, HKDF для создания расширенного общего секрета и HMAC с SHA256.
Запуск веб-сеанса WhatsApp происходит только с подключением к одному из своих серверов WebSocket на wss://w[1-8].web.whatsapp.com/ws ( wss:// означает, что соединение WebSocket безопасно; w[1-8] означает, что любое число между 1 и 8 может следовать w ). Также убедитесь, что при установлении соединения установлено значение HTTP Header Origin: https://web.whatsapp.com , в противном случае подключение будет отклонено.
Когда вы отправляете сообщения в WhatsApp WebSocket, они должны быть в определенном формате. Это довольно просто и выглядит как messageTag,JSON , EG 1515590796,["data",123] . Обратите внимание, что, по -видимому, тег сообщения может быть чем угодно. Это приложение в основном использует текущую метку времени, чтобы быть немного уникальным. Сам WhatsApp часто использует теги сообщения, такие как s1 , 1234.--0 или что-то в этом роде. Очевидно, что тег сообщения может не содержать запятую. Кроме того, возможны объекты JSON, а также полезную нагрузку.
Чтобы войти в систему на открытом WebSocket, выполните следующие действия:
clientId , который должен составлять 16 базовых байтов Base64 (то есть 25 символов). В этом приложении используются 16 случайных байтов, т.е. base64.b64encode(os.urandom(16)) в Python.messageTag,["admin","init",[0,3,2390],["Long browser description","ShortBrowserDesc"],"clientId",true] .messageTag и clientId на выбранные вами значения[0,3,2390] указывает текущую веб -версию WhatsApp. Последнее значение часто меняется. Это должно быть довольно обратно совместимо, хотя."Long browser description" - это произвольная строка, которая будет отображаться в приложении WhatsApp в списке зарегистрированных веб -клиентов WhatsApp после сканирования QR -кода."ShortBrowserDesc" еще нигде не наблюдался, но также является произвольным.status : должен быть 200ref : В приложении это рассматривается как идентификатор сервера; важно для поколения QR, см. Нижеttl : IS 20000, может быть, время после QR -кода становится недействительнымupdate : логический флагcurr : текущая веб -версия WhatsApp, например, 0.2.7314time : The TimeStamp, на которую ответил сервер, как Milliseconds с плавающей точкой, например, 1515592039037.0curve25519.Private() .privateKey.get_public() .ref с шага 4base64.b64encode(publicKey.serialize())pyqrcode ) и сканируйте ее с помощью приложения WhatsApp.ttl ).messageTag,["admin","Conn","reref"] .status : должно быть 200 (другие: 304 - повторно используйте предыдущий реф, 429 - Новый реф отрицал)ref : новый рефttl : время истечения срока действияConn : массив содержит объект JSON как второй элемент с информацией об соединении, содержащей следующие атрибуты и многое другое:battery : текущий процент батареи вашего телефонаbrowserToken : используется для выхода без активного соединения WebSocket (еще не реализовано)clientToken : используется для возобновления закрытых сессий, известно, «Помни меня» (еще не реализовано)phone : объект с подробной информацией о вашем телефоне, например, device_manufacturer , device_model , os_build_number , os_versionplatform : ваша телефонная ОС, например, androidpushname : ваше имя, которое вы предоставили WhatsAppsecret (помните это!)serverToken : используется для возобновления закрытых сессий, также известно, «Помни меня» (еще не реализовано)wid : ваш номер телефона в формате идентификации чата (см. Ниже)Stream : массив имеет в общей сложности четыре элемента, поэтому вся полезная нагрузка похожа на ["Stream","update",false,"0.2.7314"]Props : массив содержит объект JSON в качестве второго элемента с несколькими свойствами, такими как imageMaxKBytes (1024), maxParticipants (257), videoMaxEdge (960) и другиеsecret от Conn в качестве Base64 и хранить его в secret . Этот декодированный секрет будет длиной 144 байта.sharedSecret . Приложение делает это с использованием privateKey.get_shared_key(curve25519.Public(secret[:32]), lambda a:a) .sharedSecret до 80 байтов с помощью HKDF. Назовите это значение sharedSecretExpanded .HmacSha256(sharedSecretExpanded[32:64], secret[:32] + secret[64:]) . Сравните это значение с secret[32:64] . Если они не равны, прервать вход.sharedSecretExpanded[64:] + secret[64:] как keysEncrypted .sharedSecretExpanded[:32] в качестве ключа, то есть хранить AESDecrypt(sharedSecretExpanded[:32], keysEncrypted) в качестве keysDecrypted .keysDecrypted имеет длину 64 байта и содержит два ключа, каждая 32 байта длиной. encKey используется для расшифровки двоичных сообщений, отправляемых вам веб -сервером WhatsApp или шифрования двоичных сообщений, которые вы отправляете на сервер. macKey необходим для проверки отправленных вам сообщений:encKey : keysDecrypted[:32]macKey : keysDecrypted[32:64]init , проверьте, есть ли у вас serverToken и clientToken .messageTag,["admin","login","clientToken","serverToken","clientId","takeover"]{"status": 200} . Другие статусы:tos в JSON: если он равна или больше, чем 2, вы нарушили TOSserverToken и clientToken вам будет предложено подтвердить, что у вас все еще есть достоверные ключи шифрования.messageTag,["Cmd",{"type":"challenge","challenge":"BASE_64_ENCODED_STRING=="}]challenge от BASE64, подпишите его с MacKey, кодируйте его обратно с BASE64 и отправьте messageTag,["admin","challenge","BASE_64_ENCODED_STRING==","serverToken","clientId"]{"status": 200} , но это ничего не значит.goodbye,,["admin","Conn","disconnect"] .encKey с macKey и кодируйте его с Base64. Допустим, это ваш logoutToken .https://dyn.web.whatsapp.com/logout?t=browserToken&m=logoutTokenТеперь, когда у вас есть два ключа, проверка и расшифровки сообщений, отправленных вам сервера, довольно просто. Обратите внимание, что это необходимо только для двоичных сообщений, все, что вы получаете, остается простым. Двоичные сообщения всегда имеют 32 байта в начале, которые указывают контрольную сумму HMAC. Как JSON , так и бинарные сообщения имеют тег сообщений в самом начале, который можно отбросить, то есть только часть после того, как первый персонаж запятой является значительной.
macKey (здесь messageContent - это все двоичное сообщение): HmacSha256(macKey, messageContent[32:]) . Если это значение не равное messageContent[:32] , сообщение, отправленное вам сервером, является недействительным и должно быть отброшено.encKey : AESDecrypt(encKey, messageContent[32:]) .Данные, которые вы получаете на последнем этапе, имеют двоичный формат, который описан в следующем. Несмотря на то, что это двоичный, вы все равно можете увидеть в нем несколько строк, особенно содержание отправленных сообщений, которые вы там очевидно.
backend/decoder.py реализует класс MessageParser . Он может создать структуру JSON из двоичных данных, в которых данные все еще организованы довольно грязным способом. В разделе о обработке узлов ниже рассказывается о том, как узлы реорганизованы впоследствии.
Первоначально MessageParser просто нуждаются в некоторых данных, а затем обрабатывает их по байту, т.е. как поток. У него есть пара констант и множество методов, которые все нарастают друг на друга.
[None,None,None,"200","400","404","500","501","502","action","add", "after","archive","author","available","battery","before","body", "broadcast","chat","clear","code","composing","contacts","count", "create","debug","delete","demote","duplicate","encoding","error", "false","filehash","from","g.us","group","groups_v2","height","id", "image","in","index","invis","item","jid","kind","last","leave", "live","log","media","message","mimetype","missing","modify","name", "notification","notify","out","owner","participant","paused", "picture","played","presence","preview","promote","query","raw", "read","receipt","received","recipient","recording","relay", "remove","response","resume","retry","s.whatsapp.net","seconds", "set","size","status","subject","subscribe","t","text","to","true", "type","unarchive","unavailable","url","user","value","web","width", "mute","read_only","admin","creator","short","update","powersave", "checksum","epoch","block","previous","409","replaced","reason", "spam","modify_tag","message_info","delivery","emoji","title", "description","canonical-url","matched-text","star","unstar", "media_key","filename","identity","unread","page","page_count", "search","media_message","security","call_log","profile","ciphertext", "invite","gif","vcard","frequent","privacy","blacklist","whitelist", "verify","location","document","elapsed","revoke_invite","expiration", "unsubscribe","disable"]- для 10 , . за 11 и