summary refs log tree commit diff
path: root/src/LoginPage.cpp
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2022-01-24 00:41:55 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2022-01-26 21:44:13 +0100
commit4a80fdc951b57647ce9404bbbfe306b459c84f57 (patch)
tree9e61328fd11dfbc95b82d63947fa507659265563 /src/LoginPage.cpp
parentFix focus and qml parenting with qml root (diff)
downloadnheko-4a80fdc951b57647ce9404bbbfe306b459c84f57.tar.xz
Functional login page
Diffstat (limited to 'src/LoginPage.cpp')
-rw-r--r--src/LoginPage.cpp436
1 files changed, 114 insertions, 322 deletions
diff --git a/src/LoginPage.cpp b/src/LoginPage.cpp

index 4c28f364..cfc600ae 100644 --- a/src/LoginPage.cpp +++ b/src/LoginPage.cpp
@@ -5,11 +5,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include <QDesktopServices> -#include <QFontMetrics> -#include <QLabel> -#include <QPainter> -#include <QStyleOption> -#include <QtMath> #include <mtx/identifiers.hpp> #include <mtx/requests.hpp> @@ -18,247 +13,94 @@ #include "Config.h" #include "Logging.h" #include "LoginPage.h" +#include "MainWindow.h" #include "MatrixClient.h" #include "SSOHandler.h" #include "UserSettingsPage.h" -#include "ui/FlatButton.h" -#include "ui/LoadingIndicator.h" -#include "ui/OverlayModal.h" -#include "ui/RaisedButton.h" -#include "ui/TextField.h" Q_DECLARE_METATYPE(LoginPage::LoginMethod) using namespace mtx::identifiers; -LoginPage::LoginPage(QWidget *parent) - : QWidget(parent) +LoginPage::LoginPage(QObject *parent) + : QObject(parent) , inferredServerAddress_() { - qRegisterMetaType<LoginPage::LoginMethod>("LoginPage::LoginMethod"); - - top_layout_ = new QVBoxLayout(); - - top_bar_layout_ = new QHBoxLayout(); - top_bar_layout_->setSpacing(0); - top_bar_layout_->setContentsMargins(0, 0, 0, 0); - - back_button_ = new FlatButton(this); - back_button_->setMinimumSize(QSize(30, 30)); - - top_bar_layout_->addWidget(back_button_, 0, Qt::AlignLeft | Qt::AlignVCenter); - top_bar_layout_->addStretch(1); - - QIcon icon; - icon.addFile(QStringLiteral(":/icons/icons/ui/angle-arrow-left.svg")); - - back_button_->setIcon(icon); - back_button_->setIconSize(QSize(32, 32)); - - QIcon logo; - logo.addFile(QStringLiteral(":/logos/login.png")); - - logo_ = new QLabel(this); - logo_->setPixmap(logo.pixmap(128)); - - logo_layout_ = new QHBoxLayout(); - logo_layout_->setContentsMargins(0, 0, 0, 20); - logo_layout_->addWidget(logo_, 0, Qt::AlignHCenter); - - form_wrapper_ = new QHBoxLayout(); - form_widget_ = new QWidget(); - form_widget_->setMinimumSize(QSize(350, 200)); - - form_layout_ = new QVBoxLayout(); - form_layout_->setSpacing(20); - form_layout_->setContentsMargins(0, 0, 0, 30); - form_widget_->setLayout(form_layout_); - - form_wrapper_->addStretch(1); - form_wrapper_->addWidget(form_widget_); - form_wrapper_->addStretch(1); - - matrixid_input_ = new TextField(this); - matrixid_input_->setLabel(tr("Matrix ID")); - matrixid_input_->setRegexp(QRegularExpression(QStringLiteral("@.+?:.{3,}"))); - matrixid_input_->setPlaceholderText(tr("e.g @joe:matrix.org")); - matrixid_input_->setToolTip( - tr("Your login name. A mxid should start with @ followed by the user id. After the user " - "id you need to include your server name after a :.\nYou can also put your homeserver " - "address there, if your server doesn't support .well-known lookup.\nExample: " - "@user:server.my\nIf Nheko fails to discover your homeserver, it will show you a " - "field to enter the server manually.")); - - spinner_ = new LoadingIndicator(this); - spinner_->setFixedHeight(40); - spinner_->setFixedWidth(40); - spinner_->hide(); - - errorIcon_ = new QLabel(this); - errorIcon_->setPixmap(QPixmap(QStringLiteral(":/icons/icons/error.png"))); - errorIcon_->hide(); - - matrixidLayout_ = new QHBoxLayout(); - matrixidLayout_->addWidget(matrixid_input_, 0, Qt::AlignVCenter); - - QFont font; - - error_matrixid_label_ = new QLabel(this); - error_matrixid_label_->setFont(font); - error_matrixid_label_->setWordWrap(true); - - password_input_ = new TextField(this); - password_input_->setLabel(tr("Password")); - password_input_->setEchoMode(QLineEdit::Password); - password_input_->setToolTip(tr("Your password.")); - - deviceName_ = new TextField(this); - deviceName_->setLabel(tr("Device name")); - deviceName_->setToolTip( - tr("A name for this device, which will be shown to others, when verifying your devices. " - "If none is provided a default is used.")); - - serverInput_ = new TextField(this); - serverInput_->setLabel(tr("Homeserver address")); - serverInput_->setPlaceholderText(tr("server.my:8787")); - serverInput_->setToolTip(tr("The address that can be used to contact you homeservers " - "client API.\nExample: https://server.my:8787")); - serverInput_->hide(); - - serverLayout_ = new QHBoxLayout(); - serverLayout_->addWidget(serverInput_, 0, Qt::AlignVCenter); - - form_layout_->addLayout(matrixidLayout_); - form_layout_->addWidget(error_matrixid_label_, 0, Qt::AlignHCenter); - form_layout_->addWidget(password_input_); - form_layout_->addWidget(deviceName_, Qt::AlignHCenter); - form_layout_->addLayout(serverLayout_); - - error_matrixid_label_->hide(); - - button_layout_ = new QHBoxLayout(); - button_layout_->setSpacing(20); - button_layout_->setContentsMargins(0, 0, 0, 30); - - login_button_ = new RaisedButton(tr("LOGIN"), this); - login_button_->setMinimumSize(150, 65); - login_button_->setFontSize(20); - login_button_->setCornerRadius(3); - - sso_login_button_ = new RaisedButton(tr("SSO LOGIN"), this); - sso_login_button_->setMinimumSize(150, 65); - sso_login_button_->setFontSize(20); - sso_login_button_->setCornerRadius(3); - sso_login_button_->setVisible(false); - - button_layout_->addStretch(1); - button_layout_->addWidget(login_button_); - button_layout_->addWidget(sso_login_button_); - button_layout_->addStretch(1); - - error_label_ = new QLabel(this); - error_label_->setFont(font); - error_label_->setWordWrap(true); - - top_layout_->addLayout(top_bar_layout_); - top_layout_->addStretch(1); - top_layout_->addLayout(logo_layout_); - top_layout_->addLayout(form_wrapper_); - top_layout_->addStretch(1); - top_layout_->addLayout(button_layout_); - top_layout_->addWidget(error_label_, 0, Qt::AlignHCenter); - top_layout_->addStretch(1); - - setLayout(top_layout_); + [[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(); - connect(back_button_, SIGNAL(clicked()), this, SLOT(onBackButtonClicked())); - connect(login_button_, &RaisedButton::clicked, this, [this]() { - onLoginButtonClicked(passwordSupported ? LoginMethod::Password : LoginMethod::SSO); - }); - connect(sso_login_button_, &RaisedButton::clicked, this, [this]() { - onLoginButtonClicked(LoginMethod::SSO); - }); - connect(this, - &LoginPage::showErrorMessage, - this, - static_cast<void (LoginPage::*)(QLabel *, const QString &)>(&LoginPage::showError), - Qt::QueuedConnection); - connect(matrixid_input_, SIGNAL(returnPressed()), login_button_, SLOT(click())); - connect(password_input_, SIGNAL(returnPressed()), login_button_, SLOT(click())); - connect(deviceName_, SIGNAL(returnPressed()), login_button_, SLOT(click())); - connect(serverInput_, SIGNAL(returnPressed()), login_button_, SLOT(click())); - connect(matrixid_input_, SIGNAL(editingFinished()), this, SLOT(onMatrixIdEntered())); - connect(serverInput_, SIGNAL(editingFinished()), this, SLOT(onServerAddressEntered())); + http::client()->set_user(res.user_id); + MainWindow::instance()->showChatPage(); + }, + Qt::QueuedConnection); } void LoginPage::showError(const QString &msg) { - auto rect = QFontMetrics(font()).boundingRect(msg); - int width = rect.width(); - int height = rect.height(); - error_label_->setFixedHeight((int)qCeil(width / 200.0) * height); - error_label_->setText(msg); + loggingIn_ = false; + emit loggingInChanged(); + + error_ = msg; + emit errorOccurred(); } void -LoginPage::showError(QLabel *label, const QString &msg) +LoginPage::setHomeserver(QString hs) { - auto rect = QFontMetrics(font()).boundingRect(msg); - int width = rect.width(); - int height = rect.height(); - label->setFixedHeight((int)qCeil(width / 200.0) * height); - label->setText(msg); + if (hs != homeserver_) { + homeserver_ = hs; + homeserverValid_ = false; + emit homeserverChanged(); + http::client()->set_server(hs.toStdString()); + checkHomeserverVersion(); + } } void LoginPage::onMatrixIdEntered() { - error_label_->setText(QLatin1String("")); - - User user; + clearErrors(); - if (!matrixid_input_->isValid()) { - error_matrixid_label_->show(); - showError(error_matrixid_label_, - tr("You have entered an invalid Matrix ID e.g @joe:matrix.org")); - return; - } else { - error_matrixid_label_->setText(QLatin1String("")); - error_matrixid_label_->hide(); - } + homeserverValid_ = false; + emit homeserverChanged(); + User user; try { - user = parse<User>(matrixid_input_->text().toStdString()); + user = parse<User>(mxid_.toStdString()); } catch (const std::exception &) { - showError(error_matrixid_label_, - tr("You have entered an invalid Matrix ID e.g @joe:matrix.org")); + mxidError_ = tr("You have entered an invalid Matrix ID e.g @joe:matrix.org"); + emit mxidErrorChanged(); return; } - QString homeServer = QString::fromStdString(user.hostname()); - if (homeServer != inferredServerAddress_) { - serverInput_->hide(); - serverLayout_->removeWidget(errorIcon_); - errorIcon_->hide(); - if (serverInput_->isVisible()) { - matrixidLayout_->removeWidget(spinner_); - serverLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight); - spinner_->start(); - } else { - serverLayout_->removeWidget(spinner_); - matrixidLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight); - spinner_->start(); - } + 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()); + } - inferredServerAddress_ = homeServer; - serverInput_->setText(homeServer); + 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) { @@ -286,6 +128,7 @@ LoginPage::onMatrixIdEntered() nhlog::net()->info("Autodiscovery: Discovered '" + res.homeserver.base_url + "'"); http::client()->set_server(res.homeserver.base_url); + emit homeserverChanged(); checkHomeserverVersion(); }); } @@ -294,6 +137,16 @@ LoginPage::onMatrixIdEntered() 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) { @@ -333,92 +186,63 @@ LoginPage::checkHomeserverVersion() } void -LoginPage::onServerAddressEntered() -{ - error_label_->setText(QLatin1String("")); - http::client()->verify_certificates(!UserSettings::instance()->disableCertificateValidation()); - http::client()->set_server(serverInput_->text().toStdString()); - checkHomeserverVersion(); - - serverLayout_->removeWidget(errorIcon_); - errorIcon_->hide(); - serverLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight); - spinner_->start(); -} - -void LoginPage::versionError(const QString &error) { - showError(error_label_, error); - serverInput_->show(); + showError(error); - spinner_->stop(); - serverLayout_->removeWidget(spinner_); - serverLayout_->addWidget(errorIcon_, 0, Qt::AlignVCenter | Qt::AlignRight); - errorIcon_->show(); - matrixidLayout_->removeWidget(spinner_); + homeserverNeeded_ = true; + lookingUpHs_ = false; + homeserverValid_ = false; + emit lookingUpHsChanged(); + emit versionLookedUp(); } void -LoginPage::versionOk(bool passwordSupported_, bool ssoSupported_) +LoginPage::versionOk(bool passwordSupported, bool ssoSupported) { - passwordSupported = passwordSupported_; - ssoSupported = ssoSupported_; - - serverLayout_->removeWidget(spinner_); - matrixidLayout_->removeWidget(spinner_); - spinner_->stop(); - - password_input_->setVisible(passwordSupported); - password_input_->setEnabled(passwordSupported); - sso_login_button_->setVisible(ssoSupported); - login_button_->setVisible(passwordSupported); + passwordSupported_ = passwordSupported; + ssoSupported_ = ssoSupported; - if (serverInput_->isVisible()) - serverInput_->hide(); + lookingUpHs_ = false; + homeserverValid_ = true; + emit homeserverChanged(); + emit lookingUpHsChanged(); + emit versionLookedUp(); } void -LoginPage::onLoginButtonClicked(LoginMethod loginMethod) +LoginPage::onLoginButtonClicked(LoginMethod loginMethod, + QString userid, + QString password, + QString deviceName) { - error_label_->setText(QLatin1String("")); - User user; + clearErrors(); - if (!matrixid_input_->isValid()) { - error_matrixid_label_->show(); - showError(error_matrixid_label_, - tr("You have entered an invalid Matrix ID e.g @joe:matrix.org")); - return; - } else { - error_matrixid_label_->setText(QLatin1String("")); - error_matrixid_label_->hide(); - } + User user; try { - user = parse<User>(matrixid_input_->text().toStdString()); + user = parse<User>(userid.toStdString()); } catch (const std::exception &) { - showError(error_matrixid_label_, - tr("You have entered an invalid Matrix ID e.g @joe:matrix.org")); + mxidError_ = tr("You have entered an invalid Matrix ID e.g @joe:matrix.org"); + emit mxidErrorChanged(); return; } if (loginMethod == LoginMethod::Password) { - if (password_input_->text().isEmpty()) - return showError(error_label_, tr("Empty password")); + if (password.isEmpty()) + return showError(tr("Empty password")); http::client()->login( user.localpart(), - password_input_->text().toStdString(), - deviceName_->text().trimmed().isEmpty() ? initialDeviceName() - : deviceName_->text().toStdString(), + 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; - showErrorMessage(error_label_, QString::fromStdString(error)); - emit errorOccurred(); + showError(QString::fromStdString(error)); return; } @@ -432,34 +256,33 @@ LoginPage::onLoginButtonClicked(LoginMethod loginMethod) }); } else { auto sso = new SSOHandler(); - connect(sso, &SSOHandler::ssoSuccess, this, [this, sso](std::string token) { - mtx::requests::Login req{}; - req.token = token; - req.type = mtx::user_interactive::auth_types::token; - req.device_id = deviceName_->text().trimmed().isEmpty() - ? initialDeviceName() - : deviceName_->text().toStdString(); - http::client()->login( - req, [this](const mtx::responses::Login &res, mtx::http::RequestErr err) { - if (err) { - showErrorMessage(error_label_, - QString::fromStdString(err->matrix_error.error)); - emit errorOccurred(); - return; - } + 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); - } + 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(); - }); + emit loginOk(res); + }); + sso->deleteLater(); + }); connect(sso, &SSOHandler::ssoFailed, this, [this, sso]() { - showErrorMessage(error_label_, tr("SSO login failed")); + showError(tr("SSO login failed")); emit errorOccurred(); sso->deleteLater(); }); @@ -468,37 +291,6 @@ LoginPage::onLoginButtonClicked(LoginMethod loginMethod) QString::fromStdString(http::client()->login_sso_redirect(sso->url()))); } - emit loggingIn(); -} - -void -LoginPage::reset() -{ - matrixid_input_->clear(); - password_input_->clear(); - password_input_->show(); - serverInput_->clear(); - - spinner_->stop(); - errorIcon_->hide(); - serverLayout_->removeWidget(spinner_); - serverLayout_->removeWidget(errorIcon_); - matrixidLayout_->removeWidget(spinner_); - - inferredServerAddress_.clear(); -} - -void -LoginPage::onBackButtonClicked() -{ - emit backButtonClicked(); -} - -void -LoginPage::paintEvent(QPaintEvent *) -{ - QStyleOption opt; - opt.initFrom(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + loggingIn_ = true; + emit loggingInChanged(); }