diff options
Diffstat (limited to 'protocols/WhatsAppWeb/src/server.cpp')
-rw-r--r-- | protocols/WhatsAppWeb/src/server.cpp | 329 |
1 files changed, 0 insertions, 329 deletions
diff --git a/protocols/WhatsAppWeb/src/server.cpp b/protocols/WhatsAppWeb/src/server.cpp deleted file mode 100644 index 91f36b7df7..0000000000 --- a/protocols/WhatsAppWeb/src/server.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/* - -WhatsAppWeb plugin for Miranda NG -Copyright © 2019-22 George Hazan - -*/ - -#include "stdafx.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// gateway worker thread - -void WhatsAppProto::ServerThread(void *) -{ - do { - m_bRespawn = false; - ServerThreadWorker(); - } - while (m_bRespawn); - - OnLoggedOut(); -} - -void WhatsAppProto::ServerThreadWorker() -{ - // connect websocket - NETLIBHTTPHEADER hdrs[] = - { - { "Origin", "https://web.whatsapp.com" }, - { 0, 0 } - }; - - NLHR_PTR pReply(WebSocket_Connect(m_hNetlibUser, "web.whatsapp.com/ws/chat", hdrs)); - if (pReply == nullptr) { - debugLogA("Server connection failed, exiting"); - return; - } - - if (pReply->resultCode != 101) - return; - - delete m_noise; - m_noise = new WANoise(this); - m_noise->init(); - - debugLogA("Server connection succeeded"); - m_hServerConn = pReply->nlc; - m_lastRecvTime = time(0); - m_iPacketId = 1; - - Utils_GetRandom(m_wMsgPrefix, sizeof(m_wMsgPrefix)); - - auto &pubKey = m_noise->ephemeral.pub; - auto *client = new proto::HandshakeMessage::ClientHello(); client->set_ephemeral(pubKey.data(), pubKey.length()); - proto::HandshakeMessage msg; msg.set_allocated_clienthello(client); - WSSend(msg); - - MBinBuffer netbuf; - - for (m_bTerminated = false; !m_bTerminated;) { - unsigned char buf[2048]; - int bufSize = Netlib_Recv(m_hServerConn, (char *)buf, _countof(buf), MSG_NODUMP); - if (bufSize == 0) { - debugLogA("Gateway connection gracefully closed"); - break; - } - if (bufSize < 0) { - debugLogA("Gateway connection error, exiting"); - break; - } - - netbuf.append(buf, bufSize); - - WSHeader hdr; - if (!WebSocket_InitHeader(hdr, netbuf.data(), netbuf.length())) - continue; - - // we lack some data, let's read them - if (netbuf.length() < hdr.headerSize + hdr.payloadSize) - if (!WSReadPacket(hdr, netbuf)) - break; - - // debugLogA("Got packet: buffer = %d, opcode = %d, headerSize = %d, payloadSize = %d, final = %d, masked = %d", - // netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked); - // Netlib_Dump(m_hServerConn, netbuf.data(), netbuf.length(), false, 0); - - m_lastRecvTime = time(0); - - // read all payloads from the current buffer, one by one - while (true) { - MBinBuffer currPacket; - currPacket.assign(netbuf.data() + hdr.headerSize, hdr.payloadSize); - - switch (hdr.opCode) { - case 1: // json packet - debugLogA("Text packet, skipping"); - /* - currPacket.append("", 1); // add 0 to use strchr safely - CMStringA szJson(pos, (int)dataSize); - - JSONNode root = JSONNode::parse(szJson); - if (root) { - debugLogA("JSON received:\n%s", start); - - CMStringA szPrefix(start, int(pos - start - 1)); - auto *pReq = m_arPacketQueue.find((WARequest *)&szPrefix); - if (pReq != nullptr) { - root << CHAR_PARAM("$id$", szPrefix); - } - } - } - */ - break; - - case 2: // binary packet - if (hdr.payloadSize > 32) - ProcessBinaryPacket(currPacket.data(), hdr.payloadSize); - break; - - case 8: // close - debugLogA("server required to exit"); - m_bRespawn = m_bTerminated = true; // simply reconnect, don't exit - break; - - default: - Netlib_Dump(m_hServerConn, currPacket.data(), hdr.payloadSize, false, 0); - } - - netbuf.remove(hdr.headerSize + hdr.payloadSize); - // debugLogA("%d bytes removed from network buffer, %d bytes remain", hdr.headerSize + hdr.payloadSize, netbuf.length()); - if (netbuf.length() == 0) - break; - - // if we have not enough data for header, continue reading - if (!WebSocket_InitHeader(hdr, netbuf.data(), netbuf.length())) { - debugLogA("not enough data for header, continue reading"); - break; - } - - // if we have not enough data for data, continue reading - if (hdr.headerSize + hdr.payloadSize > netbuf.length()) { - debugLogA("not enough place for data (%d+%d > %d), continue reading", hdr.headerSize, hdr.payloadSize, netbuf.length()); - break; - } - - debugLogA("Got inner packet: buffer = %d, opcode = %d, headerSize = %d, payloadSize = %d, final = %d, masked = %d", - netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked); - } - } - - debugLogA("Server connection dropped"); - Netlib_CloseHandle(m_hServerConn); - m_hServerConn = nullptr; -} - -bool WhatsAppProto::WSReadPacket(const WSHeader &hdr, MBinBuffer &res) -{ - size_t currPacketSize = res.length() - hdr.headerSize; - - char buf[1024]; - while (currPacketSize < hdr.payloadSize) { - int result = Netlib_Recv(m_hServerConn, buf, _countof(buf), MSG_NODUMP); - if (result == 0) { - debugLogA("Gateway connection gracefully closed"); - return false; - } - if (result < 0) { - debugLogA("Gateway connection error, exiting"); - return false; - } - - currPacketSize += result; - res.append(buf, result); - } - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Binary data processing - -void WhatsAppProto::ProcessBinaryPacket(const void *pData, size_t cbDataLen) -{ - while (size_t payloadLen = m_noise->decodeFrame(pData, cbDataLen)) { - if (m_noise->bInitFinished) { - MBinBuffer buf = m_noise->decrypt(pData, payloadLen); - - WAReader rdr(buf.data(), buf.length()); - auto b = rdr.readInt8(); - if (b & 2) { - buf.remove(1); - buf = unzip(buf); - rdr = WAReader(buf.data(), buf.length()); - } - - if (WANode *pNode = rdr.readNode()) { - CMStringA szText; - pNode->print(szText); - debugLogA("Got binary node:\n%s", szText.c_str()); - - auto pHandler = FindPersistentHandler(*pNode); - if (pHandler) - (this->*pHandler)(*pNode); - else - debugLogA("cannot handle incoming message"); - - delete pNode; - } - else { - debugLogA("wrong or broken payload"); - Netlib_Dump(m_hServerConn, pData, cbDataLen, false, 0); - } - } - else OnProcessHandshake(pData, (int)payloadLen); - - pData = (BYTE*)pData + payloadLen; - cbDataLen -= payloadLen; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void WhatsAppProto::OnLoggedIn() -{ - debugLogA("WhatsAppProto::OnLoggedIn"); - - SetServerStatus(m_iDesiredStatus); - - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus); - m_iStatus = m_iDesiredStatus; - - m_impl.m_keepAlive.Start(1000); - - // retrieve loaded prekeys count - WSSendNode( - WANodeIq(IQ::GET, "encrypt") << XCHILD("count"), - &WhatsAppProto::OnIqCountPrekeys); - - // retrieve initial info - WANodeIq abt(IQ::GET, "abt"); - abt.addChild("props")->addAttr("protocol", "1"); - WSSendNode(abt, &WhatsAppProto::OnIqDoNothing); - - WSSendNode( - WANodeIq(IQ::GET, "w") << XCHILD("props"), - &WhatsAppProto::OnIqDoNothing); - - WSSendNode( - WANodeIq(IQ::GET, "blocklist"), - &WhatsAppProto::OnIqBlockList); - - WSSendNode( - WANodeIq(IQ::GET, "privacy") << XCHILD("privacy"), - &WhatsAppProto::OnIqDoNothing); - - /* - OBJLIST<WACollection> task(1); - task.insert(new WACollection("regular_high", 9)); - task.insert(new WACollection("regular_low", 11)); - ResyncServer(task); - */ -} - -void WhatsAppProto::OnLoggedOut(void) -{ - m_impl.m_keepAlive.Stop(); - - debugLogA("WhatsAppProto::OnLoggedOut"); - m_bTerminated = true; - - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE); - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - - setAllContactStatuses(ID_STATUS_OFFLINE, false); -} - -void WhatsAppProto::SendKeepAlive() -{ - time_t now = time(0); - if (now - m_lastRecvTime > 20) { - WSSendNode(WANodeIq(IQ::GET, "w:p") << XCHILD("ping"), &WhatsAppProto::OnIqDoNothing); - - m_lastRecvTime = now; - } -} - -void WhatsAppProto::SendReceipt(const char *pszTo, const char *pszParticipant, const char *pszId, const char *pszType) -{ - WANode receipt("receipt"); - receipt << CHAR_PARAM("id", pszId); - - if (!mir_strcmp(pszType, "read") || !mir_strcmp(pszType, "read-self")) - receipt << INT_PARAM("t", time(0)); - - if (!mir_strcmp(pszType, "sender") && WAJid(pszTo).isUser()) - receipt << CHAR_PARAM("to", pszParticipant) << CHAR_PARAM("recipient", pszTo); - else { - receipt << CHAR_PARAM("to", pszTo); - if (pszParticipant) - receipt << CHAR_PARAM("participant", pszParticipant); - } - - if (pszType) - receipt << CHAR_PARAM("type", pszType); - WSSendNode(receipt, &WhatsAppProto::OnIqDoNothing); -} - -void WhatsAppProto::SetServerStatus(int iStatus) -{ - if (mir_wstrlen(m_wszNick)) - WSSendNode( - WANode("presence") << CHAR_PARAM("name", T2Utf(m_wszNick)) << CHAR_PARAM("type", (iStatus == ID_STATUS_ONLINE) ? "available" : "unavailable"), - &WhatsAppProto::OnIqDoNothing); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void WhatsAppProto::ShutdownSession() -{ - if (m_bTerminated) - return; - - debugLogA("WhatsAppProto::ShutdownSession"); - - // shutdown all resources - if (m_hServerConn) - Netlib_Shutdown(m_hServerConn); - - OnLoggedOut(); -} |