summaryrefslogtreecommitdiff
path: root/protocols/WhatsAppWeb/src
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2022-10-02 21:48:11 +0300
committerGeorge Hazan <ghazan@miranda.im>2022-10-02 21:48:11 +0300
commit0a59ec1d5a3e02cd8bc04933ae06c038d05c6a34 (patch)
treedec44acb6fba8fb34d8ab7377c2ee226c0ed80ed /protocols/WhatsAppWeb/src
parent0f65b85e68f7ad9068b0e20f0cade4c4c41c454e (diff)
WhatsApp: prekeys upload
Diffstat (limited to 'protocols/WhatsAppWeb/src')
-rw-r--r--protocols/WhatsAppWeb/src/iq.cpp47
-rw-r--r--protocols/WhatsAppWeb/src/noise.cpp25
-rw-r--r--protocols/WhatsAppWeb/src/proto.h1
-rw-r--r--protocols/WhatsAppWeb/src/server.cpp12
-rw-r--r--protocols/WhatsAppWeb/src/utils.h3
-rw-r--r--protocols/WhatsAppWeb/src/wanode.cpp17
6 files changed, 86 insertions, 19 deletions
diff --git a/protocols/WhatsAppWeb/src/iq.cpp b/protocols/WhatsAppWeb/src/iq.cpp
index 287fbe54e5..287257594a 100644
--- a/protocols/WhatsAppWeb/src/iq.cpp
+++ b/protocols/WhatsAppWeb/src/iq.cpp
@@ -7,6 +7,53 @@ Copyright © 2019-22 George Hazan
#include "stdafx.h"
+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;
+ }
+
+ WANode iq("iq");
+ iq << CHAR_PARAM("xmlns", "encrypt") << CHAR_PARAM("type", "set") << CHAR_PARAM("to", S_WHATSAPP_NET) << CHAR_PARAM("id", generateMessageId());
+
+ auto regId = encodeBigEndian(getDword(DBKEY_REG_ID));
+ iq.addChild("registration")->content.append(regId.c_str(), regId.size());
+
+ iq.addChild("type")->content.append(KEY_BUNDLE_TYPE, 1);
+ iq.addChild("identity")->content.append(m_noise->signedIdentity.pub);
+
+ auto *n = iq.addChild("list");
+ for (auto &keyId : ids) {
+ auto *nKey = n->addChild("key");
+
+ 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)));
+ }
+
+ auto *skey = n->addChild("skey");
+
+ auto encId = encodeBigEndian(m_noise->preKey.keyid, 3);
+ skey->addChild("id")->content.append(encId.c_str(), encId.size());
+ skey->addChild("value")->content.append(m_noise->preKey.pub);
+ skey->addChild("signature")->content.append(m_noise->preKey.signature);
+
+ WSSendNode(iq);
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
void WhatsAppProto::OnStreamError(const WANode &node)
diff --git a/protocols/WhatsAppWeb/src/noise.cpp b/protocols/WhatsAppWeb/src/noise.cpp
index 30449aa09d..ecc7921b2d 100644
--- a/protocols/WhatsAppWeb/src/noise.cpp
+++ b/protocols/WhatsAppWeb/src/noise.cpp
@@ -43,9 +43,6 @@ void WANoise::init()
{
// no data? generate them
if (ppro->getDword(DBKEY_REG_ID, 0xFFFF) == 0xFFFF) {
- ppro->setDword(DBKEY_PREKEY_NEXT_ID, 1);
- ppro->setDword(DBKEY_PREKEY_UPLOAD_ID, 1);
-
// generate registration id
uint32_t regId;
Utils_GetRandom(&regId, sizeof(regId));
@@ -66,21 +63,25 @@ void WANoise::init()
auto *pPrivKey = ec_key_pair_get_private(pKeys);
db_set_blob(0, ppro->m_szModuleName, DBKEY_NOISE_PRIV, pPrivKey->data, sizeof(pPrivKey->data));
ec_key_pair_destroy(pKeys);
+ }
+
+ if (ppro->getDword(DBKEY_PREKEY_KEYID, 0xFFFF) == 0xFFFF) {
+ // generate pre keys
+ const unsigned int signed_pre_key_id = 1;
+ ppro->setDword(DBKEY_PREKEY_KEYID, 1);
+ ppro->setDword(DBKEY_PREKEY_NEXT_ID, 1);
+ ppro->setDword(DBKEY_PREKEY_UPLOAD_ID, 1);
// generate signed identity keys (private & public)
ratchet_identity_key_pair *keyPair;
signal_protocol_key_helper_generate_identity_key_pair(&keyPair, g_plugin.pCtx);
- pPubKey = ratchet_identity_key_pair_get_public(keyPair);
+ auto *pPubKey = ratchet_identity_key_pair_get_public(keyPair);
db_set_blob(0, ppro->m_szModuleName, DBKEY_SIGNED_IDENTITY_PUB, pPubKey->data, sizeof(pPubKey->data));
- pPrivKey = ratchet_identity_key_pair_get_private(keyPair);
+ auto *pPrivKey = ratchet_identity_key_pair_get_private(keyPair);
db_set_blob(0, ppro->m_szModuleName, DBKEY_SIGNED_IDENTITY_PRIV, pPrivKey->data, sizeof(pPrivKey->data));
- // generate pre keys
- const unsigned int signed_pre_key_id = 1;
- ppro->setDword(DBKEY_PREKEY_KEYID, 1);
-
session_signed_pre_key *signed_pre_key;
signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, keyPair, signed_pre_key_id, time(0), g_plugin.pCtx);
SIGNAL_UNREF(keyPair);
@@ -88,7 +89,7 @@ void WANoise::init()
signal_buffer *serialized_signed_pre_key;
session_signed_pre_key_serialize(&serialized_signed_pre_key, signed_pre_key);
- pKeys = session_signed_pre_key_get_key_pair(signed_pre_key);
+ ec_key_pair *pKeys = session_signed_pre_key_get_key_pair(signed_pre_key);
pPubKey = ec_key_pair_get_public(pKeys);
db_set_blob(0, ppro->m_szModuleName, DBKEY_PREKEY_PUB, pPubKey->data, sizeof(pPubKey->data));
@@ -100,7 +101,7 @@ void WANoise::init()
// generate and save pre keys set
CMStringA szSetting;
signal_protocol_key_helper_pre_key_list_node *keys_root;
- signal_protocol_key_helper_generate_pre_keys(&keys_root, 0, 20, g_plugin.pCtx);
+ signal_protocol_key_helper_generate_pre_keys(&keys_root, 1, 20, g_plugin.pCtx);
for (auto *it = keys_root; it; it = signal_protocol_key_helper_key_list_next(it)) {
session_pre_key *pre_key = signal_protocol_key_helper_key_list_element(it);
uint32_t pre_key_id = session_pre_key_get_id(pre_key);
@@ -115,7 +116,7 @@ void WANoise::init()
ec_key_pair *pre_key_pair = session_pre_key_get_key_pair(pre_key);
pPubKey = ec_key_pair_get_public(pre_key_pair);
szSetting.Format("PreKey%dPublic", pre_key_id);
- db_set_blob(0, ppro->m_szModuleName, szSetting, pPrivKey->data, sizeof(pPrivKey->data));
+ db_set_blob(0, ppro->m_szModuleName, szSetting, pPubKey->data, sizeof(pPubKey->data));
}
signal_protocol_key_helper_key_list_free(keys_root);
}
diff --git a/protocols/WhatsAppWeb/src/proto.h b/protocols/WhatsAppWeb/src/proto.h
index 72ac5bede9..ff1d4fe18e 100644
--- a/protocols/WhatsAppWeb/src/proto.h
+++ b/protocols/WhatsAppWeb/src/proto.h
@@ -205,6 +205,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
void OnProcessHandshake(const void *pData, int cbLen);
void InitPersistentHandlers();
+ void OnIqCountPrekeys(const WANode &node);
void OnIqPairDevice(const WANode &node);
void OnIqPairSuccess(const WANode &node);
void OnIqResult(const WANode &node);
diff --git a/protocols/WhatsAppWeb/src/server.cpp b/protocols/WhatsAppWeb/src/server.cpp
index 7cbdba3a20..cf53d72896 100644
--- a/protocols/WhatsAppWeb/src/server.cpp
+++ b/protocols/WhatsAppWeb/src/server.cpp
@@ -80,9 +80,9 @@ void WhatsAppProto::ServerThreadWorker()
if (!WSReadPacket(hdr, netbuf))
break;
- // debugLogA("Got packet: buffer = %d, opcode = %d, headerSize = %d, payloadSize = %d, final = %d, masked = %d",
- // netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked);
- // Netlib_Dump(m_hServerConn, netbuf.data(), netbuf.length(), false, 0);
+ debugLogA("Got packet: buffer = %d, opcode = %d, headerSize = %d, payloadSize = %d, final = %d, masked = %d",
+ netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked);
+ Netlib_Dump(m_hServerConn, netbuf.data(), netbuf.length(), false, 0);
m_lastRecvTime = time(0);
@@ -235,6 +235,12 @@ void WhatsAppProto::OnLoggedIn()
m_iStatus = m_iDesiredStatus;
m_impl.m_keepAlive.Start(1000);
+
+ // retrieve loaded prekeys
+ WANode iq("iq");
+ iq << CHAR_PARAM("id", generateMessageId()) << CHAR_PARAM("xmlns", "encrypt") << CHAR_PARAM("type", "get") << CHAR_PARAM("to", S_WHATSAPP_NET);
+ iq.addChild("count");
+ WSSendNode(iq, &WhatsAppProto::OnIqCountPrekeys);
}
void WhatsAppProto::OnLoggedOut(void)
diff --git a/protocols/WhatsAppWeb/src/utils.h b/protocols/WhatsAppWeb/src/utils.h
index e517301b86..292a8e7011 100644
--- a/protocols/WhatsAppWeb/src/utils.h
+++ b/protocols/WhatsAppWeb/src/utils.h
@@ -39,7 +39,8 @@ public:
void addAttr(const char *pszName, const char *pszValue);
void addAttr(const char *pszName, int iValue);
- const char* getAttr(const char *pszName) const;
+ int getAttrInt(const char *pszName) const;
+ const char *getAttr(const char *pszName) const;
CMStringA getBody() const;
diff --git a/protocols/WhatsAppWeb/src/wanode.cpp b/protocols/WhatsAppWeb/src/wanode.cpp
index f3d4053e7d..518c29d9dd 100644
--- a/protocols/WhatsAppWeb/src/wanode.cpp
+++ b/protocols/WhatsAppWeb/src/wanode.cpp
@@ -43,13 +43,24 @@ WANode::~WANode()
const char *WANode::getAttr(const char *pszName) const
{
- for (auto &p : attrs)
- if (p->name == pszName)
- return p->value.c_str();
+ if (this != nullptr)
+ for (auto &p : attrs)
+ if (p->name == pszName)
+ return p->value.c_str();
return nullptr;
}
+int WANode::getAttrInt(const char *pszName) const
+{
+ if (this != nullptr)
+ for (auto &p : attrs)
+ if (p->name == pszName)
+ return atoi(p->value.c_str());
+
+ return 0;
+}
+
void WANode::addAttr(const char *pszName, const char *pszValue)
{
attrs.insert(new Attr(pszName, pszValue));