diff options
| author | Melvin Keskin <melvo@olomono.de> | 2021-09-02 23:41:16 +0200 |
|---|---|---|
| committer | Linus Jahn <lnj@kaidan.im> | 2021-09-03 16:16:15 +0200 |
| commit | 0623aa38f2ead734dddea4cbad899a868f01cb1e (patch) | |
| tree | ce6539732310386d2ba0faf7383c054a4690f3a2 /src/base | |
| parent | 12c63eddded9f02369bd4e569f62acfdd95cc723 (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.cpp | 34 | ||||
| -rw-r--r-- | src/base/QXmppMessage.h | 5 | ||||
| -rw-r--r-- | src/base/QXmppOmemoData.cpp | 187 | ||||
| -rw-r--r-- | src/base/QXmppOmemoElement.h | 70 |
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 |
