Split error messages from event decryption
This commit is contained in:
parent
dbaddb0165
commit
1f9215a5be
47
src/Olm.cpp
47
src/Olm.cpp
@ -3,6 +3,7 @@
|
||||
#include "Olm.h"
|
||||
|
||||
#include "Cache.h"
|
||||
#include "Cache_p.h"
|
||||
#include "Logging.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "Utils.h"
|
||||
@ -551,4 +552,50 @@ send_megolm_key_to_device(const std::string &user_id,
|
||||
});
|
||||
}
|
||||
|
||||
DecryptionResult
|
||||
decryptEvent(const MegolmSessionIndex &index,
|
||||
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &event)
|
||||
{
|
||||
try {
|
||||
if (!cache::client()->inboundMegolmSessionExists(index)) {
|
||||
return {DecryptionErrorCode::MissingSession, std::nullopt, std::nullopt};
|
||||
}
|
||||
} catch (const lmdb::error &e) {
|
||||
return {DecryptionErrorCode::DbError, e.what(), std::nullopt};
|
||||
}
|
||||
|
||||
// TODO: Lookup index,event_id,origin_server_ts tuple for replay attack errors
|
||||
// TODO: Verify sender_key
|
||||
|
||||
std::string msg_str;
|
||||
try {
|
||||
auto session = cache::client()->getInboundMegolmSession(index);
|
||||
auto res = olm::client()->decrypt_group_message(session, event.content.ciphertext);
|
||||
msg_str = std::string((char *)res.data.data(), res.data.size());
|
||||
} catch (const lmdb::error &e) {
|
||||
return {DecryptionErrorCode::DbError, e.what(), std::nullopt};
|
||||
} catch (const mtx::crypto::olm_exception &e) {
|
||||
return {DecryptionErrorCode::DecryptionFailed, e.what(), std::nullopt};
|
||||
}
|
||||
|
||||
// Add missing fields for the event.
|
||||
json body = json::parse(msg_str);
|
||||
body["event_id"] = event.event_id;
|
||||
body["sender"] = event.sender;
|
||||
body["origin_server_ts"] = event.origin_server_ts;
|
||||
body["unsigned"] = event.unsigned_data;
|
||||
|
||||
// relations are unencrypted in content...
|
||||
if (json old_ev = event; old_ev["content"].count("m.relates_to") != 0)
|
||||
body["content"]["m.relates_to"] = old_ev["content"]["m.relates_to"];
|
||||
|
||||
mtx::events::collections::TimelineEvent te;
|
||||
try {
|
||||
mtx::events::collections::from_json(body, te);
|
||||
} catch (std::exception &e) {
|
||||
return {DecryptionErrorCode::ParsingFailed, e.what(), std::nullopt};
|
||||
}
|
||||
|
||||
return {std::nullopt, std::nullopt, std::move(te.data)};
|
||||
}
|
||||
} // namespace olm
|
||||
|
24
src/Olm.h
24
src/Olm.h
@ -7,10 +7,30 @@
|
||||
#include <mtx/events/encrypted.hpp>
|
||||
#include <mtxclient/crypto/client.hpp>
|
||||
|
||||
#include <CacheCryptoStructs.h>
|
||||
|
||||
constexpr auto OLM_ALGO = "m.olm.v1.curve25519-aes-sha2";
|
||||
|
||||
namespace olm {
|
||||
|
||||
enum class DecryptionErrorCode
|
||||
{
|
||||
MissingSession, // Session was not found, retrieve from backup or request from other devices
|
||||
// and try again
|
||||
DbError, // DB read failed
|
||||
DecryptionFailed, // libolm error
|
||||
ParsingFailed, // Failed to parse the actual event
|
||||
ReplayAttack, // Megolm index reused
|
||||
UnknownFingerprint, // Unknown device Fingerprint
|
||||
};
|
||||
|
||||
struct DecryptionResult
|
||||
{
|
||||
std::optional<DecryptionErrorCode> error;
|
||||
std::optional<std::string> error_message;
|
||||
std::optional<mtx::events::collections::TimelineEvents> event;
|
||||
};
|
||||
|
||||
struct OlmMessage
|
||||
{
|
||||
std::string sender_key;
|
||||
@ -65,6 +85,10 @@ encrypt_group_message(const std::string &room_id,
|
||||
const std::string &device_id,
|
||||
nlohmann::json body);
|
||||
|
||||
DecryptionResult
|
||||
decryptEvent(const MegolmSessionIndex &index,
|
||||
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &event);
|
||||
|
||||
void
|
||||
mark_keys_as_published();
|
||||
|
||||
|
@ -379,103 +379,96 @@ EventStore::decryptEvent(const IdIndex &idx,
|
||||
index.session_id = e.content.session_id;
|
||||
index.sender_key = e.content.sender_key;
|
||||
|
||||
mtx::events::RoomEvent<mtx::events::msg::Notice> dummy;
|
||||
dummy.origin_server_ts = e.origin_server_ts;
|
||||
dummy.event_id = e.event_id;
|
||||
dummy.sender = e.sender;
|
||||
dummy.content.body =
|
||||
tr("-- Encrypted Event (No keys found for decryption) --",
|
||||
"Placeholder, when the message was not decrypted yet or can't be decrypted.")
|
||||
.toStdString();
|
||||
|
||||
auto asCacheEntry = [&idx](mtx::events::collections::TimelineEvents &&event) {
|
||||
auto event_ptr = new mtx::events::collections::TimelineEvents(std::move(event));
|
||||
decryptedEvents_.insert(idx, event_ptr);
|
||||
return event_ptr;
|
||||
};
|
||||
|
||||
try {
|
||||
if (!cache::client()->inboundMegolmSessionExists(index)) {
|
||||
auto decryptionResult = olm::decryptEvent(index, e);
|
||||
|
||||
if (decryptionResult.error) {
|
||||
mtx::events::RoomEvent<mtx::events::msg::Notice> dummy;
|
||||
dummy.origin_server_ts = e.origin_server_ts;
|
||||
dummy.event_id = e.event_id;
|
||||
dummy.sender = e.sender;
|
||||
switch (*decryptionResult.error) {
|
||||
case olm::DecryptionErrorCode::MissingSession:
|
||||
dummy.content.body =
|
||||
tr("-- Encrypted Event (No keys found for decryption) --",
|
||||
"Placeholder, when the message was not decrypted yet or can't be "
|
||||
"decrypted.")
|
||||
.toStdString();
|
||||
nhlog::crypto()->info("Could not find inbound megolm session ({}, {}, {})",
|
||||
index.room_id,
|
||||
index.session_id,
|
||||
e.sender);
|
||||
// TODO: request megolm session_id & session_key from the sender.
|
||||
return asCacheEntry(std::move(dummy));
|
||||
}
|
||||
} catch (const lmdb::error &e) {
|
||||
nhlog::db()->critical("failed to check megolm session's existence: {}", e.what());
|
||||
dummy.content.body = tr("-- Decryption Error (failed to communicate with DB) --",
|
||||
"Placeholder, when the message can't be decrypted, because "
|
||||
"the DB access failed when trying to lookup the session.")
|
||||
.toStdString();
|
||||
return asCacheEntry(std::move(dummy));
|
||||
}
|
||||
|
||||
std::string msg_str;
|
||||
try {
|
||||
auto session = cache::client()->getInboundMegolmSession(index);
|
||||
auto res = olm::client()->decrypt_group_message(session, e.content.ciphertext);
|
||||
msg_str = std::string((char *)res.data.data(), res.data.size());
|
||||
} catch (const lmdb::error &e) {
|
||||
nhlog::db()->critical("failed to retrieve megolm session with index ({}, {}, {})",
|
||||
// TODO: Check if this actually works and look in key backup
|
||||
olm::send_key_request_for(room_id_, e);
|
||||
break;
|
||||
case olm::DecryptionErrorCode::DbError:
|
||||
nhlog::db()->critical(
|
||||
"failed to retrieve megolm session with index ({}, {}, {})",
|
||||
index.room_id,
|
||||
index.session_id,
|
||||
index.sender_key,
|
||||
e.what());
|
||||
decryptionResult.error_message.value_or(""));
|
||||
dummy.content.body =
|
||||
tr("-- Decryption Error (failed to retrieve megolm keys from db) --",
|
||||
"Placeholder, when the message can't be decrypted, because the DB access "
|
||||
"Placeholder, when the message can't be decrypted, because the DB "
|
||||
"access "
|
||||
"failed.")
|
||||
.toStdString();
|
||||
return asCacheEntry(std::move(dummy));
|
||||
} catch (const mtx::crypto::olm_exception &e) {
|
||||
nhlog::crypto()->critical("failed to decrypt message with index ({}, {}, {}): {}",
|
||||
break;
|
||||
case olm::DecryptionErrorCode::DecryptionFailed:
|
||||
nhlog::crypto()->critical(
|
||||
"failed to decrypt message with index ({}, {}, {}): {}",
|
||||
index.room_id,
|
||||
index.session_id,
|
||||
index.sender_key,
|
||||
e.what());
|
||||
decryptionResult.error_message.value_or(""));
|
||||
dummy.content.body =
|
||||
tr("-- Decryption Error (%1) --",
|
||||
"Placeholder, when the message can't be decrypted. In this case, the Olm "
|
||||
"Placeholder, when the message can't be decrypted. In this case, the "
|
||||
"Olm "
|
||||
"decrytion returned an error, which is passed as %1.")
|
||||
.arg(e.what())
|
||||
.arg(
|
||||
QString::fromStdString(decryptionResult.error_message.value_or("")))
|
||||
.toStdString();
|
||||
break;
|
||||
case olm::DecryptionErrorCode::ParsingFailed:
|
||||
dummy.content.body =
|
||||
tr("-- Encrypted Event (Unknown event type) --",
|
||||
"Placeholder, when the message was decrypted, but we couldn't parse "
|
||||
"it, because "
|
||||
"Nheko/mtxclient don't support that event type yet.")
|
||||
.toStdString();
|
||||
break;
|
||||
case olm::DecryptionErrorCode::ReplayAttack:
|
||||
nhlog::crypto()->critical(
|
||||
"Reply attack while decryptiong event {} in room {} from {}!",
|
||||
e.event_id,
|
||||
room_id_,
|
||||
index.sender_key);
|
||||
dummy.content.body =
|
||||
tr("-- Reply attack! This message index was reused! --").toStdString();
|
||||
break;
|
||||
case olm::DecryptionErrorCode::UnknownFingerprint:
|
||||
// TODO: don't fail, just show in UI.
|
||||
nhlog::crypto()->critical("Message by unverified fingerprint {}",
|
||||
index.sender_key);
|
||||
dummy.content.body =
|
||||
tr("-- Message by unverified device! --").toStdString();
|
||||
break;
|
||||
}
|
||||
return asCacheEntry(std::move(dummy));
|
||||
}
|
||||
|
||||
// Add missing fields for the event.
|
||||
json body = json::parse(msg_str);
|
||||
body["event_id"] = e.event_id;
|
||||
body["sender"] = e.sender;
|
||||
body["origin_server_ts"] = e.origin_server_ts;
|
||||
body["unsigned"] = e.unsigned_data;
|
||||
|
||||
// relations are unencrypted in content...
|
||||
if (json old_ev = e; old_ev["content"].count("m.relates_to") != 0)
|
||||
body["content"]["m.relates_to"] = old_ev["content"]["m.relates_to"];
|
||||
|
||||
json event_array = json::array();
|
||||
event_array.push_back(body);
|
||||
|
||||
std::vector<mtx::events::collections::TimelineEvents> temp_events;
|
||||
mtx::responses::utils::parse_timeline_events(event_array, temp_events);
|
||||
|
||||
if (temp_events.size() == 1) {
|
||||
auto encInfo = mtx::accessors::file(temp_events[0]);
|
||||
|
||||
auto encInfo = mtx::accessors::file(decryptionResult.event.value());
|
||||
if (encInfo)
|
||||
emit newEncryptedImage(encInfo.value());
|
||||
|
||||
return asCacheEntry(std::move(temp_events[0]));
|
||||
}
|
||||
|
||||
dummy.content.body =
|
||||
tr("-- Encrypted Event (Unknown event type) --",
|
||||
"Placeholder, when the message was decrypted, but we couldn't parse it, because "
|
||||
"Nheko/mtxclient don't support that event type yet.")
|
||||
.toStdString();
|
||||
return asCacheEntry(std::move(dummy));
|
||||
return asCacheEntry(std::move(decryptionResult.event.value()));
|
||||
}
|
||||
|
||||
mtx::events::collections::TimelineEvents *
|
||||
|
Loading…
Reference in New Issue
Block a user