From 718e96a95c5596fa6c7e21984cf8bdfb6d528e60 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Wed, 26 Jun 2019 23:07:24 +0300 Subject: MQTT: proper MQTT payload preparation --- protocols/Facebook/facebook.vcxproj | 3 + protocols/Facebook/src/http.cpp | 3 + protocols/Facebook/src/mqtt.cpp | 142 ++++++++++++++++++++++++++++++------ protocols/Facebook/src/mqtt.h | 39 +++++++++- protocols/Facebook/src/proto.cpp | 2 + protocols/Facebook/src/proto.h | 5 ++ protocols/Facebook/src/server.cpp | 36 ++++++++- protocols/Facebook/src/stdafx.h | 2 + 8 files changed, 202 insertions(+), 30 deletions(-) (limited to 'protocols/Facebook') diff --git a/protocols/Facebook/facebook.vcxproj b/protocols/Facebook/facebook.vcxproj index 9bf2597eb3..25c2fbe25a 100644 --- a/protocols/Facebook/facebook.vcxproj +++ b/protocols/Facebook/facebook.vcxproj @@ -29,5 +29,8 @@ {f6a9340e-b8d9-4c75-be30-47dc66d0abc7} + + {e2a369cd-eda3-414f-8ad0-e732cd7ee68c} + \ No newline at end of file diff --git a/protocols/Facebook/src/http.cpp b/protocols/Facebook/src/http.cpp index aa2d4a5c5e..88a73c4006 100644 --- a/protocols/Facebook/src/http.cpp +++ b/protocols/Facebook/src/http.cpp @@ -107,6 +107,9 @@ AsyncHttpRequest* FacebookProto::CreateRequest(const char *szName, const char *s szLocale = "en"; pReq << CHAR_PARAM("locale", szLocale); + if (!m_szAuthToken.IsEmpty()) + pReq->AddHeader("Authorization", "OAuth " + m_szAuthToken); + pReq->AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); unsigned int id; diff --git a/protocols/Facebook/src/mqtt.cpp b/protocols/Facebook/src/mqtt.cpp index ba81cbad32..5e3008def8 100644 --- a/protocols/Facebook/src/mqtt.cpp +++ b/protocols/Facebook/src/mqtt.cpp @@ -59,14 +59,14 @@ FbThrift& FbThrift::operator<<(uint8_t value) FbThrift& FbThrift::operator<<(const char *str) { size_t len = mir_strlen(str); - writeInt32((int)len); + writeIntV(len); m_buf.append((void*)str, len); return *this; } void FbThrift::writeBool(bool bValue) { - uint8_t b = (bValue) ? 1 : 2; + uint8_t b = (bValue) ? 0x11 : 0x12; m_buf.append(&b, 1); } @@ -75,11 +75,10 @@ void FbThrift::writeBuf(const void *pData, size_t cbLen) m_buf.append((void*)pData, cbLen); } -void FbThrift::writeField(int iType, int id) +void FbThrift::writeField(int iType) { - uint8_t type = encodeType(iType); + uint8_t type = encodeType(iType) + 0x10; m_buf.append(&type, 1); - writeInt64(id); } void FbThrift::writeField(int iType, int id, int lastid) @@ -96,17 +95,33 @@ void FbThrift::writeField(int iType, int id, int lastid) } } -void FbThrift::writeInt32(__int32 value) +void FbThrift::writeList(int iType, int size) +{ + uint8_t type = encodeType(iType); + if (size > 14) { + writeIntV(size); + *this << (type | 0xF0); + } + else *this << (type | (size << 4)); +} + +void FbThrift::writeInt16(uint16_t value) +{ + value = htons(value); + m_buf.append(&value, sizeof(value)); +} + +void FbThrift::writeInt32(int32_t value) { writeIntV((value << 1) ^ (value >> 31)); } -void FbThrift::writeInt64(__int64 value) +void FbThrift::writeInt64(int64_t value) { writeIntV((value << 1) ^ (value >> 63)); } -void FbThrift::writeIntV(__int64 value) +void FbThrift::writeIntV(uint64_t value) { bool bLast; do { @@ -120,50 +135,129 @@ void FbThrift::writeIntV(__int64 value) } while (!bLast); } +MqttMessage::MqttMessage(FbMqttMessageType type, uint8_t flags, size_t payloadSize) +{ + uint8_t byte = ((type & 0x0F) << 4) | (flags & 0x0F); + *this << byte; + + writeIntV(payloadSize); +} + +void MqttMessage::writeStr(const char *str) +{ + size_t len = mir_strlen(str); + writeInt16((int)len); + writeBuf(str, len); +} + ///////////////////////////////////////////////////////////////////////////////////////// // MQTT functions +bool FacebookProto::MqttConnect() +{ + NETLIBOPENCONNECTION nloc = {}; + nloc.cbSize = sizeof(nloc); + nloc.szHost = "mqtt.facebook.com"; + nloc.wPort = 443; + m_mqttConn = Netlib_OpenConnection(m_hNetlibUser, &nloc); + if (m_mqttConn == nullptr) { + debugLogA("connection failed, exiting"); + return false; + } + + memset(&zStreamIn, 0, sizeof(zStreamOut)); + memset(&zStreamOut, 0, sizeof(zStreamOut)); + + if (deflateInit(&zStreamOut, Z_BEST_COMPRESSION) == Z_OK) + if (inflateInit(&zStreamIn) == Z_OK) + m_zlibAvailable = true; + + return true; +} + void FacebookProto::MqttOpen() { + Utils_GetRandom(&m_iMqttId, sizeof(m_iMqttId)); + FbThrift thrift; - thrift.writeField(FB_THRIFT_TYPE_STRING, 1); // Client identifier + thrift.writeField(FB_THRIFT_TYPE_STRING); // Client identifier thrift << m_szClientID; thrift.writeField(FB_THRIFT_TYPE_STRUCT, 4, 1); - thrift.writeField(FB_THRIFT_TYPE_I64, 1); // User identifier + thrift.writeField(FB_THRIFT_TYPE_I64); // User identifier thrift.writeInt64(m_uid); - thrift.writeField(FB_THRIFT_TYPE_STRING, 2); // User agent + thrift.writeField(FB_THRIFT_TYPE_STRING); // User agent thrift << NETLIB_USER_AGENT; - thrift.writeField(FB_THRIFT_TYPE_I64, 3); + thrift.writeField(FB_THRIFT_TYPE_I64); thrift.writeInt64(23); - thrift.writeField(FB_THRIFT_TYPE_I64, 4); + thrift.writeField(FB_THRIFT_TYPE_I64); thrift.writeInt64(26); - thrift.writeField(FB_THRIFT_TYPE_I32, 5); + thrift.writeField(FB_THRIFT_TYPE_I32); thrift.writeInt32(1); - thrift.writeField(FB_THRIFT_TYPE_BOOL, 6); + thrift.writeBool(true); - thrift.writeField(FB_THRIFT_TYPE_BOOL, 7); // visibility - thrift.writeBool(m_iStatus != ID_STATUS_INVISIBLE); + thrift.writeBool(m_iStatus != ID_STATUS_INVISIBLE); // visibility - thrift.writeField(FB_THRIFT_TYPE_STRING, 8); // device id + thrift.writeField(FB_THRIFT_TYPE_STRING); // device id thrift << m_szDeviceID; - thrift.writeField(FB_THRIFT_TYPE_BOOL, 9); thrift.writeBool(true); - thrift.writeField(FB_THRIFT_TYPE_I32, 10); + thrift.writeField(FB_THRIFT_TYPE_I32); thrift.writeInt32(1); - thrift.writeField(FB_THRIFT_TYPE_I32, 11); + thrift.writeField(FB_THRIFT_TYPE_I32); thrift.writeInt32(0); - thrift.writeField(FB_THRIFT_TYPE_I64, 12); + thrift.writeField(FB_THRIFT_TYPE_I64); thrift.writeInt64(m_iMqttId); thrift.writeField(FB_THRIFT_TYPE_LIST, 14, 12); - thrift.writeField(FB_THRIFT_TYPE_I32, 0); + thrift.writeList(FB_THRIFT_TYPE_I32, 0); thrift << (BYTE)0; - thrift.writeField(FB_THRIFT_TYPE_LIST, 15); + thrift.writeField(FB_THRIFT_TYPE_STRING); thrift << m_szAuthToken << (BYTE)0; + + FILE *out = fopen("C:\\qq.out", "wb"); + fwrite(thrift.data(), 1, thrift.size(), out); + fclose(out); + + BYTE *pData; + size_t dataSize; + if (m_zlibAvailable) { + dataSize = thrift.size() + 100; + pData = (BYTE *)mir_alloc(dataSize); + + zStreamOut.avail_in = (unsigned)thrift.size(); + zStreamOut.next_in = (BYTE *)thrift.data(); + zStreamOut.avail_out = (unsigned)dataSize; + zStreamOut.next_out = (BYTE *)pData; + + switch (deflate(&zStreamOut, Z_SYNC_FLUSH)) { + case Z_OK: debugLogA("Deflate: Z_OK"); break; + case Z_BUF_ERROR: debugLogA("Deflate: Z_BUF_ERROR"); break; + case Z_DATA_ERROR: debugLogA("Deflate: Z_DATA_ERROR"); break; + case Z_MEM_ERROR: debugLogA("Deflate: Z_MEM_ERROR"); break; + } + + dataSize = dataSize - zStreamOut.avail_out; + } + else { + dataSize = thrift.size(); + pData = (BYTE *)thrift.data(); + } + + uint8_t protocolVersion = 3; + uint8_t flags = FB_MQTT_CONNECT_FLAG_USER | FB_MQTT_CONNECT_FLAG_PASS | FB_MQTT_CONNECT_FLAG_CLR | FB_MQTT_CONNECT_FLAG_QOS1; + MqttMessage payload(FB_MQTT_MESSAGE_TYPE_CONNECT, 0, dataSize - 3); + payload.writeStr("MQTToT"); + payload << protocolVersion << flags; + payload.writeInt16(60); // timeout + payload.writeBuf(pData, dataSize); + + if (pData != thrift.data()) + mir_free(pData); + + Netlib_Send(m_mqttConn, (char*)payload.data(), (int)payload.size()); } diff --git a/protocols/Facebook/src/mqtt.h b/protocols/Facebook/src/mqtt.h index 5b8147e5f2..55c071d0e3 100644 --- a/protocols/Facebook/src/mqtt.h +++ b/protocols/Facebook/src/mqtt.h @@ -34,21 +34,52 @@ along with this program. If not, see . #define FB_THRIFT_TYPE_SET 14 #define FB_THRIFT_TYPE_LIST 15 +enum FbMqttMessageType +{ + FB_MQTT_MESSAGE_TYPE_CONNECT = 1, + FB_MQTT_MESSAGE_TYPE_CONNACK = 2, + FB_MQTT_MESSAGE_TYPE_PUBLISH = 3, + FB_MQTT_MESSAGE_TYPE_PUBACK = 4, + FB_MQTT_MESSAGE_TYPE_PUBREC = 5, + FB_MQTT_MESSAGE_TYPE_PUBREL = 6, + FB_MQTT_MESSAGE_TYPE_PUBCOMP = 7, + FB_MQTT_MESSAGE_TYPE_SUBSCRIBE = 8, + FB_MQTT_MESSAGE_TYPE_SUBACK = 9, + FB_MQTT_MESSAGE_TYPE_UNSUBSCRIBE = 10, + FB_MQTT_MESSAGE_TYPE_UNSUBACK = 11, + FB_MQTT_MESSAGE_TYPE_PINGREQ = 12, + FB_MQTT_MESSAGE_TYPE_PINGRESP = 13, + FB_MQTT_MESSAGE_TYPE_DISCONNECT = 14 +}; + class FbThrift { MBinBuffer m_buf; public: + __inline void* data() { return m_buf.data(); } + __inline size_t size() { return m_buf.length(); } + FbThrift& operator<<(uint8_t); FbThrift& operator<<(const char *); void writeBool(bool value); void writeBuf(const void *pData, size_t cbLen); - void writeInt32(__int32 value); - void writeInt64(__int64 value); - void writeIntV(__int64 value); - void writeField(int type, int id); + void writeInt16(uint16_t value); + void writeInt32(int32_t value); + void writeInt64(int64_t value); + void writeIntV(uint64_t value); + void writeField(int type); void writeField(int type, int id, int lastid); + void writeList(int iType, int size); +}; + +class MqttMessage : public FbThrift +{ +public: + MqttMessage(FbMqttMessageType type, uint8_t flags, size_t payloadSize); + + void writeStr(const char *str); }; #define FB_MQTT_CONNECT_FLAG_CLR 0x0002 diff --git a/protocols/Facebook/src/proto.cpp b/protocols/Facebook/src/proto.cpp index a30b7c1ac1..6fe0d5acd4 100644 --- a/protocols/Facebook/src/proto.cpp +++ b/protocols/Facebook/src/proto.cpp @@ -70,6 +70,8 @@ FacebookProto::FacebookProto(const char *proto_name, const wchar_t *username) : FacebookProto::~FacebookProto() { + deflateEnd(&zStreamOut); + inflateEnd(&zStreamIn); } void FacebookProto::OnModulesLoaded() diff --git a/protocols/Facebook/src/proto.h b/protocols/Facebook/src/proto.h index aa8a9e60ab..153749776a 100644 --- a/protocols/Facebook/src/proto.h +++ b/protocols/Facebook/src/proto.h @@ -68,8 +68,12 @@ class FacebookProto : public PROTO NETLIBHTTPREQUEST* ExecuteRequest(AsyncHttpRequest *pReq); // MQTT functions + bool MqttConnect(); void MqttOpen(); + HNETLIBCONN m_mqttConn; + z_stream zStreamIn, zStreamOut; + // internal data CMStringA m_szDeviceID; // stored, GUID that identifies this miranda's account CMStringA m_szClientID; // stored, random alphanumeric string of 20 chars @@ -78,6 +82,7 @@ class FacebookProto : public PROTO bool m_invisible; bool m_bOnline; + bool m_zlibAvailable; CMStringA m_szAuthToken; // calculated diff --git a/protocols/Facebook/src/server.cpp b/protocols/Facebook/src/server.cpp index dba8178fa8..162c6f9fa6 100644 --- a/protocols/Facebook/src/server.cpp +++ b/protocols/Facebook/src/server.cpp @@ -36,8 +36,7 @@ void FacebookProto::ServerThread(void *) pReq->flags = NLHRF_HTTP11 | NLHRF_REDIRECT; pReq->m_szUrl = "https://www.facebook.com/v3.3/dialog/oauth?client_id=478386432928815&redirect_uri=https://oauth.miranda-ng.org/facebook.php&state=qq"; - JsonReply reply(ExecuteRequest(pReq)); - if (reply.error()) { + if (JsonReply(ExecuteRequest(pReq)).error()) { FAIL: ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_FAILED, (HANDLE)m_iStatus, m_iDesiredStatus); @@ -46,4 +45,37 @@ FAIL: return; } } + + auto *pReq = CreateRequest("FetchContactsFullQuery", "get"); + pReq->m_szUrl = "https://graph.facebook.com/me/friends"; + pReq->CalcSig(); + + JsonReply reply(ExecuteRequest(pReq)); + if (reply.error()) + goto FAIL; + + if (!MqttConnect()) + goto FAIL; + + MqttOpen(); + + int bufSize = 2048; + char *buf = (char*)mir_alloc(bufSize); + + while (!Miranda_IsTerminated()) { + int ret = Netlib_Recv(m_mqttConn, buf, bufSize); + if (ret == SOCKET_ERROR) { + debugLogA("Netlib_Recv() failed, error=%d", WSAGetLastError()); + break; + } + if (ret == 0) { + debugLogA("Connection closed gracefully"); + break; + } + } + + debugLogA("exiting ServerThread"); + int oldStatus = m_iStatus; + m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); } diff --git a/protocols/Facebook/src/stdafx.h b/protocols/Facebook/src/stdafx.h index dca99fc578..36af3e8128 100644 --- a/protocols/Facebook/src/stdafx.h +++ b/protocols/Facebook/src/stdafx.h @@ -50,6 +50,8 @@ along with this program. If not, see . #include #include +#include "../../libs/zlib/src/zlib.h" + #include "db.h" #include "mqtt.h" #include "proto.h" -- cgit v1.2.3