[network/ruqola] src/core: Prepare new databse

Laurent Montel <[email protected]> Tue, 4 Aug 2026 18:02:20 +0000 (UTC)
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 268abff00ce8fc325a45e01a5aac9bbad800ad7c by Laurent Montel.
Committed on 04/08/2026 at 18:02.
Pushed by mlaurent into branch 'master'.

Prepare new databse

M  +2    -0    src/core/CMakeLists.txt
A  +124  -0    src/core/localdatabase/e2eroomsdatabase.cpp     [License: LGPL(v2.0+)]
A  +28   -0    src/core/localdatabase/e2eroomsdatabase.h     [License: LGPL(v2.0+)]

https://invent.kde.org/network/ruqola/-/commit/268abff00ce8fc325a45e01a5aac9bbad800ad7c

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 2c442eaf0c..27417d07f0 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -492,6 +492,8 @@ target_sources(
         localdatabase/localaccountsdatabase.cpp
         localdatabase/e2edatabase.h
         localdatabase/e2edatabase.cpp
+        localdatabase/e2eroomsdatabase.cpp
+        localdatabase/e2eroomsdatabase.h
         localdatabase/globaldatabase.h
         localdatabase/globaldatabase.cpp
         localdatabase/localroompendingtypedinfodatabase.h
diff --git a/src/core/localdatabase/e2eroomsdatabase.cpp b/src/core/localdatabase/e2eroomsdatabase.cpp
new file mode 100644
index 0000000000..2eeaae365a
--- /dev/null
+++ b/src/core/localdatabase/e2eroomsdatabase.cpp
@@ -0,0 +1,124 @@
+/*
+   SPDX-FileCopyrightText: 2025 Andro Ranogajec <[email protected]>
+   SPDX-FileCopyrightText: 2026 Laurent Montel <[email protected]>
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "e2eroomsdatabase.h"
+#include "localdatabaseutils.h"
+#include "ruqola_database_debug.h"
+#include <QFileInfo>
+#include <QSqlError>
+#include <QSqlQuery>
+#include <QSqlTableModel>
+using namespace Qt::Literals::StringLiterals;
+static const char s_schemaE2EKeyStore[] = "CREATE TABLE E2EKEYS (userId TEXT PRIMARY KEY NOT NULL, encryptedPrivateKey BLOB, publicKey BLOB)";
+enum class E2EFields {
+    UserId,
+    EncryptedPrivateKey,
+    PublicKey
+}; // in the same order as the table
+
+E2ERoomsDataBase::E2ERoomsDataBase()
+    : LocalDatabaseBase(LocalDatabaseUtils::localE2EDatabasePath(), LocalDatabaseBase::DatabaseType::E2E)
+{
+}
+
+E2ERoomsDataBase::~E2ERoomsDataBase() = default;
+
+QString E2ERoomsDataBase::schemaDataBase() const
+{
+    return QString::fromLatin1(s_schemaE2EKeyStore);
+}
+
+bool E2ERoomsDataBase::saveKey(const QString &accountName, const QString &userId, const QByteArray &encryptedPrivateKey, const QByteArray &publicKey)
+{
+    QSqlDatabase db;
+    if (!initializeDataBase(accountName, db)) {
+        return false;
+    }
+    QSqlQuery query(db);
+    query.prepare(QStringLiteral("INSERT OR REPLACE INTO E2EKEYS (userId, encryptedPrivateKey, publicKey) VALUES (?, ?, ?)"));
+    query.addBindValue(userId);
+    query.addBindValue(encryptedPrivateKey);
+    query.addBindValue(publicKey);
+    if (!query.exec()) {
+        qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't insert-or-replace in E2EKEYS table" << db.databaseName() << query.lastError();
+        return false;
+    }
+    return true;
+}
+
+bool E2ERoomsDataBase::loadKey(const QString &accountName, const QString &userId, QByteArray &encryptedPrivateKey, QByteArray &publicKey)
+{
+    QSqlDatabase db;
+    if (!initializeDataBase(accountName, db)) {
+        return false;
+    }
+    QSqlQuery query(db);
+    query.prepare(QStringLiteral("SELECT encryptedPrivateKey, publicKey FROM E2EKEYS WHERE userId = ?"));
+    query.addBindValue(userId);
+    if (query.exec() && query.first()) {
+        encryptedPrivateKey = query.value(0).toByteArray();
+        publicKey = query.value(1).toByteArray();
+        return true;
+    }
+    return false;
+}
+
+bool E2ERoomsDataBase::deleteKey(const QString &accountName, const QString &userId)
+{
+    QSqlDatabase db;
+    if (!initializeDataBase(accountName, db)) {
+        return false;
+    }
+    QSqlQuery query(db);
+    query.prepare(QStringLiteral("DELETE FROM E2EKEYS WHERE userId = ?"));
+    query.addBindValue(userId);
+    if (!query.exec()) {
+        qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't delete from E2EKEYS table" << db.databaseName() << query.lastError();
+        return false;
+    }
+    return true;
+}
+
+bool E2ERoomsDataBase::hasKey(const QString &accountName, const QString &userId)
+{
+    QSqlDatabase db;
+    if (!initializeDataBase(accountName, db)) {
+        return false;
+    }
+    QSqlQuery query(db);
+    query.prepare(QStringLiteral("SELECT 1 FROM E2EKEYS WHERE userId = ?"));
+    query.addBindValue(userId);
+    return query.exec() && query.first();
+}
+
+std::unique_ptr<QSqlTableModel> E2ERoomsDataBase::createE2eModel(const QString &accountName) const
+{
+    const QString dbName = databaseName(accountName);
+    QSqlDatabase db = QSqlDatabase::database(dbName);
+    if (!db.isValid()) {
+        // Open the DB if it exists (don't create a new one)
+        const QString fileName = dbFileName(accountName);
+        // qDebug() << " fileName " << fileName;
+        if (!QFileInfo::exists(fileName)) {
+            return {};
+        }
+        db = QSqlDatabase::addDatabase(u"QSQLITE"_s, dbName);
+        db.setDatabaseName(fileName);
+        if (!db.open()) {
+            qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't open" << fileName;
+            return {};
+        }
+    }
+
+    Q_ASSERT(db.isValid());
+    Q_ASSERT(db.isOpen());
+    auto model = std::make_unique<QSqlTableModel>(nullptr, db);
+    model->setTable(u"E2EKEYS"_s);
+    model->setSort(int(E2EFields::UserId), Qt::AscendingOrder);
+    model->select();
+    return model;
+}
diff --git a/src/core/localdatabase/e2eroomsdatabase.h b/src/core/localdatabase/e2eroomsdatabase.h
new file mode 100644
index 0000000000..025b2c82da
--- /dev/null
+++ b/src/core/localdatabase/e2eroomsdatabase.h
@@ -0,0 +1,28 @@
+/*
+   SPDX-FileCopyrightText: 2025 Andro Ranogajec <[email protected]>
+   SPDX-FileCopyrightText: 2026 Laurent Montel <[email protected]>
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#pragma once
+
+#include "libruqolacore_export.h"
+#include "localdatabasebase.h"
+class QSqlTableModel;
+class LIBRUQOLACORE_EXPORT E2ERoomsDataBase : public LocalDatabaseBase
+{
+public:
+    E2ERoomsDataBase();
+    ~E2ERoomsDataBase() override;
+
+    [[nodiscard]] bool saveKey(const QString &accountName, const QString &userId, const QByteArray &encryptedPrivateKey, const QByteArray &publicKey);
+    [[nodiscard]] bool loadKey(const QString &accountName, const QString &userId, QByteArray &encryptedPrivateKey, QByteArray &publicKey);
+    [[nodiscard]] bool deleteKey(const QString &accountName, const QString &userId);
+    [[nodiscard]] bool hasKey(const QString &accountName, const QString &userId);
+
+    [[nodiscard]] std::unique_ptr<QSqlTableModel> createE2eModel(const QString &accountName) const;
+
+protected:
+    [[nodiscard]] QString schemaDataBase() const override;
+};