// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include "DeviceVerificationFlow.h"
#include <tuple>
#include <QDateTime>
#include <QTimer>
#include <nlohmann/json.hpp>
#include "Cache.h"
#include "Cache_p.h"
#include "ChatPage.h"
#include "Logging.h"
#include "MatrixClient.h"
#include "Utils.h"
#include "timeline/TimelineModel.h"
static constexpr int TIMEOUT = 2 * 60 * 1000; // 2 minutes
static constexpr std::string_view mac_method_alg_v1 = "hkdf-hmac-sha256";
static constexpr std::string_view mac_method_alg_v2 = "hkdf-hmac-sha256.v2";
DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
DeviceVerificationFlow::Type flow_type,
TimelineModel *model,
const QString &userID,
const std::vector<QString> &deviceIds_)
: sender(false)
, type(flow_type)
, deviceIds(std::move(deviceIds_))
, model_(model)
{
nhlog::crypto()->debug("CREATING NEW FLOW, {}, {}", static_cast<int>(flow_type), (void *)this);
if (deviceIds.size() == 1)
deviceId = deviceIds.front();
timeout = new QTimer(this);
timeout->setSingleShot(true);
this->sas = olm::client()->sas_init();
this->isMacVerified = false;
auto user_id_ = userID.toStdString();
this->toClient = mtx::identifiers::parse<mtx::identifiers::User>(user_id_);
cache::client()->query_keys(
user_id_, [user_id_, this](const UserKeyCache &res, mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to query device keys: {},{}",
mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
if (!this->deviceId.isEmpty() &&
(res.device_keys.find(deviceId.toStdString()) == res.device_keys.end())) {
nhlog::net()->warn("no devices retrieved {}", user_id_);
return;
}
this->their_keys = res;
});
cache::client()->query_keys(
http::client()->user_id().to_string(),
[this](const UserKeyCache &res, mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to query device keys: {},{}",
mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
if (res.master_keys.keys.empty())
return;
if (auto status = cache::verificationStatus(http::client()->user_id().to_string());
status && status->user_verified == crypto::Trust::Verified)
this->our_trusted_master_key = res.master_keys.keys.begin()->second;
});
if (model) {
connect(this->model_,
&TimelineModel::updateFlowEventId,
this,
[this](const std::string &event_id_) {
this->relation.rel_type = mtx::common::RelationType::Reference;
this->relation.event_id = event_id_;
this->transaction_id = event_id_;
});
}
connect(timeout, &QTimer::timeout, this, [this]() {
nhlog::crypto()->info<