diff --git a/src/Cache.cpp b/src/Cache.cpp
index 0de790ac..4022ce85 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -3666,8 +3666,11 @@ Cache::verificationStatus(const std::string &user_id)
const auto local_user = utils::localUser().toStdString();
- if (user_id == local_user)
+ crypto::Trust trustlevel = crypto::Trust::Unverified;
+ if (user_id == local_user) {
status.verified_devices.push_back(http::client()->device_id());
+ trustlevel = crypto::Trust::Verified;
+ }
verification_storage.status[user_id] = status;
@@ -3723,16 +3726,24 @@ Cache::verificationStatus(const std::string &user_id)
master_keys = theirKeys->master_keys.keys;
}
- status.user_verified = true;
+ trustlevel = crypto::Trust::Verified;
+ status.user_verified = crypto::Trust::Verified;
if (!verifyAtLeastOneSig(theirKeys->self_signing_keys, master_keys, user_id))
return status;
for (const auto &[device, device_key] : theirKeys->device_keys) {
(void)device;
- if (verifyAtLeastOneSig(
- device_key, theirKeys->self_signing_keys.keys, user_id))
- status.verified_devices.push_back(device_key.device_id);
+ try {
+ auto identkey =
+ device_key.keys.at("curve25519:" + device_key.device_id);
+ if (verifyAtLeastOneSig(
+ device_key, theirKeys->self_signing_keys.keys, user_id)) {
+ status.verified_devices.push_back(device_key.device_id);
+ status.verified_device_keys[identkey] = trustlevel;
+ }
+ } catch (...) {
+ }
}
verification_storage.status[user_id] = status;
diff --git a/src/CacheCryptoStructs.h b/src/CacheCryptoStructs.h
index c884107e..b665be86 100644
--- a/src/CacheCryptoStructs.h
+++ b/src/CacheCryptoStructs.h
@@ -4,12 +4,28 @@
#pragma once
+#include <QObject>
+
#include <map>
#include <mutex>
+#include <mtx/events/encrypted.hpp>
#include <mtx/responses/crypto.hpp>
#include <mtxclient/crypto/objects.hpp>
+namespace crypto {
+Q_NAMESPACE
+//! How much a participant is trusted.
+enum Trust
+{
+ Unverified, //! Device unverified or master key changed.
+ TOFU, //! Device is signed by the sender, but the user is not verified, but they never
+ //! changed the master key.
+ Verified, //! User was verified and has crosssigned this device or device is verified.
+};
+Q_ENUM_NS(Trust)
+}
+
struct DeviceAndMasterKeys
{
// map from device id or master key id to message_index
@@ -87,9 +103,11 @@ from_json(const nlohmann::json &obj, StoredOlmSession &msg);
struct VerificationStatus
{
//! True, if the users master key is verified
- bool user_verified = false;
+ crypto::Trust user_verified = crypto::Trust::Unverified;
//! List of all devices marked as verified
std::vector<std::string> verified_devices;
+ //! Map from sender key/curve25519 to trust status
+ std::map<std::string, crypto::Trust> verified_device_keys;
};
//! In memory cache of verification status
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index f7fb6c35..cd375cc9 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -78,7 +78,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
if (auto status =
cache::verificationStatus(http::client()->user_id().to_string());
- status && status->user_verified)
+ status && status->user_verified == crypto::Trust::Verified)
this->our_trusted_master_key = res.master_keys.keys.begin()->second;
});
diff --git a/src/Olm.cpp b/src/Olm.cpp
index b218ba2c..d08c1b3e 100644
--- a/src/Olm.cpp
+++ b/src/Olm.cpp
@@ -939,7 +939,6 @@ decryptEvent(const MegolmSessionIndex &index,
}
// TODO: Lookup index,event_id,origin_server_ts tuple for replay attack errors
- // TODO: Verify sender_key
std::string msg_str;
try {
@@ -976,6 +975,17 @@ decryptEvent(const MegolmSessionIndex &index,
return {std::nullopt, std::nullopt, std::move(te.data)};
}
+crypto::Trust
+calculate_trust(const std::string &user_id, const std::string &curve25519)
+{
+ auto status = cache::client()->verificationStatus(user_id);
+ crypto::Trust trustlevel = crypto::Trust::Unverified;
+ if (status.verified_device_keys.count(curve25519))
+ trustlevel = status.verified_device_keys.at(curve25519);
+
+ return trustlevel;
+}
+
//! Send encrypted to device messages, targets is a map from userid to device ids or {} for all
//! devices
void
diff --git a/src/Olm.h b/src/Olm.h
index bcb486a3..d356cb55 100644
--- a/src/Olm.h
+++ b/src/Olm.h
@@ -34,6 +34,7 @@ struct DecryptionResult
{
std::optional<DecryptionErrorCode> error;
std::optional<std::string> error_message;
+
std::optional<mtx::events::collections::TimelineEvents> event;
};
@@ -83,6 +84,8 @@ encrypt_group_message(const std::string &room_id,
DecryptionResult
decryptEvent(const MegolmSessionIndex &index,
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &event);
+crypto::Trust
+calculate_trust(const std::string &user_id, const std::string &curve25519);
void
mark_keys_as_published();
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index a1e9ac0c..5fa28234 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -407,6 +407,7 @@ TimelineModel::roleNames() const
{IsEdited, "isEdited"},
{IsEditable, "isEditable"},
{IsEncrypted, "isEncrypted"},
+ {Trustlevel, "trustlevel"},
{IsRoomEncrypted, "isRoomEncrypted"},
{ReplyTo, "replyTo"},
{Reactions, "reactions"},
@@ -575,6 +576,21 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(
*encrypted_event);
}
+
+ case Trustlevel: {
+ auto id = event_id(event);
+ auto encrypted_event = events.get(id, id, false);
+ if (encrypted_event) {
+ if (auto encrypted =
+ std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(
+ &*encrypted_event)) {
+ return olm::calculate_trust(encrypted->sender,
+ encrypted->content.sender_key);
+ }
+ }
+ return crypto::Trust::Unverified;
+ }
+
case IsRoomEncrypted: {
return cache::isRoomEncrypted(room_id_.toStdString());
}
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index caeb25cf..92fccd2d 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -196,6 +196,7 @@ public:
IsEdited,
IsEditable,
IsEncrypted,
+ Trustlevel,
IsRoomEncrypted,
ReplyTo,
Reactions,
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index decd245c..628f3c31 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -164,6 +164,8 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
0,
"MtxEvent",
"Can't instantiate enum!");
+ qmlRegisterUncreatableMetaObject(
+ crypto::staticMetaObject, "im.nheko", 1, 0, "Crypto", "Can't instantiate enum!");
qmlRegisterUncreatableMetaObject(verification::staticMetaObject,
"im.nheko",
1,
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index b5feb353..0f330964 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -135,7 +135,7 @@ UserProfile::isGlobalUserProfile() const
return roomid_ == "";
}
-bool
+crypto::Trust
UserProfile::getUserStatus()
{
return isUserVerified;
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index aa7266ab..bf71d0de 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -11,6 +11,8 @@
#include <mtx/responses.hpp>
#include <mtx/responses/common.hpp>
+#include "CacheCryptoStructs.h"
+
namespace verification {
Q_NAMESPACE
@@ -90,7 +92,7 @@ class UserProfile : public QObject
Q_PROPERTY(QString avatarUrl READ avatarUrl NOTIFY avatarUrlChanged)
Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
Q_PROPERTY(bool isGlobalUserProfile READ isGlobalUserProfile CONSTANT)
- Q_PROPERTY(bool isUserVerified READ getUserStatus NOTIFY userStatusChanged)
+ Q_PROPERTY(int userVerified READ getUserStatus NOTIFY userStatusChanged)
Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged)
Q_PROPERTY(
bool userVerificationEnabled READ userVerificationEnabled NOTIFY userStatusChanged)
@@ -108,7 +110,7 @@ public:
QString displayName();
QString avatarUrl();
bool isGlobalUserProfile() const;
- bool getUserStatus();
+ crypto::Trust getUserStatus();
bool userVerificationEnabled() const;
bool isSelf() const;
bool isLoading() const;
@@ -147,9 +149,9 @@ private:
QString globalUsername;
QString globalAvatarUrl;
DeviceInfoModel deviceList_;
- bool isUserVerified = false;
- bool hasMasterKey = false;
- bool isLoading_ = false;
+ crypto::Trust isUserVerified = crypto::Trust::Unverified;
+ bool hasMasterKey = false;
+ bool isLoading_ = false;
TimelineViewManager *manager;
TimelineModel *model;
};
|