diff options
-rw-r--r-- | protocols/WhatsApp/src/iq.cpp | 43 | ||||
-rw-r--r-- | protocols/WhatsApp/src/message.cpp | 46 | ||||
-rw-r--r-- | protocols/WhatsApp/src/proto.cpp | 1 | ||||
-rw-r--r-- | protocols/WhatsApp/src/proto.h | 18 | ||||
-rw-r--r-- | protocols/WhatsApp/src/server.cpp | 4 | ||||
-rw-r--r-- | protocols/WhatsApp/src/signal.cpp | 10 |
6 files changed, 72 insertions, 50 deletions
diff --git a/protocols/WhatsApp/src/iq.cpp b/protocols/WhatsApp/src/iq.cpp index c3f4ba2a38..ccc9ad6f1a 100644 --- a/protocols/WhatsApp/src/iq.cpp +++ b/protocols/WhatsApp/src/iq.cpp @@ -9,12 +9,14 @@ Copyright © 2019-22 George Hazan void WhatsAppProto::OnAccountSync(const WANode &node) { - m_arDevices.destroy(); + if (auto *pList = node.getChild("devices")) { + auto *pUser = FindUser(m_szJid); + pUser->arDevices.destroy(); - if (auto *pList = node.getChild("devices")) for (auto &it : pList->getChildren()) if (it->title == "device") - m_arDevices.insert(new WAJid(it->getAttr("jid"), it->getAttrInt("key-index"))); + pUser->arDevices.insert(new WAJid(it->getAttr("jid"), it->getAttrInt("key-index"))); + } if (auto *pList = node.getChild("blocklist")) for (auto &it : pList->getChildren()) @@ -94,35 +96,42 @@ void WhatsAppProto::OnIqGetKeys(const WANode &node, void *pUserInfo) { for (auto &it : node.getChild("list")->getChildren()) if (it->title == "user") - m_signalStore.injectSession(it); + m_signalStore.injectSession(it->getAttr("jid"), it, it); // don't forget to send delayed message when all keys are retrieved if (pUserInfo) - SendTask((WASendTask *)pUserInfo); + FinishTask((WASendTask *)pUserInfo); } ///////////////////////////////////////////////////////////////////////////////////////// -void WhatsAppProto::OnIqGetUsync(const WANode &node) +void WhatsAppProto::OnIqGetUsync(const WANode &node, void *pUserInfo) { - m_arDevices.destroy(); - if (auto *nUser = node.getChild("usync")->getChild("list")->getChild("user")) { auto *pszJid = nUser->getAttr("jid"); + + auto *pUser = AddUser(pszJid, false); + pUser->bDeviceInit = true; + pUser->arDevices.destroy(); + if (auto *pList = nUser->getChild("devices")->getChild("device-list")) for (auto &it : pList->getChildren()) if (it->title == "device") - m_arDevices.insert(new WAJid(pszJid, it->getAttrInt("id"))); + pUser->arDevices.insert(new WAJid(pszJid, it->getAttrInt("id"))); WANodeIq iq(IQ::GET, "encrypt"); auto *pKey = iq.addChild("key"); - for (auto &it : m_arDevices) { + for (auto &it : pUser->arDevices) { auto blob = getBlob(MSignalSession(it->user, it->device).getSetting()); if (blob.isEmpty()) pKey->addChild("user")->addAttr("jid", it->toString()); } + if (pKey->getChildren().getCount() > 0) - WSSendNode(iq, &WhatsAppProto::OnIqGetKeys, nullptr); + WSSendNode(iq, &WhatsAppProto::OnIqGetKeys, pUserInfo); + else if (pUserInfo) + FinishTask((WASendTask *)pUserInfo); + } } @@ -460,8 +469,9 @@ void WhatsAppProto::OnReceiveInfo(const WANode &node) if (!m_bUpdatedPrekeys) WSSendNode(WANodeIq(IQ::GET, "encrypt") << XCHILD("count"), &WhatsAppProto::OnIqCountPrekeys); - if (m_arDevices.getCount() == 0) - SendUsync(m_szJid); + auto *pUser = FindUser(m_szJid); + if (pUser->arDevices.getCount() == 0) + SendUsync(m_szJid, nullptr); for (auto &it : m_arCollections) { if (it->version == 0) { @@ -491,6 +501,13 @@ void WhatsAppProto::ProcessReceipt(MCONTACT hContact, const char *msgId, bool bR void WhatsAppProto::OnReceiveReceipt(const WANode &node) { + if (!mir_strcmp(node.getAttr("type"), "retry")) { + for (auto &it : node.getChildren()) + if (it->title == "keys") + m_signalStore.injectSession(node.getAttr("from"), &node, it); + return; + } + if (auto *pUser = FindUser(node.getAttr("from"))) { bool bRead = mir_strcmp(node.getAttr("type"), "read") == 0; ProcessReceipt(pUser->hContact, node.getAttr("id"), bRead); diff --git a/protocols/WhatsApp/src/message.cpp b/protocols/WhatsApp/src/message.cpp index 41b5cf92a6..2c9149c45b 100644 --- a/protocols/WhatsApp/src/message.cpp +++ b/protocols/WhatsApp/src/message.cpp @@ -200,7 +200,8 @@ void WhatsAppProto::ProcessMessage(WAMSG type, const Wa__WebMessageInfo &msg) else chatId = (participant) ? participant : key->remotejid; - WAUser *pUser = AddUser(chatId, false); + WAJid jidFrom(chatId); jidFrom.device = 0; + WAUser *pUser = AddUser(jidFrom.toString(), false); if (!key->fromme && msg.pushname && pUser && !pUser->bIsGroupChat) setUString(pUser->hContact, "Nick", msg.pushname); @@ -373,6 +374,7 @@ int WhatsAppProto::SendTextMessage(const char *jid, const char *pszMsg) Wa__Message body; body.extendedtextmessage = &extMessage; + bool bNeedsCheck = false; if (toJid.isGroup()) { MBinBuffer encodedMsg(proto::Serialize(&body)); padBuffer16(encodedMsg); @@ -410,24 +412,22 @@ int WhatsAppProto::SendTextMessage(const char *jid, const char *pszMsg) pTask->content.append(proto::Serialize(&msg)); - pTask->arDest.insert(new WAJid(toJid)); + if (auto *pUser = FindUser(jid)) { + if (pUser->bDeviceInit) { + for (auto &it : pUser->arDevices) + pTask->arDest.insert(new WAJid(*it)); + } + else bNeedsCheck = true; + } } padBuffer16(pTask->content); - for (auto &it : m_arDevices) + auto *pOwnUser = FindUser(m_szJid); + for (auto &it : pOwnUser->arDevices) if (it->device != (int)getDword(DBKEY_DEVICE_ID)) pTask->arDest.insert(new WAJid(*it)); - // check session presence first - LIST<WAJid> missingKeys(1); - for (auto &it : pTask->arDest) { - MSignalSession tmp(it->user, it->device); - auto blob = getBlob(tmp.getSetting()); - if (blob.isEmpty()) - missingKeys.insert(it); - } - // generate & reserve packet id int pktId; { @@ -437,19 +437,23 @@ int WhatsAppProto::SendTextMessage(const char *jid, const char *pszMsg) } // if some keys are missing, schedule task for execution & retrieve keys - if (missingKeys.getCount()) { - WANodeIq iq(IQ::GET, "encrypt"); - auto *pKey = iq.addChild("key"); - for (auto &it: missingKeys) - pKey->addChild("user")->addAttr("jid", it->toString()); - WSSendNode(iq, &WhatsAppProto::OnIqGetKeys, pTask); - } - // otherwise simply execute the task - else SendTask(pTask); + if (bNeedsCheck) + SendUsync(jid, pTask); + else // otherwise simply execute the task + SendTask(pTask); return pktId; } +void WhatsAppProto::FinishTask(WASendTask *pTask) +{ + if (auto *pUser = FindUser(pTask->payLoad.getAttr("to"))) + for (auto &it : pUser->arDevices) + pTask->arDest.insert(new WAJid(*it)); + + SendTask(pTask); +} + void WhatsAppProto::SendTask(WASendTask *pTask) { // pack all data and send the whole payload diff --git a/protocols/WhatsApp/src/proto.cpp b/protocols/WhatsApp/src/proto.cpp index ac6562450c..235b610817 100644 --- a/protocols/WhatsApp/src/proto.cpp +++ b/protocols/WhatsApp/src/proto.cpp @@ -44,7 +44,6 @@ WhatsAppProto::WhatsAppProto(const char *proto_name, const wchar_t *username) : m_szJid(getMStringA(DBKEY_ID)), m_tszDefaultGroup(getWStringA(DBKEY_DEF_GROUP)), m_arUsers(10, CompareUsers), - m_arDevices(1), m_arOwnMsgs(1, CompareOwnMsgs), m_arPersistent(1), m_arPacketQueue(10, CompareRequests), diff --git a/protocols/WhatsApp/src/proto.h b/protocols/WhatsApp/src/proto.h index a699c91481..b192696410 100644 --- a/protocols/WhatsApp/src/proto.h +++ b/protocols/WhatsApp/src/proto.h @@ -107,7 +107,8 @@ struct WAUser WAUser(MCONTACT _1, const char *_2, bool _3 = false) : hContact(_1), szId(mir_strdup(_2)), - bIsGroupChat(_3) + bIsGroupChat(_3), + arDevices(1) { } @@ -119,8 +120,9 @@ struct WAUser MCONTACT hContact; DWORD dwModifyTag = 0; char *szId; - bool bInited = false, bIsGroupChat; + bool bInited = false, bIsGroupChat, bDeviceInit = false; SESSION_INFO *si = 0; + OBJLIST<WAJid> arDevices; time_t m_timer1 = 0, m_timer2 = 0; }; @@ -236,7 +238,7 @@ public: MSignalSession* createSession(const CMStringA &szName, int deviceId); MSignalSession* getSession(const signal_protocol_address *address); - void injectSession(const WANode *pNode); + void injectSession(const char *szJid, const WANode *pNode, const WANode *pKey); MBinBuffer decryptSignalProto(const CMStringA &from, const char *pszType, const MBinBuffer &encrypted); MBinBuffer decryptGroupSignalProto(const CMStringA &from, const CMStringA &author, const MBinBuffer &encrypted); @@ -315,8 +317,6 @@ class WhatsAppProto : public PROTO<WhatsAppProto> mir_cs m_csOwnMessages; OBJLIST<WAOwnMessage> m_arOwnMsgs; - OBJLIST<WAJid> m_arDevices; - WAUser* FindUser(const char *szId); WAUser* AddUser(const char *szId, bool bTemporary); @@ -372,11 +372,13 @@ class WhatsAppProto : public PROTO<WhatsAppProto> void SendAck(const WANode &node); void SendReceipt(const char *pszTo, const char *pszParticipant, const char *pszId, const char *pszType); void SendKeepAlive(); - void SendTask(WASendTask *pTask); int SendTextMessage(const char *jid, const char *pszMsg); - void SendUsync(const char *jid); + void SendUsync(const char *jid, void *pUserInfo); void SetServerStatus(int iStatus); + void FinishTask(WASendTask *pTask); + void SendTask(WASendTask *pTask); + /// Popups ///////////////////////////////////////////////////////////////////////////// HANDLE m_hPopupClass; @@ -397,7 +399,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto> void OnIqGcGetAllMetadata(const WANode &node); void OnIqGetAvatar(const WANode &node); void OnIqGetKeys(const WANode &node, void *pUserInfo); - void OnIqGetUsync(const WANode &node); + void OnIqGetUsync(const WANode &node, void *pUserInfo); void OnIqPairDevice(const WANode &node); void OnIqPairSuccess(const WANode &node); void OnIqResult(const WANode &node); diff --git a/protocols/WhatsApp/src/server.cpp b/protocols/WhatsApp/src/server.cpp index 1fce9ed3a7..df9e3ec86e 100644 --- a/protocols/WhatsApp/src/server.cpp +++ b/protocols/WhatsApp/src/server.cpp @@ -399,7 +399,7 @@ void WhatsAppProto::SetServerStatus(int iStatus) &WhatsAppProto::OnIqDoNothing); } -void WhatsAppProto::SendUsync(const char *jid) +void WhatsAppProto::SendUsync(const char *jid, void *pUserInfo) { WANodeIq iq(IQ::GET, "usync"); @@ -410,7 +410,7 @@ void WhatsAppProto::SendUsync(const char *jid) pNode1->addChild("query")->addChild("devices")->addAttr("version", "2"); pNode1->addChild("list")->addChild("user")->addAttr("jid", jid); - WSSendNode(iq, &WhatsAppProto::OnIqGetUsync); + WSSendNode(iq, &WhatsAppProto::OnIqGetUsync, pUserInfo); } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/WhatsApp/src/signal.cpp b/protocols/WhatsApp/src/signal.cpp index 3da969a722..b94a3452e4 100644 --- a/protocols/WhatsApp/src/signal.cpp +++ b/protocols/WhatsApp/src/signal.cpp @@ -542,12 +542,12 @@ void MSignalStore::importPublicKey(ec_public_key **result, MBinBuffer &buf) curve_decode_point(result, buf.data(), buf.length(), m_pContext); } -void MSignalStore::injectSession(const WANode *pNode) +void MSignalStore::injectSession(const char *szJid, const WANode *pNode, const WANode *pKey) { - WAJid jid(pNode->getAttr("jid")); - auto *signedKey = pNode->getChild("skey"); - auto *key = pNode->getChild("key"); - auto *identity = pNode->getChild("identity"); + WAJid jid(szJid); + auto *signedKey = pKey->getChild("skey"); + auto *key = pKey->getChild("key"); + auto *identity = pKey->getChild("identity"); auto *registration = pNode->getChild("registration"); if (!signedKey || !key || !identity || !registration) { pProto->debugLogA("Bad key data for %s", jid.toString().c_str()); |