ref(omemo): reformat qomemo/

This commit is contained in:
vae 2021-05-13 17:54:37 +03:00
parent 574210f5d9
commit bbeeee4c8a
Signed by: vae
GPG Key ID: A9A33351400E00E5
23 changed files with 447 additions and 455 deletions

View File

@ -1,23 +1,23 @@
target_sources(squawk PRIVATE
bundle.cpp
bundle.h
database.cpp
database.h
device.cpp
device.h
device_key_storage.cpp
device_key_storage.h
device_service.cpp
device_service.h
qomemo.cpp
qomemo.h
sce.cpp
sce.h
user_device_list.cpp
user_device_list.h
qxmpp_omemo_manager.cpp
qxmpp_omemo_manager.h
)
bundle.cpp
bundle.h
database.cpp
database.h
device.cpp
device.h
device_key_storage.cpp
device_key_storage.h
device_service.cpp
device_service.h
qomemo.cpp
qomemo.h
sce.cpp
sce.h
user_device_list.cpp
user_device_list.h
qxmpp_omemo_manager.cpp
qxmpp_omemo_manager.h
)
add_subdirectory(signal)
add_subdirectory(variant)

View File

@ -1,12 +0,0 @@
* Generate device w/ keys
* PubSub set urn:xmpp:omemo:1:devices to announce new device
* PubSub set urn:xmpp:omemo:1:bundles to announce new key bundles
* PubSub get urn:xmpp:omemo:1:bundles to get user bundles
Sending a message:
* Create urn:xmpp:sce:0 with padding and content
* Add <encrypted xmlns='urn:xmpp:omemo:1'> with header (key list) and payload (b64)
Receiving a message:
* Check <keys> => <key>
* Decrypt (TODO)

View File

