WIP OMEMO SQLite3

This commit is contained in:
Xavier Del Campo Romero 2023-09-01 00:14:38 +02:00
parent b9163a3146
commit e94036f3bc
Signed by: xavi
GPG Key ID: 84FF3612A9BF43F2
7 changed files with 484 additions and 351 deletions

View File

@ -1,6 +1,7 @@
#include "client.h"
#include <QXmppTask.h>
#include <QDebug>
#include <iostream>
Client::Client(const QString &jid, QObject *const parent) :
QXmppClient(parent),
@ -8,7 +9,7 @@ Client::Client(const QString &jid, QObject *const parent) :
db(this->jid),
atm_db(this->jid, db),
atm(&atm_db),
omemo_db(this->jid),
omemo_db(db),
omemo(&omemo_db)
{
addExtension(&atm);
@ -33,6 +34,15 @@ Client::Client(const QString &jid, QObject *const parent) :
{
qDebug() << "load result: " << result;
});
logger()->setLoggingType(QXmppLogger::StdoutLogging);
logger()->setMessageTypes(QXmppLogger::AnyMessage);
connect(logger(), &QXmppLogger::message, this,
[=] (QXmppLogger::MessageType type, const QString &text)
{
std::cerr << qPrintable(text) << std::endl;
});
}
QString Client::jidBare()

396
jiddb.cpp
View File

@ -1,6 +1,7 @@
#include "jiddb.h"
#include <QDir>
#include <QSqlQuery>
#include <QSqlError>
#include <QStandardPaths>
#include <QTimeZone>
#include <QVariant>
@ -109,8 +110,7 @@ int JidDb::ensureSecurityPolicyTable(const QString &encryption,
static QString keysTableName(const QString &encryption)
{
// return "keys/" + encryption;
return "keys";
return "keys/" + encryption;
}
int JidDb::ensureKeysTable(const QString &encryption, QString &table) const
@ -122,8 +122,8 @@ int JidDb::ensureKeysTable(const QString &encryption, QString &table) const
if (!q.exec("create table if not exists '" + table
+ "' (owner TEXT, trustlevel TEXT, key TEXT) strict;"))
{
std::cerr << "JidDb::ensureKeysTable: query exec failed"
<< std::endl;
std::cerr << "JidDb::ensureKeysTable: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return -1;
}
@ -141,14 +141,16 @@ QList<JidDb::Message> JidDb::messages(const QString &jid,
{
if (!q.exec("select * from '" + jid + "' order by time;"))
{
std::cerr << "JidDb::messages: query exec failed";
std::cerr << "JidDb::messages: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return QList<Message>();
}
}
else if (!q.exec("select * from '" + jid + "' order by time desc limit "
+ QString::number(tail) + ";"))
{
std::cerr << "JidDb::messages: query exec failed" << std::endl;
std::cerr << "JidDb::messages: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return QList<Message>();
}
@ -189,7 +191,7 @@ QList<JidDb::Message> JidDb::messages(const QString &jid,
return ret;
}
int JidDb::storeMessage(const JidDb::Message &msg) const
int JidDb::store(const JidDb::Message &msg) const
{
QSqlQuery q(db);
QString dir;
@ -285,8 +287,12 @@ QString JidDb::securityPolicy(const QString &encryption) const
return QString();
}
int JidDb::storeSecurityPolicy(const QString &encryption,
const QString &policy) const
std::optional<QXmppOmemoStorage::OwnDevice> JidDb::omemoOwnDevice() const
{
return std::optional<QXmppOmemoStorage::OwnDevice>();
}
int JidDb::store(const QString &encryption, const QString &policy) const
{
QString table;
@ -298,7 +304,7 @@ int JidDb::storeSecurityPolicy(const QString &encryption,
if (!q.exec("insert or ignore into '" + table
+ "' (policy) values ('" + policy + "');"))
{
std::cerr << "JidDb::storeSecurityPolicy: query exec failed"
std::cerr << "JidDb::store: query exec failed"
<< std::endl;
return -1;
}
@ -352,13 +358,13 @@ QList<JidDb::Keys> JidDb::keys(const QString &encryption) const
return ret;
}
int JidDb::storeKeys(const QString &encryption, const JidDb::Keys &keys) const
int JidDb::store(const QString &encryption, const JidDb::Keys &keys) const
{
QString table;
if (ensureKeysTable(encryption, table))
{
std::cerr << "JidDb::storeKeys: ensureKeysTable failed" << std::endl;
std::cerr << "JidDb::store: ensureKeysTable failed" << std::endl;
return -1;
}
@ -366,13 +372,18 @@ int JidDb::storeKeys(const QString &encryption, const JidDb::Keys &keys) const
{
QSqlQuery q(db);
const auto kstr = k.isEmpty() ? "\"\""
: "'" + QString::fromLatin1(k.toBase64()) + "'";
if (!q.exec("insert or replace into '" + table
+ "' (owner, trustlevel, key) values ('"
+ keys.owner + ", " + keys.trust_level + ","
+ k.toBase64() + "');"))
+ "' (owner, trustlevel, key) values ("
"'" + keys.owner + "', "
"'" + keys.trust_level + "',"
+ kstr
+ ");"))
{
std::cerr << "JidDb::storeKeys: query exec failed"
<< std::endl;
std::cerr << "JidDb::store: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return -1;
}
}
@ -380,6 +391,357 @@ int JidDb::storeKeys(const QString &encryption, const JidDb::Keys &keys) const
return 0;
}
int JidDb::ensureOmemoDeviceTable() const
{
QSqlQuery q(db);
if (!q.exec("create table if not exists 'omemo/devices' "
"(jid TEXT, deviceID INTEGER, keyID TEXT, session TEXT, "
"unresp_sent INTEGER, unresp_recv INTEGER, removal INTEGER) "
"strict;"))
{
std::cerr << "JidDb::ensureOmemoTable: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return -1;
}
return 0;
}
int JidDb::store(const QString &jid, const uint32_t id,
const QXmppOmemoStorage::Device &d) const
{
if (ensureOmemoDeviceTable())
{
std::cerr << "JidDb::store: ensureOmemoTable failed" << std::endl;
return -1;
}
QSqlQuery q(db);
const auto keyId = d.keyId.isEmpty() ? "\"\""
: "'" + QString::fromLatin1(d.keyId.toBase64()) + "'",
session = d.session.isEmpty() ? "\"\""
: "'" + QString::fromLatin1(d.session.toBase64()) + "'",
query = "insert or replace into 'omemo/devices' "
"(jid, deviceID, keyID, session, "
"unresp_sent, unresp_recv , removal) values ("
"'" + jid + "', "
+ QString::number(id) + ", "
+ keyId + ", "
+ session + ", "
+ QString::number(d.unrespondedSentStanzasCount) + ", "
+ QString::number(d.unrespondedReceivedStanzasCount) + ", "
+ QString::number(d.removalFromDeviceListDate.toSecsSinceEpoch())
+ ");";
if (!q.exec(query))
{
std::cerr << "JidDb::store(id, jid, d): query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return -1;
}
return 0;
}
int JidDb::ensureOmemoSignedPreKeyTable() const
{
QSqlQuery q(db);
if (!q.exec("create table if not exists 'omemo/signedprekeys' "
"(id INTEGER, creation INTEGER, data TEXT) strict;"))
{
std::cerr << "JidDb::ensureOmemoSignedPreKeyTable: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return -1;
}
return 0;
}
int JidDb::store(uint32_t id, const QXmppOmemoStorage::SignedPreKeyPair &spk)
const
{
if (ensureOmemoSignedPreKeyTable())
{
std::cerr << "JidDb::store: ensureOmemoSignedPreKeyTable failed"
<< std::endl;
return -1;
}
QSqlQuery q(db);
const auto data = spk.data.isEmpty() ? "\"\""
: "'" + QString::fromLatin1(spk.data.toBase64()) + "'",
query = "insert or replace into 'omemo/signedprekeys' "
"(id, creation, data) values ("
+ QString::number(id) + ", "
+ QString::number(spk.creationDate.toSecsSinceEpoch()) + ", "
+ data
+ ");";
if (!q.exec(query))
{
std::cerr << "JidDb::store(spk): query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return -1;
}
return 0;
}
int JidDb::ensureOmemoPreKeyTable() const
{
QSqlQuery q(db);
if (!q.exec("create table if not exists 'omemo/prekeys' "
"(id INTEGER, data TEXT) strict;"))
{
std::cerr << "JidDb::ensureOmemoPreKeyTable: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return -1;
}
return 0;
}
int JidDb::store(const QHash<uint32_t, QByteArray> &pairs) const
{
if (ensureOmemoPreKeyTable())
{
std::cerr << "JidDb::store: ensureOmemoPreKeyTable failed"
<< std::endl;
return -1;
}
for (const auto id : pairs.keys())
{
const auto data = pairs.value(id);
const auto datastr = data.isEmpty() ? "\"\""
: "'" + QString::fromLatin1(data.toBase64()) + "'",
query = "insert or replace into 'omemo/prekeys' "
"(id, data) values ("
+ QString::number(id) + ", "
+ datastr
+ ");";
QSqlQuery q(db);
if (!q.exec(query))
{
std::cerr << "JidDb::store(pairs): query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return -1;
}
}
return 0;
}
int JidDb::ensureOmemoOwnDeviceTable() const
{
QSqlQuery q(db);
if (!q.exec("create table if not exists 'omemo/owndevice' "
"(id INTEGER, label TEXT, privkey TEXT, pubkey TEXT, "
"latestSignedPreKeyId INTEGER, latestPreKeyId INTEGER) strict;"))
{
std::cerr << "JidDb::ensureOmemoOwnDeviceTable: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return -1;
}
return 0;
}
int JidDb::store(const QXmppOmemoStorage::OwnDevice &own) const
{
if (ensureOmemoOwnDeviceTable())
{
std::cerr << "JidDb::store: ensureOmemoOwnDeviceTable failed"
<< std::endl;
return -1;
}
QSqlQuery q(db);
const auto privkey = own.privateIdentityKey.isEmpty() ? "\"\""
: "'" + QString::fromLatin1(own.privateIdentityKey.toBase64()) + "'",
pubkey = own.publicIdentityKey.isEmpty() ? "\"\""
: "'" + QString::fromLatin1(own.publicIdentityKey.toBase64()) + "'",
query = "insert or replace into 'omemo/owndevice' "
"(id, label, privkey, pubkey, latestSignedPreKeyId, "
"latestPreKeyId) values ("
+ QString::number(own.id) + ", "
"'" + own.label + "', "
+ privkey + ", "
+ pubkey + ", "
+ QString::number(own.latestSignedPreKeyId) + ", "
+ QString::number(own.latestPreKeyId)
+ ");";
if (!q.exec(query))
{
std::cerr << "JidDb::store(own): query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
std::cerr << "Query was: " << qPrintable(query) << std::endl;
return -1;
}
return 0;
}
QList<JidDb::OmemoDevice> JidDb::omemoDevices() const
{
QList<OmemoDevice> ret;
QSqlQuery q(db);
if (!q.exec("select * from 'omemo/devices';"))
{
std::cerr << "JidDb::omemoDevices: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return QList<OmemoDevice>();
}
while (q.next())
{
QXmppOmemoStorage::Device device;
bool ok;
const uint32_t deviceId = q.value("deviceID").toULongLong(&ok);
if (!ok)
{
std::cerr << "JidDb::messages: invalid deviceID" << std::endl;
// Attempt to read other messages.
continue;
}
device.unrespondedReceivedStanzasCount =
q.value("unresp_recv").toInt(&ok);
if (!ok)
{
std::cerr << "JidDb::messages: invalid unresp_recv" << std::endl;
// Attempt to read other messages.
continue;
}
device.unrespondedSentStanzasCount = q.value("unresp_sent").toInt(&ok);
if (!ok)
{
std::cerr << "JidDb::messages: invalid unresp_sent" << std::endl;
// Attempt to read other messages.
continue;
}
const QByteArray keyId = q.value("keyID").toByteArray(),
session = q.value("session").toByteArray();
const auto jid = q.value("jid").toString();
bool found = false;
for (auto &r : ret)
if (jid == r.jid)
{
r.devices.insert(deviceId, device);
break;
}
if (!found)
{
OmemoDevice d;
d.jid = jid;
d.devices.insert(deviceId, device);
ret << d;
}
}
return ret;
}
QHash<uint32_t, QXmppOmemoStorage::SignedPreKeyPair> JidDb::signedPreKeyPairs()
const
{
QHash<uint32_t, QXmppOmemoStorage::SignedPreKeyPair> ret;
QSqlQuery q(db);
if (!q.exec("select * from 'omemo/signedprekeys';"))
{
std::cerr << "JidDb::signedPreKeyPairs: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return QHash<uint32_t, QXmppOmemoStorage::SignedPreKeyPair>();
}
while (q.next())
{
QXmppOmemoStorage::SignedPreKeyPair spk;
bool ok;
const uint32_t id = q.value("id").toULongLong(&ok);
if (!ok)
{
std::cerr << "JidDb::messages: invalid id" << std::endl;
// Attempt to read other entries.
continue;
}
const auto creation = q.value("creation").toInt(&ok);
if (!ok)
{
std::cerr << "JidDb::messages: invalid creation date" << std::endl;
// Attempt to read other entries.
continue;
}
spk.creationDate = QDateTime::fromSecsSinceEpoch(creation);
spk.data = q.value("data").toString().toLatin1().toBase64();
ret.insert(id, spk);
}
return ret;
}
QHash<uint32_t, QByteArray> JidDb::preKeyPairs() const
{
QHash<uint32_t, QByteArray> ret;
QSqlQuery q(db);
if (!q.exec("select * from 'omemo/signedprekeys';"))
{
std::cerr << "JidDb::signedPreKeyPairs: query exec failed: "
<< qPrintable(q.lastError().text()) << std::endl;
return QHash<uint32_t, QByteArray>();
}
while (q.next())
{
bool ok;
const uint32_t id = q.value("id").toULongLong(&ok);
if (!ok)
{
std::cerr << "JidDb::messages: invalid id" << std::endl;
// Attempt to read other entries.
continue;
}
const auto data = q.value("data").toString().toLatin1().toBase64();
ret.insert(id, data);
}
return ret;
}
void JidDb::removeKeys() const
{
}
void JidDb::removeOmemoDevice(const QString &jid, const uint32_t id) const
{
}
void JidDb::removeOmemoDevices(const QString &jid) const
{
}

34
jiddb.h
View File

@ -10,7 +10,9 @@
#include <QString>
#include <QStringList>
#include <QSqlDatabase>
#include <QXmppOmemoStorage.h>
#include <QVariant>
#include <optional>
class JidDb : public QObject
{
@ -51,6 +53,12 @@ public:
QList<QByteArray> keys;
};
struct OmemoDevice
{
QString jid;
QHash<uint32_t, QXmppOmemoStorage::Device> devices;
};
JidDb(const QString &jid);
QStringList roster() const;
const QString &jid;
@ -59,15 +67,27 @@ public Q_SLOTS:
QList<Conversation> conversations() const;
QList<Message> messages(const QString &jid,
int tail = -1) const;
QString securityPolicy(const QString &encryption) const;
QList<Keys> keys(const QString &encryption) const;
int storeMessage(const Message &msg) const;
QString securityPolicy(const QString &encryption) const;
QList<OmemoDevice> omemoDevices() const;
std::optional<QXmppOmemoStorage::OwnDevice> omemoOwnDevice() const;
QHash<uint32_t, QXmppOmemoStorage::SignedPreKeyPair> signedPreKeyPairs()
const;
QHash<uint32_t, QByteArray> preKeyPairs() const;
int addToRoster(const QString &jid);
int addToRoster(const QStringList &roster);
int storeSecurityPolicy(const QString &encryption,
const QString &policy) const;
int storeKeys(const QString &encryption, const Keys &keys) const;
int store(const Message &msg) const;
int store(const QString &encryption,
const QString &securityPolicy) const;
int store(const QString &encryption, const Keys &keys) const;
int store(const QString &jid, uint32_t id,
const QXmppOmemoStorage::Device &d) const;
int store(uint32_t id, const QXmppOmemoStorage::SignedPreKeyPair &spk) const;
int store(const QHash<uint32_t, QByteArray> &pairs) const;
int store(const QXmppOmemoStorage::OwnDevice &own) const;
void removeKeys() const;
void removeOmemoDevice(const QString &jid, uint32_t id) const;
void removeOmemoDevices(const QString &jid) const;
Q_SIGNALS:
void addedToRoster(QString jid);
@ -78,6 +98,10 @@ private:
QString &table) const;
int ensureContactTable(const QString &jid) const;
int ensureKeysTable(const QString &encryption, QString &table) const;
int ensureOmemoDeviceTable() const;
int ensureOmemoSignedPreKeyTable() const;
int ensureOmemoPreKeyTable() const;
int ensureOmemoOwnDeviceTable() const;
QStringList tables() const;
};

