From f43396cbff99cc7cc9410f12e55783ad12d1d2f7 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Mon, 17 Apr 2023 20:07:16 +0300 Subject: Jabber: - option autoloadoob removed due to offline files support; - added support for encrypted offline files --- protocols/JabberG/src/jabber_file.cpp | 64 +++++++++++++++++++++++++++------ protocols/JabberG/src/jabber_omemo.cpp | 36 ++++++++++++++++--- protocols/JabberG/src/jabber_opt.cpp | 1 - protocols/JabberG/src/jabber_proto.cpp | 1 - protocols/JabberG/src/jabber_proto.h | 1 - protocols/JabberG/src/jabber_thread.cpp | 2 +- 6 files changed, 87 insertions(+), 18 deletions(-) (limited to 'protocols/JabberG/src') diff --git a/protocols/JabberG/src/jabber_file.cpp b/protocols/JabberG/src/jabber_file.cpp index c96f6ae92c..0b2767de8d 100644 --- a/protocols/JabberG/src/jabber_file.cpp +++ b/protocols/JabberG/src/jabber_file.cpp @@ -34,9 +34,25 @@ INT_PTR __cdecl CJabberProto::OnOfflineFile(WPARAM param, LPARAM) void __cdecl CJabberProto::OfflineFileThread(OFDTHREAD *param) { DB::EventInfo dbei(param->hDbEvent); - if (dbei && !strcmp(dbei.szModule, m_szModuleName) && dbei.eventType == EVENTTYPE_FILE) { + if (m_bJabberOnline && dbei && !strcmp(dbei.szModule, m_szModuleName) && dbei.eventType == EVENTTYPE_FILE) { DB::FILE_BLOB blob(dbei); - if (blob.isOffline()) { + if (const char *url = blob.getUrl()) { + bool encrypted = false; + // OMEMO encryped file? + char protocol[7], hexkey[100], suburl[5001], newurl[5001]; + int ret = sscanf(url, "%6[^:]://%5000[^#]#%88s", protocol, suburl, hexkey); + protocol[6] = hexkey[88] = 0; + if (ret == 3 && !strcmp(protocol, "aesgcm") && strlen(hexkey) == 88) { + mir_snprintf(newurl, "https://%s", suburl); + url = newurl; + encrypted = true; + } + else if (ret != 2 || (strcmp(protocol, "https") && strcmp(protocol, "http"))) { + debugLogA("Wrong url"); + delete param; + return; + } + // initialize the netlib request NETLIBHTTPREQUEST nlhr = {}; nlhr.cbSize = sizeof(nlhr); @@ -48,16 +64,44 @@ void __cdecl CJabberProto::OfflineFileThread(OFDTHREAD *param) NLHR_PTR nlhrReply(Netlib_HttpTransaction(m_hNetlibUser, &nlhr)); if (nlhrReply && nlhrReply->resultCode == 200) { FILE *f = _wfopen(param->wszPath, L"wb"); - fwrite(nlhrReply->pData, 1, nlhrReply->dataLength, f); - fclose(f); + size_t written = 0; + if (f) { + if (encrypted) { + int payload_len = nlhrReply->dataLength - 16; + if (payload_len > 0) { + uint8_t ivkey[44]; + hex2bin(hexkey, ivkey, 44); + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL); + EVP_DecryptInit(ctx, EVP_aes_256_gcm(), ivkey + 12, ivkey); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, nlhrReply->pData + payload_len); + + int outl = 0, round_len = 0; + uint8_t *out = (uint8_t *)mir_alloc(payload_len); + EVP_DecryptUpdate(ctx, out, &outl, (uint8_t *)nlhrReply->pData, (int)payload_len); + int dec_success = EVP_DecryptFinal(ctx, out + outl, &round_len); + outl += round_len; + EVP_CIPHER_CTX_free(ctx); + if (dec_success && outl == payload_len) + if (fwrite(out, 1, payload_len, f) == payload_len) + written = payload_len; + mir_free(out); + } + } + else if (fwrite(nlhrReply->pData, 1, nlhrReply->dataLength, f) == nlhrReply->dataLength) + written = nlhrReply->dataLength; + fclose(f); + } - DBVARIANT dbv = { DBVT_DWORD }; - dbv.dVal = nlhrReply->dataLength; - db_event_setJson(param->hDbEvent, "ft", &dbv); - db_event_setJson(param->hDbEvent, "fs", &dbv); + if (written) { + DBVARIANT dbv = { DBVT_DWORD }; + dbv.dVal = nlhrReply->dataLength; + db_event_setJson(param->hDbEvent, "ft", &dbv); + db_event_setJson(param->hDbEvent, "fs", &dbv); - if (param->bOpen) - ShellExecute(nullptr, L"open", param->wszPath, nullptr, nullptr, SW_SHOWDEFAULT); + if (param->bOpen) + ShellExecuteW(nullptr, L"open", param->wszPath, nullptr, nullptr, SW_SHOWDEFAULT); + } } } } diff --git a/protocols/JabberG/src/jabber_omemo.cpp b/protocols/JabberG/src/jabber_omemo.cpp index 9666eec9e7..06ebb64647 100644 --- a/protocols/JabberG/src/jabber_omemo.cpp +++ b/protocols/JabberG/src/jabber_omemo.cpp @@ -1431,10 +1431,38 @@ bool CJabberProto::OmemoHandleMessage(const TiXmlElement *node, const char *jid, if (!msgTime || m_bFixIncorrectTimestamps && (msgTime > now || (msgTime < (time_t)JabberGetLastContactMessageTime(hContact)))) msgTime = now; - PROTORECVEVENT recv = {}; - recv.timestamp = (uint32_t)msgTime; - recv.szMessage = result.GetBuffer(); - ProtoChainRecvMsg(hContact, &recv); + char protocol[7], hexkey[89], suburl[5001]; + int ret = sscanf(result.GetBuffer(), "%6[^:]://%5000[^#]#%88s", protocol, suburl, hexkey); + protocol[6] = hexkey[88] = suburl[5000] = 0; + if (ret == 3 && !strcmp(protocol, "aesgcm") && strlen(hexkey) == 88) { + CMStringA szName; + const char *b = strrchr(suburl, '/') + 1; + while (*b != 0 && *b != '#' && *b != '?') + szName.AppendChar(*b++); + + ptrW pwszName(mir_utf8decodeW(szName.c_str())); + + JSONNode root; + root << WCHAR_PARAM("f", pwszName) << CHAR_PARAM("u", result.GetBuffer()); + + DBEVENTINFO dbei = {}; + dbei.szModule = Proto_GetBaseAccountName(hContact); + dbei.timestamp = msgTime; + dbei.eventType = EVENTTYPE_FILE; + dbei.flags = DBEF_SECURE; + + std::string text = root.write(); + dbei.cbBlob = (int)text.size() + 1; + dbei.pBlob = (uint8_t *)text.c_str(); + db_event_add(hContact, &dbei); + } + else { + PROTORECVEVENT recv = {}; + recv.timestamp = (uint32_t)msgTime; + recv.szMessage = result.GetBuffer(); + recv.flags = PREF_ENCRYPTED; + ProtoChainRecvMsg(hContact, &recv); + } return true; } diff --git a/protocols/JabberG/src/jabber_opt.cpp b/protocols/JabberG/src/jabber_opt.cpp index 180f57c74a..4df55c6998 100644 --- a/protocols/JabberG/src/jabber_opt.cpp +++ b/protocols/JabberG/src/jabber_opt.cpp @@ -717,7 +717,6 @@ public: m_options.AddOption(LPGENW("Other"), LPGENW("Show transport agents on contact list"), m_proto->m_bShowTransport); m_options.AddOption(LPGENW("Other"), LPGENW("Automatically add contact when accept authorization"), m_proto->m_bAutoAdd); m_options.AddOption(LPGENW("Other"), LPGENW("Automatically accept authorization requests"), m_proto->m_bAutoAcceptAuthorization); - m_options.AddOption(LPGENW("Other"), LPGENW("Automatically download files passed via HTTP File Upload"), m_proto->m_bAutoLoadOOB); m_options.AddOption(LPGENW("Other"), LPGENW("Fix incorrect timestamps in incoming messages"), m_proto->m_bFixIncorrectTimestamps); m_options.AddOption(LPGENW("Other"), LPGENW("Enable XMPP link processing (requires AssocMgr)"), m_proto->m_bProcessXMPPLinks); m_options.AddOption(LPGENW("Other"), LPGENW("Embrace picture URLs with [img]"), m_proto->m_bEmbraceUrls); diff --git a/protocols/JabberG/src/jabber_proto.cpp b/protocols/JabberG/src/jabber_proto.cpp index acc141e114..6ffe603acb 100644 --- a/protocols/JabberG/src/jabber_proto.cpp +++ b/protocols/JabberG/src/jabber_proto.cpp @@ -86,7 +86,6 @@ CJabberProto::CJabberProto(const char *aProtoName, const wchar_t *aUserName) : m_bAutoJoinBookmarks(this, "AutoJoinBookmarks", true), m_bAutoJoinConferences(this, "AutoJoinConferences", false), m_bAutoJoinHidden(this, "AutoJoinHidden", true), - m_bAutoLoadOOB(this, "AutoLoadOOB", true), m_bAutosaveNotes(this, "AutosaveNotes", false), m_bBsDirect(this, "BsDirect", true), m_bBsDirectManual(this, "BsDirectManual", false), diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h index 019ea10d35..52e8b98c91 100644 --- a/protocols/JabberG/src/jabber_proto.h +++ b/protocols/JabberG/src/jabber_proto.h @@ -195,7 +195,6 @@ struct CJabberProto : public PROTO, public IJabberInterface CMOption m_bAutoJoinBookmarks; CMOption m_bAutoJoinConferences; CMOption m_bAutoJoinHidden; - CMOption m_bAutoLoadOOB; CMOption m_bAutosaveNotes; CMOption m_bBsDirect; CMOption m_bBsDirectManual; diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp index 1475657ecb..5e4fae32b9 100644 --- a/protocols/JabberG/src/jabber_thread.cpp +++ b/protocols/JabberG/src/jabber_thread.cpp @@ -1324,7 +1324,7 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) szMessage += tempstring; } } - else if (!mir_strcmp(pszXmlns, JABBER_FEAT_OOB2) && m_bAutoLoadOOB) { + else if (!mir_strcmp(pszXmlns, JABBER_FEAT_OOB2)) { if (auto *url = XmlGetChildText(xNode, "url")) { // create incoming file transfer instead of writing message CMStringA szName; -- cgit v1.2.3