@ -13,117 +13,117 @@
using namespace QXmpp::Factories;
QXmppElement QXmpp::Omemo::PreKey::toXml() const {
auto pk = createElement("preKeyPublic");
pk.setAttribute("preKeyId", QString::number(id));
// TODO: Base64
pk.setValue(data);
auto pk = createElement("preKeyPublic");
pk.setAttribute("preKeyId", QString::number(id));
// TODO: Base64
pk.setValue(data);
return pk;
return pk;
}
void QXmpp::Omemo::PreKey::fromXml(const QXmppElement &element) {
if (!elementMatches(element, "preKeyPublic"))
return;
if (!elementMatches(element, "preKeyPublic"))
return;
id = element.attribute("preKeyId").toInt();
// TODO: Base64
data = element.value();
id = element.attribute("preKeyId").toInt();
// TODO: Base64
data = element.value();
}
QXmppElement QXmpp::Omemo::Bundle::toXml() const {
auto spkNode = createElement("signedPreKeyPublic");
spkNode.setAttribute("signedPreKeyId", QString::number(spkId));
spkNode.setValue(spk);
auto spkNode = createElement("signedPreKeyPublic");
spkNode.setAttribute("signedPreKeyId", QString::number(spkId));
spkNode.setValue(spk);
auto spksNode = createElement("signedPreKeySignature");
spksNode.setValue(spks);
auto spksNode = createElement("signedPreKeySignature");
spksNode.setValue(spks);
auto ikNode = createElement("identityKey");
ikNode.setValue(ik);
auto ikNode = createElement("identityKey");
ikNode.setValue(ik);
auto prekeysNode = createElement("prekeys");
for (const auto &pk : prekeys) {
prekeysNode.appendChild(pk.toXml());
}
auto prekeysNode = createElement("prekeys");
for (const auto &pk : prekeys) {
prekeysNode.appendChild(pk.toXml());
}
auto result = createElement("bundle", "eu.siacs.conversations.axolotl");
result.appendChild(spkNode);
result.appendChild(spksNode);
result.appendChild(ikNode);
result.appendChild(prekeysNode);
auto result = createElement("bundle", "eu.siacs.conversations.axolotl");
result.appendChild(spkNode);
result.appendChild(spksNode);
result.appendChild(ikNode);
result.appendChild(prekeysNode);
return result;
return result;
}
QXmppIq QXmpp::Omemo::Bundle::toIq(int deviceId) const {
QXmppIq iq{};
QXmppIq iq{};
iq.setType(QXmppIq::Set);
iq.setType(QXmppIq::Set);
auto item = createElement("item");
item.appendChild(toXml());
auto item = createElement("item");
item.appendChild(toXml());
auto publish = createElement("publish");
publish.setAttribute(
"node",
QString("eu.siacs.conversations.axolotl.bundles:%s").arg(deviceId));
publish.appendChild(item);
auto publish = createElement("publish");
publish.setAttribute(
"node",
QString("eu.siacs.conversations.axolotl.bundles:%s").arg(deviceId));
publish.appendChild(item);
auto pubSub = createElement("pubsub", "http://jabber.org/protocol/pubsub");
pubSub.appendChild(publish);
pubSub.appendChild(createOpenPublishOptions());
auto pubSub = createElement("pubsub", "http://jabber.org/protocol/pubsub");
pubSub.appendChild(publish);
pubSub.appendChild(createOpenPublishOptions());
iq.extensions().push_back(pubSub);
iq.extensions().push_back(pubSub);
return iq;
return iq;
}
void QXmpp::Omemo::Bundle::fromXml(const QXmppElement &element) {
if (!elementMatches(element, "bundle", "eu.siacs.conversations.axolotl"))
return;
if (!elementMatches(element, "bundle", "eu.siacs.conversations.axolotl"))
return;
auto spkNode = element.firstChildElement("spk");
if (spkNode.isNull()) {
qWarning() << "'bundle': missing 'spk'";
return;
}
spk = spkNode.value();
spkId = spkNode.attribute("id").toInt();
auto spkNode = element.firstChildElement("spk");
if (spkNode.isNull()) {
qWarning() << "'bundle': missing 'spk'";
return;
}
spk = spkNode.value();
spkId = spkNode.attribute("id").toInt();
auto spksNode = element.firstChildElement("spks");
if (spksNode.isNull()) {
qWarning() << "'bundle': missing 'spks'";
return;
}
spks = spksNode.value();
auto spksNode = element.firstChildElement("spks");
if (spksNode.isNull()) {
qWarning() << "'bundle': missing 'spks'";
return;
}
spks = spksNode.value();
auto ikNode = element.firstChildElement("ik");
if (ikNode.isNull()) {
qWarning() << "'bundle': missing 'ik'";
return;
}
ik = ikNode.value();
auto ikNode = element.firstChildElement("ik");
if (ikNode.isNull()) {
qWarning() << "'bundle': missing 'ik'";
return;
}
ik = ikNode.value();
auto prekeysNode = element.firstChildElement("prekeys");
auto pkNode = prekeysNode.firstChildElement("pk");
auto prekeysNode = element.firstChildElement("prekeys");
auto pkNode = prekeysNode.firstChildElement("pk");
prekeys.clear();
while (!pkNode.isNull()) {
PreKey pk{};
pk.fromXml(pkNode);
prekeys.push_back(pk);
}
prekeys.clear();
while (!pkNode.isNull()) {
PreKey pk{};
pk.fromXml(pkNode);
prekeys.push_back(pk);
}
}
QXmppPubSubIq QXmpp::Omemo::Bundle::fetchDeviceBundleIq(int deviceId) {
QXmppPubSubIq iq{};
iq.setType(QXmppIq::Get);
iq.setQueryNode(
QString("eu.siacs.conversations.axolotl.bundles:%1").arg(deviceId));
QXmppPubSubIq iq{};
iq.setType(QXmppIq::Get);
iq.setQueryNode(
QString("eu.siacs.conversations.axolotl.bundles:%1").arg(deviceId));
QXmppPubSubItem item{};
item.setId(QString::number(deviceId));
iq.setItems({item});
QXmppPubSubItem item{};
item.setId(QString::number(deviceId));
iq.setItems({item});
return iq;
return iq;
}

View File

@ -8,34 +8,36 @@
#include <QString>
class QXmppPubSubIq;
class QXmppElement;
class QXmppIq;
namespace QXmpp::Omemo {
class PreKey {
public:
[[nodiscard]] QXmppElement toXml() const;
/// Expects a <pk>
void fromXml(const QXmppElement &element);
class PreKey {
public:
[[nodiscard]] QXmppElement toXml() const;
/// Expects a <pk>
void fromXml(const QXmppElement &element);
int id;
QString data;
};
int id;
QString data;
};
class Bundle {
public:
[[nodiscard]] static QXmppPubSubIq fetchDeviceBundleIq(int deviceId);
class Bundle {
public:
[[nodiscard]] static QXmppPubSubIq fetchDeviceBundleIq(int deviceId);
[[nodiscard]] QXmppElement toXml() const;
[[nodiscard]] QXmppIq toIq(int deviceId) const;
void fromXml(const QXmppElement &element);
[[nodiscard]] QXmppElement toXml() const;
[[nodiscard]] QXmppIq toIq(int deviceId) const;
void fromXml(const QXmppElement &element);
QString spk;
int spkId;
QString spks;
QString ik;
QList<PreKey> prekeys;
};
QString spk;
int spkId;
QString spks;
QString ik;
QList<PreKey> prekeys;
};
} // namespace QXmpp::Omemo

