Merge branch 'v1.17-dev'

reviewable/pr5962/r5
Anthony Bilinski 2020-01-19 16:16:57 -08:00
commit 49abc996ae
No known key found for this signature in database
GPG Key ID: 2AA8E0DA1B31FB3C
15 changed files with 7 additions and 1318 deletions

View File

@ -375,10 +375,6 @@ set(${PROJECT_NAME}_SOURCES
src/net/bootstrapnodeupdater.h
src/net/avatarbroadcaster.cpp
src/net/avatarbroadcaster.h
src/net/toxme.cpp
src/net/toxme.h
src/net/toxmedata.cpp
src/net/toxmedata.h
src/net/toxuri.cpp
src/net/toxuri.h
src/nexus.cpp

View File

@ -39,7 +39,6 @@ auto_test(core contactid)
auto_test(core toxid)
auto_test(core toxstring)
auto_test(chatlog textformatter)
auto_test(net toxmedata)
auto_test(net bsu)
auto_test(persistence paths)
auto_test(persistence dbschema)

View File

@ -89,7 +89,6 @@ static const QVector<QRegularExpression> URI_WORD_PATTERNS = {
QRegularExpression(QStringLiteral(R"((?<=^|\s)\S*((file|smb)://([\S| ]*)))")),
QRegularExpression(QStringLiteral(R"((?<=^|\s)\S*(tox:[a-zA-Z\d]{76}))")),
QRegularExpression(QStringLiteral(R"((?<=^|\s)\S*(mailto:\S+@\S+\.\S+))")),
QRegularExpression(QStringLiteral(R"((?<=^|\s)\S*(tox:\S+@\S+))")),
QRegularExpression(QStringLiteral(R"((?<=^|\s)\S*(magnet:[?]((xt(.\d)?=urn:)|(mt=)|(kt=)|(tr=)|(dn=)|(xl=)|(xs=)|(as=)|(x.))[\S| ]+))")),
};

View File

@ -1,295 +0,0 @@
/*
Copyright © 2015-2019 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
qTox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "toxme.h"
#include "src/core/core.h"
#include "src/core/toxpk.h"
#include "src/net/toxmedata.h"
#include "src/persistence/settings.h"
#include <ctime>
#include <sodium/crypto_box.h>
#include <sodium/randombytes.h>
#include <string>
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QThread>
#include <QtDebug>
static ToxmeData toxmeData;
/**
* @class Toxme
* @brief This class implements a client for the toxme.se API
*
* @note The class is thread safe
* @note May process events while waiting for blocking calls
*/
QByteArray Toxme::makeJsonRequest(QString url, QString json, QNetworkReply::NetworkError& error)
{
if (error)
return QByteArray();
QNetworkAccessManager netman;
netman.setProxy(Settings::getInstance().getProxy());
QNetworkRequest request{url};
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QNetworkReply* reply = netman.post(request, json.toUtf8());
while (!reply->isFinished()) {
QThread::msleep(1);
qApp->processEvents();
}
QByteArray result = reply->readAll();
delete reply;
return result;
}
QByteArray Toxme::getServerPubkey(QString url, QNetworkReply::NetworkError& error)
{
if (error)
return QByteArray();
// Get key
QNetworkAccessManager netman;
netman.setProxy(Settings::getInstance().getProxy());
QNetworkRequest request{url};
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QNetworkReply* reply = netman.get(request);
while (!reply->isFinished()) {
QThread::msleep(1);
qApp->processEvents();
}
error = reply->error();
if (error) {
qWarning() << "getServerPubkey: A network error occured:" << reply->errorString();
return QByteArray();
}
QString json = reply->readAll();
delete reply;
return toxmeData.parsePublicKey(json);
}
QByteArray Toxme::prepareEncryptedJson(QString url, int action, QString payload)
{
QPair<QByteArray, QByteArray> keypair = Core::getInstance()->getKeypair();
if (keypair.first.isEmpty() || keypair.second.isEmpty()) {
qWarning() << "prepareEncryptedJson: Couldn't get our keypair, aborting";
return QByteArray();
}
QNetworkReply::NetworkError error = QNetworkReply::NoError;
QByteArray key = getServerPubkey(url, error);
if (error != QNetworkReply::NoError)
return QByteArray();
QByteArray nonce(crypto_box_NONCEBYTES, 0);
randombytes((uint8_t*)nonce.data(), crypto_box_NONCEBYTES);
QByteArray payloadData = payload.toUtf8();
const size_t cypherlen = crypto_box_MACBYTES + payloadData.size();
unsigned char* payloadEnc = new unsigned char[cypherlen];
int cryptResult = crypto_box_easy(payloadEnc, (uint8_t*)payloadData.data(), payloadData.size(),
(uint8_t*)nonce.data(), (unsigned char*)key.constData(),
(uint8_t*)keypair.second.data());
if (cryptResult != 0) // error
return QByteArray();
QByteArray payloadEncData(reinterpret_cast<char*>(payloadEnc), cypherlen);
delete[] payloadEnc;
return toxmeData.encryptedJson(action, keypair.first, payloadEncData, nonce).toUtf8();
}
/**
* @brief Converts a toxme address to a Tox ID.
* @param address Toxme address.
* @return Found ToxId (an empty ID on error).
*/
ToxId Toxme::lookup(QString address)
{
// JSON injection ?
address = address.trimmed();
address.replace('\\', "\\\\");
address.replace('"', "\"");
const QString json = toxmeData.lookupRequest(address);
QString apiUrl = "https://" + address.split(QLatin1Char('@')).last() + "/api";
QNetworkReply::NetworkError error = QNetworkReply::NoError;
QString response = makeJsonRequest(apiUrl, json, error);
if (error != QNetworkReply::NoError)
return ToxId();
return toxmeData.lookup(response);
}
/**
* @brief Creates a new toxme address associated with a Tox ID.
* @param[out] code Tox error code @see getErrorMessage.
* @param[in] server Create toxme account on this server.
* @param[in] id ToxId of current user.
* @param[in] address Create toxme account with this adress.
* @param[in] keepPrivate If true, the address will not be published on toxme site.
* @param[in] bio A short optional description of yourself if you want to publish your address.
* @return password on success, else sets code parameter and returns an empty QString.
*/
QString Toxme::createAddress(ToxmeData::ExecCode& code, QString server, ToxId id, QString address,
bool keepPrivate, QString bio)
{
// JSON injection ?
bio.replace('\\', "\\\\");
bio.replace('"', "\"");
address.replace('\\', "\\\\");
address.replace('"', "\"");
bio = bio.trimmed();
address = address.trimmed();
server = server.trimmed();
if (!server.contains("://"))
server = "https://" + server;
const QString payload = toxmeData.createAddressRequest(id, address, bio, keepPrivate);
QString pubkeyUrl = server + "/pk";
QString apiUrl = server + "/api";
QNetworkReply::NetworkError error = QNetworkReply::NoError;
QByteArray encrypted = prepareEncryptedJson(pubkeyUrl, 1, payload);
QByteArray response = makeJsonRequest(apiUrl, encrypted, error);
code = toxmeData.extractCode(response);
if ((code != ToxmeData::Ok && code != ToxmeData::Updated) || error != QNetworkReply::NoError)
return QString();
return toxmeData.getPass(response, code);
}
/**
* @brief Deletes the address associated with your current Tox ID.
* @param server Server to delete the address from.
* @param id ToxId to delete.
* @return Status code returned from server.
*/
ToxmeData::ExecCode Toxme::deleteAddress(QString server, ToxPk pk)
{
const QString payload = toxmeData.deleteAddressRequest(pk);
server = server.trimmed();
if (!server.contains("://"))
server = "https://" + server;
QString pubkeyUrl = server + "/pk";
QString apiUrl = server + "/api";
QNetworkReply::NetworkError error = QNetworkReply::NoError;
QByteArray response = makeJsonRequest(apiUrl, prepareEncryptedJson(pubkeyUrl, 2, payload), error);
return toxmeData.extractCode(response);
}
/**
* @brief Return string of the corresponding error code
* @param errorCode Code to get error message
* @return Source error message
*/
QString Toxme::getErrorMessage(int errorCode)
{
switch (errorCode) {
case ToxmeData::IncorrectResponse:
return "Incorrect response";
case ToxmeData::NoPassword:
return "No password in response";
case ToxmeData::ServerError:
return "Server doesn't support ToxMe";
case -1:
return "You must send POST requests to /api";
case -2:
return "Problem with HTTPS connection";
case -3:
return "Unable to read encrypted payload";
case -4:
return "You're making too many requests. Wait an hour and try again";
case -25:
return "This name is already in use";
case -26:
return "This Tox ID is already registered under another name";
case -27:
return "Please don't use a space in your name";
case -28:
return "Password incorrect";
case -29:
return "You can't use this name";
case -30:
return "Name not found";
case -31:
return "Tox ID not sent";
case -41:
return "Lookup failed because the server replied with invalid data";
case -42:
return "That user does not exist";
case -43:
return "Internal lookup error. Please file a bug report.";
default:
return QString("Unknown error (%1)").arg(errorCode);
}
}
/**
* @brief Return translated error message
* @param errorCode Code to translate
* @return Translated Toxme error message
*/
QString Toxme::translateErrorMessage(int errorCode)
{
switch (errorCode) {
case ToxmeData::ServerError:
return QObject::tr("Server doesn't support ToxMe");
case -2:
return QObject::tr("Problem with HTTPS connection");
case -4:
return QObject::tr("You're making too many requests. Wait an hour and try again");
case -25:
return QObject::tr("This name is already in use");
case -26:
return QObject::tr("This Tox ID is already registered under another name");
case -27:
return QObject::tr("Please don't use a space in your name");
case -28:
return QObject::tr("Password incorrect");
case -29:
return QObject::tr("You can't use this name");
case -30:
return QObject::tr("Name not found");
case -31:
return QObject::tr("Tox ID not sent");
case -42:
return QObject::tr("That user does not exist");
default:
return QObject::tr("Internal ToxMe error");
}
}

View File

@ -1,56 +0,0 @@
/*
Copyright © 2015-2019 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
qTox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOXME_H
#define TOXME_H
#include "src/core/toxid.h"
#include "src/net/toxmedata.h"
#include <QMap>
#include <QMutex>
#include <QNetworkReply>
#include <QString>
#include <memory>
class QNetworkAccessManager;
class Toxme
{
public:
static ToxId lookup(QString address);
static QString createAddress(ToxmeData::ExecCode& code, QString server, ToxId id,
QString address, bool keepPrivate = true, QString bio = QString());
static ToxmeData::ExecCode deleteAddress(QString server, ToxPk id);
static QString getErrorMessage(int errorCode);
static QString translateErrorMessage(int errorCode);
private:
Toxme() = delete;
static QByteArray makeJsonRequest(QString url, QString json, QNetworkReply::NetworkError& error);
static QByteArray prepareEncryptedJson(QString url, int action, QString payload);
static QByteArray getServerPubkey(QString url, QNetworkReply::NetworkError& error);
static ToxmeData::ExecCode extractError(QString json);
private:
static const QMap<QString, QString> pubkeyUrls;
static const QMap<QString, QString> apiUrls;
};
#endif // TOXME_H

View File

@ -1,194 +0,0 @@
/*
Copyright © 2017-2019 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
qTox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "toxmedata.h"
#include "src/core/toxid.h"
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonObject>
#include <QString>
namespace {
namespace consts {
namespace keys {
const QString Key{QStringLiteral("key")};
const QString Action{QStringLiteral("action")};
const QString PublicKey{QStringLiteral("public_key")};
const QString Encrypted{QStringLiteral("encrypted")};
const QString Nonce{QStringLiteral("nonce")};
const QString Name{QStringLiteral("name")};
const QString ToxId{QStringLiteral("tox_id")};
const QString Code{QStringLiteral("c")};
const QString Bio{QStringLiteral("bio")};
const QString Privacy{QStringLiteral("privacy")};
const QString Timestamp{QStringLiteral("timestamp")};
const QString Password{QStringLiteral("password")};
}
}
}
static qint64 getCurrentTime()
{
return QDateTime::currentDateTimeUtc().toMSecsSinceEpoch() / 1000;
}
/**
* @brief Get server public key from Json.
* @param text Json text.
* @return Server public key.
*/
QByteArray ToxmeData::parsePublicKey(const QString& text) const
{
const QJsonObject json = QJsonDocument::fromJson(text.toLatin1()).object();
const QString& key = json[consts::keys::Key].toString();
return QByteArray::fromHex(key.toLatin1());
}
/**
* @brief Build Json with encrypted payload.
* @param action Action number.
* @param pk User public key
* @param encrypted Encrypted payload.
* @param nonce Crypto nonce.
* @return Json with action and encrypted payload.
*/
QString ToxmeData::encryptedJson(int action, const QByteArray& pk, const QByteArray& encrypted,
const QByteArray& nonce) const
{
const QJsonObject json = {
{ consts::keys::Action, action },
{ consts::keys::PublicKey, QString{pk.toHex()} },
{ consts::keys::Encrypted, QString{encrypted.toBase64()} },
{ consts::keys::Nonce, QString{nonce.toBase64()} },
};
return QJsonDocument{json}.toJson(QJsonDocument::Compact);
}
/**
* @brief Build lookup request Json.
* @param address Address to lookup.
* @return Json to lookup.
*/
QString ToxmeData::lookupRequest(const QString& address) const
{
const QJsonObject json = {
{ consts::keys::Action, 3 },
{ consts::keys::Name, address },
};
return QJsonDocument{json}.toJson(QJsonDocument::Compact);
}
/**
* @brief Extract ToxId from lookup Json.
* @param inText Json text.
* @return User ToxId.
*/
ToxId ToxmeData::lookup(const QString& inText) const
{
const QJsonObject json = QJsonDocument::fromJson(inText.toLatin1()).object();
const QString& text = json[consts::keys::ToxId].toString();
return ToxId{text};
}
/**
* @brief Extract toxme result code.
* @param srcJson Json text.
* @return Toxme code result.
*/
ToxmeData::ExecCode ToxmeData::extractCode(const QString& srcJson) const
{
const QJsonObject json = QJsonDocument::fromJson(srcJson.toLatin1()).object();
if (json.isEmpty()) {
return ServerError;
}
const int code = json[consts::keys::Code].toInt(INT32_MAX);
if (code == INT32_MAX) {
return IncorrectResponse;
}
return ExecCode(code);
}
/**
* @brief Build create address request Json.
* @param id Self ToxId.
* @param address Preferred address.
* @param bio Self biography.
* @param keepPrivate If true, the address will not be published on toxme site.
* @return Json to register Toxme address.
*/
QString ToxmeData::createAddressRequest(const ToxId id, const QString& address, const QString& bio,
bool keepPrivate) const
{
const QJsonObject json = {
{ consts::keys::Bio, bio },
{ consts::keys::Name, address },
{ consts::keys::ToxId, id.toString() },
{ consts::keys::Privacy, keepPrivate ? 0 : 2 },
{ consts::keys::Timestamp, getCurrentTime() },
};
return QJsonDocument{json}.toJson(QJsonDocument::Compact);
}
/**
* @brief Extrace password from Json answer.
* @param srcJson[in] Json text.
* @param code[out] Result code. Changed if password not extracted.
* @return Extracted password.
*/
QString ToxmeData::getPass(const QString& srcJson, ToxmeData::ExecCode& code)
{
const QJsonObject json = QJsonDocument::fromJson(srcJson.toLatin1()).object();
if (json.isEmpty()) {
code = ToxmeData::NoPassword;
return QString{};
}
const QJsonValue pass = json[consts::keys::Password];
if (pass.isNull()) {
code = ToxmeData::Updated;
return QString{};
}
if (!pass.isString()) {
code = ToxmeData::IncorrectResponse;
return QString{};
}
return pass.toString();
}
/**
* @brief Build Json to delete address.
* @param pk Self public key.
* @return Json to delete address.
*/
QString ToxmeData::deleteAddressRequest(const ToxPk& pk)
{
QJsonObject json = {
{ consts::keys::PublicKey, pk.toString() },
{ consts::keys::Timestamp, getCurrentTime() },
};
return QJsonDocument{json}.toJson(QJsonDocument::Compact);
}

View File

@ -1,55 +0,0 @@
/*
Copyright © 2017-2019 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
qTox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOXME_DATA_H
#define TOXME_DATA_H
#include <QByteArray>
#include "src/core/toxid.h"
class QString;
class ToxmeData
{
public:
enum ExecCode
{
ExecError = -50,
Ok = 0,
Updated = 1,
ServerError = 2,
IncorrectResponse = 3,
NoPassword = 4
};
QByteArray parsePublicKey(const QString& text) const;
QString encryptedJson(int action, const QByteArray& pk, const QByteArray& encrypted,
const QByteArray& nonce) const;
QString lookupRequest(const QString& address) const;
ToxId lookup(const QString& text) const;
ExecCode extractCode(const QString& json) const;
QString createAddressRequest(const ToxId id, const QString& address, const QString& bio,
bool keepPrivate) const;
QString getPass(const QString& json, ToxmeData::ExecCode& code);
QString deleteAddressRequest(const ToxPk& pk);
};
#endif // TOXME_DATA_H

View File

@ -19,7 +19,6 @@
#include "src/net/toxuri.h"
#include "src/core/core.h"
#include "src/net/toxme.h"
#include "src/nexus.h"
#include "src/widget/gui.h"
#include "src/widget/tool/friendrequestdialog.h"
@ -66,10 +65,7 @@ bool handleToxURI(const QString& toxURI)
ToxId toxId(toxaddr);
QString error = QString();
if (!toxId.isValid()) {
toxId = Toxme::lookup(toxaddr);
if (!toxId.isValid()) {
error = QMessageBox::tr("%1 is not a valid ToxMe address.").arg(toxaddr);
}
error = QMessageBox::tr("%1 is not a valid Tox address.").arg(toxaddr);
} else if (toxId == core->getSelfId()) {
error = QMessageBox::tr("You can't add yourself as a friend!",
"When trying to add your own Tox ID as friend");

View File

@ -53,9 +53,6 @@
* @warning Don't use it to save every single thing you want to save, use it
* for some general purpose widgets, such as MainWindows or Splitters,
* which have widget->saveX() and widget->loadX() methods.
*
* @var QString Settings::toxmeInfo
* @brief Toxme info like name@server
*/
const QString Settings::globalSettingsFile = "qtox.ini";
@ -581,15 +578,6 @@ void Settings::loadPersonal(QString profileName, const ToxEncrypt* passKey)
ps.endArray();
}
ps.endGroup();
ps.beginGroup("Toxme");
{
toxmeInfo = ps.value("info", "").toString();
toxmeBio = ps.value("bio", "").toString();
toxmePriv = ps.value("priv", false).toBool();
toxmePass = ps.value("pass", "").toString();
}
ps.endGroup();
}
void Settings::resetToDefault()
@ -851,16 +839,6 @@ void Settings::savePersonal(QString profileName, const ToxEncrypt* passkey)
ps.setValue("blackList", blackList.join('\n'));
}
ps.endGroup();
ps.beginGroup("Toxme");
{
ps.setValue("info", toxmeInfo);
ps.setValue("bio", toxmeBio);
ps.setValue("priv", toxmePriv);
ps.setValue("pass", toxmePass);
}
ps.endGroup();
ps.save();
}
@ -1276,93 +1254,6 @@ void Settings::setTranslation(const QString& newValue)
}
}
void Settings::deleteToxme()
{
setToxmeInfo("");
setToxmeBio("");
setToxmePriv(false);
setToxmePass("");
}
void Settings::setToxme(QString name, QString server, QString bio, bool priv, QString pass)
{
setToxmeInfo(name + "@" + server);
setToxmeBio(bio);
setToxmePriv(priv);
if (!pass.isEmpty())
setToxmePass(pass);
}
QString Settings::getToxmeInfo() const
{
QMutexLocker locker{&bigLock};
return toxmeInfo;
}
void Settings::setToxmeInfo(const QString& info)
{
QMutexLocker locker{&bigLock};
if (info != toxmeInfo) {
if (info.split("@").size() == 2) {
toxmeInfo = info;
emit toxmeInfoChanged(toxmeInfo);
} else {
qWarning() << info << "is not a valid toxme string -> value ignored.";
}
}
}
QString Settings::getToxmeBio() const
{
QMutexLocker locker{&bigLock};
return toxmeBio;
}
void Settings::setToxmeBio(const QString& bio)
{
QMutexLocker locker{&bigLock};
if (bio != toxmeBio) {
toxmeBio = bio;
emit toxmeBioChanged(toxmeBio);
}
}
bool Settings::getToxmePriv() const
{
QMutexLocker locker{&bigLock};
return toxmePriv;
}
void Settings::setToxmePriv(bool priv)
{
QMutexLocker locker{&bigLock};
if (priv != toxmePriv) {
toxmePriv = priv;
emit toxmePrivChanged(toxmePriv);
}
}
QString Settings::getToxmePass() const
{
QMutexLocker locker{&bigLock};
return toxmePass;
}
void Settings::setToxmePass(const QString& pass)
{
QMutexLocker locker{&bigLock};
if (pass != toxmePass) {
toxmePass = pass;
// password is not exposed for security reasons
emit toxmePassChanged();
}
}
bool Settings::getForceTCP() const
{
QMutexLocker locker{&bigLock};

View File

@ -190,10 +190,6 @@ signals:
void notifyHideChanged(bool enabled);
void groupAlwaysNotifyChanged(bool enabled);
void translationChanged(const QString& translation);
void toxmeInfoChanged(const QString& info);
void toxmeBioChanged(const QString& bio);
void toxmePrivChanged(bool priv);
void toxmePassChanged();
void currentProfileIdChanged(quint32 id);
void enableLoggingChanged(bool enabled);
void autoAwayTimeChanged(int minutes);
@ -276,21 +272,6 @@ public:
QString getTranslation() const;
void setTranslation(const QString& newValue);
// Toxme
void deleteToxme();
void setToxme(QString name, QString server, QString bio, bool priv, QString pass = "");
QString getToxmeInfo() const;
void setToxmeInfo(const QString& info);
QString getToxmeBio() const;
void setToxmeBio(const QString& bio);
bool getToxmePriv() const;
void setToxmePriv(bool priv);
QString getToxmePass() const;
void setToxmePass(const QString& pass);
void setAutoSaveEnabled(bool newValue);
bool getAutoSaveEnabled() const;
@ -642,12 +623,6 @@ private:
QString currentProfile;
uint32_t currentProfileId;
// Toxme Info
QString toxmeInfo;
QString toxmeBio;
bool toxmePriv;
QString toxmePass;
bool enableLogging;
int autoAwayTime;

View File

@ -19,7 +19,6 @@
#include "addfriendform.h"
#include "src/core/core.h"
#include "src/net/toxme.h"
#include "src/nexus.h"
#include "src/persistence/settings.h"
#include "src/widget/contentlayout.h"
@ -53,8 +52,7 @@ namespace
bool checkIsValidId(const QString& id)
{
static const QRegularExpression dnsIdExpression("^\\S+@\\S+$");
return ToxId::isToxId(id) || id.contains(dnsIdExpression);
return ToxId::isToxId(id);
}
}
@ -112,7 +110,7 @@ AddFriendForm::AddFriendForm()
// accessibility stuff
toxIdLabel.setAccessibleDescription(
tr("Tox ID, either 76 hexadecimal characters or name@example.com"));
tr("Tox ID, 76 hexadecimal characters"));
toxId.setAccessibleDescription(tr("Type in Tox ID of your friend"));
messageLabel.setAccessibleDescription(tr("Friend request message"));
message.setAccessibleDescription(tr(
@ -202,12 +200,9 @@ void AddFriendForm::addFriend(const QString& idText)
ToxId friendId(idText);
if (!friendId.isValid()) {
friendId = Toxme::lookup(idText); // Try Toxme
if (!friendId.isValid()) {
GUI::showWarning(tr("Couldn't add friend"),
tr("%1 Tox ID is invalid or does not exist", "Toxme error").arg(idText));
return;
}
GUI::showWarning(tr("Couldn't add friend"),
tr("%1 Tox ID is invalid", "Tox address error").arg(idText));
return;
}
deleteFriendRequest(friendId);
@ -289,7 +284,7 @@ void AddFriendForm::onIdChanged(const QString& id)
//: Tox ID of the person you're sending a friend request to
const QString toxIdText(tr("Tox ID"));
//: Tox ID format description
const QString toxIdComment(tr("either 76 hexadecimal characters or name@example.com"));
const QString toxIdComment(tr("76 hexadecimal characters"));
const QString labelText =
isValidId ? QStringLiteral("%1 (%2)") : QStringLiteral("%1 <font color='red'>(%2)</font>");

View File

@ -21,7 +21,6 @@
#include "ui_profileform.h"
#include "src/core/core.h"
#include "src/model/profile/iprofileinfo.h"
#include "src/net/toxme.h"
#include "src/persistence/profile.h"
#include "src/persistence/profilelocker.h"
#include "src/persistence/settings.h"
@ -120,22 +119,8 @@ ProfileForm::ProfileForm(IProfileInfo* profileInfo, QWidget* parent)
delete toxIdGroup->replaceWidget(bodyUI->toxId, toxId); // Original toxId is in heap, delete it
bodyUI->toxId->hide();
/* Toxme section init */
bodyUI->toxmeServersList->addItem("toxme.io");
QString toxmeInfo = Settings::getInstance().getToxmeInfo();
// User not registered
if (toxmeInfo.isEmpty()) {
showRegisterToxme();
} else {
showExistingToxme();
}
bodyUI->qrLabel->setWordWrap(true);
QRegExp re("[^@ ]+");
QRegExpValidator* validator = new QRegExpValidator(re, this);
bodyUI->toxmeUsername->setValidator(validator);
profilePicture = new MaskablePixmapWidget(this, QSize(64, 64), ":/img/avatar_mask.svg");
profilePicture->setPixmap(QPixmap(":/img/contact_dark.svg"));
profilePicture->setContextMenuPolicy(Qt::CustomContextMenu);
@ -180,10 +165,6 @@ ProfileForm::ProfileForm(IProfileInfo* profileInfo, QWidget* parent)
this, &ProfileForm::setPasswordButtonsText);
connect(bodyUI->saveQr, &QPushButton::clicked, this, &ProfileForm::onSaveQrClicked);
connect(bodyUI->copyQr, &QPushButton::clicked, this, &ProfileForm::onCopyQrClicked);
connect(bodyUI->toxmeRegisterButton, &QPushButton::clicked,
this, &ProfileForm::onRegisterButtonClicked);
connect(bodyUI->toxmeUpdateButton, &QPushButton::clicked,
this, &ProfileForm::onRegisterButtonClicked);
connect(profileInfo, &IProfileInfo::usernameChanged, this,
[=](const QString& val) { bodyUI->userName->setText(val); });
@ -485,90 +466,3 @@ void ProfileForm::retranslateUi()
"Share it with your friends to begin chatting.\n\n"
"This ID includes the NoSpam code (in blue), and the checksum (in gray)."));
}
void ProfileForm::showRegisterToxme()
{
bodyUI->toxmeUsername->setText("");
bodyUI->toxmeBio->setText("");
bodyUI->toxmePrivacy->setChecked(false);
bodyUI->toxmeRegisterButton->show();
bodyUI->toxmeUpdateButton->hide();
bodyUI->toxmePassword->hide();
bodyUI->toxmePasswordLabel->hide();
}
void ProfileForm::showExistingToxme()
{
QStringList info = Settings::getInstance().getToxmeInfo().split("@");
bodyUI->toxmeUsername->setText(info[0]);
bodyUI->toxmeServersList->addItem(info[1]);
QString bio = Settings::getInstance().getToxmeBio();
bodyUI->toxmeBio->setText(bio);
bool priv = Settings::getInstance().getToxmePriv();
bodyUI->toxmePrivacy->setChecked(priv);
QString pass = Settings::getInstance().getToxmePass();
bodyUI->toxmePassword->setText(pass);
bodyUI->toxmePassword->show();
bodyUI->toxmePasswordLabel->show();
bodyUI->toxmeRegisterButton->hide();
bodyUI->toxmeUpdateButton->show();
}
void ProfileForm::onRegisterButtonClicked()
{
QString name = bodyUI->toxmeUsername->text();
if (name.isEmpty()) {
return;
}
bodyUI->toxmeRegisterButton->setEnabled(false);
bodyUI->toxmeUpdateButton->setEnabled(false);
bodyUI->toxmeRegisterButton->setText(tr("Register (processing)"));
bodyUI->toxmeUpdateButton->setText(tr("Update (processing)"));
QString id = toxId->text();
id.remove(QRegularExpression("<[^>]*>"));
QString bio = bodyUI->toxmeBio->text();
QString server = bodyUI->toxmeServersList->currentText();
bool privacy = bodyUI->toxmePrivacy->isChecked();
Core* oldCore = Core::getInstance();
ToxmeData::ExecCode code = ToxmeData::ExecCode::Ok;
QString response = Toxme::createAddress(code, server, ToxId(id), name, privacy, bio);
Core* newCore = Core::getInstance();
// Make sure the user didn't logout (or logout and login)
// before the request is finished, else qTox will crash.
if (oldCore == newCore) {
switch (code) {
case ToxmeData::Updated:
GUI::showInfo(tr("Done!"), tr("Account %1@%2 updated successfully").arg(name, server));
Settings::getInstance().setToxme(name, server, bio, privacy);
showExistingToxme();
break;
case ToxmeData::Ok:
GUI::showInfo(tr("Done!"),
tr("Successfully added %1@%2 to the database. Save your password.")
.arg(name, server));
Settings::getInstance().setToxme(name, server, bio, privacy, response);
showExistingToxme();
break;
default:
QString errorMessage = Toxme::getErrorMessage(code);
qWarning() << errorMessage;
QString translated = Toxme::translateErrorMessage(code);
GUI::showWarning(tr("Toxme error"), translated);
}
bodyUI->toxmeRegisterButton->setEnabled(true);
bodyUI->toxmeUpdateButton->setEnabled(true);
bodyUI->toxmeRegisterButton->setText(tr("Register"));
bodyUI->toxmeUpdateButton->setText(tr("Update"));
}
}

View File

@ -77,15 +77,12 @@ private slots:
void onChangePassClicked();
void onAvatarClicked();
void showProfilePictureContextMenu(const QPoint& point);
void onRegisterButtonClicked();
private:
void showExistingToxme();
void retranslateUi();
void prFileLabelUpdate();
bool eventFilter(QObject* object, QEvent* event);
void refreshProfiles();
void showRegisterToxme();
static QString getSupportedImageFilter();
private:

View File

@ -264,163 +264,6 @@ Share it with your friends to begin chatting.</string>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="horizontalGroupBox">
<property name="title">
<string>Register on ToxMe</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="toxmeUsernameLabel">
<property name="text">
<string>My username</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="toxmeUsername">
<property name="toolTip">
<string comment="Tooltip for the `Username` ToxMe field.">Name for the ToxMe service.</string>
</property>
<property name="accessibleDescription">
<string>ToxMe username to be shown on ToxMe</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="toxmeBioLabel">
<property name="toolTip">
<string comment="Tooltip for the Biography text.">Optional. Something about you. Or your cat.</string>
</property>
<property name="text">
<string>My biography</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="toxmeBio">
<property name="toolTip">
<string comment="Tooltip for the Biography field.">Optional. Something about you. Or your cat.</string>
</property>
<property name="accessibleDescription">
<string>Optional ToxMe biography to be shown on ToxMe</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="toxmeServerLabel">
<property name="toolTip">
<string>ToxMe service to register on.</string>
</property>
<property name="text">
<string>Server</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="toxmeServersList">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>ToxMe service to register on.</string>
</property>
<property name="accessibleDescription">
<string>ToxMe service address</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="toxmePrivacy">
<property name="toolTip">
<string comment="Tooltip for the `Hide my name from public list` ToxMe checkbox.">If not set, ToxMe entries are publicly visible.</string>
</property>
<property name="accessibleDescription">
<string>Visibility on the ToxMe service</string>
</property>
<property name="text">
<string>Hide my name from the public list</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="toxmeRegisterButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="accessibleDescription">
<string>Register on ToxMe</string>
</property>
<property name="text">
<string>Register</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="toxmePasswordLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Your password</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="toxmePassword">
<property name="accessibleDescription">
<string>Password</string>
</property>
<property name="frame">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="6" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QPushButton" name="toxmeUpdateButton">
<property name="accessibleDescription">
<string>Update ToxMe entry</string>
</property>
<property name="text">
<string>Update</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="QGroupBox" name="profilesGroup">
<property name="title">
@ -618,13 +461,6 @@ Profile does not contain your history.</string>
<tabstop>toxId</tabstop>
<tabstop>saveQr</tabstop>
<tabstop>copyQr</tabstop>
<tabstop>toxmeUsername</tabstop>
<tabstop>toxmeBio</tabstop>
<tabstop>toxmeServersList</tabstop>
<tabstop>toxmePrivacy</tabstop>
<tabstop>toxmeRegisterButton</tabstop>
<tabstop>toxmeUpdateButton</tabstop>
<tabstop>toxmePassword</tabstop>
<tabstop>renameButton</tabstop>
<tabstop>deleteButton</tabstop>
<tabstop>exportButton</tabstop>