View File

@ -1,69 +1,45 @@
#include "omemo_db.h"
#include <QXmppConfiguration.h>
#include <QXmppFutureUtils_p.h>
#include <QXmppPromise.h>
#include <qt5keychain/keychain.h>
#include <QEventLoop>
#include <QtConcurrent>
#include <QString>
#include <iostream>
#include <optional>
#include <variant>
static const QString service = "xxcc", key_namespace = "omemo";
OmemoDb::OmemoDb(const QString &jid) :
jid(jid)
OmemoDb::OmemoDb(const JidDb &db) :
db(db)
{
}
QXmppTask<QXmppOmemoStorage::OmemoData> OmemoDb::allData()
{
return QXmpp::Private::makeReadyTask(QXmppOmemoStorage::OmemoData());
}
QXmppOmemoStorage::OmemoData ret;
QHash<QString, QHash<uint32_t, Device>> devices;
QXmppTask<OmemoDb::Result> OmemoDb::storeOwnKeyId(const QString &key,
const uint32_t id) const
{
const auto str = QString::number(id, 16);
for (const auto &d : db.omemoDevices())
ret.devices.insert(d.jid, d.devices);
return store(key + "/device/ownkeyid", str);
ret.ownDevice = db.omemoOwnDevice();
ret.preKeyPairs = db.preKeyPairs();
ret.signedPreKeyPairs = db.signedPreKeyPairs();
return QXmpp::Private::makeReadyTask(QXmppOmemoStorage::OmemoData(ret));
}
QXmppTask<void> OmemoDb::setOwnDevice(const std::optional<OwnDevice> &device)
{
#if 0
if (!device.has_value())
return QXmpp::Private::makeReadyTask();
if (device.has_value() && db.store(device.value()))
std::cerr << "db.store failed" << std::endl;
QXmppPromise<void> promise;
auto task = promise.task();
task.then(this,
[=] () mutable
{
const auto &d = device.value();
const auto srv = service();
storeDeviceLabel(srv, d.label)
|| storeOwnKeyId(srv, d.id)
|| storePrivateIdentityKey(srv, d.privateIdentityKey)
|| storePublicIdentityKey(srv, d.publicIdentityKey)
|| storeLatestSignedPreKeyId(srv, d.latestSignedPreKeyId)
|| storeLatestPreKeyId(srv, d.latestPreKeyId);
promise.finish();
});
return task;
#else
return QXmpp::Private::makeReadyTask();
#endif
}
QXmppTask<void> OmemoDb::addSignedPreKeyPair(const uint32_t keyId,
const SignedPreKeyPair &keyPair)
{
if (db.store(keyId, keyPair))
std::cerr << "db.store failed" << std::endl;
return QXmpp::Private::makeReadyTask();
}
@ -75,6 +51,9 @@ QXmppTask<void> OmemoDb::removeSignedPreKeyPair(uint32_t keyId)
QXmppTask<void> OmemoDb::addPreKeyPairs(
const QHash<uint32_t, QByteArray> &keyPairs)
{
if (db.store(keyPairs))
std::cerr << "db.store failed" << std::endl;
return QXmpp::Private::makeReadyTask();
}
@ -83,200 +62,19 @@ QXmppTask<void> OmemoDb::removePreKeyPair(const uint32_t keyId)
return QXmpp::Private::makeReadyTask();
}
OmemoDb::Store OmemoDb::storeCommon() const
{
const auto job = new QKeychain::WritePasswordJob(service);
QXmppPromise<Result> promise;
connect(job, &QKeychain::Job::finished, this,
[=](QKeychain::Job *job) mutable
{
if (job->error())
{
const auto str = "Failed to store device label: "
+ job->errorString();
std::cerr << qPrintable(str) << std::endl;
promise.finish(Error{str});
}
else
promise.finish(QXmpp::Success());
});
return Store(promise.task(), job);
}
QXmppTask<OmemoDb::Result> OmemoDb::store(const QString &key,
const QByteArray &data) const
{
const auto result = storeCommon();
const auto job = result.job;
job->setKey(key);
job->setBinaryData(data);
job->start();
return result.task;
}
QXmppTask<OmemoDb::Result> OmemoDb::store(const QString &key,
const QString &data) const
{
const auto result = storeCommon();
const auto job = result.job;
job->setKey(key);
job->setTextData(data);
job->start();
return result.task;
}
/* TODO: move to SQLite database. */
QXmppTask<OmemoDb::Result> OmemoDb::storeDeviceLabel(const QString &key,
const QString &label) const
{
return store(key, label);
}
QXmppTask<OmemoDb::Result> OmemoDb::storeKeyId(const QString &key,
const QByteArray &keyId) const
{
return store(key, keyId);
}
/* TODO: move to SQLite database. */
QXmppTask<OmemoDb::Result> OmemoDb::storeSession(const QString &key,
const QByteArray &session) const
{
return store(key, session);
}
QXmppTask<OmemoDb::Result> OmemoDb::storeRemovalFromDeviceListDate(
const QString &key, const QDateTime &dt) const
{
const auto str = QString::number(dt.currentMSecsSinceEpoch());
return store(key, str);
}
QXmppTask<OmemoDb::Result> OmemoDb::storeUnrespondedReceivedStanzasCount(
const QString &key, int count) const
{
const auto str = QString::number(count, 10);
return store(key, str);
}
QXmppTask<OmemoDb::Result> OmemoDb::storeUnrespondedSentStanzasCount(
const QString &key, int count) const
{
const auto str = QString::number(count, 10);
return store(key, str);
}
template<typename T, typename Q> bool OmemoDb::runTask(
QXmppPromise<void> &promise, QList<StoreArgs>::const_iterator it,
QList<StoreArgs>::const_iterator end)
{
const auto task = it->fn;
if (std::holds_alternative<T>(task))
{
const auto &fn = std::get<T>(task);
auto t = (*this.*fn)(it->key, std::get<Q>(it->data));
t.then(this,
[=](const Result &&result) mutable
{
if (std::holds_alternative<QXmpp::Success>(result))
{
std::cerr << "runTask " << qPrintable(it->key)
<< " successful" << std::endl;
runTask(promise, ++it, end);
}
else if (std::holds_alternative<Error>(result))
{
const auto &error = std::get<Error>(result);
std::cerr << "runTask " << qPrintable(it->key) << " failed: "
<< qPrintable(error.description) << std::endl;
promise.finish();
}
});
return true;
}
return false;
}
QXmppTask<void> OmemoDb::runTask(QXmppPromise<void> &promise,
QList<OmemoDb::StoreArgs>::const_iterator it,
const QList<StoreArgs>::const_iterator end)
{
if (it != end)
{
runTask<TaskBA, QByteArray>(promise, it, end)
|| runTask<TaskStr, QString>(promise, it, end)
|| runTask<TaskInt, int>(promise, it, end)
|| runTask<TaskUint32, uint32_t>(promise, it, end);
}
else
promise.finish();
return promise.task();
}
QXmppTask<void> OmemoDb::addDevice(const QString &jid,
const uint32_t deviceId, const Device &device)
const uint32_t deviceId, const Device &d)
{
const auto ns = key_namespace + "/" + jid + "/"
+ QString::number(deviceId, 16);
auto functions = new QList<StoreArgs>;
if (db.store(jid, deviceId, d))
std::cerr << "db.store failed" << std::endl;
*functions << StoreArgs{ns + "/device/label", &OmemoDb::storeDeviceLabel,
device.label};
*functions << StoreArgs{ns + "/device/keyid", &OmemoDb::storeKeyId,
device.keyId};
*functions << StoreArgs{ns + "/device/session", &OmemoDb::storeSession,
device.session};
*functions << StoreArgs{ns + "/device/unrespondedSentStanzas",
&OmemoDb::storeUnrespondedSentStanzasCount,
device.unrespondedSentStanzasCount};
*functions << StoreArgs{ns + "/device/unrespondedReceivedStanzas",
&OmemoDb::storeUnrespondedReceivedStanzasCount,
device.unrespondedReceivedStanzasCount};
*functions << StoreArgs{ns + "removalFromDeviceListDate",
&OmemoDb::storeRemovalFromDeviceListDate,
device.removalFromDeviceListDate};
QXmppPromise<void> promise;
return runTask(promise, functions->cbegin(), functions->cend());
return QXmpp::Private::makeReadyTask();
}
QXmppTask<void> OmemoDb::removeDevice(const QString &jid,
const uint32_t deviceId)
{
#if 0
const QString fullservice = service_ns + jid;
QKeychain::DeletePasswordJob job(fullservice);
QEventLoop loop;
loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
job.setKey("device/unresponded_received_stanzas");
job.setTextData(QString::number(dt.currentMSecsSinceEpoch()));
job.start();
loop.exec();
if (job.error())
{
std::cerr << "Failed to store device unresponded received stanzas: "
<< qPrintable(job.errorString()) << std::endl;
return -1;
}
return 0;
#endif
db.removeOmemoDevice(jid, deviceId);
return QXmpp::Private::makeReadyTask();
}

