297 lines
9.4 KiB
C++
297 lines
9.4 KiB
C++
// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
|
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
|
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include <QDesktopServices>
|
|
|
|
#include <mtx/identifiers.hpp>
|
|
#include <mtx/requests.hpp>
|
|
#include <mtx/responses/login.hpp>
|
|
|
|
#include "Config.h"
|
|
#include "Logging.h"
|
|
#include "LoginPage.h"
|
|
#include "MainWindow.h"
|
|
#include "MatrixClient.h"
|
|
#include "SSOHandler.h"
|
|
#include "UserSettingsPage.h"
|
|
|
|
Q_DECLARE_METATYPE(LoginPage::LoginMethod)
|
|
|
|
using namespace mtx::identifiers;
|
|
|
|
LoginPage::LoginPage(QObject *parent)
|
|
: QObject(parent)
|
|
, inferredServerAddress_()
|
|
{
|
|
[[maybe_unused]] static auto ignored =
|
|
qRegisterMetaType<LoginPage::LoginMethod>("LoginPage::LoginMethod");
|
|
|
|
connect(this, &LoginPage::versionOkCb, this, &LoginPage::versionOk, Qt::QueuedConnection);
|
|
connect(this, &LoginPage::versionErrorCb, this, &LoginPage::versionError, Qt::QueuedConnection);
|
|
connect(
|
|
this,
|
|
&LoginPage::loginOk,
|
|
this,
|
|
[this](const mtx::responses::Login &res) {
|
|
loggingIn_ = false;
|
|
emit loggingInChanged();
|
|
|
|
http::client()->set_user(res.user_id);
|
|
MainWindow::instance()->showChatPage();
|
|
},
|
|
Qt::QueuedConnection);
|
|
}
|
|
void
|
|
LoginPage::showError(const QString &msg)
|
|
{
|
|
loggingIn_ = false;
|
|
emit loggingInChanged();
|
|
|
|
error_ = msg;
|
|
emit errorOccurred();
|
|
}
|
|
|
|
void
|
|
LoginPage::setHomeserver(QString hs)
|
|
{
|
|
if (hs != homeserver_) {
|
|
homeserver_ = hs;
|
|
homeserverValid_ = false;
|
|
emit homeserverChanged();
|
|
http::client()->set_server(hs.toStdString());
|
|
checkHomeserverVersion();
|
|
}
|
|
}
|
|
|
|
void
|
|
LoginPage::onMatrixIdEntered()
|
|
{
|
|
clearErrors();
|
|
|
|
homeserverValid_ = false;
|
|
emit homeserverChanged();
|
|
|
|
User user;
|
|
try {
|
|
user = parse<User>(mxid_.toStdString());
|
|
} catch (const std::exception &) {
|
|
mxidError_ = tr("You have entered an invalid Matrix ID e.g @joe:matrix.org");
|
|
emit mxidErrorChanged();
|
|
return;
|
|
}
|
|
|
|
if (user.hostname().empty() || user.localpart().empty()) {
|
|
mxidError_ = tr("You have entered an invalid Matrix ID e.g @joe:matrix.org");
|
|
emit mxidErrorChanged();
|
|
return;
|
|
} else {
|
|
nhlog::net()->debug("hostname: {}", user.hostname());
|
|
}
|
|
|
|
if (user.hostname() != inferredServerAddress_.toStdString()) {
|
|
homeserverNeeded_ = false;
|
|
lookingUpHs_ = true;
|
|
emit lookingUpHsChanged();
|
|
|
|
http::client()->set_server(user.hostname());
|
|
http::client()->verify_certificates(
|
|
!UserSettings::instance()->disableCertificateValidation());
|
|
homeserver_ = QString::fromStdString(user.hostname());
|
|
emit homeserverChanged();
|
|
|
|
http::client()->well_known(
|
|
[this](const mtx::responses::WellKnown &res, mtx::http::RequestErr err) {
|
|
if (err) {
|
|
if (err->status_code == 404) {
|
|
nhlog::net()->info("Autodiscovery: No .well-known.");
|
|
checkHomeserverVersion();
|
|
return;
|
|
}
|
|
|
|
if (!err->parse_error.empty()) {
|
|
emit versionErrorCb(tr("Autodiscovery failed. Received malformed response."));
|
|
nhlog::net()->error("Autodiscovery failed. Received malformed response.");
|
|
return;
|
|
}
|
|
|
|
emit versionErrorCb(tr("Autodiscovery failed. Unknown error when "
|
|
"requesting .well-known."));
|
|
nhlog::net()->error("Autodiscovery failed. Unknown error when "
|
|
"requesting .well-known. {} {}",
|
|
err->status_code,
|
|
err->error_code);
|
|
return;
|
|
}
|
|
|
|
nhlog::net()->info("Autodiscovery: Discovered '" + res.homeserver.base_url + "'");
|
|
http::client()->set_server(res.homeserver.base_url);
|
|
emit homeserverChanged();
|
|
checkHomeserverVersion();
|
|
});
|
|
}
|
|
}
|
|
|
|
void
|
|
LoginPage::checkHomeserverVersion()
|
|
{
|
|
clearErrors();
|
|
|
|
try {
|
|
User user = parse<User>(mxid_.toStdString());
|
|
} catch (const std::exception &) {
|
|
mxidError_ = tr("You have entered an invalid Matrix ID e.g @joe:matrix.org");
|
|
emit mxidErrorChanged();
|
|
return;
|
|
}
|
|
|
|
http::client()->versions([this](const mtx::responses::Versions &, mtx::http::RequestErr err) {
|
|
if (err) {
|
|
if (err->status_code == 404) {
|
|
emit versionErrorCb(tr("The required endpoints were not found. "
|
|
"Possibly not a Matrix server."));
|
|
return;
|
|
}
|
|
|
|
if (!err->parse_error.empty()) {
|
|
emit versionErrorCb(tr("Received malformed response. Make sure "
|
|
"the homeserver domain is valid."));
|
|
return;
|
|
}
|
|
|
|
emit versionErrorCb(
|
|
tr("An unknown error occured. Make sure the homeserver domain is valid."));
|
|
return;
|
|
}
|
|
|
|
http::client()->get_login(
|
|
[this](mtx::responses::LoginFlows flows, mtx::http::RequestErr err) {
|
|
if (err || flows.flows.empty())
|
|
emit versionOkCb(true, false);
|
|
|
|
bool ssoSupported = false;
|
|
bool passwordSupported = false;
|
|
for (const auto &flow : flows.flows) {
|
|
if (flow.type == mtx::user_interactive::auth_types::sso) {
|
|
ssoSupported = true;
|
|
} else if (flow.type == mtx::user_interactive::auth_types::password) {
|
|
passwordSupported = true;
|
|
}
|
|
}
|
|
emit versionOkCb(passwordSupported, ssoSupported);
|
|
});
|
|
});
|
|
}
|
|
|
|
void
|
|
LoginPage::versionError(const QString &error)
|
|
{
|
|
showError(error);
|
|
|
|
homeserverNeeded_ = true;
|
|
lookingUpHs_ = false;
|
|
homeserverValid_ = false;
|
|
emit lookingUpHsChanged();
|
|
emit versionLookedUp();
|
|
}
|
|
|
|
void
|
|
LoginPage::versionOk(bool passwordSupported, bool ssoSupported)
|
|
{
|
|
passwordSupported_ = passwordSupported;
|
|
ssoSupported_ = ssoSupported;
|
|
|
|
lookingUpHs_ = false;
|
|
homeserverValid_ = true;
|
|
emit homeserverChanged();
|
|
emit lookingUpHsChanged();
|
|
emit versionLookedUp();
|
|
}
|
|
|
|
void
|
|
LoginPage::onLoginButtonClicked(LoginMethod loginMethod,
|
|
QString userid,
|
|
QString password,
|
|
QString deviceName)
|
|
{
|
|
clearErrors();
|
|
|
|
User user;
|
|
|
|
try {
|
|
user = parse<User>(userid.toStdString());
|
|
} catch (const std::exception &) {
|
|
mxidError_ = tr("You have entered an invalid Matrix ID e.g @joe:matrix.org");
|
|
emit mxidErrorChanged();
|
|
return;
|
|
}
|
|
|
|
if (loginMethod == LoginMethod::Password) {
|
|
if (password.isEmpty())
|
|
return showError(tr("Empty password"));
|
|
|
|
http::client()->login(
|
|
user.localpart(),
|
|
password.toStdString(),
|
|
deviceName.trimmed().isEmpty() ? initialDeviceName_() : deviceName.toStdString(),
|
|
[this](const mtx::responses::Login &res, mtx::http::RequestErr err) {
|
|
if (err) {
|
|
auto error = err->matrix_error.error;
|
|
if (error.empty())
|
|
error = err->parse_error;
|
|
|
|
showError(QString::fromStdString(error));
|
|
return;
|
|
}
|
|
|
|
if (res.well_known) {
|
|
http::client()->set_server(res.well_known->homeserver.base_url);
|
|
nhlog::net()->info("Login requested to user server: " +
|
|
res.well_known->homeserver.base_url);
|
|
}
|
|
|
|
emit loginOk(res);
|
|
});
|
|
} else {
|
|
auto sso = new SSOHandler();
|
|
connect(
|
|
sso, &SSOHandler::ssoSuccess, this, [this, sso, userid, deviceName](std::string token) {
|
|
mtx::requests::Login req{};
|
|
req.token = token;
|
|
req.type = mtx::user_interactive::auth_types::token;
|
|
req.device_id =
|
|
deviceName.trimmed().isEmpty() ? initialDeviceName_() : deviceName.toStdString();
|
|
http::client()->login(
|
|
req, [this](const mtx::responses::Login &res, mtx::http::RequestErr err) {
|
|
if (err) {
|
|
showError(QString::fromStdString(err->matrix_error.error));
|
|
emit errorOccurred();
|
|
return;
|
|
}
|
|
|
|
if (res.well_known) {
|
|
http::client()->set_server(res.well_known->homeserver.base_url);
|
|
nhlog::net()->info("Login requested to user server: " +
|
|
res.well_known->homeserver.base_url);
|
|
}
|
|
|
|
emit loginOk(res);
|
|
});
|
|
sso->deleteLater();
|
|
});
|
|
connect(sso, &SSOHandler::ssoFailed, this, [this, sso]() {
|
|
showError(tr("SSO login failed"));
|
|
emit errorOccurred();
|
|
sso->deleteLater();
|
|
});
|
|
|
|
QDesktopServices::openUrl(
|
|
QString::fromStdString(http::client()->login_sso_redirect(sso->url())));
|
|
}
|
|
|
|
loggingIn_ = true;
|
|
emit loggingInChanged();
|
|
}
|