From 4102144290312ebed7d4af69dd640835275a9675 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 13 Mar 2020 18:39:59 +0100 Subject: Connection: support getting the list of login flows The flows themselves are not facilitated in any way (yet). --- lib/connection.cpp | 36 +++++++++++++++++++++++++++++++----- lib/connection.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/lib/connection.cpp b/lib/connection.cpp index 6ad24fba..1989050e 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -30,7 +30,6 @@ #include "csapi/capabilities.h" #include "csapi/joining.h" #include "csapi/leaving.h" -#include "csapi/login.h" #include "csapi/logout.h" #include "csapi/receipts.h" #include "csapi/room_send.h" @@ -111,6 +110,8 @@ public: GetCapabilitiesJob* capabilitiesJob = nullptr; GetCapabilitiesJob::Capabilities capabilities; + QVector loginFlows; + #ifdef Quotient_E2EE_ENABLED QScopedPointer encryptionManager; #endif // Quotient_E2EE_ENABLED @@ -1004,6 +1005,21 @@ QUrl Connection::homeserver() const { return d->data->baseUrl(); } QString Connection::domain() const { return userId().section(':', 1); } +QVector Connection::loginFlows() const +{ + return d->loginFlows; +} + +bool Connection::supportsPasswordAuth() const +{ + return d->loginFlows.contains(LoginFlows::Password); +} + +bool Connection::supportsSso() const +{ + return d->loginFlows.contains(LoginFlows::SSO); +} + Room* Connection::room(const QString& roomId, JoinStates states) const { Room* room = d->roomMap.value({ roomId, false }, nullptr); @@ -1400,11 +1416,21 @@ QByteArray Connection::generateTxnId() const void Connection::setHomeserver(const QUrl& url) { - if (homeserver() == url) - return; + if (homeserver() != url) { + d->data->setBaseUrl(url); + d->loginFlows.clear(); + emit homeserverChanged(homeserver()); + } - d->data->setBaseUrl(url); - emit homeserverChanged(homeserver()); + // Whenever a homeserver is updated, retrieve available login flows from it + auto* j = callApi(BackgroundRequest); + connect(j, &BaseJob::finished, this, [this, j] { + if (j->status().good()) + d->loginFlows = j->flows(); + else + d->loginFlows.clear(); + emit loginFlowsChanged(); + }); } void Connection::saveRoomState(Room* r) const diff --git a/lib/connection.h b/lib/connection.h index b57f0ca8..9d89ca43 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -21,6 +21,7 @@ #include "joinstate.h" #include "qt_connection_util.h" +#include "csapi/login.h" #include "csapi/create_room.h" #include "events/accountdataevents.h" @@ -36,6 +37,8 @@ namespace QtOlm { class Account; } +Q_DECLARE_METATYPE(Quotient::GetLoginFlowsJob::LoginFlow) + namespace Quotient { Q_NAMESPACE @@ -58,6 +61,28 @@ class SendToDeviceJob; class SendMessageJob; class LeaveRoomJob; +// To simplify comparisons of LoginFlows + +inline bool operator==(const GetLoginFlowsJob::LoginFlow& lhs, + const GetLoginFlowsJob::LoginFlow& rhs) +{ + return lhs.type == rhs.type; +} + +inline bool operator!=(const GetLoginFlowsJob::LoginFlow& lhs, + const GetLoginFlowsJob::LoginFlow& rhs) +{ + return !(lhs == rhs); +} + +/// Predefined login flows +struct LoginFlows { + using LoginFlow = GetLoginFlowsJob::LoginFlow; + static inline const LoginFlow Password { "m.login.password" }; + static inline const LoginFlow SSO { "m.login.sso" }; + static inline const LoginFlow Token { "m.login.token" }; +}; + class Connection; using room_factory_t = @@ -117,6 +142,9 @@ class Connection : public QObject { Q_PROPERTY(QUrl homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged) Q_PROPERTY(QString domain READ domain NOTIFY homeserverChanged) + Q_PROPERTY(QVector loginFlows READ loginFlows NOTIFY loginFlowsChanged) + Q_PROPERTY(bool supportsSso READ supportsSso NOTIFY loginFlowsChanged) + Q_PROPERTY(bool supportsPasswordAuth READ supportsPasswordAuth NOTIFY loginFlowsChanged) Q_PROPERTY(bool cacheState READ cacheState WRITE setCacheState NOTIFY cacheStateChanged) Q_PROPERTY(bool lazyLoading READ lazyLoading WRITE setLazyLoading NOTIFY @@ -281,6 +309,12 @@ public: QUrl homeserver() const; /** Get the domain name used for ids/aliases on the server */ QString domain() const; + /** Get the list of supported login flows */ + QVector loginFlows() const; + /** Check whether the current homeserver supports password auth */ + bool supportsPasswordAuth() const; + /** Check whether the current homeserver supports SSO */ + bool supportsSso() const; /** Find a room by its id and a mask of applicable states */ Q_INVOKABLE Quotient::Room* room(const QString& roomId, @@ -421,6 +455,18 @@ public: std::forward(jobArgs)...); } + /*! Get a request URL for a job with specified type and arguments + * + * This calls JobT::makeRequestUrl() prepending the connection's homeserver + * to the list of arguments. + */ + template + QUrl getUrlForApi(JobArgTs&&... jobArgs) const + { + return JobT::makeRequestUrl(homeserver(), + std::forward(jobArgs)...); + } + /** Generate a new transaction id. Transaction id's are unique within * a single Connection object */ @@ -609,6 +655,7 @@ signals: void resolveError(QString error); void homeserverChanged(QUrl baseUrl); + void loginFlowsChanged(); void capabilitiesLoaded(); void connected(); -- cgit v1.2.3