diff options
author | Carl Schwan <carl@carlschwan.eu> | 2021-01-23 21:46:26 +0100 |
---|---|---|
committer | Tobias Fella <fella@posteo.de> | 2021-12-01 21:34:52 +0100 |
commit | c8d67f737e84bbec98a54fc19a8aa56dbc39d542 (patch) | |
tree | 094704820b91f7f31bbb0562e2e01f3f1fd2a311 | |
parent | e2075a1f33f7987385fc61338ce1756715fdaf6a (diff) | |
download | libquotient-c8d67f737e84bbec98a54fc19a8aa56dbc39d542.tar.gz libquotient-c8d67f737e84bbec98a54fc19a8aa56dbc39d542.zip |
Implement Inboundsession
-rw-r--r-- | lib/olm/e2ee.h | 71 | ||||
-rw-r--r-- | lib/olm/errors.cpp | 17 | ||||
-rw-r--r-- | lib/olm/errors.h | 39 | ||||
-rw-r--r-- | lib/olm/qolmaccount.cpp | 41 | ||||
-rw-r--r-- | lib/olm/qolmaccount.h | 61 | ||||
-rw-r--r-- | lib/olm/qolminboundsession.cpp | 157 | ||||
-rw-r--r-- | lib/olm/qolminboundsession.h | 29 |
7 files changed, 307 insertions, 108 deletions
diff --git a/lib/olm/e2ee.h b/lib/olm/e2ee.h new file mode 100644 index 00000000..40ab56c7 --- /dev/null +++ b/lib/olm/e2ee.h @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru> +// SPDX-FileCopyrightText: 2019 Kitsune Ral <Kitsune-Ral@users.sf.net> +// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org> +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include "util.h" +#include <optional> +#include <string> +#include <variant> +#include <QMap> + +#include <QStringList> + +namespace Quotient { +inline const auto CiphertextKeyL = "ciphertext"_ls; +inline const auto SenderKeyKeyL = "sender_key"_ls; +inline const auto DeviceIdKeyL = "device_id"_ls; +inline const auto SessionIdKeyL = "session_id"_ls; + +inline const auto AlgorithmKeyL = "algorithm"_ls; +inline const auto RotationPeriodMsKeyL = "rotation_period_ms"_ls; +inline const auto RotationPeriodMsgsKeyL = "rotation_period_msgs"_ls; + +inline const auto AlgorithmKey = QStringLiteral("algorithm"); +inline const auto RotationPeriodMsKey = QStringLiteral("rotation_period_ms"); +inline const auto RotationPeriodMsgsKey = + QStringLiteral("rotation_period_msgs"); + +inline const auto Ed25519Key = QStringLiteral("ed25519"); +inline const auto Curve25519Key = QStringLiteral("curve25519"); +inline const auto SignedCurve25519Key = QStringLiteral("signed_curve25519"); +inline const auto OlmV1Curve25519AesSha2AlgoKey = + QStringLiteral("m.olm.v1.curve25519-aes-sha2"); +inline const auto MegolmV1AesSha2AlgoKey = + QStringLiteral("m.megolm.v1.aes-sha2"); +inline const QStringList SupportedAlgorithms = { OlmV1Curve25519AesSha2AlgoKey, + MegolmV1AesSha2AlgoKey }; + +struct Unencrypted {}; +struct Encrypted { + QByteArray key; +}; + +using PicklingMode = std::variant<Unencrypted, Encrypted>; + +template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; +template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; + +struct IdentityKeys +{ + QByteArray curve25519; + QByteArray ed25519; +}; + +//! Struct representing the the one-time keys. +struct OneTimeKeys +{ + QMap<QString, QMap<QString, QString>> keys; + + //! Get the HashMap containing the curve25519 one-time keys. + QMap<QString, QString> curve25519() const; + + //! Get a reference to the hashmap corresponding to given key type. + std::optional<QMap<QString, QString>> get(QString keyType) const; +}; + +bool operator==(const IdentityKeys& lhs, const IdentityKeys& rhs); + +} // namespace Quotient diff --git a/lib/olm/errors.cpp b/lib/olm/errors.cpp new file mode 100644 index 00000000..fce177c6 --- /dev/null +++ b/lib/olm/errors.cpp @@ -0,0 +1,17 @@ +#include "olm/errors.h" + +Quotient::OlmError Quotient::fromString(const std::string &error_raw) { + if (error_raw.compare("BAD_ACCOUNT_KEY")) { + return OlmError::BadAccountKey; + } else if (error_raw.compare("BAD_MESSAGE_KEY_ID")) { + return OlmError::BadMessageKeyId; + } else if (error_raw.compare("INVALID_BASE64")) { + return OlmError::InvalidBase64; + } else if (error_raw.compare("NOT_ENOUGH_RANDOM")) { + return OlmError::NotEnoughRandom; + } else if (error_raw.compare("OUTPUT_BUFFER_TOO_SMALL")) { + return OlmError::OutputBufferTooSmall; + } else { + return OlmError::Unknown; + } +} diff --git a/lib/olm/errors.h b/lib/olm/errors.h index e51400ef..fc2ae2e9 100644 --- a/lib/olm/errors.h +++ b/lib/olm/errors.h @@ -2,22 +2,16 @@ // // SPDX-License-Identifier: LGPL-2.1-or-later -#pragma once +#ifndef QUOTIENT_OLM_ERROR_H +#define QUOTIENT_OLM_ERROR_H -//! All errors that could be caused by an operation regarding an `QOlmAccount`. -//! Errors are named exactly like the ones in libolm. -enum OlmAccountError { - BadAccountKey, - BadMessageKeyId, - InvalidBase64, - NotEnoughRandom, - OutputBufferTooSmall, - Unknown, -}; +#include <string> -//! All errors that could be caused by an operation regarding an `QOlmSession`. +namespace Quotient { +//! All errors that could be caused by an operation regarding Olm //! Errors are named exactly like the ones in libolm. -enum OlmSessionError { +enum OlmError +{ BadAccountKey, BadMessageFormat, BadMessageKeyId, @@ -26,21 +20,10 @@ enum OlmSessionError { InvalidBase64, NotEnoughRandom, OutputBufferTooSmall, - Unknown, -}; - -//! All errors that could be caused by an operation -//! regarding QOlmOutboundGroupSession and QOlmInboundGroupSession. -//! Errors are named exactly like the ones in libolm. -enum OlmGroupSessionError { - BadAccountKey, - BadMessageFormat, - BadMessageMac, - BadMessageVersion, - BadSessionKey, - InvalidBase64, - NotEnoughRandom, - OutputBufferTooSmall, UnknownMessageIndex, Unknown, }; + +} //namespace Quotient + +#endif diff --git a/lib/olm/qolmaccount.cpp b/lib/olm/qolmaccount.cpp index a6a07962..bde9b712 100644 --- a/lib/olm/qolmaccount.cpp +++ b/lib/olm/qolmaccount.cpp @@ -9,6 +9,8 @@ #include <QDebug> #include <iostream> +using namespace Quotient; + QMap<QString, QString> OneTimeKeys::curve25519() const { return keys[QStringLiteral("curve25519")]; @@ -23,7 +25,7 @@ std::optional<QMap<QString, QString>> OneTimeKeys::get(QString keyType) const } // Convert PicklingMode to key -QByteArray toKey(PicklingMode mode) +QByteArray toKey(const PicklingMode &mode) { if (std::holds_alternative<Unencrypted>(mode)) { return ""; @@ -36,25 +38,30 @@ bool operator==(const IdentityKeys& lhs, const IdentityKeys& rhs) return lhs.curve25519 == rhs.curve25519 &&& lhs.ed25519 == rhs.ed25519; } -// Conver olm error to enum -QOlmAccount::OlmAccountError lastError(OlmAccount *account) { - const std::string error_raw = olm_account_last_error(account); - +// TODO use impl from errors.cpp +OlmError fromString(const std::string &error_raw) { if (error_raw.compare("BAD_ACCOUNT_KEY")) { - return QOlmAccount::OlmAccountError::BadAccountKey; + return OlmError::BadAccountKey; } else if (error_raw.compare("BAD_MESSAGE_KEY_ID")) { - return QOlmAccount::OlmAccountError::BadMessageKeyId; + return OlmError::BadMessageKeyId; } else if (error_raw.compare("INVALID_BASE64")) { - return QOlmAccount::OlmAccountError::InvalidBase64; + return OlmError::InvalidBase64; } else if (error_raw.compare("NOT_ENOUGH_RANDOM")) { - return QOlmAccount::OlmAccountError::NotEnoughRandom; + return OlmError::NotEnoughRandom; } else if (error_raw.compare("OUTPUT_BUFFER_TOO_SMALL")) { - return QOlmAccount::OlmAccountError::OutputBufferTooSmall; + return OlmError::OutputBufferTooSmall; } else { - return QOlmAccount::OlmAccountError::Unknown; + return OlmError::Unknown; } } +// Conver olm error to enum +OlmError lastError(OlmAccount *account) { + const std::string error_raw = olm_account_last_error(account); + + return fromString(error_raw); +} + QByteArray getRandom(size_t bufferSize) { QByteArray buffer(bufferSize, '0'); @@ -83,7 +90,7 @@ std::optional<QOlmAccount> QOlmAccount::create() return std::make_optional<QOlmAccount>(account); } -std::variant<QOlmAccount, QOlmAccount::OlmAccountError> QOlmAccount::unpickle(QByteArray pickled, PicklingMode mode) +std::variant<QOlmAccount, OlmError> QOlmAccount::unpickle(QByteArray &pickled, const PicklingMode &mode) { auto account = olm_account(new uint8_t[olm_account_size()]); const QByteArray key = toKey(mode); @@ -94,7 +101,7 @@ std::variant<QOlmAccount, QOlmAccount::OlmAccountError> QOlmAccount::unpickle(QB return QOlmAccount(account); } -std::variant<QByteArray, QOlmAccount::OlmAccountError> QOlmAccount::pickle(PicklingMode mode) +std::variant<QByteArray, OlmError> QOlmAccount::pickle(const PicklingMode &mode) { const QByteArray key = toKey(mode); const size_t pickleLength = olm_pickle_account_length(m_account); @@ -107,7 +114,7 @@ std::variant<QByteArray, QOlmAccount::OlmAccountError> QOlmAccount::pickle(Pickl return pickleBuffer; } -std::variant<IdentityKeys, QOlmAccount::OlmAccountError> QOlmAccount::identityKeys() +std::variant<IdentityKeys, OlmError> QOlmAccount::identityKeys() { const size_t keyLength = olm_account_identity_keys_length(m_account); QByteArray keyBuffer(keyLength, '0'); @@ -122,7 +129,7 @@ std::variant<IdentityKeys, QOlmAccount::OlmAccountError> QOlmAccount::identityKe }; } -std::variant<QString, QOlmAccount::OlmAccountError> QOlmAccount::sign(QString message) const +std::variant<QString, OlmError> QOlmAccount::sign(const QString &message) const { const size_t signatureLength = olm_account_signature_length(m_account); QByteArray signatureBuffer(signatureLength, '0'); @@ -140,7 +147,7 @@ size_t QOlmAccount::maxNumberOfOneTimeKeys() const return olm_account_max_number_of_one_time_keys(m_account); } -std::optional<QOlmAccount::OlmAccountError> QOlmAccount::generateOneTimeKeys(size_t numberOfKeys) const +std::optional<OlmError> QOlmAccount::generateOneTimeKeys(size_t numberOfKeys) const { const size_t randomLen = olm_account_generate_one_time_keys_random_length(m_account, numberOfKeys); QByteArray randomBuffer = getRandom(randomLen); @@ -152,7 +159,7 @@ std::optional<QOlmAccount::OlmAccountError> QOlmAccount::generateOneTimeKeys(siz return std::nullopt; } -std::variant<OneTimeKeys, QOlmAccount::OlmAccountError> QOlmAccount::oneTimeKeys() const +std::variant<OneTimeKeys, OlmError> QOlmAccount::oneTimeKeys() const { const size_t oneTimeKeyLength = olm_account_one_time_keys_length(m_account); QByteArray oneTimeKeysBuffer(oneTimeKeyLength, '0'); diff --git a/lib/olm/qolmaccount.h b/lib/olm/qolmaccount.h index 268cd5d5..3ce1fb9a 100644 --- a/lib/olm/qolmaccount.h +++ b/lib/olm/qolmaccount.h @@ -3,44 +3,14 @@ // SPDX-License-Identifier: LGPL-2.1-or-later #pragma once -#include <QObject> -#include <QMap> -#include <optional> -#include <string> -#include <variant> +#include "olm/e2ee.h" +#include "olm/errors.h" #include "olm/olm.h" +#include <QObject> struct OlmAccount; -struct Unencrypted {}; -struct Encrypted { - QByteArray key; -}; - -using PicklingMode = std::variant<Unencrypted, Encrypted>; - -template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; -template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; - -struct IdentityKeys -{ - QByteArray curve25519; - QByteArray ed25519; -}; - -//! Struct representing the the one-time keys. -struct OneTimeKeys -{ - QMap<QString, QMap<QString, QString>> keys; - - //! Get the HashMap containing the curve25519 one-time keys. - QMap<QString, QString> curve25519() const; - - //! Get a reference to the hashmap corresponding to given key type. - std::optional<QMap<QString, QString>> get(QString keyType) const; -}; - -bool operator==(const IdentityKeys& lhs, const IdentityKeys& rhs); +namespace Quotient { //! An olm account manages all cryptographic keys used on a device. //! \code{.cpp} @@ -51,41 +21,34 @@ class QOlmAccount public: ~QOlmAccount(); - enum OlmAccountError { - BadAccountKey, - BadMessageKeyId, - InvalidBase64, - NotEnoughRandom, - OutputBufferTooSmall, - Unknown, - }; - //! Creates a new instance of OlmAccount. During the instantiation //! the Ed25519 fingerprint key pair and the Curve25519 identity key //! pair are generated. For more information see <a //! href="https://matrix.org/docs/guides/e2e_implementation.html#keys-used-in-end-to-end-encryption">here</a>. static std::optional<QOlmAccount> create(); - static std::variant<QOlmAccount, OlmAccountError> unpickle(QByteArray picked, PicklingMode mode); + static std::variant<QOlmAccount, OlmError> unpickle(QByteArray &picked, const PicklingMode &mode); //! Serialises an OlmAccount to encrypted Base64. - std::variant<QByteArray, OlmAccountError> pickle(PicklingMode mode); - std::variant<IdentityKeys, OlmAccountError> identityKeys(); + std::variant<QByteArray, OlmError> pickle(const PicklingMode &mode); + std::variant<IdentityKeys, OlmError> identityKeys(); //! Returns the signature of the supplied message. - std::variant<QString, OlmAccountError> sign(QString message) const; + std::variant<QString, OlmError> sign(const QString &message) const; //! Maximum number of one time keys that this OlmAccount can //! currently hold. size_t maxNumberOfOneTimeKeys() const; //! Generates the supplied number of one time keys. - std::optional<OlmAccountError> generateOneTimeKeys(size_t numberOfKeys) const; + std::optional<OlmError> generateOneTimeKeys(size_t numberOfKeys) const; //! Gets the OlmAccount's one time keys formatted as JSON. - std::variant<OneTimeKeys, OlmAccountError> oneTimeKeys() const; + std::variant<OneTimeKeys, OlmError> oneTimeKeys() const; // HACK do not use directly QOlmAccount(OlmAccount *account); private: OlmAccount *m_account; }; + +} // namespace Quotient diff --git a/lib/olm/qolminboundsession.cpp b/lib/olm/qolminboundsession.cpp index fbcaa802..62de138f 100644 --- a/lib/olm/qolminboundsession.cpp +++ b/lib/olm/qolminboundsession.cpp @@ -2,9 +2,42 @@ // // SPDX-License-Identifier: LGPL-2.1-or-later -#include <qolminboundsession.h> +#include "olm/qolminboundsession.h" +#include <QString> +#include <QByteArray> -std::variant<QOlmInboundGroupSession, OlmInboundGroupSession> QOlmInboundGroupSession::create(const QString &key) +using namespace Quotient; + +// TODO move to errors.cpp +OlmError fromString(const std::string &error_raw) { + if (error_raw.compare("BAD_ACCOUNT_KEY")) { + return OlmError::BadAccountKey; + } else if (error_raw.compare("BAD_MESSAGE_KEY_ID")) { + return OlmError::BadMessageKeyId; + } else if (error_raw.compare("INVALID_BASE64")) { + return OlmError::InvalidBase64; + } else if (error_raw.compare("NOT_ENOUGH_RANDOM")) { + return OlmError::NotEnoughRandom; + } else if (error_raw.compare("OUTPUT_BUFFER_TOO_SMALL")) { + return OlmError::OutputBufferTooSmall; + } else { + return OlmError::Unknown; + } +} + +OlmError lastError(OlmInboundGroupSession *session) { + const std::string error_raw = olm_inbound_group_session_last_error(session); + + return fromString(error_raw); +} + +QOlmInboundGroupSession::QOlmInboundGroupSession(OlmInboundGroupSession *session, const QByteArray &buffer) + : m_groupSession(session) + , m_buffer(buffer) +{ +} + +std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::create(const QString &key) { auto olmInboundGroupSessionBuf = QByteArray(olm_inbound_group_session_size(), '0'); @@ -12,19 +45,121 @@ std::variant<QOlmInboundGroupSession, OlmInboundGroupSession> QOlmInboundGroupSe QByteArray keyBuf = key.toUtf8(); - const auto error = olm_init_inbound_group_session(olmInboundGroupSession, keyBuf.data(), keyBuf.size()); + const auto error = olm_init_inbound_group_session(olmInboundGroupSession, + reinterpret_cast<const uint8_t *>(keyBuf.data()), keyBuf.size()); if (error == olm_error()) { - return + return lastError(olmInboundGroupSession); } - if create_error == errors::olm_error() { - Err(Self::last_error(olm_inbound_group_session_ptr)) - } else { - Ok(OlmInboundGroupSession { - group_session_ptr: olm_inbound_group_session_ptr, - group_session_buf: olm_inbound_group_session_buf, - }) + return QOlmInboundGroupSession(olmInboundGroupSession, olmInboundGroupSessionBuf); +} + + +std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::import(const QString &key) +{ + auto olmInboundGroupSessionBuf = QByteArray(olm_inbound_group_session_size(), '0'); + const auto olmInboundGroupSession = olm_inbound_group_session(olmInboundGroupSessionBuf.data()); + QByteArray keyBuf = key.toUtf8(); + + const auto error = olm_import_inbound_group_session(olmInboundGroupSession, + reinterpret_cast<const uint8_t *>(keyBuf.data()), keyBuf.size()); + if (error == olm_error()) { + return lastError(olmInboundGroupSession); + } + + return QOlmInboundGroupSession(olmInboundGroupSession, olmInboundGroupSessionBuf); +} + +QByteArray toKey(const PicklingMode &mode) +{ + if (std::holds_alternative<Unencrypted>(mode)) { + return ""; + } + return std::get<Encrypted>(mode).key; +} + +std::variant<QByteArray, OlmError> QOlmInboundGroupSession::pickle(const PicklingMode &mode) const +{ + QByteArray pickledBuf(olm_pickle_inbound_group_session_length(m_groupSession), '0'); + const QByteArray key = toKey(mode); + const auto error = olm_pickle_inbound_group_session(m_groupSession, key.data(), key.length(), pickledBuf.data(), + pickledBuf.length()); + if (error == olm_error()) { + return lastError(m_groupSession); } + return pickledBuf; +} + +std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::unpicke(QByteArray &picked, const PicklingMode &mode) +{ + QByteArray groupSessionBuf(olm_inbound_group_session_size(), '0'); + auto groupSession = olm_inbound_group_session(groupSessionBuf.data()); + const QByteArray key = toKey(mode); + const auto error = olm_unpickle_inbound_group_session(groupSession, key.data(), key.length(), picked.data(), picked.size()); + if (error == olm_error()) { + return lastError(groupSession); + } + return QOlmInboundGroupSession(groupSession, groupSessionBuf); +} + +std::variant<std::pair<QString, uint32_t>, OlmError> QOlmInboundGroupSession::decrypt(QString &message) +{ + // This is for capturing the output of olm_group_decrypt + uint32_t messageIndex = 0; + + // We need to clone the message because + // olm_decrypt_max_plaintext_length destroys the input buffer + QByteArray messageBuf = message.toUtf8(); + + QByteArray plaintextBuf(olm_group_decrypt_max_plaintext_length(m_groupSession, + reinterpret_cast<uint8_t *>(messageBuf.data()), messageBuf.length()), '0'); + const auto messageLen = messageBuf.length(); + const auto plaintextMaxLen = plaintextBuf.length(); + + const auto plaintextLen = olm_group_decrypt(m_groupSession, reinterpret_cast<uint8_t *>(messageBuf.data()), + messageLen, reinterpret_cast<uint8_t *>(plaintextBuf.data()), plaintextMaxLen, &messageIndex); + + // Error code or plaintext length is returned + const auto decryptError = plaintextLen; + + if (decryptError == olm_error()) { + return lastError(m_groupSession); + } + + plaintextBuf.truncate(plaintextLen); + return std::make_pair<QString, qint32>(QString(plaintextBuf), messageIndex); +} +std::variant<QByteArray, OlmError> QOlmInboundGroupSession::exportSession(uint32_t messageIndex) +{ + const auto keyLen = olm_export_inbound_group_session_length(m_groupSession); + QByteArray keyBuf(keyLen, '0'); + const auto error = olm_export_inbound_group_session(m_groupSession, reinterpret_cast<uint8_t *>(keyBuf.data()), keyLen, messageIndex); + + if (error == olm_error()) { + return lastError(m_groupSession); + } + return keyBuf; +} + +uint32_t QOlmInboundGroupSession::firstKnownIndex() const +{ + return olm_inbound_group_session_first_known_index(m_groupSession); +} + +std::variant<QByteArray, OlmError> QOlmInboundGroupSession::sessionId() const +{ + QByteArray sessionIdBuf(olm_inbound_group_session_id_length(m_groupSession), '0'); + const auto error = olm_inbound_group_session_id(m_groupSession, reinterpret_cast<uint8_t *>(sessionIdBuf.data()), + sessionIdBuf.length()); + if (error == olm_error()) { + return lastError(m_groupSession); + } + return sessionIdBuf; +} + +bool QOlmInboundGroupSession::isVerified() const +{ + return olm_inbound_group_session_is_verified(m_groupSession) != 0; } diff --git a/lib/olm/qolminboundsession.h b/lib/olm/qolminboundsession.h index 520f8b68..c75b7285 100644 --- a/lib/olm/qolminboundsession.h +++ b/lib/olm/qolminboundsession.h @@ -6,6 +6,11 @@ #include <QByteArray> #include <variant> +#include "olm/olm.h" +#include "olm/errors.h" +#include "olm/e2ee.h" + +namespace Quotient { //! An in-bound group session is responsible for decrypting incoming //! communication in a Megolm session. @@ -13,9 +18,27 @@ struct QOlmInboundGroupSession { public: //! Creates a new instance of `OlmInboundGroupSession`. - static std::variant<OlmInboundGroupSession, OlmGroupSessionError> create(const QString &key); + static std::variant<QOlmInboundGroupSession, OlmError> create(const QString &key); + //! Import an inbound group session, from a previous export. + static std::variant<QOlmInboundGroupSession, OlmError> import(const QString &key); + //! Serialises an `OlmInboundGroupSession` to encrypted Base64. + std::variant<QByteArray, OlmError> pickle(const PicklingMode &mode) const; + //! Deserialises from encrypted Base64 that was previously obtained by pickling + //! an `OlmInboundGroupSession`. + static std::variant<QOlmInboundGroupSession, OlmError> unpicke(QByteArray &picked, const PicklingMode &mode); + //! Decrypts ciphertext received for this group session. + std::variant<std::pair<QString, uint32_t>, OlmError> decrypt(QString &message); + //! Export the base64-encoded ratchet key for this session, at the given index, + //! in a format which can be used by import. + std::variant<QByteArray, OlmError> exportSession(uint32_t messageIndex); + //! Get the first message index we know how to decrypt. + uint32_t firstKnownIndex() const; + //! Get a base64-encoded identifier for this session. + std::variant<QByteArray, OlmError> sessionId() const; + bool isVerified() const; private: - OlmInboundGroupSession *m_groupSession + QOlmInboundGroupSession(OlmInboundGroupSession *session, const QByteArray &buffer); + OlmInboundGroupSession *m_groupSession; QByteArray m_buffer; }; - +} // namespace Quotient |