summaryrefslogtreecommitdiff
path: root/protocols/WhatsAppWeb/src/iq.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/WhatsAppWeb/src/iq.cpp')
-rw-r--r--protocols/WhatsAppWeb/src/iq.cpp188
1 files changed, 161 insertions, 27 deletions
diff --git a/protocols/WhatsAppWeb/src/iq.cpp b/protocols/WhatsAppWeb/src/iq.cpp
index 66545e26ab..756f64c622 100644
--- a/protocols/WhatsAppWeb/src/iq.cpp
+++ b/protocols/WhatsAppWeb/src/iq.cpp
@@ -28,25 +28,15 @@ void WhatsAppProto::OnIqBlockList(const WANode &node)
/////////////////////////////////////////////////////////////////////////////////////////
-static int sttEnumPrekeys(const char *szSetting, void *param)
-{
- std::vector<int> *list = (std::vector<int> *)param;
- if (!memcmp(szSetting, "PreKey", 6) && !strstr(szSetting, "Public"))
- list->push_back(atoi(szSetting + 6));
- return 0;
-}
-
void WhatsAppProto::OnIqCountPrekeys(const WANode &node)
{
- std::vector<int> ids;
- db_enum_settings(0, sttEnumPrekeys, m_szModuleName, &ids);
-
int iCount = node.getChild("count")->getAttrInt("value");
- if (iCount >= ids.size()) {
- debugLogA("Prekeys are already uploaded");
- return;
- }
+ if (iCount < 5)
+ UploadMorePrekeys();
+}
+void WhatsAppProto::UploadMorePrekeys()
+{
WANodeIq iq(IQ::SET, "encrypt");
auto regId = encodeBigEndian(getDword(DBKEY_REG_ID));
@@ -55,14 +45,20 @@ void WhatsAppProto::OnIqCountPrekeys(const WANode &node)
iq.addChild("type")->content.append(KEY_BUNDLE_TYPE, 1);
iq.addChild("identity")->content.append(m_signalStore.signedIdentity.pub);
+ const int PORTION = 10;
+ m_signalStore.generatePrekeys(PORTION);
+
+ int iStart = getDword(DBKEY_PREKEY_UPLOAD_ID, 1);
auto *n = iq.addChild("list");
- for (auto &keyId : ids) {
+ for (int i = 0; i < PORTION; i++) {
auto *nKey = n->addChild("key");
-
+
+ int keyId = iStart + i;
auto encId = encodeBigEndian(keyId, 3);
nKey->addChild("id")->content.append(encId.c_str(), encId.size());
nKey->addChild("value")->content.append(getBlob(CMStringA(FORMAT, "PreKey%dPublic", keyId)));
}
+ setDword(DBKEY_PREKEY_UPLOAD_ID, iStart + PORTION);
auto *skey = iq.addChild("skey");
@@ -82,6 +78,26 @@ void WhatsAppProto::OnIqDoNothing(const WANode &)
/////////////////////////////////////////////////////////////////////////////////////////
+void WhatsAppProto::OnNotifyEncrypt(const WANode &node)
+{
+ auto *pszFrom = node.getAttr("from");
+ if (!mir_strcmp(pszFrom, S_WHATSAPP_NET)) {
+
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::OnReceiveInfo(const WANode &node)
+{
+ if (auto *pChild = node.getFirstChild()) {
+ if (pChild->title == "offline")
+ debugLogA("Processed %d offline events", pChild->getAttrInt("count"));
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
void WhatsAppProto::OnReceiveMessage(const WANode &node)
{
auto *msgId = node.getAttr("id");
@@ -252,15 +268,6 @@ void WhatsAppProto::OnStreamError(const WANode &node)
/////////////////////////////////////////////////////////////////////////////////////////
-void WhatsAppProto::OnSuccess(const WANode &)
-{
- OnLoggedIn();
-
- WSSendNode(WANodeIq(IQ::SET, "passive") << XCHILD("active"), &WhatsAppProto::OnIqDoNothing);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
void WhatsAppProto::OnIqResult(const WANode &node)
{
if (auto *pszId = node.getAttr("id"))
@@ -522,13 +529,140 @@ LBL_Error:
/////////////////////////////////////////////////////////////////////////////////////////
+void WhatsAppProto::OnServerSync(const WANode &node)
+{
+ OBJLIST<WACollection> task(1);
+
+ for (auto &it : node.getChildren())
+ if (it->title == "collection")
+ task.insert(new WACollection(it->getAttr("name"), it->getAttrInt("version")));
+
+ ResyncServer(task);
+}
+
+void WhatsAppProto::ResyncServer(const OBJLIST<WACollection> &task)
+{
+ WANodeIq iq(IQ::SET, "w:sync:app:state");
+
+ auto *pList = iq.addChild("sync");
+ for (auto &it : task) {
+ auto *pCollection = m_arCollections.find(it);
+ if (pCollection == nullptr)
+ m_arCollections.insert(pCollection = new WACollection(it->szName, 0));
+
+ if (pCollection->version < it->version) {
+ auto *pNode = pList->addChild("collection");
+ *pNode << CHAR_PARAM("name", it->szName) << INT_PARAM("version", pCollection->version)
+ << CHAR_PARAM("return_snapshot", (!pCollection->version) ? "true" : "false");
+ }
+ }
+
+ if (pList->getFirstChild() != nullptr)
+ WSSendNode(iq, &WhatsAppProto::OnIqServerSync);
+}
+
+void WhatsAppProto::OnIqServerSync(const WANode &node)
+{
+ for (auto &coll : node.getChild("sync")->getChildren()) {
+ if (coll->title != "collection")
+ continue;
+
+ auto *pszName = coll->getAttr("name");
+
+ auto *pCollection = FindCollection(pszName);
+ if (pCollection == nullptr) {
+ pCollection = new WACollection(pszName, 0);
+ m_arCollections.insert(pCollection);
+ }
+
+ int dwVersion = 0;
+
+ CMStringW wszSnapshotPath(GetTmpFileName("collection", pszName));
+ if (auto *pSnapshot = coll->getChild("snapshot")) {
+ proto::ExternalBlobReference body;
+ body << pSnapshot->content;
+ if (!body.has_directpath() || !body.has_mediakey()) {
+ debugLogA("Invalid snapshot data, skipping");
+ continue;
+ }
+
+ MBinBuffer buf = DownloadEncryptedFile(directPath2url(body.directpath().c_str()), body.mediakey(), "App State");
+ if (!buf.data()) {
+ debugLogA("Invalid downloaded snapshot data, skipping");
+ continue;
+ }
+
+ proto::SyncdSnapshot snapshot;
+ snapshot << buf;
+
+ dwVersion = snapshot.version().version();
+ if (dwVersion > pCollection->version) {
+ auto &hash = snapshot.mac();
+ pCollection->hash.assign(hash.c_str(), hash.size());
+
+ for (auto &it : snapshot.records())
+ pCollection->parseRecord(it, true);
+ }
+ }
+
+ if (auto *pPatchList = coll->getChild("patches")) {
+ for (auto &it : pPatchList->getChildren()) {
+ proto::SyncdPatch patch;
+ patch << it->content;
+
+ dwVersion = patch.version().version();
+ if (dwVersion > pCollection->version)
+ for (auto &jt : patch.mutations())
+ pCollection->parseRecord(jt.record(), jt.operation() == proto::SyncdMutation_SyncdOperation::SyncdMutation_SyncdOperation_SET);
+ }
+ }
+
+ CMStringA szSetting(FORMAT, "Collection_%s", pszName);
+ // setDword(szSetting, dwVersion);
+
+ JSONNode jsonRoot, jsonMap;
+ for (auto &it : pCollection->indexValueMap)
+ jsonMap << CHAR_PARAM(ptrA(mir_base64_encode(it.first.c_str(), it.first.size())), ptrA(mir_base64_encode(it.second.c_str(), it.second.size())));
+ jsonRoot << INT_PARAM("version", dwVersion) << JSON_PARAM("indexValueMap", jsonMap);
+
+ // string2file(jsonRoot.write(), GetTmpFileName("collection", CMStringA(pszName) + ".json"));
+ }
+}
+
+void WACollection::parseRecord(const ::proto::SyncdRecord &rec, bool bSet)
+{
+ // auto &id = rec.keyid().id();
+ auto &index = rec.index().blob();
+ auto &value = rec.value().blob();
+
+ if (bSet) {
+ indexValueMap[index] = value.substr(0, value.size() - 32);
+ }
+ else indexValueMap.erase(index);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::OnSuccess(const WANode &)
+{
+ OnLoggedIn();
+
+ WSSendNode(WANodeIq(IQ::SET, "passive") << XCHILD("active"), &WhatsAppProto::OnIqDoNothing);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
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("message", 0, 0, 0, &WhatsAppProto::OnReceiveMessage));
+ 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));
+
+ m_arPersistent.insert(new WAPersistentHandler("ib", 0, 0, 0, &WhatsAppProto::OnReceiveInfo));
+ m_arPersistent.insert(new WAPersistentHandler("message", 0, 0, 0, &WhatsAppProto::OnReceiveMessage));
m_arPersistent.insert(new WAPersistentHandler("stream:error", 0, 0, 0, &WhatsAppProto::OnStreamError));
m_arPersistent.insert(new WAPersistentHandler("success", 0, 0, 0, &WhatsAppProto::OnSuccess));