View File

@ -13,114 +13,114 @@
using namespace QXmpp::Omemo;
Database::Database(QString jid) : jid(std::move(jid)) {
auto cacheLocation =
QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
auto path = QString("%1/.omemo/%2").arg(cacheLocation, jid);
QDir cache(path);
auto cacheLocation =
QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
auto path = QString("%1/.omemo/%2").arg(cacheLocation, jid);
QDir cache(path);
if (!cache.exists() && !cache.mkpath(path)) {
qWarning() << "Could not create:" << path;
throw QException();
}
if (!cache.exists() && !cache.mkpath(path)) {
qWarning() << "Could not create:" << path;
throw QException();
}
mdb_env_create(&env);
mdb_env_create(&env);
mdb_env_set_maxdbs(env, 5);
mdb_env_set_mapsize(env, 512UL * 1024UL * 1024UL);
mdb_env_open(env, path.toStdString().c_str(), 0, 0664);
mdb_env_set_maxdbs(env, 5);
mdb_env_set_mapsize(env, 512UL * 1024UL * 1024UL);
mdb_env_open(env, path.toStdString().c_str(), 0, 0664);
MDB_txn *txn;
mdb_txn_begin(env, nullptr, 0, &txn);
mdb_dbi_open(txn, "keys", MDB_CREATE, &dbiKeys);
mdb_dbi_open(txn, "devices", MDB_CREATE, &dbiDevices);
mdb_dbi_open(txn, "identity_keys", MDB_CREATE, &dbiIdentityKeys);
mdb_txn_commit(txn);
MDB_txn *txn;
mdb_txn_begin(env, nullptr, 0, &txn);
mdb_dbi_open(txn, "keys", MDB_CREATE, &dbiKeys);
mdb_dbi_open(txn, "devices", MDB_CREATE, &dbiDevices);
mdb_dbi_open(txn, "identity_keys", MDB_CREATE, &dbiIdentityKeys);
mdb_txn_commit(txn);
}
Database::~Database() {
mdb_dbi_close(env, dbiKeys);
mdb_dbi_close(env, dbiDevices);
mdb_dbi_close(env, dbiIdentityKeys);
mdb_env_close(env);
mdb_dbi_close(env, dbiKeys);
mdb_dbi_close(env, dbiDevices);
mdb_dbi_close(env, dbiIdentityKeys);
mdb_env_close(env);
}
QBuffer Database::loadIdentityKeySecret(int deviceId) { return QBuffer(); }
bool Database::saveIdentityKeySecret(int deviceId,
const QBuffer &identityKeySecret) {
MDB_val mdbKey, mdbValue;
auto key = QString("%1/secret").arg(QString::number(deviceId)).toStdString();
MDB_val mdbKey, mdbValue;
auto key = QString("%1/secret").arg(QString::number(deviceId)).toStdString();
mdbKey.mv_data = key.data();
mdbKey.mv_size = key.size();
mdbKey.mv_data = key.data();
mdbKey.mv_size = key.size();
mdbValue.mv_data = const_cast<char *>(identityKeySecret.data().data());
mdbValue.mv_size = identityKeySecret.size();
mdbValue.mv_data = const_cast<char *>(identityKeySecret.data().data());
mdbValue.mv_size = identityKeySecret.size();
MDB_txn *txn;
mdb_txn_begin(env, nullptr, 0, &txn);
auto err = mdb_put(txn, dbiIdentityKeys, &mdbKey, &mdbValue, MDB_NOOVERWRITE);
if (!err) {
mdb_txn_commit(txn);
return true;
}
MDB_txn *txn;
mdb_txn_begin(env, nullptr, 0, &txn);
auto err = mdb_put(txn, dbiIdentityKeys, &mdbKey, &mdbValue, MDB_NOOVERWRITE);
if (!err) {
mdb_txn_commit(txn);
return true;
}
qWarning() << "could not save identity key secret:" << mdb_strerror(err);
mdb_txn_abort(txn);
qWarning() << "could not save identity key secret:" << mdb_strerror(err);
mdb_txn_abort(txn);
return false;
return false;
}
int Database::loadActiveDeviceId() {
MDB_val key, value;
MDB_val key, value;
key.mv_data = (void *)"active";
key.mv_size = sizeof("active");
key.mv_data = (void *) "active";
key.mv_size = sizeof("active");
MDB_txn *txn;
mdb_txn_begin(env, nullptr, 0, &txn);
MDB_txn *txn;
mdb_txn_begin(env, nullptr, 0, &txn);
auto err = mdb_get(txn, dbiIdentityKeys, &key, &value);
if (err) {
qWarning() << "could not load active device id:" << mdb_strerror(err);
return 0;
}
auto err = mdb_get(txn, dbiIdentityKeys, &key, &value);
if (err) {
qWarning() << "could not load active device id:" << mdb_strerror(err);
return 0;
}
if (value.mv_size != sizeof(int)) {
qWarning() << "mv_size is" << value.mv_size << "instead of" << sizeof(int);
return 0;
}
if (value.mv_size != sizeof(int)) {
qWarning() << "mv_size is" << value.mv_size << "instead of" << sizeof(int);
return 0;
}
auto id = *reinterpret_cast<int *>(value.mv_data);
auto id = *reinterpret_cast<int *>(value.mv_data);
mdb_txn_abort(txn);
mdb_txn_abort(txn);
return id;
return id;
}
bool Database::saveActiveDeviceId(int deviceId) {
MDB_val key, value;
MDB_val key, value;
key.mv_data = (void *)"active";
key.mv_size = sizeof("active");
key.mv_data = (void *) "active";
key.mv_size = sizeof("active");
value.mv_data = &deviceId;
value.mv_size = sizeof(deviceId);
value.mv_data = &deviceId;
value.mv_size = sizeof(deviceId);
MDB_txn *txn;
mdb_txn_begin(env, nullptr, 0, &txn);
MDB_txn *txn;
mdb_txn_begin(env, nullptr, 0, &txn);
auto err = mdb_put(txn, dbiIdentityKeys, &key, &value, 0);
if (err) {
qWarning() << "could not save active device id" << mdb_strerror(err);
return false;
}
auto err = mdb_put(txn, dbiIdentityKeys, &key, &value, 0);
if (err) {
qWarning() << "could not save active device id" << mdb_strerror(err);
return false;
}
err = mdb_txn_commit(txn);
if (err) {
qWarning() << "could not save active device id" << mdb_strerror(err);
return false;
}
err = mdb_txn_commit(txn);
if (err) {
qWarning() << "could not save active device id" << mdb_strerror(err);
return false;
}
return true;
return true;
}

