mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-26 13:08:48 +03:00
Calculate verification status from cross-signing sigs and update dynamically
This commit is contained in:
parent
64d5a193f1
commit
7b6fab3373
9 changed files with 223 additions and 157 deletions
|
@ -56,7 +56,7 @@ ApplicationWindow{
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: verifyUserButton
|
id: verifyUserButton
|
||||||
text: "Verify"
|
text: qsTr("Verify")
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
enabled: !profile.isUserVerified
|
enabled: !profile.isUserVerified
|
||||||
visible: !profile.isUserVerified
|
visible: !profile.isUserVerified
|
||||||
|
@ -155,7 +155,6 @@ ApplicationWindow{
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if(model.verificationStatus == VerificationStatus.VERIFIED){
|
if(model.verificationStatus == VerificationStatus.VERIFIED){
|
||||||
profile.unverify(model.deviceId)
|
profile.unverify(model.deviceId)
|
||||||
deviceVerificationList.updateProfile(newFlow.userId);
|
|
||||||
}else{
|
}else{
|
||||||
profile.verify(model.deviceId);
|
profile.verify(model.deviceId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.3
|
import QtQuick 2.10
|
||||||
import QtQuick.Controls 2.10
|
import QtQuick.Controls 2.10
|
||||||
import QtQuick.Window 2.2
|
import QtQuick.Window 2.10
|
||||||
|
|
||||||
import im.nheko 1.0
|
import im.nheko 1.0
|
||||||
|
|
||||||
|
|
178
src/Cache.cpp
178
src/Cache.cpp
|
@ -3184,6 +3184,28 @@ Cache::updateUserKeys(const std::string &sync_token, const mtx::responses::Query
|
||||||
}
|
}
|
||||||
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
|
|
||||||
|
std::map<std::string, VerificationStatus> tmp;
|
||||||
|
const auto local_user = utils::localUser().toStdString();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(verification_storage.verification_storage_mtx);
|
||||||
|
for (auto &[user_id, update] : updates) {
|
||||||
|
if (user_id == local_user) {
|
||||||
|
std::swap(tmp, verification_storage.status);
|
||||||
|
} else {
|
||||||
|
verification_storage.status.erase(user_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto &[user_id, update] : updates) {
|
||||||
|
if (user_id == local_user) {
|
||||||
|
for (const auto &[user, status] : tmp)
|
||||||
|
emit verificationStatusChanged(user);
|
||||||
|
} else {
|
||||||
|
emit verificationStatusChanged(user_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -3236,23 +3258,19 @@ Cache::markUserKeysOutOfDate(lmdb::txn &txn,
|
||||||
void
|
void
|
||||||
to_json(json &j, const VerificationCache &info)
|
to_json(json &j, const VerificationCache &info)
|
||||||
{
|
{
|
||||||
j["verified_master_key"] = info.verified_master_key;
|
j["device_verified"] = info.device_verified;
|
||||||
j["cross_verified"] = info.cross_verified;
|
j["device_blocked"] = info.device_blocked;
|
||||||
j["device_verified"] = info.device_verified;
|
|
||||||
j["device_blocked"] = info.device_blocked;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
from_json(const json &j, VerificationCache &info)
|
from_json(const json &j, VerificationCache &info)
|
||||||
{
|
{
|
||||||
info.verified_master_key = j.at("verified_master_key");
|
info.device_verified = j.at("device_verified").get<std::vector<std::string>>();
|
||||||
info.cross_verified = j.at("cross_verified").get<std::vector<std::string>>();
|
info.device_blocked = j.at("device_blocked").get<std::vector<std::string>>();
|
||||||
info.device_verified = j.at("device_verified").get<std::vector<std::string>>();
|
|
||||||
info.device_blocked = j.at("device_blocked").get<std::vector<std::string>>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<VerificationCache>
|
std::optional<VerificationCache>
|
||||||
Cache::verificationStatus(const std::string &user_id)
|
Cache::verificationCache(const std::string &user_id)
|
||||||
{
|
{
|
||||||
lmdb::val verifiedVal;
|
lmdb::val verifiedVal;
|
||||||
|
|
||||||
|
@ -3298,6 +3316,23 @@ Cache::markDeviceVerified(const std::string &user_id, const std::string &key)
|
||||||
txn.commit();
|
txn.commit();
|
||||||
} catch (std::exception &) {
|
} catch (std::exception &) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto local_user = utils::localUser().toStdString();
|
||||||
|
std::map<std::string, VerificationStatus> tmp;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(verification_storage.verification_storage_mtx);
|
||||||
|
if (user_id == local_user) {
|
||||||
|
std::swap(tmp, verification_storage.status);
|
||||||
|
} else {
|
||||||
|
verification_storage.status.erase(user_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (user_id == local_user) {
|
||||||
|
for (const auto &[user, status] : tmp)
|
||||||
|
emit verificationStatusChanged(user);
|
||||||
|
} else {
|
||||||
|
emit verificationStatusChanged(user_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -3325,27 +3360,112 @@ Cache::markDeviceUnverified(const std::string &user_id, const std::string &key)
|
||||||
txn.commit();
|
txn.commit();
|
||||||
} catch (std::exception &) {
|
} catch (std::exception &) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto local_user = utils::localUser().toStdString();
|
||||||
|
std::map<std::string, VerificationStatus> tmp;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(verification_storage.verification_storage_mtx);
|
||||||
|
if (user_id == local_user) {
|
||||||
|
std::swap(tmp, verification_storage.status);
|
||||||
|
} else {
|
||||||
|
verification_storage.status.erase(user_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (user_id == local_user) {
|
||||||
|
for (const auto &[user, status] : tmp)
|
||||||
|
emit verificationStatusChanged(user);
|
||||||
|
} else {
|
||||||
|
emit verificationStatusChanged(user_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
VerificationStatus
|
||||||
Cache::markMasterKeyVerified(const std::string &user_id, const std::string &key)
|
Cache::verificationStatus(const std::string &user_id)
|
||||||
{
|
{
|
||||||
lmdb::val val;
|
std::unique_lock<std::mutex> lock(verification_storage.verification_storage_mtx);
|
||||||
|
if (verification_storage.status.count(user_id))
|
||||||
|
return verification_storage.status.at(user_id);
|
||||||
|
|
||||||
auto txn = lmdb::txn::begin(env_);
|
VerificationStatus status;
|
||||||
auto db = getVerificationDb(txn);
|
|
||||||
|
if (auto verifCache = verificationCache(user_id)) {
|
||||||
|
status.verified_devices = verifCache->device_verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto local_user = utils::localUser().toStdString();
|
||||||
|
|
||||||
|
if (user_id == local_user)
|
||||||
|
status.verified_devices.push_back(http::client()->device_id());
|
||||||
|
|
||||||
|
verification_storage.status[user_id] = status;
|
||||||
|
|
||||||
|
auto verifyAtLeastOneSig = [](const auto &toVerif,
|
||||||
|
const std::map<std::string, std::string> &keys,
|
||||||
|
const std::string &keyOwner) {
|
||||||
|
if (!toVerif.signatures.count(keyOwner))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto &[key_id, signature] : toVerif.signatures.at(keyOwner)) {
|
||||||
|
if (!keys.count(key_id))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (mtx::crypto::ed25519_verify_signature(
|
||||||
|
keys.at(key_id), json(toVerif), signature))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
VerificationCache verified_state;
|
// for local user verify this device_key -> our master_key -> our self_signing_key
|
||||||
auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), val);
|
// -> our device_keys
|
||||||
if (res) {
|
//
|
||||||
verified_state = json::parse(std::string_view(val.data(), val.size()));
|
// for other user verify this device_key -> our master_key -> our user_signing_key
|
||||||
|
// -> their master_key -> their self_signing_key -> their device_keys
|
||||||
|
//
|
||||||
|
// This means verifying the other user adds 2 extra steps,verifying our user_signing
|
||||||
|
// key and their master key
|
||||||
|
auto ourKeys = userKeys(local_user);
|
||||||
|
auto theirKeys = userKeys(user_id);
|
||||||
|
if (!ourKeys || !theirKeys)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (!mtx::crypto::ed25519_verify_signature(
|
||||||
|
olm::client()->identity_keys().ed25519,
|
||||||
|
json(ourKeys->master_keys),
|
||||||
|
ourKeys->master_keys.signatures.at(local_user)
|
||||||
|
.at("ed25519:" + http::client()->device_id())))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto master_keys = ourKeys->master_keys.keys;
|
||||||
|
|
||||||
|
if (user_id != local_user) {
|
||||||
|
if (!verifyAtLeastOneSig(
|
||||||
|
ourKeys->user_signing_keys, master_keys, local_user))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (!verifyAtLeastOneSig(
|
||||||
|
theirKeys->master_keys, ourKeys->user_signing_keys.keys, local_user))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
master_keys = theirKeys->master_keys.keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
verified_state.verified_master_key = key;
|
status.user_verified = true;
|
||||||
lmdb::dbi_put(txn, db, lmdb::val(user_id), lmdb::val(json(verified_state).dump()));
|
|
||||||
txn.commit();
|
if (!verifyAtLeastOneSig(theirKeys->self_signing_keys, master_keys, user_id))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
for (const auto &[device, device_key] : theirKeys->device_keys) {
|
||||||
|
if (verifyAtLeastOneSig(
|
||||||
|
device_key, theirKeys->self_signing_keys.keys, user_id))
|
||||||
|
status.verified_devices.push_back(device_key.device_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
verification_storage.status[user_id] = status;
|
||||||
|
return status;
|
||||||
} catch (std::exception &) {
|
} catch (std::exception &) {
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3551,28 +3671,22 @@ updateUserKeys(const std::string &sync_token, const mtx::responses::QueryKeys &k
|
||||||
}
|
}
|
||||||
|
|
||||||
// device & user verification cache
|
// device & user verification cache
|
||||||
std::optional<VerificationCache>
|
std::optional<VerificationStatus>
|
||||||
verificationStatus(const std::string &user_id)
|
verificationStatus(const std::string &user_id)
|
||||||
{
|
{
|
||||||
return instance_->verificationStatus(user_id);
|
return instance_->verificationStatus(user_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
markDeviceVerified(const std::string &user_id, const std::string &key)
|
markDeviceVerified(const std::string &user_id, const std::string &device)
|
||||||
{
|
{
|
||||||
instance_->markDeviceVerified(user_id, key);
|
instance_->markDeviceVerified(user_id, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
markDeviceUnverified(const std::string &user_id, const std::string &key)
|
markDeviceUnverified(const std::string &user_id, const std::string &device)
|
||||||
{
|
{
|
||||||
instance_->markDeviceUnverified(user_id, key);
|
instance_->markDeviceUnverified(user_id, device);
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
markMasterKeyVerified(const std::string &user_id, const std::string &key)
|
|
||||||
{
|
|
||||||
instance_->markMasterKeyVerified(user_id, key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
|
|
|
@ -67,14 +67,12 @@ void
|
||||||
updateUserKeys(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
|
updateUserKeys(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
|
||||||
|
|
||||||
// device & user verification cache
|
// device & user verification cache
|
||||||
std::optional<VerificationCache>
|
std::optional<VerificationStatus>
|
||||||
verificationStatus(const std::string &user_id);
|
verificationStatus(const std::string &user_id);
|
||||||
void
|
void
|
||||||
markDeviceVerified(const std::string &user_id, const std::string &key);
|
markDeviceVerified(const std::string &user_id, const std::string &device);
|
||||||
void
|
void
|
||||||
markDeviceUnverified(const std::string &user_id, const std::string &key);
|
markDeviceUnverified(const std::string &user_id, const std::string &device);
|
||||||
void
|
|
||||||
markMasterKeyVerified(const std::string &user_id, const std::string &key);
|
|
||||||
|
|
||||||
//! Load saved data for the display names & avatars.
|
//! Load saved data for the display names & avatars.
|
||||||
void
|
void
|
||||||
|
|
|
@ -66,6 +66,23 @@ struct OlmSessionStorage
|
||||||
std::mutex group_inbound_mtx;
|
std::mutex group_inbound_mtx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Verification status of a single user
|
||||||
|
struct VerificationStatus
|
||||||
|
{
|
||||||
|
//! True, if the users master key is verified
|
||||||
|
bool user_verified = false;
|
||||||
|
//! List of all devices marked as verified
|
||||||
|
std::vector<std::string> verified_devices;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! In memory cache of verification status
|
||||||
|
struct VerificationStorage
|
||||||
|
{
|
||||||
|
//! mapping of user to verification status
|
||||||
|
std::map<std::string, VerificationStatus> status;
|
||||||
|
std::mutex verification_storage_mtx;
|
||||||
|
};
|
||||||
|
|
||||||
// this will store the keys of the user with whom a encrypted room is shared with
|
// this will store the keys of the user with whom a encrypted room is shared with
|
||||||
struct UserKeyCache
|
struct UserKeyCache
|
||||||
{
|
{
|
||||||
|
@ -90,12 +107,8 @@ struct VerificationCache
|
||||||
{
|
{
|
||||||
//! list of verified device_ids with device-verification
|
//! list of verified device_ids with device-verification
|
||||||
std::vector<std::string> device_verified;
|
std::vector<std::string> device_verified;
|
||||||
//! list of verified device_ids with cross-signing, calculated from master key
|
|
||||||
std::vector<std::string> cross_verified;
|
|
||||||
//! list of devices the user blocks
|
//! list of devices the user blocks
|
||||||
std::vector<std::string> device_blocked;
|
std::vector<std::string> device_blocked;
|
||||||
//! The verified master key.
|
|
||||||
std::string verified_master_key;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -67,10 +67,9 @@ public:
|
||||||
const std::vector<std::string> &user_ids);
|
const std::vector<std::string> &user_ids);
|
||||||
|
|
||||||
// device & user verification cache
|
// device & user verification cache
|
||||||
std::optional<VerificationCache> verificationStatus(const std::string &user_id);
|
VerificationStatus verificationStatus(const std::string &user_id);
|
||||||
void markDeviceVerified(const std::string &user_id, const std::string &key);
|
void markDeviceVerified(const std::string &user_id, const std::string &device);
|
||||||
void markDeviceUnverified(const std::string &user_id, const std::string &key);
|
void markDeviceUnverified(const std::string &user_id, const std::string &device);
|
||||||
void markMasterKeyVerified(const std::string &user_id, const std::string &key);
|
|
||||||
|
|
||||||
static void removeDisplayName(const QString &room_id, const QString &user_id);
|
static void removeDisplayName(const QString &room_id, const QString &user_id);
|
||||||
static void removeAvatarUrl(const QString &room_id, const QString &user_id);
|
static void removeAvatarUrl(const QString &room_id, const QString &user_id);
|
||||||
|
@ -283,6 +282,7 @@ signals:
|
||||||
void removeNotification(const QString &room_id, const QString &event_id);
|
void removeNotification(const QString &room_id, const QString &event_id);
|
||||||
void userKeysUpdate(const std::string &sync_token,
|
void userKeysUpdate(const std::string &sync_token,
|
||||||
const mtx::responses::QueryKeys &keyQuery);
|
const mtx::responses::QueryKeys &keyQuery);
|
||||||
|
void verificationStatusChanged(const std::string &userid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Save an invited room.
|
//! Save an invited room.
|
||||||
|
@ -576,6 +576,8 @@ private:
|
||||||
return QString::fromStdString(event.state_key);
|
return QString::fromStdString(event.state_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<VerificationCache> verificationCache(const std::string &user_id);
|
||||||
|
|
||||||
void setNextBatchToken(lmdb::txn &txn, const std::string &token);
|
void setNextBatchToken(lmdb::txn &txn, const std::string &token);
|
||||||
void setNextBatchToken(lmdb::txn &txn, const QString &token);
|
void setNextBatchToken(lmdb::txn &txn, const QString &token);
|
||||||
|
|
||||||
|
@ -600,6 +602,7 @@ private:
|
||||||
static QHash<QString, QString> AvatarUrls;
|
static QHash<QString, QString> AvatarUrls;
|
||||||
|
|
||||||
OlmSessionStorage session_storage;
|
OlmSessionStorage session_storage;
|
||||||
|
VerificationStorage verification_storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace cache {
|
namespace cache {
|
||||||
|
|
|
@ -1031,7 +1031,7 @@ TimelineModel::sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!mtx::crypto::verify_identity_signature(
|
if (!mtx::crypto::verify_identity_signature(
|
||||||
json(dev.second), device_id, user_id)) {
|
dev.second, device_id, user_id)) {
|
||||||
nhlog::crypto()->warn(
|
nhlog::crypto()->warn(
|
||||||
"failed to verify identity keys: {}",
|
"failed to verify identity keys: {}",
|
||||||
json(dev.second).dump(2));
|
json(dev.second).dump(2));
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "UserProfile.h"
|
#include "UserProfile.h"
|
||||||
#include "Cache.h"
|
#include "Cache_p.h"
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
#include "DeviceVerificationFlow.h"
|
#include "DeviceVerificationFlow.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
|
@ -8,8 +8,6 @@
|
||||||
#include "timeline/TimelineModel.h"
|
#include "timeline/TimelineModel.h"
|
||||||
#include "timeline/TimelineViewManager.h"
|
#include "timeline/TimelineViewManager.h"
|
||||||
|
|
||||||
#include <iostream> // only for debugging
|
|
||||||
|
|
||||||
UserProfile::UserProfile(QString roomid,
|
UserProfile::UserProfile(QString roomid,
|
||||||
QString userid,
|
QString userid,
|
||||||
TimelineViewManager *manager_,
|
TimelineViewManager *manager_,
|
||||||
|
@ -21,6 +19,31 @@ UserProfile::UserProfile(QString roomid,
|
||||||
, model(parent)
|
, model(parent)
|
||||||
{
|
{
|
||||||
fetchDeviceList(this->userid_);
|
fetchDeviceList(this->userid_);
|
||||||
|
|
||||||
|
connect(cache::client(),
|
||||||
|
&Cache::verificationStatusChanged,
|
||||||
|
this,
|
||||||
|
[this](const std::string &user_id) {
|
||||||
|
if (user_id != this->userid_.toStdString())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto status = cache::verificationStatus(user_id);
|
||||||
|
if (!status)
|
||||||
|
return;
|
||||||
|
this->isUserVerified = status->user_verified;
|
||||||
|
emit userStatusChanged();
|
||||||
|
|
||||||
|
for (auto &deviceInfo : deviceList_.deviceList_) {
|
||||||
|
deviceInfo.verification_status =
|
||||||
|
std::find(status->verified_devices.begin(),
|
||||||
|
status->verified_devices.end(),
|
||||||
|
deviceInfo.device_id.toStdString()) ==
|
||||||
|
status->verified_devices.end()
|
||||||
|
? verification::UNVERIFIED
|
||||||
|
: verification::VERIFIED;
|
||||||
|
}
|
||||||
|
deviceList_.reset(deviceList_.deviceList_);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray>
|
QHash<int, QByteArray>
|
||||||
|
@ -126,107 +149,27 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DeviceInfo> deviceInfo;
|
std::vector<DeviceInfo> deviceInfo;
|
||||||
auto devices = other_user_keys.device_keys;
|
auto devices = other_user_keys.device_keys;
|
||||||
auto device_verified = cache::verificationStatus(other_user_id);
|
auto verificationStatus =
|
||||||
|
cache::client()->verificationStatus(other_user_id);
|
||||||
|
|
||||||
if (device_verified.has_value()) {
|
isUserVerified = verificationStatus.user_verified;
|
||||||
// TODO: properly check cross-signing signatures here
|
emit userStatusChanged();
|
||||||
isUserVerified = !device_verified->verified_master_key.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<crypto::CrossSigningKeys> lmk, lsk, luk, mk, sk, uk;
|
|
||||||
|
|
||||||
lmk = res.master_keys;
|
|
||||||
luk = res.user_signing_keys;
|
|
||||||
lsk = res.self_signing_keys;
|
|
||||||
mk = other_user_keys.master_keys;
|
|
||||||
uk = other_user_keys.user_signing_keys;
|
|
||||||
sk = other_user_keys.self_signing_keys;
|
|
||||||
|
|
||||||
// First checking if the user is verified
|
|
||||||
if (luk.has_value() && mk.has_value()) {
|
|
||||||
// iterating through the public key of local user_signing keys
|
|
||||||
for (auto sign_key : luk.value().keys) {
|
|
||||||
// checking if the signatures are empty as "at" could
|
|
||||||
// cause exceptions
|
|
||||||
auto signs = mk->signatures;
|
|
||||||
if (!signs.empty() &&
|
|
||||||
signs.find(local_user_id) != signs.end()) {
|
|
||||||
auto sign = signs.at(local_user_id);
|
|
||||||
try {
|
|
||||||
isUserVerified =
|
|
||||||
isUserVerified ||
|
|
||||||
(olm::client()->ed25519_verify_sig(
|
|
||||||
sign_key.second,
|
|
||||||
json(mk.value()),
|
|
||||||
sign.at(sign_key.first)));
|
|
||||||
} catch (std::out_of_range &) {
|
|
||||||
isUserVerified =
|
|
||||||
isUserVerified || false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &d : devices) {
|
for (const auto &d : devices) {
|
||||||
auto device = d.second;
|
auto device = d.second;
|
||||||
verification::Status verified =
|
verification::Status verified =
|
||||||
verification::Status::UNVERIFIED;
|
verification::Status::UNVERIFIED;
|
||||||
|
|
||||||
if (device_verified.has_value()) {
|
if (std::find(verificationStatus.verified_devices.begin(),
|
||||||
if (std::find(device_verified->cross_verified.begin(),
|
verificationStatus.verified_devices.end(),
|
||||||
device_verified->cross_verified.end(),
|
device.device_id) !=
|
||||||
d.first) !=
|
verificationStatus.verified_devices.end() &&
|
||||||
device_verified->cross_verified.end())
|
mtx::crypto::verify_identity_signature(
|
||||||
verified = verification::Status::VERIFIED;
|
device,
|
||||||
if (std::find(device_verified->device_verified.begin(),
|
DeviceId(device.device_id),
|
||||||
device_verified->device_verified.end(),
|
UserId(other_user_id)))
|
||||||
d.first) !=
|
verified = verification::Status::VERIFIED;
|
||||||
device_verified->device_verified.end())
|
|
||||||
verified = verification::Status::VERIFIED;
|
|
||||||
if (std::find(device_verified->device_blocked.begin(),
|
|
||||||
device_verified->device_blocked.end(),
|
|
||||||
d.first) !=
|
|
||||||
device_verified->device_blocked.end())
|
|
||||||
verified = verification::Status::BLOCKED;
|
|
||||||
} else if (isUserVerified) {
|
|
||||||
device_verified = VerificationCache{};
|
|
||||||
}
|
|
||||||
|
|
||||||
// won't check for already verified devices
|
|
||||||
if (verified != verification::Status::VERIFIED &&
|
|
||||||
isUserVerified) {
|
|
||||||
if ((sk.has_value()) && (!device.signatures.empty())) {
|
|
||||||
for (auto sign_key : sk.value().keys) {
|
|
||||||
auto signs =
|
|
||||||
device.signatures.at(other_user_id);
|
|
||||||
try {
|
|
||||||
if (olm::client()
|
|
||||||
->ed25519_verify_sig(
|
|
||||||
sign_key.second,
|
|
||||||
json(device),
|
|
||||||
signs.at(
|
|
||||||
sign_key.first))) {
|
|
||||||
verified =
|
|
||||||
verification::Status::
|
|
||||||
VERIFIED;
|
|
||||||
device_verified.value()
|
|
||||||
.cross_verified
|
|
||||||
.push_back(d.first);
|
|
||||||
}
|
|
||||||
} catch (std::out_of_range &) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(Nico): properly show cross-signing
|
|
||||||
// if (device_verified.has_value()) {
|
|
||||||
// device_verified.value().is_user_verified =
|
|
||||||
// isUserVerified;
|
|
||||||
// cache::setVerifiedCache(user_id,
|
|
||||||
// device_verified.value());
|
|
||||||
//}
|
|
||||||
|
|
||||||
deviceInfo.push_back(
|
deviceInfo.push_back(
|
||||||
{QString::fromStdString(d.first),
|
{QString::fromStdString(d.first),
|
||||||
|
@ -235,14 +178,6 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
verified});
|
verified});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << (isUserVerified ? "Yes" : "No") << std::endl;
|
|
||||||
|
|
||||||
std::sort(deviceInfo.begin(),
|
|
||||||
deviceInfo.end(),
|
|
||||||
[](const DeviceInfo &a, const DeviceInfo &b) {
|
|
||||||
return a.device_id > b.device_id;
|
|
||||||
});
|
|
||||||
|
|
||||||
this->deviceList_.queueReset(std::move(deviceInfo));
|
this->deviceList_.queueReset(std::move(deviceInfo));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -74,6 +74,8 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<DeviceInfo> deviceList_;
|
std::vector<DeviceInfo> deviceList_;
|
||||||
|
|
||||||
|
friend class UserProfile;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UserProfile : public QObject
|
class UserProfile : public QObject
|
||||||
|
@ -83,7 +85,7 @@ class UserProfile : public QObject
|
||||||
Q_PROPERTY(QString userid READ userid CONSTANT)
|
Q_PROPERTY(QString userid READ userid CONSTANT)
|
||||||
Q_PROPERTY(QString avatarUrl READ avatarUrl CONSTANT)
|
Q_PROPERTY(QString avatarUrl READ avatarUrl CONSTANT)
|
||||||
Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
|
Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
|
||||||
Q_PROPERTY(bool isUserVerified READ getUserStatus CONSTANT)
|
Q_PROPERTY(bool isUserVerified READ getUserStatus NOTIFY userStatusChanged)
|
||||||
public:
|
public:
|
||||||
UserProfile(QString roomid,
|
UserProfile(QString roomid,
|
||||||
QString userid,
|
QString userid,
|
||||||
|
@ -105,9 +107,11 @@ public:
|
||||||
Q_INVOKABLE void kickUser();
|
Q_INVOKABLE void kickUser();
|
||||||
Q_INVOKABLE void startChat();
|
Q_INVOKABLE void startChat();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void userStatusChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString roomid_, userid_;
|
QString roomid_, userid_;
|
||||||
std::optional<std::string> cross_verified;
|
|
||||||
DeviceInfoModel deviceList_;
|
DeviceInfoModel deviceList_;
|
||||||
bool isUserVerified = false;
|
bool isUserVerified = false;
|
||||||
TimelineViewManager *manager;
|
TimelineViewManager *manager;
|
||||||
|
|
Loading…
Reference in a new issue