#include "UserProfile.h" #include "Cache_p.h" #include "ChatPage.h" #include "DeviceVerificationFlow.h" #include "Logging.h" #include "Utils.h" #include "mtx/responses/crypto.hpp" #include "timeline/TimelineModel.h" #include "timeline/TimelineViewManager.h" UserProfile::UserProfile(QString roomid, QString userid, TimelineViewManager *manager_, TimelineModel *parent) : QObject(parent) , roomid_(roomid) , userid_(userid) , manager(manager_) , model(parent) { 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 DeviceInfoModel::roleNames() const { return { {DeviceId, "deviceId"}, {DeviceName, "deviceName"}, {VerificationStatus, "verificationStatus"}, }; } QVariant DeviceInfoModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= (int)deviceList_.size() || index.row() < 0) return {}; switch (role) { case DeviceId: return deviceList_[index.row()].device_id; case DeviceName: return deviceList_[index.row()].display_name; case VerificationStatus: return QVariant::fromValue(deviceList_[index.row()].verification_status); default: return {}; } } void DeviceInfoModel::reset(const std::vector &deviceList) { beginResetModel(); this->deviceList_ = std::move(deviceList); endResetModel(); } DeviceInfoModel * UserProfile::deviceList() { return &this->deviceList_; } QString UserProfile::userid() { return this->userid_; } QString UserProfile::displayName() { return cache::displayName(roomid_, userid_); } QString UserProfile::avatarUrl() { return cache::avatarUrl(roomid_, userid_); } bool UserProfile::getUserStatus() { return isUserVerified; } bool UserProfile::userVerificationEnabled() const { return hasMasterKey; } bool UserProfile::isSelf() const { return this->userid_ == utils::localUser(); } void UserProfile::fetchDeviceList(const QString &userID) { auto localUser = utils::localUser(); cache::client()->query_keys( userID.toStdString(), [other_user_id = userID.toStdString(), this](const UserKeyCache &other_user_keys, mtx::http::RequestErr err) { if (err) { nhlog::net()->warn("failed to query device keys: {},{}", err->matrix_error.errcode, static_cast(err->status_code)); return; } // Ensure local key cache is up to date cache::client()->query_keys( utils::localUser().toStdString(), [other_user_id, other_user_keys, this](const UserKeyCache &, mtx::http::RequestErr err) { using namespace mtx; std::string local_user_id = utils::localUser().toStdString(); if (err) { nhlog::net()->warn("failed to query device keys: {},{}", err->matrix_error.errcode, static_cast(err->status_code)); return; } this->hasMasterKey = !other_user_keys.master_keys.keys.empty(); std::vector deviceInfo; auto devices = other_user_keys.device_keys; auto verificationStatus = cache::client()->verificationStatus(other_user_id); isUserVerified = verificationStatus.user_verified; emit userStatusChanged(); for (const auto &d : devices) { auto device = d.second; verification::Status verified = verification::Status::UNVERIFIED; if (std::find(verificationStatus.verified_devices.begin(), verificationStatus.verified_devices.end(), device.device_id) != verificationStatus.verified_devices.end() && mtx::crypto::verify_identity_signature( device, DeviceId(device.device_id), UserId(other_user_id))) verified = verification::Status::VERIFIED; deviceInfo.push_back( {QString::fromStdString(d.first), QString::fromStdString( device.unsigned_info.device_display_name), verified}); } this->deviceList_.queueReset(std::move(deviceInfo)); }); }); } void UserProfile::banUser() { ChatPage::instance()->banUser(this->userid_, ""); } // void ignoreUser(){ // } void UserProfile::kickUser() { ChatPage::instance()->kickUser(this->userid_, ""); } void UserProfile::startChat() { ChatPage::instance()->startChat(this->userid_); } void UserProfile::verify(QString device) { if (!device.isEmpty()) manager->verifyDevice(userid_, device); else { manager->verifyUser(userid_); } } void UserProfile::unverify(QString device) { cache::markDeviceUnverified(userid_.toStdString(), device.toStdString()); }