View File

@ -10,31 +10,31 @@
namespace QXmpp::Omemo {
class Database {
public:
explicit Database(QString jid);
~Database();
Database(const Database &) = delete;
Database(Database &&) = delete;
Database &operator=(const Database &) = delete;
class Database {
public:
explicit Database(QString jid);
~Database();
Database(const Database &) = delete;
Database(Database &&) = delete;
Database &operator=(const Database &) = delete;
QBuffer loadIdentityKey();
bool saveIdentityKey(const QBuffer &identityKey);
QBuffer loadIdentityKey();
bool saveIdentityKey(const QBuffer &identityKey);
int loadActiveDeviceId();
bool saveActiveDeviceId(int deviceId);
int loadActiveDeviceId();
bool saveActiveDeviceId(int deviceId);
QBuffer loadIdentityKeySecret(int deviceId);
bool saveIdentityKeySecret(int deviceId, const QBuffer &identityKeySecret);
QBuffer loadIdentityKeySecret(int deviceId);
bool saveIdentityKeySecret(int deviceId, const QBuffer &identityKeySecret);
const QString jid;
const QString jid;
private:
MDB_env *env{};
MDB_dbi dbiDevices{};
MDB_dbi dbiKeys{};
MDB_dbi dbiPreKeys{};
MDB_dbi dbiIdentityKeys{};
};
private:
MDB_env *env{};
MDB_dbi dbiDevices{};
MDB_dbi dbiKeys{};
MDB_dbi dbiPreKeys{};
MDB_dbi dbiIdentityKeys{};
};
} // namespace QXmpp::Omemo

View File

@ -7,18 +7,19 @@
#include <QList>
class QXmppElement;
class QXmppIq;
namespace QXmpp::Omemo {
class Device {
public:
int id;
};
class Device {
public:
int id;
};
class DeviceList {
public:
QList<Device> devices;
};
class DeviceList {
public:
QList<Device> devices;
};
} // namespace QXmpp::Omemo

View File

@ -6,10 +6,9 @@
#include <QRandomGenerator>
int QXmpp::Omemo::DeviceKeyStorage::generateDeviceId() {
QRandomGenerator random{};
QRandomGenerator random{};
return 1 + random.bounded(INT32_MAX - 1);
return 1 + random.bounded(INT32_MAX - 1);
}
QXmpp::Omemo::DeviceKeyStorage::DeviceKeyStorage(int deviceId)
: deviceId(deviceId) {}
QXmpp::Omemo::DeviceKeyStorage::DeviceKeyStorage(int deviceId) : deviceId(deviceId) {}

