mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Implement tox3 support, keep tox1 as silent fallback
This commit is contained in:
parent
de3befe116
commit
0b6a4a6481
21
qtox.pro
21
qtox.pro
|
@ -63,43 +63,32 @@ contains(JENKINS,YES) {
|
||||||
# Rules for Windows, Mac OSX, and Linux
|
# Rules for Windows, Mac OSX, and Linux
|
||||||
win32 {
|
win32 {
|
||||||
RC_FILE = windows/qtox.rc
|
RC_FILE = windows/qtox.rc
|
||||||
LIBS += -liphlpapi -L$$PWD/libs/lib -ltoxav -ltoxcore -ltoxencryptsave -lvpx -lpthread
|
LIBS += -liphlpapi -L$$PWD/libs/lib -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lvpx -lpthread
|
||||||
LIBS += -L$$PWD/libs/lib -lopencv_core248 -lopencv_highgui248 -lopencv_imgproc248 -lOpenAL32 -lopus
|
LIBS += -L$$PWD/libs/lib -lopencv_core248 -lopencv_highgui248 -lopencv_imgproc248 -lOpenAL32 -lopus
|
||||||
LIBS += -lz -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -ljpeg -ltiff -lpng -ljasper -lIlmImf -lHalf -lws2_32
|
LIBS += -lz -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -ljpeg -ltiff -lpng -ljasper -lIlmImf -lHalf -lws2_32
|
||||||
} else {
|
} else {
|
||||||
macx {
|
macx {
|
||||||
ICON = img/icons/qtox.icns
|
ICON = img/icons/qtox.icns
|
||||||
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -lsodium -lvpx -framework OpenAL -lopencv_core -lopencv_highgui
|
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -framework OpenAL -lopencv_core -lopencv_highgui
|
||||||
} else {
|
} else {
|
||||||
# If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package
|
# If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package
|
||||||
contains(STATICPKG, YES) {
|
contains(STATICPKG, YES) {
|
||||||
target.path = /usr/bin
|
target.path = /usr/bin
|
||||||
INSTALLS += target
|
INSTALLS += target
|
||||||
LIBS += -L$$PWD/libs/lib/ -lopus -lvpx -lopenal -Wl,-Bstatic -ltoxcore -ltoxav -ltoxencryptsave -lsodium -lopencv_highgui -lopencv_imgproc -lopencv_core -lz -Wl,-Bdynamic
|
LIBS += -L$$PWD/libs/lib/ -lopus -lvpx -lopenal -Wl,-Bstatic -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lopencv_highgui -lopencv_imgproc -lopencv_core -lz -Wl,-Bdynamic
|
||||||
LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig
|
LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig
|
||||||
LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0
|
LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -lvpx -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc
|
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc
|
||||||
}
|
}
|
||||||
|
|
||||||
contains(JENKINS, YES) {
|
contains(JENKINS, YES) {
|
||||||
LIBS = ./libs/lib/libsodium.a ./libs/lib/libtoxcore.a ./libs/lib/libtoxav.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libvpx.a ./libs/lib/libopus.a -lopencv_core -lopencv_highgui -lopenal
|
LIBS = ./libs/lib/libsodium.a ./libs/lib/libtoxcore.a ./libs/lib/libtoxav.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxdns.a ./libs/lib/libvpx.a ./libs/lib/libopus.a -lopencv_core -lopencv_highgui -lopenal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#### Static linux build
|
|
||||||
#LIBS += -Wl,-Bstatic -ltoxcore -ltoxav -lsodium -lvpx -lopus \
|
|
||||||
# -lgstbase-0.10 -lgstreamer-0.10 -lgmodule-2.0 -lgstaudio-0.10 -lxml2 \
|
|
||||||
# -lX11-xcb -lXi -lxcb-render-util -lxcb-glx -lxcb-render -ldbus-1 \
|
|
||||||
# -lxcb -lXau -lXdmcp -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape \
|
|
||||||
# -lxcb-keysyms -lxcb-xkb -lfontconfig -lfreetype -lXrender -lXext -lX11 \
|
|
||||||
# -lpng -lz -licui18n -licuuc -licudata -lm -lgthread-2.0 \
|
|
||||||
# -pthread -lrt -lGL -lpthread -Wl,-Bdynamic -ldl -lc
|
|
||||||
#QMAKE_CXXFLAGS += -Os -flto -static-libstdc++ -static-libgcc
|
|
||||||
|
|
||||||
HEADERS += src/widget/form/addfriendform.h \
|
HEADERS += src/widget/form/addfriendform.h \
|
||||||
src/widget/form/chatform.h \
|
src/widget/form/chatform.h \
|
||||||
src/widget/form/groupchatform.h \
|
src/widget/form/groupchatform.h \
|
||||||
|
|
|
@ -18,12 +18,25 @@
|
||||||
|
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QThread>
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
#include "src/core.h"
|
#include "src/core.h"
|
||||||
|
#include "src/misc/cdata.h"
|
||||||
|
#include "tox/toxdns.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#define TOX_ID_LENGTH 2*TOX_FRIEND_ADDRESS_SIZE
|
#define TOX_ID_LENGTH 2*TOX_FRIEND_ADDRESS_SIZE
|
||||||
|
|
||||||
|
const AddFriendForm::tox3_server AddFriendForm::pinnedServers[]
|
||||||
|
{
|
||||||
|
{"toxme.se", (uint8_t[32]){0x5D, 0x72, 0xC5, 0x17, 0xDF, 0x6A, 0xEC, 0x54, 0xF1, 0xE9, 0x77, 0xA6, 0xB6, 0xF2, 0x59, 0x14,
|
||||||
|
0xEA, 0x4C, 0xF7, 0x27, 0x7A, 0x85, 0x02, 0x7C, 0xD9, 0xF5, 0x19, 0x6D, 0xF1, 0x7E, 0x0B, 0x13}},
|
||||||
|
{"utox.org", (uint8_t[32]){0xD3, 0x15, 0x4F, 0x65, 0xD2, 0x8A, 0x5B, 0x41, 0xA0, 0x5D, 0x4A, 0xC7, 0xE4, 0xB3, 0x9C, 0x6B,
|
||||||
|
0x1C, 0x23, 0x3C, 0xC8, 0x57, 0xFB, 0x36, 0x5C, 0x56, 0xE8, 0x39, 0x27, 0x37, 0x46, 0x2A, 0x12}}
|
||||||
|
};
|
||||||
|
|
||||||
AddFriendForm::AddFriendForm() : dns(this)
|
AddFriendForm::AddFriendForm() : dns(this)
|
||||||
{
|
{
|
||||||
dns.setType(QDnsLookup::TXT);
|
dns.setType(QDnsLookup::TXT);
|
||||||
|
@ -50,7 +63,6 @@ AddFriendForm::AddFriendForm() : dns(this)
|
||||||
headLayout.addWidget(&headLabel);
|
headLayout.addWidget(&headLabel);
|
||||||
|
|
||||||
connect(&sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
|
connect(&sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
|
||||||
connect(&dns, SIGNAL(finished()), this, SLOT(handleDnsLookup()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AddFriendForm::~AddFriendForm()
|
AddFriendForm::~AddFriendForm()
|
||||||
|
@ -99,50 +111,102 @@ void AddFriendForm::onSendTriggered()
|
||||||
showWarning(tr("You can't add yourself as a friend!","When trying to add your own Tox ID as friend"));
|
showWarning(tr("You can't add yourself as a friend!","When trying to add your own Tox ID as friend"));
|
||||||
else
|
else
|
||||||
emit friendRequested(id, getMessage());
|
emit friendRequested(id, getMessage());
|
||||||
this->toxId.setText("");
|
this->toxId.clear();
|
||||||
this->message.setText("");
|
this->message.clear();
|
||||||
} else {
|
} else {
|
||||||
id = id.replace("@", "._tox.");
|
// If we're querying one of our pinned server, do a tox3 request directly
|
||||||
dns.setName(id);
|
QString servname = id.mid(id.indexOf('@')+1);
|
||||||
dns.lookup();
|
for (const AddFriendForm::tox3_server& pin : pinnedServers)
|
||||||
|
{
|
||||||
|
if (servname == pin.name)
|
||||||
|
{
|
||||||
|
queryTox3(pin, id);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddFriendForm::handleDnsLookup()
|
// Otherwise try tox3 if we can get a pubkey or fallback to tox1
|
||||||
|
QByteArray pubkey = fetchLastTextRecord("_tox."+servname);
|
||||||
|
if (!pubkey.isEmpty())
|
||||||
{
|
{
|
||||||
const QString idKeyWord("id="), verKeyWord("v=");
|
QByteArray servnameData = servname.toUtf8();
|
||||||
|
AddFriendForm::tox3_server server;
|
||||||
|
server.name = servnameData.data();
|
||||||
|
server.pubkey = (uint8_t*)pubkey.data();
|
||||||
|
queryTox3(server, id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
queryTox1(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray AddFriendForm::fetchLastTextRecord(const QString& record, bool silent)
|
||||||
|
{
|
||||||
|
QByteArray result;
|
||||||
|
|
||||||
|
dns.setName(record);
|
||||||
|
dns.lookup();
|
||||||
|
|
||||||
|
int timeout;
|
||||||
|
for (timeout = 0; timeout<30 && !dns.isFinished(); ++timeout)
|
||||||
|
{
|
||||||
|
qApp->processEvents();
|
||||||
|
QThread::msleep(100);
|
||||||
|
}
|
||||||
|
if (timeout >= 30) {
|
||||||
|
dns.abort();
|
||||||
|
if (!silent)
|
||||||
|
showWarning(tr("The connection timed out","The DNS gives the Tox ID associated to toxme.se addresses"));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if (dns.error() == QDnsLookup::NotFoundError) {
|
if (dns.error() == QDnsLookup::NotFoundError) {
|
||||||
|
if (!silent)
|
||||||
showWarning(tr("This address does not exist","The DNS gives the Tox ID associated to toxme.se addresses"));
|
showWarning(tr("This address does not exist","The DNS gives the Tox ID associated to toxme.se addresses"));
|
||||||
return;
|
return result;
|
||||||
}
|
}
|
||||||
else if (dns.error() != QDnsLookup::NoError) {
|
else if (dns.error() != QDnsLookup::NoError) {
|
||||||
|
if (!silent)
|
||||||
showWarning(tr("Error while looking up DNS","The DNS gives the Tox ID associated to toxme.se addresses"));
|
showWarning(tr("Error while looking up DNS","The DNS gives the Tox ID associated to toxme.se addresses"));
|
||||||
return;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QList<QDnsTextRecord> textRecords = dns.textRecords();
|
const QList<QDnsTextRecord> textRecords = dns.textRecords();
|
||||||
if (textRecords.length() != 1) {
|
if (textRecords.isEmpty()) {
|
||||||
showWarning(tr("Unexpected number of text records", "Error with the DNS"));
|
if (!silent)
|
||||||
return;
|
showWarning(tr("No text record found", "Error with the DNS"));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QList<QByteArray> textRecordValues = textRecords.first().values();
|
const QList<QByteArray> textRecordValues = textRecords.last().values();
|
||||||
if (textRecordValues.length() != 1) {
|
if (textRecordValues.length() != 1) {
|
||||||
|
if (!silent)
|
||||||
showWarning(tr("Unexpected number of values in text record", "Error with the DNS"));
|
showWarning(tr("Unexpected number of values in text record", "Error with the DNS"));
|
||||||
return;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString entry(textRecordValues.first());
|
result = textRecordValues.first();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Check toxdns protocol version, we only support tox1 for now
|
void AddFriendForm::queryTox1(const QString& record)
|
||||||
int verx = entry.indexOf(verKeyWord);
|
{
|
||||||
|
QString realRecord = record;
|
||||||
|
realRecord.replace("@", "._tox.");
|
||||||
|
const QString entry = fetchLastTextRecord(realRecord, false);
|
||||||
|
if (entry.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check toxdns protocol version
|
||||||
|
int verx = entry.indexOf("v=");
|
||||||
if (verx) {
|
if (verx) {
|
||||||
verx += verKeyWord.size();
|
verx += 2;
|
||||||
int verend = entry.indexOf(';', verx);
|
int verend = entry.indexOf(';', verx);
|
||||||
if (verend)
|
if (verend)
|
||||||
{
|
{
|
||||||
QString ver = entry.mid(verx, verend);
|
QString ver = entry.mid(verx, verend-verx);
|
||||||
if (ver != "tox1")
|
if (ver != "tox1")
|
||||||
{
|
{
|
||||||
showWarning(tr("The version of Tox DNS used by this server is not supported", "Error with the DNS"));
|
showWarning(tr("The version of Tox DNS used by this server is not supported", "Error with the DNS"));
|
||||||
|
@ -151,13 +215,14 @@ void AddFriendForm::handleDnsLookup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = entry.indexOf(idKeyWord);
|
// Get the tox id
|
||||||
|
int idx = entry.indexOf("id=");
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
showWarning(tr("The DNS lookup does not contain any Tox ID", "Error with the DNS"));
|
showWarning(tr("The DNS lookup does not contain any Tox ID", "Error with the DNS"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
idx += idKeyWord.length();
|
idx += 3;
|
||||||
if (entry.length() < idx + static_cast<int>(TOX_ID_LENGTH)) {
|
if (entry.length() < idx + static_cast<int>(TOX_ID_LENGTH)) {
|
||||||
showWarning(tr("The DNS lookup does not contain a valid Tox ID", "Error with the DNS"));
|
showWarning(tr("The DNS lookup does not contain a valid Tox ID", "Error with the DNS"));
|
||||||
return;
|
return;
|
||||||
|
@ -171,6 +236,86 @@ void AddFriendForm::handleDnsLookup()
|
||||||
|
|
||||||
// finally we got it
|
// finally we got it
|
||||||
emit friendRequested(friendAdress, getMessage());
|
emit friendRequested(friendAdress, getMessage());
|
||||||
this->toxId.setText("");
|
this->toxId.clear();
|
||||||
this->message.setText("");
|
this->message.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddFriendForm::queryTox3(const tox3_server& server, QString &record)
|
||||||
|
{
|
||||||
|
QByteArray nameData = record.left(record.indexOf('@')).toUtf8(), id, realRecord;
|
||||||
|
QString entry, toxIdStr;
|
||||||
|
int toxIdSize, idx, verx, dns_string_len;
|
||||||
|
const int dns_string_maxlen = 128;
|
||||||
|
|
||||||
|
void* tox_dns3 = tox_dns3_new(server.pubkey);
|
||||||
|
if (!tox_dns3)
|
||||||
|
{
|
||||||
|
qWarning() << "queryTox3: failed to create a tox_dns3 object for "<<server.name<<", using tox1 as a fallback";
|
||||||
|
goto fallbackOnTox1;
|
||||||
|
}
|
||||||
|
uint32_t request_id;
|
||||||
|
uint8_t dns_string[dns_string_maxlen];
|
||||||
|
dns_string_len = tox_generate_dns3_string(tox_dns3, dns_string, dns_string_maxlen, &request_id,
|
||||||
|
(uint8_t*)nameData.data(), nameData.size());
|
||||||
|
|
||||||
|
if (dns_string_len < 0) // We can always fallback on tox1 if toxdns3 fails
|
||||||
|
{
|
||||||
|
qWarning() << "queryTox3: failed to generate dns3 string for "<<server.name<<", using tox1 as a fallback";
|
||||||
|
goto fallbackOnTox1;
|
||||||
|
}
|
||||||
|
|
||||||
|
realRecord = '_'+QByteArray((char*)dns_string, dns_string_len)+"._tox."+server.name;
|
||||||
|
entry = fetchLastTextRecord(realRecord, false);
|
||||||
|
if (entry.isEmpty())
|
||||||
|
{
|
||||||
|
qWarning() << "queryTox3: Server "<<server.name<<" returned no record, using tox1 as a fallback";
|
||||||
|
goto fallbackOnTox1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check toxdns protocol version
|
||||||
|
verx = entry.indexOf("v=");
|
||||||
|
if (verx!=-1) {
|
||||||
|
verx += 2;
|
||||||
|
int verend = entry.indexOf(';', verx);
|
||||||
|
if (verend!=-1)
|
||||||
|
{
|
||||||
|
QString ver = entry.mid(verx, verend-verx);
|
||||||
|
if (ver != "tox3")
|
||||||
|
{
|
||||||
|
qWarning() << "queryTox3: Server "<<server.name<<" returned a bad version ("<<ver<<"), using tox1 as a fallback";
|
||||||
|
goto fallbackOnTox1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get and decrypt the tox id
|
||||||
|
idx = entry.indexOf("id=");
|
||||||
|
if (idx < 0) {
|
||||||
|
qWarning() << "queryTox3: Server "<<server.name<<" returned an empty id, using tox1 as a fallback";
|
||||||
|
goto fallbackOnTox1;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx += 3;
|
||||||
|
id = entry.mid(idx).toUtf8();
|
||||||
|
uint8_t toxId[TOX_FRIEND_ADDRESS_SIZE];
|
||||||
|
toxIdSize = tox_decrypt_dns3_TXT(tox_dns3, toxId, (uint8_t*)id.data(), id.size(), request_id);
|
||||||
|
if (toxIdSize < 0) // We can always fallback on tox1 if toxdns3 fails
|
||||||
|
{
|
||||||
|
qWarning() << "queryTox3: failed to decrypt dns3 reply for "<<server.name<<", using tox1 as a fallback";
|
||||||
|
goto fallbackOnTox1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tox_dns3_kill(tox_dns3);
|
||||||
|
toxIdStr = CFriendAddress::toString(toxId);
|
||||||
|
emit friendRequested(toxIdStr, getMessage());
|
||||||
|
this->toxId.clear();
|
||||||
|
this->message.clear();
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Centralized error handling, fallback on tox1 queries
|
||||||
|
fallbackOnTox1:
|
||||||
|
if (tox_dns3)
|
||||||
|
tox_dns3_kill(tox_dns3);
|
||||||
|
queryTox1(record);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,24 @@ signals:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onSendTriggered();
|
void onSendTriggered();
|
||||||
void handleDnsLookup();
|
|
||||||
|
private:
|
||||||
|
struct tox3_server
|
||||||
|
{
|
||||||
|
tox3_server()=default;
|
||||||
|
tox3_server(const char* _name, uint8_t _pk[32]):name{_name},pubkey{_pk}{}
|
||||||
|
|
||||||
|
const char* name; ///< Hostname of the server, e.g. toxme.se
|
||||||
|
uint8_t* pubkey; ///< Public key of the tox3 server, usually 256bit long
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void queryTox1(const QString& record); ///< Record should look like user@domain.tld
|
||||||
|
void queryTox3(const tox3_server& server, QString& record); ///< Record should look like user@domain.tld, may fallback on queryTox1
|
||||||
|
/// Try to fetch the first entry of the given TXT record
|
||||||
|
/// Returns an empty object on failure. May block for up to ~3s
|
||||||
|
/// May display message boxes on error if silent if false
|
||||||
|
QByteArray fetchLastTextRecord(const QString& record, bool silent=true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel headLabel, toxIdLabel, messageLabel;
|
QLabel headLabel, toxIdLabel, messageLabel;
|
||||||
|
@ -55,6 +72,7 @@ private:
|
||||||
|
|
||||||
/** will be used for dns discovery if necessary */
|
/** will be used for dns discovery if necessary */
|
||||||
QDnsLookup dns;
|
QDnsLookup dns;
|
||||||
|
static const tox3_server pinnedServers[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ADDFRIENDFORM_H
|
#endif // ADDFRIENDFORM_H
|
||||||
|
|
Loading…
Reference in New Issue
Block a user