forked from blue/squawk
ref(omemo): reformat qomemo/
This commit is contained in:
parent
574210f5d9
commit
bbeeee4c8a
@ -1,23 +1,23 @@
|
|||||||
target_sources(squawk PRIVATE
|
target_sources(squawk PRIVATE
|
||||||
bundle.cpp
|
bundle.cpp
|
||||||
bundle.h
|
bundle.h
|
||||||
database.cpp
|
database.cpp
|
||||||
database.h
|
database.h
|
||||||
device.cpp
|
device.cpp
|
||||||
device.h
|
device.h
|
||||||
device_key_storage.cpp
|
device_key_storage.cpp
|
||||||
device_key_storage.h
|
device_key_storage.h
|
||||||
device_service.cpp
|
device_service.cpp
|
||||||
device_service.h
|
device_service.h
|
||||||
qomemo.cpp
|
qomemo.cpp
|
||||||
qomemo.h
|
qomemo.h
|
||||||
sce.cpp
|
sce.cpp
|
||||||
sce.h
|
sce.h
|
||||||
user_device_list.cpp
|
user_device_list.cpp
|
||||||
user_device_list.h
|
user_device_list.h
|
||||||
qxmpp_omemo_manager.cpp
|
qxmpp_omemo_manager.cpp
|
||||||
qxmpp_omemo_manager.h
|
qxmpp_omemo_manager.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(signal)
|
add_subdirectory(signal)
|
||||||
add_subdirectory(variant)
|
add_subdirectory(variant)
|
||||||
|
12
qomemo/TODO
12
qomemo/TODO
@ -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)
|
|
@ -13,117 +13,117 @@
|
|||||||
using namespace QXmpp::Factories;
|
using namespace QXmpp::Factories;
|
||||||
|
|
||||||
QXmppElement QXmpp::Omemo::PreKey::toXml() const {
|
QXmppElement QXmpp::Omemo::PreKey::toXml() const {
|
||||||
auto pk = createElement("preKeyPublic");
|
auto pk = createElement("preKeyPublic");
|
||||||
pk.setAttribute("preKeyId", QString::number(id));
|
pk.setAttribute("preKeyId", QString::number(id));
|
||||||
// TODO: Base64
|
// TODO: Base64
|
||||||
pk.setValue(data);
|
pk.setValue(data);
|
||||||
|
|
||||||
return pk;
|
return pk;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QXmpp::Omemo::PreKey::fromXml(const QXmppElement &element) {
|
void QXmpp::Omemo::PreKey::fromXml(const QXmppElement &element) {
|
||||||
if (!elementMatches(element, "preKeyPublic"))
|
if (!elementMatches(element, "preKeyPublic"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
id = element.attribute("preKeyId").toInt();
|
id = element.attribute("preKeyId").toInt();
|
||||||
// TODO: Base64
|
// TODO: Base64
|
||||||
data = element.value();
|
data = element.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
QXmppElement QXmpp::Omemo::Bundle::toXml() const {
|
QXmppElement QXmpp::Omemo::Bundle::toXml() const {
|
||||||
auto spkNode = createElement("signedPreKeyPublic");
|
auto spkNode = createElement("signedPreKeyPublic");
|
||||||
spkNode.setAttribute("signedPreKeyId", QString::number(spkId));
|
spkNode.setAttribute("signedPreKeyId", QString::number(spkId));
|
||||||
spkNode.setValue(spk);
|
spkNode.setValue(spk);
|
||||||
|
|
||||||
auto spksNode = createElement("signedPreKeySignature");
|
auto spksNode = createElement("signedPreKeySignature");
|
||||||
spksNode.setValue(spks);
|
spksNode.setValue(spks);
|
||||||
|
|
||||||
auto ikNode = createElement("identityKey");
|
auto ikNode = createElement("identityKey");
|
||||||
ikNode.setValue(ik);
|
ikNode.setValue(ik);
|
||||||
|
|
||||||
auto prekeysNode = createElement("prekeys");
|
auto prekeysNode = createElement("prekeys");
|
||||||
for (const auto &pk : prekeys) {
|
for (const auto &pk : prekeys) {
|
||||||
prekeysNode.appendChild(pk.toXml());
|
prekeysNode.appendChild(pk.toXml());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = createElement("bundle", "eu.siacs.conversations.axolotl");
|
auto result = createElement("bundle", "eu.siacs.conversations.axolotl");
|
||||||
result.appendChild(spkNode);
|
result.appendChild(spkNode);
|
||||||
result.appendChild(spksNode);
|
result.appendChild(spksNode);
|
||||||
result.appendChild(ikNode);
|
result.appendChild(ikNode);
|
||||||
result.appendChild(prekeysNode);
|
result.appendChild(prekeysNode);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QXmppIq QXmpp::Omemo::Bundle::toIq(int deviceId) const {
|
QXmppIq QXmpp::Omemo::Bundle::toIq(int deviceId) const {
|
||||||
QXmppIq iq{};
|
QXmppIq iq{};
|
||||||
|
|
||||||
iq.setType(QXmppIq::Set);
|
iq.setType(QXmppIq::Set);
|
||||||
|
|
||||||
auto item = createElement("item");
|
auto item = createElement("item");
|
||||||
item.appendChild(toXml());
|
item.appendChild(toXml());
|
||||||
|
|
||||||
auto publish = createElement("publish");
|
auto publish = createElement("publish");
|
||||||
publish.setAttribute(
|
publish.setAttribute(
|
||||||
"node",
|
"node",
|
||||||
QString("eu.siacs.conversations.axolotl.bundles:%s").arg(deviceId));
|
QString("eu.siacs.conversations.axolotl.bundles:%s").arg(deviceId));
|
||||||
publish.appendChild(item);
|
publish.appendChild(item);
|
||||||
|
|
||||||
auto pubSub = createElement("pubsub", "http://jabber.org/protocol/pubsub");
|
auto pubSub = createElement("pubsub", "http://jabber.org/protocol/pubsub");
|
||||||
pubSub.appendChild(publish);
|
pubSub.appendChild(publish);
|
||||||
pubSub.appendChild(createOpenPublishOptions());
|
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) {
|
void QXmpp::Omemo::Bundle::fromXml(const QXmppElement &element) {
|
||||||
if (!elementMatches(element, "bundle", "eu.siacs.conversations.axolotl"))
|
if (!elementMatches(element, "bundle", "eu.siacs.conversations.axolotl"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto spkNode = element.firstChildElement("spk");
|
auto spkNode = element.firstChildElement("spk");
|
||||||
if (spkNode.isNull()) {
|
if (spkNode.isNull()) {
|
||||||
qWarning() << "'bundle': missing 'spk'";
|
qWarning() << "'bundle': missing 'spk'";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
spk = spkNode.value();
|
spk = spkNode.value();
|
||||||
spkId = spkNode.attribute("id").toInt();
|
spkId = spkNode.attribute("id").toInt();
|
||||||
|
|
||||||
auto spksNode = element.firstChildElement("spks");
|
auto spksNode = element.firstChildElement("spks");
|
||||||
if (spksNode.isNull()) {
|
if (spksNode.isNull()) {
|
||||||
qWarning() << "'bundle': missing 'spks'";
|
qWarning() << "'bundle': missing 'spks'";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
spks = spksNode.value();
|
spks = spksNode.value();
|
||||||
|
|
||||||
auto ikNode = element.firstChildElement("ik");
|
auto ikNode = element.firstChildElement("ik");
|
||||||
if (ikNode.isNull()) {
|
if (ikNode.isNull()) {
|
||||||
qWarning() << "'bundle': missing 'ik'";
|
qWarning() << "'bundle': missing 'ik'";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ik = ikNode.value();
|
ik = ikNode.value();
|
||||||
|
|
||||||
auto prekeysNode = element.firstChildElement("prekeys");
|
auto prekeysNode = element.firstChildElement("prekeys");
|
||||||
auto pkNode = prekeysNode.firstChildElement("pk");
|
auto pkNode = prekeysNode.firstChildElement("pk");
|
||||||
|
|
||||||
prekeys.clear();
|
prekeys.clear();
|
||||||
while (!pkNode.isNull()) {
|
while (!pkNode.isNull()) {
|
||||||
PreKey pk{};
|
PreKey pk{};
|
||||||
pk.fromXml(pkNode);
|
pk.fromXml(pkNode);
|
||||||
prekeys.push_back(pk);
|
prekeys.push_back(pk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QXmppPubSubIq QXmpp::Omemo::Bundle::fetchDeviceBundleIq(int deviceId) {
|
QXmppPubSubIq QXmpp::Omemo::Bundle::fetchDeviceBundleIq(int deviceId) {
|
||||||
QXmppPubSubIq iq{};
|
QXmppPubSubIq iq{};
|
||||||
iq.setType(QXmppIq::Get);
|
iq.setType(QXmppIq::Get);
|
||||||
iq.setQueryNode(
|
iq.setQueryNode(
|
||||||
QString("eu.siacs.conversations.axolotl.bundles:%1").arg(deviceId));
|
QString("eu.siacs.conversations.axolotl.bundles:%1").arg(deviceId));
|
||||||
|
|
||||||
QXmppPubSubItem item{};
|
QXmppPubSubItem item{};
|
||||||
item.setId(QString::number(deviceId));
|
item.setId(QString::number(deviceId));
|
||||||
iq.setItems({item});
|
iq.setItems({item});
|
||||||
|
|
||||||
return iq;
|
return iq;
|
||||||
}
|
}
|
@ -8,34 +8,36 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
class QXmppPubSubIq;
|
class QXmppPubSubIq;
|
||||||
|
|
||||||
class QXmppElement;
|
class QXmppElement;
|
||||||
|
|
||||||
class QXmppIq;
|
class QXmppIq;
|
||||||
|
|
||||||
namespace QXmpp::Omemo {
|
namespace QXmpp::Omemo {
|
||||||
|
|
||||||
class PreKey {
|
class PreKey {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] QXmppElement toXml() const;
|
[[nodiscard]] QXmppElement toXml() const;
|
||||||
/// Expects a <pk>
|
/// Expects a <pk>
|
||||||
void fromXml(const QXmppElement &element);
|
void fromXml(const QXmppElement &element);
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
QString data;
|
QString data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Bundle {
|
class Bundle {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static QXmppPubSubIq fetchDeviceBundleIq(int deviceId);
|
[[nodiscard]] static QXmppPubSubIq fetchDeviceBundleIq(int deviceId);
|
||||||
|
|
||||||
[[nodiscard]] QXmppElement toXml() const;
|
[[nodiscard]] QXmppElement toXml() const;
|
||||||
[[nodiscard]] QXmppIq toIq(int deviceId) const;
|
[[nodiscard]] QXmppIq toIq(int deviceId) const;
|
||||||
void fromXml(const QXmppElement &element);
|
void fromXml(const QXmppElement &element);
|
||||||
|
|
||||||
QString spk;
|
QString spk;
|
||||||
int spkId;
|
int spkId;
|
||||||
QString spks;
|
QString spks;
|
||||||
QString ik;
|
QString ik;
|
||||||
QList<PreKey> prekeys;
|
QList<PreKey> prekeys;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QXmpp::Omemo
|
} // namespace QXmpp::Omemo
|
||||||
|
@ -13,114 +13,114 @@
|
|||||||
using namespace QXmpp::Omemo;
|
using namespace QXmpp::Omemo;
|
||||||
|
|
||||||
Database::Database(QString jid) : jid(std::move(jid)) {
|
Database::Database(QString jid) : jid(std::move(jid)) {
|
||||||
auto cacheLocation =
|
auto cacheLocation =
|
||||||
QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||||
auto path = QString("%1/.omemo/%2").arg(cacheLocation, jid);
|
auto path = QString("%1/.omemo/%2").arg(cacheLocation, jid);
|
||||||
QDir cache(path);
|
QDir cache(path);
|
||||||
|
|
||||||
if (!cache.exists() && !cache.mkpath(path)) {
|
if (!cache.exists() && !cache.mkpath(path)) {
|
||||||
qWarning() << "Could not create:" << path;
|
qWarning() << "Could not create:" << path;
|
||||||
throw QException();
|
throw QException();
|
||||||
}
|
}
|
||||||
|
|
||||||
mdb_env_create(&env);
|
mdb_env_create(&env);
|
||||||
|
|
||||||
mdb_env_set_maxdbs(env, 5);
|
mdb_env_set_maxdbs(env, 5);
|
||||||
mdb_env_set_mapsize(env, 512UL * 1024UL * 1024UL);
|
mdb_env_set_mapsize(env, 512UL * 1024UL * 1024UL);
|
||||||
mdb_env_open(env, path.toStdString().c_str(), 0, 0664);
|
mdb_env_open(env, path.toStdString().c_str(), 0, 0664);
|
||||||
|
|
||||||
MDB_txn *txn;
|
MDB_txn *txn;
|
||||||
mdb_txn_begin(env, nullptr, 0, &txn);
|
mdb_txn_begin(env, nullptr, 0, &txn);
|
||||||
mdb_dbi_open(txn, "keys", MDB_CREATE, &dbiKeys);
|
mdb_dbi_open(txn, "keys", MDB_CREATE, &dbiKeys);
|
||||||
mdb_dbi_open(txn, "devices", MDB_CREATE, &dbiDevices);
|
mdb_dbi_open(txn, "devices", MDB_CREATE, &dbiDevices);
|
||||||
mdb_dbi_open(txn, "identity_keys", MDB_CREATE, &dbiIdentityKeys);
|
mdb_dbi_open(txn, "identity_keys", MDB_CREATE, &dbiIdentityKeys);
|
||||||
mdb_txn_commit(txn);
|
mdb_txn_commit(txn);
|
||||||
}
|
}
|
||||||
|
|
||||||
Database::~Database() {
|
Database::~Database() {
|
||||||
mdb_dbi_close(env, dbiKeys);
|
mdb_dbi_close(env, dbiKeys);
|
||||||
mdb_dbi_close(env, dbiDevices);
|
mdb_dbi_close(env, dbiDevices);
|
||||||
mdb_dbi_close(env, dbiIdentityKeys);
|
mdb_dbi_close(env, dbiIdentityKeys);
|
||||||
mdb_env_close(env);
|
mdb_env_close(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
QBuffer Database::loadIdentityKeySecret(int deviceId) { return QBuffer(); }
|
QBuffer Database::loadIdentityKeySecret(int deviceId) { return QBuffer(); }
|
||||||
|
|
||||||
bool Database::saveIdentityKeySecret(int deviceId,
|
bool Database::saveIdentityKeySecret(int deviceId,
|
||||||
const QBuffer &identityKeySecret) {
|
const QBuffer &identityKeySecret) {
|
||||||
MDB_val mdbKey, mdbValue;
|
MDB_val mdbKey, mdbValue;
|
||||||
auto key = QString("%1/secret").arg(QString::number(deviceId)).toStdString();
|
auto key = QString("%1/secret").arg(QString::number(deviceId)).toStdString();
|
||||||
|
|
||||||
mdbKey.mv_data = key.data();
|
mdbKey.mv_data = key.data();
|
||||||
mdbKey.mv_size = key.size();
|
mdbKey.mv_size = key.size();
|
||||||
|
|
||||||
mdbValue.mv_data = const_cast<char *>(identityKeySecret.data().data());
|
mdbValue.mv_data = const_cast<char *>(identityKeySecret.data().data());
|
||||||
mdbValue.mv_size = identityKeySecret.size();
|
mdbValue.mv_size = identityKeySecret.size();
|
||||||
|
|
||||||
MDB_txn *txn;
|
MDB_txn *txn;
|
||||||
mdb_txn_begin(env, nullptr, 0, &txn);
|
mdb_txn_begin(env, nullptr, 0, &txn);
|
||||||
auto err = mdb_put(txn, dbiIdentityKeys, &mdbKey, &mdbValue, MDB_NOOVERWRITE);
|
auto err = mdb_put(txn, dbiIdentityKeys, &mdbKey, &mdbValue, MDB_NOOVERWRITE);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
mdb_txn_commit(txn);
|
mdb_txn_commit(txn);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
qWarning() << "could not save identity key secret:" << mdb_strerror(err);
|
qWarning() << "could not save identity key secret:" << mdb_strerror(err);
|
||||||
mdb_txn_abort(txn);
|
mdb_txn_abort(txn);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Database::loadActiveDeviceId() {
|
int Database::loadActiveDeviceId() {
|
||||||
MDB_val key, value;
|
MDB_val key, value;
|
||||||
|
|
||||||
key.mv_data = (void *)"active";
|
key.mv_data = (void *) "active";
|
||||||
key.mv_size = sizeof("active");
|
key.mv_size = sizeof("active");
|
||||||
|
|
||||||
MDB_txn *txn;
|
MDB_txn *txn;
|
||||||
mdb_txn_begin(env, nullptr, 0, &txn);
|
mdb_txn_begin(env, nullptr, 0, &txn);
|
||||||
|
|
||||||
auto err = mdb_get(txn, dbiIdentityKeys, &key, &value);
|
auto err = mdb_get(txn, dbiIdentityKeys, &key, &value);
|
||||||
if (err) {
|
if (err) {
|
||||||
qWarning() << "could not load active device id:" << mdb_strerror(err);
|
qWarning() << "could not load active device id:" << mdb_strerror(err);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.mv_size != sizeof(int)) {
|
if (value.mv_size != sizeof(int)) {
|
||||||
qWarning() << "mv_size is" << value.mv_size << "instead of" << sizeof(int);
|
qWarning() << "mv_size is" << value.mv_size << "instead of" << sizeof(int);
|
||||||
return 0;
|
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) {
|
bool Database::saveActiveDeviceId(int deviceId) {
|
||||||
MDB_val key, value;
|
MDB_val key, value;
|
||||||
|
|
||||||
key.mv_data = (void *)"active";
|
key.mv_data = (void *) "active";
|
||||||
key.mv_size = sizeof("active");
|
key.mv_size = sizeof("active");
|
||||||
|
|
||||||
value.mv_data = &deviceId;
|
value.mv_data = &deviceId;
|
||||||
value.mv_size = sizeof(deviceId);
|
value.mv_size = sizeof(deviceId);
|
||||||
|
|
||||||
MDB_txn *txn;
|
MDB_txn *txn;
|
||||||
mdb_txn_begin(env, nullptr, 0, &txn);
|
mdb_txn_begin(env, nullptr, 0, &txn);
|
||||||
|
|
||||||
auto err = mdb_put(txn, dbiIdentityKeys, &key, &value, 0);
|
auto err = mdb_put(txn, dbiIdentityKeys, &key, &value, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
qWarning() << "could not save active device id" << mdb_strerror(err);
|
qWarning() << "could not save active device id" << mdb_strerror(err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mdb_txn_commit(txn);
|
err = mdb_txn_commit(txn);
|
||||||
if (err) {
|
if (err) {
|
||||||
qWarning() << "could not save active device id" << mdb_strerror(err);
|
qWarning() << "could not save active device id" << mdb_strerror(err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -10,31 +10,31 @@
|
|||||||
|
|
||||||
namespace QXmpp::Omemo {
|
namespace QXmpp::Omemo {
|
||||||
|
|
||||||
class Database {
|
class Database {
|
||||||
public:
|
public:
|
||||||
explicit Database(QString jid);
|
explicit Database(QString jid);
|
||||||
~Database();
|
~Database();
|
||||||
Database(const Database &) = delete;
|
Database(const Database &) = delete;
|
||||||
Database(Database &&) = delete;
|
Database(Database &&) = delete;
|
||||||
Database &operator=(const Database &) = delete;
|
Database &operator=(const Database &) = delete;
|
||||||
|
|
||||||
QBuffer loadIdentityKey();
|
QBuffer loadIdentityKey();
|
||||||
bool saveIdentityKey(const QBuffer &identityKey);
|
bool saveIdentityKey(const QBuffer &identityKey);
|
||||||
|
|
||||||
int loadActiveDeviceId();
|
int loadActiveDeviceId();
|
||||||
bool saveActiveDeviceId(int deviceId);
|
bool saveActiveDeviceId(int deviceId);
|
||||||
|
|
||||||
QBuffer loadIdentityKeySecret(int deviceId);
|
QBuffer loadIdentityKeySecret(int deviceId);
|
||||||
bool saveIdentityKeySecret(int deviceId, const QBuffer &identityKeySecret);
|
bool saveIdentityKeySecret(int deviceId, const QBuffer &identityKeySecret);
|
||||||
|
|
||||||
const QString jid;
|
const QString jid;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MDB_env *env{};
|
MDB_env *env{};
|
||||||
MDB_dbi dbiDevices{};
|
MDB_dbi dbiDevices{};
|
||||||
MDB_dbi dbiKeys{};
|
MDB_dbi dbiKeys{};
|
||||||
MDB_dbi dbiPreKeys{};
|
MDB_dbi dbiPreKeys{};
|
||||||
MDB_dbi dbiIdentityKeys{};
|
MDB_dbi dbiIdentityKeys{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QXmpp::Omemo
|
} // namespace QXmpp::Omemo
|
||||||
|
@ -7,18 +7,19 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
class QXmppElement;
|
class QXmppElement;
|
||||||
|
|
||||||
class QXmppIq;
|
class QXmppIq;
|
||||||
|
|
||||||
namespace QXmpp::Omemo {
|
namespace QXmpp::Omemo {
|
||||||
|
|
||||||
class Device {
|
class Device {
|
||||||
public:
|
public:
|
||||||
int id;
|
int id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeviceList {
|
class DeviceList {
|
||||||
public:
|
public:
|
||||||
QList<Device> devices;
|
QList<Device> devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QXmpp::Omemo
|
} // namespace QXmpp::Omemo
|
||||||
|
@ -6,10 +6,9 @@
|
|||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
|
|
||||||
int QXmpp::Omemo::DeviceKeyStorage::generateDeviceId() {
|
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)
|
QXmpp::Omemo::DeviceKeyStorage::DeviceKeyStorage(int deviceId) : deviceId(deviceId) {}
|
||||||
: deviceId(deviceId) {}
|
|
||||||
|
@ -6,13 +6,13 @@
|
|||||||
|
|
||||||
namespace QXmpp::Omemo {
|
namespace QXmpp::Omemo {
|
||||||
|
|
||||||
class DeviceKeyStorage {
|
class DeviceKeyStorage {
|
||||||
public:
|
public:
|
||||||
static int generateDeviceId();
|
static int generateDeviceId();
|
||||||
|
|
||||||
explicit DeviceKeyStorage(int deviceId);
|
explicit DeviceKeyStorage(int deviceId);
|
||||||
|
|
||||||
const int deviceId;
|
const int deviceId;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QXmpp::Omemo
|
} // namespace QXmpp::Omemo
|
||||||
|
@ -7,10 +7,9 @@
|
|||||||
|
|
||||||
QXmpp::Omemo::DeviceService::DeviceService(QObject *parent) : QObject(parent) {}
|
QXmpp::Omemo::DeviceService::DeviceService(QObject *parent) : QObject(parent) {}
|
||||||
|
|
||||||
void QXmpp::Omemo::DeviceService::onDeviceListReceived(
|
void QXmpp::Omemo::DeviceService::onDeviceListReceived(const QString &jid, const QXmpp::Omemo::DeviceList &list) {
|
||||||
const QString &jid, const QXmpp::Omemo::DeviceList &list) {
|
|
||||||
|
|
||||||
for (const auto &device : list.devices) {
|
for (const auto &device : list.devices) {
|
||||||
qInfo() << "Got device for" << jid << ":" << device.id;
|
qInfo() << "Got device for" << jid << ":" << device.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,19 +11,19 @@
|
|||||||
|
|
||||||
namespace QXmpp::Omemo {
|
namespace QXmpp::Omemo {
|
||||||
|
|
||||||
class DeviceList;
|
class DeviceList;
|
||||||
|
|
||||||
class DeviceService : public QObject {
|
class DeviceService : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DeviceService(QObject *parent);
|
explicit DeviceService(QObject *parent);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onDeviceListReceived(const QString &jid, const DeviceList &list);
|
void onDeviceListReceived(const QString &jid, const QXmpp::Omemo::DeviceList &list);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMap<QString, UserDeviceList> device_lists{};
|
QMap<QString, UserDeviceList> device_lists{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QXmpp::Omemo
|
} // namespace QXmpp::Omemo
|
||||||
|
@ -13,82 +13,82 @@
|
|||||||
using namespace QXmpp::Factories;
|
using namespace QXmpp::Factories;
|
||||||
|
|
||||||
QXmppElement QXmpp::Omemo::EncryptedMessage::header() const {
|
QXmppElement QXmpp::Omemo::EncryptedMessage::header() const {
|
||||||
auto result = createElement("header");
|
auto result = createElement("header");
|
||||||
result.setAttribute("sid", QString::number(fromDeviceId));
|
result.setAttribute("sid", QString::number(fromDeviceId));
|
||||||
|
|
||||||
auto ivNode = createElement("iv");
|
auto ivNode = createElement("iv");
|
||||||
ivNode.setValue(iv);
|
ivNode.setValue(iv);
|
||||||
|
|
||||||
for (const auto &key : keys) {
|
for (const auto &key : keys) {
|
||||||
result.appendChild(key.toXml());
|
result.appendChild(key.toXml());
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QXmppElement QXmpp::Omemo::EncryptedMessage::toXml() const {
|
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());
|
result.appendChild(header());
|
||||||
// TODO: Payload is optional
|
// TODO: Payload is optional
|
||||||
result.appendChild(payload());
|
result.appendChild(payload());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QXmppElement QXmpp::Omemo::EncryptedMessage::payload() const {
|
QXmppElement QXmpp::Omemo::EncryptedMessage::payload() const {
|
||||||
QBuffer buffer;
|
QBuffer buffer;
|
||||||
buffer.open(QIODevice::ReadWrite);
|
buffer.open(QIODevice::ReadWrite);
|
||||||
QXmlStreamWriter writer(&buffer);
|
QXmlStreamWriter writer(&buffer);
|
||||||
message.toXml(&writer);
|
message.toXml(&writer);
|
||||||
|
|
||||||
QDomDocument doc;
|
QDomDocument doc;
|
||||||
doc.setContent(buffer.data(), true);
|
doc.setContent(buffer.data(), true);
|
||||||
|
|
||||||
QXmppElement root(doc.documentElement());
|
QXmppElement root(doc.documentElement());
|
||||||
root.setTagName("payload");
|
root.setTagName("payload");
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
QXmppElement QXmpp::Omemo::EncryptedMessage::content() const {
|
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()) {
|
if (!from.isEmpty()) {
|
||||||
auto fromNode = createElement("from");
|
auto fromNode = createElement("from");
|
||||||
fromNode.setAttribute("jid", from);
|
fromNode.setAttribute("jid", from);
|
||||||
envelope.appendChild(fromNode);
|
envelope.appendChild(fromNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!to.isEmpty()) {
|
if (!to.isEmpty()) {
|
||||||
auto toNode = createElement("to");
|
auto toNode = createElement("to");
|
||||||
toNode.setAttribute("jid", to);
|
toNode.setAttribute("jid", to);
|
||||||
envelope.appendChild(toNode);
|
envelope.appendChild(toNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!timestamp.isNull()) {
|
if (!timestamp.isNull()) {
|
||||||
auto timeNode = createElement("time");
|
auto timeNode = createElement("time");
|
||||||
timeNode.setAttribute("stamp", timestamp.toString(Qt::DateFormat::ISODate));
|
timeNode.setAttribute("stamp", timestamp.toString(Qt::DateFormat::ISODate));
|
||||||
envelope.appendChild(timeNode);
|
envelope.appendChild(timeNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rpad = createElement("rpad");
|
auto rpad = createElement("rpad");
|
||||||
rpad.setValue(QXmpp::Sce::generatePadding());
|
rpad.setValue(QXmpp::Sce::generatePadding());
|
||||||
envelope.appendChild(rpad);
|
envelope.appendChild(rpad);
|
||||||
|
|
||||||
return envelope;
|
return envelope;
|
||||||
}
|
}
|
||||||
|
|
||||||
QXmppElement QXmpp::Omemo::MessageKey::toXml() const {
|
QXmppElement QXmpp::Omemo::MessageKey::toXml() const {
|
||||||
auto result = createElement("key");
|
auto result = createElement("key");
|
||||||
|
|
||||||
result.setAttribute("rid", QString::number(receivingDeviceId));
|
result.setAttribute("rid", QString::number(receivingDeviceId));
|
||||||
if (prekey)
|
if (prekey)
|
||||||
result.setAttribute("prekey", "true");
|
result.setAttribute("prekey", "true");
|
||||||
|
|
||||||
result.setValue(key);
|
result.setValue(key);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -11,32 +11,32 @@
|
|||||||
|
|
||||||
namespace QXmpp::Omemo {
|
namespace QXmpp::Omemo {
|
||||||
|
|
||||||
class MessageKey {
|
class MessageKey {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] QXmppElement toXml() const;
|
[[nodiscard]] QXmppElement toXml() const;
|
||||||
|
|
||||||
int receivingDeviceId{};
|
int receivingDeviceId{};
|
||||||
bool prekey{};
|
bool prekey{};
|
||||||
QString key{};
|
QString key{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class EncryptedMessage {
|
class EncryptedMessage {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] QXmppElement header() const;
|
[[nodiscard]] QXmppElement header() const;
|
||||||
[[nodiscard]] QXmppElement content() const;
|
[[nodiscard]] QXmppElement content() const;
|
||||||
[[nodiscard]] QXmppElement toXml() const;
|
[[nodiscard]] QXmppElement toXml() const;
|
||||||
[[nodiscard]] QXmppElement payload() const;
|
[[nodiscard]] QXmppElement payload() const;
|
||||||
|
|
||||||
int fromDeviceId{};
|
int fromDeviceId{};
|
||||||
|
|
||||||
QList<MessageKey> keys{};
|
QList<MessageKey> keys{};
|
||||||
QString from{};
|
QString from{};
|
||||||
QString to{};
|
QString to{};
|
||||||
QDateTime timestamp{};
|
QDateTime timestamp{};
|
||||||
|
|
||||||
QString iv{};
|
QString iv{};
|
||||||
|
|
||||||
QXmppMessage message{};
|
QXmppMessage message{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QXmpp::Omemo
|
} // namespace QXmpp::Omemo
|
||||||
|
@ -16,60 +16,59 @@
|
|||||||
using namespace QXmpp::Omemo;
|
using namespace QXmpp::Omemo;
|
||||||
|
|
||||||
Manager::Manager()
|
Manager::Manager()
|
||||||
: deviceService(new DeviceService(this)),
|
: deviceService(new DeviceService(this)),
|
||||||
omemoVariant(new Variant::Conversations) {
|
omemoVariant(new Variant::Conversations) {
|
||||||
connect(this, &Manager::deviceListReceived, deviceService.get(),
|
connect(this, &Manager::deviceListReceived, deviceService.get(), &DeviceService::onDeviceListReceived);
|
||||||
&DeviceService::onDeviceListReceived);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QXmpp::Omemo::Manager::handleStanza(const QDomElement &stanza) {
|
bool QXmpp::Omemo::Manager::handleStanza(const QDomElement &stanza) {
|
||||||
QString str{};
|
QString str{};
|
||||||
QTextStream info(&str);
|
QTextStream info(&str);
|
||||||
stanza.save(info, 4);
|
stanza.save(info, 4);
|
||||||
|
|
||||||
std::cout << str.toStdString();
|
std::cout << str.toStdString();
|
||||||
|
|
||||||
if (stanza.tagName() == "iq") {
|
if (stanza.tagName() == "iq") {
|
||||||
if (stanza.attribute("type") == "result") {
|
if (stanza.attribute("type") == "result") {
|
||||||
auto pubsub = stanza.firstChildElement("pubsub");
|
auto pubsub = stanza.firstChildElement("pubsub");
|
||||||
if (!pubsub.isNull()) {
|
if (!pubsub.isNull()) {
|
||||||
auto items = pubsub.firstChildElement("items");
|
auto items = pubsub.firstChildElement("items");
|
||||||
if (items.attribute("node") ==
|
if (items.attribute("node") ==
|
||||||
"eu.siacs.conversations.axolotl.devicelist") {
|
"eu.siacs.conversations.axolotl.devicelist") {
|
||||||
auto item = items.firstChildElement("item");
|
auto item = items.firstChildElement("item");
|
||||||
if (!item.isNull()) {
|
if (!item.isNull()) {
|
||||||
auto list = item.firstChildElement("list");
|
auto list = item.firstChildElement("list");
|
||||||
if (!list.isNull()) {
|
if (!list.isNull()) {
|
||||||
DeviceList deviceList = omemoVariant->deviceListFromXml(list);
|
DeviceList deviceList = omemoVariant->deviceListFromXml(list);
|
||||||
emit deviceListReceived(stanza.attribute("from"), deviceList);
|
emit deviceListReceived(stanza.attribute("from"), deviceList);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QXmpp::Omemo::Manager::setClient(QXmppClient *client) {
|
void QXmpp::Omemo::Manager::setClient(QXmppClient *client) {
|
||||||
QXmppClientExtension::setClient(client);
|
QXmppClientExtension::setClient(client);
|
||||||
|
|
||||||
if (!client)
|
if (!client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QObject::connect(client, &QXmppClient::connected, this,
|
QObject::connect(client, &QXmppClient::connected, this,
|
||||||
&Manager::fetchOwnDevices);
|
&Manager::fetchOwnDevices);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QXmpp::Omemo::Manager::fetchOwnDevices() {
|
void QXmpp::Omemo::Manager::fetchOwnDevices() {
|
||||||
QXmppPubSubIq iq{};
|
QXmppPubSubIq iq{};
|
||||||
iq.setFrom(client()->configuration().jid());
|
iq.setFrom(client()->configuration().jid());
|
||||||
iq.setTo(client()->configuration().jidBare());
|
iq.setTo(client()->configuration().jidBare());
|
||||||
iq.setType(QXmppIq::Get);
|
iq.setType(QXmppIq::Get);
|
||||||
iq.setQueryNode("eu.siacs.conversations.axolotl.devicelist");
|
iq.setQueryNode("eu.siacs.conversations.axolotl.devicelist");
|
||||||
|
|
||||||
client()->sendPacket(iq);
|
client()->sendPacket(iq);
|
||||||
}
|
}
|
||||||
|
@ -12,27 +12,27 @@
|
|||||||
|
|
||||||
namespace QXmpp::Omemo {
|
namespace QXmpp::Omemo {
|
||||||
|
|
||||||
class Manager : public QXmppClientExtension {
|
class Manager : public QXmppClientExtension {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Manager();
|
Manager();
|
||||||
~Manager() override = default;
|
~Manager() override = default;
|
||||||
|
|
||||||
bool handleStanza(const QDomElement &stanza) override;
|
bool handleStanza(const QDomElement &stanza) override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void fetchOwnDevices();
|
void fetchOwnDevices();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void deviceListReceived(const QString &jid, const DeviceList &list);
|
void deviceListReceived(const QString &jid, const QXmpp::Omemo::DeviceList &list);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setClient(QXmppClient *client) override;
|
void setClient(QXmppClient *client) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScopedPointer<DeviceService> deviceService;
|
QScopedPointer<DeviceService> deviceService;
|
||||||
QScopedPointer<Variant::Base> omemoVariant;
|
QScopedPointer<Variant::Base> omemoVariant;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QXmpp::Omemo
|
} // namespace QXmpp::Omemo
|
||||||
|
@ -6,19 +6,21 @@
|
|||||||
|
|
||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
|
|
||||||
|
#define RPAD_ALPHABET "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
||||||
|
|
||||||
constexpr int RPAD_MAX_LENGTH = 200;
|
constexpr int RPAD_MAX_LENGTH = 200;
|
||||||
|
|
||||||
QString QXmpp::Sce::generatePadding() {
|
QString QXmpp::Sce::generatePadding() {
|
||||||
QRandomGenerator random{};
|
QRandomGenerator random{};
|
||||||
QString result{};
|
QString result{};
|
||||||
QString alphabet{ QStringLiteral("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~") };
|
QString alphabet{QStringLiteral(RPAD_ALPHABET)};
|
||||||
|
|
||||||
auto length = random.bounded(RPAD_MAX_LENGTH);
|
auto length = random.bounded(RPAD_MAX_LENGTH);
|
||||||
result.resize(length);
|
result.resize(length);
|
||||||
|
|
||||||
for (auto i = 0; i < length; ++i) {
|
for (auto i = 0; i < length; ++i) {
|
||||||
result[i] = alphabet[random.bounded(alphabet.length())];
|
result[i] = alphabet[random.bounded(alphabet.length())];
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,6 @@
|
|||||||
|
|
||||||
namespace QXmpp::Sce {
|
namespace QXmpp::Sce {
|
||||||
|
|
||||||
QString generatePadding();
|
QString generatePadding();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,8 @@ int Signal::Store::SignedPreKeyStore::loadSignedPreKey(signal_buffer **record, u
|
|||||||
return 0;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,5 +6,4 @@
|
|||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
QXmpp::Omemo::UserDeviceList::UserDeviceList(QString jid)
|
QXmpp::Omemo::UserDeviceList::UserDeviceList(QString jid) : jid(std::move(jid)) {}
|
||||||
: jid(std::move(jid)) {}
|
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
namespace QXmpp::Omemo {
|
namespace QXmpp::Omemo {
|
||||||
|
|
||||||
class UserDeviceList {
|
class UserDeviceList {
|
||||||
public:
|
public:
|
||||||
explicit UserDeviceList(QString jid);
|
explicit UserDeviceList(QString jid);
|
||||||
|
|
||||||
const QString jid;
|
const QString jid;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QXmpp::Omemo
|
} // namespace QXmpp::Omemo
|
||||||
|
@ -13,66 +13,66 @@ using namespace QXmpp::Omemo;
|
|||||||
using namespace QXmpp::Factories;
|
using namespace QXmpp::Factories;
|
||||||
|
|
||||||
QXmppElement Variant::Conversations::deviceToXml(const Device &device) {
|
QXmppElement Variant::Conversations::deviceToXml(const Device &device) {
|
||||||
auto result = createElement("device");
|
auto result = createElement("device");
|
||||||
result.setAttribute("id", QString::number(device.id));
|
result.setAttribute("id", QString::number(device.id));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Device Variant::Conversations::deviceFromXml(const QXmppElement &xml) {
|
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;
|
return result;
|
||||||
|
|
||||||
result.id = xml.attribute("id").toInt();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QXmppElement
|
QXmppElement
|
||||||
Variant::Conversations::deviceListToXml(const DeviceList &deviceList) {
|
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) {
|
for (const auto &device : deviceList.devices) {
|
||||||
element.appendChild(deviceToXml(device));
|
element.appendChild(deviceToXml(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceList Variant::Conversations::deviceListFromXml(const QXmppElement &xml) {
|
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;
|
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 Variant::Conversations::deviceListSetIq(const DeviceList &deviceList) {
|
||||||
QXmppIq iq{};
|
QXmppIq iq{};
|
||||||
|
|
||||||
iq.setType(QXmppIq::Set);
|
iq.setType(QXmppIq::Set);
|
||||||
|
|
||||||
auto item = createElement("item");
|
auto item = createElement("item");
|
||||||
item.appendChild(deviceListToXml(deviceList));
|
item.appendChild(deviceListToXml(deviceList));
|
||||||
|
|
||||||
auto publish = createElement("publish");
|
auto publish = createElement("publish");
|
||||||
publish.setAttribute("node", "eu.siacs.conversations.axolotl.devicelist");
|
publish.setAttribute("node", "eu.siacs.conversations.axolotl.devicelist");
|
||||||
publish.appendChild(item);
|
publish.appendChild(item);
|
||||||
|
|
||||||
auto pubSub = createElement("pubsub", "http://jabber.org/protocol/pubsub");
|
auto pubSub = createElement("pubsub", "http://jabber.org/protocol/pubsub");
|
||||||
pubSub.appendChild(publish);
|
pubSub.appendChild(publish);
|
||||||
pubSub.appendChild(createOpenPublishOptions());
|
pubSub.appendChild(createOpenPublishOptions());
|
||||||
|
|
||||||
iq.extensions().push_back(pubSub);
|
iq.extensions().push_back(pubSub);
|
||||||
|
|
||||||
return iq;
|
return iq;
|
||||||
}
|
}
|
||||||
|
@ -8,16 +8,16 @@
|
|||||||
|
|
||||||
namespace QXmpp::Omemo::Variant {
|
namespace QXmpp::Omemo::Variant {
|
||||||
|
|
||||||
class Conversations : public Base {
|
class Conversations : public Base {
|
||||||
public:
|
public:
|
||||||
~Conversations() override = default;
|
~Conversations() override = default;
|
||||||
|
|
||||||
QXmppElement deviceToXml(const Device &device) override;
|
QXmppElement deviceToXml(const Device &device) override;
|
||||||
Device deviceFromXml(const QXmppElement &xml) override;
|
Device deviceFromXml(const QXmppElement &xml) override;
|
||||||
|
|
||||||
QXmppElement deviceListToXml(const DeviceList &deviceList) override;
|
QXmppElement deviceListToXml(const DeviceList &deviceList) override;
|
||||||
DeviceList deviceListFromXml(const QXmppElement &xml) override;
|
DeviceList deviceListFromXml(const QXmppElement &xml) override;
|
||||||
QXmppIq deviceListSetIq(const DeviceList &deviceList) override;
|
QXmppIq deviceListSetIq(const DeviceList &deviceList) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QXmpp::Omemo::Variant
|
} // namespace QXmpp::Omemo::Variant
|
||||||
|
@ -5,27 +5,29 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class QXmppElement;
|
class QXmppElement;
|
||||||
|
|
||||||
class QXmppIq;
|
class QXmppIq;
|
||||||
|
|
||||||
namespace QXmpp::Omemo {
|
namespace QXmpp::Omemo {
|
||||||
|
|
||||||
class Device;
|
class Device;
|
||||||
class DeviceList;
|
|
||||||
|
|
||||||
namespace Variant {
|
class DeviceList;
|
||||||
|
|
||||||
class Base {
|
namespace Variant {
|
||||||
public:
|
|
||||||
virtual ~Base() = default;
|
|
||||||
|
|
||||||
virtual QXmppElement deviceToXml(const Device &device) = 0;
|
class Base {
|
||||||
virtual Device deviceFromXml(const QXmppElement &xml) = 0;
|
public:
|
||||||
|
virtual ~Base() = default;
|
||||||
|
|
||||||
virtual QXmppElement deviceListToXml(const DeviceList &deviceList) = 0;
|
virtual QXmppElement deviceToXml(const Device &device) = 0;
|
||||||
virtual DeviceList deviceListFromXml(const QXmppElement &xml) = 0;
|
virtual Device deviceFromXml(const QXmppElement &xml) = 0;
|
||||||
virtual QXmppIq deviceListSetIq(const DeviceList &deviceList) = 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
|
} // namespace QXmpp::Omemo
|
||||||
|
Loading…
Reference in New Issue
Block a user