Support bootstrapping crosssigning
Showing the bootstrap state and showing there are unverified devices is still missing.
This commit is contained in:
parent
c514acb7c5
commit
ad1e6c8298
20 changed files with 834 additions and 68 deletions
|
|
@ -201,6 +201,18 @@ Cache::Cache(const QString &userId, QObject *parent)
|
|||
{
|
||||
setup();
|
||||
connect(this, &Cache::userKeysUpdate, this, &Cache::updateUserKeys, Qt::QueuedConnection);
|
||||
connect(
|
||||
this,
|
||||
&Cache::verificationStatusChanged,
|
||||
this,
|
||||
[this](const std::string &u) {
|
||||
if (u == localUserId_.toStdString()) {
|
||||
auto status = verificationStatus(u);
|
||||
if (status.unverified_device_count || !status.user_verified)
|
||||
emit selfUnverified();
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -310,6 +310,7 @@ signals:
|
|||
void removeNotification(const QString &room_id, const QString &event_id);
|
||||
void userKeysUpdate(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
|
||||
void verificationStatusChanged(const std::string &userid);
|
||||
void selfUnverified();
|
||||
void secretChanged(const std::string name);
|
||||
|
||||
private:
|
||||
|
|
|
|||
249
src/SelfVerificationStatus.cpp
Normal file
249
src/SelfVerificationStatus.cpp
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "SelfVerificationStatus.h"
|
||||
|
||||
#include "Cache_p.h"
|
||||
#include "Logging.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "Olm.h"
|
||||
#include "ui/UIA.h"
|
||||
|
||||
#include <mtx/responses/common.hpp>
|
||||
|
||||
SelfVerificationStatus::SelfVerificationStatus(QObject *o)
|
||||
: QObject(o)
|
||||
{
|
||||
connect(MainWindow::instance(), &MainWindow::reload, this, [this] {
|
||||
connect(cache::client(),
|
||||
&Cache::selfUnverified,
|
||||
this,
|
||||
&SelfVerificationStatus::invalidate,
|
||||
Qt::UniqueConnection);
|
||||
invalidate();
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
SelfVerificationStatus::setupCrosssigning(bool useSSSS, QString password, bool useOnlineKeyBackup)
|
||||
{
|
||||
nhlog::db()->info("Clicked setup crossigning");
|
||||
|
||||
auto xsign_keys = olm::client()->create_crosssigning_keys();
|
||||
|
||||
if (!xsign_keys) {
|
||||
nhlog::crypto()->critical("Failed to setup cross-signing keys!");
|
||||
emit setupFailed(tr("Failed to create keys for cross-signing!"));
|
||||
return;
|
||||
}
|
||||
|
||||
cache::client()->storeSecret(mtx::secret_storage::secrets::cross_signing_master,
|
||||
xsign_keys->private_master_key);
|
||||
cache::client()->storeSecret(mtx::secret_storage::secrets::cross_signing_self_signing,
|
||||
xsign_keys->private_self_signing_key);
|
||||
cache::client()->storeSecret(mtx::secret_storage::secrets::cross_signing_user_signing,
|
||||
xsign_keys->private_user_signing_key);
|
||||
|
||||
std::optional<mtx::crypto::OlmClient::OnlineKeyBackupSetup> okb;
|
||||
if (useOnlineKeyBackup) {
|
||||
okb = olm::client()->create_online_key_backup(xsign_keys->private_master_key);
|
||||
if (!okb) {
|
||||
nhlog::crypto()->critical("Failed to setup online key backup!");
|
||||
emit setupFailed(tr("Failed to create keys for online key backup!"));
|
||||
return;
|
||||
}
|
||||
|
||||
cache::client()->storeSecret(
|
||||
mtx::secret_storage::secrets::megolm_backup_v1,
|
||||
mtx::crypto::bin2base64(mtx::crypto::to_string(okb->privateKey)));
|
||||
|
||||
http::client()->post_backup_version(
|
||||
okb->backupVersion.algorithm,
|
||||
okb->backupVersion.auth_data,
|
||||
[](const mtx::responses::Version &v, mtx::http::RequestErr e) {
|
||||
if (e) {
|
||||
nhlog::net()->error("error setting up online key backup: {} {} {} {}",
|
||||
e->parse_error,
|
||||
e->status_code,
|
||||
e->error_code,
|
||||
e->matrix_error.error);
|
||||
} else {
|
||||
nhlog::crypto()->info("Set up online key backup: '{}'", v.version);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<mtx::crypto::OlmClient::SSSSSetup> ssss;
|
||||
if (useSSSS) {
|
||||
ssss = olm::client()->create_ssss_key(password.toStdString());
|
||||
if (!ssss) {
|
||||
nhlog::crypto()->critical("Failed to setup secure server side secret storage!");
|
||||
emit setupFailed(tr("Failed to create keys secure server side secret storage!"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto master = mtx::crypto::PkSigning::from_seed(xsign_keys->private_master_key);
|
||||
nlohmann::json j = ssss->keyDescription;
|
||||
j.erase("signatures");
|
||||
ssss->keyDescription
|
||||
.signatures[http::client()->user_id().to_string()]["ed25519:" + master.public_key()] =
|
||||
master.sign(j.dump());
|
||||
|
||||
http::client()->upload_secret_storage_key(
|
||||
ssss->keyDescription.name, ssss->keyDescription, [](mtx::http::RequestErr) {});
|
||||
http::client()->set_secret_storage_default_key(ssss->keyDescription.name,
|
||||
[](mtx::http::RequestErr) {});
|
||||
|
||||
auto uploadSecret = [ssss](const std::string &key_name, const std::string &secret) {
|
||||
mtx::secret_storage::Secret s;
|
||||
s.encrypted[ssss->keyDescription.name] =
|
||||
mtx::crypto::encrypt(secret, ssss->privateKey, key_name);
|
||||
http::client()->upload_secret_storage_secret(
|
||||
key_name, s, [key_name](mtx::http::RequestErr) {
|
||||
nhlog::crypto()->info("Uploaded secret: {}", key_name);
|
||||
});
|
||||
};
|
||||
|
||||
uploadSecret(mtx::secret_storage::secrets::cross_signing_master,
|
||||
xsign_keys->private_master_key);
|
||||
uploadSecret(mtx::secret_storage::secrets::cross_signing_self_signing,
|
||||
xsign_keys->private_self_signing_key);
|
||||
uploadSecret(mtx::secret_storage::secrets::cross_signing_user_signing,
|
||||
xsign_keys->private_user_signing_key);
|
||||
|
||||
if (okb)
|
||||
uploadSecret(mtx::secret_storage::secrets::megolm_backup_v1,
|
||||
mtx::crypto::bin2base64(mtx::crypto::to_string(okb->privateKey)));
|
||||
}
|
||||
|
||||
mtx::requests::DeviceSigningUpload device_sign{};
|
||||
device_sign.master_key = xsign_keys->master_key;
|
||||
device_sign.self_signing_key = xsign_keys->self_signing_key;
|
||||
device_sign.user_signing_key = xsign_keys->user_signing_key;
|
||||
http::client()->device_signing_upload(
|
||||
device_sign,
|
||||
UIA::instance()->genericHandler(tr("Encryption Setup")),
|
||||
[this, ssss, xsign_keys](mtx::http::RequestErr e) {
|
||||
if (e) {
|
||||
nhlog::crypto()->critical("Failed to upload cross signing keys: {}",
|
||||
e->matrix_error.error);
|
||||
|
||||
emit setupFailed(tr("Encryption setup failed: %1")
|
||||
.arg(QString::fromStdString(e->matrix_error.error)));
|
||||
return;
|
||||
}
|
||||
nhlog::crypto()->info("Crosssigning keys uploaded!");
|
||||
|
||||
auto deviceKeys = cache::client()->userKeys(http::client()->user_id().to_string());
|
||||
if (deviceKeys) {
|
||||
auto myKey = deviceKeys->device_keys.at(http::client()->device_id());
|
||||
if (myKey.user_id == http::client()->user_id().to_string() &&
|
||||
myKey.device_id == http::client()->device_id() &&
|
||||
myKey.keys["ed25519:" + http::client()->device_id()] ==
|
||||
olm::client()->identity_keys().ed25519 &&
|
||||
myKey.keys["curve25519:" + http::client()->device_id()] ==
|
||||
olm::client()->identity_keys().curve25519) {
|
||||
json j = myKey;
|
||||
j.erase("signatures");
|
||||
j.erase("unsigned");
|
||||
|
||||
auto ssk =
|
||||
mtx::crypto::PkSigning::from_seed(xsign_keys->private_self_signing_key);
|
||||
myKey.signatures[http::client()->user_id().to_string()]
|
||||
["ed25519:" + ssk.public_key()] = ssk.sign(j.dump());
|
||||
mtx::requests::KeySignaturesUpload req;
|
||||
req.signatures[http::client()->user_id().to_string()]
|
||||
[http::client()->device_id()] = myKey;
|
||||
|
||||
http::client()->keys_signatures_upload(
|
||||
req,
|
||||
[](const mtx::responses::KeySignaturesUpload &res, mtx::http::RequestErr err) {
|
||||
if (err) {
|
||||
nhlog::net()->error("failed to upload signatures: {},{}",
|
||||
mtx::errors::to_string(err->matrix_error.errcode),
|
||||
static_cast<int>(err->status_code));
|
||||
}
|
||||
|
||||
for (const auto &[user_id, tmp] : res.errors)
|
||||
for (const auto &[key_id, e] : tmp)
|
||||
nhlog::net()->error("signature error for user {} and key "
|
||||
"id {}: {}, {}",
|
||||
user_id,
|
||||
key_id,
|
||||
mtx::errors::to_string(e.errcode),
|
||||
e.error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (ssss) {
|
||||
auto k = QString::fromStdString(mtx::crypto::key_to_recoverykey(ssss->privateKey));
|
||||
|
||||
QString r;
|
||||
for (int i = 0; i < k.size(); i += 4)
|
||||
r += k.mid(i, 4) + " ";
|
||||
|
||||
emit showRecoveryKey(r.trimmed());
|
||||
} else {
|
||||
emit setupCompleted();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
SelfVerificationStatus::verifyMasterKey()
|
||||
{
|
||||
nhlog::db()->info("Clicked verify master key");
|
||||
}
|
||||
|
||||
void
|
||||
SelfVerificationStatus::verifyUnverifiedDevices()
|
||||
{
|
||||
nhlog::db()->info("Clicked verify unverified devices");
|
||||
}
|
||||
|
||||
void
|
||||
SelfVerificationStatus::invalidate()
|
||||
{
|
||||
nhlog::db()->info("Invalidating self verification status");
|
||||
auto keys = cache::client()->userKeys(http::client()->user_id().to_string());
|
||||
if (!keys) {
|
||||
cache::client()->query_keys(http::client()->user_id().to_string(),
|
||||
[](const UserKeyCache &, mtx::http::RequestErr) {});
|
||||
return;
|
||||
}
|
||||
|
||||
if (keys->master_keys.keys.empty()) {
|
||||
if (status_ != SelfVerificationStatus::NoMasterKey) {
|
||||
this->status_ = SelfVerificationStatus::NoMasterKey;
|
||||
emit statusChanged();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto verifStatus = cache::client()->verificationStatus(http::client()->user_id().to_string());
|
||||
|
||||
if (!verifStatus.user_verified) {
|
||||
if (status_ != SelfVerificationStatus::UnverifiedMasterKey) {
|
||||
this->status_ = SelfVerificationStatus::UnverifiedMasterKey;
|
||||
emit statusChanged();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (verifStatus.unverified_device_count > 0) {
|
||||
if (status_ != SelfVerificationStatus::UnverifiedDevices) {
|
||||
this->status_ = SelfVerificationStatus::UnverifiedDevices;
|
||||
emit statusChanged();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (status_ != SelfVerificationStatus::AllVerified) {
|
||||
this->status_ = SelfVerificationStatus::AllVerified;
|
||||
emit statusChanged();
|
||||
return;
|
||||
}
|
||||
}
|
||||
43
src/SelfVerificationStatus.h
Normal file
43
src/SelfVerificationStatus.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class SelfVerificationStatus : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
||||
|
||||
public:
|
||||
SelfVerificationStatus(QObject *o = nullptr);
|
||||
enum Status
|
||||
{
|
||||
AllVerified,
|
||||
NoMasterKey,
|
||||
UnverifiedMasterKey,
|
||||
UnverifiedDevices,
|
||||
};
|
||||
Q_ENUM(Status)
|
||||
|
||||
Q_INVOKABLE void setupCrosssigning(bool useSSSS, QString password, bool useOnlineKeyBackup);
|
||||
Q_INVOKABLE void verifyMasterKey();
|
||||
Q_INVOKABLE void verifyUnverifiedDevices();
|
||||
|
||||
Status status() const { return status_; }
|
||||
|
||||
signals:
|
||||
void statusChanged();
|
||||
void setupCompleted();
|
||||
void showRecoveryKey(QString key);
|
||||
void setupFailed(QString message);
|
||||
|
||||
public slots:
|
||||
void invalidate();
|
||||
|
||||
private:
|
||||
Status status_ = AllVerified;
|
||||
};
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
#include "ReadReceiptsModel.h"
|
||||
#include "RoomDirectoryModel.h"
|
||||
#include "RoomsModel.h"
|
||||
#include "SelfVerificationStatus.h"
|
||||
#include "SingleImagePackModel.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "UsersModel.h"
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
#include "ui/NhekoCursorShape.h"
|
||||
#include "ui/NhekoDropArea.h"
|
||||
#include "ui/NhekoGlobalObject.h"
|
||||
#include "ui/UIA.h"
|
||||
|
||||
Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents)
|
||||
Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
|
||||
|
|
@ -212,18 +214,9 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||
"ReadReceiptsProxy needs to be instantiated on the C++ side");
|
||||
|
||||
static auto self = this;
|
||||
qmlRegisterSingletonType<MainWindow>(
|
||||
"im.nheko", 1, 0, "MainWindow", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
auto ptr = MainWindow::instance();
|
||||
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
|
||||
return ptr;
|
||||
});
|
||||
qmlRegisterSingletonType<TimelineViewManager>(
|
||||
"im.nheko", 1, 0, "TimelineManager", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
auto ptr = self;
|
||||
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
|
||||
return ptr;
|
||||
});
|
||||
qmlRegisterSingletonInstance("im.nheko", 1, 0, "MainWindow", MainWindow::instance());
|
||||
qmlRegisterSingletonInstance("im.nheko", 1, 0, "TimelineManager", self);
|
||||
qmlRegisterSingletonInstance("im.nheko", 1, 0, "UIA", UIA::instance());
|
||||
qmlRegisterSingletonType<RoomlistModel>(
|
||||
"im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
auto ptr = new FilteredRoomlistModel(self->rooms_);
|
||||
|
|
@ -238,24 +231,11 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||
&FilteredRoomlistModel::updateHiddenTagsAndSpaces);
|
||||
return ptr;
|
||||
});
|
||||
qmlRegisterSingletonType<RoomlistModel>(
|
||||
"im.nheko", 1, 0, "Communities", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
auto ptr = self->communities_;
|
||||
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
|
||||
return ptr;
|
||||
});
|
||||
qmlRegisterSingletonType<UserSettings>(
|
||||
"im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
auto ptr = ChatPage::instance()->userSettings().data();
|
||||
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
|
||||
return ptr;
|
||||
});
|
||||
qmlRegisterSingletonType<CallManager>(
|
||||
"im.nheko", 1, 0, "CallManager", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
auto ptr = ChatPage::instance()->callManager();
|
||||
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
|
||||
return ptr;
|
||||
});
|
||||
qmlRegisterSingletonInstance("im.nheko", 1, 0, "Communities", self->communities_);
|
||||
qmlRegisterSingletonInstance(
|
||||
"im.nheko", 1, 0, "Settings", ChatPage::instance()->userSettings().data());
|
||||
qmlRegisterSingletonInstance(
|
||||
"im.nheko", 1, 0, "CallManager", ChatPage::instance()->callManager());
|
||||
qmlRegisterSingletonType<Clipboard>(
|
||||
"im.nheko", 1, 0, "Clipboard", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
return new Clipboard();
|
||||
|
|
@ -264,6 +244,10 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||
"im.nheko", 1, 0, "Nheko", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
return new Nheko();
|
||||
});
|
||||
qmlRegisterSingletonType<SelfVerificationStatus>(
|
||||
"im.nheko", 1, 0, "SelfVerificationStatus", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
return new SelfVerificationStatus();
|
||||
});
|
||||
|
||||
qRegisterMetaType<mtx::events::collections::TimelineEvents>();
|
||||
qRegisterMetaType<std::vector<DeviceInfo>>();
|
||||
|
|
|
|||
136
src/ui/UIA.cpp
Normal file
136
src/ui/UIA.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "UIA.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QTimer>
|
||||
|
||||
#include "Logging.h"
|
||||
#include "MainWindow.h"
|
||||
#include "dialogs/FallbackAuth.h"
|
||||
#include "dialogs/ReCaptcha.h"
|
||||
|
||||
UIA *
|
||||
UIA::instance()
|
||||
{
|
||||
static UIA uia;
|
||||
return &uia;
|
||||
}
|
||||
|
||||
mtx::http::UIAHandler
|
||||
UIA::genericHandler(QString context)
|
||||
{
|
||||
return mtx::http::UIAHandler([this, context](const mtx::http::UIAHandler &h,
|
||||
const mtx::user_interactive::Unauthorized &u) {
|
||||
QTimer::singleShot(0, this, [this, h, u, context]() {
|
||||
this->currentHandler = h;
|
||||
this->currentStatus = u;
|
||||
this->title_ = context;
|
||||
emit titleChanged();
|
||||
|
||||
std::vector<mtx::user_interactive::Flow> flows = u.flows;
|
||||
|
||||
nhlog::ui()->info("Completed stages: {}", u.completed.size());
|
||||
|
||||
if (!u.completed.empty()) {
|
||||
// Get rid of all flows which don't start with the sequence of
|
||||
// stages that have already been completed.
|
||||
flows.erase(std::remove_if(flows.begin(),
|
||||
flows.end(),
|
||||
[completed_stages = u.completed](auto flow) {
|
||||
if (completed_stages.size() > flow.stages.size())
|
||||
return true;
|
||||
for (size_t f = 0; f < completed_stages.size(); f++)
|
||||
if (completed_stages[f] != flow.stages[f])
|
||||
return true;
|
||||
return false;
|
||||
}),
|
||||
flows.end());
|
||||
}
|
||||
|
||||
if (flows.empty()) {
|
||||
nhlog::ui()->error("No available registration flows!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto current_stage = flows.front().stages.at(u.completed.size());
|
||||
|
||||
if (current_stage == mtx::user_interactive::auth_types::password) {
|
||||
emit password();
|
||||
} else if (current_stage == mtx::user_interactive::auth_types::recaptcha) {
|
||||
auto captchaDialog =
|
||||
new dialogs::ReCaptcha(QString::fromStdString(u.session), MainWindow::instance());
|
||||
captchaDialog->setWindowTitle(context);
|
||||
|
||||
connect(
|
||||
captchaDialog, &dialogs::ReCaptcha::confirmation, this, [captchaDialog, h, u]() {
|
||||
captchaDialog->close();
|
||||
captchaDialog->deleteLater();
|
||||
h.next(mtx::user_interactive::Auth{u.session,
|
||||
mtx::user_interactive::auth::Fallback{}});
|
||||
});
|
||||
|
||||
// connect(
|
||||
// captchaDialog, &dialogs::ReCaptcha::cancel, this, &RegisterPage::errorOccurred);
|
||||
|
||||
QTimer::singleShot(0, this, [captchaDialog]() { captchaDialog->show(); });
|
||||
|
||||
} else if (current_stage == mtx::user_interactive::auth_types::dummy) {
|
||||
h.next(
|
||||
mtx::user_interactive::Auth{u.session, mtx::user_interactive::auth::Dummy{}});
|
||||
|
||||
} else if (current_stage == mtx::user_interactive::auth_types::registration_token) {
|
||||
bool ok;
|
||||
QString token =
|
||||
QInputDialog::getText(MainWindow::instance(),
|
||||
context,
|
||||
tr("Please enter a valid registration token."),
|
||||
QLineEdit::Normal,
|
||||
QString(),
|
||||
&ok);
|
||||
|
||||
if (ok) {
|
||||
h.next(mtx::user_interactive::Auth{
|
||||
u.session,
|
||||
mtx::user_interactive::auth::RegistrationToken{token.toStdString()}});
|
||||
} else {
|
||||
// emit errorOccurred();
|
||||
}
|
||||
} else {
|
||||
// use fallback
|
||||
auto dialog = new dialogs::FallbackAuth(QString::fromStdString(current_stage),
|
||||
QString::fromStdString(u.session),
|
||||
MainWindow::instance());
|
||||
dialog->setWindowTitle(context);
|
||||
|
||||
connect(dialog, &dialogs::FallbackAuth::confirmation, this, [h, u, dialog]() {
|
||||
dialog->close();
|
||||
dialog->deleteLater();
|
||||
h.next(mtx::user_interactive::Auth{u.session,
|
||||
mtx::user_interactive::auth::Fallback{}});
|
||||
});
|
||||
|
||||
// connect(dialog, &dialogs::FallbackAuth::cancel, this,
|
||||
// &RegisterPage::errorOccurred);
|
||||
|
||||
dialog->show();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
UIA::continuePassword(QString password)
|
||||
{
|
||||
mtx::user_interactive::auth::Password p{};
|
||||
p.identifier_type = mtx::user_interactive::auth::Password::UserId;
|
||||
p.password = password.toStdString();
|
||||
p.identifier_user = http::client()->user_id().to_string();
|
||||
|
||||
if (currentHandler)
|
||||
currentHandler->next(mtx::user_interactive::Auth{currentStatus.session, p});
|
||||
}
|
||||
40
src/ui/UIA.h
Normal file
40
src/ui/UIA.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <MatrixClient.h>
|
||||
|
||||
class UIA : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
|
||||
|
||||
public:
|
||||
static UIA *instance();
|
||||
|
||||
UIA(QObject *parent = nullptr)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
mtx::http::UIAHandler genericHandler(QString context);
|
||||
|
||||
QString title() const { return title_; }
|
||||
|
||||
public slots:
|
||||
void continuePassword(QString password);
|
||||
|
||||
signals:
|
||||
void password();
|
||||
|
||||
void titleChanged();
|
||||
|
||||
private:
|
||||
std::optional<mtx::http::UIAHandler> currentHandler;
|
||||
mtx::user_interactive::Unauthorized currentStatus;
|
||||
QString title_;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue