summaryrefslogtreecommitdiff
path: root/protocols/WhatsApp/src
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2022-10-21 18:43:06 +0300
committerGeorge Hazan <ghazan@miranda.im>2022-10-21 18:43:06 +0300
commit8a406120d56f454a20db346707fac5dd112b1ccb (patch)
tree144e7f6243fb9a7fc447fd1dadb0ae25f2f56e5a /protocols/WhatsApp/src
parentf565cc4efeace9a9f1c034f3956bd7192382bea7 (diff)
WhatsApp: minor fixes & code reordering
Diffstat (limited to 'protocols/WhatsApp/src')
-rw-r--r--protocols/WhatsApp/src/appsync.cpp1
-rw-r--r--protocols/WhatsApp/src/iq.cpp195
-rw-r--r--protocols/WhatsApp/src/message.cpp165
-rw-r--r--protocols/WhatsApp/src/proto.h3
-rw-r--r--protocols/WhatsApp/src/server.cpp8
5 files changed, 192 insertions, 180 deletions
diff --git a/protocols/WhatsApp/src/appsync.cpp b/protocols/WhatsApp/src/appsync.cpp
index 9728eae48c..9785dbff65 100644
--- a/protocols/WhatsApp/src/appsync.cpp
+++ b/protocols/WhatsApp/src/appsync.cpp
@@ -50,7 +50,6 @@ void WhatsAppProto::OnServerSync(const WANode &node)
void WhatsAppProto::ResyncAll()
{
- setDword("lastResyncTime", time(0));
ResyncServer(m_arCollections);
}
diff --git a/protocols/WhatsApp/src/iq.cpp b/protocols/WhatsApp/src/iq.cpp
index c0a2c414ac..258b466ac3 100644
--- a/protocols/WhatsApp/src/iq.cpp
+++ b/protocols/WhatsApp/src/iq.cpp
@@ -30,6 +30,8 @@ void WhatsAppProto::OnIqBlockList(const WANode &node)
void WhatsAppProto::OnIqCountPrekeys(const WANode &node)
{
+ m_bUpdatedPrekeys = true;
+
int iCount = node.getChild("count")->getAttrInt("value");
if (iCount < 5)
UploadMorePrekeys();
@@ -78,191 +80,39 @@ void WhatsAppProto::OnIqDoNothing(const WANode &)
/////////////////////////////////////////////////////////////////////////////////////////
-void WhatsAppProto::OnNotifyEncrypt(const WANode &node)
+void WhatsAppProto::OnNotifyDevices(const WANode &node)
{
- auto *pszFrom = node.getAttr("from");
- if (!mir_strcmp(pszFrom, S_WHATSAPP_NET)) {
-
- }
+ if (!mir_strcmp(node.getAttr("jid"), m_szJid))
+ debugLogA("received list of my own devices");
}
/////////////////////////////////////////////////////////////////////////////////////////
-void WhatsAppProto::OnReceiveInfo(const WANode &node)
+void WhatsAppProto::OnNotifyEncrypt(const WANode &node)
{
- if (auto *pChild = node.getFirstChild()) {
- if (pChild->title == "offline") {
- debugLogA("Processed %d offline events", pChild->getAttrInt("count"));
-
- if (getDword("lastResyncTime") == 0) {
- m_impl.m_resyncApp.Stop();
- m_impl.m_resyncApp.Start(1000);
- }
- }
- }
+ if (!mir_strcmp(node.getAttr("from"), S_WHATSAPP_NET))
+ OnIqCountPrekeys(node);
}
/////////////////////////////////////////////////////////////////////////////////////////
-void WhatsAppProto::OnReceiveMessage(const WANode &node)
+void WhatsAppProto::OnReceiveInfo(const WANode &node)
{
- auto *msgId = node.getAttr("id");
- auto *msgType = node.getAttr("type");
- auto *msgFrom = node.getAttr("from");
- auto *category = node.getAttr("category");
- auto *recipient = node.getAttr("recipient");
- auto *participant = node.getAttr("participant");
-
- if (msgType == nullptr || msgFrom == nullptr || msgId == nullptr) {
- debugLogA("bad message received: <%s> <%s> <%s>", msgType, msgFrom, msgId);
- return;
- }
-
- WAMSG type;
- WAJid jid(msgFrom);
- CMStringA szAuthor, szChatId;
-
- if (node.getAttr("offline"))
- type.bOffline = true;
-
- // message from one user to another
- if (jid.isUser()) {
- if (recipient) {
- if (m_szJid != msgFrom) {
- debugLogA("strange message: with recipient, but not from me");
- return;
- }
- szChatId = recipient;
- }
- else szChatId = msgFrom;
-
- type.bPrivateChat = true;
- szAuthor = msgFrom;
- }
- else if (jid.isGroup()) {
- if (!participant) {
- debugLogA("strange message: from group, but without participant");
- return;
- }
-
- type.bGroupChat = true;
- szAuthor = participant;
- szChatId = msgFrom;
- }
- else if (jid.isBroadcast()) {
- if (!participant) {
- debugLogA("strange message: from group, but without participant");
- return;
- }
-
- bool bIsMe = m_szJid == participant;
- if (jid.isStatusBroadcast()) {
- if (bIsMe)
- type.bDirectStatus = true;
- else
- type.bOtherStatus = true;
- }
- else {
- if (bIsMe)
- type.bPeerBroadcast = true;
- else
- type.bOtherBroadcast = true;
- }
- szChatId = msgFrom;
- szAuthor = participant;
- }
- else {
- debugLogA("invalid message type");
- return;
- }
-
- CMStringA szSender = (type.bPrivateChat) ? szAuthor : szChatId;
- bool bFromMe = (m_szJid == msgFrom);
- if (!bFromMe && participant)
- bFromMe = m_szJid == participant;
-
- auto *pKey = new proto::MessageKey();
- pKey->set_remotejid(szChatId);
- pKey->set_id(msgId);
- pKey->set_fromme(bFromMe);
- if (participant)
- pKey->set_participant(participant);
-
- proto::WebMessageInfo msg;
- msg.set_allocated_key(pKey);
- msg.set_messagetimestamp(_atoi64(node.getAttr("t")));
- msg.set_pushname(node.getAttr("notify"));
- if (bFromMe)
- msg.set_status(proto::WebMessageInfo_Status_SERVER_ACK);
-
- int iDecryptable = 0;
-
- for (auto &it: node.getChildren()) {
- if (it->title == "verified_name") {
- proto::VerifiedNameCertificate cert;
- cert << it->content;
+ if (auto *pChild = node.getFirstChild()) {
+ if (pChild->title == "offline") {
+ debugLogA("Processed %d offline events", pChild->getAttrInt("count"));
- proto::VerifiedNameCertificate::Details details;
- details.ParseFromString(cert.details());
-
- msg.set_verifiedbizname(details.verifiedname());
- continue;
- }
-
- if (it->title != "enc" || it->content.length() == 0)
- continue;
-
- SignalBuffer msgBody;
- auto *pszType = it->getAttr("type");
- try {
- if (!mir_strcmp(pszType, "pkmsg") || !mir_strcmp(pszType, "msg")) {
- CMStringA szUser = (WAJid(szSender).isUser()) ? szSender : szAuthor;
- msgBody = m_signalStore.decryptSignalProto(szUser, pszType, it->content);
- }
- else if (!mir_strcmp(pszType, "skmsg")) {
- msgBody = m_signalStore.decryptGroupSignalProto(szSender, szAuthor, it->content);
+ // retrieve loaded prekeys count
+ if (!m_bUpdatedPrekeys)
+ WSSendNode(WANodeIq(IQ::GET, "encrypt") << XCHILD("count"), &WhatsAppProto::OnIqCountPrekeys);
+
+ for (auto &it: m_arCollections) {
+ if (it->version == 0) {
+ m_impl.m_resyncApp.Stop();
+ m_impl.m_resyncApp.Start(1000);
+ break;
+ }
}
- else throw "Invalid e2e type";
-
- if (!msgBody)
- throw "Invalid e2e message";
-
- iDecryptable++;
-
- proto::Message encMsg;
- encMsg.ParseFromArray(msgBody.data(), msgBody.len());
- if (encMsg.devicesentmessage().has_message())
- msg.set_allocated_message(new proto::Message(encMsg.devicesentmessage().message()));
- else
- msg.set_allocated_message(new proto::Message(encMsg));
-
- if (encMsg.has_senderkeydistributionmessage())
- m_signalStore.processSenderKeyMessage(encMsg.senderkeydistributionmessage());
-
- ProcessMessage(type, msg);
- msg.clear_message();
-
- // send receipt
- const char *pszReceiptType = nullptr, *pszReceiptTo = participant;
- if (!mir_strcmp(category, "peer"))
- pszReceiptType = "peer_msg";
- else if (bFromMe) {
- // message was sent by me from a different device
- pszReceiptType = "sender";
- if (WAJid(szChatId).isUser())
- pszReceiptTo = szAuthor;
- }
- else if (!m_hServerConn)
- pszReceiptType = "inactive";
-
- SendReceipt(szChatId, pszReceiptTo, msgId, pszReceiptType);
- }
- catch (const char *) {
- }
-
- if (!iDecryptable) {
- debugLogA("Nothing to decrypt");
- return;
}
}
}
@@ -579,6 +429,7 @@ void WhatsAppProto::InitPersistentHandlers()
m_arPersistent.insert(new WAPersistentHandler("iq", "set", "md", "pair-device", &WhatsAppProto::OnIqPairDevice));
m_arPersistent.insert(new WAPersistentHandler("iq", "set", "md", "pair-success", &WhatsAppProto::OnIqPairSuccess));
+ m_arPersistent.insert(new WAPersistentHandler("notification", "devices", 0, 0, &WhatsAppProto::OnNotifyDevices));
m_arPersistent.insert(new WAPersistentHandler("notification", "encrypt", 0, 0, &WhatsAppProto::OnNotifyEncrypt));
m_arPersistent.insert(new WAPersistentHandler("notification", "account_sync", 0, 0, &WhatsAppProto::OnAccountSync));
m_arPersistent.insert(new WAPersistentHandler("notification", "server_sync", 0, 0, &WhatsAppProto::OnServerSync));
diff --git a/protocols/WhatsApp/src/message.cpp b/protocols/WhatsApp/src/message.cpp
index 806fbf1198..1952e57fc4 100644
--- a/protocols/WhatsApp/src/message.cpp
+++ b/protocols/WhatsApp/src/message.cpp
@@ -7,6 +7,171 @@ Copyright © 2019-22 George Hazan
#include "stdafx.h"
+void WhatsAppProto::OnReceiveMessage(const WANode &node)
+{
+ auto *msgId = node.getAttr("id");
+ auto *msgType = node.getAttr("type");
+ auto *msgFrom = node.getAttr("from");
+ auto *category = node.getAttr("category");
+ auto *recipient = node.getAttr("recipient");
+ auto *participant = node.getAttr("participant");
+
+ if (msgType == nullptr || msgFrom == nullptr || msgId == nullptr) {
+ debugLogA("bad message received: <%s> <%s> <%s>", msgType, msgFrom, msgId);
+ return;
+ }
+
+ WAMSG type;
+ WAJid jid(msgFrom);
+ CMStringA szAuthor, szChatId;
+
+ if (node.getAttr("offline"))
+ type.bOffline = true;
+
+ // message from one user to another
+ if (jid.isUser()) {
+ if (recipient) {
+ if (m_szJid != msgFrom) {
+ debugLogA("strange message: with recipient, but not from me");
+ return;
+ }
+ szChatId = recipient;
+ }
+ else szChatId = msgFrom;
+
+ type.bPrivateChat = true;
+ szAuthor = msgFrom;
+ }
+ else if (jid.isGroup()) {
+ if (!participant) {
+ debugLogA("strange message: from group, but without participant");
+ return;
+ }
+
+ type.bGroupChat = true;
+ szAuthor = participant;
+ szChatId = msgFrom;
+ }
+ else if (jid.isBroadcast()) {
+ if (!participant) {
+ debugLogA("strange message: from group, but without participant");
+ return;
+ }
+
+ bool bIsMe = m_szJid == participant;
+ if (jid.isStatusBroadcast()) {
+ if (bIsMe)
+ type.bDirectStatus = true;
+ else
+ type.bOtherStatus = true;
+ }
+ else {
+ if (bIsMe)
+ type.bPeerBroadcast = true;
+ else
+ type.bOtherBroadcast = true;
+ }
+ szChatId = msgFrom;
+ szAuthor = participant;
+ }
+ else {
+ debugLogA("invalid message type");
+ return;
+ }
+
+ CMStringA szSender = (type.bPrivateChat) ? szAuthor : szChatId;
+ bool bFromMe = (m_szJid == msgFrom);
+ if (!bFromMe && participant)
+ bFromMe = m_szJid == participant;
+
+ auto *pKey = new proto::MessageKey();
+ pKey->set_remotejid(szChatId);
+ pKey->set_id(msgId);
+ pKey->set_fromme(bFromMe);
+ if (participant)
+ pKey->set_participant(participant);
+
+ proto::WebMessageInfo msg;
+ msg.set_allocated_key(pKey);
+ msg.set_messagetimestamp(_atoi64(node.getAttr("t")));
+ msg.set_pushname(node.getAttr("notify"));
+ if (bFromMe)
+ msg.set_status(proto::WebMessageInfo_Status_SERVER_ACK);
+
+ int iDecryptable = 0;
+
+ for (auto &it : node.getChildren()) {
+ if (it->title == "verified_name") {
+ proto::VerifiedNameCertificate cert;
+ cert << it->content;
+
+ proto::VerifiedNameCertificate::Details details;
+ details.ParseFromString(cert.details());
+
+ msg.set_verifiedbizname(details.verifiedname());
+ continue;
+ }
+
+ if (it->title != "enc" || it->content.length() == 0)
+ continue;
+
+ SignalBuffer msgBody;
+ auto *pszType = it->getAttr("type");
+ try {
+ if (!mir_strcmp(pszType, "pkmsg") || !mir_strcmp(pszType, "msg")) {
+ CMStringA szUser = (WAJid(szSender).isUser()) ? szSender : szAuthor;
+ msgBody = m_signalStore.decryptSignalProto(szUser, pszType, it->content);
+ }
+ else if (!mir_strcmp(pszType, "skmsg")) {
+ msgBody = m_signalStore.decryptGroupSignalProto(szSender, szAuthor, it->content);
+ }
+ else throw "Invalid e2e type";
+
+ if (!msgBody)
+ throw "Invalid e2e message";
+
+ iDecryptable++;
+
+ proto::Message encMsg;
+ encMsg.ParseFromArray(msgBody.data(), msgBody.len());
+ if (encMsg.devicesentmessage().has_message())
+ msg.set_allocated_message(new proto::Message(encMsg.devicesentmessage().message()));
+ else
+ msg.set_allocated_message(new proto::Message(encMsg));
+
+ if (encMsg.has_senderkeydistributionmessage())
+ m_signalStore.processSenderKeyMessage(encMsg.senderkeydistributionmessage());
+
+ ProcessMessage(type, msg);
+ msg.clear_message();
+
+ // send receipt
+ const char *pszReceiptType = nullptr, *pszReceiptTo = participant;
+ if (!mir_strcmp(category, "peer"))
+ pszReceiptType = "peer_msg";
+ else if (bFromMe) {
+ // message was sent by me from a different device
+ pszReceiptType = "sender";
+ if (WAJid(szChatId).isUser())
+ pszReceiptTo = szAuthor;
+ }
+ else if (!m_hServerConn)
+ pszReceiptType = "inactive";
+
+ SendReceipt(szChatId, pszReceiptTo, msgId, pszReceiptType);
+ }
+ catch (const char *) {
+ }
+
+ if (!iDecryptable) {
+ debugLogA("Nothing to decrypt");
+ return;
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
static const proto::Message& getBody(const proto::Message &message)
{
if (message.has_ephemeralmessage()) {
diff --git a/protocols/WhatsApp/src/proto.h b/protocols/WhatsApp/src/proto.h
index 5814aa7538..a5b6a60f57 100644
--- a/protocols/WhatsApp/src/proto.h
+++ b/protocols/WhatsApp/src/proto.h
@@ -243,7 +243,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
}
} m_impl;
- bool m_bTerminated, m_bRespawn;
+ bool m_bTerminated, m_bRespawn, m_bUpdatedPrekeys;
ptrW m_tszDefaultGroup;
CMStringA m_szJid;
@@ -346,6 +346,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
void OnIqPairSuccess(const WANode &node);
void OnIqResult(const WANode &node);
void OnIqServerSync(const WANode &node);
+ void OnNotifyDevices(const WANode &node);
void OnNotifyEncrypt(const WANode &node);
void OnReceiveInfo(const WANode &node);
void OnReceiveMessage(const WANode &node);
diff --git a/protocols/WhatsApp/src/server.cpp b/protocols/WhatsApp/src/server.cpp
index f638f1a8b3..efe293c5b0 100644
--- a/protocols/WhatsApp/src/server.cpp
+++ b/protocols/WhatsApp/src/server.cpp
@@ -227,14 +227,10 @@ void WhatsAppProto::OnLoggedIn()
ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus);
m_iStatus = m_iDesiredStatus;
+ m_bUpdatedPrekeys = false;
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");
@@ -294,7 +290,7 @@ void WhatsAppProto::SendReceipt(const char *pszTo, const char *pszParticipant, c
if (pszType)
receipt << CHAR_PARAM("type", pszType);
- WSSendNode(receipt, &WhatsAppProto::OnIqDoNothing);
+ WSSendNode(receipt);
}
void WhatsAppProto::SetServerStatus(int iStatus)