aboutsummaryrefslogtreecommitdiff
path: root/src/base
diff options
context:
space:
mode:
authorMelvin Keskin <melvo@olomono.de>2021-09-02 23:41:16 +0200
committerLinus Jahn <lnj@kaidan.im>2021-09-03 16:16:15 +0200
commit0623aa38f2ead734dddea4cbad899a868f01cb1e (patch)
treece6539732310386d2ba0faf7383c054a4690f3a2 /src/base
parent12c63eddded9f02369bd4e569f62acfdd95cc723 (diff)
Add QXmppOmemoElement
Co-authored-by: Germán Márquez Mejía <mancho@olomono.de>
Diffstat (limited to 'src/base')
-rw-r--r--src/base/QXmppMessage.cpp34
-rw-r--r--src/base/QXmppMessage.h5
-rw-r--r--src/base/QXmppOmemoData.cpp187
-rw-r--r--src/base/QXmppOmemoElement.h70
4 files changed, 296 insertions, 0 deletions
diff --git a/src/base/QXmppMessage.cpp b/src/base/QXmppMessage.cpp
index f0e74735..f975ae3c 100644
--- a/src/base/QXmppMessage.cpp
+++ b/src/base/QXmppMessage.cpp
@@ -28,6 +28,7 @@
#include "QXmppBitsOfBinaryDataList.h"
#include "QXmppConstants_p.h"
#include "QXmppMixInvitation.h"
+#include "QXmppOmemoElement.h"
#include "QXmppTrustMessageElement.h"
#include "QXmppUtils.h"
@@ -171,6 +172,9 @@ public:
bool isSpoiler;
QString spoilerHint;
+ // XEP-0384: OMEMO Encryption
+ std::optional<QXmppOmemoElement> omemoElement;
+
// XEP-0407: Mediated Information eXchange (MIX): Miscellaneous Capabilities
std::optional<QXmppMixInvitation> mixInvitation;
@@ -1084,6 +1088,26 @@ void QXmppMessage::setSpoilerHint(const QString &spoilerHint)
}
///
+/// Returns an included OMEMO element as defined by \xep{0384, OMEMO Encryption}.
+///
+/// \since QXmpp 1.5
+///
+std::optional<QXmppOmemoElement> QXmppMessage::omemoElement() const
+{
+ return d->omemoElement;
+}
+
+///
+/// Sets an OMEMO element as defined by \xep{0384, OMEMO Encryption}.
+///
+/// \since QXmpp 1.5
+///
+void QXmppMessage::setOmemoElement(const std::optional<QXmppOmemoElement> &omemoElement)
+{
+ d->omemoElement = omemoElement;
+}
+
+///
/// Returns an included \xep{0369}: Mediated Information eXchange (MIX)
/// invitation as defined by \xep{0407}: Mediated Information eXchange (MIX):
/// Miscellaneous Capabilities.
@@ -1345,6 +1369,11 @@ bool QXmppMessage::parseExtension(const QDomElement &element)
// XEP-0382: Spoiler messages
d->isSpoiler = true;
d->spoilerHint = element.text();
+ } else if (QXmppOmemoElement::isOmemoElement(element)) {
+ // XEP-0384: OMEMO Encryption
+ QXmppOmemoElement omemoElement;
+ omemoElement.parse(element);
+ d->omemoElement = omemoElement;
} else if (checkElement(element, QStringLiteral("invitation"), ns_mix_misc)) {
// XEP-0407: Mediated Information eXchange (MIX): Miscellaneous Capabilities
QXmppMixInvitation mixInvitation;
@@ -1543,6 +1572,11 @@ void QXmppMessage::serializeExtensions(QXmlStreamWriter *xmlWriter) const
xmlWriter->writeEndElement();
}
+ // XEP-0384: OMEMO Encryption
+ if (d->omemoElement) {
+ d->omemoElement->toXml(xmlWriter);
+ }
+
// XEP-0407: Mediated Information eXchange (MIX): Miscellaneous Capabilities
if (d->mixInvitation) {
d->mixInvitation->toXml(xmlWriter);
diff --git a/src/base/QXmppMessage.h b/src/base/QXmppMessage.h
index edd0c5c1..6688d3b6 100644
--- a/src/base/QXmppMessage.h
+++ b/src/base/QXmppMessage.h
@@ -36,6 +36,7 @@
class QXmppMessagePrivate;
class QXmppBitsOfBinaryDataList;
class QXmppMixInvitation;
+class QXmppOmemoElement;
class QXmppTrustMessageElement;
///
@@ -247,6 +248,10 @@ public:
QString spoilerHint() const;
void setSpoilerHint(const QString &);
+ // XEP-0384: OMEMO Encryption
+ std::optional<QXmppOmemoElement> omemoElement() const;
+ void setOmemoElement(const std::optional<QXmppOmemoElement> &omemoElement);
+
// XEP-0407: Mediated Information eXchange (MIX): Miscellaneous Capabilities
std::optional<QXmppMixInvitation> mixInvitation() const;
void setMixInvitation(const std::optional<QXmppMixInvitation> &mixInvitation);
diff --git a/src/base/QXmppOmemoData.cpp b/src/base/QXmppOmemoData.cpp
index 6fb2580d..fbcf8261 100644
--- a/src/base/QXmppOmemoData.cpp
+++ b/src/base/QXmppOmemoData.cpp
@@ -26,6 +26,7 @@
#include "QXmppOmemoDeviceBundle.h"
#include "QXmppOmemoDeviceElement.h"
#include "QXmppOmemoDeviceList.h"
+#include "QXmppOmemoElement.h"
#include "QXmppOmemoEnvelope.h"
#include "QXmppUtils.h"
@@ -618,3 +619,189 @@ bool QXmppOmemoEnvelope::isOmemoEnvelope(const QDomElement &element)
return element.tagName() == QStringLiteral("key") &&
element.namespaceURI() == ns_omemo_1;
}
+
+///
+/// \class QXmppOmemoElement
+///
+/// \brief The QXmppOmemoElement class represents an OMEMO element as
+/// defined by \xep{0384, OMEMO Encryption}.
+///
+/// \since QXmpp 1.5
+///
+
+class QXmppOmemoElementPrivate : public QSharedData
+{
+public:
+ uint32_t senderDeviceId = 0;
+ QByteArray payload;
+ QMultiMap<QString, QXmppOmemoEnvelope> envelopes;
+};
+
+///
+/// Constructs an OMEMO element.
+///
+QXmppOmemoElement::QXmppOmemoElement()
+ : d(new QXmppOmemoElementPrivate)
+{
+}
+
+///
+/// Constructs a copy of \a other.
+///
+/// \param other
+///
+QXmppOmemoElement::QXmppOmemoElement(const QXmppOmemoElement &other) = default;
+
+QXmppOmemoElement::~QXmppOmemoElement() = default;
+
+///
+/// Assigns \a other to this OMEMO element.
+///
+/// \param other
+///
+QXmppOmemoElement &QXmppOmemoElement::operator=(const QXmppOmemoElement &other) = default;
+
+///
+/// Returns the ID of the sender's device.
+///
+/// The ID is 0 if it is unset.
+///
+/// \return the sender's device ID
+///
+uint32_t QXmppOmemoElement::senderDeviceId() const
+{
+ return d->senderDeviceId;
+}
+
+///
+/// Sets the ID of the sender's device.
+///
+/// A valid ID must be at least 1 and at most 2^32-1.
+///
+/// \param id sender's device ID
+///
+void QXmppOmemoElement::setSenderDeviceId(const uint32_t id)
+{
+ d->senderDeviceId = id;
+}
+
+///
+/// Returns the payload which consists of the encrypted SCE envelope.
+///
+/// \return the encrypted payload
+///
+QByteArray QXmppOmemoElement::payload() const
+{
+ return d->payload;
+}
+
+///
+/// Sets the payload which consists of the encrypted SCE envelope.
+///
+/// \param payload encrypted payload
+///
+void QXmppOmemoElement::setPayload(const QByteArray &payload)
+{
+ d->payload = payload;
+}
+
+///
+/// Searches for an OMEMO envelope by its recipient JID and device ID.
+///
+/// \param recipientJid bare JID of the recipient
+/// \param recipientDeviceId ID of the recipient's device
+///
+/// \return the found OMEMO envelope
+///
+std::optional<QXmppOmemoEnvelope> QXmppOmemoElement::searchEnvelope(const QString &recipientJid, uint32_t recipientDeviceId) const
+{
+ for (auto itr = d->envelopes.constFind(recipientJid); itr != d->envelopes.constEnd() && itr.key() == recipientJid; ++itr) {
+ const auto &envelope = itr.value();
+ if (envelope.recipientDeviceId() == recipientDeviceId) {
+ return envelope;
+ }
+ }
+
+ return std::nullopt;
+}
+
+///
+/// Adds an OMEMO envelope.
+///
+/// If a full JID is passed as recipientJid, it is converted into a bare JID.
+///
+/// \see QXmppOmemoEnvelope
+///
+/// \param recipientJid bare JID of the recipient
+/// \param envelope OMEMO envelope
+///
+void QXmppOmemoElement::addEnvelope(const QString &recipientJid, QXmppOmemoEnvelope &envelope)
+{
+ d->envelopes.insert(QXmppUtils::jidToBareJid(recipientJid), envelope);
+}
+
+/// \cond
+void QXmppOmemoElement::parse(const QDomElement &element)
+{
+ const auto header = element.firstChildElement("header");
+
+ d->senderDeviceId = header.attribute("sid").toInt();
+
+ for (auto recipient = header.firstChildElement("keys");
+ !recipient.isNull();
+ recipient = recipient.nextSiblingElement("keys")) {
+ const auto recipientJid = recipient.attribute("jid");
+
+ for (auto envelope = recipient.firstChildElement("key");
+ !envelope.isNull();
+ envelope = envelope.nextSiblingElement("key")) {
+ QXmppOmemoEnvelope omemoEnvelope;
+ omemoEnvelope.parse(envelope);
+ addEnvelope(recipientJid, omemoEnvelope);
+ }
+ }
+
+ d->payload = QByteArray::fromBase64(element.firstChildElement("payload").text().toLatin1());
+}
+
+void QXmppOmemoElement::toXml(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement("encrypted");
+ writer->writeAttribute("xmlns", ns_omemo_1);
+
+ writer->writeStartElement("header");
+ writer->writeAttribute("sid", QString::number(d->senderDeviceId));
+
+ const auto recipientJids = d->envelopes.uniqueKeys();
+ for (const auto &recipientJid : recipientJids) {
+ writer->writeStartElement("keys");
+ writer->writeAttribute("jid", recipientJid);
+
+ for (auto itr = d->envelopes.constFind(recipientJid); itr != d->envelopes.constEnd() && itr.key() == recipientJid; ++itr) {
+ const auto &envelope = itr.value();
+ envelope.toXml(writer);
+ }
+
+ writer->writeEndElement(); // keys
+ }
+
+ writer->writeEndElement(); // header
+
+ helperToXmlAddTextElement(writer, "payload", d->payload.toBase64());
+
+ writer->writeEndElement(); // encrypted
+}
+/// \endcond
+
+///
+/// Determines whether the given DOM element is an OMEMO element.
+///
+/// \param element DOM element being checked
+///
+/// \return true if element is an OMEMO element, otherwise false
+///
+bool QXmppOmemoElement::isOmemoElement(const QDomElement &element)
+{
+ return element.tagName() == QStringLiteral("encrypted") &&
+ element.namespaceURI() == ns_omemo_1;
+}
diff --git a/src/base/QXmppOmemoElement.h b/src/base/QXmppOmemoElement.h
new file mode 100644
index 00000000..684ed1fa
--- /dev/null
+++ b/src/base/QXmppOmemoElement.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008-2021 The QXmpp developers
+ *
+ * Author:
+ * Germán Márquez Mejía
+ * Melvin Keskin
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifndef QXMPPOMEMOELEMENT_H
+#define QXMPPOMEMOELEMENT_H
+
+#include "QXmppGlobal.h"
+
+#include <optional>
+
+#include <QSharedDataPointer>
+
+class QDomElement;
+class QXmppOmemoElementPrivate;
+class QXmppOmemoEnvelope;
+class QXmlStreamWriter;
+
+class QXMPP_EXPORT QXmppOmemoElement
+{
+public:
+ QXmppOmemoElement();
+ QXmppOmemoElement(const QXmppOmemoElement &other);
+ ~QXmppOmemoElement();
+
+ QXmppOmemoElement &operator=(const QXmppOmemoElement &other);
+
+ uint32_t senderDeviceId() const;
+ void setSenderDeviceId(uint32_t id);
+
+ QByteArray payload() const;
+ void setPayload(const QByteArray &payload);
+
+ std::optional<QXmppOmemoEnvelope> searchEnvelope(const QString &recipientJid, uint32_t recipientDeviceId) const;
+ void addEnvelope(const QString &recipientJid, QXmppOmemoEnvelope &envelope);
+
+ /// \cond
+ void parse(const QDomElement &element);
+ void toXml(QXmlStreamWriter *writer) const;
+ /// \endcond
+
+ static bool isOmemoElement(const QDomElement &element);
+
+private:
+ QSharedDataPointer<QXmppOmemoElementPrivate> d;
+};
+
+Q_DECLARE_TYPEINFO(QXmppOmemoElement, Q_MOVABLE_TYPE);
+
+#endif // QXMPPOMEMOELEMENT_H