View File

@ -1,289 +0,0 @@
/*
Copyright © 2017-2019 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
qTox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "src/net/toxmedata.h"
#include <ctime>
#include <QtTest/QtTest>
#include <QString>
#include <QJsonDocument>
#include <QJsonObject>
const QByteArray testToxId =
QByteArrayLiteral("\xC7\x71\x9C\x68\x08\xC1\x4B\x77\x34\x80\x04\x95\x6D\x1D\x98\x04"
"\x6C\xE0\x9A\x34\x37\x0E\x76\x08\x15\x0E\xAD\x74\xC3\x81\x5D\x30"
"\xC8\xBA\x3A\xB9\xBE\xB9");
const QByteArray testPublicKey =
QByteArrayLiteral("\xC7\x71\x9C\x68\x08\xC1\x4B\x77\x34\x80\x04\x95\x6D\x1D\x98\x04"
"\x6C\xE0\x9A\x34\x37\x0E\x76\x08\x15\x0E\xAD\x74\xC3\x81\x5D\x30");
class TestToxmeData : public QObject
{
Q_OBJECT
private slots:
void parsePublicKeyTest();
void encryptedJsonTest();
void lookupRequestTest();
void lookup_data();
void lookup();
void extractCode_data();
void extractCode();
void createAddressRequest();
void getPassTest_data();
void getPassTest();
void deleteAddressRequestTest();
};
/**
* @brief Test if parse public key works correctly.
*/
void TestToxmeData::parsePublicKeyTest()
{
ToxmeData data;
QString publicKeyStr = testPublicKey.toHex();
QString json = QStringLiteral(R"({"key": "%1"})").arg(publicKeyStr);
QByteArray result = data.parsePublicKey(json);
QCOMPARE(result, testPublicKey);
json = QStringLiteral("Some wrong string");
result = data.parsePublicKey(json);
QVERIFY(result.isEmpty());
}
/**
* @brief Test if generation action json with encrypted payload is correct.
*/
void TestToxmeData::encryptedJsonTest()
{
ToxmeData data;
int action = 123;
QByteArray encrypted{QStringLiteral("sometext").toLatin1()};
QByteArray nonce{QStringLiteral("nonce").toLatin1()};
QString text = data.encryptedJson(action, testPublicKey, encrypted, nonce);
QJsonObject json = QJsonDocument::fromJson(text.toLatin1()).object();
int actionRes = json["action"].toInt();
QCOMPARE(actionRes, 123);
QByteArray pkRes = QByteArray::fromHex(json["public_key"].toString().toLatin1());
QCOMPARE(pkRes, testPublicKey);
QByteArray encRes = QByteArray::fromBase64(json["encrypted"].toString().toLatin1());
QCOMPARE(encRes, encrypted);
QByteArray nonceRes = QByteArray::fromBase64(json["nonce"].toString().toLatin1());
QCOMPARE(nonceRes, nonce);
}
/**
* @brief Test if request for lookup generated correctly.
*/
void TestToxmeData::lookupRequestTest()
{
ToxmeData data;
QString json = QStringLiteral(R"({"action":3,"name":"testname"})");
QString result = data.lookupRequest("testname");
QCOMPARE(result, json);
}
Q_DECLARE_METATYPE(ToxId)
/**
* @brief Data function for lookup test.
*/
void TestToxmeData::lookup_data()
{
qRegisterMetaType<ToxId>("ToxId");
QTest::addColumn<QString>("input", nullptr);
QTest::addColumn<ToxId>("result", nullptr);
QString sToxId = testToxId.toHex();
QTest::newRow("Valid ToxId") << QStringLiteral(R"({"tox_id": "%1"})").arg(sToxId)
<< ToxId(testToxId);
QTest::newRow("Invalid ToxId") << QStringLiteral(R"({"tox_id": "SomeTextHere"})")
<< ToxId{};
QTest::newRow("Not json") << QStringLiteral("Not json string")
<< ToxId{};
}
/**
* @brief Test if ToxId parsed from lookup response correcly.
*/
void TestToxmeData::lookup()
{
QFETCH(QString, input);
QFETCH(ToxId, result);
ToxmeData data;
ToxId toxId = data.lookup(input);
QCOMPARE(result, toxId);
}
Q_DECLARE_METATYPE(ToxmeData::ExecCode)
/**
* @brief Data function for extractCode test.
*/
void TestToxmeData::extractCode_data()
{
qRegisterMetaType<ToxmeData::ExecCode>("ToxmeData::ExecCode");
QTest::addColumn<QString>("input", nullptr);
QTest::addColumn<ToxmeData::ExecCode>("result", nullptr);
QTest::newRow("Custom code") << QStringLiteral(R"({"c": 123})")
<< ToxmeData::ExecCode(123);
QTest::newRow("Ok code") << QStringLiteral(R"({"c": 0})")
<< ToxmeData::ExecCode::Ok;
QTest::newRow("String code") << QStringLiteral(R"({"c": "string here"})")
<< ToxmeData::ExecCode::IncorrectResponse;
QTest::newRow("Invalid code") << QStringLiteral(R"({"c": text})")
<< ToxmeData::ExecCode::ServerError;
QTest::newRow("Not json") << QStringLiteral("Not json string")
<< ToxmeData::ExecCode::ServerError;
}
/**
* @brief Test if exec code extracts correctly.
*/
void TestToxmeData::extractCode()
{
QFETCH(QString, input);
QFETCH(ToxmeData::ExecCode, result);
ToxmeData data;
ToxmeData::ExecCode code = data.extractCode(input);
QCOMPARE(result, code);
}
/**
* @brief Test if request for address creation is correct.
*/
void TestToxmeData::createAddressRequest()
{
ToxmeData data;
ToxId id{testToxId};
QString name{"Test address"};
QString bio{"Bio text"};
bool keepPrivate = true;
int timestamp = static_cast<int>(time(nullptr));
QString text = data.createAddressRequest(id, name, bio, keepPrivate);
QJsonObject json = QJsonDocument::fromJson(text.toLatin1()).object();
QByteArray toxIdData = QByteArray::fromHex(json["tox_id"].toString().toLatin1());
ToxId toxIdRes{toxIdData};
QCOMPARE(toxIdRes, id);
QString nameRes = json["name"].toString();
QCOMPARE(nameRes, name);
bool privRes = json["privacy"].toInt();
QCOMPARE(privRes, privRes);
QString bioRes = json["bio"].toString();
QCOMPARE(bioRes, bio);
int timeRes = json["timestamp"].toInt();
// Test will be failed if `createAddressRequest` will take more
// than 100 seconds
QVERIFY(qAbs(timeRes - timestamp) < 100);
}
/**
* @brief Data function for getPassTest.
*/
void TestToxmeData::getPassTest_data()
{
qRegisterMetaType<ToxmeData::ExecCode>("ToxmeData::ExecCode");
QTest::addColumn<QString>("input", nullptr);
QTest::addColumn<QString>("result", nullptr);
QTest::addColumn<ToxmeData::ExecCode>("code", nullptr);
QTest::newRow("Valid password") << QStringLiteral(R"({"password": "123qwe"})")
<< QStringLiteral("123qwe")
<< ToxmeData::ExecCode::Ok;
QTest::newRow("Null password") << QStringLiteral(R"({"password": null})")
<< QStringLiteral("")
<< ToxmeData::ExecCode::Updated;
QTest::newRow("Valid password with null") << QStringLiteral(R"({"password": "null"})")
<< QStringLiteral("null")
<< ToxmeData::ExecCode::Ok;
// ERROR: password value with invalid text, but started with 'null' interpreted as Update
#if 0
QTest::newRow("Invalid null password") << QStringLiteral(R"({"password": nulla})")
<< QStringLiteral("")
<< ToxmeData::ExecCode::IncorrectResponse;
#endif
QTest::newRow("Invalid int password") << QStringLiteral(R"({"password": 123})")
<< QStringLiteral("")
<< ToxmeData::ExecCode::IncorrectResponse;
QTest::newRow("Not json") << QStringLiteral("Not json")
<< QStringLiteral("")
<< ToxmeData::ExecCode::NoPassword;
}
/**
* @brief Test if password extraction is correct.
*/
void TestToxmeData::getPassTest()
{
QFETCH(QString, input);
QFETCH(QString, result);
QFETCH(ToxmeData::ExecCode, code);
ToxmeData data;
ToxmeData::ExecCode resCode = ToxmeData::ExecCode::Ok;
QString password = data.getPass(input, resCode);
QCOMPARE(password, result);
QCOMPARE(resCode, code);
}
/**
* @brief Test if request for address deletation generated correct.
*/
void TestToxmeData::deleteAddressRequestTest()
{
ToxmeData data;
ToxPk pk{testPublicKey};
int timestamp = static_cast<int>(time(nullptr));
QString text = data.deleteAddressRequest(pk);
QJsonObject json = QJsonDocument::fromJson(text.toLatin1()).object();
QByteArray pkRes = QByteArray::fromHex(json["public_key"].toString().toLatin1());
QCOMPARE(pkRes, testPublicKey);
int timeRes = json["timestamp"].toInt();
// Test will be failed if `deleteAddressRequest` will take more
// than 100 seconds
QVERIFY(qAbs(timeRes - timestamp) < 100);
}
QTEST_GUILESS_MAIN(TestToxmeData)
#include "toxmedata_test.moc"