diff options
author | George Hazan <ghazan@miranda.im> | 2021-04-24 13:33:35 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2021-04-24 13:33:35 +0300 |
commit | 9449b0587fa74976ff55828f5d850bc061e331b8 (patch) | |
tree | 0cdb4ef45ecfcb8d4ce50fb58d179bebbeba5289 /protocols/WhatsAppWeb | |
parent | f12ba22652c92aebc74eace3a3011285af3a116c (diff) |
WhatsApp:
- self-generated message ids;
- added message metric & flags;
- packet handlers switched to full prefixes instead of packet ids
Diffstat (limited to 'protocols/WhatsAppWeb')
-rw-r--r-- | protocols/WhatsAppWeb/src/proto.cpp | 38 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/proto.h | 64 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/server.cpp | 49 |
3 files changed, 109 insertions, 42 deletions
diff --git a/protocols/WhatsAppWeb/src/proto.cpp b/protocols/WhatsAppWeb/src/proto.cpp index aab94609fe..df5993592a 100644 --- a/protocols/WhatsAppWeb/src/proto.cpp +++ b/protocols/WhatsAppWeb/src/proto.cpp @@ -17,6 +17,16 @@ struct SearchParam LONG id; }; +static int CompareOwnMsgs(const WAOwnMessage *p1, const WAOwnMessage *p2) +{ + return strcmp(p1->szPrefix, p2->szPrefix); +} + +static int CompareRequests(const WARequest *p1, const WARequest *p2) +{ + return strcmp(p1->szPrefix, p2->szPrefix); +} + static int CompareUsers(const WAUser *p1, const WAUser *p2) { return strcmp(p1->szId, p2->szId); @@ -27,8 +37,8 @@ WhatsAppProto::WhatsAppProto(const char *proto_name, const wchar_t *username) : m_impl(*this), m_tszDefaultGroup(getWStringA(DBKEY_DEF_GROUP)), m_arUsers(10, CompareUsers), - m_arOwnMsgs(1, NumericKeySortT), - m_arPacketQueue(10, NumericKeySortT), + m_arOwnMsgs(1, CompareOwnMsgs), + m_arPacketQueue(10, CompareRequests), m_wszDefaultGroup(this, "DefaultGroup", L"WhatsApp"), m_bHideGroupchats(this, "HideChats", true) { @@ -196,25 +206,26 @@ int WhatsAppProto::SetStatus(int new_status) void WhatsAppProto::OnSendMessage(const JSONNode &node) { - int pktId = node["$id$"].as_int(); + CMStringA szPrefix= node["$id$"].as_mstring(); - WAOwnMessage tmp(pktId, 0); + WAOwnMessage tmp(0, 0, szPrefix); { mir_cslock lck(m_csOwnMessages); auto *pOwn = m_arOwnMsgs.find(&tmp); if (pOwn == nullptr) return; + tmp.pktId = pOwn->pktId; tmp.hContact = pOwn->hContact; m_arOwnMsgs.remove(pOwn); } int status = node["status"].as_int(); if (status == 200) - ProtoBroadcastAck(tmp.hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)pktId); + ProtoBroadcastAck(tmp.hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)tmp.pktId); else { CMStringW wszError(FORMAT, TranslateT("Operation failed with server error status %d"), status); - ProtoBroadcastAck(tmp.hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)pktId, LPARAM(wszError.c_str())); + ProtoBroadcastAck(tmp.hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)tmp.pktId, LPARAM(wszError.c_str())); } } @@ -229,9 +240,14 @@ int WhatsAppProto::SendMsg(MCONTACT hContact, int, const char *pszMsg) return 0; } + char msgId[16], szMsgId[33]; + Utils_GetRandom(msgId, sizeof(msgId)); + bin2hex(msgId, sizeof(msgId), szMsgId); + auto *key = new proto::MessageKey(); key->set_remotejid(jid); key->set_fromme(true); + key->set_id(szMsgId); proto::WebMessageInfo msg; msg.set_allocated_key(key); @@ -242,19 +258,15 @@ int WhatsAppProto::SendMsg(MCONTACT hContact, int, const char *pszMsg) mir_ptr<BYTE> pBuf((BYTE *)mir_alloc(cbBinaryLen)); msg.SerializeToArray(pBuf, (int)cbBinaryLen); - auto *message = new WANode(); - message->title = "message"; - message->content.assign(pBuf, cbBinaryLen); - WANode payLoad; payLoad.title = "action"; payLoad.addAttr("type", "relay"); - payLoad.children.push_back(message); + payLoad.content.assign(pBuf, cbBinaryLen); - int pktId = WSSendNode(payLoad, &WhatsAppProto::OnSendMessage); + int pktId = WSSendNode(szMsgId, WAMetric::message, int(WAFlag::ignore), payLoad, &WhatsAppProto::OnSendMessage); mir_cslock lck(m_csOwnMessages); - m_arOwnMsgs.insert(new WAOwnMessage(pktId, hContact)); + m_arOwnMsgs.insert(new WAOwnMessage(pktId, hContact, szMsgId)); return pktId; } diff --git a/protocols/WhatsAppWeb/src/proto.h b/protocols/WhatsAppWeb/src/proto.h index d7a3723e89..a615d4a8d2 100644 --- a/protocols/WhatsAppWeb/src/proto.h +++ b/protocols/WhatsAppWeb/src/proto.h @@ -11,10 +11,62 @@ Copyright © 2019-21 George Hazan class WhatsAppProto; typedef void (WhatsAppProto:: *WA_PKT_HANDLER)(const JSONNode &node); +enum class WAMetric +{ + debugLog = 1, + queryResume, + queryReceipt, + queryMedia, + queryChat, + queryContacts, + queryMessages, + presence, + presenceSubscribe, + group, + read, + chat, + received, + pic, + status, + message, + queryActions, + block, + queryGroup, + queryPreview, + queryEmoji, + queryMessageInfo, + spam, + querySearch, + queryIdentity, + queryUrl, + profile, + contact, + queryVcard, + queryStatus, + queryStatusUpdate, + privacyStatus, + queryLiveLocations, + liveLocation, + queryVname, + queryLabels, + call, + queryCall, + queryQuickReplies, +}; + +enum class WAFlag +{ + skipOffline = 1 << 2, + expires = 1 << 3, + notAvailable = 1 << 4, + available = 1 << 5, + ackRequest = 1 << 6, + ignore = 1 << 7, +}; + struct WARequest { - int pktId; - time_t issued; + CMStringA szPrefix; WA_PKT_HANDLER pHandler; }; @@ -40,13 +92,15 @@ struct WAUser struct WAOwnMessage { - WAOwnMessage(int _1, MCONTACT _2) : + WAOwnMessage(int _1, MCONTACT _2, const char *_3) : pktId(_1), - hContact(_2) + hContact(_2), + szPrefix(_3) {} int pktId; MCONTACT hContact; + CMStringA szPrefix; }; class WhatsAppProto : public PROTO<WhatsAppProto> @@ -111,7 +165,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto> bool WSReadPacket(const WSHeader &hdr, MBinBuffer &buf); int WSSend(const CMStringA &str, WA_PKT_HANDLER = nullptr); - int WSSendNode(WANode &node, WA_PKT_HANDLER = nullptr); + int WSSendNode(const char *pszPrefix, WAMetric, int flags, WANode &node, WA_PKT_HANDLER = nullptr); void OnLoggedIn(void); void OnLoggedOut(void); diff --git a/protocols/WhatsAppWeb/src/server.cpp b/protocols/WhatsAppWeb/src/server.cpp index c89926d1ce..13a08e9478 100644 --- a/protocols/WhatsAppWeb/src/server.cpp +++ b/protocols/WhatsAppWeb/src/server.cpp @@ -18,22 +18,24 @@ int WhatsAppProto::WSSend(const CMStringA &str, WA_PKT_HANDLER pHandler) int pktId = ++m_iPktNumber; CMStringA buf; - buf.Format("%d.--%d,", (int)m_iLoginTime, pktId); - if (!str.IsEmpty()) { - buf.AppendChar(','); - buf += str; - } + buf.Format("%d.--%d", (int)m_iLoginTime, pktId); if (pHandler != nullptr) { auto *pReq = new WARequest; - pReq->issued = time(0); pReq->pHandler = pHandler; - pReq->pktId = pktId; + pReq->szPrefix = buf; mir_cslock lck(m_csPacketQueue); m_arPacketQueue.insert(pReq); } + buf.AppendChar(','); + if (!str.IsEmpty()) { + buf.AppendChar(','); + buf += str; + } + + debugLogA("Sending packet #%d: %s", pktId, buf.c_str()); WebSocket_SendText(m_hServerConn, buf.c_str()); return pktId; @@ -43,7 +45,7 @@ int WhatsAppProto::WSSend(const CMStringA &str, WA_PKT_HANDLER pHandler) static char zeroData[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -int WhatsAppProto::WSSendNode(WANode &node, WA_PKT_HANDLER pHandler) +int WhatsAppProto::WSSendNode(const char *pszPrefix, WAMetric metric, int flags, WANode &node, WA_PKT_HANDLER pHandler) { if (m_hServerConn == nullptr) return 0; @@ -74,11 +76,11 @@ int WhatsAppProto::WSSendNode(WANode &node, WA_PKT_HANDLER pHandler) enc.assign(writer.body.data(), writer.body.length()); enc.append(mac_key.data(), mac_key.length()); - int dec_len = 0, final_len = 0; + int enc_len = 0, final_len = 0; EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (BYTE*)enc_key.data(), iv); - EVP_EncryptUpdate(ctx, (BYTE*)enc.data(), &dec_len, (BYTE*)writer.body.data(), (int)writer.body.length()); - EVP_EncryptFinal_ex(ctx, (BYTE*)enc.data() + dec_len, &final_len); + EVP_EncryptUpdate(ctx, (BYTE*)enc.data(), &enc_len, (BYTE*)writer.body.data(), (int)writer.body.length()); + EVP_EncryptFinal_ex(ctx, (BYTE*)enc.data() + enc_len, &final_len); EVP_CIPHER_CTX_free(ctx); // build the resulting buffer of the following structure: @@ -89,26 +91,27 @@ int WhatsAppProto::WSSendNode(WANode &node, WA_PKT_HANDLER pHandler) BYTE hmac[32]; unsigned int hmac_len = 32; - HMAC(EVP_sha256(), mac_key.data(), (int)mac_key.length(), (BYTE*)enc.data(), (int)enc.length(), hmac, &hmac_len); + HMAC(EVP_sha256(), mac_key.data(), (int)mac_key.length(), (BYTE*)enc.data(), enc_len, hmac, &hmac_len); int pktId = ++m_iPktNumber; - CMStringA prefix(FORMAT, "%d.--%d,", (int)m_iLoginTime, pktId); if (pHandler != nullptr) { auto *pReq = new WARequest; - pReq->issued = time(0); pReq->pHandler = pHandler; - pReq->pktId = pktId; + pReq->szPrefix = pszPrefix; mir_cslock lck(m_csPacketQueue); m_arPacketQueue.insert(pReq); } + char postPrefix[3] = { ',', (char)metric, (char)flags }; + MBinBuffer ret; - ret.append(prefix, prefix.GetLength()); + ret.append(pszPrefix, strlen(pszPrefix)); + ret.append(postPrefix, sizeof(postPrefix)); ret.append(hmac, sizeof(hmac)); ret.append(iv, sizeof(iv)); - ret.append(enc.data(), enc.length()); + ret.append(enc.data(), enc_len); WebSocket_SendBinary(m_hServerConn, ret.data(), ret.length()); return pktId; @@ -448,13 +451,11 @@ bool WhatsAppProto::ServerThreadWorker() if (root) { debugLogA("JSON received:\n%s", start); - int sessId, pktId; - if (sscanf(start, "%d.--%d,", &sessId, &pktId) == 2) { - auto *pReq = m_arPacketQueue.find((WARequest *)&pktId); - if (pReq != nullptr) { - root << INT_PARAM("$id$", pktId); - (this->*pReq->pHandler)(root); - } + CMStringA szPrefix(start, int(pos - start - 1)); + auto *pReq = m_arPacketQueue.find((WARequest *)&szPrefix); + if (pReq != nullptr) { + root << CHAR_PARAM("$id$", szPrefix); + (this->*pReq->pHandler)(root); } else ProcessPacket(root); } |