diff options
author | Tobias Fella <fella@posteo.de> | 2021-12-10 16:10:10 +0100 |
---|---|---|
committer | Tobias Fella <fella@posteo.de> | 2021-12-10 16:10:31 +0100 |
commit | b4cc38fc7c2c63d8122106a2451aec2c60176a4b (patch) | |
tree | a5c18272ce47b7aa08f96e4f8bdeebb7b8a7ea54 /lib | |
parent | 6cec450f1d749936bd51a1471ac0ed74f633ef66 (diff) | |
download | libquotient-b4cc38fc7c2c63d8122106a2451aec2c60176a4b.tar.gz libquotient-b4cc38fc7c2c63d8122106a2451aec2c60176a4b.zip |
Use individual databases for each connection
Diffstat (limited to 'lib')
-rw-r--r-- | lib/connection.cpp | 21 | ||||
-rw-r--r-- | lib/connection.h | 2 | ||||
-rw-r--r-- | lib/database.cpp | 113 | ||||
-rw-r--r-- | lib/database.h | 32 | ||||
-rw-r--r-- | lib/encryptionmanager.cpp | 9 | ||||
-rw-r--r-- | lib/room.cpp | 8 |
6 files changed, 93 insertions, 92 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp index d1a29a7d..8b9f9688 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -116,6 +116,7 @@ public: QueryKeysJob *currentQueryKeysJob = nullptr; bool encryptionUpdateRequired = false; PicklingMode picklingMode = Unencrypted {}; + Database *database = nullptr; #endif GetCapabilitiesJob* capabilitiesJob = nullptr; @@ -268,11 +269,9 @@ Connection::Connection(const QUrl& server, QObject* parent) : QObject(parent), d(new Private(std::make_unique<ConnectionData>(server))) { #ifdef Quotient_E2EE_ENABLED - d->encryptionManager = new EncryptionManager(this); connect(qApp, &QCoreApplication::aboutToQuit, this, [this](){ saveOlmAccount(); }); - Database::instance(); #endif d->q = this; // All d initialization should occur before this line } @@ -446,7 +445,8 @@ void Connection::Private::loginToServer(LoginArgTs&&... loginArgs) #ifndef Quotient_E2EE_ENABLED qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off."; #else // Quotient_E2EE_ENABLED - Database::instance().clear(loginJob->userId()); + database = new Database(loginJob->userId(), q); + database->clear(); #endif // Quotient_E2EE_ENABLED }); connect(loginJob, &BaseJob::failure, q, [this, loginJob] { @@ -502,9 +502,13 @@ void Connection::Private::completeSetup(const QString& mxId) olmAccount = std::make_unique<QOlmAccount>(data->userId(), data->deviceId(), q); connect(olmAccount.get(), &QOlmAccount::needsSave, q, &Connection::saveOlmAccount); + if (!database) { + database = new Database(data->userId(), q); + } + encryptionManager = new EncryptionManager(q); - if (Database::instance().accountPickle(data->userId()).isEmpty()) { + if (database->accountPickle().isEmpty()) { // create new account and save unpickle data olmAccount->createNewAccount(); auto job = q->callApi<UploadKeysJob>(olmAccount->deviceKeys()); @@ -513,7 +517,7 @@ void Connection::Private::completeSetup(const QString& mxId) }); } else { // account already existing - auto pickle = Database::instance().accountPickle(data->userId()); + auto pickle = database->accountPickle(); olmAccount->unpickle(pickle, picklingMode); } #endif // Quotient_E2EE_ENABLED @@ -2040,7 +2044,7 @@ void Connection::saveOlmAccount() qCDebug(E2EE) << "Saving olm account"; #ifdef Quotient_E2EE_ENABLED auto pickle = d->olmAccount->pickle(d->picklingMode); - Database::instance().setAccountPickle(userId(), std::get<QByteArray>(pickle)); + d->database->setAccountPickle(std::get<QByteArray>(pickle)); #endif } @@ -2067,4 +2071,9 @@ QJsonObject Connection::decryptNotification(const QJsonObject ¬ification) } return decrypted->fullJson(); } + +Database* Connection::database() +{ + return d->database; +} #endif diff --git a/lib/connection.h b/lib/connection.h index 3a12ec39..93ee496e 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -47,6 +47,7 @@ class DownloadFileJob; class SendToDeviceJob; class SendMessageJob; class LeaveRoomJob; +class Database; class QOlmAccount; @@ -313,6 +314,7 @@ public: bool isLoggedIn() const; #ifdef Quotient_E2EE_ENABLED QOlmAccount* olmAccount() const; + Database* database(); #endif // Quotient_E2EE_ENABLED Q_INVOKABLE Quotient::SyncJob* syncJob() const; Q_INVOKABLE int millisToReconnect() const; diff --git a/lib/database.cpp b/lib/database.cpp index 01015d3c..41e62935 100644 --- a/lib/database.cpp +++ b/lib/database.cpp @@ -17,13 +17,16 @@ //TODO: delete room specific data when leaving room using namespace Quotient; -Database::Database() +Database::Database(const QString& matrixId, QObject* parent) + : QObject(parent) + , m_matrixId(matrixId) { - QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), QStringLiteral("Quotient")); - QString databasePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + m_matrixId.replace(':', '_'); + QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), QStringLiteral("Quotient_%1").arg(m_matrixId)); + QString databasePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/%1").arg(m_matrixId); QDir(databasePath).mkpath(databasePath); - QSqlDatabase::database(QStringLiteral("Quotient")).setDatabaseName(databasePath + QStringLiteral("/quotient.db3")); - QSqlDatabase::database(QStringLiteral("Quotient")).open(); + database().setDatabaseName(databasePath + QStringLiteral("/quotient.db3")); + database().open(); switch(version()) { case 0: migrateTo1(); @@ -47,7 +50,7 @@ int Database::version() QSqlQuery Database::execute(const QString &queryString) { - auto query = QSqlDatabase::database(QStringLiteral("Quotient")).exec(queryString); + auto query = database().exec(queryString); if (query.lastError().type() != QSqlError::NoError) { qCritical() << "Failed to execute query"; qCritical() << query.lastQuery(); @@ -68,32 +71,30 @@ QSqlQuery Database::execute(QSqlQuery &query) void Database::transaction() { - QSqlDatabase::database(QStringLiteral("Quotient")).transaction(); + database().transaction(); } void Database::commit() { - QSqlDatabase::database(QStringLiteral("Quotient")).commit(); + database().commit(); } void Database::migrateTo1() { qCDebug(DATABASE) << "Migrating database to version 1"; transaction(); - execute(QStringLiteral("CREATE TABLE accounts (matrixId TEXT UNIQUE, pickle TEXT);")); - execute(QStringLiteral("CREATE TABLE olm_sessions (matrixId TEXT, senderKey TEXT, sessionId TEXT, pickle TEXT);")); - execute(QStringLiteral("CREATE TABLE inbound_megolm_sessions (matrixId TEXT, roomId TEXT, senderKey TEXT, sessionId TEXT, pickle TEXT);")); - execute(QStringLiteral("CREATE TABLE outbound_megolm_sessions (matrixId TEXT, roomId TEXT, senderKey TEXT, sessionId TEXT, pickle TEXT);")); - execute(QStringLiteral("CREATE TABLE group_session_record_index (matrixId TEXT, roomId TEXT, sessionId TEXT, i INTEGER, eventId TEXT, ts INTEGER);")); + execute(QStringLiteral("CREATE TABLE accounts (pickle TEXT);")); + execute(QStringLiteral("CREATE TABLE olm_sessions (senderKey TEXT, sessionId TEXT, pickle TEXT);")); + execute(QStringLiteral("CREATE TABLE inbound_megolm_sessions (roomId TEXT, senderKey TEXT, sessionId TEXT, pickle TEXT);")); + execute(QStringLiteral("CREATE TABLE outbound_megolm_sessions (roomId TEXT, senderKey TEXT, sessionId TEXT, pickle TEXT);")); + execute(QStringLiteral("CREATE TABLE group_session_record_index (roomId TEXT, sessionId TEXT, i INTEGER, eventId TEXT, ts INTEGER);")); execute(QStringLiteral("PRAGMA user_version = 1;")); commit(); } -QByteArray Database::accountPickle(const QString &matrixId) +QByteArray Database::accountPickle() { - QSqlQuery query(QSqlDatabase::database(QStringLiteral("Quotient"))); - query.prepare(QStringLiteral("SELECT pickle FROM accounts WHERE matrixId=:matrixId;")); - query.bindValue(":matrixId", matrixId); + auto query = prepareQuery(QStringLiteral("SELECT pickle FROM accounts;")); execute(query); if (query.next()) { return query.value(QStringLiteral("pickle")).toByteArray(); @@ -101,34 +102,23 @@ QByteArray Database::accountPickle(const QString &matrixId) return {}; } -void Database::setAccountPickle(const QString &matrixId, const QByteArray &pickle) +void Database::setAccountPickle(const QByteArray &pickle) { - QSqlQuery query(QSqlDatabase::database(QStringLiteral("Quotient"))); - query.prepare(QStringLiteral("INSERT INTO accounts(matrixId, pickle) VALUES(:matrixId, :pickle) ON CONFLICT (matrixId) DO UPDATE SET pickle=:pickle WHERE matrixId=:matrixId;")); - query.bindValue(":matrixId", matrixId); + auto deleteQuery = prepareQuery(QStringLiteral("DELETE FROM accounts;")); + auto query = prepareQuery(QStringLiteral("INSERT INTO accounts(pickle) VALUES(:pickle);")); query.bindValue(":pickle", pickle); transaction(); + execute(deleteQuery); execute(query); commit(); } -void Database::clear(const QString &matrixId) +void Database::clear() { - QSqlQuery query(QSqlDatabase::database(QStringLiteral("Quotient"))); - query.prepare(QStringLiteral("DELETE FROM accounts WHERE matrixId=:matrixId;")); - query.bindValue(":matrixId", matrixId); - - QSqlQuery sessionsQuery(QSqlDatabase::database(QStringLiteral("Quotient"))); - sessionsQuery.prepare(QStringLiteral("DELETE FROM olm_sessions WHERE matrixId=:matrixId;")); - sessionsQuery.bindValue(":matrixId", matrixId); - - QSqlQuery megolmSessionsQuery(QSqlDatabase::database(QStringLiteral("Quotient"))); - megolmSessionsQuery.prepare(QStringLiteral("DELETE FROM inbound_megolm_sessions WHERE matrixId=:matrixId;")); - megolmSessionsQuery.bindValue(":matrixId", matrixId); - - QSqlQuery groupSessionIndexRecordQuery(QSqlDatabase::database(QStringLiteral("Quotient"))); - groupSessionIndexRecordQuery.prepare(QStringLiteral("DELETE FROM group_session_record_index WHERE matrixId=:matrixId;")); - groupSessionIndexRecordQuery.bindValue(":matrixId", matrixId); + auto query = prepareQuery(QStringLiteral("DELETE FROM accounts;")); + auto sessionsQuery = prepareQuery(QStringLiteral("DELETE FROM olm_sessions;")); + auto megolmSessionsQuery = prepareQuery(QStringLiteral("DELETE FROM inbound_megolm_sessions;")); + auto groupSessionIndexRecordQuery = prepareQuery(QStringLiteral("DELETE FROM group_session_record_index;")); transaction(); execute(query); @@ -139,11 +129,9 @@ void Database::clear(const QString &matrixId) } -void Database::saveOlmSession(const QString& matrixId, const QString& senderKey, const QString& sessionId, const QByteArray &pickle) +void Database::saveOlmSession(const QString& senderKey, const QString& sessionId, const QByteArray &pickle) { - QSqlQuery query(QSqlDatabase::database(QStringLiteral("Quotient"))); - query.prepare(QStringLiteral("INSERT INTO olm_sessions(matrixId, senderKey, sessionId, pickle) VALUES(:matrixId, :senderKey, :sessionId, :pickle);")); - query.bindValue(":matrixId", matrixId); + auto query = prepareQuery(QStringLiteral("INSERT INTO olm_sessions(senderKey, sessionId, pickle) VALUES(:senderKey, :sessionId, :pickle);")); query.bindValue(":senderKey", senderKey); query.bindValue(":sessionId", sessionId); query.bindValue(":pickle", pickle); @@ -152,11 +140,9 @@ void Database::saveOlmSession(const QString& matrixId, const QString& senderKey, commit(); } -UnorderedMap<QString, std::vector<QOlmSessionPtr>> Database::loadOlmSessions(const QString& matrixId, const PicklingMode& picklingMode) +UnorderedMap<QString, std::vector<QOlmSessionPtr>> Database::loadOlmSessions(const PicklingMode& picklingMode) { - QSqlQuery query(QSqlDatabase::database(QStringLiteral("Quotient"))); - query.prepare(QStringLiteral("SELECT * FROM olm_sessions WHERE matrixId=:matrixId;")); - query.bindValue(":matrixId", matrixId); + QSqlQuery query = prepareQuery(QStringLiteral("SELECT * FROM olm_sessions;")); transaction(); execute(query); commit(); @@ -172,11 +158,9 @@ UnorderedMap<QString, std::vector<QOlmSessionPtr>> Database::loadOlmSessions(con return sessions; } -UnorderedMap<QPair<QString, QString>, QOlmInboundGroupSessionPtr> Database::loadMegolmSessions(const QString& matrixId, const QString& roomId, const PicklingMode& picklingMode) +UnorderedMap<QPair<QString, QString>, QOlmInboundGroupSessionPtr> Database::loadMegolmSessions(const QString& roomId, const PicklingMode& picklingMode) { - QSqlQuery query(QSqlDatabase::database(QStringLiteral("Quotient"))); - query.prepare(QStringLiteral("SELECT * FROM inbound_megolm_sessions WHERE matrixId=:matrixId AND roomId=:roomId;")); - query.bindValue(":matrixId", matrixId); + auto query = prepareQuery(QStringLiteral("SELECT * FROM inbound_megolm_sessions WHERE roomId=:roomId;")); query.bindValue(":roomId", roomId); transaction(); execute(query); @@ -193,11 +177,9 @@ UnorderedMap<QPair<QString, QString>, QOlmInboundGroupSessionPtr> Database::load return sessions; } -void Database::saveMegolmSession(const QString& matrixId, const QString& roomId, const QString& senderKey, const QString& sessionId, const QByteArray& pickle) +void Database::saveMegolmSession(const QString& roomId, const QString& senderKey, const QString& sessionId, const QByteArray& pickle) { - QSqlQuery query(QSqlDatabase::database(QStringLiteral("Quotient"))); - query.prepare(QStringLiteral("INSERT INTO inbound_megolm_sessions(matrixId, roomId, senderKey, sessionId, pickle) VALUES(:matrixId, :roomId, :senderKey, :sessionId, :pickle);")); - query.bindValue(":matrixId", matrixId); + auto query = prepareQuery(QStringLiteral("INSERT INTO inbound_megolm_sessions(roomId, senderKey, sessionId, pickle) VALUES(:roomId, :senderKey, :sessionId, :pickle);")); query.bindValue(":roomId", roomId); query.bindValue(":senderKey", senderKey); query.bindValue(":sessionId", sessionId); @@ -207,11 +189,9 @@ void Database::saveMegolmSession(const QString& matrixId, const QString& roomId, commit(); } -void Database::addGroupSessionIndexRecord(const QString& matrixId, const QString& roomId, const QString& sessionId, uint32_t index, const QString& eventId, qint64 ts) +void Database::addGroupSessionIndexRecord(const QString& roomId, const QString& sessionId, uint32_t index, const QString& eventId, qint64 ts) { - QSqlQuery query(QSqlDatabase::database(QStringLiteral("Quotient"))); - query.prepare("INSERT INTO group_session_record_index(matrixId, roomId, sessionId, i, eventId, ts) VALUES(:matrixId, :roomId, :sessionId, :index, :eventId, :ts);"); - query.bindValue(":matrixId", matrixId); + QSqlQuery query = prepareQuery("INSERT INTO group_session_record_index(roomId, sessionId, i, eventId, ts) VALUES(:roomId, :sessionId, :index, :eventId, :ts);"); query.bindValue(":roomId", roomId); query.bindValue(":sessionId", sessionId); query.bindValue(":index", index); @@ -222,11 +202,10 @@ void Database::addGroupSessionIndexRecord(const QString& matrixId, const QString commit(); } -QPair<QString, qint64> Database::groupSessionIndexRecord(const QString& matrixId, const QString& roomId, const QString& sessionId, qint64 index) +QPair<QString, qint64> Database::groupSessionIndexRecord(const QString& roomId, const QString& sessionId, qint64 index) { - QSqlQuery query(QSqlDatabase::database(QStringLiteral("Quotient"))); - query.prepare(QStringLiteral("SELECT * FROM group_session_record_index WHERE matrixId=:matrixId AND roomId=:roomId AND sessionId=:sessionId AND i=:index;")); - query.bindValue(":matrixId", matrixId); + QSqlQuery query(database()); + query.prepare(QStringLiteral("SELECT * FROM group_session_record_index WHERE roomId=:roomId AND sessionId=:sessionId AND i=:index;")); query.bindValue(":roomId", roomId); query.bindValue(":sessionId", sessionId); query.bindValue(":index", index); @@ -238,3 +217,15 @@ QPair<QString, qint64> Database::groupSessionIndexRecord(const QString& matrixId } return {query.value("eventId").toString(), query.value("ts").toLongLong()}; } + +QSqlDatabase Database::database() +{ + return QSqlDatabase::database(QStringLiteral("Quotient_%1").arg(m_matrixId)); +} + +QSqlQuery Database::prepareQuery(const QString& queryString) +{ + QSqlQuery query(database()); + query.prepare(queryString); + return query; +} diff --git a/lib/database.h b/lib/database.h index 25af2833..fbb940c8 100644 --- a/lib/database.h +++ b/lib/database.h @@ -15,32 +15,28 @@ class Database : public QObject Q_OBJECT public: - static Database &instance() - { - static Database _instance; - return _instance; - } + Database(const QString& matrixId, QObject* parent); int version(); void transaction(); void commit(); QSqlQuery execute(const QString &queryString); QSqlQuery execute(QSqlQuery &query); - - QByteArray accountPickle(const QString &matrixId); - void setAccountPickle(const QString &matrixId, const QByteArray &pickle); - void clear(const QString &matrixId); - void saveOlmSession(const QString& matrixId, const QString& senderKey, const QString& sessionId, const QByteArray &pickle); - UnorderedMap<QString, std::vector<QOlmSessionPtr>> loadOlmSessions(const QString& matrixId, const PicklingMode& picklingMode); - UnorderedMap<QPair<QString, QString>, QOlmInboundGroupSessionPtr> loadMegolmSessions(const QString& matrixId, const QString& roomId, const PicklingMode& picklingMode); - void saveMegolmSession(const QString& matrixId, const QString& roomId, const QString& senderKey, const QString& sessionKey, const QByteArray& pickle); - void addGroupSessionIndexRecord(const QString& matrixId, const QString& roomId, const QString& sessionId, uint32_t index, const QString& eventId, qint64 ts); - QPair<QString, qint64> groupSessionIndexRecord(const QString& matrixId, const QString& roomId, const QString& sessionId, qint64 index); - + QSqlDatabase database(); + QSqlQuery prepareQuery(const QString& quaryString); + + QByteArray accountPickle(); + void setAccountPickle(const QByteArray &pickle); + void clear(); + void saveOlmSession(const QString& senderKey, const QString& sessionId, const QByteArray &pickle); + UnorderedMap<QString, std::vector<QOlmSessionPtr>> loadOlmSessions(const PicklingMode& picklingMode); + UnorderedMap<QPair<QString, QString>, QOlmInboundGroupSessionPtr> loadMegolmSessions(const QString& roomId, const PicklingMode& picklingMode); + void saveMegolmSession(const QString& roomId, const QString& senderKey, const QString& sessionKey, const QByteArray& pickle); + void addGroupSessionIndexRecord(const QString& roomId, const QString& sessionId, uint32_t index, const QString& eventId, qint64 ts); + QPair<QString, qint64> groupSessionIndexRecord(const QString& roomId, const QString& sessionId, qint64 index); private: - Database(); - void migrateTo1(); + QString m_matrixId; }; } diff --git a/lib/encryptionmanager.cpp b/lib/encryptionmanager.cpp index c0e44f70..abdcdcee 100644 --- a/lib/encryptionmanager.cpp +++ b/lib/encryptionmanager.cpp @@ -33,19 +33,21 @@ class EncryptionManager::Private { public: EncryptionManager* q; + Connection* connection; + // A map from SenderKey to vector of InboundSession UnorderedMap<QString, std::vector<QOlmSessionPtr>> sessions; void loadSessions() { - sessions = Database::instance().loadOlmSessions(static_cast<Connection *>(q->parent())->userId(), static_cast<Connection *>(q->parent())->picklingMode()); + sessions = connection->database()->loadOlmSessions(connection->picklingMode()); } void saveSession(QOlmSessionPtr& session, const QString &senderKey) { - auto pickleResult = session->pickle(static_cast<Connection *>(q->parent())->picklingMode()); + auto pickleResult = session->pickle(connection->picklingMode()); if (std::holds_alternative<QOlmError>(pickleResult)) { qCWarning(E2EE) << "Failed to pickle olm session. Error" << std::get<QOlmError>(pickleResult); return; } - Database::instance().saveOlmSession(static_cast<Connection *>(q->parent())->userId(), senderKey, session->sessionId(), std::get<QByteArray>(pickleResult)); + connection->database()->saveOlmSession(senderKey, session->sessionId(), std::get<QByteArray>(pickleResult)); } QString sessionDecryptPrekey(const QOlmMessage& message, const QString &senderKey, std::unique_ptr<QOlmAccount>& olmAccount) { @@ -103,6 +105,7 @@ EncryptionManager::EncryptionManager(QObject* parent) , d(std::make_unique<Private>()) { d->q = this; + d->connection = static_cast<Connection *>(parent); d->loadSessions(); } diff --git a/lib/room.cpp b/lib/room.cpp index 7d608520..458f870d 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -371,7 +371,7 @@ public: UnorderedMap<QPair<QString, QString>, QOlmInboundGroupSessionPtr> groupSessions; void loadMegOlmSessions() { - groupSessions = Database::instance().loadMegolmSessions(q->localUser()->id(), q->id(), q->connection()->picklingMode()); + groupSessions = q->connection()->database()->loadMegolmSessions(q->id(), q->connection()->picklingMode()); } bool addInboundGroupSession(QString senderKey, QString sessionId, QString sessionKey) @@ -389,7 +389,7 @@ public: return false; } qCWarning(E2EE) << "Adding inbound session"; - Database::instance().saveMegolmSession(q->localUser()->id(), q->id(), senderKey, sessionId, megolmSession->pickle(q->connection()->picklingMode())); + q->connection()->database()->saveMegolmSession(q->id(), senderKey, sessionId, megolmSession->pickle(q->connection()->picklingMode())); groupSessions[{senderKey, sessionId}] = std::move(megolmSession); return true; } @@ -416,9 +416,9 @@ public: return QString(); } const auto& [content, index] = std::get<std::pair<QString, uint32_t>>(decryptResult); - const auto& [recordEventId, ts] = Database::instance().groupSessionIndexRecord(q->localUser()->id(), q->id(), senderSession->sessionId(), index); + const auto& [recordEventId, ts] = q->connection()->database()->groupSessionIndexRecord(q->id(), senderSession->sessionId(), index); if (recordEventId.isEmpty()) { - Database::instance().addGroupSessionIndexRecord(q->localUser()->id(), q->id(), senderSession->sessionId(), index, eventId, timestamp.toMSecsSinceEpoch()); + q->connection()->database()->addGroupSessionIndexRecord(q->id(), senderSession->sessionId(), index, eventId, timestamp.toMSecsSinceEpoch()); } else { if ((eventId != recordEventId) || (ts != timestamp.toMSecsSinceEpoch())) { qCWarning(E2EE) << "Detected a replay attack on event" << eventId; |