WIP OMEMO SQLite3
This commit is contained in:
parent
b9163a3146
commit
e94036f3bc
12
client.cpp
12
client.cpp
|
@ -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
396
jiddb.cpp
|
@ -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
34
jiddb.h
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
248
omemo_db.cpp
248
omemo_db.cpp
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
73
omemo_db.h
73
omemo_db.h
|
@ -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
|
||||
|
|
24
trust_db.cpp
24
trust_db.cpp
|
@ -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,
|
||||
|
|
48
xxcc.cpp
48
xxcc.cpp
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue