aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/events/encryptedfile.h88
-rw-r--r--lib/events/eventcontent.cpp20
-rw-r--r--lib/events/eventcontent.h17
-rw-r--r--lib/events/roomavatarevent.h2
-rw-r--r--lib/events/roommessageevent.cpp8
5 files changed, 121 insertions, 14 deletions
diff --git a/lib/events/encryptedfile.h b/lib/events/encryptedfile.h
new file mode 100644
index 00000000..24ac9de1
--- /dev/null
+++ b/lib/events/encryptedfile.h
@@ -0,0 +1,88 @@
+// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
+//
+// SPDX-License-Identifier: LGPl-2.1-or-later
+
+#pragma once
+
+#include "converters.h"
+
+namespace Quotient {
+/**
+ * JSON Web Key object as specified in
+ * https://spec.matrix.org/unstable/client-server-api/#extensions-to-mroommessage-msgtypes
+ * The only currently relevant member is `k`, the rest needs to be set to the defaults specified in the spec.
+ */
+struct JWK
+{
+ Q_GADGET
+ Q_PROPERTY(QString kty MEMBER kty CONSTANT)
+ Q_PROPERTY(QStringList keyOps MEMBER keyOps CONSTANT)
+ Q_PROPERTY(QString alg MEMBER alg CONSTANT)
+ Q_PROPERTY(QString k MEMBER k CONSTANT)
+ Q_PROPERTY(bool ext MEMBER ext CONSTANT)
+
+public:
+ QString kty;
+ QStringList keyOps;
+ QString alg;
+ QString k;
+ bool ext;
+};
+
+struct EncryptedFile
+{
+ Q_GADGET
+ Q_PROPERTY(QUrl url MEMBER url CONSTANT)
+ Q_PROPERTY(JWK key MEMBER key CONSTANT)
+ Q_PROPERTY(QString iv MEMBER iv CONSTANT)
+ Q_PROPERTY(QHash<QString, QString> hashes MEMBER hashes CONSTANT)
+ Q_PROPERTY(QString v MEMBER v CONSTANT)
+
+public:
+ QUrl url;
+ JWK key;
+ QString iv;
+ QHash<QString, QString> hashes;
+ QString v;
+};
+
+template <>
+struct JsonObjectConverter<EncryptedFile> {
+ static void dumpTo(QJsonObject& jo, const EncryptedFile& pod)
+ {
+ addParam<>(jo, QStringLiteral("url"), pod.url);
+ addParam<>(jo, QStringLiteral("key"), pod.key);
+ addParam<>(jo, QStringLiteral("iv"), pod.iv);
+ addParam<>(jo, QStringLiteral("hashes"), pod.hashes);
+ addParam<>(jo, QStringLiteral("v"), pod.v);
+ }
+ static void fillFrom(const QJsonObject& jo, EncryptedFile& pod)
+ {
+ fromJson(jo.value("url"_ls), pod.url);
+ fromJson(jo.value("key"_ls), pod.key);
+ fromJson(jo.value("iv"_ls), pod.iv);
+ fromJson(jo.value("hashes"_ls), pod.hashes);
+ fromJson(jo.value("v"_ls), pod.v);
+ }
+};
+
+template <>
+struct JsonObjectConverter<JWK> {
+ static void dumpTo(QJsonObject& jo, const JWK& pod)
+ {
+ addParam<>(jo, QStringLiteral("kty"), pod.kty);
+ addParam<>(jo, QStringLiteral("key_ops"), pod.keyOps);
+ addParam<>(jo, QStringLiteral("alg"), pod.alg);
+ addParam<>(jo, QStringLiteral("k"), pod.k);
+ addParam<>(jo, QStringLiteral("ext"), pod.ext);
+ }
+ static void fillFrom(const QJsonObject& jo, JWK& pod)
+ {
+ fromJson(jo.value("kty"_ls), pod.kty);
+ fromJson(jo.value("key_ops"_ls), pod.keyOps);
+ fromJson(jo.value("alg"_ls), pod.alg);
+ fromJson(jo.value("k"_ls), pod.k);
+ fromJson(jo.value("ext"_ls), pod.ext);
+ }
+};
+} // namespace Quotient
diff --git a/lib/events/eventcontent.cpp b/lib/events/eventcontent.cpp
index 1f28f195..22878d4c 100644
--- a/lib/events/eventcontent.cpp
+++ b/lib/events/eventcontent.cpp
@@ -30,11 +30,12 @@ FileInfo::FileInfo(const QFileInfo &fi)
}
FileInfo::FileInfo(QUrl u, qint64 payloadSize, const QMimeType& mimeType,
- QString originalFilename)
+ Omittable<EncryptedFile> file, QString originalFilename)
: mimeType(mimeType)
, url(move(u))
, payloadSize(payloadSize)
, originalName(move(originalFilename))
+ , file(file)
{
if (!isValid())
qCWarning(MESSAGES)
@@ -44,6 +45,7 @@ FileInfo::FileInfo(QUrl u, qint64 payloadSize, const QMimeType& mimeType,
}
FileInfo::FileInfo(QUrl mxcUrl, const QJsonObject& infoJson,
+ const Omittable<EncryptedFile> &file,
QString originalFilename)
: originalInfoJson(infoJson)
, mimeType(
@@ -51,7 +53,11 @@ FileInfo::FileInfo(QUrl mxcUrl, const QJsonObject& infoJson,
, url(move(mxcUrl))
, payloadSize(fromJson<qint64>(infoJson["size"_ls]))
, originalName(move(originalFilename))
+ , file(file)
{
+ if(url.isEmpty() && file.has_value()) {
+ url = file->url;
+ }
if (!mimeType.isValid())
mimeType = QMimeDatabase().mimeTypeForData(QByteArray());
}
@@ -76,14 +82,15 @@ ImageInfo::ImageInfo(const QFileInfo& fi, QSize imageSize)
{}
ImageInfo::ImageInfo(const QUrl& mxcUrl, qint64 fileSize, const QMimeType& type,
- QSize imageSize, const QString& originalFilename)
- : FileInfo(mxcUrl, fileSize, type, originalFilename)
+ QSize imageSize, const Omittable<EncryptedFile> &file, const QString& originalFilename)
+ : FileInfo(mxcUrl, fileSize, type, file, originalFilename)
, imageSize(imageSize)
{}
ImageInfo::ImageInfo(const QUrl& mxcUrl, const QJsonObject& infoJson,
+ const Omittable<EncryptedFile> &file,
const QString& originalFilename)
- : FileInfo(mxcUrl, infoJson, originalFilename)
+ : FileInfo(mxcUrl, infoJson, file, originalFilename)
, imageSize(infoJson["w"_ls].toInt(), infoJson["h"_ls].toInt())
{}
@@ -96,9 +103,10 @@ void ImageInfo::fillInfoJson(QJsonObject* infoJson) const
infoJson->insert(QStringLiteral("h"), imageSize.height());
}
-Thumbnail::Thumbnail(const QJsonObject& infoJson)
+Thumbnail::Thumbnail(const QJsonObject& infoJson, const Omittable<EncryptedFile> &file)
: ImageInfo(QUrl(infoJson["thumbnail_url"_ls].toString()),
- infoJson["thumbnail_info"_ls].toObject())
+ infoJson["thumbnail_info"_ls].toObject(),
+ file)
{}
void Thumbnail::fillInfoJson(QJsonObject* infoJson) const
diff --git a/lib/events/eventcontent.h b/lib/events/eventcontent.h
index 40ec3a49..f609a603 100644
--- a/lib/events/eventcontent.h
+++ b/lib/events/eventcontent.h
@@ -12,6 +12,8 @@
#include <QtCore/QUrl>
#include <QtCore/QMetaType>
+#include "encryptedfile.h"
+
class QFileInfo;
namespace Quotient {
@@ -80,8 +82,10 @@ namespace EventContent {
explicit FileInfo(const QFileInfo& fi);
explicit FileInfo(QUrl mxcUrl, qint64 payloadSize = -1,
const QMimeType& mimeType = {},
+ Omittable<EncryptedFile> file = none,
QString originalFilename = {});
FileInfo(QUrl mxcUrl, const QJsonObject& infoJson,
+ const Omittable<EncryptedFile> &file,
QString originalFilename = {});
bool isValid() const;
@@ -103,6 +107,7 @@ namespace EventContent {
QUrl url;
qint64 payloadSize;
QString originalName;
+ Omittable<EncryptedFile> file = none;
};
template <typename InfoT>
@@ -122,8 +127,10 @@ namespace EventContent {
explicit ImageInfo(const QFileInfo& fi, QSize imageSize = {});
explicit ImageInfo(const QUrl& mxcUrl, qint64 fileSize = -1,
const QMimeType& type = {}, QSize imageSize = {},
+ const Omittable<EncryptedFile> &file = none,
const QString& originalFilename = {});
ImageInfo(const QUrl& mxcUrl, const QJsonObject& infoJson,
+ const Omittable<EncryptedFile> &encryptedFile,
const QString& originalFilename = {});
void fillInfoJson(QJsonObject* infoJson) const;
@@ -142,7 +149,7 @@ namespace EventContent {
class Thumbnail : public ImageInfo {
public:
Thumbnail() = default; // Allow empty thumbnails
- Thumbnail(const QJsonObject& infoJson);
+ Thumbnail(const QJsonObject& infoJson, const Omittable<EncryptedFile> &file = none);
Thumbnail(const ImageInfo& info) : ImageInfo(info) {}
using ImageInfo::ImageInfo;
@@ -182,7 +189,7 @@ namespace EventContent {
explicit UrlBasedContent(const QJsonObject& json)
: TypedBase(json)
, InfoT(QUrl(json["url"].toString()), json["info"].toObject(),
- json["filename"].toString())
+ fromJson<Omittable<EncryptedFile>>(json["file"]), json["filename"].toString())
{
// A small hack to facilitate links creation in QML.
originalJson.insert("mediaId", InfoT::mediaId());
@@ -196,7 +203,11 @@ namespace EventContent {
void fillJson(QJsonObject* json) const override
{
Q_ASSERT(json);
- json->insert("url", InfoT::url.toString());
+ if (!InfoT::file.has_value()) {
+ json->insert("url", InfoT::url.toString());
+ } else {
+ json->insert("file", Quotient::toJson(*InfoT::file));
+ }
if (!InfoT::originalName.isEmpty())
json->insert("filename", InfoT::originalName);
json->insert("info", toInfoJson<InfoT>(*this));
diff --git a/lib/events/roomavatarevent.h b/lib/events/roomavatarevent.h
index 3fa11a0f..8618ba31 100644
--- a/lib/events/roomavatarevent.h
+++ b/lib/events/roomavatarevent.h
@@ -25,7 +25,7 @@ public:
const QSize& imageSize = {},
const QString& originalFilename = {})
: RoomAvatarEvent(EventContent::ImageContent {
- mxcUrl, fileSize, mimeType, imageSize, originalFilename })
+ mxcUrl, fileSize, mimeType, imageSize, none, originalFilename })
{}
QUrl url() const { return content().url; }
diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp
index 71f85363..9b46594e 100644
--- a/lib/events/roommessageevent.cpp
+++ b/lib/events/roommessageevent.cpp
@@ -145,21 +145,21 @@ TypedBase* contentFromFile(const QFileInfo& file, bool asGenericFile)
auto mimeTypeName = mimeType.name();
if (mimeTypeName.startsWith("image/"))
return new ImageContent(localUrl, file.size(), mimeType,
- QImageReader(filePath).size(),
+ QImageReader(filePath).size(), none,
file.fileName());
// duration can only be obtained asynchronously and can only be reliably
// done by starting to play the file. Left for a future implementation.
if (mimeTypeName.startsWith("video/"))
return new VideoContent(localUrl, file.size(), mimeType,
- QMediaResource(localUrl).resolution(),
+ QMediaResource(localUrl).resolution(), none,
file.fileName());
if (mimeTypeName.startsWith("audio/"))
- return new AudioContent(localUrl, file.size(), mimeType,
+ return new AudioContent(localUrl, file.size(), mimeType, none,
file.fileName());
}
- return new FileContent(localUrl, file.size(), mimeType, file.fileName());
+ return new FileContent(localUrl, file.size(), mimeType, none, file.fileName());
}
RoomMessageEvent::RoomMessageEvent(const QString& plainBody,