1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

refactor(toxme): Move json generation to ToxmeData class

This commit is contained in:
Diadlo 2017-10-08 10:17:59 +03:00
parent e98297134a
commit 9a543548e0
No known key found for this signature in database
GPG Key ID: 5AF9F2E29107C727
6 changed files with 257 additions and 152 deletions

View File

@ -273,6 +273,8 @@ set(${PROJECT_NAME}_SOURCES
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

@ -19,16 +19,22 @@
#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>
#include <ctime>
#include <sodium/crypto_box.h>
#include <sodium/randombytes.h>
#include <src/persistence/settings.h>
#include <string>
static ToxmeData toxmeData;
/**
* @class Toxme
@ -82,25 +88,9 @@ QByteArray Toxme::getServerPubkey(QString url, QNetworkReply::NetworkError& erro
return QByteArray();
}
// Extract key
static const QByteArray pattern{"key\":\""};
QString json = reply->readAll();
delete reply;
json = json.remove(' ');
int start = json.indexOf(pattern) + pattern.length();
int end = json.indexOf("\"", start);
int pubkeySize = (end - start) / 2;
QString rawKey = json.mid(start, pubkeySize * 2);
QByteArray key;
// I think, exist more easy way to convert key to ByteArray
for (int i = 0; i < pubkeySize; ++i) {
QString byte = rawKey.mid(i * 2, 2);
key[i] = byte.toInt(nullptr, 16);
}
return key;
return toxmeData.parsePublicKey(json);
}
QByteArray Toxme::prepareEncryptedJson(QString url, int action, QString payload)
@ -133,14 +123,7 @@ QByteArray Toxme::prepareEncryptedJson(QString url, int action, QString payload)
QByteArray payloadEncData(reinterpret_cast<char*>(payloadEnc), cypherlen);
delete[] payloadEnc;
const QString json{"{\"action\":" + QString().setNum(action) + ","
"\"public_key\":\""
+ keypair.first.toHex() + "\","
"\"encrypted\":\""
+ payloadEncData.toBase64() + "\","
"\"nonce\":\""
+ nonce.toBase64() + "\"}"};
return json.toUtf8();
return toxmeData.encryptedJson(action, keypair.first, payloadEncData, nonce).toUtf8();
}
/**
@ -155,64 +138,16 @@ ToxId Toxme::lookup(QString address)
address.replace('\\', "\\\\");
address.replace('"', "\"");
const QString json{"{\"action\":3,\"name\":\"" + address + "\"}"};
const QString json = toxmeData.lookupRequest(address);
QString apiUrl = "https://" + address.split(QLatin1Char('@')).last() + "/api";
QNetworkReply::NetworkError error = QNetworkReply::NoError;
QByteArray response = makeJsonRequest(apiUrl, json, error);
QString response = makeJsonRequest(apiUrl, json, error);
if (error != QNetworkReply::NoError)
return ToxId();
static const QByteArray pattern{"tox_id\""};
const int index = response.indexOf(pattern);
if (index == -1)
return ToxId();
response = response.mid(index + pattern.size());
const int idStart = response.indexOf('"');
if (idStart == -1)
return ToxId();
response = response.mid(idStart + 1);
const int idEnd = response.indexOf('"');
if (idEnd == -1)
return ToxId();
response.truncate(idEnd);
return ToxId(QString(response));
}
Toxme::ExecCode Toxme::extractError(QString json)
{
static const QByteArray pattern{"c\":"};
if (json.isEmpty())
return ServerError;
json = json.remove(' ');
const int start = json.indexOf(pattern);
if (start == -1)
return ServerError;
json = json.mid(start + pattern.size());
int end = json.indexOf(",");
if (end == -1) {
end = json.indexOf("}");
if (end == -1)
return IncorrectResponse;
}
json.truncate(end);
bool ok;
int r = json.toInt(&ok);
if (!ok)
return IncorrectResponse;
return ExecCode(r);
return toxmeData.lookup(response);
}
/**
@ -225,10 +160,9 @@ Toxme::ExecCode Toxme::extractError(QString json)
* @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(ExecCode& code, QString server, ToxId id, QString address,
QString Toxme::createAddress(ToxmeData::ExecCode& code, QString server, ToxId id, QString address,
bool keepPrivate, QString bio)
{
int privacy = keepPrivate ? 0 : 2;
// JSON injection ?
bio.replace('\\', "\\\\");
bio.replace('"', "\"");
@ -242,56 +176,18 @@ QString Toxme::createAddress(ExecCode& code, QString server, ToxId id, QString a
if (!server.contains("://"))
server = "https://" + server;
const QString payload{"{\"tox_id\":\"" + id.toString() + "\","
"\"name\":\""
+ address + "\","
"\"privacy\":"
+ QString().setNum(privacy) + ","
"\"bio\":\""
+ bio + "\","
"\"timestamp\":"
+ QString().setNum(time(0)) + "}"};
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 = extractError(response);
if ((code != Ok && code != Updated) || error != QNetworkReply::NoError)
code = toxmeData.extractCode(response);
if ((code != ToxmeData::Ok && code != ToxmeData::Updated) || error != QNetworkReply::NoError)
return QString();
return getPass(response, code);
}
QString Toxme::getPass(QString json, ExecCode& code)
{
static const QByteArray pattern{"password\":"};
json = json.remove(' ');
const int start = json.indexOf(pattern);
if (start == -1) {
code = NoPassword;
return QString();
}
json = json.mid(start + pattern.size());
if (json.startsWith("null")) {
code = Updated;
return QString();
}
json = json.mid(1, json.length());
int end = json.indexOf("\"");
if (end == -1) {
code = IncorrectResponse;
return QString();
}
json.truncate(end);
return json;
return toxmeData.getPass(response, code);
}
/**
@ -300,11 +196,9 @@ QString Toxme::getPass(QString json, ExecCode& code)
* @param id ToxId to delete.
* @return Status code returned from server.
*/
Toxme::ExecCode Toxme::deleteAddress(QString server, ToxPk id)
ToxmeData::ExecCode Toxme::deleteAddress(QString server, ToxPk pk)
{
const QString payload{"{\"public_key\":\"" + id.toString() + "\","
"\"timestamp\":"
+ QString().setNum(time(0)) + "}"};
const QString payload = toxmeData.deleteAddressRequest(pk);
server = server.trimmed();
if (!server.contains("://"))
@ -315,7 +209,7 @@ Toxme::ExecCode Toxme::deleteAddress(QString server, ToxPk id)
QNetworkReply::NetworkError error = QNetworkReply::NoError;
QByteArray response = makeJsonRequest(apiUrl, prepareEncryptedJson(pubkeyUrl, 2, payload), error);
return extractError(response);
return toxmeData.extractCode(response);
}
/**
@ -326,11 +220,11 @@ Toxme::ExecCode Toxme::deleteAddress(QString server, ToxPk id)
QString Toxme::getErrorMessage(int errorCode)
{
switch (errorCode) {
case IncorrectResponse:
case ToxmeData::IncorrectResponse:
return "Incorrect response";
case NoPassword:
case ToxmeData::NoPassword:
return "No password in response";
case ServerError:
case ToxmeData::ServerError:
return "Server doesn't support Toxme";
case -1:
return "You must send POST requests to /api";
@ -373,7 +267,7 @@ QString Toxme::getErrorMessage(int errorCode)
QString Toxme::translateErrorMessage(int errorCode)
{
switch (errorCode) {
case ServerError:
case ToxmeData::ServerError:
return QObject::tr("Server doesn't support Toxme");
case -2:
return QObject::tr("Problem with HTTPS connection");

View File

@ -22,6 +22,7 @@
#define TOXME_H
#include "src/core/toxid.h"
#include "src/net/toxmedata.h"
#include <QMap>
#include <QMutex>
#include <QNetworkReply>
@ -33,20 +34,10 @@ class QNetworkAccessManager;
class Toxme
{
public:
enum ExecCode
{
ExecError = -50,
Ok = 0,
Updated = 1,
ServerError = 2,
IncorrectResponse = 3,
NoPassword = 4
};
static ToxId lookup(QString address);
static QString createAddress(ExecCode& code, QString server, ToxId id, QString address,
bool keepPrivate = true, QString bio = QString());
static ExecCode deleteAddress(QString server, ToxPk id);
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);
@ -55,8 +46,7 @@ private:
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 QString getPass(QString json, ExecCode& code);
static ExecCode extractError(QString json);
static ToxmeData::ExecCode extractError(QString json);
private:
static const QMap<QString, QString> pubkeyUrls;

164
src/net/toxmedata.cpp Normal file
View File

@ -0,0 +1,164 @@
/*
Copyright © 2017 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 <QString>
QByteArray ToxmeData::parsePublicKey(const QString& text) const
{
static const QByteArray pattern{"key\":\""};
QString json = text;
json.remove(' ');
int start = json.indexOf(pattern) + pattern.length();
int end = json.indexOf("\"", start);
int pubkeySize = (end - start) / 2;
QString rawKey = json.mid(start, pubkeySize * 2);
QByteArray key;
// I think, exist more easy way to convert key to ByteArray
for (int i = 0; i < pubkeySize; ++i) {
QString byte = rawKey.mid(i * 2, 2);
key[i] = byte.toInt(nullptr, 16);
}
return key;
}
QString ToxmeData::encryptedJson(int action, const QByteArray& pk, const QByteArray& encrypted,
const QByteArray& nonce) const
{
return "{\"action\":" + QString().setNum(action) +
",\"public_key\":\"" + pk.toHex() +
"\",\"encrypted\":\"" + encrypted.toBase64() +
"\",\"nonce\":\"" + nonce.toBase64() + "\"}";
}
QString ToxmeData::lookupRequest(const QString& address) const
{
return "{\"action\":3,\"name\":\"" + address + "\"}";
}
ToxId ToxmeData::lookup(const QString& inText) const
{
QString text = inText;
static const QByteArray pattern{"tox_id\""};
const int index = text.indexOf(pattern);
if (index == -1)
return ToxId();
text = text.mid(index + pattern.size());
const int idStart = text.indexOf('"');
if (idStart == -1)
return ToxId();
text = text.mid(idStart + 1);
const int idEnd = text.indexOf('"');
if (idEnd == -1)
return ToxId();
text.truncate(idEnd);
return ToxId(text);
}
ToxmeData::ExecCode ToxmeData::extractCode(const QString& srcJson) const
{
QString json = srcJson;
static const QByteArray pattern{"c\":"};
if (json.isEmpty())
return ServerError;
json = json.remove(' ');
const int start = json.indexOf(pattern);
if (start == -1)
return ServerError;
json = json.mid(start + pattern.size());
int end = json.indexOf(",");
if (end == -1) {
end = json.indexOf("}");
if (end == -1)
return IncorrectResponse;
}
json.truncate(end);
bool ok;
int r = json.toInt(&ok);
if (!ok)
return IncorrectResponse;
return ExecCode(r);
}
QString ToxmeData::createAddressRequest(const ToxId id, const QString& address, const QString& bio,
bool keepPrivate) const
{
int privacy = keepPrivate ? 0 : 2;
return "{\"tox_id\":\"" + id.toString() +
"\",\"name\":\"" + address +
"\",\"privacy\":" + QString().setNum(privacy) +
",\"bio\":\"" + bio +
"\",\"timestamp\":" + QString().setNum(time(nullptr)) +
"}";
}
QString ToxmeData::getPass(const QString& srcJson, ToxmeData::ExecCode& code)
{
QString json = srcJson;
static const QByteArray pattern{"password\":"};
json = json.remove(' ');
const int start = json.indexOf(pattern);
if (start == -1) {
code = ToxmeData::NoPassword;
return QString();
}
json = json.mid(start + pattern.size());
if (json.startsWith("null")) {
code = ToxmeData::Updated;
return QString();
}
json = json.mid(1, json.length());
int end = json.indexOf("\"");
if (end == -1) {
code = ToxmeData::IncorrectResponse;
return QString();
}
json.truncate(end);
return json;
}
QString ToxmeData::deleteAddressRequest(const ToxPk& pk)
{
return "{\"public_key\":\"" + pk.toString() +
"\",\"timestamp\":" + QString().setNum(time(nullptr)) +
"}";
}

55
src/net/toxmedata.h Normal file
View File

@ -0,0 +1,55 @@
/*
Copyright © 2017 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

@ -519,7 +519,7 @@ void ProfileForm::onRegisterButtonClicked()
Core* oldCore = Core::getInstance();
Toxme::ExecCode code = Toxme::ExecCode::Ok;
ToxmeData::ExecCode code = ToxmeData::ExecCode::Ok;
QString response = Toxme::createAddress(code, server, ToxId(id), name, privacy, bio);
Core* newCore = Core::getInstance();
@ -527,12 +527,12 @@ void ProfileForm::onRegisterButtonClicked()
// before the request is finished, else qTox will crash.
if (oldCore == newCore) {
switch (code) {
case Toxme::Updated:
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 Toxme::Ok:
case ToxmeData::Ok:
GUI::showInfo(tr("Done!"),
tr("Successfully added %1@%2 to the database. Save your password")
.arg(name, server));