aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--autotests/testgroupsession.cpp8
-rw-r--r--autotests/testolmaccount.cpp2
-rw-r--r--lib/connection.cpp23
-rw-r--r--lib/database.cpp32
-rw-r--r--lib/e2ee/qolmaccount.cpp37
-rw-r--r--lib/e2ee/qolmaccount.h4
-rw-r--r--lib/e2ee/qolminboundsession.cpp28
-rw-r--r--lib/e2ee/qolminboundsession.h4
-rw-r--r--lib/e2ee/qolmoutboundsession.cpp24
-rw-r--r--lib/e2ee/qolmoutboundsession.h6
-rw-r--r--lib/e2ee/qolmsession.cpp46
-rw-r--r--lib/e2ee/qolmsession.h2
-rw-r--r--lib/e2ee/qolmutils.h18
-rw-r--r--lib/room.cpp45
14 files changed, 150 insertions, 129 deletions
diff --git a/autotests/testgroupsession.cpp b/autotests/testgroupsession.cpp
index 18ace73b..1054a160 100644
--- a/autotests/testgroupsession.cpp
+++ b/autotests/testgroupsession.cpp
@@ -16,13 +16,13 @@ void TestGroupSession::groupSessionPicklingValid()
QVERIFY(QByteArray::fromBase64(ogsId).size() > 0);
QCOMPARE(0, ogs->sessionMessageIndex());
- auto ogsPickled = ogs->pickle(Unencrypted {}).value();
+ auto&& ogsPickled = ogs->pickle(Unencrypted {});
auto ogs2 =
QOlmOutboundGroupSession::unpickle(std::move(ogsPickled), Unencrypted{})
.value();
QCOMPARE(ogsId, ogs2->sessionId());
- auto igs = QOlmInboundGroupSession::create(ogs->sessionKey().value());
+ auto igs = QOlmInboundGroupSession::create(ogs->sessionKey()).value();
const auto igsId = igs->sessionId();
// ID is valid base64?
QVERIFY(QByteArray::fromBase64(igsId).size() > 0);
@@ -39,11 +39,11 @@ void TestGroupSession::groupSessionPicklingValid()
void TestGroupSession::groupSessionCryptoValid()
{
auto ogs = QOlmOutboundGroupSession::create();
- auto igs = QOlmInboundGroupSession::create(ogs->sessionKey().value());
+ auto igs = QOlmInboundGroupSession::create(ogs->sessionKey()).value();
QCOMPARE(ogs->sessionId(), igs->sessionId());
const auto plainText = "Hello world!";
- const auto ciphertext = ogs->encrypt(plainText).value();
+ const auto ciphertext = ogs->encrypt(plainText);
// ciphertext valid base64?
QVERIFY(QByteArray::fromBase64(ciphertext).size() > 0);
diff --git a/autotests/testolmaccount.cpp b/autotests/testolmaccount.cpp
index 0e1eab84..56532698 100644
--- a/autotests/testolmaccount.cpp
+++ b/autotests/testolmaccount.cpp
@@ -23,7 +23,7 @@ void TestOlmAccount::pickleUnpickledTest()
QOlmAccount olmAccount(QStringLiteral("@foo:bar.com"), QStringLiteral("QuotientTestDevice"));
olmAccount.createNewAccount();
auto identityKeys = olmAccount.identityKeys();
- auto pickled = olmAccount.pickle(Unencrypted{}).value();
+ auto pickled = olmAccount.pickle(Unencrypted{});
QOlmAccount olmAccount2(QStringLiteral("@foo:bar.com"), QStringLiteral("QuotientTestDevice"));
auto unpickleResult = olmAccount2.unpickle(std::move(pickled),
Unencrypted{});
diff --git a/lib/connection.cpp b/lib/connection.cpp
index cd8ee727..0afbffbc 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -206,13 +206,9 @@ public:
}
void saveSession(const QOlmSession& session, const QString& senderKey) const
{
- if (auto pickleResult = session.pickle(picklingMode))
- q->database()->saveOlmSession(senderKey, session.sessionId(),
- *pickleResult,
- QDateTime::currentDateTime());
- else
- qCWarning(E2EE) << "Failed to pickle olm session. Error"
- << pickleResult.error();
+ q->database()->saveOlmSession(senderKey, session.sessionId(),
+ session.pickle(picklingMode),
+ QDateTime::currentDateTime());
}
template <typename FnT>
@@ -2219,11 +2215,7 @@ void Connection::saveOlmAccount()
{
#ifdef Quotient_E2EE_ENABLED
qCDebug(E2EE) << "Saving olm account";
- if (const auto expectedPickle = d->olmAccount->pickle(d->picklingMode))
- d->database->setAccountPickle(*expectedPickle);
- else
- qCWarning(E2EE) << "Couldn't save Olm account pickle:"
- << expectedPickle.error();
+ d->database->setAccountPickle(d->olmAccount->pickle(d->picklingMode));
#endif
}
@@ -2300,11 +2292,8 @@ std::pair<QOlmMessage::Type, QByteArray> Connection::Private::olmEncryptMessage(
const auto& curveKey = curveKeyForUserDevice(userId, device);
const auto& olmSession = olmSessions.at(curveKey).front();
const auto result = olmSession->encrypt(message);
- if (const auto pickle = olmSession->pickle(picklingMode)) {
- database->updateOlmSession(curveKey, olmSession->sessionId(), *pickle);
- } else {
- qWarning(E2EE) << "Failed to pickle olm session: " << pickle.error();
- }
+ database->updateOlmSession(curveKey, olmSession->sessionId(),
+ olmSession->pickle(picklingMode));
return { result.type(), result.toCiphertext() };
}
diff --git a/lib/database.cpp b/lib/database.cpp
index 4eb82cf5..2b472648 100644
--- a/lib/database.cpp
+++ b/lib/database.cpp
@@ -323,23 +323,21 @@ void Database::saveCurrentOutboundMegolmSession(
const QOlmOutboundGroupSession& session)
{
const auto pickle = session.pickle(picklingMode);
- if (pickle) {
- auto deleteQuery = prepareQuery(QStringLiteral("DELETE FROM outbound_megolm_sessions WHERE roomId=:roomId AND sessionId=:sessionId;"));
- deleteQuery.bindValue(":roomId", roomId);
- deleteQuery.bindValue(":sessionId", session.sessionId());
-
- auto insertQuery = prepareQuery(QStringLiteral("INSERT INTO outbound_megolm_sessions(roomId, sessionId, pickle, creationTime, messageCount) VALUES(:roomId, :sessionId, :pickle, :creationTime, :messageCount);"));
- insertQuery.bindValue(":roomId", roomId);
- insertQuery.bindValue(":sessionId", session.sessionId());
- insertQuery.bindValue(":pickle", pickle.value());
- insertQuery.bindValue(":creationTime", session.creationTime());
- insertQuery.bindValue(":messageCount", session.messageCount());
-
- transaction();
- execute(deleteQuery);
- execute(insertQuery);
- commit();
- }
+ auto deleteQuery = prepareQuery(QStringLiteral("DELETE FROM outbound_megolm_sessions WHERE roomId=:roomId AND sessionId=:sessionId;"));
+ deleteQuery.bindValue(":roomId", roomId);
+ deleteQuery.bindValue(":sessionId", session.sessionId());
+
+ auto insertQuery = prepareQuery(QStringLiteral("INSERT INTO outbound_megolm_sessions(roomId, sessionId, pickle, creationTime, messageCount) VALUES(:roomId, :sessionId, :pickle, :creationTime, :messageCount);"));
+ insertQuery.bindValue(":roomId", roomId);
+ insertQuery.bindValue(":sessionId", session.sessionId());
+ insertQuery.bindValue(":pickle", pickle);
+ insertQuery.bindValue(":creationTime", session.creationTime());
+ insertQuery.bindValue(":messageCount", session.messageCount());
+
+ transaction();
+ execute(deleteQuery);
+ execute(insertQuery);
+ commit();
}
QOlmOutboundGroupSessionPtr Database::loadCurrentOutboundMegolmSession(const QString& roomId, const PicklingMode& picklingMode)
diff --git a/lib/e2ee/qolmaccount.cpp b/lib/e2ee/qolmaccount.cpp
index b56272ef..d03bcb3b 100644
--- a/lib/e2ee/qolmaccount.cpp
+++ b/lib/e2ee/qolmaccount.cpp
@@ -45,9 +45,9 @@ void QOlmAccount::createNewAccount()
m_account = olm_account(new uint8_t[olm_account_size()]);
const auto randomLength = olm_create_account_random_length(m_account);
if (olm_create_account(m_account, RandomBuffer(randomLength), randomLength)
- == olm_error()) {
- throw lastError();
- }
+ == olm_error())
+ QOLM_INTERNAL_ERROR("Failed to create a new account");
+
emit needsSave();
}
@@ -64,7 +64,7 @@ OlmErrorCode QOlmAccount::unpickle(QByteArray&& pickled, const PicklingMode &mod
return OLM_SUCCESS;
}
-QOlmExpected<QByteArray> QOlmAccount::pickle(const PicklingMode &mode)
+QByteArray QOlmAccount::pickle(const PicklingMode &mode)
{
const QByteArray key = toKey(mode);
const size_t pickleLength = olm_pickle_account_length(m_account);
@@ -72,7 +72,9 @@ QOlmExpected<QByteArray> QOlmAccount::pickle(const PicklingMode &mode)
if (olm_pickle_account(m_account, key.data(), key.length(),
pickleBuffer.data(), pickleLength)
== olm_error())
- return lastErrorCode();
+ QOLM_INTERNAL_ERROR(qPrintable("Failed to pickle Olm account "
+ + accountId()));
+
return pickleBuffer;
}
@@ -82,7 +84,8 @@ IdentityKeys QOlmAccount::identityKeys() const
QByteArray keyBuffer(keyLength, '\0');
if (olm_account_identity_keys(m_account, keyBuffer.data(), keyLength)
== olm_error()) {
- throw lastError();
+ QOLM_INTERNAL_ERROR(
+ qPrintable("Failed to get " % accountId() % " identity keys"));
}
const auto key = QJsonDocument::fromJson(keyBuffer).object();
return IdentityKeys {
@@ -97,9 +100,9 @@ QByteArray QOlmAccount::sign(const QByteArray &message) const
if (olm_account_sign(m_account, message.data(), message.length(),
signatureBuffer.data(), signatureBuffer.length())
- == olm_error()) {
- throw lastError();
- }
+ == olm_error())
+ QOLM_INTERNAL_ERROR("Failed to sign a message");
+
return signatureBuffer;
}
@@ -135,9 +138,10 @@ size_t QOlmAccount::generateOneTimeKeys(size_t numberOfKeys)
const auto result = olm_account_generate_one_time_keys(
m_account, numberOfKeys, RandomBuffer(randomLength), randomLength);
- if (result == olm_error()) {
- throw lastError();
- }
+ if (result == olm_error())
+ QOLM_INTERNAL_ERROR(qPrintable(
+ "Failed to generate one-time keys for account " + accountId()));
+
emit needsSave();
return result;
}
@@ -149,9 +153,10 @@ UnsignedOneTimeKeys QOlmAccount::oneTimeKeys() const
if (olm_account_one_time_keys(m_account, oneTimeKeysBuffer.data(),
oneTimeKeyLength)
- == olm_error()) {
- throw lastError();
- }
+ == olm_error())
+ QOLM_INTERNAL_ERROR(qPrintable(
+ "Failed to obtain one-time keys for account" % accountId()));
+
const auto json = QJsonDocument::fromJson(oneTimeKeysBuffer).object();
UnsignedOneTimeKeys oneTimeKeys;
fromJson(json, oneTimeKeys.keys);
@@ -266,3 +271,5 @@ bool Quotient::ed25519VerifySignature(const QString& signingKey,
return utility.ed25519Verify(signingKeyBuf, canonicalJson, signatureBuf)
.value_or(false);
}
+
+QString QOlmAccount::accountId() const { return m_userId % '/' % m_deviceId; }
diff --git a/lib/e2ee/qolmaccount.h b/lib/e2ee/qolmaccount.h
index 0fb9803f..a5faa82a 100644
--- a/lib/e2ee/qolmaccount.h
+++ b/lib/e2ee/qolmaccount.h
@@ -41,7 +41,7 @@ public:
const PicklingMode& mode);
//! Serialises an OlmAccount to encrypted Base64.
- QOlmExpected<QByteArray> pickle(const PicklingMode &mode);
+ QByteArray pickle(const PicklingMode &mode);
//! Returns the account's public identity keys already formatted as JSON
IdentityKeys identityKeys() const;
@@ -107,6 +107,8 @@ private:
OlmAccount *m_account = nullptr; // owning
QString m_userId;
QString m_deviceId;
+
+ QString accountId() const;
};
QUOTIENT_API bool verifyIdentitySignature(const DeviceKeys& deviceKeys,
diff --git a/lib/e2ee/qolminboundsession.cpp b/lib/e2ee/qolminboundsession.cpp
index a05ddf62..1e3803f2 100644
--- a/lib/e2ee/qolminboundsession.cpp
+++ b/lib/e2ee/qolminboundsession.cpp
@@ -31,7 +31,8 @@ QOlmInboundGroupSession::~QOlmInboundGroupSession()
//delete[](reinterpret_cast<uint8_t *>(m_groupSession));
}
-std::unique_ptr<QOlmInboundGroupSession> QOlmInboundGroupSession::create(const QByteArray &key)
+QOlmExpected<QOlmInboundGroupSessionPtr> QOlmInboundGroupSession::create(
+ const QByteArray& key)
{
const auto olmInboundGroupSession = olm_inbound_group_session(new uint8_t[olm_inbound_group_session_size()]);
if (olm_init_inbound_group_session(
@@ -39,13 +40,17 @@ std::unique_ptr<QOlmInboundGroupSession> QOlmInboundGroupSession::create(const Q
reinterpret_cast<const uint8_t*>(key.constData()), key.size())
== olm_error()) {
// FIXME: create QOlmInboundGroupSession earlier and use lastErrorCode()
- throw olm_inbound_group_session_last_error_code(olmInboundGroupSession);
+ qWarning(E2EE) << "Failed to create an inbound group session:"
+ << olm_inbound_group_session_last_error(
+ olmInboundGroupSession);
+ return olm_inbound_group_session_last_error_code(olmInboundGroupSession);
}
return std::make_unique<QOlmInboundGroupSession>(olmInboundGroupSession);
}
-std::unique_ptr<QOlmInboundGroupSession> QOlmInboundGroupSession::import(const QByteArray &key)
+QOlmExpected<QOlmInboundGroupSessionPtr> QOlmInboundGroupSession::import(
+ const QByteArray& key)
{
const auto olmInboundGroupSession = olm_inbound_group_session(new uint8_t[olm_inbound_group_session_size()]);
@@ -54,7 +59,10 @@ std::unique_ptr<QOlmInboundGroupSession> QOlmInboundGroupSession::import(const Q
reinterpret_cast<const uint8_t*>(key.data()), key.size())
== olm_error()) {
// FIXME: create QOlmInboundGroupSession earlier and use lastError()
- throw olm_inbound_group_session_last_error_code(olmInboundGroupSession);
+ qWarning(E2EE) << "Failed to import an inbound group session:"
+ << olm_inbound_group_session_last_error(
+ olmInboundGroupSession);
+ return olm_inbound_group_session_last_error_code(olmInboundGroupSession);
}
return std::make_unique<QOlmInboundGroupSession>(olmInboundGroupSession);
@@ -69,7 +77,7 @@ QByteArray QOlmInboundGroupSession::pickle(const PicklingMode& mode) const
key.length(), pickledBuf.data(),
pickledBuf.length())
== olm_error()) {
- throw lastError();
+ QOLM_INTERNAL_ERROR("Failed to pickle the inbound group session");
}
return pickledBuf;
}
@@ -84,6 +92,8 @@ QOlmExpected<QOlmInboundGroupSessionPtr> QOlmInboundGroupSession::unpickle(
pickled.size())
== olm_error()) {
// FIXME: create QOlmInboundGroupSession earlier and use lastError()
+ qWarning(E2EE) << "Failed to unpickle an inbound group session:"
+ << olm_inbound_group_session_last_error(groupSession);
return olm_inbound_group_session_last_error_code(groupSession);
}
key.clear();
@@ -133,6 +143,8 @@ QOlmExpected<QByteArray> QOlmInboundGroupSession::exportSession(
m_groupSession, reinterpret_cast<uint8_t*>(keyBuf.data()),
keyLength, messageIndex)
== olm_error()) {
+ QOLM_FAIL_OR_LOG(OLM_OUTPUT_BUFFER_TOO_SMALL,
+ "Failed to export the inbound group session");
return lastErrorCode();
}
return keyBuf;
@@ -150,9 +162,9 @@ QByteArray QOlmInboundGroupSession::sessionId() const
if (olm_inbound_group_session_id(
m_groupSession, reinterpret_cast<uint8_t*>(sessionIdBuf.data()),
sessionIdBuf.length())
- == olm_error()) {
- throw lastError();
- }
+ == olm_error())
+ QOLM_INTERNAL_ERROR("Failed to obtain the group session id");
+
return sessionIdBuf;
}
diff --git a/lib/e2ee/qolminboundsession.h b/lib/e2ee/qolminboundsession.h
index 0b89349a..15979a05 100644
--- a/lib/e2ee/qolminboundsession.h
+++ b/lib/e2ee/qolminboundsession.h
@@ -17,9 +17,9 @@ class QUOTIENT_API QOlmInboundGroupSession
public:
~QOlmInboundGroupSession();
//! Creates a new instance of `OlmInboundGroupSession`.
- static std::unique_ptr<QOlmInboundGroupSession> create(const QByteArray& key);
+ static QOlmExpected<QOlmInboundGroupSessionPtr> create(const QByteArray& key);
//! Import an inbound group session, from a previous export.
- static std::unique_ptr<QOlmInboundGroupSession> import(const QByteArray& key);
+ static QOlmExpected<QOlmInboundGroupSessionPtr> import(const QByteArray& key);
//! Serialises an `OlmInboundGroupSession` to encrypted Base64.
QByteArray pickle(const PicklingMode& mode) const;
//! Deserialises from encrypted Base64 that was previously obtained by pickling
diff --git a/lib/e2ee/qolmoutboundsession.cpp b/lib/e2ee/qolmoutboundsession.cpp
index 3d176274..18af5569 100644
--- a/lib/e2ee/qolmoutboundsession.cpp
+++ b/lib/e2ee/qolmoutboundsession.cpp
@@ -39,8 +39,10 @@ QOlmOutboundGroupSessionPtr QOlmOutboundGroupSession::create()
RandomBuffer(randomLength).bytes(),
randomLength)
== olm_error()) {
- // FIXME: create the session object earlier and use lastError()
- throw olm_outbound_group_session_last_error_code(olmOutboundGroupSession);
+ // FIXME: create the session object earlier
+ QOLM_INTERNAL_ERROR_X("Failed to initialise an outbound group session",
+ olm_outbound_group_session_last_error(
+ olmOutboundGroupSession));
}
// FIXME: is it used anywhere?
@@ -52,7 +54,7 @@ QOlmOutboundGroupSessionPtr QOlmOutboundGroupSession::create()
return std::make_unique<QOlmOutboundGroupSession>(olmOutboundGroupSession);
}
-QOlmExpected<QByteArray> QOlmOutboundGroupSession::pickle(const PicklingMode &mode) const
+QByteArray QOlmOutboundGroupSession::pickle(const PicklingMode &mode) const
{
QByteArray pickledBuf(
olm_pickle_outbound_group_session_length(m_groupSession), '\0');
@@ -61,7 +63,7 @@ QOlmExpected<QByteArray> QOlmOutboundGroupSession::pickle(const PicklingMode &mo
key.length(), pickledBuf.data(),
pickledBuf.length())
== olm_error())
- return lastErrorCode();
+ QOLM_INTERNAL_ERROR("Failed to pickle the outbound group session");
key.clear();
return pickledBuf;
@@ -77,6 +79,9 @@ QOlmExpected<QOlmOutboundGroupSessionPtr> QOlmOutboundGroupSession::unpickle(
pickled.length())
== olm_error()) {
// FIXME: create the session object earlier and use lastError()
+ qWarning(E2EE) << "Failed to unpickle an outbound group session:"
+ << olm_outbound_group_session_last_error(
+ olmOutboundGroupSession);
return olm_outbound_group_session_last_error_code(
olmOutboundGroupSession);
}
@@ -90,8 +95,7 @@ QOlmExpected<QOlmOutboundGroupSessionPtr> QOlmOutboundGroupSession::unpickle(
return std::make_unique<QOlmOutboundGroupSession>(olmOutboundGroupSession);
}
-QOlmExpected<QByteArray> QOlmOutboundGroupSession::encrypt(
- const QByteArray& plaintext) const
+QByteArray QOlmOutboundGroupSession::encrypt(const QByteArray& plaintext) const
{
const auto messageMaxLength =
olm_group_encrypt_message_length(m_groupSession, plaintext.length());
@@ -102,7 +106,7 @@ QOlmExpected<QByteArray> QOlmOutboundGroupSession::encrypt(
reinterpret_cast<uint8_t*>(messageBuf.data()),
messageBuf.length())
== olm_error())
- return lastErrorCode();
+ QOLM_INTERNAL_ERROR("Failed to encrypt a message");
return messageBuf;
}
@@ -120,12 +124,12 @@ QByteArray QOlmOutboundGroupSession::sessionId() const
m_groupSession, reinterpret_cast<uint8_t*>(idBuffer.data()),
idBuffer.length())
== olm_error())
- throw lastError();
+ QOLM_INTERNAL_ERROR("Failed to obtain group session id");
return idBuffer;
}
-QOlmExpected<QByteArray> QOlmOutboundGroupSession::sessionKey() const
+QByteArray QOlmOutboundGroupSession::sessionKey() const
{
const auto keyMaxLength = olm_outbound_group_session_key_length(m_groupSession);
QByteArray keyBuffer(keyMaxLength, '\0');
@@ -133,7 +137,7 @@ QOlmExpected<QByteArray> QOlmOutboundGroupSession::sessionKey() const
m_groupSession, reinterpret_cast<uint8_t*>(keyBuffer.data()),
keyMaxLength)
== olm_error())
- return lastErrorCode();
+ QOLM_INTERNAL_ERROR("Failed to obtain group session key");
return keyBuffer;
}
diff --git a/lib/e2ee/qolmoutboundsession.h b/lib/e2ee/qolmoutboundsession.h
index e5e73ddf..d36fbf69 100644
--- a/lib/e2ee/qolmoutboundsession.h
+++ b/lib/e2ee/qolmoutboundsession.h
@@ -20,14 +20,14 @@ public:
//! Throw OlmError on errors
static QOlmOutboundGroupSessionPtr create();
//! Serialises a `QOlmOutboundGroupSession` to encrypted Base64.
- QOlmExpected<QByteArray> pickle(const PicklingMode &mode) const;
+ QByteArray pickle(const PicklingMode &mode) const;
//! Deserialises from encrypted Base64 that was previously obtained by
//! pickling a `QOlmOutboundGroupSession`.
static QOlmExpected<QOlmOutboundGroupSessionPtr> unpickle(
QByteArray&& pickled, const PicklingMode& mode);
//! Encrypts a plaintext message using the session.
- QOlmExpected<QByteArray> encrypt(const QByteArray& plaintext) const;
+ QByteArray encrypt(const QByteArray& plaintext) const;
//! Get the current message index for this session.
//!
@@ -42,7 +42,7 @@ public:
//!
//! Each message is sent with a different ratchet key. This function returns the
//! ratchet key that will be used for the next message.
- QOlmExpected<QByteArray> sessionKey() const;
+ QByteArray sessionKey() const;
QOlmOutboundGroupSession(OlmOutboundGroupSession *groupSession);
int messageCount() const;
diff --git a/lib/e2ee/qolmsession.cpp b/lib/e2ee/qolmsession.cpp
index 7c102a96..0d6edd21 100644
--- a/lib/e2ee/qolmsession.cpp
+++ b/lib/e2ee/qolmsession.cpp
@@ -90,23 +90,23 @@ QOlmExpected<QOlmSessionPtr> QOlmSession::createOutboundSession(
== olm_error()) {
// FIXME: the QOlmSession object should be created earlier
const auto lastErr = olm_session_last_error_code(olmOutboundSession);
- if (lastErr == OLM_NOT_ENOUGH_RANDOM) {
- throw lastErr;
- }
+ QOLM_FAIL_OR_LOG_X(lastErr == OLM_NOT_ENOUGH_RANDOM,
+ "Failed to create an outbound Olm session",
+ olm_session_last_error(olmOutboundSession));
return lastErr;
}
return std::make_unique<QOlmSession>(olmOutboundSession);
}
-QOlmExpected<QByteArray> QOlmSession::pickle(const PicklingMode &mode) const
+QByteArray QOlmSession::pickle(const PicklingMode &mode) const
{
QByteArray pickledBuf(olm_pickle_session_length(m_session), '\0');
QByteArray key = toKey(mode);
if (olm_pickle_session(m_session, key.data(), key.length(),
pickledBuf.data(), pickledBuf.length())
== olm_error())
- return lastErrorCode();
+ QOLM_INTERNAL_ERROR("Failed to pickle an Olm session");
key.clear();
return pickledBuf;
@@ -121,7 +121,11 @@ QOlmExpected<QOlmSessionPtr> QOlmSession::unpickle(QByteArray&& pickled,
pickled.data(), pickled.length())
== olm_error()) {
// FIXME: the QOlmSession object should be created earlier
- return olm_session_last_error_code(olmSession);
+ const auto errorCode = olm_session_last_error_code(olmSession);
+ QOLM_FAIL_OR_LOG_X(errorCode == OLM_OUTPUT_BUFFER_TOO_SMALL,
+ "Failed to unpickle an Olm session",
+ olm_session_last_error(olmSession));
+ return errorCode;
}
key.clear();
@@ -140,7 +144,7 @@ QOlmMessage QOlmSession::encrypt(const QByteArray& plaintext)
RandomBuffer(randomLength), randomLength, messageBuf.data(),
messageBuf.length())
== olm_error()) {
- throw lastError();
+ QOLM_INTERNAL_ERROR("Failed to encrypt the message");
}
return QOlmMessage(messageBuf, QOlmMessage::Type(messageType));
@@ -159,7 +163,9 @@ QOlmExpected<QByteArray> QOlmSession::decrypt(const QOlmMessage &message) const
const auto plaintextMaxLen = olm_decrypt_max_plaintext_length(
m_session, messageTypeValue, messageBuf.data(), messageBuf.length());
if (plaintextMaxLen == olm_error()) {
- return lastError();
+ qWarning(E2EE) << "Couldn't calculate decrypted message length:"
+ << lastError();
+ return lastErrorCode();
}
QByteArray plaintextBuf(plaintextMaxLen, '\0');
@@ -170,11 +176,9 @@ QOlmExpected<QByteArray> QOlmSession::decrypt(const QOlmMessage &message) const
olm_decrypt(m_session, messageTypeValue, messageBuf2.data(),
messageBuf2.length(), plaintextBuf.data(), plaintextMaxLen);
if (plaintextResultLen == olm_error()) {
- const auto lastErr = lastErrorCode();
- if (lastErr == OLM_OUTPUT_BUFFER_TOO_SMALL) {
- throw lastErr;
- }
- return lastErr;
+ QOLM_FAIL_OR_LOG(OLM_OUTPUT_BUFFER_TOO_SMALL,
+ "Failed to decrypt the message");
+ return lastErrorCode();
}
plaintextBuf.truncate(plaintextResultLen);
return plaintextBuf;
@@ -183,10 +187,10 @@ QOlmExpected<QByteArray> QOlmSession::decrypt(const QOlmMessage &message) const
QByteArray QOlmSession::sessionId() const
{
const auto idMaxLength = olm_session_id_length(m_session);
- QByteArray idBuffer(idMaxLength, '0');
- if (olm_session_id(m_session, idBuffer.data(), idMaxLength) == olm_error()) {
- throw lastError();
- }
+ QByteArray idBuffer(idMaxLength, '\0');
+ if (olm_session_id(m_session, idBuffer.data(), idMaxLength) == olm_error())
+ QOLM_INTERNAL_ERROR("Failed to obtain Olm session id");
+
return idBuffer;
}
@@ -203,8 +207,8 @@ bool QOlmSession::matchesInboundSession(const QOlmMessage& preKeyMessage) const
olm_matches_inbound_session(m_session, oneTimeKeyBuf.data(),
oneTimeKeyBuf.length());
if (maybeMatches == olm_error())
- qWarning(E2EE) << "Error matching an inbound session:"
- << olm_session_last_error(m_session);
+ qWarning(E2EE) << "Error matching an inbound session:" << lastError();
+
return maybeMatches == 1; // Any errors are treated as non-match
}
@@ -218,8 +222,8 @@ bool QOlmSession::matchesInboundSessionFrom(
oneTimeKeyMessageBuf.data(), oneTimeKeyMessageBuf.length());
if (maybeMatches == olm_error())
- qCWarning(E2EE) << "Error matching an inbound session:"
- << olm_session_last_error(m_session);
+ qCWarning(E2EE) << "Error matching an inbound session:" << lastError();
+
return maybeMatches == 1;
}
diff --git a/lib/e2ee/qolmsession.h b/lib/e2ee/qolmsession.h
index 174e98ef..400fb854 100644
--- a/lib/e2ee/qolmsession.h
+++ b/lib/e2ee/qolmsession.h
@@ -30,7 +30,7 @@ public:
const QByteArray& theirOneTimeKey);
//! Serialises an `QOlmSession` to encrypted Base64.
- QOlmExpected<QByteArray> pickle(const PicklingMode &mode) const;
+ QByteArray pickle(const PicklingMode &mode) const;
//! Deserialises from encrypted Base64 previously made with pickle()
static QOlmExpected<QOlmSessionPtr> unpickle(QByteArray&& pickled,
diff --git a/lib/e2ee/qolmutils.h b/lib/e2ee/qolmutils.h
index da9d2d18..17eee7a3 100644
--- a/lib/e2ee/qolmutils.h
+++ b/lib/e2ee/qolmutils.h
@@ -34,4 +34,22 @@ public:
return RandomBuffer(bufferSize);
}
+#define QOLM_INTERNAL_ERROR_X(Message_, LastError_) \
+ qFatal("%s, internal error: %s", Message_, LastError_)
+
+#define QOLM_INTERNAL_ERROR(Message_) \
+ QOLM_INTERNAL_ERROR_X(Message_, lastError())
+
+#define QOLM_FAIL_OR_LOG_X(InternalCondition_, Message_, LastErrorText_) \
+ do { \
+ const QString errorMsg{ (Message_) }; \
+ if (InternalCondition_) \
+ QOLM_INTERNAL_ERROR_X(qPrintable(errorMsg), (LastErrorText_)); \
+ qWarning(E2EE).nospace() << errorMsg << ": " << (LastErrorText_); \
+ } while (false) /* End of macro */
+
+#define QOLM_FAIL_OR_LOG(InternalFailureValue_, Message_) \
+ QOLM_FAIL_OR_LOG_X(lastErrorCode() == (InternalFailureValue_), (Message_), \
+ lastError())
+
} // namespace Quotient
diff --git a/lib/room.cpp b/lib/room.cpp
index 382d0243..5fdff036 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -357,7 +357,9 @@ public:
return false;
}
- auto megolmSession = QOlmInboundGroupSession::create(sessionKey);
+ auto expectedMegolmSession = QOlmInboundGroupSession::create(sessionKey);
+ Q_ASSERT(expectedMegolmSession.has_value());
+ auto&& megolmSession = *expectedMegolmSession;
if (megolmSession->sessionId() != sessionId) {
qCWarning(E2EE) << "Session ID mismatch in m.room_key event";
return false;
@@ -442,12 +444,10 @@ public:
connection->saveCurrentOutboundMegolmSession(
id, *currentOutboundMegolmSession);
- const auto sessionKey = currentOutboundMegolmSession->sessionKey();
- if(!sessionKey) {
- qCWarning(E2EE) << "Failed to load key for new megolm session";
- return;
- }
- addInboundGroupSession(currentOutboundMegolmSession->sessionId(), *sessionKey, q->localUser()->id(), "SELF"_ls);
+ currentOutboundMegolmSession->sessionKey();
+ addInboundGroupSession(currentOutboundMegolmSession->sessionId(),
+ currentOutboundMegolmSession->sessionKey(),
+ q->localUser()->id(), "SELF"_ls);
}
QMultiHash<QString, QString> getDevicesWithoutKey() const
@@ -460,22 +460,6 @@ public:
return connection->database()->devicesWithoutKey(
id, devices, currentOutboundMegolmSession->sessionId());
}
-
- void sendMegolmSession(const QMultiHash<QString, QString>& devices) const {
- // Save the session to this device
- const auto sessionId = currentOutboundMegolmSession->sessionId();
- const auto sessionKey = currentOutboundMegolmSession->sessionKey();
- if(!sessionKey) {
- qCWarning(E2EE) << "Error loading session key";
- return;
- }
-
- // Send the session to other people
- connection->sendSessionKeyToDevices(
- id, sessionId, *sessionKey, devices,
- currentOutboundMegolmSession->sessionMessageIndex());
- }
-
#endif // Quotient_E2EE_ENABLED
private:
@@ -2029,17 +2013,20 @@ QString Room::Private::doSendEvent(const RoomEvent* pEvent)
if (!hasValidMegolmSession() || shouldRotateMegolmSession()) {
createMegolmSession();
}
- sendMegolmSession(getDevicesWithoutKey());
+ // Send the session to other people
+ connection->sendSessionKeyToDevices(
+ id, currentOutboundMegolmSession->sessionId(),
+ currentOutboundMegolmSession->sessionKey(), getDevicesWithoutKey(),
+ currentOutboundMegolmSession->sessionMessageIndex());
const auto encrypted = currentOutboundMegolmSession->encrypt(QJsonDocument(pEvent->fullJson()).toJson());
currentOutboundMegolmSession->setMessageCount(currentOutboundMegolmSession->messageCount() + 1);
connection->saveCurrentOutboundMegolmSession(
id, *currentOutboundMegolmSession);
- if(!encrypted) {
- qWarning(E2EE) << "Error encrypting message" << encrypted.error();
- return {};
- }
- encryptedEvent = makeEvent<EncryptedEvent>(*encrypted, q->connection()->olmAccount()->identityKeys().curve25519, q->connection()->deviceId(), currentOutboundMegolmSession->sessionId());
+ encryptedEvent = makeEvent<EncryptedEvent>(
+ encrypted, q->connection()->olmAccount()->identityKeys().curve25519,
+ q->connection()->deviceId(),
+ currentOutboundMegolmSession->sessionId());
encryptedEvent->setTransactionId(connection->generateTxnId());
encryptedEvent->setRoomId(id);
encryptedEvent->setSender(connection->userId());