View File

@ -1,6 +1,7 @@
#ifndef OMEMO_DB_H
#define OMEMO_DB_H
#include "jiddb.h"
#include <QXmppGlobal.h>
#include <QXmppOmemoStorage.h>
#include <QXmppPromise.h>
@ -9,6 +10,7 @@
#include <QDateTime>
#include <QByteArray>
#include <QString>
#include <QSqlDatabase>
#include <cstdint>
class OmemoDb : public QObject, public QXmppOmemoStorage
@ -16,7 +18,7 @@ class OmemoDb : public QObject, public QXmppOmemoStorage
Q_OBJECT
public:
OmemoDb(const QString &jid);
OmemoDb(const JidDb &db);
QXmppTask<OmemoData> allData() override;
QXmppTask<void> setOwnDevice(
const std::optional<OwnDevice> &device) override;
@ -34,74 +36,7 @@ public:
QXmppTask<void> resetAll() override;
private:
struct Error
{
QString description;
};
using Result = std::variant<QXmpp::Success, Error>;
struct Store
{
Store(const QXmppTask<Result> &task, QKeychain::WritePasswordJob *job) :
task(task), job(job) {}
QXmppTask<Result> task;
QKeychain::WritePasswordJob *job;
};
const QString &jid;
QXmppTask<Result> store(const QString &key, const QByteArray &data) const;
QXmppTask<Result> store(const QString &key, const QString &data) const;
Store storeCommon() const;
QXmppTask<Result> storeSession(const QString &ns,
const QByteArray &session) const;
QXmppTask<Result> storeDeviceLabel(const QString &key,
const QString &label) const;
QXmppTask<Result> storeKeyId(const QString &key,
const QByteArray &keyId) const;
QXmppTask<Result> storeOwnKeyId(const QString &key, uint32_t id) const;
QXmppTask<Result> storePrivateIdentityKey(const QString &key,
const QByteArray &privateIdentityKey) const;
QXmppTask<Result> storePublicIdentityKey(const QString &key,
const QByteArray &publicIdentityKey) const;
QXmppTask<Result> storeLatestSignedPreKeyId(const QString &key,
uint32_t latestSignedPreKeyId) const;
QXmppTask<Result> storeLatestPreKeyId(const QString &key,
uint32_t latestPreKeyId) const;
QXmppTask<Result> storeUnrespondedSentStanzasCount(const QString &key,
int count) const;
QXmppTask<Result> storeUnrespondedReceivedStanzasCount(const QString &key,
int count) const;
QXmppTask<Result> storeRemovalFromDeviceListDate(const QString &key,
const QDateTime &dt) const;
using TaskBA = QXmppTask<Result> (OmemoDb::*)(const QString &,
const QByteArray &) const;
using TaskStr = QXmppTask<Result> (OmemoDb::*)(const QString &,
const QString &) const;
using TaskInt = QXmppTask<Result> (OmemoDb::*)(const QString &, int) const;
using TaskUint32 = QXmppTask<Result> (OmemoDb::*)(const QString &,
uint32_t) const;
using TaskDt = QXmppTask<Result> (OmemoDb::*)(const QString &,
const QDateTime &) const;
using StoreFn = std::variant<TaskBA, TaskStr, TaskInt, TaskUint32, TaskDt>;
using StoreData = std::variant<QByteArray , QString, int, uint32_t, QDateTime>;
struct StoreArgs
{
QString key;
StoreFn fn;
StoreData data;
};
QXmppTask<void> runTask(QXmppPromise<void> &promise,
QList<StoreArgs>::const_iterator it,
QList<StoreArgs>::const_iterator end);
template<typename T, typename Q> bool runTask(QXmppPromise<void> &promise,
QList<StoreArgs>::const_iterator it,
QList<StoreArgs>::const_iterator end);
const JidDb &db;
};
#endif

