Skip to content

Commit

Permalink
Merge #776(kitsune): Authenticated media and animated thumbnails support
Browse files Browse the repository at this point in the history
  • Loading branch information
KitsuneRal authored Jul 18, 2024
2 parents 5531fa5 + 1ae9ed4 commit 0894fc1
Show file tree
Hide file tree
Showing 96 changed files with 642 additions and 499 deletions.
77 changes: 46 additions & 31 deletions Quotient/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "user.h"

#include "csapi/account-data.h"
#include "csapi/capabilities.h"
#include "csapi/joining.h"
#include "csapi/leaving.h"
#include "csapi/logout.h"
Expand Down Expand Up @@ -194,37 +193,49 @@ void Connection::assumeIdentity(const QString& mxId, const QString& accessToken)
});
}

void Connection::reloadCapabilities()
JobHandle<GetVersionsJob> Connection::loadVersions()
{
d->capabilitiesJob = callApi<GetCapabilitiesJob>(BackgroundRequest);
connect(d->capabilitiesJob, &BaseJob::success, this, [this] {
d->capabilities = d->capabilitiesJob->capabilities();

if (d->capabilities.roomVersions) {
qCDebug(MAIN) << "Room versions:" << defaultRoomVersion()
<< "is default, full list:" << availableRoomVersions();
emit capabilitiesLoaded();
for (auto* r: std::as_const(d->roomMap))
r->checkVersion();
} else
qCWarning(MAIN)
<< "The server returned an empty set of supported versions;"
" disabling version upgrade recommendations to reduce noise";
});
connect(d->capabilitiesJob, &BaseJob::failure, this, [this] {
if (d->capabilitiesJob->error() == BaseJob::IncorrectRequest)
qCDebug(MAIN) << "Server doesn't support /capabilities;"
" version upgrade recommendations won't be issued";
return callApi<GetVersionsJob>(BackgroundRequest).then([this](GetVersionsJob::Response r) {
d->data->setSupportedSpecVersions(std::move(r.versions));
});
}

bool Connection::loadingCapabilities() const
JobHandle<GetCapabilitiesJob> Connection::loadCapabilities()
{
return callApi<GetCapabilitiesJob>(BackgroundRequest)
.then(
[this](GetCapabilitiesJob::Capabilities response) {
d->capabilities = std::move(response);
if (d->capabilities.roomVersions) {
qCInfo(MAIN) << "Room versions:" << defaultRoomVersion()
<< "is default, full list:" << availableRoomVersions();
emit capabilitiesLoaded();
for (auto* r : std::as_const(d->roomMap))
r->checkVersion();
} else
qCWarning(MAIN) << "The server hasn't reported room versions it supports;"
" version upgrade recommendations won't be issued";
},
[](const GetCapabilitiesJob* job) {
if (job->error() == BaseJob::IncorrectRequest)
qCDebug(MAIN) << "The server doesn't support /capabilities;"
" version upgrade recommendations won't be issued";
});
}

void Connection::reloadCapabilities() { loadCapabilities(); }

bool Connection::loadingCapabilities() const { return !capabilitiesReady(); }

bool Connection::capabilitiesReady() const
{
// (Ab)use the fact that room versions cannot be omitted after
// the capabilities have been loaded (see reloadCapabilities() above).
return !d->capabilities.roomVersions;
return d->capabilities.roomVersions.has_value();
}

QStringList Connection::supportedMatrixSpecVersions() const { return d->apiVersions.versions; }

void Connection::Private::saveAccessTokenToKeychain() const
{
qCDebug(MAIN) << "Saving access token to keychain for" << q->userId();
Expand Down Expand Up @@ -296,14 +307,18 @@ void Connection::Private::loginToServer(LoginArgTs&&... loginArgs)
void Connection::Private::completeSetup(const QString& mxId, bool mock)
{
data->setUserId(mxId);
if (!mock)
q->user()->load(); // Load the local user's profile
q->setObjectName(data->userId() % u'/' % data->deviceId());
qCDebug(MAIN) << "Using server" << data->baseUrl().toDisplayString()
<< "by user" << data->userId()
<< "from device" << data->deviceId();
connect(qApp, &QCoreApplication::aboutToQuit, q, &Connection::saveState);

if (!mock) {
q->loadVersions();
q->loadCapabilities();
q->user()->load(); // Load the local user's profile
}

if (useEncryption) {
if (auto&& maybeEncryptionData =
_impl::ConnectionEncryptionData::setup(q, mock)) {
Expand All @@ -318,8 +333,6 @@ void Connection::Private::completeSetup(const QString& mxId, bool mock)

emit q->stateChanged();
emit q->connected();
if (!mock)
q->reloadCapabilities();
}

QFuture<void> Connection::Private::ensureHomeserver(const QString& userId,
Expand Down Expand Up @@ -741,15 +754,15 @@ JobHandle<UploadContentJob> Connection::uploadFile(const QString& fileName,
overrideContentType);
}

GetContentJob* Connection::getContent(const QString& mediaId)
BaseJob* Connection::getContent(const QString& mediaId)
{
auto idParts = splitMediaId(mediaId);
return callApi<GetContentJob>(idParts.front(), idParts.back());
return callApi<DownloadFileJob>(idParts.front(), idParts.back());
}

GetContentJob* Connection::getContent(const QUrl& url)
BaseJob* Connection::getContent(const QUrl& url)
{
return getContent(url.authority() + url.path());
QT_IGNORE_DEPRECATIONS(return getContent(url.authority() + url.path());)
}

DownloadFileJob* Connection::downloadFile(const QUrl& url, const QString& localFilename)
Expand Down Expand Up @@ -1294,6 +1307,8 @@ const ConnectionData* Connection::connectionData() const
return d->data.get();
}

HomeserverData Connection::homeserverData() const { return d->data->homeserverData(); }

Room* Connection::provideRoom(const QString& id, std::optional<JoinState> joinState)
{
// TODO: This whole function is a strong case for a RoomManager class.
Expand Down
37 changes: 26 additions & 11 deletions Quotient/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@

#include "csapi/create_room.h"
#include "csapi/login.h"
#include "csapi/content-repo.h"

#include "e2ee/qolmoutboundsession.h"

#include "events/accountdataevents.h"

#include "jobs/jobhandle.h"

#include <QtCore/QDir>
#include <QtCore/QObject>
#include <QtCore/QSize>
#include <QtCore/QUrl>
#include <QtCore/QFuture>

#include <functional>

Expand All @@ -39,15 +38,15 @@ class User;
class ConnectionData;
class RoomEvent;

class GetVersionsJob;
class GetCapabilitiesJob;
class SyncJob;
class SyncData;
class RoomMessagesJob;
class PostReceiptJob;
class ForgetRoomJob;
class MediaThumbnailJob;
class JoinRoomJob;
class UploadContentJob;
class GetContentJob;
class DownloadFileJob;
class SendToDeviceJob;
class SendMessageJob;
Expand Down Expand Up @@ -395,9 +394,15 @@ class QUOTIENT_API Connection : public QObject {
}
};

//! Find out if capabilites are still loading from the server
//! Find out if homeserver capabilites have been loaded
Q_INVOKABLE bool capabilitiesReady() const;

[[deprecated("Use capabilitiesReady() instead; don't forget to negate the returned value")]]
Q_INVOKABLE bool loadingCapabilities() const;

//! Get the list of Matrix CS API spec versions supported by the homeserver
QStringList supportedMatrixSpecVersions() const;

//! \brief Get the room version recommended by the server
//!
//! Only works after server capabilities have been loaded.
Expand Down Expand Up @@ -523,8 +528,7 @@ class QUOTIENT_API Connection : public QObject {
template <typename JobT, typename... JobArgTs>
QUrl getUrlForApi(JobArgTs&&... jobArgs) const
{
return JobT::makeRequestUrl(homeserver(),
std::forward<JobArgTs>(jobArgs)...);
return JobT::makeRequestUrl(homeserverData(), std::forward<JobArgTs>(jobArgs)...);
}

//! \brief Start a local HTTP server and generate a single sign-on URL
Expand Down Expand Up @@ -652,8 +656,15 @@ public Q_SLOTS:
//! \since 0.7.2
void assumeIdentity(const QString& mxId, const QString& accessToken);

//! Explicitly request capabilities from the server
void reloadCapabilities();
//! \brief Request supported spec versions from the homeserver
//!
//! This call does not obtain room versions - use loadCapabilities() for that.
JobHandle<GetVersionsJob> loadVersions();

//! Request capabilities and room versions from the server
JobHandle<GetCapabilitiesJob> loadCapabilities();

[[deprecated("Use loadCapabilities() instead")]] void reloadCapabilities();

QFuture<void> logout();

Expand All @@ -676,8 +687,9 @@ public Q_SLOTS:
const QString& overrideContentType = {});
JobHandle<UploadContentJob> uploadFile(const QString& fileName,
const QString& overrideContentType = {});
GetContentJob* getContent(const QString& mediaId);
GetContentJob* getContent(const QUrl& url);
[[deprecated("Use downloadFile() instead")]] BaseJob* getContent(const QString& mediaId);
[[deprecated("Use downloadFile() instead")]] BaseJob* getContent(const QUrl& url);

// If localFilename is empty, a temporary file will be created
DownloadFileJob* downloadFile(const QUrl& url, const QString& localFilename = {});

Expand Down Expand Up @@ -910,6 +922,9 @@ public Q_SLOTS:
//! Access the underlying ConnectionData class
const ConnectionData* connectionData() const;

//! Get the homeserver data necessary to construct network requests
HomeserverData homeserverData() const;

//! \brief Get a Room object for the given id in the given state
//!
//! Use this method when you need a Room object in the local list
Expand Down
8 changes: 4 additions & 4 deletions Quotient/connection_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
#include "settings.h"
#include "syncdata.h"

#include "csapi/account-data.h"
#include "csapi/capabilities.h"
#include "csapi/logout.h"
#include "csapi/versions.h"
#include "csapi/wellknown.h"

#include "csapi/account-data.h"

#include <QtCore/QCoreApplication>

namespace Quotient {
Expand Down Expand Up @@ -51,8 +51,8 @@ class Q_DECL_HIDDEN Quotient::Connection::Private {
QMetaObject::Connection syncLoopConnection {};
int syncTimeout = -1;

GetCapabilitiesJob* capabilitiesJob = nullptr;
GetCapabilitiesJob::Capabilities capabilities;
GetVersionsJob::Response apiVersions{};
GetCapabilitiesJob::Capabilities capabilities{};

QVector<GetLoginFlowsJob::LoginFlow> loginFlows;

Expand Down
26 changes: 22 additions & 4 deletions Quotient/connectiondata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class ConnectionData::Private {
QString lastEvent;
QString userId;
QString deviceId;
QStringList supportedSpecVersions;
std::vector<QString> needToken;

mutable unsigned int txnCounter = 0;
Expand Down Expand Up @@ -102,6 +103,11 @@ QByteArray ConnectionData::accessToken() const { return d->accessToken; }

QUrl ConnectionData::baseUrl() const { return d->baseUrl; }

HomeserverData ConnectionData::homeserverData() const
{
return { d->baseUrl, d->supportedSpecVersions };
}

NetworkAccessManager* ConnectionData::nam() const
{
return NetworkAccessManager::instance();
Expand All @@ -111,8 +117,12 @@ void ConnectionData::setBaseUrl(QUrl baseUrl)
{
d->baseUrl = std::move(baseUrl);
qCDebug(MAIN) << "updated baseUrl to" << d->baseUrl;
if (!d->userId.isEmpty() && d->baseUrl.isValid())
NetworkAccessManager::addBaseUrl(d->userId, d->baseUrl);
if (!d->userId.isEmpty()) {
if (d->baseUrl.isValid())
NetworkAccessManager::addAccount(d->userId, d->baseUrl);
else
NetworkAccessManager::dropAccount(d->userId);
}
}

void ConnectionData::setToken(QByteArray token)
Expand All @@ -139,9 +149,9 @@ void ConnectionData::setUserId(const QString& userId)
{
if (d->baseUrl.isValid()) {
if (d->userId != userId)
NetworkAccessManager::dropBaseUrl(d->userId);
NetworkAccessManager::dropAccount(d->userId);
if (!userId.isEmpty())
NetworkAccessManager::addBaseUrl(userId, d->baseUrl);
NetworkAccessManager::addAccount(userId, d->baseUrl);
}
d->userId = userId;
}
Expand All @@ -151,6 +161,14 @@ void ConnectionData::setNeedsToken(const QString& requestName)
d->needToken.push_back(requestName);
}

void ConnectionData::setSupportedSpecVersions(QStringList versions)
{
qCInfo(MAIN).noquote() << "CS API versions:" << versions.join(u' ');
d->supportedSpecVersions = std::move(versions);
if (!ALARM(d->userId.isEmpty()) && !ALARM(!d->baseUrl.isValid()))
NetworkAccessManager::updateAccountSpecVersions(d->userId, d->supportedSpecVersions);
}

QString ConnectionData::lastEvent() const { return d->lastEvent; }

void ConnectionData::setLastEvent(QString identifier)
Expand Down
2 changes: 2 additions & 0 deletions Quotient/connectiondata.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ class QUOTIENT_API ConnectionData {
const QString& deviceId() const;
const QString& userId() const;
bool needsToken(const QString& requestName) const;
HomeserverData homeserverData() const;
Quotient::NetworkAccessManager *nam() const;

void setBaseUrl(QUrl baseUrl);
void setToken(QByteArray accessToken);
void setDeviceId(const QString& deviceId);
void setUserId(const QString& userId);
void setNeedsToken(const QString& requestName);
void setSupportedSpecVersions(QStringList versions);

QString lastEvent() const;
void setLastEvent(QString identifier);
Expand Down
14 changes: 7 additions & 7 deletions Quotient/csapi/account-data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ SetAccountDataJob::SetAccountDataJob(const QString& userId, const QString& type,
setRequestData({ toJson(content) });
}

QUrl GetAccountDataJob::makeRequestUrl(QUrl baseUrl, const QString& userId, const QString& type)
QUrl GetAccountDataJob::makeRequestUrl(const HomeserverData& hsData, const QString& userId,
const QString& type)
{
return BaseJob::makeRequestUrl(std::move(baseUrl), makePath("/_matrix/client/v3", "/user/",
userId, "/account_data/", type));
return BaseJob::makeRequestUrl(hsData, makePath("/_matrix/client/v3", "/user/", userId,
"/account_data/", type));
}

GetAccountDataJob::GetAccountDataJob(const QString& userId, const QString& type)
Expand All @@ -32,12 +33,11 @@ SetAccountDataPerRoomJob::SetAccountDataPerRoomJob(const QString& userId, const
setRequestData({ toJson(content) });
}

QUrl GetAccountDataPerRoomJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
QUrl GetAccountDataPerRoomJob::makeRequestUrl(const HomeserverData& hsData, const QString& userId,
const QString& roomId, const QString& type)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
makePath("/_matrix/client/v3", "/user/", userId, "/rooms/",
roomId, "/account_data/", type));
return BaseJob::makeRequestUrl(hsData, makePath("/_matrix/client/v3", "/user/", userId,
"/rooms/", roomId, "/account_data/", type));
}

GetAccountDataPerRoomJob::GetAccountDataPerRoomJob(const QString& userId, const QString& roomId,
Expand Down
7 changes: 4 additions & 3 deletions Quotient/csapi/account-data.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ class QUOTIENT_API GetAccountDataJob : public BaseJob {
//!
//! This function can be used when a URL for GetAccountDataJob
//! is necessary but the job itself isn't.
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId, const QString& type);
static QUrl makeRequestUrl(const HomeserverData& hsData, const QString& userId,
const QString& type);

// Result properties

Expand Down Expand Up @@ -104,8 +105,8 @@ class QUOTIENT_API GetAccountDataPerRoomJob : public BaseJob {
//!
//! This function can be used when a URL for GetAccountDataPerRoomJob
//! is necessary but the job itself isn't.
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId, const QString& roomId,
const QString& type);
static QUrl makeRequestUrl(const HomeserverData& hsData, const QString& userId,
const QString& roomId, const QString& type);

// Result properties

Expand Down
Loading

0 comments on commit 0894fc1

Please sign in to comment.