aboutsummaryrefslogtreecommitdiff
path: root/src/base/QXmppOmemoDataBase.cpp
diff options
context:
space:
mode:
authorLinus Jahn <lnj@kaidan.im>2022-05-31 12:22:48 +0200
committerLinus Jahn <lnj@kaidan.im>2022-08-13 15:55:03 +0200
commitf0e0e1cd227c08ffd97aa42813a479b8c3ca6d23 (patch)
tree12ca6aefdef9195ee8937406db86e73cf1a5f820 /src/base/QXmppOmemoDataBase.cpp
parent87df8a8dda385558d39639ce09e2717974264ab6 (diff)
downloadqxmpp-f0e0e1cd227c08ffd97aa42813a479b8c3ca6d23.tar.gz
Split up OMEMO into extra module
Diffstat (limited to 'src/base/QXmppOmemoDataBase.cpp')
-rw-r--r--src/base/QXmppOmemoDataBase.cpp290
1 files changed, 290 insertions, 0 deletions
diff --git a/src/base/QXmppOmemoDataBase.cpp b/src/base/QXmppOmemoDataBase.cpp
new file mode 100644
index 00000000..a75d54ea
--- /dev/null
+++ b/src/base/QXmppOmemoDataBase.cpp
@@ -0,0 +1,290 @@
+// SPDX-FileCopyrightText: 2021 Germán Márquez Mejía <mancho@olomono.de>
+// SPDX-FileCopyrightText: 2021 Melvin Keskin <melvo@olomono.de>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "QXmppConstants_p.h"
+#include "QXmppOmemoElement_p.h"
+#include "QXmppOmemoEnvelope_p.h"
+#include "QXmppUtils.h"
+
+#include <QDomElement>
+#include <QXmlStreamWriter>
+
+/// \cond
+///
+/// \class QXmppOmemoEnvelope
+///
+/// \brief The QXmppOmemoEnvelope class represents an OMEMO envelope as
+/// defined by \xep{0384, OMEMO Encryption}.
+///
+
+///
+/// Returns the ID of the recipient's device.
+///
+/// The ID is 0 if it is unset.
+///
+/// \return the recipient's device ID
+///
+uint32_t QXmppOmemoEnvelope::recipientDeviceId() const
+{
+ return m_recipientDeviceId;
+}
+
+///
+/// Sets the ID of the recipient's device.
+///
+/// The ID must be at least 1 and at most \c std::numeric_limits<int32_t>::max().
+///
+/// \param id recipient's device ID
+///
+void QXmppOmemoEnvelope::setRecipientDeviceId(uint32_t id)
+{
+ m_recipientDeviceId = id;
+}
+
+///
+/// Returns true if a pre-key was used to prepare this envelope.
+///
+/// The default is false.
+///
+/// \return true if a pre-key was used to prepare this envelope, otherwise false
+///
+bool QXmppOmemoEnvelope::isUsedForKeyExchange() const
+{
+ return m_isUsedForKeyExchange;
+}
+
+///
+/// Sets whether a pre-key was used to prepare this envelope.
+///
+/// \param isUsed whether a pre-key was used to prepare this envelope
+///
+void QXmppOmemoEnvelope::setIsUsedForKeyExchange(bool isUsed)
+{
+ m_isUsedForKeyExchange = isUsed;
+}
+
+///
+/// Returns the BLOB containing the data for the underlying double ratchet library.
+///
+/// It should be treated like an obscure BLOB being passed as is to the ratchet
+/// library for further processing.
+///
+/// \return the binary data for the ratchet library
+///
+QByteArray QXmppOmemoEnvelope::data() const
+{
+ return m_data;
+}
+
+///
+/// Sets the BLOB containing the data from the underlying double ratchet library.
+///
+/// It should be treated like an obscure BLOB produced by the ratchet library.
+///
+/// \param data binary data from the ratchet library
+///
+void QXmppOmemoEnvelope::setData(const QByteArray &data)
+{
+ m_data = data;
+}
+
+void QXmppOmemoEnvelope::parse(const QDomElement &element)
+{
+ m_recipientDeviceId = element.attribute(QStringLiteral("rid")).toInt();
+
+ const auto isUsedForKeyExchange = element.attribute(QStringLiteral("kex"));
+ if (isUsedForKeyExchange == QStringLiteral("true") ||
+ isUsedForKeyExchange == QStringLiteral("1")) {
+ m_isUsedForKeyExchange = true;
+ }
+
+ m_data = QByteArray::fromBase64(element.text().toLatin1());
+}
+
+void QXmppOmemoEnvelope::toXml(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement(QStringLiteral("key"));
+ writer->writeAttribute(QStringLiteral("rid"), QString::number(m_recipientDeviceId));
+
+ if (m_isUsedForKeyExchange) {
+ helperToXmlAddAttribute(writer, QStringLiteral("kex"), QStringLiteral("true"));
+ }
+
+ writer->writeCharacters(m_data.toBase64());
+ writer->writeEndElement();
+}
+
+///
+/// Determines whether the given DOM element is an OMEMO envelope.
+///
+/// \param element DOM element being checked
+///
+/// \return true if element is an OMEMO envelope, otherwise false
+///
+bool QXmppOmemoEnvelope::isOmemoEnvelope(const QDomElement &element)
+{
+ return element.tagName() == QStringLiteral("key") &&
+ element.namespaceURI() == ns_omemo_2;
+}
+
+///
+/// \class QXmppOmemoElement
+///
+/// \brief The QXmppOmemoElement class represents an OMEMO element as
+/// defined by \xep{0384, OMEMO Encryption}.
+///
+
+///
+/// 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 m_senderDeviceId;
+}
+
+///
+/// Sets the ID of the sender's device.
+///
+/// The ID must be at least 1 and at most
+/// \c std::numeric_limits<int32_t>::max().
+///
+/// \param id sender's device ID
+///
+void QXmppOmemoElement::setSenderDeviceId(uint32_t id)
+{
+ m_senderDeviceId = id;
+}
+
+///
+/// Returns the payload which consists of the encrypted SCE envelope.
+///
+/// \return the encrypted payload
+///
+QByteArray QXmppOmemoElement::payload() const
+{
+ return m_payload;
+}
+
+///
+/// Sets the payload which consists of the encrypted SCE envelope.
+///
+/// \param payload encrypted payload
+///
+void QXmppOmemoElement::setPayload(const QByteArray &payload)
+{
+ m_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 = m_envelopes.constFind(recipientJid);
+ itr != m_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, const QXmppOmemoEnvelope &envelope)
+{
+ m_envelopes.insert(QXmppUtils::jidToBareJid(recipientJid), envelope);
+}
+
+void QXmppOmemoElement::parse(const QDomElement &element)
+{
+ const auto header = element.firstChildElement(QStringLiteral("header"));
+
+ m_senderDeviceId = header.attribute(QStringLiteral("sid")).toInt();
+
+ for (auto recipient = header.firstChildElement(QStringLiteral("keys"));
+ !recipient.isNull();
+ recipient = recipient.nextSiblingElement(QStringLiteral("keys"))) {
+ const auto recipientJid = recipient.attribute(QStringLiteral("jid"));
+
+ for (auto envelope = recipient.firstChildElement(QStringLiteral("key"));
+ !envelope.isNull();
+ envelope = envelope.nextSiblingElement(QStringLiteral("key"))) {
+ QXmppOmemoEnvelope omemoEnvelope;
+ omemoEnvelope.parse(envelope);
+ addEnvelope(recipientJid, omemoEnvelope);
+ }
+ }
+
+ m_payload = QByteArray::fromBase64(element.firstChildElement(QStringLiteral("payload")).text().toLatin1());
+}
+
+void QXmppOmemoElement::toXml(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement(QStringLiteral("encrypted"));
+ writer->writeDefaultNamespace(ns_omemo_2);
+
+ writer->writeStartElement(QStringLiteral("header"));
+ writer->writeAttribute(QStringLiteral("sid"), QString::number(m_senderDeviceId));
+
+ const auto recipientJids = m_envelopes.uniqueKeys();
+ for (const auto &recipientJid : recipientJids) {
+ writer->writeStartElement(QStringLiteral("keys"));
+ writer->writeAttribute(QStringLiteral("jid"), recipientJid);
+
+ for (auto itr = m_envelopes.constFind(recipientJid);
+ itr != m_envelopes.constEnd() && itr.key() == recipientJid;
+ ++itr) {
+ const auto &envelope = itr.value();
+ envelope.toXml(writer);
+ }
+
+ writer->writeEndElement(); // keys
+ }
+
+ writer->writeEndElement(); // header
+
+ // The payload element is only included if there is a payload.
+ // An empty OMEMO message does not contain a payload.
+ if (!m_payload.isEmpty()) {
+ writer->writeTextElement(QStringLiteral("payload"), m_payload.toBase64());
+ }
+
+ writer->writeEndElement(); // encrypted
+}
+
+///
+/// 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_2;
+}
+/// \endcond