summaryrefslogtreecommitdiff
path: root/protocols/WhatsAppWeb/src
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-10-15 13:06:52 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-10-15 13:06:52 +0300
commit71c1ad117340f089d4820bf7c7bddce20a5e113a (patch)
treefb53900b4db14e958d3445c8ebd634073835d6f6 /protocols/WhatsAppWeb/src
parentfb3fad1e6519b029cd06e7c7113fc948aaef6770 (diff)
WhatsAppWeb: session restoration code
Diffstat (limited to 'protocols/WhatsAppWeb/src')
-rw-r--r--protocols/WhatsAppWeb/src/proto.h6
-rw-r--r--protocols/WhatsAppWeb/src/server.cpp61
-rw-r--r--protocols/WhatsAppWeb/src/stdafx.h1
3 files changed, 68 insertions, 0 deletions
diff --git a/protocols/WhatsAppWeb/src/proto.h b/protocols/WhatsAppWeb/src/proto.h
index 06f8c7609f..7f8cff994a 100644
--- a/protocols/WhatsAppWeb/src/proto.h
+++ b/protocols/WhatsAppWeb/src/proto.h
@@ -40,6 +40,8 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
CMStringA m_szJid, m_szClientId, m_szClientToken;
CMStringW m_tszAvatarFolder;
+ MBinBuffer mac_key, enc_key;
+
EVP_PKEY *m_pKeys; // private & public keys
bool ShowQrCode(const CMStringA &ref);
@@ -62,11 +64,15 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
void StartSession(void);
void ShutdownSession(void);
+ void ProcessChallenge(const CMStringA &szChallenge);
+
/// Request handlers ///////////////////////////////////////////////////////////////////
+ void OnRestoreSession(const JSONNode &node);
void OnStartSession(const JSONNode &node);
void ProcessPacket(const JSONNode &node);
+ void ProcessCmd(const JSONNode &node);
void ProcessConn(const JSONNode &node);
/// Avatars ////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/WhatsAppWeb/src/server.cpp b/protocols/WhatsAppWeb/src/server.cpp
index 3a682e00fa..be9fc55200 100644
--- a/protocols/WhatsAppWeb/src/server.cpp
+++ b/protocols/WhatsAppWeb/src/server.cpp
@@ -199,10 +199,57 @@ void WhatsAppProto::OnLoggedOut(void)
setAllContactStatuses(ID_STATUS_OFFLINE, false);
}
+//////////////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::ProcessChallenge(const CMStringA &szChallenge)
+{
+ if (mac_key.isEmpty()) {
+ ShutdownSession();
+ return;
+ }
+
+ size_t cbLen;
+ void *pChallenge = mir_base64_decode(szChallenge, &cbLen);
+
+ BYTE digest[32];
+ unsigned cbResult = sizeof(digest);
+ HMAC(EVP_sha256(), mac_key.data(), mac_key.length(), (BYTE*)pChallenge, cbLen, digest, &cbResult);
+
+ ptrA szServer(getStringA(DBKEY_SERVER_TOKEN));
+ CMStringA payload(FORMAT, "[\"admin\",\"challenge\",\"%s\",\"%s\",\"%s\"]",
+ ptrA(mir_base64_encode(digest, cbResult)).get(), szServer.get(), m_szClientId.c_str());
+ WSSend(payload);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
void WhatsAppProto::RestoreSession()
{
+ ptrA szClient(getStringA(DBKEY_CLIENT_TOKEN)), szServer(getStringA(DBKEY_SERVER_TOKEN));
+ if (szClient == nullptr || szServer == nullptr) {
+ ShutdownSession();
+ return;
+ }
+
+ CMStringA payload(FORMAT, "[\"admin\",\"login\",\"%s\",\"%s\",\"%s\",\"takeover\"]", szClient.get(), szServer.get(), m_szClientId.c_str());
+ WSSend(payload, &WhatsAppProto::OnRestoreSession);
+}
+
+void WhatsAppProto::OnRestoreSession(const JSONNode &root)
+{
+ int status = root["status"].as_int();
+ if (status != 200) {
+ debugLogA("Attmept to restore session failed with error %d", status);
+ delSetting(DBKEY_CLIENT_TOKEN);
+ delSetting(DBKEY_SERVER_TOKEN);
+
+ ShutdownSession();
+ return;
+ }
}
+//////////////////////////////////////////////////////////////////////////////////////
+
void WhatsAppProto::ShutdownSession()
{
if (m_bTerminated)
@@ -217,6 +264,8 @@ void WhatsAppProto::ShutdownSession()
OnLoggedOut();
}
+//////////////////////////////////////////////////////////////////////////////////////
+
void WhatsAppProto::StartSession()
{
CMStringA payload(FORMAT, "[\"admin\",\"init\",[0,3,4940],[\"Windows\",\"Chrome\",\"10\"],\"%s\",true]", m_szClientId.c_str());
@@ -400,6 +449,18 @@ void WhatsAppProto::ProcessPacket(const JSONNode &root)
if (szType == "Conn")
ProcessConn(content);
+ else if (szType == "Cmd")
+ ProcessCmd(content);
+}
+
+void WhatsAppProto::ProcessCmd(const JSONNode &root)
+{
+ CMStringW wszType(root["type"].as_mstring());
+ if (wszType == L"challenge") {
+ CMStringA szChallenge(root["challenge"].as_mstring());
+ if (!szChallenge.IsEmpty())
+ ProcessChallenge(szChallenge);
+ }
}
void WhatsAppProto::ProcessConn(const JSONNode &root)
diff --git a/protocols/WhatsAppWeb/src/stdafx.h b/protocols/WhatsAppWeb/src/stdafx.h
index 171e384674..82f1e715c0 100644
--- a/protocols/WhatsAppWeb/src/stdafx.h
+++ b/protocols/WhatsAppWeb/src/stdafx.h
@@ -43,6 +43,7 @@ Copyright © 2019 George Hazan
#include <m_gui.h>
#include <openssl/evp.h>
+#include <openssl/hmac.h>
#include "../../libs/libqrencode/src/qrencode.h"
#include "../../libs/libsignal/src/curve.h"