View File

@ -6,13 +6,13 @@
namespace QXmpp::Omemo {
class DeviceKeyStorage {
public:
static int generateDeviceId();
class DeviceKeyStorage {
public:
static int generateDeviceId();
explicit DeviceKeyStorage(int deviceId);
explicit DeviceKeyStorage(int deviceId);
const int deviceId;
};
const int deviceId;
};
} // namespace QXmpp::Omemo

View File

@ -7,10 +7,9 @@
QXmpp::Omemo::DeviceService::DeviceService(QObject *parent) : QObject(parent) {}
void QXmpp::Omemo::DeviceService::onDeviceListReceived(
const QString &jid, const QXmpp::Omemo::DeviceList &list) {
void QXmpp::Omemo::DeviceService::onDeviceListReceived(const QString &jid, const QXmpp::Omemo::DeviceList &list) {
for (const auto &device : list.devices) {
qInfo() << "Got device for" << jid << ":" << device.id;
}
for (const auto &device : list.devices) {
qInfo() << "Got device for" << jid << ":" << device.id;
}
}

View File

@ -11,19 +11,19 @@
namespace QXmpp::Omemo {
class DeviceList;
class DeviceList;
class DeviceService : public QObject {
Q_OBJECT
class DeviceService : public QObject {
Q_OBJECT
public:
explicit DeviceService(QObject *parent);
public:
explicit DeviceService(QObject *parent);
public slots:
void onDeviceListReceived(const QString &jid, const DeviceList &list);
public slots:
void onDeviceListReceived(const QString &jid, const QXmpp::Omemo::DeviceList &list);
private:
QMap<QString, UserDeviceList> device_lists{};
};
private:
QMap<QString, UserDeviceList> device_lists{};
};
} // namespace QXmpp::Omemo

View File

@ -13,82 +13,82 @@
using namespace QXmpp::Factories;
QXmppElement QXmpp::Omemo::EncryptedMessage::header() const {
auto result = createElement("header");
result.setAttribute("sid", QString::number(fromDeviceId));
auto result = createElement("header");
result.setAttribute("sid", QString::number(fromDeviceId));
auto ivNode = createElement("iv");
ivNode.setValue(iv);
auto ivNode = createElement("iv");
ivNode.setValue(iv);
for (const auto &key : keys) {
result.appendChild(key.toXml());
}
for (const auto &key : keys) {
result.appendChild(key.toXml());
}
return result;
return result;
}
QXmppElement QXmpp::Omemo::EncryptedMessage::toXml() const {
auto result = createElement("encrypted", "eu.siacs.conversations.axolotl");
auto result = createElement("encrypted", "eu.siacs.conversations.axolotl");
result.appendChild(header());
// TODO: Payload is optional
result.appendChild(payload());
result.appendChild(header());
// TODO: Payload is optional
result.appendChild(payload());
return result;
return result;
}
QXmppElement QXmpp::Omemo::EncryptedMessage::payload() const {
QBuffer buffer;
buffer.open(QIODevice::ReadWrite);
QXmlStreamWriter writer(&buffer);
message.toXml(&writer);
QBuffer buffer;
buffer.open(QIODevice::ReadWrite);
QXmlStreamWriter writer(&buffer);
message.toXml(&writer);
QDomDocument doc;
doc.setContent(buffer.data(), true);
QDomDocument doc;
doc.setContent(buffer.data(), true);
QXmppElement root(doc.documentElement());
root.setTagName("payload");
QXmppElement root(doc.documentElement());
root.setTagName("payload");
return root;
return root;
}
QXmppElement QXmpp::Omemo::EncryptedMessage::content() const {
auto envelope = createElement("content", "urn:xmpp:sce:0");
auto envelope = createElement("content", "urn:xmpp:sce:0");
envelope.appendChild(payload());
envelope.appendChild(payload());
if (!from.isEmpty()) {
auto fromNode = createElement("from");
fromNode.setAttribute("jid", from);
envelope.appendChild(fromNode);
}
if (!from.isEmpty()) {
auto fromNode = createElement("from");
fromNode.setAttribute("jid", from);
envelope.appendChild(fromNode);
}
if (!to.isEmpty()) {
auto toNode = createElement("to");
toNode.setAttribute("jid", to);
envelope.appendChild(toNode);
}
if (!to.isEmpty()) {
auto toNode = createElement("to");
toNode.setAttribute("jid", to);
envelope.appendChild(toNode);
}
if (!timestamp.isNull()) {
auto timeNode = createElement("time");
timeNode.setAttribute("stamp", timestamp.toString(Qt::DateFormat::ISODate));
envelope.appendChild(timeNode);
}
if (!timestamp.isNull()) {
auto timeNode = createElement("time");
timeNode.setAttribute("stamp", timestamp.toString(Qt::DateFormat::ISODate));
envelope.appendChild(timeNode);
}
auto rpad = createElement("rpad");
rpad.setValue(QXmpp::Sce::generatePadding());
envelope.appendChild(rpad);
auto rpad = createElement("rpad");
rpad.setValue(QXmpp::Sce::generatePadding());
envelope.appendChild(rpad);
return envelope;
return envelope;
}
QXmppElement QXmpp::Omemo::MessageKey::toXml() const {
auto result = createElement("key");
auto result = createElement("key");
result.setAttribute("rid", QString::number(receivingDeviceId));
if (prekey)
result.setAttribute("prekey", "true");
result.setAttribute("rid", QString::number(receivingDeviceId));
if (prekey)
result.setAttribute("prekey", "true");
result.setValue(key);
result.setValue(key);
return result;
return result;
}

View File

@ -11,32 +11,32 @@
namespace QXmpp::Omemo {
class MessageKey {
public:
[[nodiscard]] QXmppElement toXml() const;
class MessageKey {
public:
[[nodiscard]] QXmppElement toXml() const;
int receivingDeviceId{};
bool prekey{};
QString key{};
};
int receivingDeviceId{};
bool prekey{};
QString key{};
};
class EncryptedMessage {
public:
[[nodiscard]] QXmppElement header() const;
[[nodiscard]] QXmppElement content() const;
[[nodiscard]] QXmppElement toXml() const;
[[nodiscard]] QXmppElement payload() const;
class EncryptedMessage {
public:
[[nodiscard]] QXmppElement header() const;
[[nodiscard]] QXmppElement content() const;
[[nodiscard]] QXmppElement toXml() const;
[[nodiscard]] QXmppElement payload() const;
int fromDeviceId{};
int fromDeviceId{};
QList<MessageKey> keys{};
QString from{};
QString to{};
QDateTime timestamp{};
QList<MessageKey> keys{};
QString from{};
QString to{};
QDateTime timestamp{};
QString iv{};
QString iv{};
QXmppMessage message{};
};
QXmppMessage message{};
};
} // namespace QXmpp::Omemo

View File

@ -16,60 +16,59 @@
using namespace QXmpp::Omemo;
Manager::Manager()
: deviceService(new DeviceService(this)),
omemoVariant(new Variant::Conversations) {
connect(this, &Manager::deviceListReceived, deviceService.get(),
&DeviceService::onDeviceListReceived);
: deviceService(new DeviceService(this)),
omemoVariant(new Variant::Conversations) {
connect(this, &Manager::deviceListReceived, deviceService.get(), &DeviceService::onDeviceListReceived);
}
bool QXmpp::Omemo::Manager::handleStanza(const QDomElement &stanza) {
QString str{};
QTextStream info(&str);
stanza.save(info, 4);
QString str{};
QTextStream info(&str);
stanza.save(info, 4);
std::cout << str.toStdString();
std::cout << str.toStdString();
if (stanza.tagName() == "iq") {
if (stanza.attribute("type") == "result") {
auto pubsub = stanza.firstChildElement("pubsub");
if (!pubsub.isNull()) {
auto items = pubsub.firstChildElement("items");
if (items.attribute("node") ==
"eu.siacs.conversations.axolotl.devicelist") {
auto item = items.firstChildElement("item");
if (!item.isNull()) {
auto list = item.firstChildElement("list");
if (!list.isNull()) {
DeviceList deviceList = omemoVariant->deviceListFromXml(list);
emit deviceListReceived(stanza.attribute("from"), deviceList);
if (stanza.tagName() == "iq") {
if (stanza.attribute("type") == "result") {
auto pubsub = stanza.firstChildElement("pubsub");
if (!pubsub.isNull()) {
auto items = pubsub.firstChildElement("items");
if (items.attribute("node") ==
"eu.siacs.conversations.axolotl.devicelist") {
auto item = items.firstChildElement("item");
if (!item.isNull()) {
auto list = item.firstChildElement("list");
if (!list.isNull()) {
DeviceList deviceList = omemoVariant->deviceListFromXml(list);
emit deviceListReceived(stanza.attribute("from"), deviceList);
return true;
return true;
}
}
}
}
}
}
}
}
}
return false;
return false;
}
void QXmpp::Omemo::Manager::setClient(QXmppClient *client) {
QXmppClientExtension::setClient(client);
QXmppClientExtension::setClient(client);
if (!client)
return;
if (!client)
return;
QObject::connect(client, &QXmppClient::connected, this,
&Manager::fetchOwnDevices);
QObject::connect(client, &QXmppClient::connected, this,
&Manager::fetchOwnDevices);
}
void QXmpp::Omemo::Manager::fetchOwnDevices() {
QXmppPubSubIq iq{};
iq.setFrom(client()->configuration().jid());
iq.setTo(client()->configuration().jidBare());
iq.setType(QXmppIq::Get);
iq.setQueryNode("eu.siacs.conversations.axolotl.devicelist");
QXmppPubSubIq iq{};
iq.setFrom(client()->configuration().jid());
iq.setTo(client()->configuration().jidBare());
iq.setType(QXmppIq::Get);
iq.setQueryNode("eu.siacs.conversations.axolotl.devicelist");
client()->sendPacket(iq);
client()->sendPacket(iq);
}

View File

@ -12,27 +12,27 @@
namespace QXmpp::Omemo {
class Manager : public QXmppClientExtension {
Q_OBJECT;
class Manager : public QXmppClientExtension {
Q_OBJECT;
public:
Manager();
~Manager() override = default;
public:
Manager();
~Manager() override = default;
bool handleStanza(const QDomElement &stanza) override;
bool handleStanza(const QDomElement &stanza) override;
public slots:
void fetchOwnDevices();
public slots:
void fetchOwnDevices();
signals:
void deviceListReceived(const QString &jid, const DeviceList &list);
signals:
void deviceListReceived(const QString &jid, const QXmpp::Omemo::DeviceList &list);
protected:
void setClient(QXmppClient *client) override;
protected:
void setClient(QXmppClient *client) override;
private:
QScopedPointer<DeviceService> deviceService;
QScopedPointer<Variant::Base> omemoVariant;
};
private:
QScopedPointer<DeviceService> deviceService;
QScopedPointer<Variant::Base> omemoVariant;
};
} // namespace QXmpp::Omemo

View File

@ -6,19 +6,21 @@
#include <QRandomGenerator>
#define RPAD_ALPHABET "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
constexpr int RPAD_MAX_LENGTH = 200;
QString QXmpp::Sce::generatePadding() {
QRandomGenerator random{};
QString result{};
QString alphabet{ QStringLiteral("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~") };
QRandomGenerator random{};
QString result{};
QString alphabet{QStringLiteral(RPAD_ALPHABET)};
auto length = random.bounded(RPAD_MAX_LENGTH);
result.resize(length);
auto length = random.bounded(RPAD_MAX_LENGTH);
result.resize(length);
for (auto i = 0; i < length; ++i) {
result[i] = alphabet[random.bounded(alphabet.length())];
}
for (auto i = 0; i < length; ++i) {
result[i] = alphabet[random.bounded(alphabet.length())];
}
return result;
return result;
}

View File

@ -9,6 +9,6 @@
namespace QXmpp::Sce {
QString generatePadding();
QString generatePadding();
}

View File

@ -35,7 +35,8 @@ int Signal::Store::SignedPreKeyStore::loadSignedPreKey(signal_buffer **record, u
return 0;
}
int Signal::Store::SignedPreKeyStore::storeSignedPreKey(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len) {
int
Signal::Store::SignedPreKeyStore::storeSignedPreKey(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len) {
return 0;
}

View File

@ -6,5 +6,4 @@
#include <utility>
QXmpp::Omemo::UserDeviceList::UserDeviceList(QString jid)
: jid(std::move(jid)) {}
QXmpp::Omemo::UserDeviceList::UserDeviceList(QString jid) : jid(std::move(jid)) {}

View File

@ -8,11 +8,11 @@
namespace QXmpp::Omemo {
class UserDeviceList {
public:
explicit UserDeviceList(QString jid);
class UserDeviceList {
public:
explicit UserDeviceList(QString jid);
const QString jid;
};
const QString jid;
};
} // namespace QXmpp::Omemo

View File

@ -13,66 +13,66 @@ using namespace QXmpp::Omemo;
using namespace QXmpp::Factories;
QXmppElement Variant::Conversations::deviceToXml(const Device &device) {
auto result = createElement("device");
result.setAttribute("id", QString::number(device.id));
auto result = createElement("device");
result.setAttribute("id", QString::number(device.id));
return result;
return result;
}
Device Variant::Conversations::deviceFromXml(const QXmppElement &xml) {
Device result{};
Device result{};
if (!elementMatches(xml, "device"))
return result;
result.id = xml.attribute("id").toInt();
if (!elementMatches(xml, "device"))
return result;
result.id = xml.attribute("id").toInt();
return result;
}
QXmppElement
Variant::Conversations::deviceListToXml(const DeviceList &deviceList) {
auto element = createElement("list", "eu.siacs.conversations.axolotl");
auto element = createElement("list", "eu.siacs.conversations.axolotl");
for (const auto &device : deviceList.devices) {
element.appendChild(deviceToXml(device));
}
for (const auto &device : deviceList.devices) {
element.appendChild(deviceToXml(device));
}
return element;
return element;
}
DeviceList Variant::Conversations::deviceListFromXml(const QXmppElement &xml) {
DeviceList result{};
DeviceList result{};
if (!elementMatches(xml, "list", "eu.siacs.conversations.axolotl"))
return result;
auto deviceElement = xml.firstChildElement("device");
while (!deviceElement.isNull()) {
result.devices.push_back(deviceFromXml(deviceElement));
deviceElement = deviceElement.nextSiblingElement("device");
}
if (!elementMatches(xml, "list", "eu.siacs.conversations.axolotl"))
return result;
auto deviceElement = xml.firstChildElement("device");
while (!deviceElement.isNull()) {
result.devices.push_back(deviceFromXml(deviceElement));
deviceElement = deviceElement.nextSiblingElement("device");
}
return result;
}
QXmppIq Variant::Conversations::deviceListSetIq(const DeviceList &deviceList) {
QXmppIq iq{};
QXmppIq iq{};
iq.setType(QXmppIq::Set);
iq.setType(QXmppIq::Set);
auto item = createElement("item");
item.appendChild(deviceListToXml(deviceList));
auto item = createElement("item");
item.appendChild(deviceListToXml(deviceList));
auto publish = createElement("publish");
publish.setAttribute("node", "eu.siacs.conversations.axolotl.devicelist");
publish.appendChild(item);
auto publish = createElement("publish");
publish.setAttribute("node", "eu.siacs.conversations.axolotl.devicelist");
publish.appendChild(item);
auto pubSub = createElement("pubsub", "http://jabber.org/protocol/pubsub");
pubSub.appendChild(publish);
pubSub.appendChild(createOpenPublishOptions());
auto pubSub = createElement("pubsub", "http://jabber.org/protocol/pubsub");
pubSub.appendChild(publish);
pubSub.appendChild(createOpenPublishOptions());
iq.extensions().push_back(pubSub);
iq.extensions().push_back(pubSub);
return iq;
return iq;
}

View File

@ -8,16 +8,16 @@
namespace QXmpp::Omemo::Variant {
class Conversations : public Base {
public:
~Conversations() override = default;
class Conversations : public Base {
public:
~Conversations() override = default;
QXmppElement deviceToXml(const Device &device) override;
Device deviceFromXml(const QXmppElement &xml) override;
QXmppElement deviceToXml(const Device &device) override;
Device deviceFromXml(const QXmppElement &xml) override;
QXmppElement deviceListToXml(const DeviceList &deviceList) override;
DeviceList deviceListFromXml(const QXmppElement &xml) override;
QXmppIq deviceListSetIq(const DeviceList &deviceList) override;
};
QXmppElement deviceListToXml(const DeviceList &deviceList) override;
DeviceList deviceListFromXml(const QXmppElement &xml) override;
QXmppIq deviceListSetIq(const DeviceList &deviceList) override;
};
} // namespace QXmpp::Omemo::Variant

View File

@ -5,27 +5,29 @@
#pragma once
class QXmppElement;
class QXmppIq;
namespace QXmpp::Omemo {
class Device;
class DeviceList;
class Device;
namespace Variant {
class DeviceList;
class Base {
public:
virtual ~Base() = default;
namespace Variant {
virtual QXmppElement deviceToXml(const Device &device) = 0;
virtual Device deviceFromXml(const QXmppElement &xml) = 0;
class Base {
public:
virtual ~Base() = default;
virtual QXmppElement deviceListToXml(const DeviceList &deviceList) = 0;
virtual DeviceList deviceListFromXml(const QXmppElement &xml) = 0;
virtual QXmppIq deviceListSetIq(const DeviceList &deviceList) = 0;
};
virtual QXmppElement deviceToXml(const Device &device) = 0;
virtual Device deviceFromXml(const QXmppElement &xml) = 0;
} // namespace Variant
virtual QXmppElement deviceListToXml(const DeviceList &deviceList) = 0;
virtual DeviceList deviceListFromXml(const QXmppElement &xml) = 0;
virtual QXmppIq deviceListSetIq(const DeviceList &deviceList) = 0;
};
} // namespace Variant
} // namespace QXmpp::Omemo