diff --git a/imports/Spectral/Dialog/LoginDialog.qml b/imports/Spectral/Dialog/LoginDialog.qml index b531ebc08..cdafed19c 100644 --- a/imports/Spectral/Dialog/LoginDialog.qml +++ b/imports/Spectral/Dialog/LoginDialog.qml @@ -44,6 +44,16 @@ Dialog { placeholderText: "Password" echoMode: TextInput.Password + onAccepted: accessTokenField.forceActiveFocus() + } + + AutoTextField { + Layout.fillWidth: true + + id: accessTokenField + + placeholderText: "Access Token (Optional)" + onAccepted: deviceNameField.forceActiveFocus() } @@ -52,14 +62,19 @@ Dialog { id: deviceNameField - placeholderText: "Device Name" + placeholderText: "Device Name (Optional)" onAccepted: root.accept() } } function doLogin() { - spectralController.loginWithCredentials(serverField.text, usernameField.text, passwordField.text, deviceNameField.text) + if (accessTokenField.text !== "") { + console.log("Login using access token.") + spectralController.loginWithAccessToken(serverField.text, usernameField.text, accessTokenField.text, deviceNameField.text) + } else { + spectralController.loginWithCredentials(serverField.text, usernameField.text, passwordField.text, deviceNameField.text) + } } onClosed: destroy() diff --git a/src/controller.cpp b/src/controller.cpp index 79312949d..2ef5ecfb1 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -103,6 +103,39 @@ void Controller::loginWithCredentials(QString serverAddr, } } +void Controller::loginWithAccessToken(QString serverAddr, + QString user, + QString token, + QString deviceName) { + if (!user.isEmpty() && !token.isEmpty()) { + QUrl serverUrl(serverAddr); + + Connection* conn = new Connection(this); + if (serverUrl.isValid()) { + conn->setHomeserver(serverUrl); + } + + connect(conn, &Connection::connected, [=] { + AccountSettings account(conn->userId()); + account.setKeepLoggedIn(true); + account.clearAccessToken(); // Drop the legacy - just in case + account.setHomeserver(conn->homeserver()); + account.setDeviceId(conn->deviceId()); + account.setDeviceName(deviceName); + if (!saveAccessTokenToKeyChain(account, conn->accessToken())) + qWarning() << "Couldn't save access token"; + account.sync(); + addConnection(conn); + setConnection(conn); + }); + connect(conn, &Connection::networkError, + [=](QString error, QString, int, int) { + emit errorOccured("Network Error", error); + }); + conn->connectWithToken(user, token, deviceName); + } +} + void Controller::logout(Connection* conn) { if (!conn) { qCritical() << "Attempt to logout null connection"; @@ -112,16 +145,24 @@ void Controller::logout(Connection* conn) { SettingsGroup("Accounts").remove(conn->userId()); QFile(accessTokenFileName(AccountSettings(conn->userId()))).remove(); - auto job = conn->callApi(); - connect(job, &LogoutJob::finished, conn, [=] { + QKeychain::DeletePasswordJob job(qAppName()); + job.setAutoDelete(true); + job.setKey(conn->userId()); + QEventLoop loop; + QKeychain::DeletePasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.start(); + loop.exec(); + + auto logoutJob = conn->callApi(); + connect(logoutJob, &LogoutJob::finished, conn, [=] { conn->stopSync(); emit conn->stateChanged(); emit conn->loggedOut(); if (!m_connections.isEmpty()) setConnection(m_connections[0]); }); - connect(job, &LogoutJob::failure, this, [=] { - emit errorOccured("Server-side Logout Failed", job->errorString()); + connect(logoutJob, &LogoutJob::failure, this, [=] { + emit errorOccured("Server-side Logout Failed", logoutJob->errorString()); }); } diff --git a/src/controller.h b/src/controller.h index 49c92c5d3..5c9e1836f 100644 --- a/src/controller.h +++ b/src/controller.h @@ -32,6 +32,7 @@ class Controller : public QObject { ~Controller(); Q_INVOKABLE void loginWithCredentials(QString, QString, QString, QString); + Q_INVOKABLE void loginWithAccessToken(QString, QString, QString, QString); QVector connections() { return m_connections; } diff --git a/src/spectralroom.cpp b/src/spectralroom.cpp index 28953d1da..6b6b9dfcd 100644 --- a/src/spectralroom.cpp +++ b/src/spectralroom.cpp @@ -12,6 +12,7 @@ #include "events/accountdataevents.h" #include "events/roommessageevent.h" #include "events/typingevent.h" +#include "events/reactionevent.h" #include "jobs/downloadfilejob.h" #include @@ -119,13 +120,13 @@ QString SpectralRoom::lastEvent() { for (auto i = messageEvents().rbegin(); i < messageEvents().rend(); i++) { const RoomEvent* evt = i->get(); - if (is(*evt)) + if (is(*evt) || is(*evt)) continue; if (evt->isRedacted()) continue; if (evt->isStateEvent() && - static_cast(evt)->repeatsState()) + static_cast(*evt).repeatsState()) continue; if (connection()->isIgnored(user(evt->senderId())))