continue on switching QString and QByteArray

This commit is contained in:
csoler 2021-11-29 22:59:46 +01:00
parent e4ce32bef8
commit 6a4cdcc471
28 changed files with 525 additions and 397 deletions

View file

@ -744,7 +744,6 @@ HEADERS += tor/AddOnionCommand.h \
tor/TorManager.h \ tor/TorManager.h \
tor/TorProcess.h \ tor/TorProcess.h \
tor/TorProcess_p.h \ tor/TorProcess_p.h \
tor/TorSocket.h \
tor/Useful.h tor/Useful.h
SOURCES += tor/AddOnionCommand.cpp \ SOURCES += tor/AddOnionCommand.cpp \
@ -758,7 +757,6 @@ SOURCES += tor/AddOnionCommand.cpp \
tor/TorControlSocket.cpp \ tor/TorControlSocket.cpp \
tor/TorManager.cpp \ tor/TorManager.cpp \
tor/TorProcess.cpp \ tor/TorProcess.cpp \
tor/TorSocket.cpp \
tor/CryptoKey.cpp \ tor/CryptoKey.cpp \
tor/PendingOperation.cpp \ tor/PendingOperation.cpp \
tor/SecureRNG.cpp \ tor/SecureRNG.cpp \

View file

@ -45,12 +45,12 @@ AddOnionCommand::AddOnionCommand(HiddenService *service)
bool AddOnionCommand::isSuccessful() const bool AddOnionCommand::isSuccessful() const
{ {
return statusCode() == 250 && m_errorMessage.isEmpty(); return statusCode() == 250 && m_errorMessage.empty();
} }
QByteArray AddOnionCommand::build() ByteArray AddOnionCommand::build()
{ {
QByteArray out("ADD_ONION"); ByteArray out("ADD_ONION");
if (m_service->privateKey().isLoaded()) { if (m_service->privateKey().isLoaded()) {
out += " "; out += " ";
@ -74,11 +74,11 @@ QByteArray AddOnionCommand::build()
return out; return out;
} }
void AddOnionCommand::onReply(int statusCode, const QByteArray &data) void AddOnionCommand::onReply(int statusCode, const ByteArray &data)
{ {
TorControlCommand::onReply(statusCode, data); TorControlCommand::onReply(statusCode, data);
if (statusCode != 250) { if (statusCode != 250) {
m_errorMessage = QString::fromLatin1(data); m_errorMessage = data.toString();
return; return;
} }
@ -86,17 +86,17 @@ void AddOnionCommand::onReply(int statusCode, const QByteArray &data)
const QByteArray sidPrefix("ServiceID="); const QByteArray sidPrefix("ServiceID=");
if(data.startsWith("ServiceID=")){ if(data.startsWith("ServiceID=")){
QByteArray service_id = data.mid(sidPrefix.size()); ByteArray service_id = data.mid(sidPrefix.size());
m_service->setServiceId(service_id); m_service->setServiceId(service_id);
} }
if (data.startsWith(keyPrefix)) { if (data.startsWith(keyPrefix)) {
QByteArray keyData(data.mid(keyPrefix.size())); ByteArray keyData(data.mid(keyPrefix.size()));
CryptoKey key; CryptoKey key;
if (!key.loadFromTorMessage(keyData)) { if (!key.loadFromTorMessage(keyData)) {
m_errorMessage = QStringLiteral("Key structure check failed"); m_errorMessage = "Key structure check failed";
return; return;
} }

View file

@ -48,15 +48,15 @@ class AddOnionCommand : public TorControlCommand
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(AddOnionCommand) Q_DISABLE_COPY(AddOnionCommand)
Q_PROPERTY(QString errorMessage READ errorMessage CONSTANT) Q_PROPERTY(std::string errorMessage READ errorMessage CONSTANT)
Q_PROPERTY(bool successful READ isSuccessful CONSTANT) Q_PROPERTY(bool successful READ isSuccessful CONSTANT)
public: public:
AddOnionCommand(HiddenService *service); AddOnionCommand(HiddenService *service);
QByteArray build(); ByteArray build();
QString errorMessage() const { return m_errorMessage; } std::string errorMessage() const { return m_errorMessage; }
bool isSuccessful() const; bool isSuccessful() const;
signals: signals:
@ -65,9 +65,9 @@ signals:
protected: protected:
HiddenService *m_service; HiddenService *m_service;
QString m_errorMessage; std::string m_errorMessage;
virtual void onReply(int statusCode, const QByteArray &data); virtual void onReply(int statusCode, const ByteArray &data);
virtual void onFinished(int statusCode); virtual void onFinished(int statusCode);
}; };

View file

@ -41,12 +41,12 @@ GetConfCommand::GetConfCommand(Type t)
{ {
} }
ByteArray GetConfCommand::build(const ByteArray &key) ByteArray GetConfCommand::build(const std::string &key)
{ {
return build(QList<ByteArray>() << key); return build(std::list<std::string> { key } );
} }
ByteArray GetConfCommand::build(const QList<ByteArray> &keys) ByteArray GetConfCommand::build(const std::list<std::string> &keys)
{ {
ByteArray out; ByteArray out;
if (type == GetConf) { if (type == GetConf) {
@ -97,9 +97,9 @@ void GetConfCommand::onDataFinished()
m_lastKey.clear(); m_lastKey.clear();
} }
std::list<std::string> GetConfCommand::get(const ByteArray& key) const std::list<std::string> GetConfCommand::get(const std::string& key) const
{ {
auto it = m_results.find(key.toString()); auto it = m_results.find(key);
if(it != m_results.end()) if(it != m_results.end())
return it->second; return it->second;

View file

@ -56,11 +56,11 @@ public:
GetConfCommand(Type type); GetConfCommand(Type type);
ByteArray build(const ByteArray &key); ByteArray build(const std::string &key);
ByteArray build(const QList<ByteArray> &keys); ByteArray build(const std::list<std::string> &keys);
const std::map<std::string,std::list<std::string> > &results() const { return m_results; } const std::map<std::string,std::list<std::string> > &results() const { return m_results; }
std::list<std::string> get(const ByteArray &key) const; std::list<std::string> get(const std::string &key) const;
protected: protected:
virtual void onReply(int statusCode, const ByteArray &data); virtual void onReply(int statusCode, const ByteArray &data);

View file

@ -34,9 +34,7 @@
#include "TorControl.h" #include "TorControl.h"
#include "CryptoKey.h" #include "CryptoKey.h"
#include "Useful.h" #include "Useful.h"
#include <QDir> #include "util/rsdir.h"
#include <QTimer>
#include <QDebug>
using namespace Tor; using namespace Tor;
@ -49,9 +47,10 @@ HiddenService::HiddenService(HiddenServiceClient *client,const std::string& path
: m_dataPath(path), m_status(NotCreated), m_client(client) : m_dataPath(path), m_status(NotCreated), m_client(client)
{ {
/* Set the initial status and, if possible, load the hostname */ /* Set the initial status and, if possible, load the hostname */
if (QDir(m_dataPath).exists(QLatin1String("private_key"))) { if(RsDirUtil::fileExists(m_dataPath + "/private_key"))
{
loadPrivateKey(); loadPrivateKey();
if (!m_hostname.isEmpty()) if (!m_hostname.empty())
m_status = Offline; m_status = Offline;
} }
} }
@ -81,19 +80,19 @@ void HiddenService::setStatus(Status newStatus)
void HiddenService::addTarget(const Target &target) void HiddenService::addTarget(const Target &target)
{ {
m_targets.append(target); m_targets.push_back(target);
} }
void HiddenService::addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort) void HiddenService::addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort)
{ {
Target t = { targetAddress, servicePort, targetPort }; Target t = { targetAddress, servicePort, targetPort };
m_targets.append(t); m_targets.push_back(t);
} }
void HiddenService::setServiceId(const ByteArray& sid) void HiddenService::setServiceId(const ByteArray& sid)
{ {
m_service_id = sid; m_service_id = sid;
m_hostname = sid + ".onion"; m_hostname = sid.toString() + ".onion";
if(m_client) if(m_client)
m_client->hiddenServiceHostnameChanged(); // emit hostnameChanged(); m_client->hiddenServiceHostnameChanged(); // emit hostnameChanged();
@ -105,13 +104,6 @@ void HiddenService::setPrivateKey(const CryptoKey &key)
return; return;
} }
#ifdef TO_REMOVE
if (!key.isPrivate()) {
BUG() << "Cannot create a hidden service with a public key";
return;
}
#endif
m_privateKey = key; m_privateKey = key;
if(m_client) if(m_client)
@ -120,13 +112,13 @@ void HiddenService::setPrivateKey(const CryptoKey &key)
void HiddenService::loadPrivateKey() void HiddenService::loadPrivateKey()
{ {
if (m_privateKey.isLoaded() || m_dataPath.isEmpty()) if (m_privateKey.isLoaded() || m_dataPath.empty())
return; return;
bool ok = m_privateKey.loadFromFile(m_dataPath + QLatin1String("/private_key")); bool ok = m_privateKey.loadFromFile(m_dataPath + "/private_key");
if (!ok) { if (!ok) {
qWarning() << "Failed to load hidden service key"; RsWarn() << "Failed to load hidden service key";
return; return;
} }
@ -138,7 +130,7 @@ void HiddenService::servicePublished()
{ {
loadPrivateKey(); loadPrivateKey();
if (m_hostname.isEmpty()) { if (m_hostname.empty()) {
std::cerr << "Failed to read hidden service hostname" << std::endl; std::cerr << "Failed to read hidden service hostname" << std::endl;
return; return;
} }

View file

@ -35,9 +35,7 @@
#include <QObject> #include <QObject>
#include <QHostAddress> #include <QHostAddress>
#include <QList>
#include "CryptoKey.h" #include "CryptoKey.h"
#include "bytearray.h" #include "bytearray.h"
namespace Tor namespace Tor
@ -78,7 +76,7 @@ public:
HiddenService(HiddenServiceClient *client); HiddenService(HiddenServiceClient *client);
HiddenService(HiddenServiceClient *client, const std::string &dataPath); HiddenService(HiddenServiceClient *client, const std::string &dataPath);
HiddenService(HiddenServiceClient *client, const CryptoKey &privateKey, const std::string &dataPath = QString()); HiddenService(HiddenServiceClient *client, const CryptoKey &privateKey, const std::string &dataPath = std::string());
Status status() const { return m_status; } Status status() const { return m_status; }

View file

@ -44,23 +44,23 @@ bool PendingOperation::isFinished() const
bool PendingOperation::isSuccess() const bool PendingOperation::isSuccess() const
{ {
return m_finished && m_errorMessage.isNull(); return m_finished && m_errorMessage.empty();
} }
bool PendingOperation::isError() const bool PendingOperation::isError() const
{ {
return m_finished && !m_errorMessage.isNull(); return m_finished && !m_errorMessage.empty();
} }
QString PendingOperation::errorMessage() const std::string PendingOperation::errorMessage() const
{ {
return m_errorMessage; return m_errorMessage;
} }
void PendingOperation::finishWithError(const QString &message) void PendingOperation::finishWithError(const std::string &message)
{ {
if (message.isEmpty()) if (message.empty())
m_errorMessage = QStringLiteral("Unknown Error"); m_errorMessage = "Unknown Error";
m_errorMessage = message; m_errorMessage = message;
if (!m_finished) { if (!m_finished) {
@ -72,7 +72,7 @@ void PendingOperation::finishWithError(const QString &message)
void PendingOperation::finishWithSuccess() void PendingOperation::finishWithSuccess()
{ {
Q_ASSERT(m_errorMessage.isNull()); Q_ASSERT(m_errorMessage.empty());
if (!m_finished) { if (!m_finished) {
m_finished = true; m_finished = true;

View file

@ -55,7 +55,7 @@ class PendingOperation : public QObject
Q_PROPERTY(bool isFinished READ isFinished NOTIFY finished FINAL) Q_PROPERTY(bool isFinished READ isFinished NOTIFY finished FINAL)
Q_PROPERTY(bool isSuccess READ isSuccess NOTIFY success FINAL) Q_PROPERTY(bool isSuccess READ isSuccess NOTIFY success FINAL)
Q_PROPERTY(bool isError READ isError NOTIFY error FINAL) Q_PROPERTY(bool isError READ isError NOTIFY error FINAL)
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY finished FINAL) Q_PROPERTY(std::string errorMessage READ errorMessage NOTIFY finished FINAL)
public: public:
PendingOperation(QObject *parent = 0); PendingOperation(QObject *parent = 0);
@ -63,23 +63,23 @@ public:
bool isFinished() const; bool isFinished() const;
bool isSuccess() const; bool isSuccess() const;
bool isError() const; bool isError() const;
QString errorMessage() const; std::string errorMessage() const;
signals: signals:
// Always emitted once when finished, regardless of status // Always emitted once when finished, regardless of status
void finished(); void finished();
// One of error() or success() is emitted once // One of error() or success() is emitted once
void error(const QString &errorMessage); void error(const std::string &errorMessage);
void success(); void success();
protected slots: protected slots:
void finishWithError(const QString &errorMessage); void finishWithError(const std::string &errorMessage);
void finishWithSuccess(); void finishWithSuccess();
private: private:
bool m_finished; bool m_finished;
QString m_errorMessage; std::string m_errorMessage;
}; };
Q_DECLARE_METATYPE(PendingOperation*) Q_DECLARE_METATYPE(PendingOperation*)

View file

@ -33,7 +33,6 @@
#include "ProtocolInfoCommand.h" #include "ProtocolInfoCommand.h"
#include "TorControl.h" #include "TorControl.h"
#include "StrUtil.h" #include "StrUtil.h"
#include <QList>
using namespace Tor; using namespace Tor;
@ -55,14 +54,15 @@ void ProtocolInfoCommand::onReply(int statusCode, const ByteArray &data)
if (data.startsWith("AUTH ")) if (data.startsWith("AUTH "))
{ {
QList<ByteArray> tokens = splitQuotedStrings(data.mid(5), ' '); std::list<ByteArray> tokens = splitQuotedStrings(data.mid(5), ' ');
foreach (ByteArray token, tokens) foreach (ByteArray token, tokens)
{ {
if (token.startsWith("METHODS=")) if (token.startsWith("METHODS="))
{ {
QList<ByteArray> textMethods = unquotedString(token.mid(8)).split(','); std::list<ByteArray> textMethods = unquotedString(token.mid(8)).split(',');
for (QList<ByteArray>::Iterator it = textMethods.begin(); it != textMethods.end(); ++it)
for (std::list<ByteArray>::iterator it = textMethods.begin(); it != textMethods.end(); ++it)
{ {
if (*it == "NULL") if (*it == "NULL")
m_authMethods |= AuthNull; m_authMethods |= AuthNull;
@ -74,12 +74,12 @@ void ProtocolInfoCommand::onReply(int statusCode, const ByteArray &data)
} }
else if (token.startsWith("COOKIEFILE=")) else if (token.startsWith("COOKIEFILE="))
{ {
m_cookieFile = QString::fromLatin1(unquotedString(token.mid(11))); m_cookieFile = unquotedString(token.mid(11)).toString();
} }
} }
} }
else if (data.startsWith("VERSION Tor=")) else if (data.startsWith("VERSION Tor="))
{ {
m_torVersion = std::string(unquotedString(data.mid(12, data.indexOf(' ', 12)))); m_torVersion = unquotedString(data.mid(12, data.indexOf(' ', 12))).toString();
} }
} }

View file

@ -34,7 +34,6 @@
#define PROTOCOLINFOCOMMAND_H #define PROTOCOLINFOCOMMAND_H
#include "TorControlCommand.h" #include "TorControlCommand.h"
#include <QFlags>
namespace Tor namespace Tor
{ {
@ -60,8 +59,8 @@ public:
ByteArray build(); ByteArray build();
AuthMethods authMethods() const { return m_authMethods; } AuthMethods authMethods() const { return m_authMethods; }
QString torVersion() const { return m_torVersion; } std::string torVersion() const { return m_torVersion; }
QString cookieFile() const { return m_cookieFile; } std::string cookieFile() const { return m_cookieFile; }
protected: protected:
virtual void onReply(int statusCode, const ByteArray &data); virtual void onReply(int statusCode, const ByteArray &data);
@ -69,8 +68,8 @@ protected:
private: private:
TorControl *manager; TorControl *manager;
AuthMethods m_authMethods; AuthMethods m_authMethods;
QString m_torVersion; std::string m_torVersion;
QString m_cookieFile; std::string m_cookieFile;
}; };
} }

View file

@ -50,9 +50,9 @@ bool SetConfCommand::isSuccessful() const
return statusCode() == 250; return statusCode() == 250;
} }
ByteArray SetConfCommand::build(const ByteArray &key, const ByteArray &value) ByteArray SetConfCommand::build(const std::string &key, const std::string &value)
{ {
return build(std::list<std::pair<ByteArray, ByteArray> > { std::make_pair(key, value) } ); return build(std::list<std::pair<std::string, std::string> > { std::make_pair(key, value) } );
} }
// ByteArray SetConfCommand::build(const std::list<std::pair<ByteArray,ByteArray> > &data) // ByteArray SetConfCommand::build(const std::list<std::pair<ByteArray,ByteArray> > &data)
@ -74,7 +74,7 @@ ByteArray SetConfCommand::build(const ByteArray &key, const ByteArray &value)
// return build(out); // return build(out);
// } // }
ByteArray SetConfCommand::build(const std::list<std::pair<ByteArray, ByteArray> >& data) ByteArray SetConfCommand::build(const std::list<std::pair<std::string, std::string> >& data)
{ {
ByteArray out(m_resetMode ? "RESETCONF" : "SETCONF"); ByteArray out(m_resetMode ? "RESETCONF" : "SETCONF");

View file

@ -54,8 +54,8 @@ public:
void setResetMode(bool resetMode); void setResetMode(bool resetMode);
ByteArray build(const ByteArray &key, const ByteArray &value); ByteArray build(const std::string &key, const std::string &value);
ByteArray build(const std::list<std::pair<ByteArray, ByteArray> > &data); ByteArray build(const std::list<std::pair<std::string, std::string> > &data);
std::string errorMessage() const { return m_errorMessage; } std::string errorMessage() const { return m_errorMessage; }
bool isSuccessful() const; bool isSuccessful() const;

View file

@ -115,7 +115,7 @@ QString SettingsFile::filePath() const
return d->filePath; return d->filePath;
} }
bool SettingsFile::setFilePath(const QString &filePath) bool SettingsFile::setFilePath(const std::string& filePath)
{ {
if (d->filePath == filePath) if (d->filePath == filePath)
return hasError(); return hasError();
@ -125,8 +125,8 @@ bool SettingsFile::setFilePath(const QString &filePath)
QFileInfo fileInfo(filePath); QFileInfo fileInfo(filePath);
QDir dir(fileInfo.path()); QDir dir(fileInfo.path());
if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) { if (!dir.exists() && !dir.mkpath(".")) {
d->setError(QStringLiteral("Cannot create directory: %1").arg(dir.path())); d->setError("Cannot create directory: " + dir.path()));
return false; return false;
} }
d->checkDirPermissions(fileInfo.path()); d->checkDirPermissions(fileInfo.path());
@ -137,7 +137,7 @@ bool SettingsFile::setFilePath(const QString &filePath)
return true; return true;
} }
QString SettingsFile::errorMessage() const std::string SettingsFile::errorMessage() const
{ {
return d->errorMessage; return d->errorMessage;
} }

View file

@ -66,9 +66,9 @@ public:
virtual ~SettingsFile(); virtual ~SettingsFile();
QString filePath() const; QString filePath() const;
bool setFilePath(const QString &filePath); bool setFilePath(const std::string &filePath);
QString errorMessage() const; std::string errorMessage() const;
bool hasError() const; bool hasError() const;
SettingsObject *root(); SettingsObject *root();
@ -136,38 +136,38 @@ public:
static SettingsFile *defaultFile(); static SettingsFile *defaultFile();
static void setDefaultFile(SettingsFile *file); static void setDefaultFile(SettingsFile *file);
QString path() const; std::string path() const;
void setPath(const QString &path); void setPath(const std::string &path);
QJsonObject data() const; QJsonObject data() const;
void setData(const QJsonObject &data); void setData(const QJsonObject &data);
Q_INVOKABLE QJsonValue read(const QString &key, const QJsonValue &defaultValue = QJsonValue::Undefined) const; Q_INVOKABLE QJsonValue read(const std::string &key, const QJsonValue &defaultValue = QJsonValue::Undefined) const;
template<typename T> T read(const QString &key) const; template<typename T> T read(const std::string &key) const;
Q_INVOKABLE void write(const QString &key, const QJsonValue &value); Q_INVOKABLE void write(const std::string &key, const QJsonValue &value);
template<typename T> void write(const QString &key, const T &value); template<typename T> void write(const std::string &key, const T &value);
Q_INVOKABLE void unset(const QString &key); Q_INVOKABLE void unset(const std::string &key);
// const char* key overloads // const char* key overloads
QJsonValue read(const char *key, const QJsonValue &defaultValue = QJsonValue::Undefined) const QJsonValue read(const char *key, const QJsonValue &defaultValue = QJsonValue::Undefined) const
{ {
return read(QString::fromLatin1(key), defaultValue); return read(std::string(key), defaultValue);
} }
template<typename T> T read(const char *key) const template<typename T> T read(const char *key) const
{ {
return read<T>(QString::fromLatin1(key)); return read<T>(std::string(key));
} }
void write(const char *key, const QJsonValue &value) void write(const char *key, const QJsonValue &value)
{ {
write(QString::fromLatin1(key), value); write(std::string(key), value);
} }
template<typename T> void write(const char *key, const T &value) template<typename T> void write(const char *key, const T &value)
{ {
write<T>(QString::fromLatin1(key), value); write<T>(std::string(key), value);
} }
void unset(const char *key) void unset(const char *key)
{ {
unset(QString::fromLatin1(key)); unset(std::string(key));
} }
Q_INVOKABLE void undefine(); Q_INVOKABLE void undefine();
@ -176,56 +176,56 @@ signals:
void pathChanged(); void pathChanged();
void dataChanged(); void dataChanged();
void modified(const QString &path, const QJsonValue &value); void modified(const std::string &path, const QJsonValue &value);
private: private:
SettingsObjectPrivate *d; SettingsObjectPrivate *d;
}; };
template<typename T> inline void SettingsObject::write(const QString &key, const T &value) template<typename T> inline void SettingsObject::write(const std::string &key, const T &value)
{ {
write(key, QJsonValue(value)); write(key, QJsonValue(value));
} }
template<> inline QString SettingsObject::read<QString>(const QString &key) const template<> inline std::string SettingsObject::read<std::string>(const std::string &key) const
{ {
return read(key).toString(); return read(key).toString();
} }
template<> inline QJsonArray SettingsObject::read<QJsonArray>(const QString &key) const template<> inline QJsonArray SettingsObject::read<QJsonArray>(const std::string &key) const
{ {
return read(key).toArray(); return read(key).toArray();
} }
template<> inline QJsonObject SettingsObject::read<QJsonObject>(const QString &key) const template<> inline QJsonObject SettingsObject::read<QJsonObject>(const std::string &key) const
{ {
return read(key).toObject(); return read(key).toObject();
} }
template<> inline double SettingsObject::read<double>(const QString &key) const template<> inline double SettingsObject::read<double>(const std::string &key) const
{ {
return read(key).toDouble(); return read(key).toDouble();
} }
template<> inline int SettingsObject::read<int>(const QString &key) const template<> inline int SettingsObject::read<int>(const std::string &key) const
{ {
return read(key).toInt(); return read(key).toInt();
} }
template<> inline bool SettingsObject::read<bool>(const QString &key) const template<> inline bool SettingsObject::read<bool>(const std::string &key) const
{ {
return read(key).toBool(); return read(key).toBool();
} }
template<> inline QDateTime SettingsObject::read<QDateTime>(const QString &key) const template<> inline QDateTime SettingsObject::read<QDateTime>(const std::string &key) const
{ {
QString value = read(key).toString(); std::string value = read(key).toString();
if (value.isEmpty()) if (value.isEmpty())
return QDateTime(); return QDateTime();
return QDateTime::fromString(value, Qt::ISODate).toLocalTime(); return QDateTime::fromString(value, Qt::ISODate).toLocalTime();
} }
template<> inline void SettingsObject::write<QDateTime>(const QString &key, const QDateTime &value) template<> inline void SettingsObject::write<QDateTime>(const std::string &key, const QDateTime &value)
{ {
write(key, QJsonValue(value.toUTC().toString(Qt::ISODate))); write(key, QJsonValue(value.toUTC().toString(Qt::ISODate)));
} }
@ -242,14 +242,14 @@ private:
QByteArray d; QByteArray d;
}; };
template<> inline Base64Encode SettingsObject::read<Base64Encode>(const QString &key) const template<> inline Base64Encode SettingsObject::read<Base64Encode>(const std::string &key) const
{ {
return Base64Encode(QByteArray::fromBase64(read(key).toString().toLatin1())); return Base64Encode(QByteArray::fromBase64(read(key).toString().toLatin1()));
} }
template<> inline void SettingsObject::write<Base64Encode>(const QString &key, const Base64Encode &value) template<> inline void SettingsObject::write<Base64Encode>(const std::string &key, const Base64Encode &value)
{ {
write(key, QJsonValue(QString::fromLatin1(value.encoded()))); write(key, QJsonValue(std::string(value.encoded())));
} }
#endif #endif

View file

@ -59,7 +59,7 @@ ByteArray quotedString(const ByteArray &string)
return out; return out;
} }
ByteArray unquotedString(const ByteArray &string) ByteArray unquotedString(const ByteArray& string)
{ {
if (string.size() < 2 || string[0] != '"') if (string.size() < 2 || string[0] != '"')
return string; return string;

View file

@ -31,6 +31,8 @@
*/ */
#include <time.h> #include <time.h>
#include <fstream>
#include "util/rsdir.h"
#include "retroshare/rstor.h" #include "retroshare/rstor.h"
#include "TorControl.h" #include "TorControl.h"
@ -83,15 +85,15 @@ public:
TorControlSocket *socket; TorControlSocket *socket;
QHostAddress torAddress; QHostAddress torAddress;
QString errorMessage; std::string errorMessage;
QString torVersion; std::string torVersion;
ByteArray authPassword; ByteArray authPassword;
QHostAddress socksAddress; QHostAddress socksAddress;
QList<HiddenService*> services; QList<HiddenService*> services;
quint16 controlPort, socksPort; quint16 controlPort, socksPort;
TorControl::Status status; TorControl::Status status;
TorControl::TorStatus torStatus; TorControl::TorStatus torStatus;
QVariantMap bootstrapStatus; std::map<std::string,std::string> bootstrapStatus;
bool hasOwnership; bool hasOwnership;
TorControlPrivate(TorControl *parent); TorControlPrivate(TorControl *parent);
@ -110,10 +112,10 @@ public slots:
void authenticateReply(); void authenticateReply();
void protocolInfoReply(); void protocolInfoReply();
void getTorInfoReply(); void getTorInfoReply();
void setError(const QString &message); void setError(const std::string &message);
void statusEvent(int code, const ByteArray &data); void statusEvent(int code, const ByteArray &data);
void updateBootstrap(const QList<ByteArray> &data); void updateBootstrap(const std::list<ByteArray> &data);
}; };
} }
@ -219,12 +221,12 @@ void TorControlPrivate::setTorStatus(TorControl::TorStatus n)
} }
} }
void TorControlPrivate::setError(const QString &message) void TorControlPrivate::setError(const std::string &message)
{ {
errorMessage = message; errorMessage = message;
setStatus(TorControl::Error); setStatus(TorControl::Error);
qWarning() << "torctrl: Error:" << errorMessage; RsWarn() << "torctrl: Error:" << errorMessage;
socket->abort(); socket->abort();
@ -241,12 +243,12 @@ TorControl::TorStatus TorControl::torStatus() const
return d->torStatus; return d->torStatus;
} }
QString TorControl::torVersion() const std::string TorControl::torVersion() const
{ {
return d->torVersion; return d->torVersion;
} }
QString TorControl::errorMessage() const std::string TorControl::errorMessage() const
{ {
return d->errorMessage; return d->errorMessage;
} }
@ -271,7 +273,7 @@ QList<HiddenService*> TorControl::hiddenServices() const
return d->services; return d->services;
} }
QVariantMap TorControl::bootstrapStatus() const std::map<std::string,std::string> TorControl::bootstrapStatus() const
{ {
return d->bootstrapStatus; return d->bootstrapStatus;
} }
@ -369,7 +371,7 @@ void TorControlPrivate::socketDisconnected()
void TorControlPrivate::socketError() void TorControlPrivate::socketError()
{ {
setError(QStringLiteral("Connection failed: %1").arg(socket->errorString())); setError("Connection failed: " + socket->errorString()));
} }
void TorControlPrivate::protocolInfoReply() void TorControlPrivate::protocolInfoReply()
@ -393,11 +395,11 @@ void TorControlPrivate::protocolInfoReply()
torCtrlDebug() << "torctrl: Using null authentication" << std::endl; torCtrlDebug() << "torctrl: Using null authentication" << std::endl;
data = auth->build(); data = auth->build();
} }
else if (methods.testFlag(ProtocolInfoCommand::AuthCookie) && !info->cookieFile().isEmpty()) else if (methods.testFlag(ProtocolInfoCommand::AuthCookie) && !info->cookieFile().empty())
{ {
QString cookieFile = info->cookieFile(); std::string cookieFile = info->cookieFile();
QString cookieError; std::string cookieError;
torCtrlDebug() << "torctrl: Using cookie authentication with file" << cookieFile.toStdString() << std::endl; torCtrlDebug() << "torctrl: Using cookie authentication with file" << cookieFile << std::endl;
QFile file(cookieFile); QFile file(cookieFile);
if (file.open(QIODevice::ReadOnly)) if (file.open(QIODevice::ReadOnly))
@ -410,28 +412,28 @@ void TorControlPrivate::protocolInfoReply()
if (cookie.size() == 32) if (cookie.size() == 32)
data = auth->build(cookie); data = auth->build(cookie);
else else
cookieError = QStringLiteral("Unexpected file size"); cookieError = "Unexpected file size";
} }
else else
cookieError = file.errorString(); cookieError = file.errorString();
if (!cookieError.isNull() || data.isNull()) if (!cookieError.empty() || data.isNull())
{ {
/* If we know a password and password authentication is allowed, try using that instead. /* If we know a password and password authentication is allowed, try using that instead.
* This is a strange corner case that will likely never happen in a normal configuration, * This is a strange corner case that will likely never happen in a normal configuration,
* but it has happened. */ * but it has happened. */
if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword) && !authPassword.isEmpty()) if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword) && !authPassword.empty())
{ {
torCtrlDebug() << "torctrl: Unable to read authentication cookie file:" << cookieError.toStdString() << std::endl; torCtrlDebug() << "torctrl: Unable to read authentication cookie file:" << cookieError << std::endl;
goto usePasswordAuth; goto usePasswordAuth;
} }
setError(QStringLiteral("Unable to read authentication cookie file: %1").arg(cookieError)); setError("Unable to read authentication cookie file: " + cookieError);
delete auth; delete auth;
return; return;
} }
} }
else if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword) && !authPassword.isEmpty()) else if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword) && !authPassword.empty())
{ {
usePasswordAuth: usePasswordAuth:
torCtrlDebug() << "torctrl: Using hashed password authentication" << std::endl; torCtrlDebug() << "torctrl: Using hashed password authentication" << std::endl;
@ -440,9 +442,9 @@ void TorControlPrivate::protocolInfoReply()
else else
{ {
if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword)) if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword))
setError(QStringLiteral("Tor requires a control password to connect, but no password is configured.")); setError("Tor requires a control password to connect, but no password is configured.");
else else
setError(QStringLiteral("Tor is not configured to accept any supported authentication methods.")); setError("Tor is not configured to accept any supported authentication methods.");
delete auth; delete auth;
return; return;
} }
@ -458,11 +460,10 @@ void TorControlPrivate::getTorInfo()
GetConfCommand *command = new GetConfCommand(GetConfCommand::GetInfo); GetConfCommand *command = new GetConfCommand(GetConfCommand::GetInfo);
connect(command, &TorControlCommand::finished, this, &TorControlPrivate::getTorInfoReply); connect(command, &TorControlCommand::finished, this, &TorControlPrivate::getTorInfoReply);
QList<ByteArray> keys; std::list<std::string> keys{ "status/circuit-established","status/bootstrap-phase" };
keys << ByteArray("status/circuit-established") << ByteArray("status/bootstrap-phase");
/* If these are set in the config, they override the automatic behavior. */ /* If these are set in the config, they override the automatic behavior. */
SettingsObject settings(QStringLiteral("tor")); SettingsObject settings("tor");
QHostAddress forceAddress(settings.read("socksAddress").toString()); QHostAddress forceAddress(settings.read("socksAddress").toString());
quint16 port = (quint16)settings.read("socksPort").toInt(); quint16 port = (quint16)settings.read("socksPort").toInt();
@ -478,8 +479,9 @@ void TorControlPrivate::getTorInfo()
ev->mTorManagerEventType = RsTorManagerEventCode::TOR_CONNECTIVITY_CHANGED; ev->mTorManagerEventType = RsTorManagerEventCode::TOR_CONNECTIVITY_CHANGED;
rsEvents->sendEvent(ev); rsEvents->sendEvent(ev);
} }
} else }
keys << ByteArray("net/listeners/socks"); else
keys .push_back("net/listeners/socks");
socket->sendCommand(command, command->build(keys)); socket->sendCommand(command, command->build(keys));
} }
@ -490,11 +492,12 @@ void TorControlPrivate::getTorInfoReply()
if (!command || !q->isConnected()) if (!command || !q->isConnected())
return; return;
QList<ByteArray> listenAddresses = splitQuotedStrings(command->get(ByteArray("net/listeners/socks")).toString().toLatin1(), ' '); std::list<ByteArray> listenAddresses = splitQuotedStrings(command->get("net/listeners/socks").front(), ' ');
for (QList<ByteArray>::Iterator it = listenAddresses.begin(); it != listenAddresses.end(); ++it) {
ByteArray value = unquotedString(*it); for (const auto& add:listenAddresses) {
ByteArray value = unquotedString(add);
int sepp = value.indexOf(':'); int sepp = value.indexOf(':');
QHostAddress address(QString::fromLatin1(value.mid(0, sepp))); QHostAddress address(value.mid(0, sepp));
quint16 port = (quint16)value.mid(sepp+1).toUInt(); quint16 port = (quint16)value.mid(sepp+1).toUInt();
/* Use the first address that matches the one used for this control connection. If none do, /* Use the first address that matches the one used for this control connection. If none do,
@ -523,16 +526,16 @@ void TorControlPrivate::getTorInfoReply()
} }
} }
if (command->get(ByteArray("status/circuit-established")).toInt() == 1) { if (command->get("status/circuit-established").toInt() == 1) {
torCtrlDebug() << "torctrl: Tor indicates that circuits have been established; state is TorReady" << std::endl; torCtrlDebug() << "torctrl: Tor indicates that circuits have been established; state is TorReady" << std::endl;
setTorStatus(TorControl::TorReady); setTorStatus(TorControl::TorReady);
} else { } else {
setTorStatus(TorControl::TorOffline); setTorStatus(TorControl::TorOffline);
} }
ByteArray bootstrap = command->get(ByteArray("status/bootstrap-phase")).toString().toLatin1(); auto bootstrap = command->get("status/bootstrap-phase");
if (!bootstrap.isEmpty()) if (!bootstrap.empty())
updateBootstrap(splitQuotedStrings(bootstrap, ' ')); updateBootstrap(splitQuotedStrings(bootstrap.front(), ' '));
} }
void TorControl::addHiddenService(HiddenService *service) void TorControl::addHiddenService(HiddenService *service)
@ -555,7 +558,7 @@ void TorControlPrivate::publishServices()
} }
std::cerr << std::endl; std::cerr << std::endl;
SettingsObject settings(QStringLiteral("tor")); SettingsObject settings("tor");
if (settings.read("neverPublishServices").toBool()) if (settings.read("neverPublishServices").toBool())
{ {
torCtrlDebug() << "torctrl: Skipping service publication because neverPublishService is enabled" << std::endl; torCtrlDebug() << "torctrl: Skipping service publication because neverPublishService is enabled" << std::endl;
@ -567,12 +570,12 @@ void TorControlPrivate::publishServices()
return; return;
} }
if (q->torVersionAsNewAs(QStringLiteral("0.2.7"))) { if (q->torVersionAsNewAs("0.2.7")) {
foreach (HiddenService *service, services) { foreach (HiddenService *service, services) {
if (service->hostname().isEmpty()) if (service->hostname().empty())
torCtrlDebug() << "torctrl: Creating a new hidden service" << std::endl; torCtrlDebug() << "torctrl: Creating a new hidden service" << std::endl;
else else
torCtrlDebug() << "torctrl: Publishing hidden service: " << service->hostname().toStdString() << std::endl; torCtrlDebug() << "torctrl: Publishing hidden service: " << service->hostname() << std::endl;
AddOnionCommand *onionCommand = new AddOnionCommand(service); AddOnionCommand *onionCommand = new AddOnionCommand(service);
QObject::connect(onionCommand, &AddOnionCommand::succeeded, service, &HiddenService::servicePublished); QObject::connect(onionCommand, &AddOnionCommand::succeeded, service, &HiddenService::servicePublished);
socket->sendCommand(onionCommand, onionCommand->build()); socket->sendCommand(onionCommand, onionCommand->build());
@ -580,37 +583,37 @@ void TorControlPrivate::publishServices()
} else { } else {
torCtrlDebug() << "torctrl: Using legacy SETCONF hidden service configuration for tor" << torVersion.toStdString() << std::endl; torCtrlDebug() << "torctrl: Using legacy SETCONF hidden service configuration for tor" << torVersion.toStdString() << std::endl;
SetConfCommand *command = new SetConfCommand; SetConfCommand *command = new SetConfCommand;
QList<QPair<ByteArray,ByteArray> > torConfig; std::list<std::pair<std::string,std::string> > torConfig;
foreach (HiddenService *service, services) foreach (HiddenService *service, services)
{ {
if (service->dataPath().isEmpty()) if (service->dataPath().empty())
continue; continue;
if (service->privateKey().isLoaded() && !QFile::exists(service->dataPath() + QStringLiteral("/private_key"))) { if (service->privateKey().isLoaded() && !RsDirUtil::fileExists(service->dataPath() + "/private_key")) {
// This case can happen if tor is downgraded after the profile is created // This case can happen if tor is downgraded after the profile is created
qWarning() << "Cannot publish ephemeral hidden services with this version of tor; skipping"; RsWarn() << "Cannot publish ephemeral hidden services with this version of tor; skipping";
continue; continue;
} }
torCtrlDebug() << "torctrl: Configuring hidden service at" << service->dataPath().toStdString() << std::endl; torCtrlDebug() << "torctrl: Configuring hidden service at" << service->dataPath() << std::endl;
QDir dir(service->dataPath()); QDir dir(service->dataPath());
torConfig.append(qMakePair(ByteArray("HiddenServiceDir"), dir.absolutePath().toLocal8Bit())); torConfig.append(qMakePair(ByteArray("HiddenServiceDir"), dir.absolutePath().toLocal8Bit()));
const QList<HiddenService::Target> &targets = service->targets(); const std::list<HiddenService::Target> &targets = service->targets();
for (QList<HiddenService::Target>::ConstIterator tit = targets.begin(); tit != targets.end(); ++tit) for (auto tit:targets)
{ {
QString target = QString::fromLatin1("%1 %2:%3").arg(tit->servicePort) std::string target = RsUtil::NumberToString(tit.servicePort) + " "
.arg(tit->targetAddress.toString()) +tit.targetAddress + ":"
.arg(tit->targetPort); +RsUtil::NumberToString(tit.targetPort);
torConfig.append(qMakePair(ByteArray("HiddenServicePort"), target.toLatin1())); torConfig.append(qMakePair(ByteArray("HiddenServicePort"), target));
} }
QObject::connect(command, &SetConfCommand::setConfSucceeded, service, &HiddenService::servicePublished); QObject::connect(command, &SetConfCommand::setConfSucceeded, service, &HiddenService::servicePublished);
} }
if (!torConfig.isEmpty()) if (!torConfig.empty())
socket->sendCommand(command, command->build(torConfig)); socket->sendCommand(command, command->build(torConfig));
} }
} }
@ -644,34 +647,41 @@ void TorControlPrivate::statusEvent(int code, const ByteArray &data)
{ {
Q_UNUSED(code); Q_UNUSED(code);
QList<ByteArray> tokens = splitQuotedStrings(data.trimmed(), ' '); std::list<ByteArray> tokens = splitQuotedStrings(data.trimmed(), ' ');
if (tokens.size() < 3) if (tokens.size() < 3)
return; return;
torCtrlDebug() << "torctrl: status event:" << QString(data.trimmed()).toStdString() << std::endl; torCtrlDebug() << "torctrl: status event:" << data.trimmed().toString() << std::endl;
const ByteArray& tok2 = *(++tokens.begin());
if (tokens[2] == "CIRCUIT_ESTABLISHED") { if (tok2 == "CIRCUIT_ESTABLISHED") {
setTorStatus(TorControl::TorReady); setTorStatus(TorControl::TorReady);
} else if (tokens[2] == "CIRCUIT_NOT_ESTABLISHED") { } else if (tok2 == "CIRCUIT_NOT_ESTABLISHED") {
setTorStatus(TorControl::TorOffline); setTorStatus(TorControl::TorOffline);
} else if (tokens[2] == "BOOTSTRAP") { } else if (tok2 == "BOOTSTRAP") {
tokens.takeFirst(); tokens.pop_front();
updateBootstrap(tokens); updateBootstrap(tokens);
} }
} }
void TorControlPrivate::updateBootstrap(const QList<ByteArray> &data) void TorControlPrivate::updateBootstrap(const std::list<ByteArray> &data)
{ {
bootstrapStatus.clear(); bootstrapStatus.clear();
// WARN or NOTICE // WARN or NOTICE
bootstrapStatus[QStringLiteral("severity")] = data.value(0); bootstrapStatus["severity"] = (*data.begin()).toString();
for (int i = 1; i < data.size(); i++) {
int equals = data[i].indexOf('='); auto dat = data.begin();
QString key = QString::fromLatin1(data[i].mid(0, equals)); ++dat;
QString value;
for(;dat!=data.end();++dat) { // for(int i = 1; i < data.size(); i++) {
int equals = (*dat).indexOf('=');
ByteArray key = (*dat).mid(0, equals);
ByteArray value;
if (equals >= 0) if (equals >= 0)
value = QString::fromLatin1(unquotedString(data[i].mid(equals + 1))); value = unquotedString((*dat).mid(equals + 1));
bootstrapStatus[key.toLower()] = value;
bootstrapStatus[key.toLower().toString()] = value.toString();
} }
//torCtrlDebug() << bootstrapStatus << std::endl; //torCtrlDebug() << bootstrapStatus << std::endl;
@ -685,16 +695,16 @@ void TorControlPrivate::updateBootstrap(const QList<ByteArray> &data)
} }
} }
QObject *TorControl::getConfiguration(const QString &options) QObject *TorControl::getConfiguration(const std::string& options)
{ {
GetConfCommand *command = new GetConfCommand(GetConfCommand::GetConf); GetConfCommand *command = new GetConfCommand(GetConfCommand::GetConf);
d->socket->sendCommand(command, command->build(options.toLatin1())); d->socket->sendCommand(command, command->build(options));
//QQmlEngine::setObjectOwnership(command, QQmlEngine::CppOwnership); //QQmlEngine::setObjectOwnership(command, QQmlEngine::CppOwnership);
return command; return command;
} }
QObject *TorControl::setConfiguration(const QVariantMap &options) QObject *TorControl::setConfiguration(const std::list<std::pair<std::string,std::string> >& options)
{ {
SetConfCommand *command = new SetConfCommand; SetConfCommand *command = new SetConfCommand;
command->setResetMode(true); command->setResetMode(true);
@ -721,7 +731,8 @@ public:
Q_ASSERT(!command); Q_ASSERT(!command);
command = new GetConfCommand(GetConfCommand::GetInfo); command = new GetConfCommand(GetConfCommand::GetInfo);
QObject::connect(command, &TorControlCommand::finished, this, &SaveConfigOperation::configTextReply); QObject::connect(command, &TorControlCommand::finished, this, &SaveConfigOperation::configTextReply);
socket->sendCommand(command, command->build(QList<ByteArray>() << "config-text" << "config-file"));
socket->sendCommand(command, command->build(std::list<std::string> { "config-text" , "config-file" } ));
} }
private slots: private slots:
@ -731,23 +742,29 @@ private slots:
if (!command) if (!command)
return; return;
QString path = QFile::decodeName(command->get("config-file").toByteArray()); auto lpath = command->get("config-file");
if (path.isEmpty()) { std::string path = (lpath.empty()?std::string():lpath.front());
finishWithError(QStringLiteral("Cannot write torrc without knowing its path"));
if (path.empty()) {
finishWithError("Cannot write torrc without knowing its path");
return; return;
} }
// Out of paranoia, refuse to write any file not named 'torrc', or if the // Out of paranoia, refuse to write any file not named 'torrc', or if the
// file doesn't exist // file doesn't exist
QFileInfo fileInfo(path);
if (fileInfo.fileName() != QStringLiteral("torrc") || !fileInfo.exists()) { auto filename = RsDirUtil::getFileName(path);
finishWithError(QStringLiteral("Refusing to write torrc to unacceptable path %1").arg(path));
if(filename != "torrc" || !RsDirUtil::fileExists(path))
{
finishWithError("Refusing to write torrc to unacceptable path " + path);
return; return;
} }
QSaveFile file(path); std::ofstream file(path);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
finishWithError(QStringLiteral("Failed opening torrc file for writing: %1").arg(file.errorString())); if (!file.is_open()) {
finishWithError("Failed opening torrc file for writing: permissions error?");
return; return;
} }
@ -761,9 +778,11 @@ private slots:
0 0
}; };
QVariantList configText = command->get("config-text").toList(); auto configText = command->get("config-text") ;
foreach (const QVariant &value, configText) {
ByteArray line = value.toByteArray(); for(const auto& value: configText)
{
ByteArray line(value);
bool skip = false; bool skip = false;
for (const char **key = bannedKeys; *key; key++) { for (const char **key = bannedKeys; *key; key++) {
@ -775,14 +794,10 @@ private slots:
if (skip) if (skip)
continue; continue;
file.write(line); file << line.toString() << std::endl;
file.write("\n");
} }
if (!file.commit()) { file.close();
finishWithError(QStringLiteral("Failed writing torrc: %1").arg(file.errorString()));
return;
}
torCtrlDebug() << "torctrl: Wrote torrc file" << std::endl; torCtrlDebug() << "torctrl: Wrote torrc file" << std::endl;
finishWithSuccess(); finishWithSuccess();
@ -820,12 +835,12 @@ void TorControl::takeOwnership()
d->socket->sendCommand("TAKEOWNERSHIP\r\n"); d->socket->sendCommand("TAKEOWNERSHIP\r\n");
// Reset PID-based polling // Reset PID-based polling
QVariantMap options; std::list<std::pair<std::string,std::string> > options;
options[QStringLiteral("__OwningControllerProcess")] = QVariant(); options.push_back(std::make_pair("__OwningControllerProcess",std::string()));
setConfiguration(options); setConfiguration(options);
} }
bool TorControl::torVersionAsNewAs(const QString &match) const bool TorControl::torVersionAsNewAs(const std::string& match) const
{ {
QRegularExpression r(QStringLiteral("[.-]")); QRegularExpression r(QStringLiteral("[.-]"));
QStringList split = torVersion().split(r); QStringList split = torVersion().split(r);

View file

@ -38,6 +38,7 @@
#include <QObject> #include <QObject>
#include <QHostAddress> #include <QHostAddress>
#include "PendingOperation.h" #include "PendingOperation.h"
#include "bytearray.h"
class QNetworkProxy; class QNetworkProxy;
@ -86,9 +87,9 @@ public:
/* Information */ /* Information */
Status status() const; Status status() const;
TorStatus torStatus() const; TorStatus torStatus() const;
QString torVersion() const; std::string torVersion() const;
bool torVersionAsNewAs(const QString &version) const; bool torVersionAsNewAs(const std::string &version) const;
QString errorMessage() const; std::string errorMessage() const;
bool hasConnectivity() const; bool hasConnectivity() const;
QHostAddress socksAddress() const; QHostAddress socksAddress() const;
@ -96,7 +97,7 @@ public:
QNetworkProxy connectionProxy(); QNetworkProxy connectionProxy();
/* Authentication */ /* Authentication */
void setAuthPassword(const QByteArray &password); void setAuthPassword(const ByteArray& password);
/* Connection */ /* Connection */
bool isConnected() const { return status() == Connected; } bool isConnected() const { return status() == Connected; }
@ -111,9 +112,9 @@ public:
QList<HiddenService*> hiddenServices() const; QList<HiddenService*> hiddenServices() const;
void addHiddenService(HiddenService *service); void addHiddenService(HiddenService *service);
QVariantMap bootstrapStatus() const; std::map<std::string, std::string> bootstrapStatus() const;
Q_INVOKABLE QObject *getConfiguration(const QString &options); Q_INVOKABLE QObject *getConfiguration(const std::string &options);
Q_INVOKABLE QObject *setConfiguration(const QVariantMap &options); Q_INVOKABLE QObject *setConfiguration(const std::list<std::pair<std::string, std::string> > &options);
Q_INVOKABLE PendingOperation *saveConfiguration(); Q_INVOKABLE PendingOperation *saveConfiguration();
signals: signals:

View file

@ -49,24 +49,27 @@ TorControlSocket::~TorControlSocket()
clear(); clear();
} }
void TorControlSocket::sendCommand(TorControlCommand *command, const QByteArray &data) void TorControlSocket::sendCommand(TorControlCommand *command, const ByteArray &data)
{ {
Q_ASSERT(data.endsWith("\r\n")); assert(data.endsWith(ByteArray("\r\n")));
commandQueue.push_back(command); commandQueue.push_back(command);
write(data); write(data);
std::cerr << "[TOR CTRL] Sent: \"" << QString(data.trimmed()).toStdString() << "\"" << std::endl; std::cerr << "[TOR CTRL] Sent: \"" << data.trimmed().toString() << "\"" << std::endl;
} }
void TorControlSocket::registerEvent(const QByteArray &event, TorControlCommand *command) void TorControlSocket::registerEvent(const ByteArray &event, TorControlCommand *command)
{ {
eventCommands.insert(event, command); eventCommands.insert(std::make_pair(event, command));
QByteArray data("SETEVENTS"); ByteArray data("SETEVENTS");
foreach (const QByteArray &key, eventCommands.keys()) { for(auto it:eventCommands)
{
//const ByteArray &key, eventCommands.keys()) {
//data += key;
data += ' '; data += ' ';
data += key; data += it.first;
} }
data += "\r\n"; data += "\r\n";
@ -96,9 +99,9 @@ void TorControlSocket::process()
if (!canReadLine()) if (!canReadLine())
return; return;
QByteArray line = readLine(5120); ByteArray line = readLine(5120);
if (!line.endsWith("\r\n")) { if (!line.endsWith(ByteArray("\r\n"))) {
setError(QStringLiteral("Invalid control message syntax")); setError("Invalid control message syntax");
return; return;
} }
line.chop(2); line.chop(2);
@ -117,7 +120,7 @@ void TorControlSocket::process()
} }
if (line.size() < 4) { if (line.size() < 4) {
setError(QStringLiteral("Invalid control message syntax")); setError("Invalid control message syntax");
return; return;
} }
@ -130,7 +133,7 @@ void TorControlSocket::process()
line = line.mid(4); line = line.mid(4);
if (!isFinalReply && !inDataReply && type != '-') { if (!isFinalReply && !inDataReply && type != '-') {
setError(QStringLiteral("Invalid control message syntax")); setError("Invalid control message syntax");
return; return;
} }
@ -142,7 +145,7 @@ void TorControlSocket::process()
currentCommand = eventCommands.value(line.mid(0, space)); currentCommand = eventCommands.value(line.mid(0, space));
if (!currentCommand) { if (!currentCommand) {
qWarning() << "torctrl: Ignoring unknown event"; RsWarn() << "torctrl: Ignoring unknown event";
continue; continue;
} }
} }
@ -155,19 +158,19 @@ void TorControlSocket::process()
continue; continue;
} }
if (commandQueue.isEmpty()) { if (commandQueue.empty()) {
qWarning() << "torctrl: Received unexpected data"; RsWarn() << "torctrl: Received unexpected data";
continue; continue;
} }
TorControlCommand *command = commandQueue.first(); TorControlCommand *command = commandQueue.front();
if (command) if (command)
command->onReply(statusCode, line); command->onReply(statusCode, line);
if (inDataReply) { if (inDataReply) {
currentCommand = command; currentCommand = command;
} else if (isFinalReply) { } else if (isFinalReply) {
commandQueue.takeFirst(); commandQueue.pop_front();
if (command) { if (command) {
command->onFinished(statusCode); command->onFinished(statusCode);
command->deleteLater(); command->deleteLater();

View file

@ -33,6 +33,7 @@
#pragma once #pragma once
#include "pqi/rstcpsocket.h" #include "pqi/rstcpsocket.h"
#include "bytearray.h"
namespace Tor namespace Tor
{ {
@ -47,10 +48,10 @@ public:
std::string errorMessage() const { return m_errorMessage; } std::string errorMessage() const { return m_errorMessage; }
void registerEvent(const QByteArray &event, TorControlCommand *handler); void registerEvent(const ByteArray &event, TorControlCommand *handler);
void sendCommand(const std::string& data) { sendCommand(0, data); } void sendCommand(const std::string& data) { sendCommand(0, data); }
void sendCommand(TorControlCommand *command, const QByteArray &data); void sendCommand(TorControlCommand *command, const ByteArray &data);
signals: signals:
void error(const QString &message); void error(const QString &message);
@ -61,7 +62,7 @@ private slots:
private: private:
std::list<TorControlCommand*> commandQueue; std::list<TorControlCommand*> commandQueue;
QHash<QByteArray,TorControlCommand*> eventCommands; std::map<ByteArray,TorControlCommand*> eventCommands;
std::string m_errorMessage; std::string m_errorMessage;
TorControlCommand *currentCommand; TorControlCommand *currentCommand;
bool inDataReply; bool inDataReply;
@ -70,5 +71,3 @@ private:
}; };
} }
#endif // TORCONTROLSOCKET_H

View file

@ -31,6 +31,7 @@
*/ */
#include <iostream> #include <iostream>
#include <fstream>
// This works on linux only. I have no clue how to do that on windows. Anyway, this // This works on linux only. I have no clue how to do that on windows. Anyway, this
// is only needed for an assert that should normaly never be triggered. // is only needed for an assert that should normaly never be triggered.
@ -67,25 +68,25 @@ public:
TorManager *q; TorManager *q;
TorProcess *process; TorProcess *process;
TorControl *control; TorControl *control;
QString dataDir; std::string dataDir;
QString hiddenServiceDir; std::string hiddenServiceDir;
QStringList logMessages; std::list<std::string> logMessages;
QString errorMessage; std::string errorMessage;
bool configNeeded; bool configNeeded;
HiddenService *hiddenService ; HiddenService *hiddenService ;
explicit TorManagerPrivate(TorManager *parent = 0); explicit TorManagerPrivate(TorManager *parent = 0);
QString torExecutablePath() const; std::string torExecutablePath() const;
bool createDataDir(const QString &path); bool createDataDir(const std::string &path);
bool createDefaultTorrc(const QString &path); bool createDefaultTorrc(const std::string &path);
void setError(const QString &errorMessage); void setError(const std::string &errorMessage);
virtual void processStateChanged(int state) override; virtual void processStateChanged(int state) override;
virtual void processErrorChanged(const QString &errorMessage) override; virtual void processErrorChanged(const std::string &errorMessage) override;
virtual void processLogMessage(const QString &message) override; virtual void processLogMessage(const std::string &message) override;
public slots: public slots:
void controlStatusChanged(int status); void controlStatusChanged(int status);
@ -128,12 +129,12 @@ TorProcess *TorManager::process()
return d->process; return d->process;
} }
QString TorManager::torDataDirectory() const std::string TorManager::torDataDirectory() const
{ {
return d->dataDir; return d->dataDir;
} }
void TorManager::setTorDataDirectory(const QString &path) void TorManager::setTorDataDirectory(const std::string &path)
{ {
d->dataDir = QDir::fromNativeSeparators(path); d->dataDir = QDir::fromNativeSeparators(path);
@ -141,16 +142,16 @@ void TorManager::setTorDataDirectory(const QString &path)
d->dataDir.append(QLatin1Char('/')); d->dataDir.append(QLatin1Char('/'));
} }
QString TorManager::hiddenServiceDirectory() const std::string TorManager::hiddenServiceDirectory() const
{ {
return d->hiddenServiceDir; return d->hiddenServiceDir;
} }
void TorManager::setHiddenServiceDirectory(const QString &path) void TorManager::setHiddenServiceDirectory(const std::string &path)
{ {
d->hiddenServiceDir = QDir::fromNativeSeparators(path); d->hiddenServiceDir = QDir::fromNativeSeparators(path);
if (!d->hiddenServiceDir.isEmpty() && !d->hiddenServiceDir.endsWith(QLatin1Char('/'))) if (!d->hiddenServiceDir.empty() && !(d->hiddenServiceDir.back() == '/'))
d->hiddenServiceDir.append(QLatin1Char('/')); d->hiddenServiceDir += '/';
} }
bool TorManager::setupHiddenService() bool TorManager::setupHiddenService()
@ -161,34 +162,34 @@ bool TorManager::setupHiddenService()
return true ; return true ;
} }
QString keyData ;//= m_settings->read("serviceKey").toString(); std::string keyData ;//= m_settings->read("serviceKey").toString();
QString legacyDir = d->hiddenServiceDir; std::string legacyDir = d->hiddenServiceDir;
std::cerr << "TorManager: setting up hidden service." << std::endl; std::cerr << "TorManager: setting up hidden service." << std::endl;
if(legacyDir.isNull()) if(legacyDir.empty())
{ {
std::cerr << "legacy dir not set! Cannot proceed." << std::endl; std::cerr << "legacy dir not set! Cannot proceed." << std::endl;
return false ; return false ;
} }
std::cerr << "Using legacy dir: " << legacyDir.toStdString() << std::endl; std::cerr << "Using legacy dir: " << legacyDir << std::endl;
if (!legacyDir.isEmpty() && QFile::exists(legacyDir + QLatin1String("/private_key"))) if (!legacyDir.empty() && QFile::exists(legacyDir.c_str() + QLatin1String("/private_key")))
{ {
std::cerr << "Attempting to load key from legacy filesystem format in " << legacyDir.toStdString() << std::endl; std::cerr << "Attempting to load key from legacy filesystem format in " << legacyDir << std::endl;
CryptoKey key; CryptoKey key;
if (!key.loadFromFile(legacyDir + QLatin1String("/private_key"))) if (!key.loadFromFile(legacyDir + "/private_key"))
{ {
qWarning() << "Cannot load legacy format key from" << legacyDir << "for conversion"; RsWarn() << "Cannot load legacy format key from" << legacyDir << "for conversion";
return false; return false;
} }
d->hiddenService = new Tor::HiddenService(this,key, legacyDir); d->hiddenService = new Tor::HiddenService(this,key, legacyDir);
std::cerr << "Got key from legacy dir: " << std::endl; std::cerr << "Got key from legacy dir: " << std::endl;
std::cerr << key.bytes().toStdString() << std::endl; std::cerr << key.bytes().toHex().toString() << std::endl;
} }
else else
{ {
@ -239,11 +240,9 @@ void TorManager::hiddenServicePrivateKeyChanged()
if(!d->hiddenService) if(!d->hiddenService)
return ; return ;
QString key = QString::fromLatin1(d->hiddenService->privateKey().bytes()); std::string key = d->hiddenService->privateKey().bytes().toString();
QFile outfile(d->hiddenServiceDir + QLatin1String("/private_key")) ; std::ofstream s(d->hiddenServiceDir + "/private_key");
outfile.open( QIODevice::WriteOnly | QIODevice::Text );
QTextStream s(&outfile);
#ifdef TO_REMOVE #ifdef TO_REMOVE
s << "-----BEGIN RSA PRIVATE KEY-----" << endl; s << "-----BEGIN RSA PRIVATE KEY-----" << endl;
@ -255,10 +254,10 @@ void TorManager::hiddenServicePrivateKeyChanged()
#endif #endif
s << key ; s << key ;
outfile.close(); s.close();
std::cerr << "Hidden service private key changed!" << std::endl; std::cerr << "Hidden service private key changed!" << std::endl;
std::cerr << key.toStdString() << std::endl; std::cerr << key << std::endl;
} }
void TorManager::hiddenServiceHostnameChanged() void TorManager::hiddenServiceHostnameChanged()
@ -270,7 +269,7 @@ void TorManager::hiddenServiceHostnameChanged()
outfile2.open( QIODevice::WriteOnly | QIODevice::Text ); outfile2.open( QIODevice::WriteOnly | QIODevice::Text );
QTextStream t(&outfile2); QTextStream t(&outfile2);
QString hostname(d->hiddenService->hostname()); std::string hostname(d->hiddenService->hostname());
t << hostname << endl; t << hostname << endl;
outfile2.close(); outfile2.close();
@ -283,7 +282,7 @@ bool TorManager::configurationNeeded() const
return d->configNeeded; return d->configNeeded;
} }
QStringList TorManager::logMessages() const std::string TorManager::logMessages() const
{ {
return d->logMessages; return d->logMessages;
} }
@ -293,7 +292,7 @@ bool TorManager::hasError() const
return !d->errorMessage.isEmpty(); return !d->errorMessage.isEmpty();
} }
QString TorManager::errorMessage() const std::string TorManager::errorMessage() const
{ {
return d->errorMessage; return d->errorMessage;
} }
@ -306,7 +305,7 @@ bool TorManager::start()
//emit errorChanged(); // not needed because there's no error to handle //emit errorChanged(); // not needed because there's no error to handle
} }
SettingsObject settings(QStringLiteral("tor")); SettingsObject settings("tor");
// If a control port is defined by config or environment, skip launching tor // If a control port is defined by config or environment, skip launching tor
if (!settings.read("controlPort").isUndefined() || if (!settings.read("controlPort").isUndefined() ||
@ -317,7 +316,7 @@ bool TorManager::start()
QByteArray password = settings.read("controlPassword").toString().toLatin1(); QByteArray password = settings.read("controlPassword").toString().toLatin1();
if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_HOST")) if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_HOST"))
address = QHostAddress(QString::fromLatin1(qgetenv("TOR_CONTROL_HOST"))); address = QHostAddress(qgetenv("TOR_CONTROL_HOST"));
if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_PORT")) { if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_PORT")) {
bool ok = false; bool ok = false;
@ -330,7 +329,7 @@ bool TorManager::start()
password = qgetenv("TOR_CONTROL_PASSWD"); password = qgetenv("TOR_CONTROL_PASSWD");
if (!port) { if (!port) {
d->setError(QStringLiteral("Invalid control port settings from environment or configuration")); d->setError("Invalid control port settings from environment or configuration");
return false; return false;
} }
@ -341,12 +340,12 @@ bool TorManager::start()
d->control->connect(address, port); d->control->connect(address, port);
} else { } else {
// Launch a bundled Tor instance // Launch a bundled Tor instance
QString executable = d->torExecutablePath(); std::string executable = d->torExecutablePath();
std::cerr << "Executable path: " << executable.toStdString() << std::endl; std::cerr << "Executable path: " << executable.toStdString() << std::endl;
if (executable.isEmpty()) { if (executable.isEmpty()) {
d->setError(QStringLiteral("Cannot find tor executable")); d->setError("Cannot find tor executable");
return false; return false;
} }
@ -354,22 +353,23 @@ bool TorManager::start()
d->process = new TorProcess(d); d->process = new TorProcess(d);
// QObject::connect(d->process, SIGNAL(stateChanged(int)), d, SLOT(processStateChanged(int))); // QObject::connect(d->process, SIGNAL(stateChanged(int)), d, SLOT(processStateChanged(int)));
// QObject::connect(d->process, SIGNAL(errorMessageChanged(QString)), d, SLOT(processErrorChanged(QString))); // QObject::connect(d->process, SIGNAL(errorMessageChanged(std::string)), d, SLOT(processErrorChanged(std::string)));
// QObject::connect(d->process, SIGNAL(logMessage(QString)), d, SLOT(processLogMessage(QString))); // QObject::connect(d->process, SIGNAL(logMessage(std::string)), d, SLOT(processLogMessage(std::string)));
} }
if (!QFile::exists(d->dataDir) && !d->createDataDir(d->dataDir)) { if (!QFile::exists(d->dataDir) && !d->createDataDir(d->dataDir)) {
d->setError(QStringLiteral("Cannot write data location: %1").arg(d->dataDir)); d->setError(std::string("Cannot write data location: ") + d->dataDir);
return false; return false;
} }
QString defaultTorrc = d->dataDir + QStringLiteral("default_torrc"); std::string defaultTorrc = d->dataDir + "default_torrc";
if (!QFile::exists(defaultTorrc) && !d->createDefaultTorrc(defaultTorrc)) { if (!QFile::exists(defaultTorrc) && !d->createDefaultTorrc(defaultTorrc))
d->setError(QStringLiteral("Cannot write data files: %1").arg(defaultTorrc)); {
d->setError("Cannot write data files: ")+defaultTorrc);
return false; return false;
} }
QFile torrc(d->dataDir + QStringLiteral("torrc")); QFile torrc(d->dataDir + "torrc");
if (!torrc.exists() || torrc.size() == 0) { if (!torrc.exists() || torrc.size() == 0) {
d->configNeeded = true; d->configNeeded = true;
@ -403,7 +403,7 @@ bool TorManager::getProxyServerInfo(QHostAddress& proxy_server_adress,uint16_t&
return proxy_server_port > 1023 ; return proxy_server_port > 1023 ;
} }
bool TorManager::getHiddenServiceInfo(QString& service_id,QString& service_onion_address,uint16_t& service_port, QHostAddress& service_target_address,uint16_t& target_port) bool TorManager::getHiddenServiceInfo(std::string& service_id,std::string& service_onion_address,uint16_t& service_port, QHostAddress& service_target_address,uint16_t& target_port)
{ {
QList<Tor::HiddenService*> hidden_services = control()->hiddenServices(); QList<Tor::HiddenService*> hidden_services = control()->hiddenServices();
@ -431,7 +431,7 @@ bool TorManager::getHiddenServiceInfo(QString& service_id,QString& service_onion
void TorManagerPrivate::processStateChanged(int state) void TorManagerPrivate::processStateChanged(int state)
{ {
std::cerr << Q_FUNC_INFO << "state: " << state << " passwd=\"" << QString(process->controlPassword()).toStdString() << "\" " << process->controlHost().toString().toStdString() std::cerr << Q_FUNC_INFO << "state: " << state << " passwd=\"" << std::string(process->controlPassword()).toStdString() << "\" " << process->controlHost().toString().toStdString()
<< ":" << process->controlPort() << std::endl; << ":" << process->controlPort() << std::endl;
if (state == TorProcess::Ready) { if (state == TorProcess::Ready) {
control->setAuthPassword(process->controlPassword()); control->setAuthPassword(process->controlPassword());
@ -439,18 +439,18 @@ void TorManagerPrivate::processStateChanged(int state)
} }
} }
void TorManagerPrivate::processErrorChanged(const QString &errorMessage) void TorManagerPrivate::processErrorChanged(const std::string &errorMessage)
{ {
std::cerr << "tor error:" << errorMessage.toStdString() << std::endl; std::cerr << "tor error:" << errorMessage << std::endl;
setError(errorMessage); setError(errorMessage);
} }
void TorManagerPrivate::processLogMessage(const QString &message) void TorManagerPrivate::processLogMessage(const std::string &message)
{ {
std::cerr << "tor:" << message.toStdString() << std::endl; std::cerr << "tor:" << message << std::endl;
if (logMessages.size() >= 50) if (logMessages.size() >= 50)
logMessages.takeFirst(); logMessages.pop_front();
logMessages.append(message); logMessages.push_back(message);
} }
void TorManagerPrivate::controlStatusChanged(int status) void TorManagerPrivate::controlStatusChanged(int status)
@ -458,7 +458,7 @@ void TorManagerPrivate::controlStatusChanged(int status)
if (status == TorControl::Connected) { if (status == TorControl::Connected) {
if (!configNeeded) { if (!configNeeded) {
// If DisableNetwork is 1, trigger configurationNeeded // If DisableNetwork is 1, trigger configurationNeeded
connect(control->getConfiguration(QStringLiteral("DisableNetwork")), connect(control->getConfiguration("DisableNetwork"),
SIGNAL(finished()), SLOT(getConfFinished())); SIGNAL(finished()), SLOT(getConfFinished()));
} }
@ -488,18 +488,18 @@ void TorManagerPrivate::getConfFinished()
} }
} }
QString TorManagerPrivate::torExecutablePath() const std::string TorManagerPrivate::torExecutablePath() const
{ {
SettingsObject settings(QStringLiteral("tor")); SettingsObject settings("tor");
QString path = settings.read("executablePath").toString(); std::string path = settings.read("executablePath").toString();
if (!path.isEmpty() && QFile::exists(path)) if (!path.isEmpty() && QFile::exists(path))
return path; return path;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QString filename(QStringLiteral("/tor/tor.exe")); std::string filename("/tor/tor.exe");
#else #else
QString filename(QStringLiteral("/tor")); std::string filename("/tor");
#endif #endif
path = qApp->applicationDirPath(); path = qApp->applicationDirPath();
@ -508,7 +508,7 @@ QString TorManagerPrivate::torExecutablePath() const
return path + filename; return path + filename;
#ifdef BUNDLED_TOR_PATH #ifdef BUNDLED_TOR_PATH
path = QStringLiteral(BUNDLED_TOR_PATH); path = BUNDLED_TOR_PATH;
if (QFile::exists(path + filename)) if (QFile::exists(path + filename))
return path + filename; return path + filename;
#endif #endif
@ -516,7 +516,7 @@ QString TorManagerPrivate::torExecutablePath() const
#ifdef __APPLE__ #ifdef __APPLE__
// on MacOS, try traditional brew installation path // on MacOS, try traditional brew installation path
path = QStringLiteral("/usr/local/opt/tor/bin") ; path = "/usr/local/opt/tor/bin" ;
if (QFile::exists(path + filename)) if (QFile::exists(path + filename))
return path + filename; return path + filename;
@ -526,13 +526,13 @@ QString TorManagerPrivate::torExecutablePath() const
return filename.mid(1); return filename.mid(1);
} }
bool TorManagerPrivate::createDataDir(const QString &path) bool TorManagerPrivate::createDataDir(const std::string &path)
{ {
QDir dir(path); QDir dir(path);
return dir.mkpath(QStringLiteral(".")); return dir.mkpath(".");
} }
bool TorManagerPrivate::createDefaultTorrc(const QString &path) bool TorManagerPrivate::createDefaultTorrc(const std::string &path)
{ {
static const char defaultTorrcContent[] = static const char defaultTorrcContent[] =
"SocksPort auto\n" "SocksPort auto\n"
@ -548,7 +548,7 @@ bool TorManagerPrivate::createDefaultTorrc(const QString &path)
return true; return true;
} }
void TorManagerPrivate::setError(const QString &message) void TorManagerPrivate::setError(const std::string &message)
{ {
errorMessage = message; errorMessage = message;
@ -557,7 +557,7 @@ void TorManagerPrivate::setError(const QString &message)
auto ev = std::make_shared<RsTorManagerEvent>(); auto ev = std::make_shared<RsTorManagerEvent>();
ev->mTorManagerEventType = RsTorManagerEventCode::TOR_MANAGER_ERROR; ev->mTorManagerEventType = RsTorManagerEventCode::TOR_MANAGER_ERROR;
ev->mErrorMessage = message.toStdString(); ev->mErrorMessage = message;
rsEvents->sendEvent(ev); rsEvents->sendEvent(ev);
} }
//emit q->errorChanged(); //emit q->errorChanged();
@ -567,7 +567,7 @@ void TorManagerPrivate::setError(const QString &message)
bool RsTor::isTorAvailable() bool RsTor::isTorAvailable()
{ {
return !instance()->d->torExecutablePath().isNull(); return !instance()->d->torExecutablePath().empty();
} }
bool RsTor::getHiddenServiceInfo(std::string& service_id, bool RsTor::getHiddenServiceInfo(std::string& service_id,
@ -576,15 +576,15 @@ bool RsTor::getHiddenServiceInfo(std::string& service_id,
std::string& service_target_address, std::string& service_target_address,
uint16_t& target_port) uint16_t& target_port)
{ {
QString sid; std::string sid;
QString soa; std::string soa;
QHostAddress sta; QHostAddress sta;
if(!instance()->getHiddenServiceInfo(sid,soa,service_port,sta,target_port)) if(!instance()->getHiddenServiceInfo(sid,soa,service_port,sta,target_port))
return false; return false;
service_id = sid.toStdString(); service_id = sid;
service_onion_address = soa.toStdString(); service_onion_address = soa;
service_target_address = sta.toString().toStdString(); service_target_address = sta.toString().toStdString();
return true; return true;
@ -592,13 +592,7 @@ bool RsTor::getHiddenServiceInfo(std::string& service_id,
std::list<std::string> RsTor::logMessages() std::list<std::string> RsTor::logMessages()
{ {
QStringList qs = instance()->logMessages(); return instance()->logMessages();
std::list<std::string> s;
for(auto& ss:qs)
s.push_back(ss.toStdString());
return s;
} }
std::string RsTor::socksAddress() std::string RsTor::socksAddress()
@ -652,7 +646,7 @@ RsTorHiddenServiceStatus RsTor::getHiddenServiceStatus(std::string& service_id)
if(list.empty()) if(list.empty())
return RsTorHiddenServiceStatus::NOT_CREATED; return RsTorHiddenServiceStatus::NOT_CREATED;
service_id = (*list.begin())->serviceId().toStdString(); service_id = (*list.begin())->serviceId();
switch((*list.begin())->status()) switch((*list.begin())->status())
{ {
@ -680,7 +674,7 @@ bool RsTor::hasError()
} }
std::string RsTor::errorMessage() std::string RsTor::errorMessage()
{ {
return instance()->errorMessage().toStdString(); return instance()->errorMessage();
} }
void RsTor::getProxyServerInfo(std::string& server_address, uint16_t& server_port) void RsTor::getProxyServerInfo(std::string& server_address, uint16_t& server_port)
@ -698,11 +692,11 @@ bool RsTor::start()
void RsTor::setTorDataDirectory(const std::string& dir) void RsTor::setTorDataDirectory(const std::string& dir)
{ {
instance()->setTorDataDirectory(QString::fromStdString(dir)); instance()->setTorDataDirectory(dir);
} }
void RsTor::setHiddenServiceDirectory(const std::string& dir) void RsTor::setHiddenServiceDirectory(const std::string& dir)
{ {
instance()->setHiddenServiceDirectory(QString::fromStdString(dir)); instance()->setHiddenServiceDirectory(dir);
} }
TorManager *RsTor::instance() TorManager *RsTor::instance()

View file

@ -38,7 +38,6 @@
#include "retroshare/rstor.h" #include "retroshare/rstor.h"
#include "HiddenService.h" #include "HiddenService.h"
#include <QStringList>
#include <QHostAddress> #include <QHostAddress>
namespace Tor namespace Tor
@ -70,11 +69,11 @@ public:
TorControl *control(); TorControl *control();
QString torDataDirectory() const; std::string torDataDirectory() const;
void setTorDataDirectory(const QString &path); void setTorDataDirectory(const std::string &path);
QString hiddenServiceDirectory() const; std::string hiddenServiceDirectory() const;
void setHiddenServiceDirectory(const QString &path); void setHiddenServiceDirectory(const std::string &path);
// Starts a hidden service, loading it from the config directory that has been set earlier. // Starts a hidden service, loading it from the config directory that has been set earlier.
bool setupHiddenService() ; bool setupHiddenService() ;
@ -82,12 +81,12 @@ public:
// True on first run or when the Tor configuration wizard needs to be shown // True on first run or when the Tor configuration wizard needs to be shown
bool configurationNeeded() const; bool configurationNeeded() const;
QStringList logMessages() const; std::list<std::string> logMessages() const;
bool hasError() const; bool hasError() const;
QString errorMessage() const; std::string errorMessage() const;
bool getHiddenServiceInfo(QString& service_id,QString& service_onion_address,uint16_t& service_port, QHostAddress& service_target_address,uint16_t& target_port); bool getHiddenServiceInfo(std::string& service_id,std::string& service_onion_address,uint16_t& service_port, QHostAddress& service_target_address,uint16_t& target_port);
bool getProxyServerInfo(QHostAddress& proxy_server_adress,uint16_t& proxy_server_port); bool getProxyServerInfo(QHostAddress& proxy_server_adress,uint16_t& proxy_server_port);
//public slots: //public slots:

View file

@ -30,6 +30,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include "util/rsdir.h"
#include "TorProcess_p.h" #include "TorProcess_p.h"
#include "CryptoKey.h" #include "CryptoKey.h"
#include "SecureRNG.h" #include "SecureRNG.h"
@ -64,42 +70,42 @@ TorProcessPrivate::TorProcessPrivate(TorProcess *q)
connect(&controlPortTimer, &QTimer::timeout, this, &TorProcessPrivate::tryReadControlPort); connect(&controlPortTimer, &QTimer::timeout, this, &TorProcessPrivate::tryReadControlPort);
} }
QString TorProcess::executable() const std::string TorProcess::executable() const
{ {
return d->executable; return d->executable;
} }
void TorProcess::setExecutable(const QString &path) void TorProcess::setExecutable(const std::string &path)
{ {
d->executable = path; d->executable = path;
} }
QString TorProcess::dataDir() const std::string TorProcess::dataDir() const
{ {
return d->dataDir; return d->dataDir;
} }
void TorProcess::setDataDir(const QString &path) void TorProcess::setDataDir(const std::string &path)
{ {
d->dataDir = path; d->dataDir = path;
} }
QString TorProcess::defaultTorrc() const std::string TorProcess::defaultTorrc() const
{ {
return d->defaultTorrc; return d->defaultTorrc;
} }
void TorProcess::setDefaultTorrc(const QString &path) void TorProcess::setDefaultTorrc(const std::string &path)
{ {
d->defaultTorrc = path; d->defaultTorrc = path;
} }
QStringList TorProcess::extraSettings() const std::list<std::string> TorProcess::extraSettings() const
{ {
return d->extraSettings; return d->extraSettings;
} }
void TorProcess::setExtraSettings(const QStringList &settings) void TorProcess::setExtraSettings(const std::list<std::string> &settings)
{ {
d->extraSettings = settings; d->extraSettings = settings;
} }
@ -109,7 +115,7 @@ TorProcess::State TorProcess::state() const
return d->state; return d->state;
} }
QString TorProcess::errorMessage() const std::string TorProcess::errorMessage() const
{ {
return d->errorMessage; return d->errorMessage;
} }
@ -121,8 +127,8 @@ void TorProcess::start()
d->errorMessage.clear(); d->errorMessage.clear();
if (d->executable.isEmpty() || d->dataDir.isEmpty()) { if (d->executable.empty() || d->dataDir.empty()) {
d->errorMessage = QStringLiteral("Tor executable and data directory not specified"); d->errorMessage = "Tor executable and data directory not specified";
d->state = Failed; d->state = Failed;
if(m_client) m_client->processStateChanged(d->state); // emit stateChanged(d->state); if(m_client) m_client->processStateChanged(d->state); // emit stateChanged(d->state);
@ -137,32 +143,50 @@ void TorProcess::start()
return; return;
} }
QByteArray password = controlPassword(); ByteArray password = controlPassword();
QByteArray hashedPassword = torControlHashedPassword(password); ByteArray hashedPassword = torControlHashedPassword(password);
if (password.isEmpty() || hashedPassword.isEmpty()) { if (password.empty() || hashedPassword.empty()) {
d->errorMessage = QStringLiteral("Random password generation failed"); d->errorMessage = "Random password generation failed";
d->state = Failed; d->state = Failed;
if(m_client) m_client->processErrorChanged(d->errorMessage);// emit errorMessageChanged(d->errorMessage); if(m_client) m_client->processErrorChanged(d->errorMessage);// emit errorMessageChanged(d->errorMessage);
if(m_client) m_client->processStateChanged(d->state); // emit stateChanged(d->state); if(m_client) m_client->processStateChanged(d->state); // emit stateChanged(d->state);
} }
QStringList args; std::list<std::string> args;
if (!d->defaultTorrc.isEmpty()) if (!d->defaultTorrc.empty())
args << QStringLiteral("--defaults-torrc") << d->defaultTorrc; {
args << QStringLiteral("-f") << d->torrcPath(); args.push_back("--defaults-torrc");
args << QStringLiteral("DataDirectory") << d->dataDir; args.push_back(d->defaultTorrc);
args << QStringLiteral("HashedControlPassword") << QString::fromLatin1(hashedPassword); }
args << QStringLiteral("ControlPort") << QStringLiteral("auto");
args << QStringLiteral("ControlPortWriteToFile") << d->controlPortFilePath(); args.push_back("-f");
args << QStringLiteral("__OwningControllerProcess") << QString::number(qApp->applicationPid()); args.push_back(d->torrcPath());
args << d->extraSettings;
args.push_back("DataDirectory") ;
args.push_back(d->dataDir);
args.push_back("HashedControlPassword") ;
args.push_back(hashedPassword.toString());
args.push_back("ControlPort") ;
args.push_back("auto");
args.push_back("ControlPortWriteToFile");
args.push_back(d->controlPortFilePath());
args.push_back("__OwningControllerProcess") ;
args.push_back(RsUtil::NumberToString(getpid()));
for(auto s:d->extraSettings)
args.push_back(s);
d->state = Starting; d->state = Starting;
if(m_client) m_client->processStateChanged(d->state);// emit stateChanged(d->state); if(m_client) m_client->processStateChanged(d->state);// emit stateChanged(d->state);
if (QFile::exists(d->controlPortFilePath())) if (RsDirUtil::fileExists(d->controlPortFilePath()))
QFile::remove(d->controlPortFilePath()); RsDirUtil::removeFile(d->controlPortFilePath());
d->controlPort = 0; d->controlPort = 0;
d->controlHost.clear(); d->controlHost.clear();
@ -204,21 +228,22 @@ void TorProcess::stateChanged(int newState)
if(m_client) if(m_client)
m_client->processStateChanged(newState); m_client->processStateChanged(newState);
} }
void TorProcess::errorMessageChanged(const QString &errorMessage) void TorProcess::errorMessageChanged(const std::string& errorMessage)
{ {
if(m_client) if(m_client)
m_client->processErrorChanged(errorMessage); m_client->processErrorChanged(errorMessage);
} }
void TorProcess::logMessage(const QString &message) void TorProcess::logMessage(const std::string& message)
{ {
if(m_client) if(m_client)
m_client->processLogMessage(message); m_client->processLogMessage(message);
} }
QByteArray TorProcess::controlPassword() ByteArray TorProcess::controlPassword()
{ {
if (d->controlPassword.isEmpty()) if (d->controlPassword.empty())
d->controlPassword = SecureRNG::randomPrintable(16); d->controlPassword = RsRandom::printable(16);
return d->controlPassword; return d->controlPassword;
} }
@ -234,29 +259,34 @@ quint16 TorProcess::controlPort()
bool TorProcessPrivate::ensureFilesExist() bool TorProcessPrivate::ensureFilesExist()
{ {
QFile torrc(torrcPath()); if(!RsDirUtil::checkCreateDirectory(dataDir))
if (!torrc.exists()) { {
QDir dir(dataDir); errorMessage = "Cannot create Tor data directory: " + dataDir;
if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) {
errorMessage = QStringLiteral("Cannot create Tor data directory: %1").arg(dataDir);
return false; return false;
} }
if (!torrc.open(QIODevice::ReadWrite)) { if (!RsDirUtil::fileExists(torrcPath()))
errorMessage = QStringLiteral("Cannot create Tor configuration file: %1").arg(torrcPath()); {
FILE *f = RsDirUtil::rs_fopen(torrcPath().c_str(),"w");
if(!f)
{
errorMessage = "Cannot create Tor configuration file: " + torrcPath();
return false; return false;
} }
else
fclose(f);
} }
return true; return true;
} }
QString TorProcessPrivate::torrcPath() const std::string TorProcessPrivate::torrcPath() const
{ {
return QDir::toNativeSeparators(dataDir) + QDir::separator() + QStringLiteral("torrc"); return QDir::toNativeSeparators(dataDir) + QDir::separator() + QStringLiteral("torrc");
} }
QString TorProcessPrivate::controlPortFilePath() const std::string TorProcessPrivate::controlPortFilePath() const
{ {
return QDir::toNativeSeparators(dataDir) + QDir::separator() + QStringLiteral("control-port"); return QDir::toNativeSeparators(dataDir) + QDir::separator() + QStringLiteral("control-port");
} }
@ -278,9 +308,11 @@ void TorProcessPrivate::processFinished()
return; return;
controlPortTimer.stop(); controlPortTimer.stop();
errorMessage = process.errorString(); errorMessage = process.errorString().toStdString();
if (errorMessage.isEmpty())
errorMessage = QStringLiteral("Process exited unexpectedly (code %1)").arg(process.exitCode()); if (errorMessage.empty())
errorMessage = "Process exited unexpectedly (code " + RsUtil::NumberToString(process.exitCode()) + ")";
state = TorProcess::Failed; state = TorProcess::Failed;
/*emit*/ q->errorMessageChanged(errorMessage); /*emit*/ q->errorMessageChanged(errorMessage);
/*emit*/ q->stateChanged(state); /*emit*/ q->stateChanged(state);
@ -294,22 +326,30 @@ void TorProcessPrivate::processError(QProcess::ProcessError error)
void TorProcessPrivate::processReadable() void TorProcessPrivate::processReadable()
{ {
while (process.bytesAvailable() > 0) { while (process.bytesAvailable() > 0)
QByteArray line = process.readLine(2048).trimmed(); {
if (!line.isEmpty()) ByteArray line = process.readLine(2048).trimmed();
/*emit*/ q->logMessage(QString::fromLatin1(line));
if (!line.empty())
/*emit*/ q->logMessage(line.toString()));
} }
} }
void TorProcessPrivate::tryReadControlPort() void TorProcessPrivate::tryReadControlPort()
{ {
QFile file(controlPortFilePath()); FILE *file = RsDirUtil::rs_fopen(controlPortFilePath().c_str(),"r");
if (file.open(QIODevice::ReadOnly)) {
QByteArray data = file.readLine().trimmed(); if(file)
{
char *line = nullptr;
size_t size = getline(&line,0,file);
ByteArray data = ByteArray((unsigned char*)line,size).trimmed();
free(line);
int p; int p;
if (data.startsWith("PORT=") && (p = data.lastIndexOf(':')) > 0) { if (data.startsWith("PORT=") && (p = data.lastIndexOf(':')) > 0) {
controlHost = QHostAddress(QString::fromLatin1(data.mid(5, p - 5))); controlHost = QHostAddress(data.mid(5, p - 5));
controlPort = data.mid(p+1).toUShort(); controlPort = data.mid(p+1).toUShort();
if (!controlHost.isNull() && controlPort > 0) { if (!controlHost.isNull() && controlPort > 0) {
@ -322,7 +362,7 @@ void TorProcessPrivate::tryReadControlPort()
} }
if (++controlPortAttempts * controlPortTimer.interval() > 10000) { if (++controlPortAttempts * controlPortTimer.interval() > 10000) {
errorMessage = QStringLiteral("No control port available after launching process"); errorMessage = "No control port available after launching process";
state = TorProcess::Failed; state = TorProcess::Failed;
/*emit*/ q->errorMessageChanged(errorMessage); /*emit*/ q->errorMessageChanged(errorMessage);
/*emit*/ q->stateChanged(state); /*emit*/ q->stateChanged(state);

View file

@ -36,6 +36,8 @@
#include <QObject> #include <QObject>
#include <QHostAddress> #include <QHostAddress>
#include "bytearray.h"
namespace Tor namespace Tor
{ {
@ -47,8 +49,8 @@ class TorProcessClient
{ {
public: public:
virtual void processStateChanged(int) = 0; virtual void processStateChanged(int) = 0;
virtual void processErrorChanged(const QString&) = 0; virtual void processErrorChanged(const std::string&) = 0;
virtual void processLogMessage(const QString&) = 0; virtual void processLogMessage(const std::string&) = 0;
}; };
/* Launches and controls a Tor instance with behavior suitable for bundling /* Launches and controls a Tor instance with behavior suitable for bundling
@ -59,7 +61,7 @@ class TorProcess
//Q_ENUMS(State) //Q_ENUMS(State)
//Q_PROPERTY(State state READ state NOTIFY stateChanged) //Q_PROPERTY(State state READ state NOTIFY stateChanged)
//Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged) //Q_PROPERTY(std::string errorMessage READ errorMessage NOTIFY errorMessageChanged)
public: public:
enum State { enum State {
@ -73,28 +75,28 @@ public:
explicit TorProcess(TorProcessClient *client,QObject *parent = 0); explicit TorProcess(TorProcessClient *client,QObject *parent = 0);
virtual ~TorProcess(); virtual ~TorProcess();
QString executable() const; std::string executable() const;
void setExecutable(const QString &path); void setExecutable(const std::string &path);
QString dataDir() const; std::string dataDir() const;
void setDataDir(const QString &path); void setDataDir(const std::string &path);
QString defaultTorrc() const; std::string defaultTorrc() const;
void setDefaultTorrc(const QString &path); void setDefaultTorrc(const std::string &path);
QStringList extraSettings() const; std::list<std::string> extraSettings() const;
void setExtraSettings(const QStringList &settings); void setExtraSettings(const std::list<std::string> &settings);
State state() const; State state() const;
QString errorMessage() const; std::string errorMessage() const;
QHostAddress controlHost(); QHostAddress controlHost();
quint16 controlPort(); quint16 controlPort();
QByteArray controlPassword(); ByteArray controlPassword();
//signals: //signals:
void stateChanged(int newState); void stateChanged(int newState);
void errorMessageChanged(const QString &errorMessage); void errorMessageChanged(const std::string &errorMessage);
void logMessage(const QString &message); void logMessage(const std::string &message);
//public slots: //public slots:
void start(); void start();

View file

@ -46,23 +46,23 @@ class TorProcessPrivate : public QObject
public: public:
TorProcess *q; TorProcess *q;
QProcess process; QProcess process;
QString executable; std::string executable;
QString dataDir; std::string dataDir;
QString defaultTorrc; std::string defaultTorrc;
QStringList extraSettings; std::list<std::string> extraSettings;
TorProcess::State state; TorProcess::State state;
QString errorMessage; std::string errorMessage;
QHostAddress controlHost; QHostAddress controlHost;
quint16 controlPort; quint16 controlPort;
QByteArray controlPassword; ByteArray controlPassword;
QTimer controlPortTimer; QTimer controlPortTimer;
int controlPortAttempts; int controlPortAttempts;
TorProcessPrivate(TorProcess *q); TorProcessPrivate(TorProcess *q);
QString torrcPath() const; std::string torrcPath() const;
QString controlPortFilePath() const; std::string controlPortFilePath() const;
bool ensureFilesExist(); bool ensureFilesExist();
public slots: public slots:

View file

@ -1,8 +1,11 @@
#pragma once
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <list>
#include "util/rsprint.h" #include "util/rsprint.h"
#include "util/rsdebug.h" #include "util/rsdebug.h"
@ -32,8 +35,10 @@ public:
ByteArray& operator+=(const char *b) { for(uint32_t n=0;b[n]!=0;++n) push_back(b[n]); return *this;} ByteArray& operator+=(const char *b) { for(uint32_t n=0;b[n]!=0;++n) push_back(b[n]); return *this;}
ByteArray left(uint32_t l) const { auto res = *this; res.resize(std::min((uint32_t)size(),l)); return res; } ByteArray left(uint32_t l) const { auto res = *this; res.resize(std::min((uint32_t)size(),l)); return res; }
ByteArray toUpper() const { auto res = *this; for(uint32_t i=0;i<size();++i) if( res[i]<='z' && res[i]>='a') res[i] += 'A'-'a'; return res; } ByteArray toUpper() const { auto res = *this; for(uint32_t i=0;i<size();++i) if( res[i]<='z' && res[i]>='a') res[i] += int('A')-int('a'); return res; }
ByteArray toLower() const { auto res = *this; for(uint32_t i=0;i<size();++i) if( res[i]<='Z' && res[i]>='A') res[i] += int('a')-int('A'); return res; }
bool endsWidth(const ByteArray& b) const { return size() >= b.size() && !memcmp(&data()[size()-b.size()],b.data(),b.size()); }
bool startsWith(const char *b) const bool startsWith(const char *b) const
{ {
for(uint32_t n=0;b[n]!=0;++n) for(uint32_t n=0;b[n]!=0;++n)
@ -88,4 +93,59 @@ public:
return res; return res;
} }
std::list<ByteArray> split(unsigned char sep)
{
std::list<ByteArray> res;
ByteArray current_block;
for(uint32_t i=0;i<size();++i)
if(operator[](i) == sep)
{
res.push_back(current_block);
current_block.clear();
}
else
current_block += operator[](i);
return res;
}
// Removes the following characters from the beginning and from the end of the array:
// '\t', '\n', '\v', '\f', '\r', and ' '.
ByteArray trimmed() const
{
auto res(*this);
while(!res.empty() && ( res.back() == '\t' || res.back() == '\n' || res.back() == '\v'
|| res.back() == '\f' || res.back() == '\r' || res.back() == ' ' ) )
res.pop_back();
uint32_t i=0;
for(;i<res.size();++i)
if(res[i] != '\t' && res[i] != '\n' && res[i] != '\v' && res[i] != '\f' && res[i] != '\r' && res[i] != ' ')
break;
return res.mid(i);
}
// Removes n bytes from the end of the array
void chop(uint32_t n)
{
resize(std::max(0,(int)size() - (int)n));
}
// Returns the last index of a given byte, -1 if not found.
int lastIndexOf(unsigned char s)
{
for(int i=size()-1;i>=0;--i)
if(operator[](i) == s)
return i;
return -1;
}
}; };

View file

@ -84,6 +84,25 @@ bool std::filesystem::create_directories(const std::string& path)
# include <filesystem> # include <filesystem>
#endif // __cplusplus < 201703L #endif // __cplusplus < 201703L
bool RsDirUtil::fileExists(const std::string& file_path)
{
FILE *f = fopen(file_path.c_str(),"r");
if(!f)
return false;
fclose(f);
return true;
}
std::string RsDirUtil::getFileName(const std::string& full_file_path)
{
size_t n = full_file_path.find_last_of('/');
if(n == std::string::npos)
return full_file_path;
else
return full_file_path.substr(n+1);
}
std::string RsDirUtil::getTopDir(const std::string& dir) std::string RsDirUtil::getTopDir(const std::string& dir)
{ {
std::string top; std::string top;

View file

@ -63,12 +63,15 @@ std::string getRootDir(const std::string&);
std::string removeRootDir(const std::string& path); std::string removeRootDir(const std::string& path);
void removeTopDir(const std::string& dir, std::string &path); void removeTopDir(const std::string& dir, std::string &path);
std::string removeRootDirs(const std::string& path, const std::string& root); std::string removeRootDirs(const std::string& path, const std::string& root);
std::string getFileName(const std::string& full_file_path);
// Renames file from to file to. Files should be on the same file system. // Renames file from to file to. Files should be on the same file system.
// returns true if succeed, false otherwise. // returns true if succeed, false otherwise.
bool renameFile(const std::string& from,const std::string& to) ; bool renameFile(const std::string& from,const std::string& to) ;
//bool createBackup (const std::string& sFilename, unsigned int nCount = 5); //bool createBackup (const std::string& sFilename, unsigned int nCount = 5);
bool fileExists(const std::string& file_path);
// returns the CRC32 of the data of length len // returns the CRC32 of the data of length len
// //
uint32_t rs_CRC32(const unsigned char *data,uint32_t len) ; uint32_t rs_CRC32(const unsigned char *data,uint32_t len) ;
@ -107,6 +110,12 @@ rstime_t lastWriteTime(
std::error_condition& errc = RS_DEFAULT_STORAGE_PARAM(std::error_condition) ); std::error_condition& errc = RS_DEFAULT_STORAGE_PARAM(std::error_condition) );
bool checkDirectory(const std::string& dir); bool checkDirectory(const std::string& dir);
/*!
* \brief checkCreateDirectory
* \param dir
* \return false when the directory does not exist and could not be created.
*/
bool checkCreateDirectory(const std::string& dir); bool checkCreateDirectory(const std::string& dir);
// Removes all symbolic links along the path and computes the actual location of the file/dir passed as argument. // Removes all symbolic links along the path and computes the actual location of the file/dir passed as argument.