File indexing completed on 2024-10-06 12:54:05

0001 // SPDX-FileCopyrightText: 2020 Tobias Fella <tobias.fella@kde.org>
0002 // SPDX-License-Identifier: GPL-2.0-or-later
0003 
0004 #include "login.h"
0005 
0006 #include <Quotient/accountregistry.h>
0007 #include <Quotient/connection.h>
0008 #include <Quotient/qt_connection_util.h>
0009 
0010 #include "controller.h"
0011 
0012 #include <KLocalizedString>
0013 
0014 using namespace Quotient;
0015 
0016 Login::Login(QObject *parent)
0017     : QObject(parent)
0018 {
0019     init();
0020 }
0021 
0022 void Login::init()
0023 {
0024     m_homeserverReachable = false;
0025     m_connection = new Connection();
0026     m_matrixId = QString();
0027     m_password = QString();
0028     m_deviceName = QStringLiteral("NeoChat %1 %2 %3 %4")
0029                        .arg(QSysInfo::machineHostName(), QSysInfo::productType(), QSysInfo::productVersion(), QSysInfo::currentCpuArchitecture());
0030     m_supportsSso = false;
0031     m_supportsPassword = false;
0032     m_ssoUrl = QUrl();
0033 
0034     connect(this, &Login::matrixIdChanged, this, [this]() {
0035         setHomeserverReachable(false);
0036         QRegularExpression validator("^\\@?[a-zA-Z0-9\\._=\\-/]+\\:[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)*(\\:[0-9]+)?$");
0037         if (!validator.match(m_matrixId).hasMatch()) {
0038             return;
0039         }
0040 
0041         if (m_matrixId == "@") {
0042             return;
0043         }
0044 
0045         m_isLoggedIn = Controller::instance().accounts().isLoggedIn(m_matrixId);
0046         Q_EMIT isLoggedInChanged();
0047         if (m_isLoggedIn) {
0048             return;
0049         }
0050 
0051         m_testing = true;
0052         Q_EMIT testingChanged();
0053         if (!m_connection) {
0054             m_connection = new Connection();
0055         }
0056         m_connection->resolveServer(m_matrixId);
0057         connectSingleShot(m_connection, &Connection::loginFlowsChanged, this, [this]() {
0058             setHomeserverReachable(true);
0059             m_testing = false;
0060             Q_EMIT testingChanged();
0061             m_supportsSso = m_connection->supportsSso();
0062             m_supportsPassword = m_connection->supportsPasswordAuth();
0063             Q_EMIT loginFlowsChanged();
0064         });
0065     });
0066     connect(m_connection, &Connection::connected, this, [this] {
0067         Q_EMIT connected();
0068         m_isLoggingIn = false;
0069         Q_EMIT isLoggingInChanged();
0070         Q_ASSERT(m_connection);
0071         AccountSettings account(m_connection->userId());
0072         account.setKeepLoggedIn(true);
0073         account.setHomeserver(m_connection->homeserver());
0074         account.setDeviceId(m_connection->deviceId());
0075         account.setDeviceName(m_deviceName);
0076         if (!Controller::instance().saveAccessTokenToKeyChain(account, m_connection->accessToken())) {
0077             qWarning() << "Couldn't save access token";
0078         }
0079         account.sync();
0080         Controller::instance().addConnection(m_connection);
0081         Controller::instance().setActiveConnection(m_connection);
0082         m_connection = nullptr;
0083     });
0084     connect(m_connection, &Connection::networkError, this, [this](QString error, const QString &, int, int) {
0085         Q_EMIT Controller::instance().globalErrorOccured(i18n("Network Error"), std::move(error));
0086         m_isLoggingIn = false;
0087         Q_EMIT isLoggingInChanged();
0088     });
0089     connect(m_connection, &Connection::loginError, this, [this](QString error, const QString &) {
0090         Q_EMIT errorOccured(i18n("Login Failed: %1", error));
0091         m_isLoggingIn = false;
0092         Q_EMIT isLoggingInChanged();
0093     });
0094 
0095     connect(m_connection, &Connection::resolveError, this, [](QString error) {
0096         Q_EMIT Controller::instance().globalErrorOccured(i18n("Network Error"), std::move(error));
0097     });
0098 
0099     connectSingleShot(m_connection, &Connection::syncDone, this, []() {
0100         Q_EMIT Controller::instance().initiated();
0101     });
0102 }
0103 
0104 void Login::setHomeserverReachable(bool reachable)
0105 {
0106     m_homeserverReachable = reachable;
0107     Q_EMIT homeserverReachableChanged();
0108 }
0109 
0110 bool Login::homeserverReachable() const
0111 {
0112     return m_homeserverReachable;
0113 }
0114 
0115 QString Login::matrixId() const
0116 {
0117     return m_matrixId;
0118 }
0119 
0120 void Login::setMatrixId(const QString &matrixId)
0121 {
0122     m_matrixId = matrixId;
0123     if (!m_matrixId.startsWith('@')) {
0124         m_matrixId.prepend('@');
0125     }
0126     Q_EMIT matrixIdChanged();
0127 }
0128 
0129 QString Login::password() const
0130 {
0131     return m_password;
0132 }
0133 
0134 void Login::setPassword(const QString &password)
0135 {
0136     m_password = password;
0137     Q_EMIT passwordChanged();
0138 }
0139 
0140 QString Login::deviceName() const
0141 {
0142     return m_deviceName;
0143 }
0144 
0145 void Login::setDeviceName(const QString &deviceName)
0146 {
0147     m_deviceName = deviceName;
0148     Q_EMIT deviceNameChanged();
0149 }
0150 
0151 void Login::login()
0152 {
0153     m_isLoggingIn = true;
0154     Q_EMIT isLoggingInChanged();
0155 
0156     // Some servers do not have a .well_known file. So we login via the username part from the mxid,
0157     // rather than with the full mxid, as that would lead to an invalid user.
0158     auto username = m_matrixId.mid(1, m_matrixId.indexOf(":") - 1);
0159     m_connection->loginWithPassword(username, m_password, m_deviceName, QString());
0160 }
0161 
0162 bool Login::supportsPassword() const
0163 {
0164     return m_supportsPassword;
0165 }
0166 
0167 bool Login::supportsSso() const
0168 {
0169     return m_supportsSso;
0170 }
0171 
0172 QUrl Login::ssoUrl() const
0173 {
0174     return m_ssoUrl;
0175 }
0176 
0177 void Login::loginWithSso()
0178 {
0179     m_connection->resolveServer(m_matrixId);
0180     connectSingleShot(m_connection, &Connection::loginFlowsChanged, this, [this]() {
0181         SsoSession *session = m_connection->prepareForSso(m_deviceName);
0182         m_ssoUrl = session->ssoUrl();
0183         Q_EMIT ssoUrlChanged();
0184     });
0185 }
0186 
0187 bool Login::testing() const
0188 {
0189     return m_testing;
0190 }
0191 
0192 bool Login::isLoggingIn() const
0193 {
0194     return m_isLoggingIn;
0195 }
0196 
0197 bool Login::isLoggedIn() const
0198 {
0199     return m_isLoggedIn;
0200 }
0201 
0202 #include "moc_login.cpp"