Proyek ini bermaksud untuk memberikan deskripsi lengkap dan penerapan kembali dari WhatsApp Web API, yang pada akhirnya akan mengarah ke klien khusus. WhatsApp Web secara internal berfungsi menggunakan WebSockets; Proyek ini juga melakukannya.
Tidak perlu menginstal atau mengelola versi Python dan Node, file shell.nix mendefinisikan lingkungan dengan semua dependensi yang disertakan untuk menjalankan proyek ini.
Ada file .envrc di folder root yang dipanggil secara otomatis ketika cd ing (mengubah direktori) untuk diproyeksikan, jika program direnv diinstal bersama dengan nix Anda harus mendapatkan output seperti ini:
> 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]$ Jika Anda tidak menggunakan direnv atau hanya ingin secara manual masuk ke lingkungan build do:
nix-shelldi root proyek
Sebelum Anda dapat menjalankan aplikasi, pastikan bahwa Anda memiliki perangkat lunak berikut yang diinstal:
async await digunakan)pip berikut diinstal:websocket-client dan git+https://github.com/dpallot/simple-websocket-server.git untuk bertindak sebagai server web dan klien.curve25519-donna dan pycrypto untuk hal-hal enkripsi.pyqrcode untuk pembuatan kode QR.protobuf untuk membaca dan menulis format percakapan biner.curve25519-donna memerlukan Microsoft Visual C ++ 9.0 dan Anda perlu menyalin stdint.h ke C:UsersYOUR USERNAMEAppDataLocalProgramsCommonMicrosoftVisual C++ for Python9.0VCinclude . Sebelum memulai aplikasi untuk pertama kalinya, jalankan npm install -f untuk menginstal semua simpul dan pip install -r requirements.txt untuk semua dependensi Python.
Terakhir, untuk akhirnya meluncurkannya, cukup jalankan npm start pada OS dan npm run win berbasis Linux di Windows. Menggunakan Fancy concurrently dan nodemon Magic, ketiga komponen lokal akan dimulai setelah satu sama lain dan ketika Anda mengedit file, modul yang diubah akan secara otomatis restart untuk menerapkan perubahan.
Tambahan baru-baru ini adalah versi rutin dekripsi yang diterjemahkan ke javascript in-browser. Jalankan node index_jsdemo.js (hanya diperlukan karena browser tidak mengizinkan mengubah header http untuk websockets), kemudian buka client/login-via-js-demo.html sebagai file normal di browser apa pun. Output konsol harus menampilkan pesan biner yang didekripsi setelah memindai kode QR.
Adiwajshing membuat baileys, perpustakaan simpul yang mengimplementasikan WhatsApp Web API.
Ndunks membuat penerimaan ulang naskah di Wajs.
P4KL0NC4T membuat Kyros, paket Python yang mengimplementasikan WhatsApp Web API.
Dengan whatsappweb-rs, Wiomoc membuat klien web whatsapp di karat.
Rhymen membuat go-whatsapp, paket go yang mengimplementasikan WhatsApp Web API.
Vzaramel membuat whatsappweb-clj, perpustakaan clojure yang mengimplementasikan WhatsApp Web API.
Proyek ini diselenggarakan dengan cara berikut. Perhatikan port yang digunakan dan pastikan bahwa mereka tidak digunakan di tempat lain sebelum memulai aplikasi.
WhatsApp Web mengenkripsi data menggunakan beberapa algoritma yang berbeda. Ini termasuk AES 256 CBC, Curve25519 sebagai skema perjanjian kunci diffie-Hellman, HKDF untuk menghasilkan rahasia bersama yang diperluas dan HMAC dengan SHA256.
Memulai sesi web WhatsApp terjadi hanya dengan menghubungkan ke salah satu server Websocket di wss://w[1-8].web.whatsapp.com/ws ( wss:// berarti bahwa koneksi WebSocket aman; w[1-8] berarti berapa pun angka antara 1 dan 8 dapat mengikuti w ). Pastikan juga, ketika membangun koneksi, Origin: https://web.whatsapp.com diatur, jika tidak koneksi akan ditolak.
Saat Anda mengirim pesan ke WhatsApp Web Websocket, mereka harus berada dalam format tertentu. Cukup sederhana dan terlihat seperti messageTag,JSON , misalnya 1515590796,["data",123] . Perhatikan bahwa tampaknya tag pesan bisa apa saja. Aplikasi ini sebagian besar menggunakan cap waktu saat ini sebagai tag, hanya untuk menjadi sedikit unik. WhatsApp sendiri sering menggunakan tag pesan seperti s1 , 1234.--0 atau sesuatu seperti itu. Jelas tag pesan mungkin tidak mengandung koma. Selain itu, objek JSON dimungkinkan serta muatan.
Untuk masuk di Websocket yang terbuka, ikuti langkah -langkah ini:
clientId Anda sendiri, yang perlu 16 byte yang dikodekan base64 (yaitu 25 karakter). Aplikasi ini hanya menggunakan 16 byte acak, yaitu base64.b64encode(os.urandom(16)) dalam Python.messageTag,["admin","init",[0,3,2390],["Long browser description","ShortBrowserDesc"],"clientId",true] .messageTag dan clientId dengan nilai -nilai yang Anda pilih sebelumnya[0,3,2390] menentukan versi web WhatsApp saat ini. Nilai terakhir sering berubah. Itu harus sangat kompatibel dengan sangat ke belakang."Long browser description" adalah string sewenang -wenang yang akan ditampilkan di aplikasi WhatsApp dalam daftar klien web WhatsApp terdaftar setelah Anda memindai kode QR."ShortBrowserDesc" belum diamati di mana pun tetapi juga sewenang -wenang.status : harus 200ref : Dalam aplikasi, ini diperlakukan sebagai ID server; Penting untuk generasi QR, lihat di bawahttl : adalah tahun 20000, mungkin waktu setelah kode QR menjadi tidak validupdate : Bendera Booleancurr : Versi web WhatsApp saat ini, misalnya 0.2.7314time : Cap waktu server merespons, seperti floating-point milidetik, misalnya 1515592039037.0curve25519.Private() .privateKey.get_public() .ref dari langkah 4base64.b64encode(publicKey.serialize())pyqrcode ) dan pindai menggunakan aplikasi WhatsApp.ttl ).messageTag,["admin","Conn","reref"] .status : Harus 200 (yang lain: 304 - Gunakan kembali Ref sebelumnya, 429 - Ref baru ditolak)ref : Ref baruttl : Waktu KedaluwarsaConn : Array berisi objek JSON sebagai elemen kedua dengan informasi koneksi yang berisi atribut berikut dan banyak lagi:battery : Persentase baterai ponsel Anda saat inibrowserToken : Digunakan untuk keluar tanpa koneksi WebSocket aktif (belum diimplementasikan)clientToken : Digunakan untuk melanjutkan sesi tertutup alias "Remember Me" (belum diimplementasikan)phone : Objek dengan informasi terperinci tentang ponsel Anda, misalnya device_manufacturer , device_model , os_build_number , os_versionplatform : OS ponsel Anda, misalnya androidpushname : Nama Anda yang Anda berikan whatsappsecret (ingat ini!)serverToken : Digunakan untuk melanjutkan sesi tertutup alias "ingat saya" (belum diimplementasikan)wid : Nomor telepon Anda dalam format identifikasi obrolan (lihat di bawah)Stream : Array memiliki empat elemen secara total, sehingga seluruh muatan seperti ["Stream","update",false,"0.2.7314"]Props : Array berisi objek JSON sebagai elemen kedua dengan beberapa properti seperti imageMaxKBytes (1024), maxParticipants (257), videoMaxEdge (960) dan lainnyasecret dari Conn sebagai base64 dan menyimpannya sebagai secret . Rahasia decoded ini akan panjang 144 byte.sharedSecret . Aplikasi melakukannya menggunakan privateKey.get_shared_key(curve25519.Public(secret[:32]), lambda a:a) .sharedSecret ke 80 byte menggunakan HKDF. Panggil nilai ini sharedSecretExpanded .HmacSha256(sharedSecretExpanded[32:64], secret[:32] + secret[64:]) . Bandingkan nilai ini dengan secret[32:64] . Jika mereka tidak sama, batalkan login.sharedSecretExpanded[64:] + secret[64:] sebagai keysEncrypted .sharedSecretExpanded[:32] sebagai kuncinya, yaitu toko AESDecrypt(sharedSecretExpanded[:32], keysEncrypted) sebagai keysDecrypted .keysDecrypted panjangnya 64 byte dan berisi dua tombol, masing -masing panjang 32 byte. encKey digunakan untuk mendekripsi pesan biner yang dikirimkan kepada Anda oleh server web WhatsApp atau mengenkripsi pesan biner yang Anda kirim ke server. macKey diperlukan untuk memvalidasi pesan yang dikirimkan kepada Anda:encKey : keysDecrypted[:32]macKey : keysDecrypted[32:64]init , periksa apakah Anda memiliki serverToken dan clientToken .messageTag,["admin","login","clientToken","serverToken","clientId","takeover"]{"status": 200} . Status Lainnya:tos di JSON: Jika sama atau lebih dari 2, Anda telah melanggar TOSserverToken lama atau clientToken , Anda akan ditantang untuk mengkonfirmasi bahwa Anda masih memiliki kunci enkripsi yang valid.messageTag,["Cmd",{"type":"challenge","challenge":"BASE_64_ENCODED_STRING=="}]challenge decode dari base64, tandatangani dengan mackey Anda, encode kembali dengan base64 dan kirim messageTag,["admin","challenge","BASE_64_ENCODED_STRING==","serverToken","clientId"]{"status": 200} , tetapi itu tidak ada artinya.goodbye,,["admin","Conn","disconnect"] .encKey Anda dengan macKey Anda dan encode dengan Base64. Katakanlah itu adalah logoutToken Anda.https://dyn.web.whatsapp.com/logout?t=browserToken&m=logoutTokenSekarang Anda memiliki dua kunci, memvalidasi dan mendekripsi pesan yang dikirimkan kepada server kepada Anda cukup mudah. Perhatikan bahwa ini hanya diperlukan untuk pesan biner , semua JSON yang Anda terima tetap sederhana. Pesan biner selalu memiliki 32 byte di awal yang menentukan checksum HMAC. Baik JSON dan pesan biner memiliki tag pesan pada awalnya yang dapat dibuang, yaitu hanya porsi setelah karakter koma pertama yang signifikan.
macKey (di sini messageContent adalah seluruh pesan biner): HmacSha256(macKey, messageContent[32:]) . Jika nilai ini tidak sama dengan messageContent[:32] , pesan yang dikirimkan kepada Anda oleh server tidak valid dan harus dibuang.encKey : AESDecrypt(encKey, messageContent[32:]) .Data yang Anda dapatkan dalam langkah terakhir memiliki format biner yang dijelaskan sebagai berikut. Meskipun itu biner, Anda masih dapat melihat beberapa string di dalamnya, terutama konten pesan yang Anda kirim cukup jelas di sana.
Skrip Python backend/decoder.py mengimplementasikan kelas MessageParser . Ini mampu membuat struktur JSON dari data biner di mana data masih diatur dengan cara yang agak berantakan. Bagian tentang penanganan simpul di bawah ini akan membahas bagaimana node direorganisasi setelahnya.
MessageParser awalnya hanya membutuhkan beberapa data dan kemudian memprosesnya byte byte, yaitu sebagai aliran. Ini memiliki beberapa konstanta dan banyak metode yang semuanya dibangun satu sama lain.
[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"]- untuk 10 , . untuk 11 dan