View File

@ -90,8 +90,8 @@ QString TrustDb::service() const
QXmppTask<void> TrustDb::setSecurityPolicy(const QString &encryption,
const QXmpp::TrustSecurityPolicy securityPolicy)
{
if (db.storeSecurityPolicy(encryption, toString(securityPolicy)))
std::cerr << "TrustDb::setSecurityPolicy: storeSecurityPolicy failed"
if (db.store(encryption, toString(securityPolicy)))
std::cerr << "TrustDb::setSecurityPolicy: store failed"
<< std::endl;
return QXmpp::Private::makeReadyTask();
@ -99,8 +99,8 @@ QXmppTask<void> TrustDb::setSecurityPolicy(const QString &encryption,
QXmppTask<void> TrustDb::resetSecurityPolicy(const QString &encryption)
{
if (db.storeSecurityPolicy(encryption, QString()))
std::cerr << "TrustDb::resetSecurityPolicy: storeSecurityPolicy failed"
if (db.store(encryption, QString()))
std::cerr << "TrustDb::resetSecurityPolicy: store failed"
<< std::endl;
return QXmpp::Private::makeReadyTask();
@ -182,8 +182,8 @@ QXmppTask<void> TrustDb::addKeys(const QString &encryption,
{
const struct JidDb::Keys keys(keyOwnerJid, toString(trustLevel), keyIds);
if (db.storeKeys(encryption, keys))
std::cerr << "TrustDb::addKeys: storeKeys failed" << std::endl;
if (db.store(encryption, keys))
std::cerr << "TrustDb::addKeys: store failed" << std::endl;
return QXmpp::Private::makeReadyTask();
}
@ -206,8 +206,8 @@ QXmppTask<void> TrustDb::removeKeys(const QString &encryption,
}
for (const auto &k : keys)
if (db.storeKeys(encryption, k))
std::cerr << "TrustDb::removeKeys: storeKeys failed" << std::endl;
if (db.store(encryption, k))
std::cerr << "TrustDb::removeKeys: store failed" << std::endl;
return QXmpp::Private::makeReadyTask();
}
@ -225,8 +225,8 @@ QXmppTask<void> TrustDb::removeKeys(const QString &encryption,
}
for (const auto &k : keys)
if (db.storeKeys(encryption, k))
std::cerr << "TrustDb::removeKeys: storeKeys failed" << std::endl;
if (db.store(encryption, k))
std::cerr << "TrustDb::removeKeys: store failed" << std::endl;
return QXmpp::Private::makeReadyTask();
}
@ -363,8 +363,8 @@ QXmppTask<QHash<QString,
}
for (const auto &key : keys)
if (db.storeKeys(encryption, key))
std::cerr << "TrustDb::setTrustLevel: storeKeys failed"
if (db.store(encryption, key))
std::cerr << "TrustDb::setTrustLevel: store failed"
<< std::endl;
return QXmpp::Private::makeReadyTask(QHash<QString,

View File

@ -206,31 +206,35 @@ void xxcc::send(void)
const auto from = selected->jidBare(),
to = ui.jid->text(), msg = ui.chatinput->toPlainText();
const bool enc = ui.omemo->isChecked();
static const auto encmsg = "This is an OMEMO-encrypted message.";
QXmppMessage out(from, to, enc ? encmsg : msg);
QXmppMessage out(from, to, msg);
out.setE2eeFallbackBody("[xxcc: This is an OMEMO-encrypted message]");
out.setStamp(QDateTime::currentDateTimeUtc());
selected->sendSensitive(std::move(out)).then(this,
[=](const QXmpp::SendResult &&result) mutable
{
qDebug() << "result.index(): " << result.index();
if (std::holds_alternative<QXmpp::SendSuccess>(result))
if (enc)
{
selected->sendSensitive(std::move(out)).then(this,
[=](const QXmpp::SendResult &&result) mutable
{
const auto &success = std::get<QXmpp::SendSuccess>(result);
qDebug() << "acknowledged: " << success.acknowledged;
addOutMessage(out);
storeMessage(out, Direction::Out);
ui.chatinput->clear();
}
else if (std::holds_alternative<QXmppError>(result))
{
const auto &error = std::get<QXmppError>(result);
qDebug() << error.description;
}
});
// selected->sendPacket(out);
qDebug() << "result.index(): " << result.index();
if (std::holds_alternative<QXmpp::SendSuccess>(result))
{
const auto &success = std::get<QXmpp::SendSuccess>(result);
qDebug() << "acknowledged: " << success.acknowledged;
addOutMessage(out);
storeMessage(out, Direction::Out);
ui.chatinput->clear();
}
else if (std::holds_alternative<QXmppError>(result))
{
const auto &error = std::get<QXmppError>(result);
qDebug() << error.description;
}
});
}
else
selected->sendPacket(out);
}
void xxcc::storeMessage(const QXmppMessage &msg, const Direction dir) const
@ -261,7 +265,7 @@ void xxcc::storeMessage(const QXmppMessage &msg, const Direction dir) const
m.dt = msg.stamp();
m.direction = dir;
m.contact = contact;
db.storeMessage(m);
db.store(m);
}
}
}