summaryrefslogtreecommitdiff
path: root/protocols/WhatsAppWeb
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2021-04-24 13:33:35 +0300
committerGeorge Hazan <ghazan@miranda.im>2021-04-24 13:33:35 +0300
commit9449b0587fa74976ff55828f5d850bc061e331b8 (patch)
tree0cdb4ef45ecfcb8d4ce50fb58d179bebbeba5289 /protocols/WhatsAppWeb
parentf12ba22652c92aebc74eace3a3011285af3a116c (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.cpp38
-rw-r--r--protocols/WhatsAppWeb/src/proto.h64
-rw-r--r--protocols/WhatsAppWeb/src/server.cpp49
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);
}