mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-26 13:08:48 +03:00
Clean up verification and key cache a bit
This commit is contained in:
parent
4802c34009
commit
94690ebd4c
11 changed files with 416 additions and 335 deletions
|
@ -136,7 +136,7 @@ ApplicationWindow{
|
||||||
model: profile.deviceList
|
model: profile.deviceList
|
||||||
|
|
||||||
delegate: RowLayout{
|
delegate: RowLayout{
|
||||||
width: parent.width
|
width: devicelist.width
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
ColumnLayout{
|
ColumnLayout{
|
||||||
|
|
367
src/Cache.cpp
367
src/Cache.cpp
|
@ -91,6 +91,7 @@ Q_DECLARE_METATYPE(RoomMember)
|
||||||
Q_DECLARE_METATYPE(mtx::responses::Timeline)
|
Q_DECLARE_METATYPE(mtx::responses::Timeline)
|
||||||
Q_DECLARE_METATYPE(RoomSearchResult)
|
Q_DECLARE_METATYPE(RoomSearchResult)
|
||||||
Q_DECLARE_METATYPE(RoomInfo)
|
Q_DECLARE_METATYPE(RoomInfo)
|
||||||
|
Q_DECLARE_METATYPE(mtx::responses::QueryKeys)
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::unique_ptr<Cache> instance_ = nullptr;
|
std::unique_ptr<Cache> instance_ = nullptr;
|
||||||
|
@ -155,26 +156,7 @@ Cache::Cache(const QString &userId, QObject *parent)
|
||||||
, localUserId_{userId}
|
, localUserId_{userId}
|
||||||
{
|
{
|
||||||
setup();
|
setup();
|
||||||
connect(
|
connect(this, &Cache::userKeysUpdate, this, &Cache::updateUserKeys, Qt::QueuedConnection);
|
||||||
this,
|
|
||||||
&Cache::updateUserCacheFlag,
|
|
||||||
this,
|
|
||||||
[this](const std::string &user_id) {
|
|
||||||
std::optional<UserCache> cache_ = getUserCache(user_id);
|
|
||||||
if (cache_.has_value()) {
|
|
||||||
cache_.value().isUpdated = false;
|
|
||||||
setUserCache(user_id, cache_.value());
|
|
||||||
} else {
|
|
||||||
setUserCache(user_id, UserCache{});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Qt::QueuedConnection);
|
|
||||||
connect(
|
|
||||||
this,
|
|
||||||
&Cache::deleteLeftUsers,
|
|
||||||
this,
|
|
||||||
[this](const std::string &user_id) { deleteUserCache(user_id); },
|
|
||||||
Qt::QueuedConnection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1017,6 +999,8 @@ Cache::saveState(const mtx::responses::Sync &res)
|
||||||
using namespace mtx::events;
|
using namespace mtx::events;
|
||||||
auto user_id = this->localUserId_.toStdString();
|
auto user_id = this->localUserId_.toStdString();
|
||||||
|
|
||||||
|
auto currentBatchToken = nextBatchToken();
|
||||||
|
|
||||||
auto txn = lmdb::txn::begin(env_);
|
auto txn = lmdb::txn::begin(env_);
|
||||||
|
|
||||||
setNextBatchToken(txn, res.next_batch);
|
setNextBatchToken(txn, res.next_batch);
|
||||||
|
@ -1034,6 +1018,8 @@ Cache::saveState(const mtx::responses::Sync &res)
|
||||||
ev);
|
ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto userKeyCacheDb = getUserKeysDb(txn);
|
||||||
|
|
||||||
// Save joined rooms
|
// Save joined rooms
|
||||||
for (const auto &room : res.rooms.join) {
|
for (const auto &room : res.rooms.join) {
|
||||||
auto statesdb = getStatesDb(txn, room.first);
|
auto statesdb = getStatesDb(txn, room.first);
|
||||||
|
@ -1107,7 +1093,8 @@ Cache::saveState(const mtx::responses::Sync &res)
|
||||||
|
|
||||||
savePresence(txn, res.presence);
|
savePresence(txn, res.presence);
|
||||||
|
|
||||||
updateUserCache(res.device_lists);
|
markUserKeysOutOfDate(txn, userKeyCacheDb, res.device_lists.changed, currentBatchToken);
|
||||||
|
deleteUserKeys(txn, userKeyCacheDb, res.device_lists.left);
|
||||||
|
|
||||||
removeLeftRooms(txn, res.rooms.leave);
|
removeLeftRooms(txn, res.rooms.leave);
|
||||||
|
|
||||||
|
@ -3098,126 +3085,246 @@ Cache::statusMessage(const std::string &user_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
to_json(json &j, const UserCache &info)
|
to_json(json &j, const UserKeyCache &info)
|
||||||
{
|
{
|
||||||
j["keys"] = info.keys;
|
j["device_keys"] = info.device_keys;
|
||||||
j["isUpdated"] = info.isUpdated;
|
j["master_keys"] = info.master_keys;
|
||||||
|
j["user_signing_keys"] = info.user_signing_keys;
|
||||||
|
j["self_signing_keys"] = info.self_signing_keys;
|
||||||
|
j["updated_at"] = info.updated_at;
|
||||||
|
j["last_changed"] = info.last_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
from_json(const json &j, UserCache &info)
|
from_json(const json &j, UserKeyCache &info)
|
||||||
{
|
{
|
||||||
info.keys = j.at("keys").get<mtx::responses::QueryKeys>();
|
info.device_keys = j.value("device_keys", std::map<std::string, mtx::crypto::DeviceKeys>{});
|
||||||
info.isUpdated = j.at("isUpdated").get<bool>();
|
info.master_keys = j.value("master_keys", mtx::crypto::CrossSigningKeys{});
|
||||||
|
info.user_signing_keys = j.value("user_signing_keys", mtx::crypto::CrossSigningKeys{});
|
||||||
|
info.self_signing_keys = j.value("self_signing_keys", mtx::crypto::CrossSigningKeys{});
|
||||||
|
info.updated_at = j.value("updated_at", "");
|
||||||
|
info.last_changed = j.value("last_changed", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<UserCache>
|
std::optional<UserKeyCache>
|
||||||
Cache::getUserCache(const std::string &user_id)
|
Cache::userKeys(const std::string &user_id)
|
||||||
{
|
{
|
||||||
lmdb::val verifiedVal;
|
lmdb::val keys;
|
||||||
|
|
||||||
auto txn = lmdb::txn::begin(env_);
|
try {
|
||||||
auto db = getUserCacheDb(txn);
|
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
|
||||||
auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), verifiedVal);
|
auto db = getUserKeysDb(txn);
|
||||||
|
auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), keys);
|
||||||
|
|
||||||
txn.commit();
|
if (res) {
|
||||||
|
return json::parse(std::string_view(keys.data(), keys.size()))
|
||||||
UserCache verified_state;
|
.get<UserKeyCache>();
|
||||||
if (res) {
|
} else {
|
||||||
verified_state = json::parse(std::string(verifiedVal.data(), verifiedVal.size()));
|
return {};
|
||||||
return verified_state;
|
}
|
||||||
} else {
|
} catch (std::exception &) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! be careful when using make sure is_user_verified is not changed
|
void
|
||||||
int
|
Cache::updateUserKeys(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery)
|
||||||
Cache::setUserCache(const std::string &user_id, const UserCache &body)
|
|
||||||
{
|
{
|
||||||
auto txn = lmdb::txn::begin(env_);
|
auto txn = lmdb::txn::begin(env_);
|
||||||
auto db = getUserCacheDb(txn);
|
auto db = getUserKeysDb(txn);
|
||||||
|
|
||||||
auto res = lmdb::dbi_put(txn, db, lmdb::val(user_id), lmdb::val(json(body).dump()));
|
std::map<std::string, UserKeyCache> updates;
|
||||||
|
|
||||||
txn.commit();
|
for (const auto &[user, keys] : keyQuery.device_keys)
|
||||||
|
updates[user].device_keys = keys;
|
||||||
|
for (const auto &[user, keys] : keyQuery.master_keys)
|
||||||
|
updates[user].master_keys = keys;
|
||||||
|
for (const auto &[user, keys] : keyQuery.user_signing_keys)
|
||||||
|
updates[user].user_signing_keys = keys;
|
||||||
|
for (const auto &[user, keys] : keyQuery.self_signing_keys)
|
||||||
|
updates[user].self_signing_keys = keys;
|
||||||
|
|
||||||
return res;
|
for (auto &[user, update] : updates) {
|
||||||
}
|
lmdb::val oldKeys;
|
||||||
|
auto res = lmdb::dbi_get(txn, db, lmdb::val(user), oldKeys);
|
||||||
|
|
||||||
void
|
if (res) {
|
||||||
Cache::updateUserCache(const mtx::responses::DeviceLists body)
|
auto last_changed =
|
||||||
{
|
json::parse(std::string_view(oldKeys.data(), oldKeys.size()))
|
||||||
for (std::string user_id : body.changed) {
|
.get<UserKeyCache>()
|
||||||
emit updateUserCacheFlag(user_id);
|
.last_changed;
|
||||||
|
// skip if we are tracking this and expect it to be up to date with the last
|
||||||
|
// sync token
|
||||||
|
if (!last_changed.empty() && last_changed != sync_token)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lmdb::dbi_put(txn, db, lmdb::val(user), lmdb::val(json(update).dump()));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::string user_id : body.left) {
|
|
||||||
emit deleteLeftUsers(user_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Cache::deleteUserCache(const std::string &user_id)
|
|
||||||
{
|
|
||||||
auto txn = lmdb::txn::begin(env_);
|
|
||||||
auto db = getUserCacheDb(txn);
|
|
||||||
auto res = lmdb::dbi_del(txn, db, lmdb::val(user_id), nullptr);
|
|
||||||
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
to_json(json &j, const DeviceVerifiedCache &info)
|
Cache::deleteUserKeys(lmdb::txn &txn, lmdb::dbi &db, const std::vector<std::string> &user_ids)
|
||||||
{
|
{
|
||||||
j["is_user_verified"] = info.is_user_verified;
|
for (const auto &user_id : user_ids)
|
||||||
j["cross_verified"] = info.cross_verified;
|
lmdb::dbi_del(txn, db, lmdb::val(user_id), nullptr);
|
||||||
j["device_verified"] = info.device_verified;
|
|
||||||
j["device_blocked"] = info.device_blocked;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
from_json(const json &j, DeviceVerifiedCache &info)
|
Cache::markUserKeysOutOfDate(lmdb::txn &txn,
|
||||||
|
lmdb::dbi &db,
|
||||||
|
const std::vector<std::string> &user_ids,
|
||||||
|
const std::string &sync_token)
|
||||||
{
|
{
|
||||||
info.is_user_verified = j.at("is_user_verified");
|
mtx::requests::QueryKeys query;
|
||||||
info.cross_verified = j.at("cross_verified").get<std::vector<std::string>>();
|
query.token = sync_token;
|
||||||
info.device_verified = j.at("device_verified").get<std::vector<std::string>>();
|
|
||||||
info.device_blocked = j.at("device_blocked").get<std::vector<std::string>>();
|
for (const auto &user : user_ids) {
|
||||||
|
lmdb::val oldKeys;
|
||||||
|
auto res = lmdb::dbi_get(txn, db, lmdb::val(user), oldKeys);
|
||||||
|
|
||||||
|
if (!res)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto cacheEntry =
|
||||||
|
json::parse(std::string_view(oldKeys.data(), oldKeys.size())).get<UserKeyCache>();
|
||||||
|
cacheEntry.last_changed = sync_token;
|
||||||
|
lmdb::dbi_put(txn, db, lmdb::val(user), lmdb::val(json(cacheEntry).dump()));
|
||||||
|
|
||||||
|
query.device_keys[user] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!query.device_keys.empty())
|
||||||
|
http::client()->query_keys(query,
|
||||||
|
[this, sync_token](const mtx::responses::QueryKeys &keys,
|
||||||
|
mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
nhlog::net()->warn(
|
||||||
|
"failed to query device keys: {} {}",
|
||||||
|
err->matrix_error.error,
|
||||||
|
static_cast<int>(err->status_code));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit userKeysUpdate(sync_token, keys);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<DeviceVerifiedCache>
|
void
|
||||||
Cache::getVerifiedCache(const std::string &user_id)
|
to_json(json &j, const VerificationCache &info)
|
||||||
|
{
|
||||||
|
j["verified_master_key"] = info.verified_master_key;
|
||||||
|
j["cross_verified"] = info.cross_verified;
|
||||||
|
j["device_verified"] = info.device_verified;
|
||||||
|
j["device_blocked"] = info.device_blocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
from_json(const json &j, VerificationCache &info)
|
||||||
|
{
|
||||||
|
info.verified_master_key = j.at("verified_master_key");
|
||||||
|
info.cross_verified = j.at("cross_verified").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>
|
||||||
|
Cache::verificationStatus(const std::string &user_id)
|
||||||
{
|
{
|
||||||
lmdb::val verifiedVal;
|
lmdb::val verifiedVal;
|
||||||
|
|
||||||
auto txn = lmdb::txn::begin(env_);
|
auto txn = lmdb::txn::begin(env_);
|
||||||
auto db = getDeviceVerifiedDb(txn);
|
auto db = getVerificationDb(txn);
|
||||||
auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), verifiedVal);
|
|
||||||
|
|
||||||
txn.commit();
|
try {
|
||||||
|
VerificationCache verified_state;
|
||||||
DeviceVerifiedCache verified_state;
|
auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), verifiedVal);
|
||||||
if (res) {
|
if (res) {
|
||||||
verified_state = json::parse(std::string(verifiedVal.data(), verifiedVal.size()));
|
verified_state =
|
||||||
return verified_state;
|
json::parse(std::string_view(verifiedVal.data(), verifiedVal.size()));
|
||||||
} else {
|
return verified_state;
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} catch (std::exception &) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
Cache::setVerifiedCache(const std::string &user_id, const DeviceVerifiedCache &body)
|
Cache::markDeviceVerified(const std::string &user_id, const std::string &key)
|
||||||
{
|
{
|
||||||
|
lmdb::val val;
|
||||||
|
|
||||||
auto txn = lmdb::txn::begin(env_);
|
auto txn = lmdb::txn::begin(env_);
|
||||||
auto db = getDeviceVerifiedDb(txn);
|
auto db = getVerificationDb(txn);
|
||||||
|
|
||||||
auto res = lmdb::dbi_put(txn, db, lmdb::val(user_id), lmdb::val(json(body).dump()));
|
try {
|
||||||
|
VerificationCache verified_state;
|
||||||
|
auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), val);
|
||||||
|
if (res) {
|
||||||
|
verified_state = json::parse(std::string_view(val.data(), val.size()));
|
||||||
|
}
|
||||||
|
|
||||||
txn.commit();
|
for (const auto &device : verified_state.device_verified)
|
||||||
|
if (device == key)
|
||||||
|
return;
|
||||||
|
|
||||||
return res;
|
verified_state.device_verified.push_back(key);
|
||||||
|
lmdb::dbi_put(txn, db, lmdb::val(user_id), lmdb::val(json(verified_state).dump()));
|
||||||
|
txn.commit();
|
||||||
|
} catch (std::exception &) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Cache::markDeviceUnverified(const std::string &user_id, const std::string &key)
|
||||||
|
{
|
||||||
|
lmdb::val val;
|
||||||
|
|
||||||
|
auto txn = lmdb::txn::begin(env_);
|
||||||
|
auto db = getVerificationDb(txn);
|
||||||
|
|
||||||
|
try {
|
||||||
|
VerificationCache verified_state;
|
||||||
|
auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), val);
|
||||||
|
if (res) {
|
||||||
|
verified_state = json::parse(std::string_view(val.data(), val.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
verified_state.device_verified.erase(
|
||||||
|
std::remove(verified_state.device_verified.begin(),
|
||||||
|
verified_state.device_verified.end(),
|
||||||
|
key),
|
||||||
|
verified_state.device_verified.end());
|
||||||
|
|
||||||
|
lmdb::dbi_put(txn, db, lmdb::val(user_id), lmdb::val(json(verified_state).dump()));
|
||||||
|
txn.commit();
|
||||||
|
} catch (std::exception &) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Cache::markMasterKeyVerified(const std::string &user_id, const std::string &key)
|
||||||
|
{
|
||||||
|
lmdb::val val;
|
||||||
|
|
||||||
|
auto txn = lmdb::txn::begin(env_);
|
||||||
|
auto db = getVerificationDb(txn);
|
||||||
|
|
||||||
|
try {
|
||||||
|
VerificationCache verified_state;
|
||||||
|
auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), val);
|
||||||
|
if (res) {
|
||||||
|
verified_state = json::parse(std::string_view(val.data(), val.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
verified_state.verified_master_key = key;
|
||||||
|
lmdb::dbi_put(txn, db, lmdb::val(user_id), lmdb::val(json(verified_state).dump()));
|
||||||
|
txn.commit();
|
||||||
|
} catch (std::exception &) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -3401,41 +3508,6 @@ statusMessage(const std::string &user_id)
|
||||||
{
|
{
|
||||||
return instance_->statusMessage(user_id);
|
return instance_->statusMessage(user_id);
|
||||||
}
|
}
|
||||||
std::optional<UserCache>
|
|
||||||
getUserCache(const std::string &user_id)
|
|
||||||
{
|
|
||||||
return instance_->getUserCache(user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
updateUserCache(const mtx::responses::DeviceLists body)
|
|
||||||
{
|
|
||||||
instance_->updateUserCache(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
setUserCache(const std::string &user_id, const UserCache &body)
|
|
||||||
{
|
|
||||||
return instance_->setUserCache(user_id, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
deleteUserCache(const std::string &user_id)
|
|
||||||
{
|
|
||||||
return instance_->deleteUserCache(user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<DeviceVerifiedCache>
|
|
||||||
getVerifiedCache(const std::string &user_id)
|
|
||||||
{
|
|
||||||
return instance_->getVerifiedCache(user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
setVerifiedCache(const std::string &user_id, const DeviceVerifiedCache &body)
|
|
||||||
{
|
|
||||||
return instance_->setVerifiedCache(user_id, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Load saved data for the display names & avatars.
|
//! Load saved data for the display names & avatars.
|
||||||
void
|
void
|
||||||
|
@ -3444,6 +3516,43 @@ populateMembers()
|
||||||
instance_->populateMembers();
|
instance_->populateMembers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// user cache stores user keys
|
||||||
|
std::optional<UserKeyCache>
|
||||||
|
userKeys(const std::string &user_id)
|
||||||
|
{
|
||||||
|
return instance_->userKeys(user_id);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
updateUserKeys(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery)
|
||||||
|
{
|
||||||
|
instance_->updateUserKeys(sync_token, keyQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
// device & user verification cache
|
||||||
|
std::optional<VerificationCache>
|
||||||
|
verificationStatus(const std::string &user_id)
|
||||||
|
{
|
||||||
|
return instance_->verificationStatus(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
markDeviceVerified(const std::string &user_id, const std::string &key)
|
||||||
|
{
|
||||||
|
instance_->markDeviceVerified(user_id, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
markDeviceUnverified(const std::string &user_id, const std::string &key)
|
||||||
|
{
|
||||||
|
instance_->markDeviceUnverified(user_id, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
markMasterKeyVerified(const std::string &user_id, const std::string &key)
|
||||||
|
{
|
||||||
|
instance_->markMasterKeyVerified(user_id, key);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
joinedRooms()
|
joinedRooms()
|
||||||
{
|
{
|
||||||
|
|
30
src/Cache.h
30
src/Cache.h
|
@ -60,25 +60,21 @@ presenceState(const std::string &user_id);
|
||||||
std::string
|
std::string
|
||||||
statusMessage(const std::string &user_id);
|
statusMessage(const std::string &user_id);
|
||||||
|
|
||||||
//! user Cache
|
// user cache stores user keys
|
||||||
std::optional<UserCache>
|
std::optional<UserKeyCache>
|
||||||
getUserCache(const std::string &user_id);
|
userKeys(const std::string &user_id);
|
||||||
|
|
||||||
void
|
void
|
||||||
updateUserCache(const mtx::responses::DeviceLists body);
|
updateUserKeys(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
|
||||||
|
|
||||||
int
|
// device & user verification cache
|
||||||
setUserCache(const std::string &user_id, const UserCache &body);
|
std::optional<VerificationCache>
|
||||||
|
verificationStatus(const std::string &user_id);
|
||||||
int
|
void
|
||||||
deleteUserCache(const std::string &user_id);
|
markDeviceVerified(const std::string &user_id, const std::string &key);
|
||||||
|
void
|
||||||
//! verified Cache
|
markDeviceUnverified(const std::string &user_id, const std::string &key);
|
||||||
std::optional<DeviceVerifiedCache>
|
void
|
||||||
getVerifiedCache(const std::string &user_id);
|
markMasterKeyVerified(const std::string &user_id, const std::string &key);
|
||||||
|
|
||||||
int
|
|
||||||
setVerifiedCache(const std::string &user_id, const DeviceVerifiedCache &body);
|
|
||||||
|
|
||||||
//! Load saved data for the display names & avatars.
|
//! Load saved data for the display names & avatars.
|
||||||
void
|
void
|
||||||
|
|
|
@ -67,52 +67,38 @@ struct OlmSessionStorage
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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 UserCache
|
struct UserKeyCache
|
||||||
{
|
{
|
||||||
//! map of public key key_ids and their public_key
|
//! Device id to device keys
|
||||||
mtx::responses::QueryKeys keys;
|
std::map<std::string, mtx::crypto::DeviceKeys> device_keys;
|
||||||
//! if the current cache is updated or not
|
//! corss signing keys
|
||||||
bool isUpdated = false;
|
mtx::crypto::CrossSigningKeys master_keys, user_signing_keys, self_signing_keys;
|
||||||
|
//! Sync token when nheko last fetched the keys
|
||||||
UserCache(mtx::responses::QueryKeys res, bool isUpdated_ = false)
|
std::string updated_at;
|
||||||
: keys(res)
|
//! Sync token when the keys last changed. updated != last_changed means they are outdated.
|
||||||
, isUpdated(isUpdated_)
|
std::string last_changed;
|
||||||
{}
|
|
||||||
UserCache() {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
to_json(nlohmann::json &j, const UserCache &info);
|
to_json(nlohmann::json &j, const UserKeyCache &info);
|
||||||
void
|
void
|
||||||
from_json(const nlohmann::json &j, UserCache &info);
|
from_json(const nlohmann::json &j, UserKeyCache &info);
|
||||||
|
|
||||||
// the reason these are stored in a seperate cache rather than storing it in the user cache is
|
// the reason these are stored in a seperate cache rather than storing it in the user cache is
|
||||||
// UserCache stores only keys of users with which encrypted room is shared
|
// UserKeyCache stores only keys of users with which encrypted room is shared
|
||||||
struct DeviceVerifiedCache
|
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
|
//! list of verified device_ids with cross-signing, calculated from master key
|
||||||
std::vector<std::string> cross_verified;
|
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;
|
||||||
//! this stores if the user is verified (with cross-signing)
|
//! The verified master key.
|
||||||
bool is_user_verified = false;
|
std::string verified_master_key;
|
||||||
|
|
||||||
DeviceVerifiedCache(std::vector<std::string> device_verified_,
|
|
||||||
std::vector<std::string> cross_verified_,
|
|
||||||
std::vector<std::string> device_blocked_,
|
|
||||||
bool is_user_verified_ = false)
|
|
||||||
: device_verified(device_verified_)
|
|
||||||
, cross_verified(cross_verified_)
|
|
||||||
, device_blocked(device_blocked_)
|
|
||||||
, is_user_verified(is_user_verified_)
|
|
||||||
{}
|
|
||||||
|
|
||||||
DeviceVerifiedCache() {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
to_json(nlohmann::json &j, const DeviceVerifiedCache &info);
|
to_json(nlohmann::json &j, const VerificationCache &info);
|
||||||
void
|
void
|
||||||
from_json(const nlohmann::json &j, DeviceVerifiedCache &info);
|
from_json(const nlohmann::json &j, VerificationCache &info);
|
||||||
|
|
|
@ -55,14 +55,22 @@ public:
|
||||||
std::string statusMessage(const std::string &user_id);
|
std::string statusMessage(const std::string &user_id);
|
||||||
|
|
||||||
// user cache stores user keys
|
// user cache stores user keys
|
||||||
std::optional<UserCache> getUserCache(const std::string &user_id);
|
std::optional<UserKeyCache> userKeys(const std::string &user_id);
|
||||||
void updateUserCache(const mtx::responses::DeviceLists body);
|
void updateUserKeys(const std::string &sync_token,
|
||||||
int setUserCache(const std::string &user_id, const UserCache &body);
|
const mtx::responses::QueryKeys &keyQuery);
|
||||||
int deleteUserCache(const std::string &user_id);
|
void markUserKeysOutOfDate(lmdb::txn &txn,
|
||||||
|
lmdb::dbi &db,
|
||||||
|
const std::vector<std::string> &user_ids,
|
||||||
|
const std::string &sync_token);
|
||||||
|
void deleteUserKeys(lmdb::txn &txn,
|
||||||
|
lmdb::dbi &db,
|
||||||
|
const std::vector<std::string> &user_ids);
|
||||||
|
|
||||||
// device verified cache
|
// device & user verification cache
|
||||||
std::optional<DeviceVerifiedCache> getVerifiedCache(const std::string &user_id);
|
std::optional<VerificationCache> verificationStatus(const std::string &user_id);
|
||||||
int setVerifiedCache(const std::string &user_id, const DeviceVerifiedCache &body);
|
void markDeviceVerified(const std::string &user_id, const std::string &key);
|
||||||
|
void markDeviceUnverified(const std::string &user_id, const std::string &key);
|
||||||
|
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);
|
||||||
|
@ -272,8 +280,8 @@ signals:
|
||||||
void newReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
void newReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
||||||
void roomReadStatus(const std::map<QString, bool> &status);
|
void roomReadStatus(const std::map<QString, bool> &status);
|
||||||
void removeNotification(const QString &room_id, const QString &event_id);
|
void removeNotification(const QString &room_id, const QString &event_id);
|
||||||
void updateUserCacheFlag(const std::string &user_id);
|
void userKeysUpdate(const std::string &sync_token,
|
||||||
void deleteLeftUsers(const std::string &user_id);
|
const mtx::responses::QueryKeys &keyQuery);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Save an invited room.
|
//! Save an invited room.
|
||||||
|
@ -539,12 +547,12 @@ private:
|
||||||
return lmdb::dbi::open(txn, "presence", MDB_CREATE);
|
return lmdb::dbi::open(txn, "presence", MDB_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
lmdb::dbi getUserCacheDb(lmdb::txn &txn)
|
lmdb::dbi getUserKeysDb(lmdb::txn &txn)
|
||||||
{
|
{
|
||||||
return lmdb::dbi::open(txn, "user_cache", MDB_CREATE);
|
return lmdb::dbi::open(txn, "user_key", MDB_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
lmdb::dbi getDeviceVerifiedDb(lmdb::txn &txn)
|
lmdb::dbi getVerificationDb(lmdb::txn &txn)
|
||||||
{
|
{
|
||||||
return lmdb::dbi::open(txn, "verified", MDB_CREATE);
|
return lmdb::dbi::open(txn, "verified", MDB_CREATE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1466,35 +1466,43 @@ ChatPage::initiateLogout()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::query_keys(
|
ChatPage::query_keys(const std::string &user_id,
|
||||||
const mtx::requests::QueryKeys &req,
|
std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb)
|
||||||
std::function<void(const mtx::responses::QueryKeys &, mtx::http::RequestErr)> cb)
|
|
||||||
{
|
{
|
||||||
std::string user_id = req.device_keys.begin()->first;
|
auto cache_ = cache::userKeys(user_id);
|
||||||
auto cache_ = cache::getUserCache(user_id);
|
|
||||||
|
|
||||||
if (cache_.has_value()) {
|
if (cache_.has_value()) {
|
||||||
if (cache_.value().isUpdated) {
|
if (!cache_->updated_at.empty() && cache_->updated_at == cache_->last_changed) {
|
||||||
cb(cache_.value().keys, {});
|
cb(cache_.value(), {});
|
||||||
} else {
|
return;
|
||||||
http::client()->query_keys(
|
|
||||||
req,
|
|
||||||
[cb, user_id](const mtx::responses::QueryKeys &res,
|
|
||||||
mtx::http::RequestErr err) {
|
|
||||||
if (err) {
|
|
||||||
nhlog::net()->warn("failed to query device keys: {},{}",
|
|
||||||
err->matrix_error.errcode,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cache::setUserCache(std::move(user_id),
|
|
||||||
std::move(UserCache{res, true}));
|
|
||||||
cb(res, err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
http::client()->query_keys(req, cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mtx::requests::QueryKeys req;
|
||||||
|
req.device_keys[user_id] = {};
|
||||||
|
|
||||||
|
std::string last_changed;
|
||||||
|
if (cache_)
|
||||||
|
last_changed = cache_->last_changed;
|
||||||
|
req.token = last_changed;
|
||||||
|
|
||||||
|
http::client()->query_keys(req,
|
||||||
|
[cb, user_id, last_changed](const mtx::responses::QueryKeys &res,
|
||||||
|
mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
nhlog::net()->warn(
|
||||||
|
"failed to query device keys: {},{}",
|
||||||
|
err->matrix_error.errcode,
|
||||||
|
static_cast<int>(err->status_code));
|
||||||
|
cb({}, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache::updateUserKeys(last_changed, res);
|
||||||
|
|
||||||
|
auto keys = cache::userKeys(user_id);
|
||||||
|
cb(keys.value_or(UserKeyCache{}), err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "CacheCryptoStructs.h"
|
||||||
#include "CacheStructs.h"
|
#include "CacheStructs.h"
|
||||||
#include "CallManager.h"
|
#include "CallManager.h"
|
||||||
#include "CommunitiesList.h"
|
#include "CommunitiesList.h"
|
||||||
|
@ -89,9 +90,8 @@ public:
|
||||||
//! Show the room/group list (if it was visible).
|
//! Show the room/group list (if it was visible).
|
||||||
void showSideBars();
|
void showSideBars();
|
||||||
void initiateLogout();
|
void initiateLogout();
|
||||||
void query_keys(
|
void query_keys(const std::string &req,
|
||||||
const mtx::requests::QueryKeys &req,
|
std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb);
|
||||||
std::function<void(const mtx::responses::QueryKeys &, mtx::http::RequestErr)> cb);
|
|
||||||
void focusMessageInput();
|
void focusMessageInput();
|
||||||
|
|
||||||
QString status() const;
|
QString status() const;
|
||||||
|
|
|
@ -328,22 +328,14 @@ DeviceVerificationFlow::setTransactionId(QString transaction_id_)
|
||||||
void
|
void
|
||||||
DeviceVerificationFlow::setUserId(QString userID)
|
DeviceVerificationFlow::setUserId(QString userID)
|
||||||
{
|
{
|
||||||
this->userId = userID;
|
this->userId = userID;
|
||||||
this->toClient = mtx::identifiers::parse<mtx::identifiers::User>(userID.toStdString());
|
this->toClient = mtx::identifiers::parse<mtx::identifiers::User>(userID.toStdString());
|
||||||
auto user_cache = cache::getUserCache(userID.toStdString());
|
|
||||||
|
|
||||||
if (user_cache.has_value()) {
|
auto user_id = userID.toStdString();
|
||||||
this->callback_fn(user_cache->keys, {}, userID.toStdString());
|
ChatPage::instance()->query_keys(
|
||||||
} else {
|
user_id, [user_id, this](const UserKeyCache &res, mtx::http::RequestErr err) {
|
||||||
mtx::requests::QueryKeys req;
|
this->callback_fn(res, err, user_id);
|
||||||
req.device_keys[userID.toStdString()] = {};
|
});
|
||||||
http::client()->query_keys(
|
|
||||||
req,
|
|
||||||
[user_id = userID.toStdString(), this](const mtx::responses::QueryKeys &res,
|
|
||||||
mtx::http::RequestErr err) {
|
|
||||||
this->callback_fn(res, err, user_id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -622,30 +614,52 @@ DeviceVerificationFlow::sendVerificationKey()
|
||||||
(model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationKey);
|
(model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mtx::events::msg::KeyVerificationMac
|
||||||
|
key_verification_mac(mtx::crypto::SAS *sas,
|
||||||
|
mtx::identifiers::User sender,
|
||||||
|
const std::string &senderDevice,
|
||||||
|
mtx::identifiers::User receiver,
|
||||||
|
const std::string &receiverDevice,
|
||||||
|
const std::string &transactionId,
|
||||||
|
std::map<std::string, std::string> keys)
|
||||||
|
{
|
||||||
|
mtx::events::msg::KeyVerificationMac req;
|
||||||
|
|
||||||
|
std::string info = "MATRIX_KEY_VERIFICATION_MAC" + sender.to_string() + senderDevice +
|
||||||
|
receiver.to_string() + receiverDevice + transactionId;
|
||||||
|
|
||||||
|
std::string key_list;
|
||||||
|
bool first = true;
|
||||||
|
for (const auto &[key_id, key] : keys) {
|
||||||
|
req.mac[key_id] = sas->calculate_mac(key, info + key_id);
|
||||||
|
|
||||||
|
if (!first)
|
||||||
|
key_list += ",";
|
||||||
|
key_list += key_id;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.keys = sas->calculate_mac(key_list, info + "KEY_IDS");
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
//! sends the mac of the keys
|
//! sends the mac of the keys
|
||||||
void
|
void
|
||||||
DeviceVerificationFlow::sendVerificationMac()
|
DeviceVerificationFlow::sendVerificationMac()
|
||||||
{
|
{
|
||||||
mtx::events::msg::KeyVerificationMac req;
|
std::map<std::string, std::string> key_list;
|
||||||
|
key_list["ed25519:" + http::client()->device_id()] = olm::client()->identity_keys().ed25519;
|
||||||
|
|
||||||
std::string info = "MATRIX_KEY_VERIFICATION_MAC" + http::client()->user_id().to_string() +
|
mtx::events::msg::KeyVerificationMac req =
|
||||||
http::client()->device_id() + this->toClient.to_string() +
|
key_verification_mac(sas.get(),
|
||||||
this->deviceId.toStdString() + this->transaction_id;
|
http::client()->user_id(),
|
||||||
|
http::client()->device_id(),
|
||||||
//! this vector stores the type of the key and the key
|
this->toClient,
|
||||||
std::vector<std::pair<std::string, std::string>> key_list;
|
this->deviceId.toStdString(),
|
||||||
key_list.push_back(make_pair("ed25519", olm::client()->identity_keys().ed25519));
|
this->transaction_id,
|
||||||
std::sort(key_list.begin(), key_list.end());
|
key_list);
|
||||||
for (auto x : key_list) {
|
|
||||||
req.mac.insert(
|
|
||||||
std::make_pair(x.first + ":" + http::client()->device_id(),
|
|
||||||
this->sas->calculate_mac(
|
|
||||||
x.second, info + x.first + ":" + http::client()->device_id())));
|
|
||||||
req.keys += x.first + ":" + http::client()->device_id() + ",";
|
|
||||||
}
|
|
||||||
|
|
||||||
req.keys =
|
|
||||||
this->sas->calculate_mac(req.keys.substr(0, req.keys.size() - 1), info + "KEY_IDS");
|
|
||||||
|
|
||||||
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
||||||
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationMac> body;
|
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationMac> body;
|
||||||
|
@ -673,27 +687,16 @@ DeviceVerificationFlow::sendVerificationMac()
|
||||||
void
|
void
|
||||||
DeviceVerificationFlow::acceptDevice()
|
DeviceVerificationFlow::acceptDevice()
|
||||||
{
|
{
|
||||||
auto verified_cache = cache::getVerifiedCache(this->userId.toStdString());
|
cache::markDeviceVerified(this->userId.toStdString(), this->deviceId.toStdString());
|
||||||
if (verified_cache.has_value()) {
|
|
||||||
verified_cache->device_verified.push_back(this->deviceId.toStdString());
|
|
||||||
verified_cache->device_blocked.erase(
|
|
||||||
std::remove(verified_cache->device_blocked.begin(),
|
|
||||||
verified_cache->device_blocked.end(),
|
|
||||||
this->deviceId.toStdString()),
|
|
||||||
verified_cache->device_blocked.end());
|
|
||||||
} else {
|
|
||||||
cache::setVerifiedCache(
|
|
||||||
this->userId.toStdString(),
|
|
||||||
DeviceVerifiedCache{{this->deviceId.toStdString()}, {}, {}});
|
|
||||||
}
|
|
||||||
|
|
||||||
emit deviceVerified();
|
emit deviceVerified();
|
||||||
emit refreshProfile();
|
emit refreshProfile();
|
||||||
this->deleteLater();
|
this->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! callback function to keep track of devices
|
//! callback function to keep track of devices
|
||||||
void
|
void
|
||||||
DeviceVerificationFlow::callback_fn(const mtx::responses::QueryKeys &res,
|
DeviceVerificationFlow::callback_fn(const UserKeyCache &res,
|
||||||
mtx::http::RequestErr err,
|
mtx::http::RequestErr err,
|
||||||
std::string user_id)
|
std::string user_id)
|
||||||
{
|
{
|
||||||
|
@ -704,35 +707,22 @@ DeviceVerificationFlow::callback_fn(const mtx::responses::QueryKeys &res,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.device_keys.empty() || (res.device_keys.find(user_id) == res.device_keys.end())) {
|
if (res.device_keys.empty() ||
|
||||||
|
(res.device_keys.find(deviceId.toStdString()) == res.device_keys.end())) {
|
||||||
nhlog::net()->warn("no devices retrieved {}", user_id);
|
nhlog::net()->warn("no devices retrieved {}", user_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto x : res.device_keys) {
|
for (const auto &[algorithm, key] : res.device_keys.at(deviceId.toStdString()).keys) {
|
||||||
for (auto y : x.second) {
|
// TODO: Verify Signatures
|
||||||
auto z = y.second;
|
this->device_keys[algorithm] = key;
|
||||||
if (z.user_id == user_id && z.device_id == this->deviceId.toStdString()) {
|
|
||||||
for (auto a : z.keys) {
|
|
||||||
// TODO: Verify Signatures
|
|
||||||
this->device_keys[a.first] = a.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DeviceVerificationFlow::unverify()
|
DeviceVerificationFlow::unverify()
|
||||||
{
|
{
|
||||||
auto verified_cache = cache::getVerifiedCache(this->userId.toStdString());
|
cache::markDeviceUnverified(this->userId.toStdString(), this->deviceId.toStdString());
|
||||||
if (verified_cache.has_value()) {
|
|
||||||
auto it = std::remove(verified_cache->device_verified.begin(),
|
|
||||||
verified_cache->device_verified.end(),
|
|
||||||
this->deviceId.toStdString());
|
|
||||||
verified_cache->device_verified.erase(it);
|
|
||||||
cache::setVerifiedCache(this->userId.toStdString(), verified_cache.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
emit refreshProfile();
|
emit refreshProfile();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Olm.h"
|
|
||||||
|
|
||||||
#include "MatrixClient.h"
|
|
||||||
#include "mtx/responses/crypto.hpp"
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <mtx/responses/crypto.hpp>
|
||||||
|
|
||||||
|
#include "CacheCryptoStructs.h"
|
||||||
|
#include "MatrixClient.h"
|
||||||
|
#include "Olm.h"
|
||||||
|
|
||||||
class QTimer;
|
class QTimer;
|
||||||
|
|
||||||
using sas_ptr = std::unique_ptr<mtx::crypto::SAS>;
|
using sas_ptr = std::unique_ptr<mtx::crypto::SAS>;
|
||||||
|
@ -71,9 +73,7 @@ public:
|
||||||
void setSender(bool sender_);
|
void setSender(bool sender_);
|
||||||
void setEventId(std::string event_id);
|
void setEventId(std::string event_id);
|
||||||
|
|
||||||
void callback_fn(const mtx::responses::QueryKeys &res,
|
void callback_fn(const UserKeyCache &res, mtx::http::RequestErr err, std::string user_id);
|
||||||
mtx::http::RequestErr err,
|
|
||||||
std::string user_id);
|
|
||||||
|
|
||||||
nlohmann::json canonical_json;
|
nlohmann::json canonical_json;
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -89,12 +89,10 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
{
|
{
|
||||||
auto localUser = utils::localUser();
|
auto localUser = utils::localUser();
|
||||||
|
|
||||||
mtx::requests::QueryKeys req;
|
|
||||||
req.device_keys[userID.toStdString()] = {};
|
|
||||||
ChatPage::instance()->query_keys(
|
ChatPage::instance()->query_keys(
|
||||||
req,
|
userID.toStdString(),
|
||||||
[user_id = userID.toStdString(), this](const mtx::responses::QueryKeys &res,
|
[other_user_id = userID.toStdString(), this](const UserKeyCache &other_user_keys,
|
||||||
mtx::http::RequestErr err) {
|
mtx::http::RequestErr err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
nhlog::net()->warn("failed to query device keys: {},{}",
|
nhlog::net()->warn("failed to query device keys: {},{}",
|
||||||
err->matrix_error.errcode,
|
err->matrix_error.errcode,
|
||||||
|
@ -102,20 +100,11 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.device_keys.empty() ||
|
|
||||||
(res.device_keys.find(user_id) == res.device_keys.end())) {
|
|
||||||
nhlog::net()->warn("no devices retrieved {}", user_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finding if the User is Verified or not based on the Signatures
|
// Finding if the User is Verified or not based on the Signatures
|
||||||
mtx::requests::QueryKeys req;
|
|
||||||
req.device_keys[utils::localUser().toStdString()] = {};
|
|
||||||
|
|
||||||
ChatPage::instance()->query_keys(
|
ChatPage::instance()->query_keys(
|
||||||
req,
|
utils::localUser().toStdString(),
|
||||||
[user_id, other_res = res, this](const mtx::responses::QueryKeys &res,
|
[other_user_id, other_user_keys, this](const UserKeyCache &res,
|
||||||
mtx::http::RequestErr err) {
|
mtx::http::RequestErr err) {
|
||||||
using namespace mtx;
|
using namespace mtx;
|
||||||
std::string local_user_id = utils::localUser().toStdString();
|
std::string local_user_id = utils::localUser().toStdString();
|
||||||
|
|
||||||
|
@ -126,34 +115,28 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.device_keys.empty() ||
|
if (res.device_keys.empty()) {
|
||||||
(res.device_keys.find(local_user_id) == res.device_keys.end())) {
|
nhlog::net()->warn("no devices retrieved {}", local_user_id);
|
||||||
nhlog::net()->warn("no devices retrieved {}", user_id);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DeviceInfo> deviceInfo;
|
std::vector<DeviceInfo> deviceInfo;
|
||||||
auto devices = other_res.device_keys.at(user_id);
|
auto devices = other_user_keys.device_keys;
|
||||||
auto device_verified = cache::getVerifiedCache(user_id);
|
auto device_verified = cache::verificationStatus(other_user_id);
|
||||||
|
|
||||||
if (device_verified.has_value()) {
|
if (device_verified.has_value()) {
|
||||||
isUserVerified = device_verified.value().is_user_verified;
|
// TODO: properly check cross-signing signatures here
|
||||||
|
isUserVerified = !device_verified->verified_master_key.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<crypto::CrossSigningKeys> lmk, lsk, luk, mk, sk, uk;
|
std::optional<crypto::CrossSigningKeys> lmk, lsk, luk, mk, sk, uk;
|
||||||
|
|
||||||
if (!res.master_keys.empty())
|
lmk = res.master_keys;
|
||||||
lmk = res.master_keys.at(local_user_id);
|
luk = res.user_signing_keys;
|
||||||
if (!res.user_signing_keys.empty())
|
lsk = res.self_signing_keys;
|
||||||
luk = res.user_signing_keys.at(local_user_id);
|
mk = other_user_keys.master_keys;
|
||||||
if (!res.self_signing_keys.empty())
|
uk = other_user_keys.user_signing_keys;
|
||||||
lsk = res.self_signing_keys.at(local_user_id);
|
sk = other_user_keys.self_signing_keys;
|
||||||
if (!other_res.master_keys.empty())
|
|
||||||
mk = other_res.master_keys.at(user_id);
|
|
||||||
if (!other_res.user_signing_keys.empty())
|
|
||||||
uk = other_res.user_signing_keys.at(user_id);
|
|
||||||
if (!other_res.self_signing_keys.empty())
|
|
||||||
sk = other_res.self_signing_keys.at(user_id);
|
|
||||||
|
|
||||||
// First checking if the user is verified
|
// First checking if the user is verified
|
||||||
if (luk.has_value() && mk.has_value()) {
|
if (luk.has_value() && mk.has_value()) {
|
||||||
|
@ -202,7 +185,7 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
device_verified->device_blocked.end())
|
device_verified->device_blocked.end())
|
||||||
verified = verification::Status::BLOCKED;
|
verified = verification::Status::BLOCKED;
|
||||||
} else if (isUserVerified) {
|
} else if (isUserVerified) {
|
||||||
device_verified = DeviceVerifiedCache{};
|
device_verified = VerificationCache{};
|
||||||
}
|
}
|
||||||
|
|
||||||
// won't check for already verified devices
|
// won't check for already verified devices
|
||||||
|
@ -211,7 +194,7 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
if ((sk.has_value()) && (!device.signatures.empty())) {
|
if ((sk.has_value()) && (!device.signatures.empty())) {
|
||||||
for (auto sign_key : sk.value().keys) {
|
for (auto sign_key : sk.value().keys) {
|
||||||
auto signs =
|
auto signs =
|
||||||
device.signatures.at(user_id);
|
device.signatures.at(other_user_id);
|
||||||
try {
|
try {
|
||||||
if (olm::client()
|
if (olm::client()
|
||||||
->ed25519_verify_sig(
|
->ed25519_verify_sig(
|
||||||
|
@ -232,12 +215,13 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device_verified.has_value()) {
|
// TODO(Nico): properly show cross-signing
|
||||||
device_verified.value().is_user_verified =
|
// if (device_verified.has_value()) {
|
||||||
isUserVerified;
|
// device_verified.value().is_user_verified =
|
||||||
cache::setVerifiedCache(user_id,
|
// isUserVerified;
|
||||||
device_verified.value());
|
// cache::setVerifiedCache(user_id,
|
||||||
}
|
// device_verified.value());
|
||||||
|
//}
|
||||||
|
|
||||||
deviceInfo.push_back(
|
deviceInfo.push_back(
|
||||||
{QString::fromStdString(d.first),
|
{QString::fromStdString(d.first),
|
||||||
|
|
Loading…
Reference in a new issue