From 5ca2d5e27bbe68c09b1488f579999b4ee6371c21 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 21 Dec 2017 10:43:28 +0100 Subject: [PATCH 01/42] added retrotor option in global .pri, and TorControl code --- .../src/TorControl/AddOnionCommand.cpp | 105 +++ .../src/TorControl/AddOnionCommand.h | 77 ++ .../src/TorControl/AuthenticateCommand.cpp | 64 ++ .../src/TorControl/AuthenticateCommand.h | 63 ++ retroshare-gui/src/TorControl/CryptoKey.cpp | 477 +++++++++++ retroshare-gui/src/TorControl/CryptoKey.h | 95 +++ .../src/TorControl/GetConfCommand.cpp | 124 +++ .../src/TorControl/GetConfCommand.h | 77 ++ .../src/TorControl/HiddenService.cpp | 137 ++++ retroshare-gui/src/TorControl/HiddenService.h | 104 +++ .../src/TorControl/PendingOperation.cpp | 84 ++ .../src/TorControl/PendingOperation.h | 87 ++ .../src/TorControl/ProtocolInfoCommand.cpp | 85 ++ .../src/TorControl/ProtocolInfoCommand.h | 78 ++ retroshare-gui/src/TorControl/SecureRNG.cpp | 146 ++++ retroshare-gui/src/TorControl/SecureRNG.h | 51 ++ .../src/TorControl/SetConfCommand.cpp | 106 +++ .../src/TorControl/SetConfCommand.h | 78 ++ retroshare-gui/src/TorControl/Settings.cpp | 553 +++++++++++++ retroshare-gui/src/TorControl/Settings.h | 257 ++++++ retroshare-gui/src/TorControl/StringUtil.cpp | 118 +++ retroshare-gui/src/TorControl/StringUtil.h | 46 ++ retroshare-gui/src/TorControl/TorControl.cpp | 763 ++++++++++++++++++ retroshare-gui/src/TorControl/TorControl.h | 141 ++++ .../src/TorControl/TorControlCommand.cpp | 63 ++ .../src/TorControl/TorControlCommand.h | 70 ++ .../src/TorControl/TorControlSocket.cpp | 176 ++++ .../src/TorControl/TorControlSocket.h | 77 ++ retroshare-gui/src/TorControl/TorManager.cpp | 335 ++++++++ retroshare-gui/src/TorControl/TorManager.h | 94 +++ retroshare-gui/src/TorControl/TorProcess.cpp | 311 +++++++ retroshare-gui/src/TorControl/TorProcess.h | 100 +++ retroshare-gui/src/TorControl/TorProcess_p.h | 79 ++ retroshare-gui/src/TorControl/TorSocket.cpp | 155 ++++ retroshare-gui/src/TorControl/TorSocket.h | 97 +++ retroshare-gui/src/TorControl/Useful.h | 71 ++ retroshare-gui/src/main.cpp | 26 +- retroshare-gui/src/retroshare-gui.pro | 46 +- retroshare.pri | 4 + 39 files changed, 5617 insertions(+), 3 deletions(-) create mode 100644 retroshare-gui/src/TorControl/AddOnionCommand.cpp create mode 100644 retroshare-gui/src/TorControl/AddOnionCommand.h create mode 100644 retroshare-gui/src/TorControl/AuthenticateCommand.cpp create mode 100644 retroshare-gui/src/TorControl/AuthenticateCommand.h create mode 100644 retroshare-gui/src/TorControl/CryptoKey.cpp create mode 100644 retroshare-gui/src/TorControl/CryptoKey.h create mode 100644 retroshare-gui/src/TorControl/GetConfCommand.cpp create mode 100644 retroshare-gui/src/TorControl/GetConfCommand.h create mode 100644 retroshare-gui/src/TorControl/HiddenService.cpp create mode 100644 retroshare-gui/src/TorControl/HiddenService.h create mode 100644 retroshare-gui/src/TorControl/PendingOperation.cpp create mode 100644 retroshare-gui/src/TorControl/PendingOperation.h create mode 100644 retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp create mode 100644 retroshare-gui/src/TorControl/ProtocolInfoCommand.h create mode 100644 retroshare-gui/src/TorControl/SecureRNG.cpp create mode 100644 retroshare-gui/src/TorControl/SecureRNG.h create mode 100644 retroshare-gui/src/TorControl/SetConfCommand.cpp create mode 100644 retroshare-gui/src/TorControl/SetConfCommand.h create mode 100644 retroshare-gui/src/TorControl/Settings.cpp create mode 100644 retroshare-gui/src/TorControl/Settings.h create mode 100644 retroshare-gui/src/TorControl/StringUtil.cpp create mode 100644 retroshare-gui/src/TorControl/StringUtil.h create mode 100644 retroshare-gui/src/TorControl/TorControl.cpp create mode 100644 retroshare-gui/src/TorControl/TorControl.h create mode 100644 retroshare-gui/src/TorControl/TorControlCommand.cpp create mode 100644 retroshare-gui/src/TorControl/TorControlCommand.h create mode 100644 retroshare-gui/src/TorControl/TorControlSocket.cpp create mode 100644 retroshare-gui/src/TorControl/TorControlSocket.h create mode 100644 retroshare-gui/src/TorControl/TorManager.cpp create mode 100644 retroshare-gui/src/TorControl/TorManager.h create mode 100644 retroshare-gui/src/TorControl/TorProcess.cpp create mode 100644 retroshare-gui/src/TorControl/TorProcess.h create mode 100644 retroshare-gui/src/TorControl/TorProcess_p.h create mode 100644 retroshare-gui/src/TorControl/TorSocket.cpp create mode 100644 retroshare-gui/src/TorControl/TorSocket.h create mode 100644 retroshare-gui/src/TorControl/Useful.h diff --git a/retroshare-gui/src/TorControl/AddOnionCommand.cpp b/retroshare-gui/src/TorControl/AddOnionCommand.cpp new file mode 100644 index 000000000..88ae232fd --- /dev/null +++ b/retroshare-gui/src/TorControl/AddOnionCommand.cpp @@ -0,0 +1,105 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2016, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "AddOnionCommand.h" +#include "HiddenService.h" +#include "CryptoKey.h" +#include "StringUtil.h" + +using namespace Tor; + +AddOnionCommand::AddOnionCommand(HiddenService *service) + : m_service(service) +{ + Q_ASSERT(m_service); +} + +bool AddOnionCommand::isSuccessful() const +{ + return statusCode() == 250 && m_errorMessage.isEmpty(); +} + +QByteArray AddOnionCommand::build() +{ + QByteArray out("ADD_ONION"); + + if (m_service->privateKey().isLoaded()) { + out += " RSA1024:"; + out += m_service->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64(); + } else { + out += " NEW:RSA1024"; + } + + foreach (const HiddenService::Target &target, m_service->targets()) { + out += " Port="; + out += QByteArray::number(target.servicePort); + out += ","; + out += target.targetAddress.toString().toLatin1(); + out += ":"; + out += QByteArray::number(target.targetPort); + } + + out.append("\r\n"); + return out; +} + +void AddOnionCommand::onReply(int statusCode, const QByteArray &data) +{ + TorControlCommand::onReply(statusCode, data); + if (statusCode != 250) { + m_errorMessage = QString::fromLatin1(data); + return; + } + + const QByteArray keyPrefix("PrivateKey=RSA1024:"); + if (data.startsWith(keyPrefix)) { + QByteArray keyData(QByteArray::fromBase64(data.mid(keyPrefix.size()))); + CryptoKey key; + if (!key.loadFromData(keyData, CryptoKey::PrivateKey, CryptoKey::DER)) { + m_errorMessage = QStringLiteral("Key decoding failed"); + return; + } + + m_service->setPrivateKey(key); + } +} + +void AddOnionCommand::onFinished(int statusCode) +{ + TorControlCommand::onFinished(statusCode); + if (isSuccessful()) + emit succeeded(); + else + emit failed(statusCode); +} + + diff --git a/retroshare-gui/src/TorControl/AddOnionCommand.h b/retroshare-gui/src/TorControl/AddOnionCommand.h new file mode 100644 index 000000000..7c0afaf5e --- /dev/null +++ b/retroshare-gui/src/TorControl/AddOnionCommand.h @@ -0,0 +1,77 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2016, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ADDONIONCOMMAND_H +#define ADDONIONCOMMAND_H + +#include "TorControlCommand.h" +#include +#include +#include + +namespace Tor +{ + +class HiddenService; + +class AddOnionCommand : public TorControlCommand +{ + Q_OBJECT + Q_DISABLE_COPY(AddOnionCommand) + + Q_PROPERTY(QString errorMessage READ errorMessage CONSTANT) + Q_PROPERTY(bool successful READ isSuccessful CONSTANT) + +public: + AddOnionCommand(HiddenService *service); + + QByteArray build(); + + QString errorMessage() const { return m_errorMessage; } + bool isSuccessful() const; + +signals: + void succeeded(); + void failed(int code); + +protected: + HiddenService *m_service; + QString m_errorMessage; + + virtual void onReply(int statusCode, const QByteArray &data); + virtual void onFinished(int statusCode); +}; + +} + +#endif // ADDONIONCOMMAND_H + diff --git a/retroshare-gui/src/TorControl/AuthenticateCommand.cpp b/retroshare-gui/src/TorControl/AuthenticateCommand.cpp new file mode 100644 index 000000000..497c28f89 --- /dev/null +++ b/retroshare-gui/src/TorControl/AuthenticateCommand.cpp @@ -0,0 +1,64 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "AuthenticateCommand.h" + +using namespace Tor; + +AuthenticateCommand::AuthenticateCommand() +{ +} + +QByteArray AuthenticateCommand::build(const QByteArray &data) +{ + if (data.isNull()) + return QByteArray("AUTHENTICATE\r\n"); + + return QByteArray("AUTHENTICATE ") + data.toHex() + "\r\n"; +} + +void AuthenticateCommand::onReply(int statusCode, const QByteArray &data) +{ + TorControlCommand::onReply(statusCode, data); + m_statusMessage = QString::fromLatin1(data); +} + +void AuthenticateCommand::onFinished(int statusCode) +{ + if (statusCode == 515) { + m_statusMessage = QStringLiteral("Authentication failed - incorrect password"); + } else if (statusCode != 250) { + if (m_statusMessage.isEmpty()) + m_statusMessage = QStringLiteral("Authentication failed (error %1").arg(statusCode); + } + TorControlCommand::onFinished(statusCode); +} diff --git a/retroshare-gui/src/TorControl/AuthenticateCommand.h b/retroshare-gui/src/TorControl/AuthenticateCommand.h new file mode 100644 index 000000000..79c901d98 --- /dev/null +++ b/retroshare-gui/src/TorControl/AuthenticateCommand.h @@ -0,0 +1,63 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AUTHENTICATECOMMAND_H +#define AUTHENTICATECOMMAND_H + +#include "TorControlCommand.h" + +namespace Tor +{ + +class AuthenticateCommand : public TorControlCommand +{ + Q_OBJECT + +public: + AuthenticateCommand(); + + QByteArray build(const QByteArray &data = QByteArray()); + + bool isSuccessful() const { return statusCode() == 250; } + QString errorMessage() const { return m_statusMessage; } + +protected: + virtual void onReply(int statusCode, const QByteArray &data); + virtual void onFinished(int statusCode); + +private: + QString m_statusMessage; +}; + +} + +#endif // AUTHENTICATECOMMAND_H diff --git a/retroshare-gui/src/TorControl/CryptoKey.cpp b/retroshare-gui/src/TorControl/CryptoKey.cpp new file mode 100644 index 000000000..8aa035754 --- /dev/null +++ b/retroshare-gui/src/TorControl/CryptoKey.cpp @@ -0,0 +1,477 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "CryptoKey.h" +#include "SecureRNG.h" +#include "Useful.h" +#include +#include +#include +#include +#include + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) +{ + *p = r->p; + *q = r->q; +} +#define RSA_bits(o) (BN_num_bits((o)->n)) +#endif + +void base32_encode(char *dest, unsigned destlen, const char *src, unsigned srclen); +bool base32_decode(char *dest, unsigned destlen, const char *src, unsigned srclen); + +CryptoKey::CryptoKey() +{ +} + +CryptoKey::~CryptoKey() +{ + clear(); +} + +CryptoKey::Data::~Data() +{ + if (key) + { + RSA_free(key); + key = 0; + } +} + +void CryptoKey::clear() +{ + d = 0; +} + +bool CryptoKey::loadFromData(const QByteArray &data, KeyType type, KeyFormat format) +{ + RSA *key = NULL; + clear(); + + if (data.isEmpty()) + return false; + + if (format == PEM) { + BIO *b = BIO_new_mem_buf((void*)data.constData(), -1); + + if (type == PrivateKey) + key = PEM_read_bio_RSAPrivateKey(b, NULL, NULL, NULL); + else + key = PEM_read_bio_RSAPublicKey(b, NULL, NULL, NULL); + + BIO_free(b); + } else if (format == DER) { + const uchar *dp = reinterpret_cast(data.constData()); + + if (type == PrivateKey) + key = d2i_RSAPrivateKey(NULL, &dp, data.size()); + else + key = d2i_RSAPublicKey(NULL, &dp, data.size()); + } else { + Q_UNREACHABLE(); + } + + if (!key) { + qWarning() << "Failed to parse" << (type == PrivateKey ? "private" : "public") << "key from data"; + return false; + } + + d = new Data(key); + return true; +} + +bool CryptoKey::loadFromFile(const QString &path, KeyType type, KeyFormat format) +{ + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) + { + qWarning() << "Failed to open" << (type == PrivateKey ? "private" : "public") << "key from" + << path << "-" << file.errorString(); + return false; + } + + QByteArray data = file.readAll(); + file.close(); + + return loadFromData(data, type, format); +} + +bool CryptoKey::isPrivate() const +{ + if (!isLoaded()) { + return false; + } else { + const BIGNUM *p, *q; + RSA_get0_factors(d->key, &p, &q); + return (p != 0); + } +} + +int CryptoKey::bits() const +{ + return isLoaded() ? RSA_bits(d->key) : 0; +} + +QByteArray CryptoKey::publicKeyDigest() const +{ + if (!isLoaded()) + return QByteArray(); + + QByteArray buf = encodedPublicKey(DER); + + QByteArray re(20, 0); + bool ok = SHA1(reinterpret_cast(buf.constData()), buf.size(), + reinterpret_cast(re.data())) != NULL; + + if (!ok) + { + qWarning() << "Failed to hash public key data for digest"; + return QByteArray(); + } + + return re; +} + +QByteArray CryptoKey::encodedPublicKey(KeyFormat format) const +{ + if (!isLoaded()) + return QByteArray(); + + if (format == PEM) { + BIO *b = BIO_new(BIO_s_mem()); + + if (!PEM_write_bio_RSAPublicKey(b, d->key)) { + BUG() << "Failed to encode public key in PEM format"; + BIO_free(b); + return QByteArray(); + } + + BUF_MEM *buf; + BIO_get_mem_ptr(b, &buf); + + /* Close BIO, but don't free buf. */ + (void)BIO_set_close(b, BIO_NOCLOSE); + BIO_free(b); + + QByteArray re((const char *)buf->data, (int)buf->length); + BUF_MEM_free(buf); + return re; + } else if (format == DER) { + uchar *buf = NULL; + int len = i2d_RSAPublicKey(d->key, &buf); + if (len <= 0 || !buf) { + BUG() << "Failed to encode public key in DER format"; + return QByteArray(); + } + + QByteArray re((const char*)buf, len); + OPENSSL_free(buf); + return re; + } else { + Q_UNREACHABLE(); + } + + return QByteArray(); +} + +QByteArray CryptoKey::encodedPrivateKey(KeyFormat format) const +{ + if (!isLoaded() || !isPrivate()) + return QByteArray(); + + if (format == PEM) { + BIO *b = BIO_new(BIO_s_mem()); + + if (!PEM_write_bio_RSAPrivateKey(b, d->key, NULL, NULL, 0, NULL, NULL)) { + BUG() << "Failed to encode private key in PEM format"; + BIO_free(b); + return QByteArray(); + } + + BUF_MEM *buf; + BIO_get_mem_ptr(b, &buf); + + /* Close BIO, but don't free buf. */ + (void)BIO_set_close(b, BIO_NOCLOSE); + BIO_free(b); + + QByteArray re((const char *)buf->data, (int)buf->length); + BUF_MEM_free(buf); + return re; + } else if (format == DER) { + uchar *buf = NULL; + int len = i2d_RSAPrivateKey(d->key, &buf); + if (len <= 0 || !buf) { + BUG() << "Failed to encode private key in DER format"; + return QByteArray(); + } + + QByteArray re((const char*)buf, len); + OPENSSL_free(buf); + return re; + } else { + Q_UNREACHABLE(); + } + + return QByteArray(); +} + +QString CryptoKey::torServiceID() const +{ + if (!isLoaded()) + return QString(); + + QByteArray digest = publicKeyDigest(); + if (digest.isNull()) + return QString(); + + static const int hostnameDigestSize = 10; + static const int hostnameEncodedSize = 16; + + QByteArray re(hostnameEncodedSize+1, 0); + base32_encode(re.data(), re.size(), digest.constData(), hostnameDigestSize); + + // Chop extra null byte + re.chop(1); + + return QString::fromLatin1(re); +} + +QByteArray CryptoKey::signData(const QByteArray &data) const +{ + QByteArray digest(32, 0); + bool ok = SHA256(reinterpret_cast(data.constData()), data.size(), + reinterpret_cast(digest.data())) != NULL; + if (!ok) { + qWarning() << "Digest for RSA signature failed"; + return QByteArray(); + } + + return signSHA256(digest); +} + +QByteArray CryptoKey::signSHA256(const QByteArray &digest) const +{ + if (!isPrivate()) + return QByteArray(); + + QByteArray re(RSA_size(d->key), 0); + unsigned sigsize = 0; + int r = RSA_sign(NID_sha256, reinterpret_cast(digest.constData()), digest.size(), + reinterpret_cast(re.data()), &sigsize, d->key); + + if (r != 1) { + qWarning() << "RSA encryption failed when generating signature"; + return QByteArray(); + } + + re.truncate(sigsize); + return re; +} + +bool CryptoKey::verifyData(const QByteArray &data, QByteArray signature) const +{ + QByteArray digest(32, 0); + bool ok = SHA256(reinterpret_cast(data.constData()), data.size(), + reinterpret_cast(digest.data())) != NULL; + + if (!ok) { + qWarning() << "Digest for RSA verify failed"; + return false; + } + + return verifySHA256(digest, signature); +} + +bool CryptoKey::verifySHA256(const QByteArray &digest, QByteArray signature) const +{ + if (!isLoaded()) + return false; + + int r = RSA_verify(NID_sha256, reinterpret_cast(digest.constData()), digest.size(), + reinterpret_cast(signature.data()), signature.size(), d->key); + if (r != 1) + return false; + return true; +} + +/* Cryptographic hash of a password as expected by Tor's HashedControlPassword */ +QByteArray torControlHashedPassword(const QByteArray &password) +{ + QByteArray salt = SecureRNG::random(8); + if (salt.isNull()) + return QByteArray(); + + int count = ((quint32)16 + (96 & 15)) << ((96 >> 4) + 6); + + SHA_CTX hash; + SHA1_Init(&hash); + + QByteArray tmp = salt + password; + while (count) + { + int c = qMin(count, tmp.size()); + SHA1_Update(&hash, reinterpret_cast(tmp.constData()), c); + count -= c; + } + + unsigned char md[20]; + SHA1_Final(md, &hash); + + /* 60 is the hex-encoded value of 96, which is a constant used by Tor's algorithm. */ + return QByteArray("16:") + salt.toHex().toUpper() + QByteArray("60") + + QByteArray::fromRawData(reinterpret_cast(md), 20).toHex().toUpper(); +} + +/* Copyright (c) 2001-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson + * Copyright (c) 2007-2010, The Tor Project, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567" + +/* Implements base32 encoding as in rfc3548. Requires that srclen*8 is a multiple of 5. */ +void base32_encode(char *dest, unsigned destlen, const char *src, unsigned srclen) +{ + unsigned i, bit, v, u; + unsigned nbits = srclen * 8; + + /* We need an even multiple of 5 bits, and enough space */ + if ((nbits%5) != 0 || destlen > (nbits/5)+1) { + Q_ASSERT(false); + memset(dest, 0, destlen); + return; + } + + for (i = 0, bit = 0; bit < nbits; ++i, bit += 5) + { + /* set v to the 16-bit value starting at src[bits/8], 0-padded. */ + v = ((quint8) src[bit / 8]) << 8; + if (bit + 5 < nbits) + v += (quint8) src[(bit/8)+1]; + + /* set u to the 5-bit value at the bit'th bit of src. */ + u = (v >> (11 - (bit % 8))) & 0x1F; + dest[i] = BASE32_CHARS[u]; + } + + dest[i] = '\0'; +} + +/* Implements base32 decoding as in rfc3548. Requires that srclen*5 is a multiple of 8. */ +bool base32_decode(char *dest, unsigned destlen, const char *src, unsigned srclen) +{ + unsigned int i, j, bit; + unsigned nbits = srclen * 5; + + /* We need an even multiple of 8 bits, and enough space */ + if ((nbits%8) != 0 || (nbits/8)+1 > destlen) { + Q_ASSERT(false); + return false; + } + + char *tmp = new char[srclen]; + + /* Convert base32 encoded chars to the 5-bit values that they represent. */ + for (j = 0; j < srclen; ++j) + { + if (src[j] > 0x60 && src[j] < 0x7B) + tmp[j] = src[j] - 0x61; + else if (src[j] > 0x31 && src[j] < 0x38) + tmp[j] = src[j] - 0x18; + else if (src[j] > 0x40 && src[j] < 0x5B) + tmp[j] = src[j] - 0x41; + else + { + delete[] tmp; + return false; + } + } + + /* Assemble result byte-wise by applying five possible cases. */ + for (i = 0, bit = 0; bit < nbits; ++i, bit += 8) + { + switch (bit % 40) + { + case 0: + dest[i] = (((quint8)tmp[(bit/5)]) << 3) + (((quint8)tmp[(bit/5)+1]) >> 2); + break; + case 8: + dest[i] = (((quint8)tmp[(bit/5)]) << 6) + (((quint8)tmp[(bit/5)+1]) << 1) + + (((quint8)tmp[(bit/5)+2]) >> 4); + break; + case 16: + dest[i] = (((quint8)tmp[(bit/5)]) << 4) + (((quint8)tmp[(bit/5)+1]) >> 1); + break; + case 24: + dest[i] = (((quint8)tmp[(bit/5)]) << 7) + (((quint8)tmp[(bit/5)+1]) << 2) + + (((quint8)tmp[(bit/5)+2]) >> 3); + break; + case 32: + dest[i] = (((quint8)tmp[(bit/5)]) << 5) + ((quint8)tmp[(bit/5)+1]); + break; + } + } + + delete[] tmp; + return true; +} diff --git a/retroshare-gui/src/TorControl/CryptoKey.h b/retroshare-gui/src/TorControl/CryptoKey.h new file mode 100644 index 000000000..70ada1977 --- /dev/null +++ b/retroshare-gui/src/TorControl/CryptoKey.h @@ -0,0 +1,95 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CRYPTOKEY_H +#define CRYPTOKEY_H + +#include +#include +#include + +class CryptoKey +{ +public: + enum KeyType { + PrivateKey, + PublicKey + }; + + enum KeyFormat { + PEM, + DER + }; + + CryptoKey(); + CryptoKey(const CryptoKey &other) : d(other.d) { } + ~CryptoKey(); + + bool loadFromData(const QByteArray &data, KeyType type, KeyFormat format = PEM); + bool loadFromFile(const QString &path, KeyType type, KeyFormat format = PEM); + void clear(); + + bool isLoaded() const { return d.data() && d->key != 0; } + bool isPrivate() const; + + QByteArray publicKeyDigest() const; + QByteArray encodedPublicKey(KeyFormat format) const; + QByteArray encodedPrivateKey(KeyFormat format) const; + QString torServiceID() const; + int bits() const; + + // Calculate and sign SHA-256 digest of data using this key and PKCS #1 v2.0 padding + QByteArray signData(const QByteArray &data) const; + // Verify a signature as per signData + bool verifyData(const QByteArray &data, QByteArray signature) const; + + // Sign the input SHA-256 digest using this key and PKCS #1 v2.0 padding + QByteArray signSHA256(const QByteArray &digest) const; + // Verify a signature as per signSHA256 + bool verifySHA256(const QByteArray &digest, QByteArray signature) const; + +private: + struct Data : public QSharedData + { + typedef struct rsa_st RSA; + RSA *key; + + Data(RSA *k = 0) : key(k) { } + ~Data(); + }; + + QExplicitlySharedDataPointer d; +}; + +QByteArray torControlHashedPassword(const QByteArray &password); + +#endif // CRYPTOKEY_H diff --git a/retroshare-gui/src/TorControl/GetConfCommand.cpp b/retroshare-gui/src/TorControl/GetConfCommand.cpp new file mode 100644 index 000000000..f7574f7fd --- /dev/null +++ b/retroshare-gui/src/TorControl/GetConfCommand.cpp @@ -0,0 +1,124 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "GetConfCommand.h" +#include "StringUtil.h" +#include + +using namespace Tor; + +GetConfCommand::GetConfCommand(Type t) + : type(t) +{ +} + +QByteArray GetConfCommand::build(const QByteArray &key) +{ + return build(QList() << key); +} + +QByteArray GetConfCommand::build(const QList &keys) +{ + QByteArray out; + if (type == GetConf) { + out = "GETCONF"; + } else if (type == GetInfo) { + out = "GETINFO"; + } else { + Q_ASSERT(false); + return out; + } + + foreach (const QByteArray &key, keys) { + out.append(' '); + out.append(key); + } + + out.append("\r\n"); + return out; +} + +void GetConfCommand::onReply(int statusCode, const QByteArray &data) +{ + TorControlCommand::onReply(statusCode, data); + if (statusCode != 250) + return; + + int kep = data.indexOf('='); + QString key = QString::fromLatin1(data.mid(0, kep)); + QVariant value; + if (kep >= 0) + value = QString::fromLatin1(unquotedString(data.mid(kep + 1))); + + m_lastKey = key; + QVariantMap::iterator it = m_results.find(key); + if (it != m_results.end()) { + // Make a list of values + QVariantList results = it->toList(); + if (results.isEmpty()) + results.append(*it); + results.append(value); + *it = QVariant(results); + } else { + m_results.insert(key, value); + } +} + +void GetConfCommand::onDataLine(const QByteArray &data) +{ + if (m_lastKey.isEmpty()) { + qWarning() << "torctrl: Unexpected data line in GetConf command"; + return; + } + + QVariantMap::iterator it = m_results.find(m_lastKey); + if (it != m_results.end()) { + QVariantList results = it->toList(); + if (results.isEmpty() && !it->toByteArray().isEmpty()) + results.append(*it); + results.append(data); + *it = QVariant(results); + } else { + m_results.insert(m_lastKey, QVariantList() << data); + } +} + +void GetConfCommand::onDataFinished() +{ + m_lastKey.clear(); +} + +QVariant GetConfCommand::get(const QByteArray &key) const +{ + return m_results.value(QString::fromLatin1(key)); +} + diff --git a/retroshare-gui/src/TorControl/GetConfCommand.h b/retroshare-gui/src/TorControl/GetConfCommand.h new file mode 100644 index 000000000..0de97d1b7 --- /dev/null +++ b/retroshare-gui/src/TorControl/GetConfCommand.h @@ -0,0 +1,77 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GETCONFCOMMAND_H +#define GETCONFCOMMAND_H + +#include "TorControlCommand.h" +#include +#include + +namespace Tor +{ + +class GetConfCommand : public TorControlCommand +{ + Q_OBJECT + Q_DISABLE_COPY(GetConfCommand) + + Q_PROPERTY(QVariantMap results READ results CONSTANT) + +public: + enum Type { + GetConf, + GetInfo + }; + const Type type; + + GetConfCommand(Type type); + + QByteArray build(const QByteArray &key); + QByteArray build(const QList &keys); + + const QVariantMap &results() const { return m_results; } + QVariant get(const QByteArray &key) const; + +protected: + virtual void onReply(int statusCode, const QByteArray &data); + virtual void onDataLine(const QByteArray &data); + virtual void onDataFinished(); + +private: + QVariantMap m_results; + QString m_lastKey; +}; + +} + +#endif // GETCONFCOMMAND_H diff --git a/retroshare-gui/src/TorControl/HiddenService.cpp b/retroshare-gui/src/TorControl/HiddenService.cpp new file mode 100644 index 000000000..e22576b5d --- /dev/null +++ b/retroshare-gui/src/TorControl/HiddenService.cpp @@ -0,0 +1,137 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "HiddenService.h" +#include "TorControl.h" +#include "TorSocket.h" +#include "CryptoKey.h" +#include "Useful.h" +#include +#include +#include +#include + +using namespace Tor; + +HiddenService::HiddenService(QObject *parent) + : QObject(parent), m_status(NotCreated) +{ +} + +HiddenService::HiddenService(const QString &path, QObject *parent) + : QObject(parent), m_dataPath(path), m_status(NotCreated) +{ + /* Set the initial status and, if possible, load the hostname */ + if (QDir(m_dataPath).exists(QLatin1String("private_key"))) { + loadPrivateKey(); + if (!m_hostname.isEmpty()) + m_status = Offline; + } +} + +HiddenService::HiddenService(const CryptoKey &privateKey, const QString &path, QObject *parent) + : QObject(parent), m_dataPath(path), m_status(NotCreated) +{ + setPrivateKey(privateKey); + m_status = Offline; +} + +void HiddenService::setStatus(Status newStatus) +{ + if (m_status == newStatus) + return; + + Status old = m_status; + m_status = newStatus; + + emit statusChanged(m_status, old); + + if (m_status == Online) + emit serviceOnline(); +} + +void HiddenService::addTarget(const Target &target) +{ + m_targets.append(target); +} + +void HiddenService::addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort) +{ + Target t = { targetAddress, servicePort, targetPort }; + m_targets.append(t); +} + +void HiddenService::setPrivateKey(const CryptoKey &key) +{ + if (m_privateKey.isLoaded()) { + BUG() << "Cannot change the private key on an existing HiddenService"; + return; + } + + if (!key.isPrivate()) { + BUG() << "Cannot create a hidden service with a public key"; + return; + } + + m_privateKey = key; + m_hostname = m_privateKey.torServiceID() + QStringLiteral(".onion"); + emit privateKeyChanged(); +} + +void HiddenService::loadPrivateKey() +{ + if (m_privateKey.isLoaded() || m_dataPath.isEmpty()) + return; + + bool ok = m_privateKey.loadFromFile(m_dataPath + QLatin1String("/private_key"), CryptoKey::PrivateKey); + if (!ok) { + qWarning() << "Failed to load hidden service key"; + return; + } + + m_hostname = m_privateKey.torServiceID(); + emit privateKeyChanged(); +} + +void HiddenService::servicePublished() +{ + loadPrivateKey(); + + if (m_hostname.isEmpty()) { + qDebug() << "Failed to read hidden service hostname"; + return; + } + + qDebug() << "Hidden service published successfully"; + setStatus(Online); +} + diff --git a/retroshare-gui/src/TorControl/HiddenService.h b/retroshare-gui/src/TorControl/HiddenService.h new file mode 100644 index 000000000..71c20a972 --- /dev/null +++ b/retroshare-gui/src/TorControl/HiddenService.h @@ -0,0 +1,104 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HIDDENSERVICE_H +#define HIDDENSERVICE_H + +#include +#include +#include +#include "CryptoKey.h" + +namespace Tor +{ + +class TorSocket; + +class HiddenService : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(HiddenService) + + friend class TorControlPrivate; + +public: + struct Target + { + QHostAddress targetAddress; + quint16 servicePort, targetPort; + }; + + enum Status + { + NotCreated = -1, /* Service has not been created yet */ + Offline = 0, /* Data exists, but service is not published */ + Online /* Published */ + }; + + HiddenService(QObject *parent = 0); + HiddenService(const QString &dataPath, QObject *parent = 0); + HiddenService(const CryptoKey &privateKey, const QString &dataPath = QString(), QObject *parent = 0); + + Status status() const { return m_status; } + + const QString &hostname() const { return m_hostname; } + const QString &dataPath() const { return m_dataPath; } + + CryptoKey privateKey() { return m_privateKey; } + void setPrivateKey(const CryptoKey &privateKey); + + const QList &targets() const { return m_targets; } + void addTarget(const Target &target); + void addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort); + +signals: + void statusChanged(int newStatus, int oldStatus); + void serviceOnline(); + void privateKeyChanged(); + +private slots: + void servicePublished(); + +private: + QString m_dataPath; + QList m_targets; + QString m_hostname; + Status m_status; + CryptoKey m_privateKey; + + void loadPrivateKey(); + void setStatus(Status newStatus); +}; + +} + +#endif // HIDDENSERVICE_H diff --git a/retroshare-gui/src/TorControl/PendingOperation.cpp b/retroshare-gui/src/TorControl/PendingOperation.cpp new file mode 100644 index 000000000..4a11f3e75 --- /dev/null +++ b/retroshare-gui/src/TorControl/PendingOperation.cpp @@ -0,0 +1,84 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PendingOperation.h" + +PendingOperation::PendingOperation(QObject *parent) + : QObject(parent), m_finished(false) +{ +} + +bool PendingOperation::isFinished() const +{ + return m_finished; +} + +bool PendingOperation::isSuccess() const +{ + return m_finished && m_errorMessage.isNull(); +} + +bool PendingOperation::isError() const +{ + return m_finished && !m_errorMessage.isNull(); +} + +QString PendingOperation::errorMessage() const +{ + return m_errorMessage; +} + +void PendingOperation::finishWithError(const QString &message) +{ + if (message.isEmpty()) + m_errorMessage = QStringLiteral("Unknown Error"); + m_errorMessage = message; + + if (!m_finished) { + m_finished = true; + emit finished(); + emit error(m_errorMessage); + } +} + +void PendingOperation::finishWithSuccess() +{ + Q_ASSERT(m_errorMessage.isNull()); + + if (!m_finished) { + m_finished = true; + emit finished(); + if (isSuccess()) + emit success(); + } +} + diff --git a/retroshare-gui/src/TorControl/PendingOperation.h b/retroshare-gui/src/TorControl/PendingOperation.h new file mode 100644 index 000000000..8f776a8d7 --- /dev/null +++ b/retroshare-gui/src/TorControl/PendingOperation.h @@ -0,0 +1,87 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PENDINGOPERATION_H +#define PENDINGOPERATION_H + +#include + +/* Represents an asynchronous operation for reporting status + * + * This class is used for asynchronous operations that report a + * status and errors when finished, particularly for exposing them + * to QML. + * + * Subclass PendingOperation to implement your operation's logic. + * You also need to handle the object's lifetime, for example by + * calling deleteLater() when finished() is emitted. + * + * PendingOperation will emit finished() and one of success() or + * error() when completed. + */ +class PendingOperation : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool isFinished READ isFinished NOTIFY finished FINAL) + Q_PROPERTY(bool isSuccess READ isSuccess NOTIFY success FINAL) + Q_PROPERTY(bool isError READ isError NOTIFY error FINAL) + Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY finished FINAL) + +public: + PendingOperation(QObject *parent = 0); + + bool isFinished() const; + bool isSuccess() const; + bool isError() const; + QString errorMessage() const; + +signals: + // Always emitted once when finished, regardless of status + void finished(); + + // One of error() or success() is emitted once + void error(const QString &errorMessage); + void success(); + +protected slots: + void finishWithError(const QString &errorMessage); + void finishWithSuccess(); + +private: + bool m_finished; + QString m_errorMessage; +}; + +Q_DECLARE_METATYPE(PendingOperation*) + +#endif diff --git a/retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp b/retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp new file mode 100644 index 000000000..ad8c9e3e6 --- /dev/null +++ b/retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp @@ -0,0 +1,85 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ProtocolInfoCommand.h" +#include "TorControl.h" +#include "StringUtil.h" +#include + +using namespace Tor; + +ProtocolInfoCommand::ProtocolInfoCommand(TorControl *m) + : manager(m) +{ +} + +QByteArray ProtocolInfoCommand::build() +{ + return QByteArray("PROTOCOLINFO 1\r\n"); +} + +void ProtocolInfoCommand::onReply(int statusCode, const QByteArray &data) +{ + TorControlCommand::onReply(statusCode, data); + if (statusCode != 250) + return; + + if (data.startsWith("AUTH ")) + { + QList tokens = splitQuotedStrings(data.mid(5), ' '); + + foreach (QByteArray token, tokens) + { + if (token.startsWith("METHODS=")) + { + QList textMethods = unquotedString(token.mid(8)).split(','); + for (QList::Iterator it = textMethods.begin(); it != textMethods.end(); ++it) + { + if (*it == "NULL") + m_authMethods |= AuthNull; + else if (*it == "HASHEDPASSWORD") + m_authMethods |= AuthHashedPassword; + else if (*it == "COOKIE") + m_authMethods |= AuthCookie; + } + } + else if (token.startsWith("COOKIEFILE=")) + { + m_cookieFile = QString::fromLatin1(unquotedString(token.mid(11))); + } + } + } + else if (data.startsWith("VERSION Tor=")) + { + m_torVersion = QString::fromLatin1(unquotedString(data.mid(12, data.indexOf(' ', 12)))); + } +} diff --git a/retroshare-gui/src/TorControl/ProtocolInfoCommand.h b/retroshare-gui/src/TorControl/ProtocolInfoCommand.h new file mode 100644 index 000000000..7789cfefd --- /dev/null +++ b/retroshare-gui/src/TorControl/ProtocolInfoCommand.h @@ -0,0 +1,78 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PROTOCOLINFOCOMMAND_H +#define PROTOCOLINFOCOMMAND_H + +#include "TorControlCommand.h" +#include + +namespace Tor +{ + +class TorControl; + +class ProtocolInfoCommand : public TorControlCommand +{ + Q_OBJECT + Q_DISABLE_COPY(ProtocolInfoCommand) + +public: + enum AuthMethod + { + AuthUnknown = 0, + AuthNull = 0x1, + AuthHashedPassword = 0x2, + AuthCookie = 0x4 + }; + Q_DECLARE_FLAGS(AuthMethods, AuthMethod) + + ProtocolInfoCommand(TorControl *manager); + QByteArray build(); + + AuthMethods authMethods() const { return m_authMethods; } + QString torVersion() const { return m_torVersion; } + QString cookieFile() const { return m_cookieFile; } + +protected: + virtual void onReply(int statusCode, const QByteArray &data); + +private: + TorControl *manager; + AuthMethods m_authMethods; + QString m_torVersion; + QString m_cookieFile; +}; + +} + +#endif // PROTOCOLINFOCOMMAND_H diff --git a/retroshare-gui/src/TorControl/SecureRNG.cpp b/retroshare-gui/src/TorControl/SecureRNG.cpp new file mode 100644 index 000000000..3a6eacd83 --- /dev/null +++ b/retroshare-gui/src/TorControl/SecureRNG.cpp @@ -0,0 +1,146 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SecureRNG.h" +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#include +#endif + +#if QT_VERSION >= 0x040700 +#include +#endif + +bool SecureRNG::seed() +{ +#if QT_VERSION >= 0x040700 + QElapsedTimer timer; + timer.start(); +#endif + +#ifdef Q_OS_WIN + /* RAND_poll is very unreliable on windows; with older versions of OpenSSL, + * it can take up to several minutes to run and has been known to crash. + * Even newer versions seem to take around 400ms, which is far too long for + * interactive startup. Random data from the windows CSP is used as a seed + * instead, as it should be very high quality random and fast. */ + HCRYPTPROV provider = 0; + if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + qWarning() << "Failed to acquire CSP context for RNG seed:" << hex << GetLastError(); + return false; + } + + /* Same amount of entropy OpenSSL uses, apparently. */ + char buf[32]; + + if (!CryptGenRandom(provider, sizeof(buf), reinterpret_cast(buf))) + { + qWarning() << "Failed to get entropy from CSP for RNG seed: " << hex << GetLastError(); + CryptReleaseContext(provider, 0); + return false; + } + + CryptReleaseContext(provider, 0); + + RAND_seed(buf, sizeof(buf)); + memset(buf, 0, sizeof(buf)); +#else + if (!RAND_poll()) + { + qWarning() << "OpenSSL RNG seed failed:" << ERR_get_error(); + return false; + } +#endif + +#if QT_VERSION >= 0x040700 + qDebug() << "RNG seed took" << timer.elapsed() << "ms"; +#endif + + return true; +} + +void SecureRNG::random(char *buf, int size) +{ + int r = RAND_bytes(reinterpret_cast(buf), size); + if (r <= 0) + qFatal("RNG failed: %lu", ERR_get_error()); +} + +QByteArray SecureRNG::random(int size) +{ + QByteArray re(size, 0); + random(re.data(), size); + return re; +} + +QByteArray SecureRNG::randomPrintable(int length) +{ + QByteArray re(length, 0); + for (int i = 0; i < re.size(); i++) + re[i] = randomInt(95) + 32; + return re; +} + +unsigned SecureRNG::randomInt(unsigned max) +{ + unsigned cutoff = UINT_MAX - (UINT_MAX % max); + unsigned value = 0; + + for (;;) + { + random(reinterpret_cast(&value), sizeof(value)); + if (value < cutoff) + return value % max; + } +} + +#ifndef UINT64_MAX +#define UINT64_MAX ((quint64)-1) +#endif + +quint64 SecureRNG::randomInt64(quint64 max) +{ + quint64 cutoff = UINT64_MAX - (UINT64_MAX % max); + quint64 value = 0; + + for (;;) + { + random(reinterpret_cast(value), sizeof(value)); + if (value < cutoff) + return value % max; + } +} diff --git a/retroshare-gui/src/TorControl/SecureRNG.h b/retroshare-gui/src/TorControl/SecureRNG.h new file mode 100644 index 000000000..f3b2a4b64 --- /dev/null +++ b/retroshare-gui/src/TorControl/SecureRNG.h @@ -0,0 +1,51 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SECURERNG_H +#define SECURERNG_H + +#include + +class SecureRNG +{ +public: + static bool seed(); + + static void random(char *buf, int size); + static QByteArray random(int size); + + static QByteArray randomPrintable(int length); + static unsigned randomInt(unsigned max); + static quint64 randomInt64(quint64 max); +}; + +#endif // SECURERNG_H diff --git a/retroshare-gui/src/TorControl/SetConfCommand.cpp b/retroshare-gui/src/TorControl/SetConfCommand.cpp new file mode 100644 index 000000000..fa4fd5b27 --- /dev/null +++ b/retroshare-gui/src/TorControl/SetConfCommand.cpp @@ -0,0 +1,106 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SetConfCommand.h" +#include "StringUtil.h" + +using namespace Tor; + +SetConfCommand::SetConfCommand() + : m_resetMode(false) +{ +} + +void SetConfCommand::setResetMode(bool enabled) +{ + m_resetMode = enabled; +} + +bool SetConfCommand::isSuccessful() const +{ + return statusCode() == 250; +} + +QByteArray SetConfCommand::build(const QByteArray &key, const QByteArray &value) +{ + return build(QList >() << qMakePair(key, value)); +} + +QByteArray SetConfCommand::build(const QVariantMap &data) +{ + QList > out; + + for (QVariantMap::ConstIterator it = data.begin(); it != data.end(); it++) { + QByteArray key = it.key().toLatin1(); + + if (static_cast(it.value().type()) == QMetaType::QVariantList) { + QVariantList values = it.value().value(); + foreach (const QVariant &value, values) + out.append(qMakePair(key, value.toString().toLatin1())); + } else { + out.append(qMakePair(key, it.value().toString().toLatin1())); + } + } + + return build(out); +} + +QByteArray SetConfCommand::build(const QList > &data) +{ + QByteArray out(m_resetMode ? "RESETCONF" : "SETCONF"); + + for (int i = 0; i < data.size(); i++) { + out += " " + data[i].first; + if (!data[i].second.isEmpty()) + out += "=" + quotedString(data[i].second); + } + + out.append("\r\n"); + return out; +} + +void SetConfCommand::onReply(int statusCode, const QByteArray &data) +{ + TorControlCommand::onReply(statusCode, data); + if (statusCode != 250) + m_errorMessage = QString::fromLatin1(data); +} + +void SetConfCommand::onFinished(int statusCode) +{ + TorControlCommand::onFinished(statusCode); + if (isSuccessful()) + emit setConfSucceeded(); + else + emit setConfFailed(statusCode); +} + diff --git a/retroshare-gui/src/TorControl/SetConfCommand.h b/retroshare-gui/src/TorControl/SetConfCommand.h new file mode 100644 index 000000000..5bdcb9329 --- /dev/null +++ b/retroshare-gui/src/TorControl/SetConfCommand.h @@ -0,0 +1,78 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SETCONFCOMMAND_H +#define SETCONFCOMMAND_H + +#include "TorControlCommand.h" +#include +#include +#include + +namespace Tor +{ + +class SetConfCommand : public TorControlCommand +{ + Q_OBJECT + Q_DISABLE_COPY(SetConfCommand) + + Q_PROPERTY(QString errorMessage READ errorMessage CONSTANT) + Q_PROPERTY(bool successful READ isSuccessful CONSTANT) + +public: + SetConfCommand(); + + void setResetMode(bool resetMode); + + QByteArray build(const QByteArray &key, const QByteArray &value); + QByteArray build(const QVariantMap &data); + QByteArray build(const QList > &data); + + QString errorMessage() const { return m_errorMessage; } + bool isSuccessful() const; + +signals: + void setConfSucceeded(); + void setConfFailed(int code); + +protected: + QString m_errorMessage; + bool m_resetMode; + + virtual void onReply(int statusCode, const QByteArray &data); + virtual void onFinished(int statusCode); +}; + +} + +#endif // SETCONFCOMMAND_H diff --git a/retroshare-gui/src/TorControl/Settings.cpp b/retroshare-gui/src/TorControl/Settings.cpp new file mode 100644 index 000000000..b20d330b7 --- /dev/null +++ b/retroshare-gui/src/TorControl/Settings.cpp @@ -0,0 +1,553 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Settings.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SettingsFilePrivate : public QObject +{ + Q_OBJECT + +public: + SettingsFile *q; + QString filePath; + QString errorMessage; + QTimer syncTimer; + QJsonObject jsonRoot; + SettingsObject *rootObject; + + SettingsFilePrivate(SettingsFile *qp); + virtual ~SettingsFilePrivate(); + + void reset(); + void setError(const QString &message); + bool checkDirPermissions(const QString &path); + bool readFile(); + bool writeFile(); + + static QStringList splitPath(const QString &input, bool &ok); + QJsonValue read(const QJsonObject &base, const QStringList &path); + bool write(const QStringList &path, const QJsonValue &value); + +signals: + void modified(const QStringList &path, const QJsonValue &value); + +private slots: + void sync(); +}; + +SettingsFile::SettingsFile(QObject *parent) + : QObject(parent), d(new SettingsFilePrivate(this)) +{ + d->rootObject = new SettingsObject(this, QString()); +} + +SettingsFile::~SettingsFile() +{ +} + +SettingsFilePrivate::SettingsFilePrivate(SettingsFile *qp) + : QObject(qp) + , q(qp) + , rootObject(0) +{ + syncTimer.setInterval(0); + syncTimer.setSingleShot(true); + connect(&syncTimer, &QTimer::timeout, this, &SettingsFilePrivate::sync); +} + +SettingsFilePrivate::~SettingsFilePrivate() +{ + if (syncTimer.isActive()) + sync(); + delete rootObject; +} + +void SettingsFilePrivate::reset() +{ + filePath.clear(); + errorMessage.clear(); + + jsonRoot = QJsonObject(); + emit modified(QStringList(), jsonRoot); +} + +QString SettingsFile::filePath() const +{ + return d->filePath; +} + +bool SettingsFile::setFilePath(const QString &filePath) +{ + if (d->filePath == filePath) + return hasError(); + + d->reset(); + d->filePath = filePath; + + QFileInfo fileInfo(filePath); + QDir dir(fileInfo.path()); + if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) { + d->setError(QStringLiteral("Cannot create directory: %1").arg(dir.path())); + return false; + } + d->checkDirPermissions(fileInfo.path()); + + if (!d->readFile()) + return false; + + return true; +} + +QString SettingsFile::errorMessage() const +{ + return d->errorMessage; +} + +bool SettingsFile::hasError() const +{ + return !d->errorMessage.isEmpty(); +} + +void SettingsFilePrivate::setError(const QString &message) +{ + errorMessage = message; + emit q->error(); +} + +bool SettingsFilePrivate::checkDirPermissions(const QString &path) +{ + static QFile::Permissions desired = QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ExeUser; + static QFile::Permissions ignored = QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner; + + QFile file(path); + if ((file.permissions() & ~ignored) != desired) { + qDebug() << "Correcting permissions on configuration directory"; + if (!file.setPermissions(desired)) { + qWarning() << "Correcting permissions on configuration directory failed"; + return false; + } + } + + return true; +} + +SettingsObject *SettingsFile::root() +{ + return d->rootObject; +} + +const SettingsObject *SettingsFile::root() const +{ + return d->rootObject; +} + +void SettingsFilePrivate::sync() +{ + if (filePath.isEmpty()) + return; + + syncTimer.stop(); + writeFile(); +} + +bool SettingsFilePrivate::readFile() +{ + QFile file(filePath); + if (!file.open(QIODevice::ReadWrite)) { + setError(file.errorString()); + return false; + } + + QByteArray data = file.readAll(); + if (data.isEmpty() && (file.error() != QFileDevice::NoError || file.size() > 0)) { + setError(file.errorString()); + return false; + } + + if (data.isEmpty()) { + jsonRoot = QJsonObject(); + return true; + } + + QJsonParseError parseError; + QJsonDocument document = QJsonDocument::fromJson(data, &parseError); + if (document.isNull()) { + setError(parseError.errorString()); + return false; + } + + if (!document.isObject()) { + setError(QStringLiteral("Invalid configuration file (expected object)")); + return false; + } + + jsonRoot = document.object(); + + emit modified(QStringList(), jsonRoot); + return true; +} + +bool SettingsFilePrivate::writeFile() +{ + QSaveFile file(filePath); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + setError(file.errorString()); + return false; + } + + QJsonDocument document(jsonRoot); + QByteArray data = document.toJson(); + if (data.isEmpty() && !document.isEmpty()) { + setError(QStringLiteral("Encoding failure")); + return false; + } + + if (file.write(data) < data.size() || !file.commit()) { + setError(file.errorString()); + return false; + } + + return true; +} + +QStringList SettingsFilePrivate::splitPath(const QString &input, bool &ok) +{ + QStringList components = input.split(QLatin1Char('.')); + + // Allow a leading '.' to simplify concatenation + if (!components.isEmpty() && components.first().isEmpty()) + components.takeFirst(); + + // No other empty components, including a trailing . + foreach (const QString &word, components) { + if (word.isEmpty()) { + ok = false; + return QStringList(); + } + } + + ok = true; + return components; +} + +QJsonValue SettingsFilePrivate::read(const QJsonObject &base, const QStringList &path) +{ + QJsonValue current = base; + + foreach (const QString &key, path) { + QJsonObject object = current.toObject(); + if (object.isEmpty() || (current = object.value(key)).isUndefined()) + return QJsonValue::Undefined; + } + + return current; +} + +// Compare two QJsonValue to find keys that have changed, +// recursing into objects and building paths as necessary. +typedef QList > ModifiedList; +static void findModifiedRecursive(ModifiedList &modified, const QStringList &path, const QJsonValue &oldValue, const QJsonValue &newValue) +{ + if (oldValue.isObject() || newValue.isObject()) { + // If either is a non-object type, this returns an empty object + QJsonObject oldObject = oldValue.toObject(); + QJsonObject newObject = newValue.toObject(); + + // Iterate keys of the original object and compare to new + for (QJsonObject::iterator it = oldObject.begin(); it != oldObject.end(); it++) { + QJsonValue newSubValue = newObject.value(it.key()); + if (*it == newSubValue) + continue; + + if ((*it).isObject() || newSubValue.isObject()) + findModifiedRecursive(modified, QStringList() << path << it.key(), *it, newSubValue); + else + modified.append(qMakePair(QStringList() << path << it.key(), newSubValue)); + } + + // Iterate keys of the new object that may not be in original + for (QJsonObject::iterator it = newObject.begin(); it != newObject.end(); it++) { + if (oldObject.contains(it.key())) + continue; + + if ((*it).isObject()) + findModifiedRecursive(modified, QStringList() << path << it.key(), QJsonValue::Undefined, it.value()); + else + modified.append(qMakePair(QStringList() << path << it.key(), it.value())); + } + } else + modified.append(qMakePair(path, newValue)); +} + +bool SettingsFilePrivate::write(const QStringList &path, const QJsonValue &value) +{ + typedef QVarLengthArray > ObjectStack; + ObjectStack stack; + QJsonValue current = jsonRoot; + QJsonValue originalValue; + QString currentKey; + + foreach (const QString &key, path) { + const QJsonObject &parent = current.toObject(); + stack.append(qMakePair(currentKey, parent)); + current = parent.value(key); + currentKey = key; + } + + // Stack now contains parent objects starting with the root, and current + // is the old value. Write back changes in reverse. + if (current == value) + return false; + originalValue = current; + current = value; + + ObjectStack::const_iterator it = stack.end(), begin = stack.begin(); + while (it != begin) { + --it; + QJsonObject update = it->second; + update.insert(currentKey, current); + current = update; + currentKey = it->first; + } + + // current is now the updated jsonRoot + jsonRoot = current.toObject(); + syncTimer.start(); + + ModifiedList modified; + findModifiedRecursive(modified, path, originalValue, value); + + for (ModifiedList::iterator it = modified.begin(); it != modified.end(); it++) + emit this->modified(it->first, it->second); + + return true; +} + +class SettingsObjectPrivate : public QObject +{ + Q_OBJECT + +public: + explicit SettingsObjectPrivate(SettingsObject *q); + + SettingsObject *q; + SettingsFile *file; + QStringList path; + QJsonObject object; + bool invalid; + + void setFile(SettingsFile *file); + +public slots: + void modified(const QStringList &absolutePath, const QJsonValue &value); +}; + +SettingsObject::SettingsObject(QObject *parent) + : QObject(parent) + , d(new SettingsObjectPrivate(this)) +{ + d->setFile(defaultFile()); + if (d->file) + setPath(QString()); +} + +SettingsObject::SettingsObject(const QString &path, QObject *parent) + : QObject(parent) + , d(new SettingsObjectPrivate(this)) +{ + d->setFile(defaultFile()); + setPath(path); +} + +SettingsObject::SettingsObject(SettingsFile *file, const QString &path, QObject *parent) + : QObject(parent) + , d(new SettingsObjectPrivate(this)) +{ + d->setFile(file); + setPath(path); +} + +SettingsObject::SettingsObject(SettingsObject *base, const QString &path, QObject *parent) + : QObject(parent) + , d(new SettingsObjectPrivate(this)) +{ + d->setFile(base->d->file); + setPath(base->path() + QLatin1Char('.') + path); +} + +SettingsObjectPrivate::SettingsObjectPrivate(SettingsObject *qp) + : QObject(qp) + , q(qp) + , file(0) + , invalid(true) +{ +} + +void SettingsObjectPrivate::setFile(SettingsFile *value) +{ + if (file == value) + return; + + if (file) + disconnect(file, 0, this, 0); + file = value; + if (file) + connect(file->d, &SettingsFilePrivate::modified, this, &SettingsObjectPrivate::modified); +} + +// Emit SettingsObject::modified with a relative path if path is matched +void SettingsObjectPrivate::modified(const QStringList &key, const QJsonValue &value) +{ + if (key.size() < path.size()) + return; + + for (int i = 0; i < path.size(); i++) { + if (path[i] != key[i]) + return; + } + + object = file->d->read(file->d->jsonRoot, path).toObject(); + emit q->modified(QStringList(key.mid(path.size())).join(QLatin1Char('.')), value); + emit q->dataChanged(); +} + +static QPointer defaultObjectFile; + +SettingsFile *SettingsObject::defaultFile() +{ + return defaultObjectFile; +} + +void SettingsObject::setDefaultFile(SettingsFile *file) +{ + defaultObjectFile = file; +} + +QString SettingsObject::path() const +{ + return d->path.join(QLatin1Char('.')); +} + +void SettingsObject::setPath(const QString &input) +{ + bool ok = false; + QStringList newPath = SettingsFilePrivate::splitPath(input, ok); + if (!ok) { + d->invalid = true; + d->path.clear(); + d->object = QJsonObject(); + + emit pathChanged(); + emit dataChanged(); + return; + } + + if (!d->invalid && d->path == newPath) + return; + + d->path = newPath; + if (d->file) { + d->invalid = false; + d->object = d->file->d->read(d->file->d->jsonRoot, d->path).toObject(); + emit dataChanged(); + } + + emit pathChanged(); +} + +QJsonObject SettingsObject::data() const +{ + return d->object; +} + +void SettingsObject::setData(const QJsonObject &input) +{ + if (d->invalid || d->object == input) + return; + + d->object = input; + d->file->d->write(d->path, d->object); +} + +QJsonValue SettingsObject::read(const QString &key, const QJsonValue &defaultValue) const +{ + bool ok = false; + QStringList splitKey = SettingsFilePrivate::splitPath(key, ok); + if (d->invalid || !ok || splitKey.isEmpty()) { + qDebug() << "Invalid settings read of path" << key; + return defaultValue; + } + + QJsonValue ret = d->file->d->read(d->object, splitKey); + if (ret.isUndefined()) + ret = defaultValue; + return ret; +} + +void SettingsObject::write(const QString &key, const QJsonValue &value) +{ + bool ok = false; + QStringList splitKey = SettingsFilePrivate::splitPath(key, ok); + if (d->invalid || !ok || splitKey.isEmpty()) { + qDebug() << "Invalid settings write of path" << key; + return; + } + + splitKey = d->path + splitKey; + d->file->d->write(splitKey, value); +} + +void SettingsObject::unset(const QString &key) +{ + write(key, QJsonValue()); +} + +void SettingsObject::undefine() +{ + if (d->invalid) + return; + + d->object = QJsonObject(); + d->file->d->write(d->path, QJsonValue::Undefined); +} + +#include "Settings.moc" diff --git a/retroshare-gui/src/TorControl/Settings.h b/retroshare-gui/src/TorControl/Settings.h new file mode 100644 index 000000000..79ad032d1 --- /dev/null +++ b/retroshare-gui/src/TorControl/Settings.h @@ -0,0 +1,257 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SETTINGS_H +#define SETTINGS_H + +#include +#include +#include +#include +#include +#include + +class SettingsObject; +class SettingsFilePrivate; +class SettingsObjectPrivate; + +/* SettingsFile represents a JSON-encoded configuration file. + * + * SettingsFile is an API for reading, writing, and change notification + * on JSON-encoded settings files. + * + * Data is accessed via SettingsObject, either using the root property + * or by creating a SettingsObject, optionally using a base path. + */ +class SettingsFile : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(SettingsFile) + + Q_PROPERTY(SettingsObject *root READ root CONSTANT) + Q_PROPERTY(QString filePath READ filePath WRITE setFilePath NOTIFY filePathChanged) + Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY error) + Q_PROPERTY(bool hasError READ hasError NOTIFY error) + +public: + explicit SettingsFile(QObject *parent = 0); + virtual ~SettingsFile(); + + QString filePath() const; + bool setFilePath(const QString &filePath); + + QString errorMessage() const; + bool hasError() const; + + SettingsObject *root(); + const SettingsObject *root() const; + +signals: + void filePathChanged(); + void error(); + +private: + SettingsFilePrivate *d; + + friend class SettingsObject; + friend class SettingsObjectPrivate; +}; + +/* SettingsObject reads and writes data within a SettingsFile + * + * A SettingsObject is associated with a SettingsFile and represents an object + * tree within that file. It refers to the JSON object tree using a path + * notation with keys separated by '.'. For example: + * + * { + * "one": { + * "two": { + * "three": "value" + * } + * } + * } + * + * With this data, a SettingsObject with an empty path can read with the path + * "one.two.three", and a SettingsObject with a path of "one.two" can simply + * read or write on "three". + * + * Multiple SettingsObjects may be created for the same path, and will be kept + * synchronized with changes. The modified signal is emitted for all changes + * affecting keys within a path, including writes of object trees and from other + * instances. + */ +class SettingsObject : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(SettingsObject) + + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) + Q_PROPERTY(QJsonObject data READ data WRITE setData NOTIFY dataChanged) + +public: + explicit SettingsObject(QObject *parent = 0); + explicit SettingsObject(const QString &path, QObject *parent = 0); + explicit SettingsObject(SettingsFile *file, const QString &path, QObject *parent = 0); + explicit SettingsObject(SettingsObject *base, const QString &path, QObject *parent = 0); + + /* Specify a SettingsFile to use by default on SettingsObject instances. + * + * After calling setDefaultFile, a SettingsObject created without any file, e.g.: + * + * SettingsObject settings; + * SettingsObject animals(QStringLiteral("animals")); + * + * Will use the specified SettingsFile instance by default. This is a convenience + * over passing around instances of SettingsFile in application use cases, and is + * particularly useful for QML. + */ + static SettingsFile *defaultFile(); + static void setDefaultFile(SettingsFile *file); + + QString path() const; + void setPath(const QString &path); + + QJsonObject data() const; + void setData(const QJsonObject &data); + + Q_INVOKABLE QJsonValue read(const QString &key, const QJsonValue &defaultValue = QJsonValue::Undefined) const; + template T read(const QString &key) const; + Q_INVOKABLE void write(const QString &key, const QJsonValue &value); + template void write(const QString &key, const T &value); + Q_INVOKABLE void unset(const QString &key); + + // const char* key overloads + QJsonValue read(const char *key, const QJsonValue &defaultValue = QJsonValue::Undefined) const + { + return read(QString::fromLatin1(key), defaultValue); + } + template T read(const char *key) const + { + return read(QString::fromLatin1(key)); + } + void write(const char *key, const QJsonValue &value) + { + write(QString::fromLatin1(key), value); + } + template void write(const char *key, const T &value) + { + write(QString::fromLatin1(key), value); + } + void unset(const char *key) + { + unset(QString::fromLatin1(key)); + } + + Q_INVOKABLE void undefine(); + +signals: + void pathChanged(); + void dataChanged(); + + void modified(const QString &path, const QJsonValue &value); + +private: + SettingsObjectPrivate *d; +}; + +template inline void SettingsObject::write(const QString &key, const T &value) +{ + write(key, QJsonValue(value)); +} + +template<> inline QString SettingsObject::read(const QString &key) const +{ + return read(key).toString(); +} + +template<> inline QJsonArray SettingsObject::read(const QString &key) const +{ + return read(key).toArray(); +} + +template<> inline QJsonObject SettingsObject::read(const QString &key) const +{ + return read(key).toObject(); +} + +template<> inline double SettingsObject::read(const QString &key) const +{ + return read(key).toDouble(); +} + +template<> inline int SettingsObject::read(const QString &key) const +{ + return read(key).toInt(); +} + +template<> inline bool SettingsObject::read(const QString &key) const +{ + return read(key).toBool(); +} + +template<> inline QDateTime SettingsObject::read(const QString &key) const +{ + QString value = read(key).toString(); + if (value.isEmpty()) + return QDateTime(); + return QDateTime::fromString(value, Qt::ISODate).toLocalTime(); +} + +template<> inline void SettingsObject::write(const QString &key, const QDateTime &value) +{ + write(key, QJsonValue(value.toUTC().toString(Qt::ISODate))); +} + +// Explicitly store value encoded as base64. Decodes and casts implicitly to QByteArray for reads. +class Base64Encode +{ +public: + explicit Base64Encode(const QByteArray &value) : d(value) { } + operator QByteArray() { return d; } + QByteArray encoded() const { return d.toBase64(); } + +private: + QByteArray d; +}; + +template<> inline Base64Encode SettingsObject::read(const QString &key) const +{ + return Base64Encode(QByteArray::fromBase64(read(key).toString().toLatin1())); +} + +template<> inline void SettingsObject::write(const QString &key, const Base64Encode &value) +{ + write(key, QJsonValue(QString::fromLatin1(value.encoded()))); +} + +#endif + diff --git a/retroshare-gui/src/TorControl/StringUtil.cpp b/retroshare-gui/src/TorControl/StringUtil.cpp new file mode 100644 index 000000000..8215d1351 --- /dev/null +++ b/retroshare-gui/src/TorControl/StringUtil.cpp @@ -0,0 +1,118 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "StringUtil.h" + +QByteArray quotedString(const QByteArray &string) +{ + QByteArray out; + out.reserve(string.size() * 2); + + out.append('"'); + + for (int i = 0; i < string.size(); ++i) + { + switch (string[i]) + { + case '"': + out.append("\\\""); + break; + case '\\': + out.append("\\\\"); + break; + default: + out.append(string[i]); + break; + } + } + + out.append('"'); + return out; +} + +QByteArray unquotedString(const QByteArray &string) +{ + if (string.size() < 2 || string[0] != '"') + return string; + + QByteArray out; + out.reserve(string.size() - 2); + + for (int i = 1; i < string.size(); ++i) + { + switch (string[i]) + { + case '\\': + if (++i < string.size()) + out.append(string[i]); + break; + case '"': + return out; + default: + out.append(string[i]); + } + } + + return out; +} + +QList splitQuotedStrings(const QByteArray &input, char separator) +{ + QList out; + bool inquote = false; + int start = 0; + + for (int i = 0; i < input.size(); ++i) + { + switch (input[i]) + { + case '"': + inquote = !inquote; + break; + case '\\': + if (inquote) + ++i; + break; + } + + if (!inquote && input[i] == separator) + { + out.append(input.mid(start, i - start)); + start = i+1; + } + } + + if (start < input.size()) + out.append(input.mid(start)); + + return out; +} diff --git a/retroshare-gui/src/TorControl/StringUtil.h b/retroshare-gui/src/TorControl/StringUtil.h new file mode 100644 index 000000000..c86d2c6ec --- /dev/null +++ b/retroshare-gui/src/TorControl/StringUtil.h @@ -0,0 +1,46 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STRINGUTIL_H +#define STRINGUTIL_H + +#include +#include + +QByteArray quotedString(const QByteArray &string); + +/* Return the unquoted contents of a string, either until an end quote or an unescaped separator character. */ +QByteArray unquotedString(const QByteArray &string); + +QList splitQuotedStrings(const QByteArray &input, char separator); + +#endif // STRINGUTIL_H diff --git a/retroshare-gui/src/TorControl/TorControl.cpp b/retroshare-gui/src/TorControl/TorControl.cpp new file mode 100644 index 000000000..8c5a1adee --- /dev/null +++ b/retroshare-gui/src/TorControl/TorControl.cpp @@ -0,0 +1,763 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TorControl.h" +#include "TorControlSocket.h" +#include "HiddenService.h" +#include "ProtocolInfoCommand.h" +#include "AuthenticateCommand.h" +#include "SetConfCommand.h" +#include "GetConfCommand.h" +#include "AddOnionCommand.h" +#include "StringUtil.h" +#include "Settings.h" +#include "PendingOperation.h" +#include +#include +#include +//#include +#include +#include +#include +#include + +Tor::TorControl *torControl = 0; + +using namespace Tor; + +namespace Tor { + +class TorControlPrivate : public QObject +{ + Q_OBJECT + +public: + TorControl *q; + + TorControlSocket *socket; + QHostAddress torAddress; + QString errorMessage; + QString torVersion; + QByteArray authPassword; + QHostAddress socksAddress; + QList services; + quint16 controlPort, socksPort; + TorControl::Status status; + TorControl::TorStatus torStatus; + QVariantMap bootstrapStatus; + bool hasOwnership; + + TorControlPrivate(TorControl *parent); + + void setStatus(TorControl::Status status); + void setTorStatus(TorControl::TorStatus status); + + void getTorInfo(); + void publishServices(); + +public slots: + void socketConnected(); + void socketDisconnected(); + void socketError(); + + void authenticateReply(); + void protocolInfoReply(); + void getTorInfoReply(); + void setError(const QString &message); + + void statusEvent(int code, const QByteArray &data); + void updateBootstrap(const QList &data); +}; + +} + +TorControl::TorControl(QObject *parent) + : QObject(parent), d(new TorControlPrivate(this)) +{ +} + +TorControlPrivate::TorControlPrivate(TorControl *parent) + : QObject(parent), q(parent), controlPort(0), socksPort(0), + status(TorControl::NotConnected), torStatus(TorControl::TorUnknown), + hasOwnership(false) +{ + socket = new TorControlSocket(this); + QObject::connect(socket, SIGNAL(connected()), this, SLOT(socketConnected())); + QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); + QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError())); + QObject::connect(socket, SIGNAL(error(QString)), this, SLOT(setError(QString))); +} + +QNetworkProxy TorControl::connectionProxy() +{ + return QNetworkProxy(QNetworkProxy::Socks5Proxy, d->socksAddress.toString(), d->socksPort); +} + +void TorControlPrivate::setStatus(TorControl::Status n) +{ + if (n == status) + return; + + TorControl::Status old = status; + status = n; + + if (old == TorControl::Error) + errorMessage.clear(); + + emit q->statusChanged(status, old); + + if (status == TorControl::Connected && old < TorControl::Connected) + emit q->connected(); + else if (status < TorControl::Connected && old >= TorControl::Connected) + emit q->disconnected(); +} + +void TorControlPrivate::setTorStatus(TorControl::TorStatus n) +{ + if (n == torStatus) + return; + + TorControl::TorStatus old = torStatus; + torStatus = n; + emit q->torStatusChanged(torStatus, old); + emit q->connectivityChanged(); + + if (torStatus == TorControl::TorReady && socksAddress.isNull()) { + // Request info again to read the SOCKS port + getTorInfo(); + } +} + +void TorControlPrivate::setError(const QString &message) +{ + errorMessage = message; + setStatus(TorControl::Error); + + qWarning() << "torctrl: Error:" << errorMessage; + + socket->abort(); + + QTimer::singleShot(15000, q, SLOT(reconnect())); +} + +TorControl::Status TorControl::status() const +{ + return d->status; +} + +TorControl::TorStatus TorControl::torStatus() const +{ + return d->torStatus; +} + +QString TorControl::torVersion() const +{ + return d->torVersion; +} + +QString TorControl::errorMessage() const +{ + return d->errorMessage; +} + +bool TorControl::hasConnectivity() const +{ + return torStatus() == TorReady && !d->socksAddress.isNull(); +} + +QHostAddress TorControl::socksAddress() const +{ + return d->socksAddress; +} + +quint16 TorControl::socksPort() const +{ + return d->socksPort; +} + +QList TorControl::hiddenServices() const +{ + return d->services; +} + +QVariantMap TorControl::bootstrapStatus() const +{ + return d->bootstrapStatus; +} + +void TorControl::setAuthPassword(const QByteArray &password) +{ + d->authPassword = password; +} + +void TorControl::connect(const QHostAddress &address, quint16 port) +{ + if (status() > Connecting) + { + qDebug() << "Ignoring TorControl::connect due to existing connection"; + return; + } + + d->torAddress = address; + d->controlPort = port; + d->setTorStatus(TorUnknown); + + bool b = d->socket->blockSignals(true); + d->socket->abort(); + d->socket->blockSignals(b); + + d->setStatus(Connecting); + d->socket->connectToHost(address, port); +} + +void TorControl::reconnect() +{ + Q_ASSERT(!d->torAddress.isNull() && d->controlPort); + if (d->torAddress.isNull() || !d->controlPort || status() >= Connecting) + return; + + d->setStatus(Connecting); + d->socket->connectToHost(d->torAddress, d->controlPort); +} + +void TorControlPrivate::authenticateReply() +{ + AuthenticateCommand *command = qobject_cast(sender()); + Q_ASSERT(command); + Q_ASSERT(status == TorControl::Authenticating); + if (!command) + return; + + if (!command->isSuccessful()) { + setError(command->errorMessage()); + return; + } + + qDebug() << "torctrl: Authentication successful"; + setStatus(TorControl::Connected); + + setTorStatus(TorControl::TorUnknown); + + TorControlCommand *clientEvents = new TorControlCommand; + connect(clientEvents, &TorControlCommand::replyLine, this, &TorControlPrivate::statusEvent); + socket->registerEvent("STATUS_CLIENT", clientEvents); + + getTorInfo(); + publishServices(); + + // XXX Fix old configurations that would store unwanted options in torrc. + // This can be removed some suitable amount of time after 1.0.4. + if (hasOwnership) + q->saveConfiguration(); +} + +void TorControlPrivate::socketConnected() +{ + Q_ASSERT(status == TorControl::Connecting); + + qDebug() << "torctrl: Connected socket; querying information"; + setStatus(TorControl::Authenticating); + + ProtocolInfoCommand *command = new ProtocolInfoCommand(q); + connect(command, &TorControlCommand::finished, this, &TorControlPrivate::protocolInfoReply); + socket->sendCommand(command, command->build()); +} + +void TorControlPrivate::socketDisconnected() +{ + /* Clear some internal state */ + torVersion.clear(); + socksAddress.clear(); + socksPort = 0; + setTorStatus(TorControl::TorUnknown); + + /* This emits the disconnected() signal as well */ + setStatus(TorControl::NotConnected); +} + +void TorControlPrivate::socketError() +{ + setError(QStringLiteral("Connection failed: %1").arg(socket->errorString())); +} + +void TorControlPrivate::protocolInfoReply() +{ + ProtocolInfoCommand *info = qobject_cast(sender()); + if (!info) + return; + + torVersion = info->torVersion(); + + if (status == TorControl::Authenticating) + { + AuthenticateCommand *auth = new AuthenticateCommand; + connect(auth, &TorControlCommand::finished, this, &TorControlPrivate::authenticateReply); + + QByteArray data; + ProtocolInfoCommand::AuthMethods methods = info->authMethods(); + + if (methods.testFlag(ProtocolInfoCommand::AuthNull)) + { + qDebug() << "torctrl: Using null authentication"; + data = auth->build(); + } + else if (methods.testFlag(ProtocolInfoCommand::AuthCookie) && !info->cookieFile().isEmpty()) + { + QString cookieFile = info->cookieFile(); + QString cookieError; + qDebug() << "torctrl: Using cookie authentication with file" << cookieFile; + + QFile file(cookieFile); + if (file.open(QIODevice::ReadOnly)) + { + QByteArray cookie = file.readAll(); + file.close(); + + /* Simple test to avoid a vulnerability where any process listening on what we think is + * the control port could trick us into sending the contents of an arbitrary file */ + if (cookie.size() == 32) + data = auth->build(cookie); + else + cookieError = QStringLiteral("Unexpected file size"); + } + else + cookieError = file.errorString(); + + if (!cookieError.isNull() || data.isNull()) + { + /* 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, + * but it has happened. */ + if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword) && !authPassword.isEmpty()) + { + qDebug() << "torctrl: Unable to read authentication cookie file:" << cookieError; + goto usePasswordAuth; + } + + setError(QStringLiteral("Unable to read authentication cookie file: %1").arg(cookieError)); + delete auth; + return; + } + } + else if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword) && !authPassword.isEmpty()) + { + usePasswordAuth: + qDebug() << "torctrl: Using hashed password authentication"; + data = auth->build(authPassword); + } + else + { + if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword)) + setError(QStringLiteral("Tor requires a control password to connect, but no password is configured.")); + else + setError(QStringLiteral("Tor is not configured to accept any supported authentication methods.")); + delete auth; + return; + } + + socket->sendCommand(auth, data); + } +} + +void TorControlPrivate::getTorInfo() +{ + Q_ASSERT(q->isConnected()); + + GetConfCommand *command = new GetConfCommand(GetConfCommand::GetInfo); + connect(command, &TorControlCommand::finished, this, &TorControlPrivate::getTorInfoReply); + + QList keys; + keys << QByteArray("status/circuit-established") << QByteArray("status/bootstrap-phase"); + + /* If these are set in the config, they override the automatic behavior. */ + SettingsObject settings(QStringLiteral("tor")); + QHostAddress forceAddress(settings.read("socksAddress").toString()); + quint16 port = (quint16)settings.read("socksPort").toInt(); + + if (!forceAddress.isNull() && port) { + qDebug() << "torctrl: Using manually specified SOCKS connection settings"; + socksAddress = forceAddress; + socksPort = port; + emit q->connectivityChanged(); + } else + keys << QByteArray("net/listeners/socks"); + + socket->sendCommand(command, command->build(keys)); +} + +void TorControlPrivate::getTorInfoReply() +{ + GetConfCommand *command = qobject_cast(sender()); + if (!command || !q->isConnected()) + return; + + QList listenAddresses = splitQuotedStrings(command->get(QByteArray("net/listeners/socks")).toString().toLatin1(), ' '); + for (QList::Iterator it = listenAddresses.begin(); it != listenAddresses.end(); ++it) { + QByteArray value = unquotedString(*it); + int sepp = value.indexOf(':'); + QHostAddress address(QString::fromLatin1(value.mid(0, sepp))); + quint16 port = (quint16)value.mid(sepp+1).toUInt(); + + /* Use the first address that matches the one used for this control connection. If none do, + * just use the first address and rely on the user to reconfigure if necessary (not a problem; + * their setup is already very customized) */ + if (socksAddress.isNull() || address == socket->peerAddress()) { + socksAddress = address; + socksPort = port; + if (address == socket->peerAddress()) + break; + } + } + + /* It is not immediately an error to have no SOCKS address; when DisableNetwork is set there won't be a + * listener yet. To handle that situation, we'll try to read the socks address again when TorReady state + * is reached. */ + if (!socksAddress.isNull()) { + qDebug().nospace() << "torctrl: SOCKS address is " << socksAddress.toString() << ":" << socksPort; + emit q->connectivityChanged(); + } + + if (command->get(QByteArray("status/circuit-established")).toInt() == 1) { + qDebug() << "torctrl: Tor indicates that circuits have been established; state is TorReady"; + setTorStatus(TorControl::TorReady); + } else { + setTorStatus(TorControl::TorOffline); + } + + QByteArray bootstrap = command->get(QByteArray("status/bootstrap-phase")).toString().toLatin1(); + if (!bootstrap.isEmpty()) + updateBootstrap(splitQuotedStrings(bootstrap, ' ')); +} + +void TorControl::addHiddenService(HiddenService *service) +{ + if (d->services.contains(service)) + return; + + d->services.append(service); +} + +void TorControlPrivate::publishServices() +{ + Q_ASSERT(q->isConnected()); + if (services.isEmpty()) + return; + + SettingsObject settings(QStringLiteral("tor")); + if (settings.read("neverPublishServices").toBool()) + { + qDebug() << "torctrl: Skipping service publication because neverPublishService is enabled"; + + /* Call servicePublished under the assumption that they're published externally. */ + for (QList::Iterator it = services.begin(); it != services.end(); ++it) + (*it)->servicePublished(); + + return; + } + + if (q->torVersionAsNewAs(QStringLiteral("0.2.7"))) { + foreach (HiddenService *service, services) { + if (service->hostname().isEmpty()) + qDebug() << "torctrl: Creating a new hidden service"; + else + qDebug() << "torctrl: Publishing hidden service" << service->hostname(); + AddOnionCommand *onionCommand = new AddOnionCommand(service); + QObject::connect(onionCommand, &AddOnionCommand::succeeded, service, &HiddenService::servicePublished); + socket->sendCommand(onionCommand, onionCommand->build()); + } + } else { + qDebug() << "torctrl: Using legacy SETCONF hidden service configuration for tor" << torVersion; + SetConfCommand *command = new SetConfCommand; + QList > torConfig; + + foreach (HiddenService *service, services) + { + if (service->dataPath().isEmpty()) + continue; + + if (service->privateKey().isLoaded() && !QFile::exists(service->dataPath() + QStringLiteral("/private_key"))) { + // 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"; + continue; + } + + qDebug() << "torctrl: Configuring hidden service at" << service->dataPath(); + + QDir dir(service->dataPath()); + torConfig.append(qMakePair(QByteArray("HiddenServiceDir"), dir.absolutePath().toLocal8Bit())); + + const QList &targets = service->targets(); + for (QList::ConstIterator tit = targets.begin(); tit != targets.end(); ++tit) + { + QString target = QString::fromLatin1("%1 %2:%3").arg(tit->servicePort) + .arg(tit->targetAddress.toString()) + .arg(tit->targetPort); + torConfig.append(qMakePair(QByteArray("HiddenServicePort"), target.toLatin1())); + } + + QObject::connect(command, &SetConfCommand::setConfSucceeded, service, &HiddenService::servicePublished); + } + + if (!torConfig.isEmpty()) + socket->sendCommand(command, command->build(torConfig)); + } +} + +void TorControl::shutdown() +{ + if (!hasOwnership()) { + qWarning() << "torctrl: Ignoring shutdown command for a tor instance I don't own"; + return; + } + + d->socket->sendCommand("SIGNAL SHUTDOWN\r\n"); +} + +void TorControl::shutdownSync() +{ + if (!hasOwnership()) { + qWarning() << "torctrl: Ignoring shutdown command for a tor instance I don't own"; + return; + } + + shutdown(); + while (d->socket->bytesToWrite()) + { + if (!d->socket->waitForBytesWritten(5000)) + return; + } +} + +void TorControlPrivate::statusEvent(int code, const QByteArray &data) +{ + Q_UNUSED(code); + + QList tokens = splitQuotedStrings(data.trimmed(), ' '); + if (tokens.size() < 3) + return; + + qDebug() << "torctrl: status event:" << data.trimmed(); + + if (tokens[2] == "CIRCUIT_ESTABLISHED") { + setTorStatus(TorControl::TorReady); + } else if (tokens[2] == "CIRCUIT_NOT_ESTABLISHED") { + setTorStatus(TorControl::TorOffline); + } else if (tokens[2] == "BOOTSTRAP") { + tokens.takeFirst(); + updateBootstrap(tokens); + } +} + +void TorControlPrivate::updateBootstrap(const QList &data) +{ + bootstrapStatus.clear(); + // WARN or NOTICE + bootstrapStatus[QStringLiteral("severity")] = data.value(0); + for (int i = 1; i < data.size(); i++) { + int equals = data[i].indexOf('='); + QString key = QString::fromLatin1(data[i].mid(0, equals)); + QString value; + if (equals >= 0) + value = QString::fromLatin1(unquotedString(data[i].mid(equals + 1))); + bootstrapStatus[key.toLower()] = value; + } + + qDebug() << bootstrapStatus; + emit q->bootstrapStatusChanged(); +} + +QObject *TorControl::getConfiguration(const QString &options) +{ + GetConfCommand *command = new GetConfCommand(GetConfCommand::GetConf); + d->socket->sendCommand(command, command->build(options.toLatin1())); + + //QQmlEngine::setObjectOwnership(command, QQmlEngine::CppOwnership); + return command; +} + +QObject *TorControl::setConfiguration(const QVariantMap &options) +{ + SetConfCommand *command = new SetConfCommand; + command->setResetMode(true); + d->socket->sendCommand(command, command->build(options)); + + //QQmlEngine::setObjectOwnership(command, QQmlEngine::CppOwnership); + return command; +} + +namespace Tor { + +class SaveConfigOperation : public PendingOperation +{ + Q_OBJECT + +public: + SaveConfigOperation(QObject *parent) + : PendingOperation(parent), command(0) + { + } + + void start(TorControlSocket *socket) + { + Q_ASSERT(!command); + command = new GetConfCommand(GetConfCommand::GetInfo); + QObject::connect(command, &TorControlCommand::finished, this, &SaveConfigOperation::configTextReply); + socket->sendCommand(command, command->build(QList() << "config-text" << "config-file")); + } + +private slots: + void configTextReply() + { + Q_ASSERT(command); + if (!command) + return; + + QString path = QFile::decodeName(command->get("config-file").toByteArray()); + if (path.isEmpty()) { + finishWithError(QStringLiteral("Cannot write torrc without knowing its path")); + return; + } + + // Out of paranoia, refuse to write any file not named 'torrc', or if the + // file doesn't exist + QFileInfo fileInfo(path); + if (fileInfo.fileName() != QStringLiteral("torrc") || !fileInfo.exists()) { + finishWithError(QStringLiteral("Refusing to write torrc to unacceptable path %1").arg(path)); + return; + } + + QSaveFile file(path); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + finishWithError(QStringLiteral("Failed opening torrc file for writing: %1").arg(file.errorString())); + return; + } + + // Remove these keys when writing torrc; they are set at runtime and contain + // absolute paths or port numbers + static const char *bannedKeys[] = { + "ControlPortWriteToFile", + "DataDirectory", + "HiddenServiceDir", + "HiddenServicePort", + 0 + }; + + QVariantList configText = command->get("config-text").toList(); + foreach (const QVariant &value, configText) { + QByteArray line = value.toByteArray(); + + bool skip = false; + for (const char **key = bannedKeys; *key; key++) { + if (line.startsWith(*key)) { + skip = true; + break; + } + } + if (skip) + continue; + + file.write(line); + file.write("\n"); + } + + if (!file.commit()) { + finishWithError(QStringLiteral("Failed writing torrc: %1").arg(file.errorString())); + return; + } + + qDebug() << "torctrl: Wrote torrc file"; + finishWithSuccess(); + } + +private: + GetConfCommand *command; +}; + +} + +PendingOperation *TorControl::saveConfiguration() +{ + if (!hasOwnership()) { + qWarning() << "torctrl: Ignoring save configuration command for a tor instance I don't own"; + return 0; + } + + SaveConfigOperation *operation = new SaveConfigOperation(this); + QObject::connect(operation, &PendingOperation::finished, operation, &QObject::deleteLater); + operation->start(d->socket); + + //QQmlEngine::setObjectOwnership(operation, QQmlEngine::CppOwnership); + return operation; +} + +bool TorControl::hasOwnership() const +{ + return d->hasOwnership; +} + +void TorControl::takeOwnership() +{ + d->hasOwnership = true; + d->socket->sendCommand("TAKEOWNERSHIP\r\n"); + + // Reset PID-based polling + QVariantMap options; + options[QStringLiteral("__OwningControllerProcess")] = QVariant(); + setConfiguration(options); +} + +bool TorControl::torVersionAsNewAs(const QString &match) const +{ + QRegularExpression r(QStringLiteral("[.-]")); + QStringList split = torVersion().split(r); + QStringList matchSplit = match.split(r); + + for (int i = 0; i < matchSplit.size(); i++) { + if (i >= split.size()) + return false; + bool ok1 = false, ok2 = false; + int currentVal = split[i].toInt(&ok1); + int matchVal = matchSplit[i].toInt(&ok2); + if (!ok1 || !ok2) + return false; + if (currentVal > matchVal) + return true; + if (currentVal < matchVal) + return false; + } + + // Versions are equal, up to the length of match + return true; +} + +#include "TorControl.moc" + diff --git a/retroshare-gui/src/TorControl/TorControl.h b/retroshare-gui/src/TorControl/TorControl.h new file mode 100644 index 000000000..93be0099c --- /dev/null +++ b/retroshare-gui/src/TorControl/TorControl.h @@ -0,0 +1,141 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TORCONTROL_H +#define TORCONTROL_H + +#include +#include +#include "PendingOperation.h" + +class QNetworkProxy; + +namespace Tor +{ + +class HiddenService; +class TorControlPrivate; + +class TorControl : public QObject +{ + Q_OBJECT + Q_ENUMS(Status TorStatus) + + // Status of the control connection + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + // Status of Tor (and whether it believes it can connect) + Q_PROPERTY(TorStatus torStatus READ torStatus NOTIFY torStatusChanged) + // Whether it's possible to make a SOCKS connection and connect + Q_PROPERTY(bool hasConnectivity READ hasConnectivity NOTIFY connectivityChanged) + Q_PROPERTY(QString torVersion READ torVersion NOTIFY connected) + Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY statusChanged) + Q_PROPERTY(QVariantMap bootstrapStatus READ bootstrapStatus NOTIFY bootstrapStatusChanged) + Q_PROPERTY(bool hasOwnership READ hasOwnership NOTIFY hasOwnershipChanged) + +public: + enum Status + { + Error = -1, + NotConnected, + Connecting, + Authenticating, + Connected + }; + + enum TorStatus + { + TorUnknown, + TorOffline, + TorReady + }; + + explicit TorControl(QObject *parent = 0); + + /* Information */ + Status status() const; + TorStatus torStatus() const; + QString torVersion() const; + bool torVersionAsNewAs(const QString &version) const; + QString errorMessage() const; + + bool hasConnectivity() const; + QHostAddress socksAddress() const; + quint16 socksPort() const; + QNetworkProxy connectionProxy(); + + /* Authentication */ + void setAuthPassword(const QByteArray &password); + + /* Connection */ + bool isConnected() const { return status() == Connected; } + void connect(const QHostAddress &address, quint16 port); + + /* Ownership means that tor is managed by this socket, and we + * can shut it down, own its configuration, etc. */ + bool hasOwnership() const; + void takeOwnership(); + + /* Hidden Services */ + QList hiddenServices() const; + void addHiddenService(HiddenService *service); + + QVariantMap bootstrapStatus() const; + Q_INVOKABLE QObject *getConfiguration(const QString &options); + Q_INVOKABLE QObject *setConfiguration(const QVariantMap &options); + Q_INVOKABLE PendingOperation *saveConfiguration(); + +signals: + void statusChanged(int newStatus, int oldStatus); + void torStatusChanged(int newStatus, int oldStatus); + void connected(); + void disconnected(); + void connectivityChanged(); + void bootstrapStatusChanged(); + void hasOwnershipChanged(); + +public slots: + /* Instruct Tor to shutdown */ + void shutdown(); + /* Call shutdown(), and wait synchronously for the command to be written */ + void shutdownSync(); + + void reconnect(); + +private: + TorControlPrivate *d; +}; + +} + +extern Tor::TorControl *torControl; + +#endif // TORCONTROLMANAGER_H diff --git a/retroshare-gui/src/TorControl/TorControlCommand.cpp b/retroshare-gui/src/TorControl/TorControlCommand.cpp new file mode 100644 index 000000000..48d4aab8b --- /dev/null +++ b/retroshare-gui/src/TorControl/TorControlCommand.cpp @@ -0,0 +1,63 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TorControlCommand.h" +#include + +using namespace Tor; + +TorControlCommand::TorControlCommand() + : m_finalStatus(0) +{ +} + +void TorControlCommand::onReply(int statusCode, const QByteArray &data) +{ + emit replyLine(statusCode, data); +} + +void TorControlCommand::onFinished(int statusCode) +{ + m_finalStatus = statusCode; + emit finished(); +} + +void TorControlCommand::onDataLine(const QByteArray &data) +{ + Q_UNUSED(data); +} + +void TorControlCommand::onDataFinished() +{ + qWarning() << "torctrl: Unexpected data response for command"; +} + diff --git a/retroshare-gui/src/TorControl/TorControlCommand.h b/retroshare-gui/src/TorControl/TorControlCommand.h new file mode 100644 index 000000000..894381054 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorControlCommand.h @@ -0,0 +1,70 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TORCONTROLCOMMAND_H +#define TORCONTROLCOMMAND_H + +#include +#include + +namespace Tor +{ + +class TorControlCommand : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(TorControlCommand) + + friend class TorControlSocket; + +public: + TorControlCommand(); + + int statusCode() const { return m_finalStatus; } + +signals: + void replyLine(int statusCode, const QByteArray &data); + void finished(); + +protected: + virtual void onReply(int statusCode, const QByteArray &data); + virtual void onFinished(int statusCode); + virtual void onDataLine(const QByteArray &data); + virtual void onDataFinished(); + +private: + int m_finalStatus; +}; + +} + +#endif // TORCONTROLCOMMAND_H diff --git a/retroshare-gui/src/TorControl/TorControlSocket.cpp b/retroshare-gui/src/TorControl/TorControlSocket.cpp new file mode 100644 index 000000000..33b411c54 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorControlSocket.cpp @@ -0,0 +1,176 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TorControlSocket.h" +#include "TorControlCommand.h" +#include + +using namespace Tor; + +TorControlSocket::TorControlSocket(QObject *parent) + : QTcpSocket(parent), currentCommand(0), inDataReply(false) +{ + connect(this, SIGNAL(readyRead()), this, SLOT(process())); + connect(this, SIGNAL(disconnected()), this, SLOT(clear())); +} + +TorControlSocket::~TorControlSocket() +{ + clear(); +} + +void TorControlSocket::sendCommand(TorControlCommand *command, const QByteArray &data) +{ + Q_ASSERT(data.endsWith("\r\n")); + + commandQueue.append(command); + write(data); + + qDebug() << "torctrl: Sent" << data.trimmed(); +} + +void TorControlSocket::registerEvent(const QByteArray &event, TorControlCommand *command) +{ + eventCommands.insert(event, command); + + QByteArray data("SETEVENTS"); + foreach (const QByteArray &key, eventCommands.keys()) { + data += ' '; + data += key; + } + data += "\r\n"; + + sendCommand(data); +} + +void TorControlSocket::clear() +{ + qDeleteAll(commandQueue); + commandQueue.clear(); + qDeleteAll(eventCommands); + eventCommands.clear(); + inDataReply = false; + currentCommand = 0; +} + +void TorControlSocket::setError(const QString &message) +{ + m_errorMessage = message; + emit error(message); + abort(); +} + +void TorControlSocket::process() +{ + for (;;) { + if (!canReadLine()) + return; + + QByteArray line = readLine(5120); + if (!line.endsWith("\r\n")) { + setError(QStringLiteral("Invalid control message syntax")); + return; + } + line.chop(2); + + if (inDataReply) { + if (line == ".") { + inDataReply = false; + if (currentCommand) + currentCommand->onDataFinished(); + currentCommand = 0; + } else { + if (currentCommand) + currentCommand->onDataLine(line); + } + continue; + } + + if (line.size() < 4) { + setError(QStringLiteral("Invalid control message syntax")); + return; + } + + int statusCode = line.left(3).toInt(); + char type = line[3]; + bool isFinalReply = (type == ' '); + inDataReply = (type == '+'); + + // Trim down to just data + line = line.mid(4); + + if (!isFinalReply && !inDataReply && type != '-') { + setError(QStringLiteral("Invalid control message syntax")); + return; + } + + // 6xx replies are asynchronous responses + if (statusCode >= 600 && statusCode < 700) { + if (!currentCommand) { + int space = line.indexOf(' '); + if (space > 0) + currentCommand = eventCommands.value(line.mid(0, space)); + + if (!currentCommand) { + qWarning() << "torctrl: Ignoring unknown event"; + continue; + } + } + + currentCommand->onReply(statusCode, line); + if (isFinalReply) { + currentCommand->onFinished(statusCode); + currentCommand = 0; + } + continue; + } + + if (commandQueue.isEmpty()) { + qWarning() << "torctrl: Received unexpected data"; + continue; + } + + TorControlCommand *command = commandQueue.first(); + if (command) + command->onReply(statusCode, line); + + if (inDataReply) { + currentCommand = command; + } else if (isFinalReply) { + commandQueue.takeFirst(); + if (command) { + command->onFinished(statusCode); + command->deleteLater(); + } + } + } +} diff --git a/retroshare-gui/src/TorControl/TorControlSocket.h b/retroshare-gui/src/TorControl/TorControlSocket.h new file mode 100644 index 000000000..2db911503 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorControlSocket.h @@ -0,0 +1,77 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TORCONTROLSOCKET_H +#define TORCONTROLSOCKET_H + +#include +#include + +namespace Tor +{ + +class TorControlCommand; + +class TorControlSocket : public QTcpSocket +{ +Q_OBJECT +public: + explicit TorControlSocket(QObject *parent = 0); + virtual ~TorControlSocket(); + + QString errorMessage() const { return m_errorMessage; } + + void registerEvent(const QByteArray &event, TorControlCommand *handler); + + void sendCommand(const QByteArray &data) { sendCommand(0, data); } + void sendCommand(TorControlCommand *command, const QByteArray &data); + +signals: + void error(const QString &message); + +private slots: + void process(); + void clear(); + +private: + QQueue commandQueue; + QHash eventCommands; + QString m_errorMessage; + TorControlCommand *currentCommand; + bool inDataReply; + + void setError(const QString &message); +}; + +} + +#endif // TORCONTROLSOCKET_H diff --git a/retroshare-gui/src/TorControl/TorManager.cpp b/retroshare-gui/src/TorControl/TorManager.cpp new file mode 100644 index 000000000..3b0c2d77f --- /dev/null +++ b/retroshare-gui/src/TorControl/TorManager.cpp @@ -0,0 +1,335 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "TorManager.h" +#include "TorProcess.h" +#include "TorControl.h" +#include "GetConfCommand.h" +#include "Settings.h" +#include +#include +#include + +using namespace Tor; + +namespace Tor +{ + +class TorManagerPrivate : public QObject +{ + Q_OBJECT + +public: + TorManager *q; + TorProcess *process; + TorControl *control; + QString dataDir; + QStringList logMessages; + QString errorMessage; + bool configNeeded; + + explicit TorManagerPrivate(TorManager *parent = 0); + + QString torExecutablePath() const; + bool createDataDir(const QString &path); + bool createDefaultTorrc(const QString &path); + + void setError(const QString &errorMessage); + +public slots: + void processStateChanged(int state); + void processErrorChanged(const QString &errorMessage); + void processLogMessage(const QString &message); + void controlStatusChanged(int status); + void getConfFinished(); +}; + +} + +TorManager::TorManager(QObject *parent) + : QObject(parent), d(new TorManagerPrivate(this)) +{ +} + +TorManagerPrivate::TorManagerPrivate(TorManager *parent) + : QObject(parent) + , q(parent) + , process(0) + , control(new TorControl(this)) + , configNeeded(false) +{ + connect(control, SIGNAL(statusChanged(int,int)), SLOT(controlStatusChanged(int))); +} + +TorManager *TorManager::instance() +{ + static TorManager *p = 0; + if (!p) + p = new TorManager(qApp); + return p; +} + +TorControl *TorManager::control() +{ + return d->control; +} + +TorProcess *TorManager::process() +{ + return d->process; +} + +QString TorManager::dataDirectory() const +{ + return d->dataDir; +} + +void TorManager::setDataDirectory(const QString &path) +{ + d->dataDir = QDir::fromNativeSeparators(path); + if (!d->dataDir.isEmpty() && !d->dataDir.endsWith(QLatin1Char('/'))) + d->dataDir.append(QLatin1Char('/')); +} + +bool TorManager::configurationNeeded() const +{ + return d->configNeeded; +} + +QStringList TorManager::logMessages() const +{ + return d->logMessages; +} + +bool TorManager::hasError() const +{ + return !d->errorMessage.isEmpty(); +} + +QString TorManager::errorMessage() const +{ + return d->errorMessage; +} + +void TorManager::start() +{ + if (!d->errorMessage.isEmpty()) { + d->errorMessage.clear(); + emit errorChanged(); + } + + SettingsObject settings(QStringLiteral("tor")); + + // If a control port is defined by config or environment, skip launching tor + if (!settings.read("controlPort").isUndefined() || + !qEnvironmentVariableIsEmpty("TOR_CONTROL_PORT")) + { + QHostAddress address(settings.read("controlAddress").toString()); + quint16 port = (quint16)settings.read("controlPort").toInt(); + QByteArray password = settings.read("controlPassword").toString().toLatin1(); + + if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_HOST")) + address = QHostAddress(QString::fromLatin1(qgetenv("TOR_CONTROL_HOST"))); + + if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_PORT")) { + bool ok = false; + port = qgetenv("TOR_CONTROL_PORT").toUShort(&ok); + if (!ok) + port = 0; + } + + if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_PASSWD")) + password = qgetenv("TOR_CONTROL_PASSWD"); + + if (!port) { + d->setError(QStringLiteral("Invalid control port settings from environment or configuration")); + return; + } + + if (address.isNull()) + address = QHostAddress::LocalHost; + + d->control->setAuthPassword(password); + d->control->connect(address, port); + } else { + // Launch a bundled Tor instance + QString executable = d->torExecutablePath(); + + std::cerr << "Executable path: " << executable.toStdString() << std::endl; + + if (executable.isEmpty()) { + d->setError(QStringLiteral("Cannot find tor executable")); + return; + } + + if (!d->process) { + d->process = new TorProcess(this); + connect(d->process, SIGNAL(stateChanged(int)), d, SLOT(processStateChanged(int))); + connect(d->process, SIGNAL(errorMessageChanged(QString)), d, + SLOT(processErrorChanged(QString))); + connect(d->process, SIGNAL(logMessage(QString)), d, SLOT(processLogMessage(QString))); + } + + if (!QFile::exists(d->dataDir) && !d->createDataDir(d->dataDir)) { + d->setError(QStringLiteral("Cannot write data location: %1").arg(d->dataDir)); + return; + } + + QString defaultTorrc = d->dataDir + QStringLiteral("default_torrc"); + if (!QFile::exists(defaultTorrc) && !d->createDefaultTorrc(defaultTorrc)) { + d->setError(QStringLiteral("Cannot write data files: %1").arg(defaultTorrc)); + return; + } + + QFile torrc(d->dataDir + QStringLiteral("torrc")); + if (!torrc.exists() || torrc.size() == 0) { + d->configNeeded = true; + emit configurationNeededChanged(); + } + + d->process->setExecutable(executable); + d->process->setDataDir(d->dataDir); + d->process->setDefaultTorrc(defaultTorrc); + d->process->start(); + } +} + +void TorManagerPrivate::processStateChanged(int state) +{ + qDebug() << Q_FUNC_INFO << state << TorProcess::Ready << process->controlPassword() << process->controlHost() << process->controlPort(); + if (state == TorProcess::Ready) { + control->setAuthPassword(process->controlPassword()); + control->connect(process->controlHost(), process->controlPort()); + } +} + +void TorManagerPrivate::processErrorChanged(const QString &errorMessage) +{ + qDebug() << "tor error:" << errorMessage; + setError(errorMessage); +} + +void TorManagerPrivate::processLogMessage(const QString &message) +{ + qDebug() << "tor:" << message; + if (logMessages.size() >= 50) + logMessages.takeFirst(); + logMessages.append(message); +} + +void TorManagerPrivate::controlStatusChanged(int status) +{ + if (status == TorControl::Connected) { + if (!configNeeded) { + // If DisableNetwork is 1, trigger configurationNeeded + connect(control->getConfiguration(QStringLiteral("DisableNetwork")), + SIGNAL(finished()), SLOT(getConfFinished())); + } + + if (process) { + // Take ownership via this control socket + control->takeOwnership(); + } + } +} + +void TorManagerPrivate::getConfFinished() +{ + GetConfCommand *command = qobject_cast(sender()); + if (!command) + return; + + if (command->get("DisableNetwork").toInt() == 1 && !configNeeded) { + configNeeded = true; + emit q->configurationNeededChanged(); + } +} + +QString TorManagerPrivate::torExecutablePath() const +{ + SettingsObject settings(QStringLiteral("tor")); + QString path = settings.read("executablePath").toString(); + if (!path.isEmpty()) + return path; + +#ifdef Q_OS_WIN + QString filename(QStringLiteral("/tor.exe")); +#else + QString filename(QStringLiteral("/tor")); +#endif + + path = qApp->applicationDirPath(); + if (QFile::exists(path + filename)) + return path + filename; + +#ifdef BUNDLED_TOR_PATH + path = QStringLiteral(BUNDLED_TOR_PATH); + if (QFile::exists(path + filename)) + return path + filename; +#endif + + // Try $PATH + return filename.mid(1); +} + +bool TorManagerPrivate::createDataDir(const QString &path) +{ + QDir dir(path); + return dir.mkpath(QStringLiteral(".")); +} + +bool TorManagerPrivate::createDefaultTorrc(const QString &path) +{ + static const char defaultTorrcContent[] = + "SocksPort auto\n" + "AvoidDiskWrites 1\n" + "DisableNetwork 1\n" + "__ReloadTorrcOnSIGHUP 0\n"; + + QFile file(path); + if (!file.open(QIODevice::WriteOnly)) + return false; + if (file.write(defaultTorrcContent) < 0) + return false; + return true; +} + +void TorManagerPrivate::setError(const QString &message) +{ + errorMessage = message; + emit q->errorChanged(); +} + +#include "TorManager.moc" + diff --git a/retroshare-gui/src/TorControl/TorManager.h b/retroshare-gui/src/TorControl/TorManager.h new file mode 100644 index 000000000..86b4327a0 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorManager.h @@ -0,0 +1,94 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This code has been further modified to fit Retroshare context. + +#ifndef TORMANAGER_H +#define TORMANAGER_H + +#include +#include + +namespace Tor +{ + +class TorProcess; +class TorControl; +class TorManagerPrivate; + +/* Run/connect to an instance of Tor according to configuration, and manage + * UI interaction, first time configuration, etc. */ +class TorManager : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool configurationNeeded READ configurationNeeded NOTIFY configurationNeededChanged) + Q_PROPERTY(QStringList logMessages READ logMessages CONSTANT) + Q_PROPERTY(Tor::TorProcess* process READ process CONSTANT) + Q_PROPERTY(Tor::TorControl* control READ control CONSTANT) + Q_PROPERTY(bool hasError READ hasError NOTIFY errorChanged) + Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorChanged) + Q_PROPERTY(QString dataDirectory READ dataDirectory WRITE setDataDirectory) + +public: + explicit TorManager(QObject *parent = 0); + static TorManager *instance(); + + TorProcess *process(); + TorControl *control(); + + QString dataDirectory() const; + void setDataDirectory(const QString &path); + + // True on first run or when the Tor configuration wizard needs to be shown + bool configurationNeeded() const; + + QStringList logMessages() const; + + bool hasError() const; + QString errorMessage() const; + +public slots: + void start(); + +signals: + void configurationNeededChanged(); + void errorChanged(); + +private: + TorManagerPrivate *d; +}; + +} + +#endif +# diff --git a/retroshare-gui/src/TorControl/TorProcess.cpp b/retroshare-gui/src/TorControl/TorProcess.cpp new file mode 100644 index 000000000..ca1aecfe5 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorProcess.cpp @@ -0,0 +1,311 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TorProcess_p.h" +#include "CryptoKey.h" +#include "SecureRNG.h" +#include +#include +#include + +using namespace Tor; + +TorProcess::TorProcess(QObject *parent) + : QObject(parent), d(new TorProcessPrivate(this)) +{ +} + +TorProcess::~TorProcess() +{ + if (state() > NotStarted) + stop(); +} + +TorProcessPrivate::TorProcessPrivate(TorProcess *q) + : QObject(q), q(q), state(TorProcess::NotStarted), controlPort(0), controlPortAttempts(0) +{ + connect(&process, &QProcess::started, this, &TorProcessPrivate::processStarted); + connect(&process, (void (QProcess::*)(int, QProcess::ExitStatus))&QProcess::finished, + this, &TorProcessPrivate::processFinished); + connect(&process, (void (QProcess::*)(QProcess::ProcessError))&QProcess::error, + this, &TorProcessPrivate::processError); + connect(&process, &QProcess::readyRead, this, &TorProcessPrivate::processReadable); + + controlPortTimer.setInterval(500); + connect(&controlPortTimer, &QTimer::timeout, this, &TorProcessPrivate::tryReadControlPort); +} + +QString TorProcess::executable() const +{ + return d->executable; +} + +void TorProcess::setExecutable(const QString &path) +{ + d->executable = path; +} + +QString TorProcess::dataDir() const +{ + return d->dataDir; +} + +void TorProcess::setDataDir(const QString &path) +{ + d->dataDir = path; +} + +QString TorProcess::defaultTorrc() const +{ + return d->defaultTorrc; +} + +void TorProcess::setDefaultTorrc(const QString &path) +{ + d->defaultTorrc = path; +} + +QStringList TorProcess::extraSettings() const +{ + return d->extraSettings; +} + +void TorProcess::setExtraSettings(const QStringList &settings) +{ + d->extraSettings = settings; +} + +TorProcess::State TorProcess::state() const +{ + return d->state; +} + +QString TorProcess::errorMessage() const +{ + return d->errorMessage; +} + +void TorProcess::start() +{ + if (state() > NotStarted) + return; + + d->errorMessage.clear(); + + if (d->executable.isEmpty() || d->dataDir.isEmpty()) { + d->errorMessage = QStringLiteral("Tor executable and data directory not specified"); + d->state = Failed; + emit errorMessageChanged(d->errorMessage); + emit stateChanged(d->state); + return; + } + + if (!d->ensureFilesExist()) { + d->state = Failed; + emit errorMessageChanged(d->errorMessage); + emit stateChanged(d->state); + return; + } + + QByteArray password = controlPassword(); + QByteArray hashedPassword = torControlHashedPassword(password); + if (password.isEmpty() || hashedPassword.isEmpty()) { + d->errorMessage = QStringLiteral("Random password generation failed"); + d->state = Failed; + emit errorMessageChanged(d->errorMessage); + emit stateChanged(d->state); + } + + QStringList args; + if (!d->defaultTorrc.isEmpty()) + args << QStringLiteral("--defaults-torrc") << d->defaultTorrc; + args << QStringLiteral("-f") << d->torrcPath(); + args << QStringLiteral("DataDirectory") << d->dataDir; + args << QStringLiteral("HashedControlPassword") << QString::fromLatin1(hashedPassword); + args << QStringLiteral("ControlPort") << QStringLiteral("auto"); + args << QStringLiteral("ControlPortWriteToFile") << d->controlPortFilePath(); + args << QStringLiteral("__OwningControllerProcess") << QString::number(qApp->applicationPid()); + args << d->extraSettings; + + d->state = Starting; + emit stateChanged(d->state); + + if (QFile::exists(d->controlPortFilePath())) + QFile::remove(d->controlPortFilePath()); + d->controlPort = 0; + d->controlHost.clear(); + + d->process.setProcessChannelMode(QProcess::MergedChannels); + d->process.start(d->executable, args, QIODevice::ReadOnly); +} + +void TorProcess::stop() +{ + if (state() < Starting) + return; + + d->controlPortTimer.stop(); + + if (d->process.state() == QProcess::Starting) + d->process.waitForStarted(2000); + + d->state = NotStarted; + + // Windows can't terminate the process well, but Tor will clean itself up +#ifndef Q_OS_WIN + if (d->process.state() == QProcess::Running) { + d->process.terminate(); + if (!d->process.waitForFinished(5000)) { + qWarning() << "Tor process" << d->process.pid() << "did not respond to terminate, killing..."; + d->process.kill(); + if (!d->process.waitForFinished(2000)) { + qCritical() << "Tor process" << d->process.pid() << "did not respond to kill!"; + } + } + } +#endif + + emit stateChanged(d->state); +} + +QByteArray TorProcess::controlPassword() +{ + if (d->controlPassword.isEmpty()) + d->controlPassword = SecureRNG::randomPrintable(16); + return d->controlPassword; +} + +QHostAddress TorProcess::controlHost() +{ + return d->controlHost; +} + +quint16 TorProcess::controlPort() +{ + return d->controlPort; +} + +bool TorProcessPrivate::ensureFilesExist() +{ + QFile torrc(torrcPath()); + if (!torrc.exists()) { + QDir dir(dataDir); + if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) { + errorMessage = QStringLiteral("Cannot create Tor data directory: %1").arg(dataDir); + return false; + } + + if (!torrc.open(QIODevice::ReadWrite)) { + errorMessage = QStringLiteral("Cannot create Tor configuration file: %1").arg(torrcPath()); + return false; + } + } + + return true; +} + +QString TorProcessPrivate::torrcPath() const +{ + return QDir::toNativeSeparators(dataDir) + QDir::separator() + QStringLiteral("torrc"); +} + +QString TorProcessPrivate::controlPortFilePath() const +{ + return QDir::toNativeSeparators(dataDir) + QDir::separator() + QStringLiteral("control-port"); +} + +void TorProcessPrivate::processStarted() +{ + state = TorProcess::Connecting; + emit q->stateChanged(state); + + controlPortAttempts = 0; + controlPortTimer.start(); +} + +void TorProcessPrivate::processFinished() +{ + if (state < TorProcess::Starting) + return; + + controlPortTimer.stop(); + errorMessage = process.errorString(); + if (errorMessage.isEmpty()) + errorMessage = QStringLiteral("Process exited unexpectedly (code %1)").arg(process.exitCode()); + state = TorProcess::Failed; + emit q->errorMessageChanged(errorMessage); + emit q->stateChanged(state); +} + +void TorProcessPrivate::processError(QProcess::ProcessError error) +{ + if (error == QProcess::FailedToStart || error == QProcess::Crashed) + processFinished(); +} + +void TorProcessPrivate::processReadable() +{ + while (process.bytesAvailable() > 0) { + QByteArray line = process.readLine(2048).trimmed(); + if (!line.isEmpty()) + emit q->logMessage(QString::fromLatin1(line)); + } +} + +void TorProcessPrivate::tryReadControlPort() +{ + QFile file(controlPortFilePath()); + if (file.open(QIODevice::ReadOnly)) { + QByteArray data = file.readLine().trimmed(); + + int p; + if (data.startsWith("PORT=") && (p = data.lastIndexOf(':')) > 0) { + controlHost = QHostAddress(QString::fromLatin1(data.mid(5, p - 5))); + controlPort = data.mid(p+1).toUShort(); + + if (!controlHost.isNull() && controlPort > 0) { + controlPortTimer.stop(); + state = TorProcess::Ready; + emit q->stateChanged(state); + return; + } + } + } + + if (++controlPortAttempts * controlPortTimer.interval() > 10000) { + errorMessage = QStringLiteral("No control port available after launching process"); + state = TorProcess::Failed; + emit q->errorMessageChanged(errorMessage); + emit q->stateChanged(state); + } +} + diff --git a/retroshare-gui/src/TorControl/TorProcess.h b/retroshare-gui/src/TorControl/TorProcess.h new file mode 100644 index 000000000..ad489dc43 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorProcess.h @@ -0,0 +1,100 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TORPROCESS_H +#define TORPROCESS_H + +#include +#include + +namespace Tor +{ + +class TorProcessPrivate; + +/* Launches and controls a Tor instance with behavior suitable for bundling + * an instance with the application. */ +class TorProcess : public QObject +{ + Q_OBJECT + Q_ENUMS(State) + + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged) + +public: + enum State { + Failed = -1, + NotStarted, + Starting, + Connecting, + Ready + }; + + explicit TorProcess(QObject *parent = 0); + virtual ~TorProcess(); + + QString executable() const; + void setExecutable(const QString &path); + + QString dataDir() const; + void setDataDir(const QString &path); + + QString defaultTorrc() const; + void setDefaultTorrc(const QString &path); + + QStringList extraSettings() const; + void setExtraSettings(const QStringList &settings); + + State state() const; + QString errorMessage() const; + QHostAddress controlHost(); + quint16 controlPort(); + QByteArray controlPassword(); + +public slots: + void start(); + void stop(); + +signals: + void stateChanged(int newState); + void errorMessageChanged(const QString &errorMessage); + void logMessage(const QString &message); + +private: + TorProcessPrivate *d; +}; + +} + +#endif + diff --git a/retroshare-gui/src/TorControl/TorProcess_p.h b/retroshare-gui/src/TorControl/TorProcess_p.h new file mode 100644 index 000000000..9aa2585e3 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorProcess_p.h @@ -0,0 +1,79 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TORPROCESS_P_H +#define TORPROCESS_P_H + +#include "TorProcess.h" +#include +#include + +namespace Tor { + +class TorProcessPrivate : public QObject +{ + Q_OBJECT + +public: + TorProcess *q; + QProcess process; + QString executable; + QString dataDir; + QString defaultTorrc; + QStringList extraSettings; + TorProcess::State state; + QString errorMessage; + QHostAddress controlHost; + quint16 controlPort; + QByteArray controlPassword; + + QTimer controlPortTimer; + int controlPortAttempts; + + TorProcessPrivate(TorProcess *q); + + QString torrcPath() const; + QString controlPortFilePath() const; + bool ensureFilesExist(); + +public slots: + void processStarted(); + void processFinished(); + void processError(QProcess::ProcessError error); + void processReadable(); + void tryReadControlPort(); +}; + +} + +#endif + diff --git a/retroshare-gui/src/TorControl/TorSocket.cpp b/retroshare-gui/src/TorControl/TorSocket.cpp new file mode 100644 index 000000000..615369b3a --- /dev/null +++ b/retroshare-gui/src/TorControl/TorSocket.cpp @@ -0,0 +1,155 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TorSocket.h" +#include "TorControl.h" +#include + +using namespace Tor; + +TorSocket::TorSocket(QObject *parent) + : QTcpSocket(parent) + , m_port(0) + , m_reconnectEnabled(true) + , m_maxInterval(900) + , m_connectAttempts(0) +{ + connect(torControl, SIGNAL(connectivityChanged()), SLOT(connectivityChanged())); + connect(&m_connectTimer, SIGNAL(timeout()), SLOT(reconnect())); + connect(this, SIGNAL(disconnected()), SLOT(onFailed())); + connect(this, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(onFailed())); + + m_connectTimer.setSingleShot(true); + connectivityChanged(); +} + +TorSocket::~TorSocket() +{ +} + +void TorSocket::setReconnectEnabled(bool enabled) +{ + if (enabled == m_reconnectEnabled) + return; + + m_reconnectEnabled = enabled; + if (m_reconnectEnabled) { + m_connectAttempts = 0; + reconnect(); + } else { + m_connectTimer.stop(); + } +} + +void TorSocket::setMaxAttemptInterval(int interval) +{ + m_maxInterval = interval; +} + +void TorSocket::resetAttempts() +{ + m_connectAttempts = 0; + if (m_connectTimer.isActive()) { + m_connectTimer.stop(); + m_connectTimer.start(reconnectInterval() * 1000); + } +} + +int TorSocket::reconnectInterval() +{ + int delay = 0; + if (m_connectAttempts <= 4) + delay = 30; + else if (m_connectAttempts <= 6) + delay = 120; + else + delay = m_maxInterval; + + return qMin(delay, m_maxInterval); +} + +void TorSocket::reconnect() +{ + if (!torControl->hasConnectivity() || !reconnectEnabled()) + return; + + m_connectTimer.stop(); + if (!m_host.isEmpty() && m_port) { + qDebug() << "Attempting reconnection of socket to" << m_host << m_port; + connectToHost(m_host, m_port); + } +} + +void TorSocket::connectivityChanged() +{ + if (torControl->hasConnectivity()) { + setProxy(torControl->connectionProxy()); + if (state() == QAbstractSocket::UnconnectedState) + reconnect(); + } else { + m_connectTimer.stop(); + m_connectAttempts = 0; + } +} + +void TorSocket::connectToHost(const QString &hostName, quint16 port, OpenMode openMode, + NetworkLayerProtocol protocol) +{ + m_host = hostName; + m_port = port; + + if (!torControl->hasConnectivity()) + return; + + if (proxy() != torControl->connectionProxy()) + setProxy(torControl->connectionProxy()); + + QAbstractSocket::connectToHost(hostName, port, openMode, protocol); +} + +void TorSocket::connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode) +{ + TorSocket::connectToHost(address.toString(), port, openMode); +} + +void TorSocket::onFailed() +{ + // Make sure the internal connection to the SOCKS proxy is closed + // Otherwise reconnect attempts will fail (#295) + close(); + + if (reconnectEnabled() && !m_connectTimer.isActive()) { + m_connectAttempts++; + m_connectTimer.start(reconnectInterval() * 1000); + qDebug() << "Reconnecting socket to" << m_host << m_port << "in" << m_connectTimer.interval() / 1000 << "seconds"; + } +} diff --git a/retroshare-gui/src/TorControl/TorSocket.h b/retroshare-gui/src/TorControl/TorSocket.h new file mode 100644 index 000000000..0c68f7854 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorSocket.h @@ -0,0 +1,97 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TORSOCKET_H +#define TORSOCKET_H + +#include +#include + +namespace Tor { + +/* Specialized QTcpSocket which makes connections over the SOCKS proxy + * from a TorControl instance, automatically attempts reconnections, and + * reacts to Tor's connectivity state. + * + * Use normal QTcpSocket/QAbstractSocket API. When a connection fails, it + * will be retried automatically after the correct interval and when + * connectivity is available. + * + * To fully disconnect, destroy the object, or call + * setReconnectEnabled(false) and disconnect the socket with + * disconnectFromHost or abort. + * + * The caller is responsible for resetting the attempt counter if a + * connection was successful and reconnection will be used again. + */ +class TorSocket : public QTcpSocket +{ + Q_OBJECT + +public: + explicit TorSocket(QObject *parent = 0); + virtual ~TorSocket(); + + bool reconnectEnabled() const { return m_reconnectEnabled; } + void setReconnectEnabled(bool enabled); + int maxAttemptInterval() { return m_maxInterval; } + void setMaxAttemptInterval(int interval); + void resetAttempts(); + + virtual void connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol); + virtual void connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode = ReadWrite); + + QString hostName() const { return m_host; } + quint16 port() const { return m_port; } + +protected: + virtual int reconnectInterval(); + +private slots: + void reconnect(); + void connectivityChanged(); + void onFailed(); + +private: + QString m_host; + quint16 m_port; + QTimer m_connectTimer; + bool m_reconnectEnabled; + int m_maxInterval; + int m_connectAttempts; + + using QAbstractSocket::connectToHost; +}; + +} + +#endif diff --git a/retroshare-gui/src/TorControl/Useful.h b/retroshare-gui/src/TorControl/Useful.h new file mode 100644 index 000000000..6bb6e44c1 --- /dev/null +++ b/retroshare-gui/src/TorControl/Useful.h @@ -0,0 +1,71 @@ +/* Ricochet - https://ricochet.im/ + * Copyright (C) 2014, John Brooks + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the names of the copyright owners nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UTILS_USEFUL_H +#define UTILS_USEFUL_H + +#include +#include + +/* Print a warning for bug conditions, and assert on a debug build. + * + * This should be used in place of Q_ASSERT for bug conditions, along + * with a proper error case for release-mode builds. For example: + * + * if (!connection || !user) { + * BUG() << "Request" << request << "should have a connection and user"; + * return false; + * } + * + * Do not confuse bugs with actual error cases; BUG() should never be + * triggered unless the code or logic is wrong. + */ +#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) +# define BUG() Explode(__FILE__,__LINE__), qWarning() << "BUG:" +namespace { +class Explode +{ +public: + const char *file; + int line; + Explode(const char *file, int line) : file(file), line(line) { } + ~Explode() { + qt_assert("something broke!", file, line); + } +}; +} +#else +# define BUG() qWarning() << "BUG:" +#endif + +#endif + diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 2430a1984..59213ac5b 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -46,6 +46,10 @@ #include "lang/languagesupport.h" #include "util/RsGxsUpdateBroadcast.h" +#ifdef RETROTOR +#include "TorControl/TorManager.h" +#endif + #include "retroshare/rsidentity.h" #ifdef SIGFPE_DEBUG @@ -274,8 +278,26 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); RshareSettings::Create (); /* Setup The GUI Stuff */ - Rshare rshare(args, argc, argv, - QString::fromUtf8(RsAccounts::ConfigDirectory().c_str())); + Rshare rshare(args, argc, argv, QString::fromUtf8(RsAccounts::ConfigDirectory().c_str())); + +#ifdef RETROTOR + // Start the Tor engine, and make sure it provides a viable hidden service + + /* Tor control manager */ + Tor::TorManager *torManager = Tor::TorManager::instance(); + torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); + //torManager->setDataDirectory(QString("./tor"));//settings->filePath()).path() + QString("/tor/")); + + Tor::TorControl *torControl = torManager->control(); + torManager->start(); + + while(torManager->configurationNeeded()) + { + usleep(1000*1000) ; + + // we should display some configuration window here! + } +#endif /* Start RetroShare */ QSplashScreen splashScreen(QPixmap(":/images/logo/logo_splash.png")/* , Qt::WindowStaysOnTopHint*/); diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 6b3211392..f7e23bc8c 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -1,7 +1,7 @@ !include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") TEMPLATE = app -QT += network xml +QT += network xml CONFIG += qt gui uic qrc resources idle bitdht CONFIG += link_prl TARGET = retroshare @@ -20,6 +20,9 @@ profiling { QMAKE_LFLAGS *= -pg } +retrotor { + DEFINES *= RETROTOR +} #QMAKE_CFLAGS += -fmudflap #LIBS *= /usr/lib/gcc/x86_64-linux-gnu/4.4/libmudflap.a /usr/lib/gcc/x86_64-linux-gnu/4.4/libmudflapth.a @@ -325,6 +328,47 @@ INCLUDEPATH += $$PWD/../../libresapi/src PRE_TARGETDEPS *= $$OUT_PWD/../../libresapi/src/lib/libresapi.a LIBS += $$OUT_PWD/../../libresapi/src/lib/libresapi.a +retrotor { +HEADERS += TorControl/AddOnionCommand.h \ + TorControl/AuthenticateCommand.h \ + TorControl/GetConfCommand.h \ + TorControl/HiddenService.h \ + TorControl/ProtocolInfoCommand.h \ + TorControl/SetConfCommand.h \ + TorControl/TorControlCommand.h \ + TorControl/TorControl.h \ + TorControl/TorControlSocket.h \ + TorControl/TorManager.h \ + TorControl/TorProcess.h \ + TorControl/TorProcess_p.h \ + TorControl/TorSocket.h \ + TorControl/Useful.h \ + TorControl/CryptoKey.h \ + TorControl/PendingOperation.h \ + TorControl/SecureRNG.h \ + TorControl/Settings.h \ + TorControl/StringUtil.h \ + TorControl/TorProcess_p.h + +SOURCES += TorControl/AddOnionCommand.cpp \ + TorControl/AuthenticateCommand.cpp \ + TorControl/GetConfCommand.cpp \ + TorControl/HiddenService.cpp \ + TorControl/ProtocolInfoCommand.cpp \ + TorControl/SetConfCommand.cpp \ + TorControl/TorControlCommand.cpp \ + TorControl/TorControl.cpp \ + TorControl/TorControlSocket.cpp \ + TorControl/TorManager.cpp \ + TorControl/TorProcess.cpp \ + TorControl/TorSocket.cpp \ + TorControl/CryptoKey.cpp \ + TorControl/PendingOperation.cpp \ + TorControl/SecureRNG.cpp \ + TorControl/Settings.cpp \ + TorControl/StringUtil.cpp +} + # Input HEADERS += rshare.h \ retroshare-gui/configpage.h \ diff --git a/retroshare.pri b/retroshare.pri index 0b61671f6..5ae0e46b0 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -3,6 +3,10 @@ CONFIG *= retroshare_gui no_retroshare_gui:CONFIG -= retroshare_gui +# To build the RetroTor executable, just include the following option + +CONFIG *= retrotor + # To disable RetroShare-nogui append the following # assignation to qmake command line "CONFIG+=no_retroshare_nogui" CONFIG *= retroshare_nogui From e87b25794f7c085cb367ac4548bda7d4aabe0f6b Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 21 Dec 2017 15:32:42 +0100 Subject: [PATCH 02/42] added Tor control window --- .../src/TorControl/TorControlWindow.cpp | 176 ++++++++++++++++++ .../src/TorControl/TorControlWindow.h | 20 ++ .../src/TorControl/TorControlWindow.ui | 70 +++++++ retroshare-gui/src/main.cpp | 24 +-- retroshare-gui/src/retroshare-gui.pro | 4 + 5 files changed, 283 insertions(+), 11 deletions(-) create mode 100644 retroshare-gui/src/TorControl/TorControlWindow.cpp create mode 100644 retroshare-gui/src/TorControl/TorControlWindow.h create mode 100644 retroshare-gui/src/TorControl/TorControlWindow.ui diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp new file mode 100644 index 000000000..b6787a625 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -0,0 +1,176 @@ +#include +#include +#include + +#include "TorControlWindow.h" +#include "TorControl.h" +#include "HiddenService.h" + +TorControlDialog::TorControlDialog(Tor::TorManager *tm,QWidget *parent) + : mTorManager(tm) +{ + setupUi(this) ; + + QObject::connect(tm,SIGNAL(errorChanged()),this,SLOT(showLog())) ; + + QObject::connect(tm->control(),SIGNAL(statusChanged(int,int)),this,SLOT(statusChanged())) ; + QObject::connect(tm->control(),SIGNAL(connected()),this,SLOT(statusChanged())); + QObject::connect(tm->control(),SIGNAL(disconnected()),this,SLOT(statusChanged())); + QObject::connect(tm->control(),SIGNAL(bootstrapStatusChanged()),this,SLOT(statusChanged())); + QObject::connect(tm->control(),SIGNAL(connectivityChanged()),this,SLOT(statusChanged())); + + QTimer::singleShot(2000,this,SLOT(checkForHiddenService())) ; + //void configurationNeededChanged(); +} + +void TorControlDialog::setupHiddenService() +{ + QString keyData = m_settings->read("serviceKey").toString(); + QString legacyDir = m_settings->read("dataDirectory").toString(); + + if (!keyData.isEmpty()) + { + CryptoKey key; + if (!key.loadFromData(QByteArray::fromBase64(keyData.toLatin1()), CryptoKey::PrivateKey, CryptoKey::DER)) { + qWarning() << "Cannot load service key from configuration"; + return; + } + + m_hiddenService = new Tor::HiddenService(key, legacyDir, this); + } + else if (!legacyDir.isEmpty() && QFile::exists(legacyDir + QLatin1String("/private_key"))) + { + qDebug() << "Attempting to load key from legacy filesystem format in" << legacyDir; + + CryptoKey key; + if (!key.loadFromFile(legacyDir + QLatin1String("/private_key"), CryptoKey::PrivateKey)) { + qWarning() << "Cannot load legacy format key from" << legacyDir << "for conversion"; + return; + } else { + keyData = QString::fromLatin1(key.encodedPrivateKey(CryptoKey::DER).toBase64()); + m_settings->write("serviceKey", keyData); + m_hiddenService = new Tor::HiddenService(key, legacyDir, this); + } + } + else if (!m_settings->read("initializing").toBool()) + { + qWarning() << "Missing private key for initialized identity"; + return; + } + else + { + m_hiddenService = new Tor::HiddenService(legacyDir, this); + + connect(m_hiddenService, &Tor::HiddenService::privateKeyChanged, this, [&]() + { + QString key = QString::fromLatin1(m_hiddenService->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64()); + m_settings->write("serviceKey", key); + } + ); + } + + Q_ASSERT(m_hiddenService); + connect(m_hiddenService, SIGNAL(statusChanged(int,int)), SLOT(onStatusChanged(int,int))); + + // Generally, these are not used, and we bind to localhost and port 0 + // for an automatic (and portable) selection. + QHostAddress address(m_settings->read("localListenAddress").toString()); + if (address.isNull()) + address = QHostAddress::LocalHost; + quint16 port = (quint16)m_settings->read("localListenPort").toInt(); + + m_incomingServer = new QTcpServer(this); + if (!m_incomingServer->listen(address, port)) { + // XXX error case + qWarning() << "Failed to open incoming socket:" << m_incomingServer->errorString(); + return; + } + + connect(m_incomingServer, &QTcpServer::newConnection, this, &UserIdentity::onIncomingConnection); + + m_hiddenService->addTarget(9878, m_incomingServer->serverAddress(), m_incomingServer->serverPort()); + torControl->addHiddenService(m_hiddenService); +} + +void TorControlDialog::checkForHiddenService() +{ + QList hidden_services = mTorManager->control()->hiddenServices(); + + std::cerr << "Checking for hidden services:" << std::endl; + + if(hidden_services.empty()) + { + setupHiddenService(); + + QTimer::singleShot(2000,this,SLOT(checkForHiddenService())) ; + } +} + +void TorControlDialog::statusChanged() +{ + int status = mTorManager->control()->status(); + int torstatus = mTorManager->control()->torStatus(); + + QString status_str,torstatus_str ; + + switch(status) + { + default: + case Tor::TorControl::Error : status_str = "Error" ; break ; + case Tor::TorControl::NotConnected: status_str = "Not connected" ; break ; + case Tor::TorControl::Connecting: status_str = "Connecting" ; break ; + case Tor::TorControl::Authenticating: status_str = "Authenticating" ; break ; + case Tor::TorControl::Connected: status_str = "Connected" ; break ; + } + + switch(torstatus) + { + default: + case Tor::TorControl::TorUnknown: torstatus_str = "Unknown" ; break ; + case Tor::TorControl::TorOffline: torstatus_str = "Tor offline" ; break ; + case Tor::TorControl::TorReady: torstatus_str = "Tor ready" ; break ; + } + + torStatus_LB->setText(torstatus_str + "(" + status_str + ")") ; + + QVariantMap qvm = mTorManager->control()->bootstrapStatus(); + QString bootstrapstatus_str ; + + for(auto it(qvm.begin());it!=qvm.end();++it) + bootstrapstatus_str += it.key() + ":" + it.value().toString(); + + torBootstrapStatus_LB->setText(bootstrapstatus_str) ; + + QList hidden_services = mTorManager->control()->hiddenServices(); + + if(hidden_services.empty()) + hiddenService_LB->setText(QString("None")) ; + else + { + QString hiddenservices_str ; + + for(auto it(hidden_services.begin());it!=hidden_services.end();++it) + { + hiddenservices_str += (*it)->hostname(); + + for(auto it2((*it)->targets().begin());it2!=(*it)->targets().end();++it2) + hiddenservices_str += QString::number((*it2).servicePort) + ":" + (*it2).targetAddress.toString() + ":" + QString::number((*it2).targetPort) + " " ; + } + + hiddenService_LB->setText(hiddenservices_str) ; + } + + showLog(); +} + +void TorControlDialog::showLog() +{ + QString s ; + QStringList logmsgs = mTorManager->logMessages() ; + + for(QStringList::const_iterator it(logmsgs.begin());it!=logmsgs.end();++it) + s += *it + "\n" ; + + torLog_TB->setText(s) ; + QCoreApplication::processEvents() ; +} diff --git a/retroshare-gui/src/TorControl/TorControlWindow.h b/retroshare-gui/src/TorControl/TorControlWindow.h new file mode 100644 index 000000000..79a66d863 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorControlWindow.h @@ -0,0 +1,20 @@ +#include "ui_TorControlWindow.h" +#include "TorManager.h" + +class TorControlDialog: public QDialog, public Ui::TorControlDialog +{ + Q_OBJECT + +public: + TorControlDialog(Tor::TorManager *tm,QWidget *parent =NULL); + +protected slots: + void showLog(); + void statusChanged(); + void checkForHiddenService(); + +private: + void setupHiddenService(); + + Tor::TorManager *mTorManager ; +}; diff --git a/retroshare-gui/src/TorControl/TorControlWindow.ui b/retroshare-gui/src/TorControl/TorControlWindow.ui new file mode 100644 index 000000000..76985d0e3 --- /dev/null +++ b/retroshare-gui/src/TorControl/TorControlWindow.ui @@ -0,0 +1,70 @@ + + + TorControlDialog + + + + 0 + 0 + 739 + 489 + + + + Dialog + + + + + + + + TextLabel + + + + + + + Tor bootstrap status: + + + + + + + TextLabel + + + + + + + Hidden service: + + + + + + + Tor status: + + + + + + + TextLabel + + + + + + + + + + + + + diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 59213ac5b..70ef4345f 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -48,6 +48,7 @@ #ifdef RETROTOR #include "TorControl/TorManager.h" +#include "TorControl/TorControlWindow.h" #endif #include "retroshare/rsidentity.h" @@ -284,19 +285,20 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); // Start the Tor engine, and make sure it provides a viable hidden service /* Tor control manager */ - Tor::TorManager *torManager = Tor::TorManager::instance(); - torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); - //torManager->setDataDirectory(QString("./tor"));//settings->filePath()).path() + QString("/tor/")); + Tor::TorManager *torManager = Tor::TorManager::instance(); + torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); + //torManager->setDataDirectory(QString("./tor"));//settings->filePath()).path() + QString("/tor/")); - Tor::TorControl *torControl = torManager->control(); - torManager->start(); + torManager->start(); - while(torManager->configurationNeeded()) - { - usleep(1000*1000) ; - - // we should display some configuration window here! - } + TorControlDialog tcd(torManager) ; + tcd.exec(); +// tcd.show() ; +// +// while(true) +// { +// QCoreApplication::processEvents(); +// } #endif /* Start RetroShare */ diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index f7e23bc8c..7fbe7de87 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -22,6 +22,10 @@ profiling { retrotor { DEFINES *= RETROTOR + + FORMS += TorControl/TorControlWindow.ui + SOURCES += TorControl/TorControlWindow.cpp + HEADERS += TorControl/TorControlWindow.h } #QMAKE_CFLAGS += -fmudflap From 5b5a2bef81533ce3cda3cf46716cf6031eb3f871 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 21 Dec 2017 18:16:32 +0100 Subject: [PATCH 03/42] split tor control into two parts --- .../src/TorControl/TorControlWindow.cpp | 112 ++++++++++++------ .../src/TorControl/TorControlWindow.h | 31 ++++- .../src/gui/settings/rsharesettings.h | 4 + retroshare-gui/src/main.cpp | 53 +++++++-- 4 files changed, 151 insertions(+), 49 deletions(-) diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp index b6787a625..dfe34eb05 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.cpp +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -1,8 +1,13 @@ +#include + #include #include +#include + #include #include "TorControlWindow.h" +#include "TorManager.h" #include "TorControl.h" #include "HiddenService.h" @@ -19,37 +24,51 @@ TorControlDialog::TorControlDialog(Tor::TorManager *tm,QWidget *parent) QObject::connect(tm->control(),SIGNAL(bootstrapStatusChanged()),this,SLOT(statusChanged())); QObject::connect(tm->control(),SIGNAL(connectivityChanged()),this,SLOT(statusChanged())); - QTimer::singleShot(2000,this,SLOT(checkForHiddenService())) ; - //void configurationNeededChanged(); + //QTimer::singleShot(2000,this,SLOT(checkForHiddenService())) ; + + mIncomingServer = new QTcpServer(this) ; + mHiddenService = NULL ; + + connect(mIncomingServer, SIGNAL(QTcpServer::newConnection()), this, SLOT(onIncomingConnection())); +} + +void TorControlDialog::onIncomingConnection() +{ + std::cerr << "Incoming connection !!" << std::endl; } void TorControlDialog::setupHiddenService() { - QString keyData = m_settings->read("serviceKey").toString(); + /* + QString keyData = m_settings->read("serviceKey").toString(); QString legacyDir = m_settings->read("dataDirectory").toString(); if (!keyData.isEmpty()) { CryptoKey key; - if (!key.loadFromData(QByteArray::fromBase64(keyData.toLatin1()), CryptoKey::PrivateKey, CryptoKey::DER)) { + if (!key.loadFromData(QByteArray::fromBase64(keyData.toLatin1()), CryptoKey::PrivateKey, CryptoKey::DER)) + { qWarning() << "Cannot load service key from configuration"; return; } - m_hiddenService = new Tor::HiddenService(key, legacyDir, this); + mHiddenService = new Tor::HiddenService(key, legacyDir, this); } else if (!legacyDir.isEmpty() && QFile::exists(legacyDir + QLatin1String("/private_key"))) { qDebug() << "Attempting to load key from legacy filesystem format in" << legacyDir; CryptoKey key; - if (!key.loadFromFile(legacyDir + QLatin1String("/private_key"), CryptoKey::PrivateKey)) { + if (!key.loadFromFile(legacyDir + QLatin1String("/private_key"), CryptoKey::PrivateKey)) + { qWarning() << "Cannot load legacy format key from" << legacyDir << "for conversion"; return; - } else { + } + else + { keyData = QString::fromLatin1(key.encodedPrivateKey(CryptoKey::DER).toBase64()); m_settings->write("serviceKey", keyData); - m_hiddenService = new Tor::HiddenService(key, legacyDir, this); + mHiddenService = new Tor::HiddenService(key, legacyDir, this); } } else if (!m_settings->read("initializing").toBool()) @@ -59,52 +78,54 @@ void TorControlDialog::setupHiddenService() } else { - m_hiddenService = new Tor::HiddenService(legacyDir, this); + mHiddenService = new Tor::HiddenService(legacyDir, this); - connect(m_hiddenService, &Tor::HiddenService::privateKeyChanged, this, [&]() + connect(mHiddenService, &Tor::HiddenService::privateKeyChanged, this, [&]() { - QString key = QString::fromLatin1(m_hiddenService->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64()); + QString key = QString::fromLatin1(mHiddenService->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64()); m_settings->write("serviceKey", key); } ); } - Q_ASSERT(m_hiddenService); - connect(m_hiddenService, SIGNAL(statusChanged(int,int)), SLOT(onStatusChanged(int,int))); + Q_ASSERT(mHiddenService); + connect(mHiddenService, SIGNAL(statusChanged(int,int)), SLOT(onStatusChanged(int,int))); // Generally, these are not used, and we bind to localhost and port 0 // for an automatic (and portable) selection. + QHostAddress address(m_settings->read("localListenAddress").toString()); + if (address.isNull()) address = QHostAddress::LocalHost; + quint16 port = (quint16)m_settings->read("localListenPort").toInt(); - m_incomingServer = new QTcpServer(this); - if (!m_incomingServer->listen(address, port)) { + if (!mIncomingServer->listen(address, port)) + { // XXX error case - qWarning() << "Failed to open incoming socket:" << m_incomingServer->errorString(); + qWarning() << "Failed to open incoming socket:" << mIncomingServer->errorString(); return; } - connect(m_incomingServer, &QTcpServer::newConnection, this, &UserIdentity::onIncomingConnection); - - m_hiddenService->addTarget(9878, m_incomingServer->serverAddress(), m_incomingServer->serverPort()); - torControl->addHiddenService(m_hiddenService); + mHiddenService->addTarget(9878, mIncomingServer->serverAddress(), mIncomingServer->serverPort()); + torControl->addHiddenService(mHiddenService); + */ } -void TorControlDialog::checkForHiddenService() -{ - QList hidden_services = mTorManager->control()->hiddenServices(); - - std::cerr << "Checking for hidden services:" << std::endl; - - if(hidden_services.empty()) - { - setupHiddenService(); - - QTimer::singleShot(2000,this,SLOT(checkForHiddenService())) ; - } -} +// void TorControlDialog::checkForHiddenService() +// { +// QList hidden_services = mTorManager->control()->hiddenServices(); +// +// std::cerr << "Checking for hidden services:" << std::endl; +// +// if(hidden_services.empty()) +// { +// setupHiddenService(); +// +// QTimer::singleShot(2000,this,SLOT(checkForHiddenService())) ; +// } +// } void TorControlDialog::statusChanged() { @@ -120,7 +141,7 @@ void TorControlDialog::statusChanged() case Tor::TorControl::NotConnected: status_str = "Not connected" ; break ; case Tor::TorControl::Connecting: status_str = "Connecting" ; break ; case Tor::TorControl::Authenticating: status_str = "Authenticating" ; break ; - case Tor::TorControl::Connected: status_str = "Connected" ; break ; + case Tor::TorControl::Connected: status_str = "Connected" ; break ; } switch(torstatus) @@ -128,7 +149,7 @@ void TorControlDialog::statusChanged() default: case Tor::TorControl::TorUnknown: torstatus_str = "Unknown" ; break ; case Tor::TorControl::TorOffline: torstatus_str = "Tor offline" ; break ; - case Tor::TorControl::TorReady: torstatus_str = "Tor ready" ; break ; + case Tor::TorControl::TorReady: torstatus_str = "Tor ready" ; break ; } torStatus_LB->setText(torstatus_str + "(" + status_str + ")") ; @@ -174,3 +195,24 @@ void TorControlDialog::showLog() torLog_TB->setText(s) ; QCoreApplication::processEvents() ; } + +TorControlDialog::TorStatus TorControlDialog::checkForTor() +{ + switch(mTorManager->control()->status()) + { + case Tor::TorControl::Connected: usleep(2*1000*1000);return TOR_STATUS_OK ; + case Tor::TorControl::Error: return TOR_STATUS_FAIL ; + + default: + return TOR_STATUS_UNKNOWN ; + } +} + +TorControlDialog::HiddenServiceStatus TorControlDialog::checkForHiddenService() +{ + return HIDDEN_SERVICE_STATUS_UNKNOWN ; +} + + + + diff --git a/retroshare-gui/src/TorControl/TorControlWindow.h b/retroshare-gui/src/TorControl/TorControlWindow.h index 79a66d863..86d82159a 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.h +++ b/retroshare-gui/src/TorControl/TorControlWindow.h @@ -1,5 +1,11 @@ #include "ui_TorControlWindow.h" -#include "TorManager.h" + +class QTcpServer ; + +namespace Tor { + class HiddenService ; + class TorManager ; +} class TorControlDialog: public QDialog, public Ui::TorControlDialog { @@ -8,13 +14,34 @@ class TorControlDialog: public QDialog, public Ui::TorControlDialog public: TorControlDialog(Tor::TorManager *tm,QWidget *parent =NULL); + enum TorStatus { + TOR_STATUS_UNKNOWN = 0x00, + TOR_STATUS_OK = 0x01, + TOR_STATUS_FAIL = 0x02 + }; + + enum HiddenServiceStatus { + HIDDEN_SERVICE_STATUS_UNKNOWN = 0x00, + HIDDEN_SERVICE_STATUS_OK = 0x01, + HIDDEN_SERVICE_STATUS_FAIL = 0x02 + }; + + // Should be called multiple times in a loop until it returns something else than *_UNKNOWN + + TorStatus checkForTor() ; + HiddenServiceStatus checkForHiddenService() ; + protected slots: void showLog(); void statusChanged(); - void checkForHiddenService(); +// void checkForHiddenService(); + void onIncomingConnection(); private: void setupHiddenService(); Tor::TorManager *mTorManager ; + Tor::HiddenService *mHiddenService ; + + QTcpServer *mIncomingServer ; }; diff --git a/retroshare-gui/src/gui/settings/rsharesettings.h b/retroshare-gui/src/gui/settings/rsharesettings.h index 21b1faae9..99e33b5f2 100644 --- a/retroshare-gui/src/gui/settings/rsharesettings.h +++ b/retroshare-gui/src/gui/settings/rsharesettings.h @@ -187,6 +187,10 @@ public: /** Sets whether the bandwidth graph is always on top. */ void setBWGraphAlwaysOnTop(bool alwaysOnTop); +#ifdef RETROTOR + void setHiddenServiceKey() ; +#endif + uint getNewsFeedFlags(); void setNewsFeedFlags(uint flags); diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 70ef4345f..13f90ed93 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -282,23 +282,29 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); Rshare rshare(args, argc, argv, QString::fromUtf8(RsAccounts::ConfigDirectory().c_str())); #ifdef RETROTOR - // Start the Tor engine, and make sure it provides a viable hidden service + // First check that we can start the Tor engine, if not, quit. /* Tor control manager */ Tor::TorManager *torManager = Tor::TorManager::instance(); torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); - //torManager->setDataDirectory(QString("./tor"));//settings->filePath()).path() + QString("/tor/")); - torManager->start(); TorControlDialog tcd(torManager) ; - tcd.exec(); -// tcd.show() ; -// -// while(true) -// { -// QCoreApplication::processEvents(); -// } + tcd.show(); + + while(tcd.checkForTor() == TorControlDialog::TOR_STATUS_UNKNOWN) // runs until some status is reached: either tor works, or it fails. + { + QCoreApplication::processEvents(); + usleep(1000) ; + } + + tcd.hide(); + + if(tcd.checkForTor() != TorControlDialog::TOR_STATUS_OK) + { + QMessageBox::critical(NULL,QObject::tr("Tor not found!"),QObject::tr("Tor wasn't found on your system. Please install it and re-start Retroshare.")) ; + return 1 ; + } #endif /* Start RetroShare */ @@ -330,9 +336,10 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); if (genCert) { GenCertDialog gd(false); - if (gd.exec () == QDialog::Rejected) { + + if (gd.exec () == QDialog::Rejected) return 1; - } + sDefaultGXSIdToCreate = gd.getGXSNickname(); } @@ -364,6 +371,28 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); SoundManager::create(); +#ifdef RETROTOR + // Now that we know the Tor service running, and we know the SSL id, we can make sure it provides a viable hidden service + + /* Tor control manager */ + + tcd.show(); + + while(tcd.checkForHiddenService() == TorControlDialog::HIDDEN_SERVICE_STATUS_UNKNOWN) // runs until some status is reached: either tor works, or it fails. + { + QCoreApplication::processEvents(); + usleep(1000) ; + } + + tcd.hide(); + + if(tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) + { + QMessageBox::critical(NULL,QObject::tr("Cannot start a hidden tor service!"),QObject::tr("It was not possible to start a hidden service.")) ; + return 1 ; + } +#endif + splashScreen.showMessage(rshare.translate("SplashScreen", "Load configuration"), Qt::AlignHCenter | Qt::AlignBottom); /* stop Retroshare if startup fails */ From f5ce711ad6bda88de9c5412b95b6196673c04ee7 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 21 Dec 2017 21:34:51 +0100 Subject: [PATCH 04/42] only load hidden nodes in retro-only mode --- libretroshare/src/libretroshare.pro | 3 ++ libretroshare/src/rsserver/rsaccounts.cc | 12 +++-- libretroshare/src/rsserver/rsaccounts.h | 4 +- retroshare-gui/src/TorControl/TorManager.cpp | 1 + retroshare-gui/src/main.cpp | 55 +++++++++++--------- 5 files changed, 46 insertions(+), 29 deletions(-) diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 1521f5574..e58d01eef 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -10,6 +10,9 @@ DESTDIR = lib #CONFIG += dsdv +retrotor { + DEFINES *= RETROTOR +} # the dht stunner is used to obtain RS' external ip addr. when it is natted # this system is unreliable and rs supports a newer and better one (asking connected peers) # CONFIG += useDhtStunner diff --git a/libretroshare/src/rsserver/rsaccounts.cc b/libretroshare/src/rsserver/rsaccounts.cc index 45983b5c3..6136a2a87 100644 --- a/libretroshare/src/rsserver/rsaccounts.cc +++ b/libretroshare/src/rsserver/rsaccounts.cc @@ -71,8 +71,11 @@ RsAccountsDetail::RsAccountsDetail() : mAccountsLocked(false), mPreferredId("") bool RsAccountsDetail::loadAccounts() { int failing_accounts ; - - getAvailableAccounts(mAccounts,failing_accounts,mUnsupportedKeys); +#ifdef RETROTOR + getAvailableAccounts(mAccounts,failing_accounts,mUnsupportedKeys,true); +#else + getAvailableAccounts(mAccounts,failing_accounts,mUnsupportedKeys,false); +#endif loadPreferredAccount(); checkPreferredId(); @@ -512,7 +515,7 @@ bool RsAccountsDetail::getAccountOptions(bool &ishidden, bool &isFirstTimeRun) /* directories with valid certificates in the expected location */ -bool RsAccountsDetail::getAvailableAccounts(std::map &accounts,int& failing_accounts,std::map >& unsupported_keys) +bool RsAccountsDetail::getAvailableAccounts(std::map &accounts,int& failing_accounts,std::map >& unsupported_keys,bool hidden_only) { failing_accounts = 0 ; /* get the directories */ @@ -615,6 +618,9 @@ bool RsAccountsDetail::getAvailableAccounts(std::map & continue; } + if(hidden_only && !hidden_location) + continue ; + if(valid_prefix && isHexaString(lochex) && (lochex).length() == 32) { std::string accountdir = mBaseDirectory + "/" + *it; diff --git a/libretroshare/src/rsserver/rsaccounts.h b/libretroshare/src/rsserver/rsaccounts.h index 5832dfa00..8ff253587 100644 --- a/libretroshare/src/rsserver/rsaccounts.h +++ b/libretroshare/src/rsserver/rsaccounts.h @@ -142,9 +142,9 @@ class RsAccountsDetail static bool defaultBaseDirectory(); - bool getAvailableAccounts(std::map &accounts, + bool getAvailableAccounts(std::map &accounts, int& failing_accounts, - std::map >& unsupported_keys); + std::map >& unsupported_keys, bool hidden_only=false); bool setupAccount(const std::string& accountdir); diff --git a/retroshare-gui/src/TorControl/TorManager.cpp b/retroshare-gui/src/TorControl/TorManager.cpp index 3b0c2d77f..47fef939d 100644 --- a/retroshare-gui/src/TorControl/TorManager.cpp +++ b/retroshare-gui/src/TorControl/TorManager.cpp @@ -118,6 +118,7 @@ QString TorManager::dataDirectory() const void TorManager::setDataDirectory(const QString &path) { d->dataDir = QDir::fromNativeSeparators(path); + if (!d->dataDir.isEmpty() && !d->dataDir.endsWith(QLatin1Char('/'))) d->dataDir.append(QLatin1Char('/')); } diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 13f90ed93..3357bd688 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -289,21 +289,25 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); torManager->start(); - TorControlDialog tcd(torManager) ; - tcd.show(); + // We do not need to show this dialog. If too much of a pain, we may hide it and only show when it reports an error. - while(tcd.checkForTor() == TorControlDialog::TOR_STATUS_UNKNOWN) // runs until some status is reached: either tor works, or it fails. { - QCoreApplication::processEvents(); - usleep(1000) ; - } + TorControlDialog tcd(torManager) ; + tcd.show(); - tcd.hide(); + while(tcd.checkForTor() == TorControlDialog::TOR_STATUS_UNKNOWN) // runs until some status is reached: either tor works, or it fails. + { + QCoreApplication::processEvents(); + usleep(1000) ; + } - if(tcd.checkForTor() != TorControlDialog::TOR_STATUS_OK) - { - QMessageBox::critical(NULL,QObject::tr("Tor not found!"),QObject::tr("Tor wasn't found on your system. Please install it and re-start Retroshare.")) ; - return 1 ; + tcd.hide(); + + if(tcd.checkForTor() != TorControlDialog::TOR_STATUS_OK) + { + QMessageBox::critical(NULL,QObject::tr("Tor not found!"),QObject::tr("Tor wasn't found on your system. Please install it and re-start Retroshare.")) ; + return 1 ; + } } #endif @@ -374,22 +378,25 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); #ifdef RETROTOR // Now that we know the Tor service running, and we know the SSL id, we can make sure it provides a viable hidden service - /* Tor control manager */ - - tcd.show(); - - while(tcd.checkForHiddenService() == TorControlDialog::HIDDEN_SERVICE_STATUS_UNKNOWN) // runs until some status is reached: either tor works, or it fails. { - QCoreApplication::processEvents(); - usleep(1000) ; - } + torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); // re-set it, because now it's changed to the specific location that is run - tcd.hide(); + TorControlDialog tcd(torManager) ; + tcd.show(); - if(tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) - { - QMessageBox::critical(NULL,QObject::tr("Cannot start a hidden tor service!"),QObject::tr("It was not possible to start a hidden service.")) ; - return 1 ; + while(tcd.checkForHiddenService() == TorControlDialog::HIDDEN_SERVICE_STATUS_UNKNOWN) // runs until some status is reached: either tor works, or it fails. + { + QCoreApplication::processEvents(); + usleep(1000) ; + } + + tcd.hide(); + + if(tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) + { + QMessageBox::critical(NULL,QObject::tr("Cannot start a hidden tor service!"),QObject::tr("It was not possible to start a hidden service.")) ; + return 1 ; + } } #endif From 659367ca96317488a3f04f3987dbdfa7b6f46d25 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 25 Dec 2017 22:59:42 +0100 Subject: [PATCH 05/42] added basic hidden service creation. Untested. --- retroshare-gui/src/TorControl/TorControl.h | 1 + .../src/TorControl/TorControlWindow.cpp | 121 ++++-------------- .../src/TorControl/TorControlWindow.h | 10 +- retroshare-gui/src/TorControl/TorManager.cpp | 101 +++++++++++++++ retroshare-gui/src/TorControl/TorManager.h | 10 ++ retroshare-gui/src/main.cpp | 2 +- 6 files changed, 145 insertions(+), 100 deletions(-) diff --git a/retroshare-gui/src/TorControl/TorControl.h b/retroshare-gui/src/TorControl/TorControl.h index 93be0099c..3b897eb63 100644 --- a/retroshare-gui/src/TorControl/TorControl.h +++ b/retroshare-gui/src/TorControl/TorControl.h @@ -78,6 +78,7 @@ public: TorReady }; + explicit TorControl(QObject *parent = 0); /* Information */ diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp index dfe34eb05..ee9bd6a9d 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.cpp +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -37,96 +37,6 @@ void TorControlDialog::onIncomingConnection() std::cerr << "Incoming connection !!" << std::endl; } -void TorControlDialog::setupHiddenService() -{ - /* - QString keyData = m_settings->read("serviceKey").toString(); - QString legacyDir = m_settings->read("dataDirectory").toString(); - - if (!keyData.isEmpty()) - { - CryptoKey key; - if (!key.loadFromData(QByteArray::fromBase64(keyData.toLatin1()), CryptoKey::PrivateKey, CryptoKey::DER)) - { - qWarning() << "Cannot load service key from configuration"; - return; - } - - mHiddenService = new Tor::HiddenService(key, legacyDir, this); - } - else if (!legacyDir.isEmpty() && QFile::exists(legacyDir + QLatin1String("/private_key"))) - { - qDebug() << "Attempting to load key from legacy filesystem format in" << legacyDir; - - CryptoKey key; - if (!key.loadFromFile(legacyDir + QLatin1String("/private_key"), CryptoKey::PrivateKey)) - { - qWarning() << "Cannot load legacy format key from" << legacyDir << "for conversion"; - return; - } - else - { - keyData = QString::fromLatin1(key.encodedPrivateKey(CryptoKey::DER).toBase64()); - m_settings->write("serviceKey", keyData); - mHiddenService = new Tor::HiddenService(key, legacyDir, this); - } - } - else if (!m_settings->read("initializing").toBool()) - { - qWarning() << "Missing private key for initialized identity"; - return; - } - else - { - mHiddenService = new Tor::HiddenService(legacyDir, this); - - connect(mHiddenService, &Tor::HiddenService::privateKeyChanged, this, [&]() - { - QString key = QString::fromLatin1(mHiddenService->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64()); - m_settings->write("serviceKey", key); - } - ); - } - - Q_ASSERT(mHiddenService); - connect(mHiddenService, SIGNAL(statusChanged(int,int)), SLOT(onStatusChanged(int,int))); - - // Generally, these are not used, and we bind to localhost and port 0 - // for an automatic (and portable) selection. - - QHostAddress address(m_settings->read("localListenAddress").toString()); - - if (address.isNull()) - address = QHostAddress::LocalHost; - - quint16 port = (quint16)m_settings->read("localListenPort").toInt(); - - if (!mIncomingServer->listen(address, port)) - { - // XXX error case - qWarning() << "Failed to open incoming socket:" << mIncomingServer->errorString(); - return; - } - - mHiddenService->addTarget(9878, mIncomingServer->serverAddress(), mIncomingServer->serverPort()); - torControl->addHiddenService(mHiddenService); - */ -} - -// void TorControlDialog::checkForHiddenService() -// { -// QList hidden_services = mTorManager->control()->hiddenServices(); -// -// std::cerr << "Checking for hidden services:" << std::endl; -// -// if(hidden_services.empty()) -// { -// setupHiddenService(); -// -// QTimer::singleShot(2000,this,SLOT(checkForHiddenService())) ; -// } -// } - void TorControlDialog::statusChanged() { int status = mTorManager->control()->status(); @@ -210,9 +120,32 @@ TorControlDialog::TorStatus TorControlDialog::checkForTor() TorControlDialog::HiddenServiceStatus TorControlDialog::checkForHiddenService() { - return HIDDEN_SERVICE_STATUS_UNKNOWN ; + std::cerr << "Checking for hidden services:" << std::endl; + + switch(mHiddenServiceStatus) + { + case HIDDEN_SERVICE_STATUS_UNKNOWN: { + + if(!mTorManager->setupHiddenService()) + { + mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_FAIL ; + return mHiddenServiceStatus ; + } + mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_REQUESTED ; + break ; + } + + case HIDDEN_SERVICE_STATUS_REQUESTED: { + QList hidden_services = mTorManager->control()->hiddenServices(); + + if(mHiddenService == NULL) + mHiddenService = *(hidden_services.begin()) ; + } + case HIDDEN_SERVICE_STATUS_OK : break; + + default: break ; + } + + return mHiddenServiceStatus ; } - - - diff --git a/retroshare-gui/src/TorControl/TorControlWindow.h b/retroshare-gui/src/TorControl/TorControlWindow.h index 86d82159a..ac70877b9 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.h +++ b/retroshare-gui/src/TorControl/TorControlWindow.h @@ -21,9 +21,10 @@ public: }; enum HiddenServiceStatus { - HIDDEN_SERVICE_STATUS_UNKNOWN = 0x00, - HIDDEN_SERVICE_STATUS_OK = 0x01, - HIDDEN_SERVICE_STATUS_FAIL = 0x02 + HIDDEN_SERVICE_STATUS_UNKNOWN = 0x00, // no information known. + HIDDEN_SERVICE_STATUS_FAIL = 0x01, // some error occurred + HIDDEN_SERVICE_STATUS_REQUESTED = 0x02, // one service at least has been requested. Still being tested. + HIDDEN_SERVICE_STATUS_OK = 0x03 // one service responds and has been tested }; // Should be called multiple times in a loop until it returns something else than *_UNKNOWN @@ -34,11 +35,10 @@ public: protected slots: void showLog(); void statusChanged(); -// void checkForHiddenService(); void onIncomingConnection(); private: - void setupHiddenService(); + HiddenServiceStatus mHiddenServiceStatus ; Tor::TorManager *mTorManager ; Tor::HiddenService *mHiddenService ; diff --git a/retroshare-gui/src/TorControl/TorManager.cpp b/retroshare-gui/src/TorControl/TorManager.cpp index 47fef939d..6cf5ae808 100644 --- a/retroshare-gui/src/TorControl/TorManager.cpp +++ b/retroshare-gui/src/TorControl/TorManager.cpp @@ -35,11 +35,15 @@ #include "TorManager.h" #include "TorProcess.h" #include "TorControl.h" +#include "CryptoKey.h" +#include "HiddenService.h" #include "GetConfCommand.h" #include "Settings.h" #include #include #include +#include +#include using namespace Tor; @@ -55,10 +59,13 @@ public: TorProcess *process; TorControl *control; QString dataDir; + QString hiddenServiceDir; QStringList logMessages; QString errorMessage; bool configNeeded; + HiddenService *hiddenService ; + explicit TorManagerPrivate(TorManager *parent = 0); QString torExecutablePath() const; @@ -123,6 +130,100 @@ void TorManager::setDataDirectory(const QString &path) d->dataDir.append(QLatin1Char('/')); } +QString TorManager::hiddenServiceDirectory() const +{ + return d->hiddenServiceDir; +} +void TorManager::setHiddenServiceDirectory(const QString &path) +{ + d->hiddenServiceDir = QDir::fromNativeSeparators(path); + + if (!d->hiddenServiceDir.isEmpty() && !d->hiddenServiceDir.endsWith(QLatin1Char('/'))) + d->hiddenServiceDir.append(QLatin1Char('/')); +} + +bool TorManager::setupHiddenService() +{ + QString keyData ;//= m_settings->read("serviceKey").toString(); + QString legacyDir = d->hiddenServiceDir; + +// if (!keyData.isEmpty()) +// { +// CryptoKey key; +// if (!key.loadFromData(QByteArray::fromBase64(keyData.toLatin1()), CryptoKey::PrivateKey, CryptoKey::DER)) +// { +// qWarning() << "Cannot load service key from configuration"; +// return; +// } +// +// mHiddenService = new Tor::HiddenService(key, legacyDir, this); +// } +// else + + if (!legacyDir.isEmpty() && QFile::exists(legacyDir + QLatin1String("/private_key"))) + { + qDebug() << "Attempting to load key from legacy filesystem format in" << legacyDir; + + CryptoKey key; + if (!key.loadFromFile(legacyDir + QLatin1String("/private_key"), CryptoKey::PrivateKey)) + { + qWarning() << "Cannot load legacy format key from" << legacyDir << "for conversion"; + return false; + } + else + { + keyData = QString::fromLatin1(key.encodedPrivateKey(CryptoKey::DER).toBase64()); + d->hiddenService = new Tor::HiddenService(key, legacyDir, this); + } + } +// else if (!m_settings->read("initializing").toBool()) +// { +// qWarning() << "Missing private key for initialized identity"; +// return; +// } + else + { + d->hiddenService = new Tor::HiddenService(legacyDir, this); + + connect(d->hiddenService, SIGNAL(Tor::HiddenService::privateKeyChanged), this, SLOT(hiddenServicePrivateKeyChanged())) ; + } + + Q_ASSERT(d->hiddenService); + connect(d->hiddenService, SIGNAL(statusChanged(int,int)), SLOT(onStatusChanged(int,int))); + + // Generally, these are not used, and we bind to localhost and port 0 + // for an automatic (and portable) selection. + + QHostAddress address = QHostAddress::LocalHost; // we only listen from localhost + + quint16 port = 7934;//(quint16)m_settings->read("localListenPort").toInt(); + + if (!QTcpServer().listen(address, port)) + { + // XXX error case + qWarning() << "Failed to open incoming socket on port :" << port; + return false; + } + + //d->hiddenService->addTarget(9878, mIncomingServer->serverAddress(), mIncomingServer->serverPort()); + d->hiddenService->addTarget(9878, QHostAddress::LocalHost,7934); + torControl->addHiddenService(d->hiddenService); + + return true ; +} + +void TorManager::hiddenServicePrivateKeyChanged() +{ + QString key = QString::fromLatin1(d->hiddenService->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64()); + + QFile outfile(d->hiddenServiceDir + QLatin1String("/private_key")) ; + outfile.open( QIODevice::WriteOnly | QIODevice::Text ); + QTextStream s(&outfile); + + s << key ; + outfile.close(); +} + bool TorManager::configurationNeeded() const { return d->configNeeded; diff --git a/retroshare-gui/src/TorControl/TorManager.h b/retroshare-gui/src/TorControl/TorManager.h index 86b4327a0..883159efb 100644 --- a/retroshare-gui/src/TorControl/TorManager.h +++ b/retroshare-gui/src/TorControl/TorManager.h @@ -60,6 +60,7 @@ class TorManager : public QObject Q_PROPERTY(QString dataDirectory READ dataDirectory WRITE setDataDirectory) public: + explicit TorManager(QObject *parent = 0); static TorManager *instance(); @@ -69,6 +70,12 @@ public: QString dataDirectory() const; void setDataDirectory(const QString &path); + QString hiddenServiceDirectory() const; + void setHiddenServiceDirectory(const QString &path); + + // Starts a hidden service, loading it from the config directory that has been set earlier. + bool setupHiddenService() ; + // True on first run or when the Tor configuration wizard needs to be shown bool configurationNeeded() const; @@ -80,6 +87,9 @@ public: public slots: void start(); +private slots: + void hiddenServicePrivateKeyChanged(); + signals: void configurationNeededChanged(); void errorChanged(); diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 3357bd688..b12ca021d 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -379,7 +379,7 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); // Now that we know the Tor service running, and we know the SSL id, we can make sure it provides a viable hidden service { - torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); // re-set it, because now it's changed to the specific location that is run + torManager->setDataDirectory(Rshare::dataDirectory() + QString("/hidden_service/")); // re-set it, because now it's changed to the specific location that is run TorControlDialog tcd(torManager) ; tcd.show(); From 1a9a9ca20829087b867a285421c8b0f0a3a62ded Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 26 Dec 2017 17:21:57 +0100 Subject: [PATCH 06/42] fixed creation of hidden service and saving of private key/hostname --- .../src/TorControl/HiddenService.cpp | 4 +- retroshare-gui/src/TorControl/TorControl.cpp | 59 +++++++++----- retroshare-gui/src/TorControl/TorControl.h | 2 + .../src/TorControl/TorControlSocket.cpp | 4 +- .../src/TorControl/TorControlWindow.cpp | 60 +++++++++++---- retroshare-gui/src/TorControl/TorManager.cpp | 67 ++++++++++++---- retroshare-gui/src/TorControl/TorSocket.cpp | 4 +- retroshare-gui/src/main.cpp | 76 +++++++++++-------- retroshare-gui/src/retroshare-gui.pro | 1 + 9 files changed, 194 insertions(+), 83 deletions(-) diff --git a/retroshare-gui/src/TorControl/HiddenService.cpp b/retroshare-gui/src/TorControl/HiddenService.cpp index e22576b5d..1dd1071c8 100644 --- a/retroshare-gui/src/TorControl/HiddenService.cpp +++ b/retroshare-gui/src/TorControl/HiddenService.cpp @@ -127,11 +127,11 @@ void HiddenService::servicePublished() loadPrivateKey(); if (m_hostname.isEmpty()) { - qDebug() << "Failed to read hidden service hostname"; + std::cerr << "Failed to read hidden service hostname" << std::endl; return; } - qDebug() << "Hidden service published successfully"; + std::cerr << "Hidden service published successfully" << std::endl; setStatus(Online); } diff --git a/retroshare-gui/src/TorControl/TorControl.cpp b/retroshare-gui/src/TorControl/TorControl.cpp index 8c5a1adee..d8ab0149c 100644 --- a/retroshare-gui/src/TorControl/TorControl.cpp +++ b/retroshare-gui/src/TorControl/TorControl.cpp @@ -52,6 +52,21 @@ Tor::TorControl *torControl = 0; +class nullstream: public std::ostream {}; + +static std::ostream& torctrldebug() +{ + static nullstream null ; + + if(true) + return std::cerr << time(NULL) << ":TOR CONTROL: " ; + else + return null ; +} + +#define torCtrlDebug torctrldebug + + using namespace Tor; namespace Tor { @@ -223,7 +238,7 @@ void TorControl::connect(const QHostAddress &address, quint16 port) { if (status() > Connecting) { - qDebug() << "Ignoring TorControl::connect due to existing connection"; + torCtrlDebug() << "Ignoring TorControl::connect due to existing connection" << std::endl; return; } @@ -262,7 +277,7 @@ void TorControlPrivate::authenticateReply() return; } - qDebug() << "torctrl: Authentication successful"; + torCtrlDebug() << "torctrl: Authentication successful" << std::endl; setStatus(TorControl::Connected); setTorStatus(TorControl::TorUnknown); @@ -280,11 +295,12 @@ void TorControlPrivate::authenticateReply() q->saveConfiguration(); } + void TorControlPrivate::socketConnected() { Q_ASSERT(status == TorControl::Connecting); - qDebug() << "torctrl: Connected socket; querying information"; + torCtrlDebug() << "torctrl: Connected socket; querying information" << std::endl; setStatus(TorControl::Authenticating); ProtocolInfoCommand *command = new ProtocolInfoCommand(q); @@ -327,14 +343,14 @@ void TorControlPrivate::protocolInfoReply() if (methods.testFlag(ProtocolInfoCommand::AuthNull)) { - qDebug() << "torctrl: Using null authentication"; + torCtrlDebug() << "torctrl: Using null authentication" << std::endl; data = auth->build(); } else if (methods.testFlag(ProtocolInfoCommand::AuthCookie) && !info->cookieFile().isEmpty()) { QString cookieFile = info->cookieFile(); QString cookieError; - qDebug() << "torctrl: Using cookie authentication with file" << cookieFile; + torCtrlDebug() << "torctrl: Using cookie authentication with file" << cookieFile.toStdString() << std::endl; QFile file(cookieFile); if (file.open(QIODevice::ReadOnly)) @@ -359,7 +375,7 @@ void TorControlPrivate::protocolInfoReply() * but it has happened. */ if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword) && !authPassword.isEmpty()) { - qDebug() << "torctrl: Unable to read authentication cookie file:" << cookieError; + torCtrlDebug() << "torctrl: Unable to read authentication cookie file:" << cookieError.toStdString() << std::endl; goto usePasswordAuth; } @@ -371,7 +387,7 @@ void TorControlPrivate::protocolInfoReply() else if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword) && !authPassword.isEmpty()) { usePasswordAuth: - qDebug() << "torctrl: Using hashed password authentication"; + torCtrlDebug() << "torctrl: Using hashed password authentication" << std::endl; data = auth->build(authPassword); } else @@ -404,7 +420,7 @@ void TorControlPrivate::getTorInfo() quint16 port = (quint16)settings.read("socksPort").toInt(); if (!forceAddress.isNull() && port) { - qDebug() << "torctrl: Using manually specified SOCKS connection settings"; + torCtrlDebug() << "torctrl: Using manually specified SOCKS connection settings"; socksAddress = forceAddress; socksPort = port; emit q->connectivityChanged(); @@ -442,12 +458,12 @@ void TorControlPrivate::getTorInfoReply() * listener yet. To handle that situation, we'll try to read the socks address again when TorReady state * is reached. */ if (!socksAddress.isNull()) { - qDebug().nospace() << "torctrl: SOCKS address is " << socksAddress.toString() << ":" << socksPort; + torCtrlDebug() << "torctrl: SOCKS address is " << socksAddress.toString().toStdString() << ":" << socksPort << std::endl; emit q->connectivityChanged(); } if (command->get(QByteArray("status/circuit-established")).toInt() == 1) { - qDebug() << "torctrl: Tor indicates that circuits have been established; state is TorReady"; + torCtrlDebug() << "torctrl: Tor indicates that circuits have been established; state is TorReady" << std::endl; setTorStatus(TorControl::TorReady); } else { setTorStatus(TorControl::TorOffline); @@ -468,14 +484,20 @@ void TorControl::addHiddenService(HiddenService *service) void TorControlPrivate::publishServices() { + torCtrlDebug() << "Publish Services... " ; + Q_ASSERT(q->isConnected()); if (services.isEmpty()) + { + std::cerr << "No service regstered!" << std::endl; return; + } + std::cerr << std::endl; SettingsObject settings(QStringLiteral("tor")); if (settings.read("neverPublishServices").toBool()) { - qDebug() << "torctrl: Skipping service publication because neverPublishService is enabled"; + torCtrlDebug() << "torctrl: Skipping service publication because neverPublishService is enabled" << std::endl; /* Call servicePublished under the assumption that they're published externally. */ for (QList::Iterator it = services.begin(); it != services.end(); ++it) @@ -487,15 +509,15 @@ void TorControlPrivate::publishServices() if (q->torVersionAsNewAs(QStringLiteral("0.2.7"))) { foreach (HiddenService *service, services) { if (service->hostname().isEmpty()) - qDebug() << "torctrl: Creating a new hidden service"; + torCtrlDebug() << "torctrl: Creating a new hidden service" << std::endl; else - qDebug() << "torctrl: Publishing hidden service" << service->hostname(); + torCtrlDebug() << "torctrl: Publishing hidden service: " << service->hostname().toStdString() << std::endl; AddOnionCommand *onionCommand = new AddOnionCommand(service); QObject::connect(onionCommand, &AddOnionCommand::succeeded, service, &HiddenService::servicePublished); socket->sendCommand(onionCommand, onionCommand->build()); } } else { - qDebug() << "torctrl: Using legacy SETCONF hidden service configuration for tor" << torVersion; + torCtrlDebug() << "torctrl: Using legacy SETCONF hidden service configuration for tor" << torVersion.toStdString() << std::endl; SetConfCommand *command = new SetConfCommand; QList > torConfig; @@ -510,7 +532,7 @@ void TorControlPrivate::publishServices() continue; } - qDebug() << "torctrl: Configuring hidden service at" << service->dataPath(); + torCtrlDebug() << "torctrl: Configuring hidden service at" << service->dataPath().toStdString() << std::endl; QDir dir(service->dataPath()); torConfig.append(qMakePair(QByteArray("HiddenServiceDir"), dir.absolutePath().toLocal8Bit())); @@ -565,7 +587,7 @@ void TorControlPrivate::statusEvent(int code, const QByteArray &data) if (tokens.size() < 3) return; - qDebug() << "torctrl: status event:" << data.trimmed(); + torCtrlDebug() << "torctrl: status event:" << QString(data.trimmed()).toStdString() << std::endl; if (tokens[2] == "CIRCUIT_ESTABLISHED") { setTorStatus(TorControl::TorReady); @@ -591,7 +613,8 @@ void TorControlPrivate::updateBootstrap(const QList &data) bootstrapStatus[key.toLower()] = value; } - qDebug() << bootstrapStatus; + //torCtrlDebug() << bootstrapStatus << std::endl; + emit q->bootstrapStatusChanged(); } @@ -694,7 +717,7 @@ private slots: return; } - qDebug() << "torctrl: Wrote torrc file"; + torCtrlDebug() << "torctrl: Wrote torrc file" << std::endl; finishWithSuccess(); } diff --git a/retroshare-gui/src/TorControl/TorControl.h b/retroshare-gui/src/TorControl/TorControl.h index 3b897eb63..4a47384fa 100644 --- a/retroshare-gui/src/TorControl/TorControl.h +++ b/retroshare-gui/src/TorControl/TorControl.h @@ -33,6 +33,8 @@ #ifndef TORCONTROL_H #define TORCONTROL_H +#include + #include #include #include "PendingOperation.h" diff --git a/retroshare-gui/src/TorControl/TorControlSocket.cpp b/retroshare-gui/src/TorControl/TorControlSocket.cpp index 33b411c54..b4c85d096 100644 --- a/retroshare-gui/src/TorControl/TorControlSocket.cpp +++ b/retroshare-gui/src/TorControl/TorControlSocket.cpp @@ -30,6 +30,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include + #include "TorControlSocket.h" #include "TorControlCommand.h" #include @@ -55,7 +57,7 @@ void TorControlSocket::sendCommand(TorControlCommand *command, const QByteArray commandQueue.append(command); write(data); - qDebug() << "torctrl: Sent" << data.trimmed(); + std::cerr << "torctrl: Sent: \"" << QString(data.trimmed()).toStdString() << "\"" << std::endl; } void TorControlSocket::registerEvent(const QByteArray &event, TorControlCommand *command) diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp index ee9bd6a9d..6d31b5a86 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.cpp +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -16,8 +16,6 @@ TorControlDialog::TorControlDialog(Tor::TorManager *tm,QWidget *parent) { setupUi(this) ; - QObject::connect(tm,SIGNAL(errorChanged()),this,SLOT(showLog())) ; - QObject::connect(tm->control(),SIGNAL(statusChanged(int,int)),this,SLOT(statusChanged())) ; QObject::connect(tm->control(),SIGNAL(connected()),this,SLOT(statusChanged())); QObject::connect(tm->control(),SIGNAL(disconnected()),this,SLOT(statusChanged())); @@ -28,8 +26,14 @@ TorControlDialog::TorControlDialog(Tor::TorManager *tm,QWidget *parent) mIncomingServer = new QTcpServer(this) ; mHiddenService = NULL ; + mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_UNKNOWN; connect(mIncomingServer, SIGNAL(QTcpServer::newConnection()), this, SLOT(onIncomingConnection())); + + QTimer *timer = new QTimer ; + + QObject::connect(timer,SIGNAL(timeout()),this,SLOT(showLog())) ; + timer->start(500) ; } void TorControlDialog::onIncomingConnection() @@ -103,14 +107,16 @@ void TorControlDialog::showLog() s += *it + "\n" ; torLog_TB->setText(s) ; - QCoreApplication::processEvents() ; +// QCoreApplication::processEvents() ; + +// std::cerr << s.toStdString() << std::endl; } TorControlDialog::TorStatus TorControlDialog::checkForTor() { switch(mTorManager->control()->status()) { - case Tor::TorControl::Connected: usleep(2*1000*1000);return TOR_STATUS_OK ; + case Tor::TorControl::Connected: usleep(1*1000*1000);return TOR_STATUS_OK ; case Tor::TorControl::Error: return TOR_STATUS_FAIL ; default: @@ -120,32 +126,60 @@ TorControlDialog::TorStatus TorControlDialog::checkForTor() TorControlDialog::HiddenServiceStatus TorControlDialog::checkForHiddenService() { - std::cerr << "Checking for hidden services:" << std::endl; + std::cerr << "Checking for hidden services:" ; switch(mHiddenServiceStatus) { + default: case HIDDEN_SERVICE_STATUS_UNKNOWN: { + std::cerr << " trying to setup. " ; + if(!mTorManager->setupHiddenService()) { mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_FAIL ; + std::cerr << "Failed." << std::endl; return mHiddenServiceStatus ; } + std::cerr << "Done." << std::endl; mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_REQUESTED ; - break ; + return mHiddenServiceStatus ; } case HIDDEN_SERVICE_STATUS_REQUESTED: { QList hidden_services = mTorManager->control()->hiddenServices(); - if(mHiddenService == NULL) - mHiddenService = *(hidden_services.begin()) ; - } - case HIDDEN_SERVICE_STATUS_OK : break; + if(hidden_services.empty()) + { + std::cerr << "Not ready yet." << std::endl; + return mHiddenServiceStatus ; + } + else + { + if(mHiddenService == NULL) + mHiddenService = *(hidden_services.begin()) ; - default: break ; - } + Tor::HiddenService::Status hss = mHiddenService->status(); - return mHiddenServiceStatus ; + std::cerr << "New service acquired. Status is " << hss ; + + if(hss == Tor::HiddenService::Online) + { + mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_OK ; + std::cerr << ": published and running!" << std::endl; + + return mHiddenServiceStatus ; + } + else + { + std::cerr << ": not ready yet." << std::endl; + return mHiddenServiceStatus ; + } + } + } + case HIDDEN_SERVICE_STATUS_OK : + std::cerr << "New service acquired." << std::endl; + return mHiddenServiceStatus ; + } } diff --git a/retroshare-gui/src/TorControl/TorManager.cpp b/retroshare-gui/src/TorControl/TorManager.cpp index 6cf5ae808..6634d23cd 100644 --- a/retroshare-gui/src/TorControl/TorManager.cpp +++ b/retroshare-gui/src/TorControl/TorManager.cpp @@ -147,6 +147,13 @@ bool TorManager::setupHiddenService() QString keyData ;//= m_settings->read("serviceKey").toString(); QString legacyDir = d->hiddenServiceDir; + std::cerr << "TorManager: setting up hidden service." << std::endl; + + if(legacyDir.isNull()) + { + std::cerr << "legacy dir not set! Cannot proceed." << std::endl; + return false ; + } // if (!keyData.isEmpty()) // { // CryptoKey key; @@ -160,9 +167,11 @@ bool TorManager::setupHiddenService() // } // else + std::cerr << "Using legacy dir: " << legacyDir.toStdString() << std::endl; + if (!legacyDir.isEmpty() && QFile::exists(legacyDir + QLatin1String("/private_key"))) { - qDebug() << "Attempting to load key from legacy filesystem format in" << legacyDir; + std::cerr << "Attempting to load key from legacy filesystem format in " << legacyDir.toStdString() << std::endl; CryptoKey key; if (!key.loadFromFile(legacyDir + QLatin1String("/private_key"), CryptoKey::PrivateKey)) @@ -170,11 +179,12 @@ bool TorManager::setupHiddenService() qWarning() << "Cannot load legacy format key from" << legacyDir << "for conversion"; return false; } - else - { - keyData = QString::fromLatin1(key.encodedPrivateKey(CryptoKey::DER).toBase64()); - d->hiddenService = new Tor::HiddenService(key, legacyDir, this); - } + + keyData = QString::fromLatin1(key.encodedPrivateKey(CryptoKey::DER).toBase64()); + d->hiddenService = new Tor::HiddenService(key, legacyDir, this); + + std::cerr << "Got key from legacy dir: " << std::endl; + std::cerr << keyData.toStdString() << std::endl; } // else if (!m_settings->read("initializing").toBool()) // { @@ -185,11 +195,13 @@ bool TorManager::setupHiddenService() { d->hiddenService = new Tor::HiddenService(legacyDir, this); - connect(d->hiddenService, SIGNAL(Tor::HiddenService::privateKeyChanged), this, SLOT(hiddenServicePrivateKeyChanged())) ; + std::cerr << "Creating new hidden service." << std::endl; + + connect(d->hiddenService, SIGNAL(privateKeyChanged()), this, SLOT(hiddenServicePrivateKeyChanged())) ; } Q_ASSERT(d->hiddenService); - connect(d->hiddenService, SIGNAL(statusChanged(int,int)), SLOT(onStatusChanged(int,int))); + connect(d->hiddenService, SIGNAL(statusChanged(int,int)), this, SLOT(hiddenServiceStatusChanged(int,int))); // Generally, these are not used, and we bind to localhost and port 0 // for an automatic (and portable) selection. @@ -198,20 +210,29 @@ bool TorManager::setupHiddenService() quint16 port = 7934;//(quint16)m_settings->read("localListenPort").toInt(); + std::cerr << "Testing host address: " << address.toString().toStdString() << ":" << port ; + if (!QTcpServer().listen(address, port)) { // XXX error case - qWarning() << "Failed to open incoming socket on port :" << port; + std::cerr << " Failed to open incoming socket" << std::endl; return false; } + std::cerr << " OK - Adding hidden service to TorControl." << std::endl; + //d->hiddenService->addTarget(9878, mIncomingServer->serverAddress(), mIncomingServer->serverPort()); d->hiddenService->addTarget(9878, QHostAddress::LocalHost,7934); - torControl->addHiddenService(d->hiddenService); + control()->addHiddenService(d->hiddenService); return true ; } +void hiddenServiceStatusChanged(int old_status,int new_status) +{ + std::cerr << "Hidden service status changed from " << old_status << " to " << new_status << std::endl; +} + void TorManager::hiddenServicePrivateKeyChanged() { QString key = QString::fromLatin1(d->hiddenService->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64()); @@ -220,8 +241,25 @@ void TorManager::hiddenServicePrivateKeyChanged() outfile.open( QIODevice::WriteOnly | QIODevice::Text ); QTextStream s(&outfile); - s << key ; + s << "-----BEGIN RSA PRIVATE KEY-----" << endl; + + for(uint32_t i=0;ihiddenServiceDir + QLatin1String("/hostname")) ; + outfile2.open( QIODevice::WriteOnly | QIODevice::Text ); + QTextStream t(&outfile2); + + t << d->hiddenService->hostname() << endl; + + outfile2.close(); } bool TorManager::configurationNeeded() const @@ -329,7 +367,8 @@ void TorManager::start() void TorManagerPrivate::processStateChanged(int state) { - qDebug() << Q_FUNC_INFO << state << TorProcess::Ready << process->controlPassword() << process->controlHost() << process->controlPort(); + std::cerr << Q_FUNC_INFO << "state: " << state << " passwd=\"" << QString(process->controlPassword()).toStdString() << "\" " << process->controlHost().toString().toStdString() + << ":" << process->controlPort() << std::endl; if (state == TorProcess::Ready) { control->setAuthPassword(process->controlPassword()); control->connect(process->controlHost(), process->controlPort()); @@ -338,13 +377,13 @@ void TorManagerPrivate::processStateChanged(int state) void TorManagerPrivate::processErrorChanged(const QString &errorMessage) { - qDebug() << "tor error:" << errorMessage; + std::cerr << "tor error:" << errorMessage.toStdString() << std::endl; setError(errorMessage); } void TorManagerPrivate::processLogMessage(const QString &message) { - qDebug() << "tor:" << message; + std::cerr << "tor:" << message.toStdString() << std::endl; if (logMessages.size() >= 50) logMessages.takeFirst(); logMessages.append(message); diff --git a/retroshare-gui/src/TorControl/TorSocket.cpp b/retroshare-gui/src/TorControl/TorSocket.cpp index 615369b3a..fb9c07b26 100644 --- a/retroshare-gui/src/TorControl/TorSocket.cpp +++ b/retroshare-gui/src/TorControl/TorSocket.cpp @@ -104,7 +104,7 @@ void TorSocket::reconnect() m_connectTimer.stop(); if (!m_host.isEmpty() && m_port) { - qDebug() << "Attempting reconnection of socket to" << m_host << m_port; + std::cerr << "Attempting reconnection of socket to" << m_host.toStdString() << ":" << m_port << std::endl; connectToHost(m_host, m_port); } } @@ -150,6 +150,6 @@ void TorSocket::onFailed() if (reconnectEnabled() && !m_connectTimer.isActive()) { m_connectAttempts++; m_connectTimer.start(reconnectInterval() * 1000); - qDebug() << "Reconnecting socket to" << m_host << m_port << "in" << m_connectTimer.interval() / 1000 << "seconds"; + std::cerr << "Reconnecting socket to" << m_host.toStdString() << ":" << m_port << "in" << m_connectTimer.interval() / 1000 << "seconds" << std::endl; } } diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index b12ca021d..036a702fe 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -45,6 +45,7 @@ #include "idle/idle.h" #include "lang/languagesupport.h" #include "util/RsGxsUpdateBroadcast.h" +#include "util/rsdir.h" #ifdef RETROTOR #include "TorControl/TorManager.h" @@ -281,35 +282,35 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); /* Setup The GUI Stuff */ Rshare rshare(args, argc, argv, QString::fromUtf8(RsAccounts::ConfigDirectory().c_str())); -#ifdef RETROTOR - // First check that we can start the Tor engine, if not, quit. - - /* Tor control manager */ - Tor::TorManager *torManager = Tor::TorManager::instance(); - torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); - torManager->start(); - - // We do not need to show this dialog. If too much of a pain, we may hide it and only show when it reports an error. - - { - TorControlDialog tcd(torManager) ; - tcd.show(); - - while(tcd.checkForTor() == TorControlDialog::TOR_STATUS_UNKNOWN) // runs until some status is reached: either tor works, or it fails. - { - QCoreApplication::processEvents(); - usleep(1000) ; - } - - tcd.hide(); - - if(tcd.checkForTor() != TorControlDialog::TOR_STATUS_OK) - { - QMessageBox::critical(NULL,QObject::tr("Tor not found!"),QObject::tr("Tor wasn't found on your system. Please install it and re-start Retroshare.")) ; - return 1 ; - } - } -#endif +// #ifdef RETROTOR +// // First check that we can start the Tor engine, if not, quit. +// +// /* Tor control manager */ +// Tor::TorManager *torManager = Tor::TorManager::instance(); +// torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); +// torManager->start(); +// +// // We do not need to show this dialog. If too much of a pain, we may hide it and only show when it reports an error. +// TorControlDialog tcd(torManager) ; +// +// { +// tcd.show(); +// +// while(tcd.checkForTor() == TorControlDialog::TOR_STATUS_UNKNOWN) // runs until some status is reached: either tor works, or it fails. +// { +// QCoreApplication::processEvents(); +// usleep(1000) ; +// } +// +// tcd.hide(); +// +// if(tcd.checkForTor() != TorControlDialog::TOR_STATUS_OK) +// { +// QMessageBox::critical(NULL,QObject::tr("Tor not found!"),QObject::tr("Tor wasn't found on your system. Please install it and re-start Retroshare.")) ; +// return 1 ; +// } +// } +// #endif /* Start RetroShare */ QSplashScreen splashScreen(QPixmap(":/images/logo/logo_splash.png")/* , Qt::WindowStaysOnTopHint*/); @@ -378,16 +379,25 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); #ifdef RETROTOR // Now that we know the Tor service running, and we know the SSL id, we can make sure it provides a viable hidden service - { - torManager->setDataDirectory(Rshare::dataDirectory() + QString("/hidden_service/")); // re-set it, because now it's changed to the specific location that is run + QString tor_hidden_service_dir = QString::fromStdString(RsAccounts::AccountDirectory()) + QString("/hidden_service/") ; + Tor::TorManager *torManager = Tor::TorManager::instance(); + torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); + torManager->setHiddenServiceDirectory(tor_hidden_service_dir); // re-set it, because now it's changed to the specific location that is run + + RsDirUtil::checkCreateDirectory(std::string(tor_hidden_service_dir.toUtf8())) ; + + torManager->setupHiddenService(); + torManager->start(); + + { TorControlDialog tcd(torManager) ; tcd.show(); - while(tcd.checkForHiddenService() == TorControlDialog::HIDDEN_SERVICE_STATUS_UNKNOWN) // runs until some status is reached: either tor works, or it fails. + while(tcd.checkForHiddenService() != 1+TorControlDialog::HIDDEN_SERVICE_STATUS_OK) // runs until some status is reached: either tor works, or it fails. { QCoreApplication::processEvents(); - usleep(1000) ; + usleep(0.2*1000*1000) ; } tcd.hide(); diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 7fbe7de87..79003f845 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -4,6 +4,7 @@ TEMPLATE = app QT += network xml CONFIG += qt gui uic qrc resources idle bitdht CONFIG += link_prl +CONFIG += console TARGET = retroshare DEFINES += TARGET=\\\"$${TARGET}\\\" From 355a0b42e9bde390de3ec18448a876618565f529 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 26 Dec 2017 18:44:15 +0100 Subject: [PATCH 07/42] avoid launching hidden service twice --- retroshare-gui/src/TorControl/TorManager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/retroshare-gui/src/TorControl/TorManager.cpp b/retroshare-gui/src/TorControl/TorManager.cpp index 6634d23cd..8db6c205e 100644 --- a/retroshare-gui/src/TorControl/TorManager.cpp +++ b/retroshare-gui/src/TorControl/TorManager.cpp @@ -95,6 +95,7 @@ TorManagerPrivate::TorManagerPrivate(TorManager *parent) , process(0) , control(new TorControl(this)) , configNeeded(false) + , hiddenService(NULL) { connect(control, SIGNAL(statusChanged(int,int)), SLOT(controlStatusChanged(int))); } @@ -144,6 +145,12 @@ void TorManager::setHiddenServiceDirectory(const QString &path) bool TorManager::setupHiddenService() { + if(d->hiddenService != NULL) + { + std::cerr << "TorManager: setupHiddenService() called twice! Not doing anything this time." << std::endl; + return true ; + } + QString keyData ;//= m_settings->read("serviceKey").toString(); QString legacyDir = d->hiddenServiceDir; From 390af949a82c1c67f17baca9f70f951f197240b1 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 26 Dec 2017 20:42:25 +0100 Subject: [PATCH 08/42] improved display of Tor starting window --- .../src/TorControl/TorControlWindow.cpp | 38 ++++- .../src/TorControl/TorControlWindow.h | 2 +- .../src/TorControl/TorControlWindow.ui | 154 +++++++++++++----- retroshare-gui/src/gui/icons.qrc | 1 + retroshare-gui/src/gui/icons/onion.png | Bin 0 -> 14776 bytes retroshare-gui/src/main.cpp | 18 +- 6 files changed, 152 insertions(+), 61 deletions(-) create mode 100644 retroshare-gui/src/gui/icons/onion.png diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp index 6d31b5a86..835c04f9f 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.cpp +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -34,6 +35,19 @@ TorControlDialog::TorControlDialog(Tor::TorManager *tm,QWidget *parent) QObject::connect(timer,SIGNAL(timeout()),this,SLOT(showLog())) ; timer->start(500) ; + + // Hide some debug output for the released version +// torLog_TB->hide(); + torBootstrapStatus_LB->hide(); + label_2->hide(); + + setWindowFlags( Qt::Dialog | Qt::FramelessWindowHint ); + + adjustSize(); + +// QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect(this); +// effect->setBlurRadius(30.0); +// setGraphicsEffect(effect); } void TorControlDialog::onIncomingConnection() @@ -66,7 +80,8 @@ void TorControlDialog::statusChanged() case Tor::TorControl::TorReady: torstatus_str = "Tor ready" ; break ; } - torStatus_LB->setText(torstatus_str + "(" + status_str + ")") ; + //torStatus_LB->setText(torstatus_str + "(" + status_str + ")") ; + torStatus_LB->setText(status_str) ; QVariantMap qvm = mTorManager->control()->bootstrapStatus(); QString bootstrapstatus_str ; @@ -79,23 +94,29 @@ void TorControlDialog::statusChanged() QList hidden_services = mTorManager->control()->hiddenServices(); if(hidden_services.empty()) - hiddenService_LB->setText(QString("None")) ; + { + hiddenServiceAddress_LB->setText(QString("[Not ready]")) ; + onionAddress_LB->setText(QString("[Not ready]")) ; + } else { QString hiddenservices_str ; for(auto it(hidden_services.begin());it!=hidden_services.end();++it) { - hiddenservices_str += (*it)->hostname(); + onionAddress_LB->setText((*it)->hostname()); for(auto it2((*it)->targets().begin());it2!=(*it)->targets().end();++it2) - hiddenservices_str += QString::number((*it2).servicePort) + ":" + (*it2).targetAddress.toString() + ":" + QString::number((*it2).targetPort) + " " ; + { + hiddenServiceAddress_LB->setText(QString::number((*it2).servicePort) + ":" + (*it2).targetAddress.toString() + ":" + QString::number((*it2).targetPort)); + break ; + } + break ; } - - hiddenService_LB->setText(hiddenservices_str) ; } showLog(); + adjustSize(); } void TorControlDialog::showLog() @@ -106,10 +127,9 @@ void TorControlDialog::showLog() for(QStringList::const_iterator it(logmsgs.begin());it!=logmsgs.end();++it) s += *it + "\n" ; - torLog_TB->setText(s) ; -// QCoreApplication::processEvents() ; +// torLog_TB->setText(s) ; -// std::cerr << s.toStdString() << std::endl; + std::cerr << s.toStdString() << std::endl; } TorControlDialog::TorStatus TorControlDialog::checkForTor() diff --git a/retroshare-gui/src/TorControl/TorControlWindow.h b/retroshare-gui/src/TorControl/TorControlWindow.h index ac70877b9..c7b6c024f 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.h +++ b/retroshare-gui/src/TorControl/TorControlWindow.h @@ -7,7 +7,7 @@ namespace Tor { class TorManager ; } -class TorControlDialog: public QDialog, public Ui::TorControlDialog +class TorControlDialog: public QWidget, public Ui::TorControlDialog { Q_OBJECT diff --git a/retroshare-gui/src/TorControl/TorControlWindow.ui b/retroshare-gui/src/TorControl/TorControlWindow.ui index 76985d0e3..7d5f3993a 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.ui +++ b/retroshare-gui/src/TorControl/TorControlWindow.ui @@ -1,70 +1,134 @@ TorControlDialog - + 0 0 - 739 - 489 + 600 + 188 + + + 0 + 0 + + Dialog - - - + + + + 75 + true + + + + Setting up Tor... + + + Qt::AlignCenter + + + + + + + - TextLabel + + + + :/icons/tor-logo.png + + + false - - - - Tor bootstrap status: - - - - - - - TextLabel - - - - - - - Hidden service: - - - - - - - Tor status: - - - - - - - TextLabel - - + + + + + + Tor status: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + Hidden service address: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Tor bootstrap status: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + TextLabel + + + + + + + Onion address: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + TextLabel + + + + - - - - + + + diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index 5fe788ba2..8fbbf5465 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -1,5 +1,6 @@ + icons/onion.png icons/svg/hidden.svg icons/svg/randomness.svg icons/svg/password.svg diff --git a/retroshare-gui/src/gui/icons/onion.png b/retroshare-gui/src/gui/icons/onion.png new file mode 100644 index 0000000000000000000000000000000000000000..256dc2403992029472d2d10f22c90e26629a5343 GIT binary patch literal 14776 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 rI3FK1zxm|`O)6f40QaxP* literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 036a702fe..3ce7ec2ec 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -313,8 +313,6 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); // #endif /* Start RetroShare */ - QSplashScreen splashScreen(QPixmap(":/images/logo/logo_splash.png")/* , Qt::WindowStaysOnTopHint*/); - QString sDefaultGXSIdToCreate = ""; switch (initResult) { case RS_INIT_OK: @@ -348,13 +346,13 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); sDefaultGXSIdToCreate = gd.getGXSNickname(); } - splashScreen.show(); + //splashScreen.show(); } break; case RS_INIT_HAVE_ACCOUNT: { - splashScreen.show(); - splashScreen.showMessage(rshare.translate("SplashScreen", "Load profile"), Qt::AlignHCenter | Qt::AlignBottom); + //splashScreen.show(); + //splashScreen.showMessage(rshare.translate("SplashScreen", "Load profile"), Qt::AlignHCenter | Qt::AlignBottom); RsPeerId preferredId; RsAccounts::GetPreferredAccountId(preferredId); @@ -394,7 +392,12 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); TorControlDialog tcd(torManager) ; tcd.show(); - while(tcd.checkForHiddenService() != 1+TorControlDialog::HIDDEN_SERVICE_STATUS_OK) // runs until some status is reached: either tor works, or it fails. + while(tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) // runs until some status is reached: either tor works, or it fails. + { + QCoreApplication::processEvents(); + usleep(0.2*1000*1000) ; + } + for(uint32_t i=0;i<10;++i) // give some time (2 secs) to see what's going on { QCoreApplication::processEvents(); usleep(0.2*1000*1000) ; @@ -410,6 +413,9 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); } #endif + QSplashScreen splashScreen(QPixmap(":/images/logo/logo_splash.png")/* , Qt::WindowStaysOnTopHint*/); + + splashScreen.show(); splashScreen.showMessage(rshare.translate("SplashScreen", "Load configuration"), Qt::AlignHCenter | Qt::AlignBottom); /* stop Retroshare if startup fails */ From 77d0337ae9f38b234a5a5c71246960ef6384364b Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 27 Dec 2017 18:59:50 +0100 Subject: [PATCH 09/42] auto-set hidden node address and ports from TorManager --- .../src/TorControl/TorControlWindow.cpp | 27 ++++----- retroshare-gui/src/TorControl/TorManager.cpp | 26 +++++++++ retroshare-gui/src/TorControl/TorManager.h | 3 + retroshare-gui/src/main.cpp | 55 +++++++++---------- 4 files changed, 64 insertions(+), 47 deletions(-) diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp index 835c04f9f..7ec3f547f 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.cpp +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -91,28 +91,21 @@ void TorControlDialog::statusChanged() torBootstrapStatus_LB->setText(bootstrapstatus_str) ; - QList hidden_services = mTorManager->control()->hiddenServices(); + QString service_id ; + QString onion_address ; + QHostAddress service_target_address ; + uint16_t service_port ; + uint16_t target_port ; - if(hidden_services.empty()) + if(mTorManager->getHiddenServiceInfo(service_id,onion_address,service_port, service_target_address,target_port)) { - hiddenServiceAddress_LB->setText(QString("[Not ready]")) ; - onionAddress_LB->setText(QString("[Not ready]")) ; + hiddenServiceAddress_LB->setText(QString::number(service_port) + ":" + service_target_address.toString() + ":" + QString::number(target_port)); + onionAddress_LB->setText(onion_address); } else { - QString hiddenservices_str ; - - for(auto it(hidden_services.begin());it!=hidden_services.end();++it) - { - onionAddress_LB->setText((*it)->hostname()); - - for(auto it2((*it)->targets().begin());it2!=(*it)->targets().end();++it2) - { - hiddenServiceAddress_LB->setText(QString::number((*it2).servicePort) + ":" + (*it2).targetAddress.toString() + ":" + QString::number((*it2).targetPort)); - break ; - } - break ; - } + hiddenServiceAddress_LB->setText(QString("[Not ready]")) ; + onionAddress_LB->setText(QString("[Not ready]")) ; } showLog(); diff --git a/retroshare-gui/src/TorControl/TorManager.cpp b/retroshare-gui/src/TorControl/TorManager.cpp index 8db6c205e..a6a6f0ab4 100644 --- a/retroshare-gui/src/TorControl/TorManager.cpp +++ b/retroshare-gui/src/TorControl/TorManager.cpp @@ -372,6 +372,32 @@ void TorManager::start() } } +bool TorManager::getHiddenServiceInfo(QString& service_id,QString& service_onion_address,uint16_t& service_port, QHostAddress& service_target_address,uint16_t& target_port) +{ + QList hidden_services = control()->hiddenServices(); + + if(hidden_services.empty()) + return false ; + + // Only return the first one. + + for(auto it(hidden_services.begin());it!=hidden_services.end();++it) + { + service_onion_address = (*it)->hostname(); + service_id = (*it)->privateKey().torServiceID(); + + for(auto it2((*it)->targets().begin());it2!=(*it)->targets().end();++it2) + { + service_port = (*it2).servicePort ; + service_target_address = (*it2).targetAddress ; + target_port = (*it2).targetPort; + break ; + } + break ; + } + return true ; +} + void TorManagerPrivate::processStateChanged(int state) { std::cerr << Q_FUNC_INFO << "state: " << state << " passwd=\"" << QString(process->controlPassword()).toStdString() << "\" " << process->controlHost().toString().toStdString() diff --git a/retroshare-gui/src/TorControl/TorManager.h b/retroshare-gui/src/TorControl/TorManager.h index 883159efb..4c5ffeb44 100644 --- a/retroshare-gui/src/TorControl/TorManager.h +++ b/retroshare-gui/src/TorControl/TorManager.h @@ -37,6 +37,7 @@ #include #include +#include namespace Tor { @@ -84,6 +85,8 @@ public: bool hasError() const; QString errorMessage() const; + bool getHiddenServiceInfo(QString& service_id,QString& service_onion_address,uint16_t& service_port, QHostAddress& service_target_address,uint16_t& target_port); + public slots: void start(); diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 3ce7ec2ec..5cc752b10 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -53,6 +53,7 @@ #endif #include "retroshare/rsidentity.h" +#include "retroshare/rspeers.h" #ifdef SIGFPE_DEBUG #include @@ -282,36 +283,6 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); /* Setup The GUI Stuff */ Rshare rshare(args, argc, argv, QString::fromUtf8(RsAccounts::ConfigDirectory().c_str())); -// #ifdef RETROTOR -// // First check that we can start the Tor engine, if not, quit. -// -// /* Tor control manager */ -// Tor::TorManager *torManager = Tor::TorManager::instance(); -// torManager->setDataDirectory(Rshare::dataDirectory() + QString("/tor/")); -// torManager->start(); -// -// // We do not need to show this dialog. If too much of a pain, we may hide it and only show when it reports an error. -// TorControlDialog tcd(torManager) ; -// -// { -// tcd.show(); -// -// while(tcd.checkForTor() == TorControlDialog::TOR_STATUS_UNKNOWN) // runs until some status is reached: either tor works, or it fails. -// { -// QCoreApplication::processEvents(); -// usleep(1000) ; -// } -// -// tcd.hide(); -// -// if(tcd.checkForTor() != TorControlDialog::TOR_STATUS_OK) -// { -// QMessageBox::critical(NULL,QObject::tr("Tor not found!"),QObject::tr("Tor wasn't found on your system. Please install it and re-start Retroshare.")) ; -// return 1 ; -// } -// } -// #endif - /* Start RetroShare */ QString sDefaultGXSIdToCreate = ""; switch (initResult) { @@ -425,10 +396,34 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); return 1; } +#ifdef RETROTOR + // Tor works with viable hidden service. Let's use it! + + QString service_id ; + QString onion_address ; + uint16_t service_port ; + uint16_t service_target_port ; + QHostAddress service_target_address ; + + torManager->getHiddenServiceInfo(service_id,onion_address,service_port,service_target_address,service_target_port); + + std::cerr << "Got hidden service info: " << std::endl; + std::cerr << " onion address : " << onion_address.toStdString() << std::endl; + std::cerr << " service_id : " << service_id.toStdString() << std::endl; + std::cerr << " service port : " << service_port << std::endl; + std::cerr << " target port : " << service_target_port << std::endl; + std::cerr << " target address : " << service_target_address.toString().toStdString() << std::endl; + + std::cerr << "Setting proxy server to " << service_target_address.toString().toStdString() << ":" << service_target_port << std::endl; + + rsPeers->setLocalAddress(rsPeers->getOwnId(), service_target_address.toString().toStdString(), service_target_port); + rsPeers->setHiddenNode(rsPeers->getOwnId(), onion_address.toStdString(), service_port); +#endif Rshare::initPlugins(); splashScreen.showMessage(rshare.translate("SplashScreen", "Create interface"), Qt::AlignHCenter | Qt::AlignBottom); + QCoreApplication::processEvents(); // forces splashscreen to show up RsharePeerSettings::Create(); From 475b6a4a62e30066a3c7026a9dda0d9debf911ee Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 28 Dec 2017 17:01:56 +0100 Subject: [PATCH 10/42] fixed auto-configuraiton of socks proxy --- .../src/TorControl/TorControlSocket.cpp | 2 +- .../src/TorControl/TorControlWindow.cpp | 39 +++++++++++++------ retroshare-gui/src/TorControl/TorManager.cpp | 10 ++++- retroshare-gui/src/TorControl/TorManager.h | 1 + retroshare-gui/src/main.cpp | 4 ++ 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/retroshare-gui/src/TorControl/TorControlSocket.cpp b/retroshare-gui/src/TorControl/TorControlSocket.cpp index b4c85d096..c6b1eb707 100644 --- a/retroshare-gui/src/TorControl/TorControlSocket.cpp +++ b/retroshare-gui/src/TorControl/TorControlSocket.cpp @@ -57,7 +57,7 @@ void TorControlSocket::sendCommand(TorControlCommand *command, const QByteArray commandQueue.append(command); write(data); - std::cerr << "torctrl: Sent: \"" << QString(data.trimmed()).toStdString() << "\"" << std::endl; + std::cerr << "[TOR CTRL] Sent: \"" << QString(data.trimmed()).toStdString() << "\"" << std::endl; } void TorControlSocket::registerEvent(const QByteArray &event, TorControlCommand *command) diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp index 7ec3f547f..f3d93a61d 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.cpp +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -37,17 +38,10 @@ TorControlDialog::TorControlDialog(Tor::TorManager *tm,QWidget *parent) timer->start(500) ; // Hide some debug output for the released version -// torLog_TB->hide(); - torBootstrapStatus_LB->hide(); - label_2->hide(); setWindowFlags( Qt::Dialog | Qt::FramelessWindowHint ); adjustSize(); - -// QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect(this); -// effect->setBlurRadius(30.0); -// setGraphicsEffect(effect); } void TorControlDialog::onIncomingConnection() @@ -86,10 +80,15 @@ void TorControlDialog::statusChanged() QVariantMap qvm = mTorManager->control()->bootstrapStatus(); QString bootstrapstatus_str ; - for(auto it(qvm.begin());it!=qvm.end();++it) - bootstrapstatus_str += it.key() + ":" + it.value().toString(); + std::cerr << "Bootstrap status map: " << std::endl; - torBootstrapStatus_LB->setText(bootstrapstatus_str) ; + for(auto it(qvm.begin());it!=qvm.end();++it) + std::cerr << " " << it.key().toStdString() << " : " << it.value().toString().toStdString() << std::endl; + + if(!qvm["progress"].toString().isNull()) + torBootstrapStatus_LB->setText(qvm["progress"].toString() + " % (" + qvm["summary"].toString() + ")") ; + else + torBootstrapStatus_LB->setText(tr("[Waiting for Tor...]")) ; QString service_id ; QString onion_address ; @@ -110,19 +109,35 @@ void TorControlDialog::statusChanged() showLog(); adjustSize(); + + QCoreApplication::processEvents(); // forces update } void TorControlDialog::showLog() { + static std::set already_seen ; + QString s ; QStringList logmsgs = mTorManager->logMessages() ; + bool can_print = false ; for(QStringList::const_iterator it(logmsgs.begin());it!=logmsgs.end();++it) + { s += *it + "\n" ; -// torLog_TB->setText(s) ; + if(already_seen.find(*it) == already_seen.end()) + { + can_print = true ; + already_seen.insert(*it); + } - std::cerr << s.toStdString() << std::endl; + if(can_print) + std::cerr << "[TOR DEBUG LOG] " << (*it).toStdString() << std::endl; + } + +// torLog_TB->setText(s) ;: + + std::cerr << "Connexion Proxy: " << mTorManager->control()->socksAddress().toString().toStdString() << ":" << mTorManager->control()->socksPort() << std::endl; } TorControlDialog::TorStatus TorControlDialog::checkForTor() diff --git a/retroshare-gui/src/TorControl/TorManager.cpp b/retroshare-gui/src/TorControl/TorManager.cpp index a6a6f0ab4..b7b14e5dc 100644 --- a/retroshare-gui/src/TorControl/TorManager.cpp +++ b/retroshare-gui/src/TorControl/TorManager.cpp @@ -372,6 +372,14 @@ void TorManager::start() } } +bool TorManager::getProxyServerInfo(QHostAddress& proxy_server_adress,uint16_t& proxy_server_port) +{ + proxy_server_adress = control()->socksAddress(); + proxy_server_port = control()->socksPort(); + + 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) { QList hidden_services = control()->hiddenServices(); @@ -488,7 +496,7 @@ bool TorManagerPrivate::createDefaultTorrc(const QString &path) static const char defaultTorrcContent[] = "SocksPort auto\n" "AvoidDiskWrites 1\n" - "DisableNetwork 1\n" +// "DisableNetwork 1\n" // (cyril) I removed this because it prevents Tor to bootstrap. "__ReloadTorrcOnSIGHUP 0\n"; QFile file(path); diff --git a/retroshare-gui/src/TorControl/TorManager.h b/retroshare-gui/src/TorControl/TorManager.h index 4c5ffeb44..254306779 100644 --- a/retroshare-gui/src/TorControl/TorManager.h +++ b/retroshare-gui/src/TorControl/TorManager.h @@ -86,6 +86,7 @@ public: QString errorMessage() const; bool getHiddenServiceInfo(QString& service_id,QString& 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); public slots: void start(); diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 5cc752b10..1d86a5c13 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -403,9 +403,12 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); QString onion_address ; uint16_t service_port ; uint16_t service_target_port ; + uint16_t proxy_server_port ; QHostAddress service_target_address ; + QHostAddress proxy_server_address ; torManager->getHiddenServiceInfo(service_id,onion_address,service_port,service_target_address,service_target_port); + torManager->getProxyServerInfo(proxy_server_address,proxy_server_port) ; std::cerr << "Got hidden service info: " << std::endl; std::cerr << " onion address : " << onion_address.toStdString() << std::endl; @@ -418,6 +421,7 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); rsPeers->setLocalAddress(rsPeers->getOwnId(), service_target_address.toString().toStdString(), service_target_port); rsPeers->setHiddenNode(rsPeers->getOwnId(), onion_address.toStdString(), service_port); + rsPeers->setProxyServer(RS_HIDDEN_TYPE_TOR, proxy_server_address.toString().toStdString(),proxy_server_port) ; #endif Rshare::initPlugins(); From a591001cecd3f3754894397838920269dccef22f Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 28 Dec 2017 21:39:35 +0100 Subject: [PATCH 11/42] improved Tor startup phase integration in TorControlDialog --- .../src/TorControl/TorControlWindow.cpp | 30 +++++++------- .../src/gui/settings/ServerPage.cpp | 41 ++++++++++++++++--- retroshare-gui/src/gui/settings/ServerPage.ui | 8 ++-- retroshare-gui/src/main.cpp | 12 +++--- 4 files changed, 61 insertions(+), 30 deletions(-) diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp index f3d93a61d..4cd626298 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.cpp +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -29,6 +29,7 @@ TorControlDialog::TorControlDialog(Tor::TorManager *tm,QWidget *parent) mIncomingServer = new QTcpServer(this) ; mHiddenService = NULL ; mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_UNKNOWN; + //mBootstrapPhaseFinished = false ; connect(mIncomingServer, SIGNAL(QTcpServer::newConnection()), this, SLOT(onIncomingConnection())); @@ -51,19 +52,19 @@ void TorControlDialog::onIncomingConnection() void TorControlDialog::statusChanged() { - int status = mTorManager->control()->status(); + int tor_control_status = mTorManager->control()->status(); int torstatus = mTorManager->control()->torStatus(); - QString status_str,torstatus_str ; + QString tor_control_status_str,torstatus_str ; - switch(status) + switch(tor_control_status) { default: - case Tor::TorControl::Error : status_str = "Error" ; break ; - case Tor::TorControl::NotConnected: status_str = "Not connected" ; break ; - case Tor::TorControl::Connecting: status_str = "Connecting" ; break ; - case Tor::TorControl::Authenticating: status_str = "Authenticating" ; break ; - case Tor::TorControl::Connected: status_str = "Connected" ; break ; + case Tor::TorControl::Error : tor_control_status_str = "Error" ; break ; + case Tor::TorControl::NotConnected: tor_control_status_str = "Not connected" ; break ; + case Tor::TorControl::Connecting: tor_control_status_str = "Connecting" ; break ; + case Tor::TorControl::Authenticating: tor_control_status_str = "Authenticating" ; break ; + case Tor::TorControl::Connected: tor_control_status_str = "Connected" ; break ; } switch(torstatus) @@ -74,12 +75,15 @@ void TorControlDialog::statusChanged() case Tor::TorControl::TorReady: torstatus_str = "Tor ready" ; break ; } - //torStatus_LB->setText(torstatus_str + "(" + status_str + ")") ; - torStatus_LB->setText(status_str) ; + torStatus_LB->setText(torstatus_str) ; + //torStatus_LB->setText(tor_control_status_str) ; QVariantMap qvm = mTorManager->control()->bootstrapStatus(); QString bootstrapstatus_str ; + std::cerr << "Tor control status: " << tor_control_status_str.toStdString() << std::endl; + std::cerr << "Tor status: " << torstatus_str.toStdString() << std::endl; + std::cerr << "Bootstrap status map: " << std::endl; for(auto it(qvm.begin());it!=qvm.end();++it) @@ -142,11 +146,9 @@ void TorControlDialog::showLog() TorControlDialog::TorStatus TorControlDialog::checkForTor() { - switch(mTorManager->control()->status()) + switch(mTorManager->control()->torStatus()) { - case Tor::TorControl::Connected: usleep(1*1000*1000);return TOR_STATUS_OK ; - case Tor::TorControl::Error: return TOR_STATUS_FAIL ; - + case Tor::TorControl::TorReady: usleep(1*1000*1000);return TOR_STATUS_OK ; default: return TOR_STATUS_UNKNOWN ; } diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index e2179e8f1..fe2939cf6 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -59,7 +59,17 @@ /// /// \brief hiddenServiceIncomingTab index of hidden serice incoming tab /// -const static uint32_t hiddenServiceIncomingTab = 2; +/// + +#ifdef RETROTOR +const static uint32_t TAB_HIDDEN_SERVICE_INCOMING = 1; +const static uint32_t TAB_IP_FILTERS = 99; // This is a trick: these tabs do not exist, so enabling/disabling them has no effect +const static uint32_t TAB_RELAYS = 99; +#else +const static uint32_t TAB_IP_FILTERS = 1; +const static uint32_t TAB_HIDDEN_SERVICE_INCOMING = 2; +const static uint32_t TAB_RELAYS = 3; +#endif //#define SERVER_DEBUG 1 @@ -71,6 +81,24 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) manager = NULL ; +#ifdef RETROTOR + ui.tabWidget->removeTab(3) ; // remove relays. Not useful in Tor mode. + ui.tabWidget->removeTab(1) ; // remove IP filters. Not useful in Tor mode. + + ui.hiddenServiceTab->removeTab(1) ; // remove the Automatic I2P/BOB tab + ui.hiddenpage_proxyAddress_i2p->hide() ; + ui.hiddenpage_proxyLabel_i2p->hide() ; + ui.hiddenpage_proxyPort_i2p->hide() ; + ui.label_i2p_outgoing->hide() ; + ui.iconlabel_i2p_outgoing->hide() ; + ui.plainTextEdit->hide() ; + ui.hiddenpage_configuration->hide() ; + ui.l_hiddenpage_configuration->hide() ; + ui.hiddenpageInHelpPlainTextEdit->hide() ; + + ui.hiddenpage_outHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ; + ui.hiddenpage_inHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ; +#endif ui.filteredIpsTable->setHorizontalHeaderItem(COLUMN_RANGE,new QTableWidgetItem(tr("IP Range"))) ; ui.filteredIpsTable->setHorizontalHeaderItem(COLUMN_STATUS,new QTableWidgetItem(tr("Status"))) ; ui.filteredIpsTable->setHorizontalHeaderItem(COLUMN_ORIGIN,new QTableWidgetItem(tr("Origin"))) ; @@ -98,7 +126,7 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) for(std::list::const_iterator it(ip_servers.begin());it!=ip_servers.end();++it) ui.IPServersLV->addItem(QString::fromStdString(*it)) ; - ui.hiddenServiceTab->setTabEnabled(hiddenServiceIncomingTab, false); + ui.hiddenServiceTab->setTabEnabled(TAB_HIDDEN_SERVICE_INCOMING, false); ui.gbBob->setEnabled(false); ui.swBobAdvanced->setCurrentIndex(0); @@ -195,7 +223,6 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) QObject::connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(updateRelayMode())); QObject::connect(ui.serverCheckBox,SIGNAL(toggled(bool)),this,SLOT(updateRelayMode())); - } void ServerPage::saveAndTestInProxy() @@ -299,8 +326,8 @@ void ServerPage::load() if (mIsHiddenNode) { mHiddenType = detail.hiddenType; - ui.tabWidget->setTabEnabled(1,false) ; // ip filter - ui.tabWidget->setTabEnabled(3,false) ; // relay + ui.tabWidget->setTabEnabled(TAB_IP_FILTERS,false) ; // ip filter + ui.tabWidget->setTabEnabled(TAB_RELAYS,false) ; // relay loadHiddenNode(); return; } @@ -856,6 +883,8 @@ void ServerPage::toggleUPnP() settingChangeable = true; } + // Shouldn't we use readOnly instead of enabled?? + if (settingChangeable) { ui.localAddress->setEnabled(false); @@ -1048,7 +1077,7 @@ void ServerPage::loadHiddenNode() ui.label_dynDNS->setVisible(false); ui.dynDNS ->setVisible(false); - ui.hiddenServiceTab->setTabEnabled(hiddenServiceIncomingTab, true); + ui.hiddenServiceTab->setTabEnabled(TAB_HIDDEN_SERVICE_INCOMING, true); /* Addresses must be set here - otherwise can't edit it */ /* set local address */ diff --git a/retroshare-gui/src/gui/settings/ServerPage.ui b/retroshare-gui/src/gui/settings/ServerPage.ui index 666e69bab..5b4051914 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.ui +++ b/retroshare-gui/src/gui/settings/ServerPage.ui @@ -6,8 +6,8 @@ 0 0 - 1220 - 896 + 1283 + 917 @@ -26,7 +26,7 @@ - 0 + 2 @@ -810,7 +810,7 @@ behind a firewall or a VPN. - 0 + 2 diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 1d86a5c13..70f041b23 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -363,16 +363,16 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); TorControlDialog tcd(torManager) ; tcd.show(); - while(tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) // runs until some status is reached: either tor works, or it fails. - { - QCoreApplication::processEvents(); - usleep(0.2*1000*1000) ; - } - for(uint32_t i=0;i<10;++i) // give some time (2 secs) to see what's going on + while(tcd.checkForTor() != TorControlDialog::TOR_STATUS_OK || tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) // runs until some status is reached: either tor works, or it fails. { QCoreApplication::processEvents(); usleep(0.2*1000*1000) ; } +// for(uint32_t i=0;i<10;++i) // give some time (2 secs) to see what's going on +// { +// QCoreApplication::processEvents(); +// usleep(0.2*1000*1000) ; +// } tcd.hide(); From 064df4cccaed2e1af92569197ff30957046a48bb Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 31 Dec 2017 16:09:44 +0100 Subject: [PATCH 12/42] added scripts to make retrotor AppImage --- .../AppImage/makeAppImage_retrotor.sh | 3 +++ build_scripts/AppImage/retrotor.yml | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100755 build_scripts/AppImage/makeAppImage_retrotor.sh create mode 100644 build_scripts/AppImage/retrotor.yml diff --git a/build_scripts/AppImage/makeAppImage_retrotor.sh b/build_scripts/AppImage/makeAppImage_retrotor.sh new file mode 100755 index 000000000..5e128fd5c --- /dev/null +++ b/build_scripts/AppImage/makeAppImage_retrotor.sh @@ -0,0 +1,3 @@ +#!/bin/sh +./Recipe retrotor.yml + diff --git a/build_scripts/AppImage/retrotor.yml b/build_scripts/AppImage/retrotor.yml new file mode 100644 index 000000000..dbcabf36d --- /dev/null +++ b/build_scripts/AppImage/retrotor.yml @@ -0,0 +1,19 @@ +app: retroshare +union: true + +ingredients: + dist: trusty + sources: + - deb http://archive.ubuntu.com/ubuntu trusty main restricted universe multiverse + - deb http://archive.ubuntu.com/ubuntu trusty-updates main restricted universe multiverse + ppas: + - retroshare/retrotor + packages: + - libqt4-svg + - tor + - retroshare + +script: + - rm -rf usr/share/glib-2.0/schemas/ + - sed -i -e 's|/usr/share/pixmaps/||g' retroshare.desktop + - sed -i -e 's|/usr/bin/||g' retroshare.desktop From c00a236004a19b461bdf7b28c0696a931fc67bd6 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 31 Dec 2017 16:22:19 +0100 Subject: [PATCH 13/42] added ubuntu packaging scripts for retro-tor --- .../Debian+Ubuntu/makeSourcePackage.sh | 12 ++++ build_scripts/Debian+Ubuntu/rules.retrotor | 61 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100755 build_scripts/Debian+Ubuntu/rules.retrotor diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index 9e3bd4fff..553a0587e 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -27,6 +27,7 @@ time=`git log --pretty=format:"%aD" | head -1 | cut -d\ -f5 | sed -e s/://g` hhsh=`git log --pretty=format:"%H" | head -1 | cut -c1-8` rev=${date}.${hhsh} +useretrotor="false" while [ ${#} -gt 0 ]; do case ${1} in @@ -34,6 +35,9 @@ while [ ${#} -gt 0 ]; do rev=${1} shift ;; + "-retrotor") shift + useretrotor="true" + ;; "-distribution") shift dist=${1} shift @@ -71,6 +75,10 @@ echo " "Hash : ${hhsh} echo " "Using branch : ${branch} echo " "Using revision : ${rev} +if test ${useretrotor} = "true"; then + echo " "Specific flags : retrotor +fi + echo Done. version="${version}"."${rev}" echo Got version number ${version}. @@ -121,6 +129,10 @@ for i in ${dist}; do echo copying changelog for ${i} sed -e s/XXXXXX/"${rev}"/g -e s/YYYYYY/"${i}"/g ../changelog > debian/changelog + if test ${useretrotor} = "true"; then + cp ../rules.retrotor debian/rules + fi + if test -f ../control."${i}" ; then echo \/\!\\ Using specific control file for distribution "${i}" cp ../control."${i}" debian/control diff --git a/build_scripts/Debian+Ubuntu/rules.retrotor b/build_scripts/Debian+Ubuntu/rules.retrotor new file mode 100755 index 000000000..a5cc9dd9a --- /dev/null +++ b/build_scripts/Debian+Ubuntu/rules.retrotor @@ -0,0 +1,61 @@ +#!/usr/bin/make -f + +configure: configure-stamp +configure-stamp: + dh_testdir + cd src && qmake "CONFIG-=debug" "CONFIG+=release" "CONFIG+=rs_autologin" PREFIX=/usr LIB_DIR=/usr/lib RetroShare.pro + touch $@ + + +build: build-stamp +build-stamp: configure-stamp + dh_testdir + # Add here commands to compile the package. + # cd libssh-0.6.4 && mkdir -p build && cd build && cmake -DWITH_STATIC_LIB=ON .. && make + # cd sqlcipher && ./configure --disable-shared --enable-static --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-lcrypto" && make + # mkdir lib + # cp -r libssh-0.6.4 lib/ + #cp -r sqlcipher lib/ + #cd src/rsctrl/src && make + cd src && $(MAKE) + touch $@ + +clean: + dh_testdir + dh_testroot + rm -f configure-stamp build-stamp + # Add here commands to clean up after the build process. + [ ! -f src/Makefile ] || (cd src && $(MAKE) distclean) + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + #dh_installdirs + cd src && $(MAKE) INSTALL_ROOT=$(CURDIR)/debian/tmp install + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_install --list-missing + #dh_installdocs + #dh_installexamples + #dh_installman + dh_link + dh_strip + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure From da5253059a3155b6dd02d32eb7a63cc3522c726d Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 31 Dec 2017 17:27:21 +0100 Subject: [PATCH 14/42] fixed retrotor compilation when removing dht and udp --- RetroShare.pro | 13 +++++++++--- libretroshare/src/libretroshare.pro | 12 +++++++---- libretroshare/src/pqi/pqinetstatebox.cc | 2 ++ libretroshare/src/pqi/pqisslpersongrp.cc | 3 +++ libretroshare/src/rsserver/rsinit.cc | 20 +++++++++++++++---- .../src/gui/connect/ConnectProgressDialog.cpp | 4 ++++ .../src/gui/statistics/DhtWindow.cpp | 3 ++- retroshare.pri | 5 ++--- 8 files changed, 47 insertions(+), 15 deletions(-) diff --git a/RetroShare.pro b/RetroShare.pro index 833173029..9a6f24d5f 100644 --- a/RetroShare.pro +++ b/RetroShare.pro @@ -6,12 +6,16 @@ TEMPLATE = subdirs SUBDIRS += openpgpsdk openpgpsdk.file = openpgpsdk/src/openpgpsdk.pro -SUBDIRS += libbitdht -libbitdht.file = libbitdht/src/libbitdht.pro +retrotor { + libretroshare.depends = openpgpsdk +} else { + SUBDIRS += libbitdht + libbitdht.file = libbitdht/src/libbitdht.pro + libretroshare.depends = openpgpsdk libbitdht +} SUBDIRS += libretroshare libretroshare.file = libretroshare/src/libretroshare.pro -libretroshare.depends = openpgpsdk libbitdht SUBDIRS += libresapi libresapi.file = libresapi/src/libresapi.pro @@ -24,12 +28,15 @@ retroshare_gui { retroshare_gui.target = retroshare_gui } +retrotor { +} else { retroshare_nogui { SUBDIRS += retroshare_nogui retroshare_nogui.file = retroshare-nogui/src/retroshare-nogui.pro retroshare_nogui.depends = libretroshare libresapi retroshare_nogui.target = retroshare_nogui } +} retroshare_android_service { SUBDIRS += retroshare_android_service diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index e58d01eef..7093f273e 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -1,7 +1,7 @@ !include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") TEMPLATE = lib -CONFIG += staticlib bitdht +CONFIG += staticlib CONFIG += create_prl CONFIG -= qt TARGET = retroshare @@ -12,8 +12,12 @@ DESTDIR = lib retrotor { DEFINES *= RETROTOR + CONFIG -= bitdht +} else { + CONFIG += bitdht } -# the dht stunner is used to obtain RS' external ip addr. when it is natted + +# the dht stunner is used to obtain RS external ip addr. when it is natted # this system is unreliable and rs supports a newer and better one (asking connected peers) # CONFIG += useDhtStunner @@ -93,6 +97,7 @@ HEADERS += tcponudp/udppeer.h \ tcponudp/tcpstream.h \ tcponudp/tou.h \ tcponudp/udprelay.h \ + pqi/pqissludp.h \ SOURCES += tcponudp/udppeer.cc \ tcponudp/tcppacket.cc \ @@ -100,6 +105,7 @@ SOURCES += tcponudp/udppeer.cc \ tcponudp/tou.cc \ tcponudp/bss_tou.c \ tcponudp/udprelay.cc \ + pqi/pqissludp.cc \ useDhtStunner { HEADERS += dht/stunaddrassist.h \ @@ -437,7 +443,6 @@ HEADERS += pqi/authssl.h \ pqi/pqissllistener.h \ pqi/pqisslpersongrp.h \ pqi/pqissli2pbob.h \ - pqi/pqissludp.h \ pqi/pqisslproxy.h \ pqi/pqistore.h \ pqi/pqistreamer.h \ @@ -593,7 +598,6 @@ SOURCES += pqi/authgpg.cc \ pqi/pqissllistener.cc \ pqi/pqisslpersongrp.cc \ pqi/pqissli2pbob.cpp \ - pqi/pqissludp.cc \ pqi/pqisslproxy.cc \ pqi/pqistore.cc \ pqi/pqistreamer.cc \ diff --git a/libretroshare/src/pqi/pqinetstatebox.cc b/libretroshare/src/pqi/pqinetstatebox.cc index b08994855..128c4d9e5 100644 --- a/libretroshare/src/pqi/pqinetstatebox.cc +++ b/libretroshare/src/pqi/pqinetstatebox.cc @@ -4,7 +4,9 @@ #include "pqi/pqinetstatebox.h" #include "time.h" +#ifdef RS_USE_BITDHT #include "bitdht/bdiface.h" +#endif // External Interface. diff --git a/libretroshare/src/pqi/pqisslpersongrp.cc b/libretroshare/src/pqi/pqisslpersongrp.cc index 432ba1bbf..20fe314d4 100644 --- a/libretroshare/src/pqi/pqisslpersongrp.cc +++ b/libretroshare/src/pqi/pqisslpersongrp.cc @@ -36,6 +36,9 @@ static struct RsLog::logInfo pqipersongrpzoneInfo = {RsLog::Default, "pqipersong /**** * #define PQI_DISABLE_UDP 1 ***/ +#ifdef RETROTOR +#define PQI_DISABLE_UDP 1 +#endif /********************************** SSL Specific features ***************************/ diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index dae235aa2..797d53067 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -65,6 +65,11 @@ #include #endif +// This needs to be defined here, because when USE_BITDHT is unset, the variable, that is defined in libbitdht (not compiled!) will be missing. +#ifndef RS_USE_BITDHT +RsDht *rsDht = NULL ; +#endif + // for blocking signals #include @@ -825,9 +830,10 @@ RsGRouter *rsGRouter = NULL ; #include "pqi/p3linkmgr.h" #include "pqi/p3netmgr.h" - +#ifndef RETROTOR #include "tcponudp/tou.h" #include "tcponudp/rsudpstack.h" +#endif #ifdef RS_USE_BITDHT @@ -1155,9 +1161,9 @@ int RsServer::StartupRetroShare() #ifdef RS_USE_DHT_STUNNER mNetMgr->setAddrAssist(new stunAddrAssist(mDhtStunner), new stunAddrAssist(mProxyStunner)); #endif // RS_USE_DHT_STUNNER -#else //RS_USE_BITDHT - /* install NULL Pointer for rsDht Interface */ - rsDht = NULL; +// #else //RS_USE_BITDHT +// /* install NULL Pointer for rsDht Interface */ +// rsDht = NULL; #endif //RS_USE_BITDHT @@ -1474,7 +1480,11 @@ int RsServer::StartupRetroShare() interfaces.mMsgs = rsMsgs; interfaces.mTurtle = rsTurtle; interfaces.mDisc = rsDisc; +#ifdef RS_USE_BITDHT interfaces.mDht = rsDht; +#else + interfaces.mDht = NULL; +#endif interfaces.mNotify = mNotify; interfaces.mServiceControl = serviceCtrl; interfaces.mPluginHandler = mPluginsManager; @@ -1511,7 +1521,9 @@ int RsServer::StartupRetroShare() p3BanList *mBanList = new p3BanList(serviceCtrl, mNetMgr); rsBanList = mBanList ; pqih -> addService(mBanList, true); +#ifdef RS_USE_BITDHT mBitDht->setupPeerSharer(mBanList); +#endif p3BandwidthControl *mBwCtrl = new p3BandwidthControl(pqih); pqih -> addService(mBwCtrl, true); diff --git a/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp b/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp index aae2af466..1f860acde 100755 --- a/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp +++ b/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp @@ -484,6 +484,7 @@ void ConnectProgressDialog::updateLookupStatus() ui->LookupProgressBar->setValue(calcProgress(now, mLookupTS, CONNECT_LOOKUP_TYPICAL, CONNECT_LOOKUP_SLOW, CONNECT_LOOKUP_PERIOD)); +#ifdef RS_USE_BITDHT /* now actually look at the DHT Details */ RsDhtNetPeer status; rsDht->getNetPeerStatus(mId, status); @@ -520,6 +521,7 @@ void ConnectProgressDialog::updateLookupStatus() mLookupStatus = CONNECT_LOOKUP_ONLINE; break; } +#endif } @@ -572,6 +574,7 @@ void ConnectProgressDialog::updateUdpStatus() ui->UdpProgressBar->setValue(calcProgress(now, mUdpTS, CONNECT_UDP_TYPICAL, CONNECT_UDP_SLOW, CONNECT_UDP_PERIOD)); +#ifdef RS_USE_BITDHT /* now lookup details from Dht */ RsDhtNetPeer status; rsDht->getNetPeerStatus(mId, status); @@ -599,6 +602,7 @@ void ConnectProgressDialog::updateUdpStatus() } } } +#endif } diff --git a/retroshare-gui/src/gui/statistics/DhtWindow.cpp b/retroshare-gui/src/gui/statistics/DhtWindow.cpp index a6406743d..5684593fd 100644 --- a/retroshare-gui/src/gui/statistics/DhtWindow.cpp +++ b/retroshare-gui/src/gui/statistics/DhtWindow.cpp @@ -279,6 +279,7 @@ void DhtWindow::updateNetStatus() void DhtWindow::updateNetPeers() { +#ifdef RS_USE_BITDHT //QTreeWidget *peerTreeWidget = ui.peerTreeWidget; std::list peerIds; @@ -364,7 +365,6 @@ void DhtWindow::updateNetPeers() QHeaderView * _header = ui.peerTreeWidget->header () ; _header->resizeSection ( PTW_COL_RSNAME, 170 ); - /* update the data */ RsDhtNetPeer status; rsDht->getNetPeerStatus(*it, status); @@ -518,6 +518,7 @@ void DhtWindow::updateNetPeers() //peerSummaryLabel->setText(connstr); +#endif } diff --git a/retroshare.pri b/retroshare.pri index 5ae0e46b0..db1834efe 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -3,9 +3,8 @@ CONFIG *= retroshare_gui no_retroshare_gui:CONFIG -= retroshare_gui -# To build the RetroTor executable, just include the following option - -CONFIG *= retrotor +# To build the RetroTor executable, just uncomment the following option +# CONFIG *= retrotor # To disable RetroShare-nogui append the following # assignation to qmake command line "CONFIG+=no_retroshare_nogui" From 6feb1bc0ec952af9aa27a94925b6d008cc2ee757 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 31 Dec 2017 18:15:19 +0100 Subject: [PATCH 15/42] fixed dependencies --- .../Debian+Ubuntu/makeSourcePackage.sh | 20 +++++++++++-------- build_scripts/Debian+Ubuntu/rules.retrotor | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index 553a0587e..4f2d8b10f 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -36,7 +36,7 @@ while [ ${#} -gt 0 ]; do shift ;; "-retrotor") shift - useretrotor="true" + useretrotor="true" ;; "-distribution") shift dist=${1} @@ -58,6 +58,11 @@ while [ ${#} -gt 0 ]; do esac done +if test "${useretrotor}" = "true"; then + gitpath="https://github.com/csoler/RetroShare.git" + branch="v0.6-TorOnly" +fi + if test "${dist}" = "" ; then dist="precise trusty xenial zesty artful" fi @@ -91,7 +96,7 @@ echo Extracting base archive... mkdir -p ${workdir}/src echo Checking out latest snapshot... cd ${workdir}/src -git clone --depth 1 https://github.com/RetroShare/RetroShare.git --single-branch --branch $branch . +git clone --depth 1 ${gitpath} --single-branch --branch $branch . # if ! test "$hhsh" = "" ; then # echo Checking out revision $hhsh @@ -131,15 +136,14 @@ for i in ${dist}; do if test ${useretrotor} = "true"; then cp ../rules.retrotor debian/rules - fi - - if test -f ../control."${i}" ; then + cp ../control.trusty_retrotor debian/control + elif test -f ../control."${i}" ; then echo \/\!\\ Using specific control file for distribution "${i}" - cp ../control."${i}" debian/control + cp ../control."${i}" debian/control else echo Using standard control file control."${i}" for distribution "${i}" - cp ../debian/control debian/control - fi + cp ../debian/control debian/control + fi debuild -S -k${gpgkey} done diff --git a/build_scripts/Debian+Ubuntu/rules.retrotor b/build_scripts/Debian+Ubuntu/rules.retrotor index a5cc9dd9a..06655ef88 100755 --- a/build_scripts/Debian+Ubuntu/rules.retrotor +++ b/build_scripts/Debian+Ubuntu/rules.retrotor @@ -3,7 +3,7 @@ configure: configure-stamp configure-stamp: dh_testdir - cd src && qmake "CONFIG-=debug" "CONFIG+=release" "CONFIG+=rs_autologin" PREFIX=/usr LIB_DIR=/usr/lib RetroShare.pro + cd src && qmake "CONFIG-=debug" "CONFIG+=release retrotor" "CONFIG+=rs_autologin" PREFIX=/usr LIB_DIR=/usr/lib RetroShare.pro touch $@ From d018fdcbb47d3b9b4350929db584c8bda0195ec4 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 31 Dec 2017 18:50:02 +0100 Subject: [PATCH 16/42] updated retrotor packaging control file --- .../Debian+Ubuntu/control.trusty_retrotor | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 build_scripts/Debian+Ubuntu/control.trusty_retrotor diff --git a/build_scripts/Debian+Ubuntu/control.trusty_retrotor b/build_scripts/Debian+Ubuntu/control.trusty_retrotor new file mode 100644 index 000000000..9114ef2ee --- /dev/null +++ b/build_scripts/Debian+Ubuntu/control.trusty_retrotor @@ -0,0 +1,29 @@ +Source: retroshare +Section: devel +Priority: standard +Maintainer: Cyril Soler +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.6, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev, qtmultimedia5-dev, qttools5-dev, libqt5x11extras5-dev, qt5-default +Standards-Version: 3.9.6 +Homepage: http://retroshare.sourceforge.net + +Package: retroshare-voip-plugin +Architecture: any +Conflicts: retroshare06-voip-plugin +Depends: ${shlibs:Depends}, ${misc:Depends}, retrotor, libspeex1, libspeexdsp1, libqt5multimedia5 +Description: RetroShare VOIP plugin + This package provides a plugin for RetroShare, a secured Friend-to-Friend communication + plateform. The plugin adds voice-over-IP functionality to the private chat window. Both + friends chatting together need the plugin installed to be able to talk together. + +Package: retrotor +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring, tor +Conflicts: retroshare-nogui,retroshare06, retroshare +Description: Secure communication with friends + RetroShare is a Open Source cross-platform, private and secure decentralised + commmunication platform. It lets you to securely chat and share files with your + friends and family, using a web-of-trust to authenticate peers and OpenSSL to + encrypt all communication. RetroShare provides filesharing, chat, messages, + forums and channels. + + From 2c10f4f3407fa1b074d92d7d299ab88f790b36a1 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 1 Jan 2018 12:46:14 +0100 Subject: [PATCH 17/42] fixed retrotor packaging control file --- build_scripts/Debian+Ubuntu/control.trusty_retrotor | 9 --------- 1 file changed, 9 deletions(-) diff --git a/build_scripts/Debian+Ubuntu/control.trusty_retrotor b/build_scripts/Debian+Ubuntu/control.trusty_retrotor index 9114ef2ee..4c41786e2 100644 --- a/build_scripts/Debian+Ubuntu/control.trusty_retrotor +++ b/build_scripts/Debian+Ubuntu/control.trusty_retrotor @@ -6,15 +6,6 @@ Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, libssl-dev, libxs Standards-Version: 3.9.6 Homepage: http://retroshare.sourceforge.net -Package: retroshare-voip-plugin -Architecture: any -Conflicts: retroshare06-voip-plugin -Depends: ${shlibs:Depends}, ${misc:Depends}, retrotor, libspeex1, libspeexdsp1, libqt5multimedia5 -Description: RetroShare VOIP plugin - This package provides a plugin for RetroShare, a secured Friend-to-Friend communication - plateform. The plugin adds voice-over-IP functionality to the private chat window. Both - friends chatting together need the plugin installed to be able to talk together. - Package: retrotor Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring, tor From fcc3995d8780a96af6a56d0efce979c88ad923ee Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 1 Jan 2018 15:49:49 +0100 Subject: [PATCH 18/42] removed BanList service from Retro-Tor version --- libretroshare/src/pqi/p3netmgr.cc | 4 +-- libretroshare/src/pqi/p3peermgr.cc | 8 +++--- libretroshare/src/pqi/pqissl.cc | 12 ++++----- libretroshare/src/rsserver/rsinit.cc | 7 +++++ retroshare-gui/src/gui/AboutWidget.cpp | 5 ++-- retroshare-gui/src/gui/GenCertDialog.cpp | 26 +++++++++++++------ .../src/gui/settings/ServerPage.cpp | 3 +++ retroshare-gui/src/gui/settings/ServerPage.ui | 2 +- retroshare.pri | 9 ++++++- 9 files changed, 52 insertions(+), 24 deletions(-) diff --git a/libretroshare/src/pqi/p3netmgr.cc b/libretroshare/src/pqi/p3netmgr.cc index 03c809789..2d593e42f 100644 --- a/libretroshare/src/pqi/p3netmgr.cc +++ b/libretroshare/src/pqi/p3netmgr.cc @@ -718,7 +718,7 @@ void p3NetMgrIMPL::netExtCheck() #endif if(sockaddr_storage_isValidNet(tmpip)) { - if(rsBanList->isAddressAccepted(tmpip,RSBANLIST_CHECKING_FLAGS_BLACKLIST)) + if( (rsBanList==NULL) || rsBanList->isAddressAccepted(tmpip,RSBANLIST_CHECKING_FLAGS_BLACKLIST)) { // must be stable??? isStable = true; @@ -761,7 +761,7 @@ void p3NetMgrIMPL::netExtCheck() /* input network bits */ if (mDhtStunner->getExternalAddr(tmpaddr, isstable)) { - if(rsBanList->isAddressAccepted(tmpaddr,RSBANLIST_CHECKING_FLAGS_BLACKLIST)) + if((rsBanList == NULL) || rsBanList->isAddressAccepted(tmpaddr,RSBANLIST_CHECKING_FLAGS_BLACKLIST)) { // must be stable??? isStable = (isstable == 1); diff --git a/libretroshare/src/pqi/p3peermgr.cc b/libretroshare/src/pqi/p3peermgr.cc index d62d2ca08..61deb9713 100644 --- a/libretroshare/src/pqi/p3peermgr.cc +++ b/libretroshare/src/pqi/p3peermgr.cc @@ -1218,7 +1218,7 @@ bool p3PeerMgrIMPL::UpdateOwnAddress(const struct sockaddr_storage &localAddr, std::cerr << ")" << std::endl; #endif - if(!rsBanList->isAddressAccepted(localAddr, RSBANLIST_CHECKING_FLAGS_BLACKLIST)) + if((rsBanList != NULL) && !rsBanList->isAddressAccepted(localAddr, RSBANLIST_CHECKING_FLAGS_BLACKLIST)) { std::cerr << "(SS) Trying to set own IP to a banned IP " << sockaddr_storage_iptostring(localAddr) << ". This probably means that a friend in under traffic re-routing attack." << std::endl; return false ; @@ -1357,7 +1357,7 @@ bool p3PeerMgrIMPL::setExtAddress(const RsPeerId &id, const struct sockaddr_s bool changed = false; uint32_t check_res = 0 ; - if(!rsBanList->isAddressAccepted(addr,RSBANLIST_CHECKING_FLAGS_BLACKLIST,&check_res)) + if(rsBanList!=NULL && !rsBanList->isAddressAccepted(addr,RSBANLIST_CHECKING_FLAGS_BLACKLIST,&check_res)) { std::cerr << "(SS) trying to set external contact address for peer " << id << " to a banned address " << sockaddr_storage_iptostring(addr )<< std::endl; return false ; @@ -1531,7 +1531,7 @@ bool p3PeerMgrIMPL::addCandidateForOwnExternalAddress(const RsPeerId &from, cons // Notify for every friend that has reported a wrong external address, except if that address is in the IP whitelist. - if((!rsBanList->isAddressAccepted(addr_filtered,RSBANLIST_CHECKING_FLAGS_WHITELIST)) && (!sockaddr_storage_sameip(own_addr,addr_filtered))) + if((rsBanList!=NULL && !rsBanList->isAddressAccepted(addr_filtered,RSBANLIST_CHECKING_FLAGS_WHITELIST)) && (!sockaddr_storage_sameip(own_addr,addr_filtered))) { std::cerr << " Peer " << from << " reports a connection address (" << sockaddr_storage_iptostring(addr_filtered) <<") that is not your current external address (" << sockaddr_storage_iptostring(own_addr) << "). This is weird." << std::endl; @@ -2774,7 +2774,7 @@ bool p3PeerMgrIMPL::removeBannedIps() if(cleanIpList(it->second.ipAddrs.mExt.mAddrs,it->first,mLinkMgr)) changed = true ; if(cleanIpList(it->second.ipAddrs.mLocal.mAddrs,it->first,mLinkMgr)) changed = true ; - if(!rsBanList->isAddressAccepted(it->second.serveraddr,RSBANLIST_CHECKING_FLAGS_BLACKLIST)) + if(rsBanList!=NULL && !rsBanList->isAddressAccepted(it->second.serveraddr,RSBANLIST_CHECKING_FLAGS_BLACKLIST)) { sockaddr_storage_clear(it->second.serveraddr) ; std::cerr << "(SS) Peer " << it->first << " has a banned server address. Wiping it out." << std::endl; diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index caa2ac6bb..898080262 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -1321,14 +1321,14 @@ int pqissl::Authorise_SSL_Connection() if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL) checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST; - if(!rsBanList->isAddressAccepted(remote_addr,checking_flags,&check_result)) + if(rsBanList!=NULL && !rsBanList->isAddressAccepted(remote_addr,checking_flags,&check_result)) { - std::cerr << "(SS) refusing connection attempt from IP address " << sockaddr_storage_iptostring(remote_addr) << ". Reason: " << + std::cerr << "(SS) refusing connection attempt from IP address " << sockaddr_storage_iptostring(remote_addr) << ". Reason: " << ((check_result == RSBANLIST_CHECK_RESULT_NOT_WHITELISTED)?"not whitelisted (peer requires whitelist)":"blacklisted") << std::endl; RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_IP_BLACKLISTED, PeerId().toStdString(), sockaddr_storage_iptostring(remote_addr), "", "", check_result); - reset_locked(); - return 0 ; + reset_locked(); + return 0 ; } // check it's the right one. if (certCorrect) @@ -1371,12 +1371,12 @@ int pqissl::accept_locked(SSL *ssl, int fd, const struct sockaddr_storage &forei if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL) checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST; - if(!rsBanList->isAddressAccepted(foreign_addr,checking_flags,&check_result)) + if(rsBanList!=NULL && !rsBanList->isAddressAccepted(foreign_addr,checking_flags,&check_result)) { std::cerr << "(SS) refusing incoming SSL connection from blacklisted foreign address " << sockaddr_storage_iptostring(foreign_addr) << ". Reason: " << check_result << "." << std::endl; RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_IP_BLACKLISTED, PeerId().toStdString(), sockaddr_storage_iptostring(foreign_addr), "", "", check_result); - reset_locked(); + reset_locked(); return -1; } if (waiting != WAITING_NOT) diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 797d53067..b93082080 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1518,9 +1518,14 @@ int RsServer::StartupRetroShare() #endif // new services to test. +#ifndef RETROTOR p3BanList *mBanList = new p3BanList(serviceCtrl, mNetMgr); rsBanList = mBanList ; pqih -> addService(mBanList, true); +#else + rsBanList = NULL ; +#endif + #ifdef RS_USE_BITDHT mBitDht->setupPeerSharer(mBanList); #endif @@ -1589,7 +1594,9 @@ int RsServer::StartupRetroShare() mConfigMgr->addConfiguration("p3History.cfg", mHistoryMgr); mConfigMgr->addConfiguration("p3Status.cfg", mStatusSrv); mConfigMgr->addConfiguration("turtle.cfg", tr); +#ifndef RETROTOR mConfigMgr->addConfiguration("banlist.cfg", mBanList); +#endif mConfigMgr->addConfiguration("servicecontrol.cfg", serviceCtrl); mConfigMgr->addConfiguration("reputations.cfg", mReputations); #ifdef ENABLE_GROUTER diff --git a/retroshare-gui/src/gui/AboutWidget.cpp b/retroshare-gui/src/gui/AboutWidget.cpp index d19e4a7bc..1ade24dc7 100644 --- a/retroshare-gui/src/gui/AboutWidget.cpp +++ b/retroshare-gui/src/gui/AboutWidget.cpp @@ -225,9 +225,10 @@ void AWidget::initImages() //p.drawPixmap(QRect(10, 10, width()-10, 60), image); /* Draw RetroShare version */ - p.drawText(QPointF(10, 50), QString("%1 : %2").arg(tr("Retroshare version"), Rshare::retroshareVersion(true))); #ifdef RS_ONLYHIDDENNODE - p.drawText(QPointF(10, 70), QString("Only Hidden Node")); + p.drawText(QPointF(10, 50), QString("%1 : %2 (With embedded Tor)").arg(tr("Retroshare version"), Rshare::retroshareVersion(true))); +#else + p.drawText(QPointF(10, 50), QString("%1 : %2").arg(tr("Retroshare version"), Rshare::retroshareVersion(true))); #endif /* Draw Qt's version number */ diff --git a/retroshare-gui/src/gui/GenCertDialog.cpp b/retroshare-gui/src/gui/GenCertDialog.cpp index 75bb7d7a3..133bfbc4a 100644 --- a/retroshare-gui/src/gui/GenCertDialog.cpp +++ b/retroshare-gui/src/gui/GenCertDialog.cpp @@ -195,6 +195,10 @@ GenCertDialog::GenCertDialog(bool onlyGenerateIdentity, QWidget *parent) ui.nodeType_CB->setCurrentIndex(1); ui.nodeType_CB->setEnabled(false); #endif +#ifdef RETROTOR + ui.adv_checkbox->setChecked(false); + ui.adv_checkbox->setVisible(true); +#endif initKeyList(); setupState(); @@ -255,10 +259,16 @@ void GenCertDialog::setupState() { bool adv_state = ui.adv_checkbox->isChecked(); +#ifdef RETROTOR + bool retrotor = true ; +#else + bool retrotor = false ; +#endif + if(!adv_state) { ui.reuse_existing_node_CB->setChecked(false) ; - ui.nodeType_CB->setCurrentIndex(0) ; + ui.nodeType_CB->setCurrentIndex(retrotor?1:0) ; ui.keylength_comboBox->setCurrentIndex(0) ; } bool hidden_state = ui.nodeType_CB->currentIndex()==1; @@ -271,8 +281,8 @@ void GenCertDialog::setupState() setWindowTitle(generate_new?tr("Create new profile and new Retroshare node"):tr("Create new Retroshare node")); //ui.headerFrame->setHeaderText(generate_new?tr("Create a new profile and node"):tr("Create a new node")); - ui.label_nodeType->setVisible(adv_state) ; - ui.nodeType_CB->setVisible(adv_state) ; + ui.label_nodeType->setVisible(adv_state && !retrotor) ; + ui.nodeType_CB->setVisible(adv_state && !retrotor) ; ui.reuse_existing_node_CB->setEnabled(adv_state) ; ui.importIdentity_PB->setVisible(adv_state && !generate_new) ; ui.exportIdentity_PB->setVisible(adv_state && !generate_new) ; @@ -308,13 +318,13 @@ void GenCertDialog::setupState() ui.entropy_bar->setVisible(true); ui.genButton->setVisible(true); - ui.hiddenaddr_input->setVisible(hidden_state); - ui.hiddenaddr_label->setVisible(hidden_state); + ui.hiddenaddr_input->setVisible(hidden_state && !retrotor); + ui.hiddenaddr_label->setVisible(hidden_state && !retrotor); - ui.hiddenport_label->setVisible(hidden_state); - ui.hiddenport_spinBox->setVisible(hidden_state); + ui.hiddenport_label->setVisible(hidden_state && !retrotor); + ui.hiddenport_spinBox->setVisible(hidden_state && !retrotor); - ui.cbUseBob->setVisible(hidden_state); + ui.cbUseBob->setVisible(hidden_state && !retrotor); if(!mAllFieldsOk) { diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index fe2939cf6..9076d76af 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -487,6 +487,9 @@ void ServerPage::toggleIpFiltering(bool b) void ServerPage::loadFilteredIps() { + if(rsBanList == NULL) + return ; + if(rsBanList->ipFilteringEnabled()) { whileBlocking(ui.denyAll_CB)->setChecked(true) ; diff --git a/retroshare-gui/src/gui/settings/ServerPage.ui b/retroshare-gui/src/gui/settings/ServerPage.ui index 5b4051914..5394ce5be 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.ui +++ b/retroshare-gui/src/gui/settings/ServerPage.ui @@ -26,7 +26,7 @@ - 2 + 0 diff --git a/retroshare.pri b/retroshare.pri index db1834efe..e2397e62b 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -3,7 +3,10 @@ CONFIG *= retroshare_gui no_retroshare_gui:CONFIG -= retroshare_gui -# To build the RetroTor executable, just uncomment the following option +# To build the RetroTor executable, just uncomment the following option. +# RetroTor is a version of RS that automatically configures Tor for its own usage +# using only hidden nodes. It will not start if Tor is not working. + # CONFIG *= retrotor # To disable RetroShare-nogui append the following @@ -231,6 +234,10 @@ rs_autologin { warning("You have enabled RetroShare auto-login, this is discouraged. The usage of auto-login on some linux distributions may allow someone having access to your session to steal the SSL keys of your node location and therefore compromise your security") } +retrotor { + DEFINES *= RS_ONLYHIDDENNODE +} + rs_onlyhiddennode { DEFINES *= RS_ONLYHIDDENNODE warning("QMAKE: You have enabled only hidden node.") From 6528da3c27e7011c9960784ce072481fe1bfc6d0 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 1 Jan 2018 17:15:34 +0100 Subject: [PATCH 19/42] fixed retrotor.yml appImage script --- build_scripts/AppImage/retrotor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_scripts/AppImage/retrotor.yml b/build_scripts/AppImage/retrotor.yml index dbcabf36d..d996288d0 100644 --- a/build_scripts/AppImage/retrotor.yml +++ b/build_scripts/AppImage/retrotor.yml @@ -7,11 +7,11 @@ ingredients: - deb http://archive.ubuntu.com/ubuntu trusty main restricted universe multiverse - deb http://archive.ubuntu.com/ubuntu trusty-updates main restricted universe multiverse ppas: - - retroshare/retrotor + - retroshare/testing packages: - libqt4-svg - tor - - retroshare + - retrotor script: - rm -rf usr/share/glib-2.0/schemas/ From 5eca17d3cbb94ea659610a172fe8864a5e3d5e29 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 1 Jan 2018 18:40:47 +0100 Subject: [PATCH 20/42] fixed ubuntu packaging scripts --- build_scripts/Debian+Ubuntu/control.trusty_retrotor | 4 ++-- build_scripts/Debian+Ubuntu/debian/retrotor.install | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 build_scripts/Debian+Ubuntu/debian/retrotor.install diff --git a/build_scripts/Debian+Ubuntu/control.trusty_retrotor b/build_scripts/Debian+Ubuntu/control.trusty_retrotor index 4c41786e2..542b9b0e1 100644 --- a/build_scripts/Debian+Ubuntu/control.trusty_retrotor +++ b/build_scripts/Debian+Ubuntu/control.trusty_retrotor @@ -4,12 +4,12 @@ Priority: standard Maintainer: Cyril Soler Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.6, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev, qtmultimedia5-dev, qttools5-dev, libqt5x11extras5-dev, qt5-default Standards-Version: 3.9.6 -Homepage: http://retroshare.sourceforge.net +Homepage: http://retroshare.net Package: retrotor Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring, tor -Conflicts: retroshare-nogui,retroshare06, retroshare +Conflicts: retroshare-nogui,retroshare06,retroshare Description: Secure communication with friends RetroShare is a Open Source cross-platform, private and secure decentralised commmunication platform. It lets you to securely chat and share files with your diff --git a/build_scripts/Debian+Ubuntu/debian/retrotor.install b/build_scripts/Debian+Ubuntu/debian/retrotor.install new file mode 100644 index 000000000..2a81067cd --- /dev/null +++ b/build_scripts/Debian+Ubuntu/debian/retrotor.install @@ -0,0 +1,5 @@ +debian/tmp/usr/bin/retroshare +debian/tmp/usr/share/applications/retroshare.desktop +debian/tmp/usr/share/icons/hicolor/* +debian/tmp/usr/share/pixmaps/retroshare.xpm +debian/tmp/usr/share/retroshare/* From fd25521b8a71a819692e06c99d7a03ad116eb9b5 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 1 Jan 2018 22:57:31 +0100 Subject: [PATCH 21/42] added control file for xenial --- build_scripts/AppImage/retrotor.yml | 2 +- .../Debian+Ubuntu/control.trusty_retrotor | 2 +- .../Debian+Ubuntu/control.xenial_retrotor | 20 +++++++++++++++++++ .../Debian+Ubuntu/makeSourcePackage.sh | 6 +++++- 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 build_scripts/Debian+Ubuntu/control.xenial_retrotor diff --git a/build_scripts/AppImage/retrotor.yml b/build_scripts/AppImage/retrotor.yml index d996288d0..feb77967a 100644 --- a/build_scripts/AppImage/retrotor.yml +++ b/build_scripts/AppImage/retrotor.yml @@ -10,7 +10,7 @@ ingredients: - retroshare/testing packages: - libqt4-svg - - tor + - tor - retrotor script: diff --git a/build_scripts/Debian+Ubuntu/control.trusty_retrotor b/build_scripts/Debian+Ubuntu/control.trusty_retrotor index 542b9b0e1..5de94658f 100644 --- a/build_scripts/Debian+Ubuntu/control.trusty_retrotor +++ b/build_scripts/Debian+Ubuntu/control.trusty_retrotor @@ -8,7 +8,7 @@ Homepage: http://retroshare.net Package: retrotor Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring, tor +Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring, tor (>= 0.2.6) Conflicts: retroshare-nogui,retroshare06,retroshare Description: Secure communication with friends RetroShare is a Open Source cross-platform, private and secure decentralised diff --git a/build_scripts/Debian+Ubuntu/control.xenial_retrotor b/build_scripts/Debian+Ubuntu/control.xenial_retrotor new file mode 100644 index 000000000..4db7a123c --- /dev/null +++ b/build_scripts/Debian+Ubuntu/control.xenial_retrotor @@ -0,0 +1,20 @@ +Source: retroshare +Section: devel +Priority: standard +Maintainer: Cyril Soler +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.6, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev, qtmultimedia5-dev, qttools5-dev, libqt5x11extras5-dev, qt5-default +Standards-Version: 3.9.6 +Homepage: http://retroshare.sourceforge.net + +Package: retrotor +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring, tor (>= 0.2.6) +Conflicts: retroshare-nogui,retroshare06,retroshare +Description: Secure communication with friends + RetroShare is a Open Source cross-platform, private and secure decentralised + commmunication platform. It lets you to securely chat and share files with your + friends and family, using a web-of-trust to authenticate peers and OpenSSL to + encrypt all communication. RetroShare provides filesharing, chat, messages, + forums and channels. + + diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index 4f2d8b10f..e61fd378d 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -59,6 +59,10 @@ while [ ${#} -gt 0 ]; do done if test "${useretrotor}" = "true"; then + if ! test "${dist}" = "xenial"; then + echo ERROR: retro-tor can only be packaged for xenial for now. + exit 1; + fi gitpath="https://github.com/csoler/RetroShare.git" branch="v0.6-TorOnly" fi @@ -136,7 +140,7 @@ for i in ${dist}; do if test ${useretrotor} = "true"; then cp ../rules.retrotor debian/rules - cp ../control.trusty_retrotor debian/control + cp ../control.xenial_retrotor debian/control elif test -f ../control."${i}" ; then echo \/\!\\ Using specific control file for distribution "${i}" cp ../control."${i}" debian/control From eef82aa5f097a84869492b2ec367ad141dd0238f Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 2 Jan 2018 11:06:51 +0100 Subject: [PATCH 22/42] finally fixed appImage scripts --- build_scripts/AppImage/retrotor.yml | 3 ++- build_scripts/Debian+Ubuntu/makeSourcePackage.sh | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build_scripts/AppImage/retrotor.yml b/build_scripts/AppImage/retrotor.yml index feb77967a..e7eba009a 100644 --- a/build_scripts/AppImage/retrotor.yml +++ b/build_scripts/AppImage/retrotor.yml @@ -6,10 +6,11 @@ ingredients: sources: - deb http://archive.ubuntu.com/ubuntu trusty main restricted universe multiverse - deb http://archive.ubuntu.com/ubuntu trusty-updates main restricted universe multiverse + - deb http://deb.torproject.org/torproject.org/ trusty main ppas: - retroshare/testing packages: - - libqt4-svg + - libqt5svg5 - tor - retrotor diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index e61fd378d..8d4033e13 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -59,8 +59,8 @@ while [ ${#} -gt 0 ]; do done if test "${useretrotor}" = "true"; then - if ! test "${dist}" = "xenial"; then - echo ERROR: retro-tor can only be packaged for xenial for now. + if ! test "${dist}" = "trusty"; then + echo ERROR: retro-tor can only be packaged for trusty for now. exit 1; fi gitpath="https://github.com/csoler/RetroShare.git" @@ -140,7 +140,7 @@ for i in ${dist}; do if test ${useretrotor} = "true"; then cp ../rules.retrotor debian/rules - cp ../control.xenial_retrotor debian/control + cp ../control.trusty_retrotor debian/control elif test -f ../control."${i}" ; then echo \/\!\\ Using specific control file for distribution "${i}" cp ../control."${i}" debian/control From a69e068db3897f5eb31c85c075ce34b210628ade Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 15 Jan 2018 21:41:19 +0100 Subject: [PATCH 23/42] fixed connectProgressDialog for hidden nodes --- .../src/gui/connect/ConnectProgressDialog.cpp | 33 ++++++++++++++++--- .../src/gui/connect/ConnectProgressDialog.h | 3 ++ .../src/gui/connect/ConnectProgressDialog.ui | 26 ++++++++++----- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp b/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp index 1f860acde..c243006d4 100755 --- a/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp +++ b/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp @@ -64,6 +64,9 @@ ConnectProgressDialog::ConnectProgressDialog(const RsPeerId& id, QWidget *parent ui->headerFrame->setHeaderText(tr("Connection Assistant")); connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(stopAndClose())); + + mAmIHiddenNode = rsPeers->isHiddenNode(rsPeers->getOwnId()) ; + mIsPeerHiddenNode = rsPeers->isHiddenNode(id) ; } ConnectProgressDialog::~ConnectProgressDialog() @@ -165,15 +168,35 @@ void ConnectProgressDialog::initDialog() ui->NetResult->setText(tr("N/A")); ui->ContactResult->setText(tr("N/A")); +#ifdef RS_USE_BITDHT + if(!mIsPeerHiddenNode && !mAmIHiddenNode) + { ui->DhtResult->setText(tr("DHT Startup")); ui->DhtProgressBar->setValue(0); + } +#else + if(mIsPeerHiddenNode || mAmIHiddenNode) + { + ui->DhtResult->hide(); + ui->DhtLabel->hide(); + ui->DhtProgressBar->hide(); + } +#endif + if(mIsPeerHiddenNode || mAmIHiddenNode) + { + ui->UdpResult->hide(); + ui->UdpProgressBar->hide(); + ui->UdpLabel->hide(); + } + else + { + ui->UdpResult->setText(tr("N/A")); + ui->UdpProgressBar->setValue(0); + } ui->LookupResult->setText(tr("N/A")); ui->LookupProgressBar->setValue(0); - ui->UdpResult->setText(tr("N/A")); - ui->UdpProgressBar->setValue(0); - sayInProgress(); if (rsPeers->isFriend(mId)) @@ -219,7 +242,9 @@ void ConnectProgressDialog::updateStatus() updateNetworkStatus(); updateContactStatus(); +#ifdef RS_USE_BITDHT updateDhtStatus(); +#endif updateLookupStatus(); updateUdpStatus(); @@ -443,6 +468,7 @@ void ConnectProgressDialog::updateLookupStatus() break; } +#ifdef RS_USE_BITDHT time_t now = time(NULL); switch(mDhtStatus) { @@ -484,7 +510,6 @@ void ConnectProgressDialog::updateLookupStatus() ui->LookupProgressBar->setValue(calcProgress(now, mLookupTS, CONNECT_LOOKUP_TYPICAL, CONNECT_LOOKUP_SLOW, CONNECT_LOOKUP_PERIOD)); -#ifdef RS_USE_BITDHT /* now actually look at the DHT Details */ RsDhtNetPeer status; rsDht->getNetPeerStatus(mId, status); diff --git a/retroshare-gui/src/gui/connect/ConnectProgressDialog.h b/retroshare-gui/src/gui/connect/ConnectProgressDialog.h index 1dcda6730..8620bd93b 100644 --- a/retroshare-gui/src/gui/connect/ConnectProgressDialog.h +++ b/retroshare-gui/src/gui/connect/ConnectProgressDialog.h @@ -97,6 +97,9 @@ private: time_t mUdpTS; uint32_t mUdpStatus; + bool mAmIHiddenNode ; + bool mIsPeerHiddenNode ; + /** Qt Designer generated object */ Ui::ConnectProgressDialog *ui; }; diff --git a/retroshare-gui/src/gui/connect/ConnectProgressDialog.ui b/retroshare-gui/src/gui/connect/ConnectProgressDialog.ui index c9129d8c5..8666655b6 100644 --- a/retroshare-gui/src/gui/connect/ConnectProgressDialog.ui +++ b/retroshare-gui/src/gui/connect/ConnectProgressDialog.ui @@ -6,8 +6,8 @@ 0 0 - 553 - 489 + 623 + 608 @@ -21,7 +21,16 @@ 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -97,7 +106,7 @@ - + 75 @@ -117,7 +126,7 @@ - + 75 @@ -137,7 +146,7 @@ - + 75 @@ -283,10 +292,10 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">This Widget shows the progress of your connection to your new peer.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">It is helpful for problem-solving.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:13pt;"></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:13pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">If you are an expert RS user, or trust that RS will do the right thing</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">you can close it.</span></p></body></html> @@ -331,7 +340,6 @@ p, li { white-space: pre-wrap; } - From fe0b22e9f12a526207ed526e2189d5184eb6802c Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 15 Jan 2018 21:42:58 +0100 Subject: [PATCH 24/42] remove "attempt to connect" to normal nodes menu entry for hidden nodes --- retroshare-gui/src/gui/common/FriendList.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index c251a9575..726bf61ea 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -342,7 +342,8 @@ void FriendList::peerTreeWidgetCustomPopupMenu() // QMenu *lobbyMenu = NULL; - switch (type) { + switch (type) + { case TYPE_GROUP: { bool standard = c->data(COLUMN_DATA, ROLE_STANDARD).toBool(); @@ -448,11 +449,11 @@ void FriendList::peerTreeWidgetCustomPopupMenu() contextMenu->addAction(QIcon(IMAGE_EXPORTFRIEND), tr("Recommend this node to..."), this, SLOT(recommendfriend())); } - contextMenu->addAction(QIcon(IMAGE_CONNECT), tr("Attempt to connect"), this, SLOT(connectfriend())); + if(!rsPeers->isHiddenNode(rsPeers->getOwnId()) || rsPeers->isHiddenNode( RsPeerId(getRsId(c)) )) + contextMenu->addAction(QIcon(IMAGE_CONNECT), tr("Attempt to connect"), this, SLOT(connectfriend())); contextMenu->addAction(QIcon(IMAGE_COPYLINK), tr("Copy certificate link"), this, SLOT(copyFullCertificate())); - //this is a SSL key contextMenu->addAction(QIcon(IMAGE_REMOVEFRIEND), tr("Remove Friend Node"), this, SLOT(removefriend())); From c8a638c1d6d4f253a0b342d4bc662962efbe3ccf Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 15 Jan 2018 22:00:08 +0100 Subject: [PATCH 25/42] removed useless IP whitelist options for hidden nodes --- .../src/gui/connect/ConnectFriendWizard.cpp | 25 ++++++++++++++----- .../src/gui/connect/ConnectFriendWizard.ui | 4 +-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp index 0eb83b5fc..8c50c719d 100755 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp @@ -435,15 +435,29 @@ void ConnectFriendWizard::initializePage(int id) break; case Page_Conclusion: { + bool peerIsHiddenNode = peerDetails.isHiddenNode ; + bool amIHiddenNode = rsPeers->isHiddenNode(rsPeers->getOwnId()) ; + std::cerr << "Conclusion page id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl; ui->_direct_transfer_CB_2 ->setChecked(false) ; //peerDetails.service_perm_flags & RS_NODE_PERM_DIRECT_DL) ; ui->_allow_push_CB_2 ->setChecked(peerDetails.service_perm_flags & RS_NODE_PERM_ALLOW_PUSH) ; - ui->_require_WL_CB_2 ->setChecked(peerDetails.service_perm_flags & RS_NODE_PERM_REQUIRE_WL) ; + + if(!peerIsHiddenNode && !amIHiddenNode) + ui->_require_WL_CB_2 ->setChecked(peerDetails.service_perm_flags & RS_NODE_PERM_REQUIRE_WL) ; + else + { + ui->_require_WL_CB_2 ->setChecked(false) ; + ui->_require_WL_CB_2 ->hide() ; + + ui->_addIPToWhiteList_CB_2->hide(); + ui->_addIPToWhiteList_ComboBox_2->hide(); + } sockaddr_storage addr ; - std::cerr << "Cert IP = " << peerDetails.extAddr << std::endl; + std::cerr << "Cert IP = " << peerDetails.extAddr << std::endl; + if(sockaddr_storage_ipv4_aton(addr,peerDetails.extAddr.c_str()) && sockaddr_storage_isValidNet(addr)) { QString ipstring0 = QString::fromStdString(sockaddr_storage_iptostring(addr)); @@ -577,29 +591,28 @@ void ConnectFriendWizard::initializePage(int id) ui->fr_avatar->setFrameType(AvatarWidget::NORMAL_FRAME); setPixmap(QWizard::LogoPixmap, QPixmap(":/images/user/user_request48.png")); + ui->fr_signGPGCheckBox->setChecked(false); + //set the radio button to sign the GPG key if (peerDetails.accept_connection && !peerDetails.ownsign) { //gpg key connection is already accepted, don't propose to accept it again - ui->fr_signGPGCheckBox->setChecked(false); ui->fr_acceptNoSignGPGCheckBox->hide(); + ui->fr_signGPGCheckBox->show(); ui->fr_acceptNoSignGPGCheckBox->setChecked(false); } if (!peerDetails.accept_connection && peerDetails.ownsign) { //gpg key is already signed, don't propose to sign it again ui->fr_acceptNoSignGPGCheckBox->setChecked(true); ui->fr_signGPGCheckBox->hide(); - ui->fr_signGPGCheckBox->setChecked(false); } if (!peerDetails.accept_connection && !peerDetails.ownsign) { ui->fr_acceptNoSignGPGCheckBox->setChecked(true); ui->fr_signGPGCheckBox->show(); - ui->fr_signGPGCheckBox->setChecked(false); ui->fr_acceptNoSignGPGCheckBox->show(); } if (peerDetails.accept_connection && peerDetails.ownsign) { ui->fr_acceptNoSignGPGCheckBox->setChecked(false); ui->fr_acceptNoSignGPGCheckBox->hide(); - ui->fr_signGPGCheckBox->setChecked(false); ui->fr_signGPGCheckBox->hide(); } diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui b/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui index 3df4cf673..a11bb18e7 100644 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui @@ -6,8 +6,8 @@ 0 0 - 760 - 538 + 1161 + 1223 From 7b6394b3f96f3b5fa7bb1496ca810e17bde90682 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 15 Jan 2018 22:01:20 +0100 Subject: [PATCH 26/42] removed old makefile --- supportlibs/pegmarkdown/Makefile.orig | 42 --------------------------- 1 file changed, 42 deletions(-) delete mode 100644 supportlibs/pegmarkdown/Makefile.orig diff --git a/supportlibs/pegmarkdown/Makefile.orig b/supportlibs/pegmarkdown/Makefile.orig deleted file mode 100644 index 1e8c7a003..000000000 --- a/supportlibs/pegmarkdown/Makefile.orig +++ /dev/null @@ -1,42 +0,0 @@ -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') -ifneq (,$(findstring MINGW,$(uname_S))) - X = .exe -endif - -export X - -PROGRAM=markdown$(X) -CFLAGS ?= -Wall -O3 -ansi -D_GNU_SOURCE # -flto for newer GCC versions -OBJS=markdown_parser.o markdown_output.o markdown_lib.o utility_functions.o parsing_functions.o odf.o -PEGDIR=peg-0.1.9 -LEG=$(PEGDIR)/leg$(X) -PKG_CONFIG = pkg-config - -ALL : $(PROGRAM) - -$(LEG): $(PEGDIR) - CC=gcc make -C $(PEGDIR) - -%.o : %.c markdown_peg.h - $(CC) -c `$(PKG_CONFIG) --cflags glib-2.0` $(CFLAGS) -o $@ $< - -$(PROGRAM) : markdown.c $(OBJS) - $(CC) `$(PKG_CONFIG) --cflags glib-2.0` $(CFLAGS) -o $@ $< $(OBJS) `$(PKG_CONFIG) --libs glib-2.0` - -markdown_parser.c : markdown_parser.leg $(LEG) markdown_peg.h parsing_functions.c utility_functions.c - $(LEG) -o $@ $< - -.PHONY: clean test - -clean: - rm -f markdown_parser.c $(PROGRAM) $(OBJS) - -distclean: clean - make -C $(PEGDIR) clean -\ -test: $(PROGRAM) - cd MarkdownTest_1.0.3; \ - ./MarkdownTest.pl --script=../$(PROGRAM) --tidy - -leak-check: $(PROGRAM) - valgrind --leak-check=full ./markdown README From b6a2d757478398cc24d8f850590886bbcfb56d0f Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 18 Jan 2018 22:13:24 +0100 Subject: [PATCH 27/42] moved StringUtil into StrUtil to avoid conflicts with another file with lower case name in gui/util --- retroshare-gui/src/TorControl/AddOnionCommand.cpp | 2 +- retroshare-gui/src/TorControl/GetConfCommand.cpp | 2 +- retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp | 2 +- retroshare-gui/src/TorControl/SetConfCommand.cpp | 2 +- retroshare-gui/src/TorControl/{StringUtil.cpp => StrUtil.cpp} | 2 +- retroshare-gui/src/TorControl/{StringUtil.h => StrUtil.h} | 0 retroshare-gui/src/TorControl/TorControl.cpp | 2 +- retroshare-gui/src/retroshare-gui.pro | 4 ++-- 8 files changed, 8 insertions(+), 8 deletions(-) rename retroshare-gui/src/TorControl/{StringUtil.cpp => StrUtil.cpp} (99%) rename retroshare-gui/src/TorControl/{StringUtil.h => StrUtil.h} (100%) diff --git a/retroshare-gui/src/TorControl/AddOnionCommand.cpp b/retroshare-gui/src/TorControl/AddOnionCommand.cpp index 88ae232fd..f454b690b 100644 --- a/retroshare-gui/src/TorControl/AddOnionCommand.cpp +++ b/retroshare-gui/src/TorControl/AddOnionCommand.cpp @@ -33,7 +33,7 @@ #include "AddOnionCommand.h" #include "HiddenService.h" #include "CryptoKey.h" -#include "StringUtil.h" +#include "StrUtil.h" using namespace Tor; diff --git a/retroshare-gui/src/TorControl/GetConfCommand.cpp b/retroshare-gui/src/TorControl/GetConfCommand.cpp index f7574f7fd..933def562 100644 --- a/retroshare-gui/src/TorControl/GetConfCommand.cpp +++ b/retroshare-gui/src/TorControl/GetConfCommand.cpp @@ -31,7 +31,7 @@ */ #include "GetConfCommand.h" -#include "StringUtil.h" +#include "StrUtil.h" #include using namespace Tor; diff --git a/retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp b/retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp index ad8c9e3e6..a365a5c4d 100644 --- a/retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp +++ b/retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp @@ -32,7 +32,7 @@ #include "ProtocolInfoCommand.h" #include "TorControl.h" -#include "StringUtil.h" +#include "StrUtil.h" #include using namespace Tor; diff --git a/retroshare-gui/src/TorControl/SetConfCommand.cpp b/retroshare-gui/src/TorControl/SetConfCommand.cpp index fa4fd5b27..f13a9fdef 100644 --- a/retroshare-gui/src/TorControl/SetConfCommand.cpp +++ b/retroshare-gui/src/TorControl/SetConfCommand.cpp @@ -31,7 +31,7 @@ */ #include "SetConfCommand.h" -#include "StringUtil.h" +#include "StrUtil.h" using namespace Tor; diff --git a/retroshare-gui/src/TorControl/StringUtil.cpp b/retroshare-gui/src/TorControl/StrUtil.cpp similarity index 99% rename from retroshare-gui/src/TorControl/StringUtil.cpp rename to retroshare-gui/src/TorControl/StrUtil.cpp index 8215d1351..81de151b0 100644 --- a/retroshare-gui/src/TorControl/StringUtil.cpp +++ b/retroshare-gui/src/TorControl/StrUtil.cpp @@ -30,7 +30,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "StringUtil.h" +#include "StrUtil.h" QByteArray quotedString(const QByteArray &string) { diff --git a/retroshare-gui/src/TorControl/StringUtil.h b/retroshare-gui/src/TorControl/StrUtil.h similarity index 100% rename from retroshare-gui/src/TorControl/StringUtil.h rename to retroshare-gui/src/TorControl/StrUtil.h diff --git a/retroshare-gui/src/TorControl/TorControl.cpp b/retroshare-gui/src/TorControl/TorControl.cpp index d8ab0149c..7f2f7b744 100644 --- a/retroshare-gui/src/TorControl/TorControl.cpp +++ b/retroshare-gui/src/TorControl/TorControl.cpp @@ -38,7 +38,7 @@ #include "SetConfCommand.h" #include "GetConfCommand.h" #include "AddOnionCommand.h" -#include "StringUtil.h" +#include "StrUtil.h" #include "Settings.h" #include "PendingOperation.h" #include diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 6e12665dc..a6ed430d2 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -352,7 +352,7 @@ HEADERS += TorControl/AddOnionCommand.h \ TorControl/PendingOperation.h \ TorControl/SecureRNG.h \ TorControl/Settings.h \ - TorControl/StringUtil.h \ + TorControl/StrUtil.h \ TorControl/TorProcess_p.h SOURCES += TorControl/AddOnionCommand.cpp \ @@ -371,7 +371,7 @@ SOURCES += TorControl/AddOnionCommand.cpp \ TorControl/PendingOperation.cpp \ TorControl/SecureRNG.cpp \ TorControl/Settings.cpp \ - TorControl/StringUtil.cpp + TorControl/StrUtil.cpp } # Input From 9a54205addf43ea9488a46fae0475cc33c331b11 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 18 Jan 2018 22:40:28 +0100 Subject: [PATCH 28/42] added time.h include for windows compilation --- retroshare-gui/src/TorControl/TorControl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/retroshare-gui/src/TorControl/TorControl.cpp b/retroshare-gui/src/TorControl/TorControl.cpp index 7f2f7b744..29979e2b3 100644 --- a/retroshare-gui/src/TorControl/TorControl.cpp +++ b/retroshare-gui/src/TorControl/TorControl.cpp @@ -30,6 +30,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include + #include "TorControl.h" #include "TorControlSocket.h" #include "HiddenService.h" From 85341473137130b41ac9b24cba289a3a5b40f463 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 19 Jan 2018 13:42:16 +0100 Subject: [PATCH 29/42] added Tor status icon in the status bar --- retroshare-gui/src/gui/MainWindow.cpp | 16 +++ retroshare-gui/src/gui/MainWindow.h | 2 + retroshare-gui/src/gui/icons.qrc | 1 + retroshare-gui/src/gui/icons/no-tor.png | Bin 0 -> 8178 bytes .../src/gui/statusbar/torstatus.cpp | 115 ++++++++++++++++++ retroshare-gui/src/gui/statusbar/torstatus.h | 41 +++++++ retroshare-gui/src/retroshare-gui.pro | 2 + 7 files changed, 177 insertions(+) create mode 100644 retroshare-gui/src/gui/icons/no-tor.png create mode 100644 retroshare-gui/src/gui/statusbar/torstatus.cpp create mode 100644 retroshare-gui/src/gui/statusbar/torstatus.h diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index 35399146a..61eb6548f 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -83,6 +83,7 @@ #include "statusbar/SoundStatus.h" #include "statusbar/ToasterDisable.h" #include "statusbar/SysTrayStatus.h" +#include "statusbar/torstatus.h" #include #include @@ -244,6 +245,17 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) peerstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowPeer", QVariant(true)).toBool()); statusBar()->addWidget(peerstatus); + if(hiddenmode) + { + torstatus = new TorStatus(); + torstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowTor", QVariant(true)).toBool()); + statusBar()->addWidget(torstatus); + torstatus->getTorStatus(); + } + else + torstatus = NULL ; + +#ifndef RETROTOR natstatus = new NATStatus(); if(hiddenmode) natstatus->setVisible(false); else natstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowNAT", QVariant(true)).toBool()); @@ -255,6 +267,7 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) else dhtstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowDHT", QVariant(true)).toBool()); statusBar()->addWidget(dhtstatus); dhtstatus->getDHTStatus(); +#endif hashingstatus = new HashingStatus(); hashingstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowHashing", QVariant(true)).toBool()); @@ -710,6 +723,9 @@ void MainWindow::updateStatus() if (ratesstatus) ratesstatus->getRatesStatus(downKb, upKb); + if(torstatus) + torstatus->getTorStatus(); + if(!hiddenmode) { if (natstatus) diff --git a/retroshare-gui/src/gui/MainWindow.h b/retroshare-gui/src/gui/MainWindow.h index a52bf0073..0705cac6e 100644 --- a/retroshare-gui/src/gui/MainWindow.h +++ b/retroshare-gui/src/gui/MainWindow.h @@ -46,6 +46,7 @@ class OpModeStatus; class SoundStatus; class ToasterDisable; class SysTrayStatus; +class TorStatus ; //class ForumsDialog; class GxsChannelDialog ; class GxsForumsDialog ; @@ -293,6 +294,7 @@ private: SoundStatus *soundStatus; ToasterDisable *toasterDisable; SysTrayStatus *sysTrayStatus; + TorStatus *torstatus; /* Status */ std::set m_apStatusObjects; // added objects for status diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index 8fbbf5465..aab1afb40 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -228,6 +228,7 @@ icons/tor-logo.png icons/tor-off.png icons/tor-on.png + icons/no-tor.png icons/tor-starting.png icons/tor-stopping.png icons/user-away_64.png diff --git a/retroshare-gui/src/gui/icons/no-tor.png b/retroshare-gui/src/gui/icons/no-tor.png new file mode 100644 index 0000000000000000000000000000000000000000..ed0c29538b99b92d1723ba41cc0ceee6b4303e32 GIT binary patch literal 8178 zcmWkz1ymGW6rNp{TDlQXQd$842?Z9UyFsKuxa@PKx)_?w^i;r{;3%uUNy z=GN_)*Ej)^h?qHHGv5XfQV)GCJWCs=BHJ_AiiDEMqF{7{o5Nj}=)C}Ngy!Yx?^Z2# z3#oDhpn%iVb0*^cm51PFRc0N4E&)I>5O3i?;?;qH=b8hgzyKvstx;zV2a*B6&dXPV z0Vu@-_WsFG$*2Y=SU+&ri2}ozGP{eiB@7!TK7d7HLN6Ra zWEwlmFos2u9t&eIk>yK77SioRkg75C4!9ITOC)R(3}hKkp1F_;#polh;}-_#UPRtT zw#e`#2iB^g{f2%(G<~I|itNjEop9qLFhHi}+fGo`KM_HG&o7=(*#6)K_(jH=At!k7 zEu!a4^rOS2j6dp9G53?3ZRqlA$MKsz))jCkqwdHyImBXuMj=V|una>8yX=DE<7IRe zb>Dn_y2n^g+>E7z9UQ{b#ln#ERi*x^H}O@Er>SsFysmUP^8x)6`s}BMEchfwNwQ4% zgNf_PaQdh5FXV9KY-JZ@pA~8picS(*XDTx9#@i46S;wkHmeZvrG{h6ct0dkGcCR;( z3in2=Dq`m|sTU>_%k#e%+kh42ypTxGEma#W$^MO18X=scCug7QuF9nmUP8k6;q%kc z4DvU_h0hA6etx#Lw7#(7+Hq^fUJ8C9mG(1j(smnjXKN?;p9d~p7+!F{tSRdw+ebc+ ziYXf&aiuGMLI0JOKA_1x^MX3v@)N-)M=f3Ub9P^{gdyS-;S}u@|CFs#O)Xa~u_>=o z9L+KnB-bQg4OhF2RFDxDi9 zTcByy(Dx{Yp1kkH`(s^+X%}s@T~6CiN~Z5>ul5w((Ql~TxqK8g-nf=plv^ZNWNkW+ zLh$=)P)9;@net=wV|Zge&(NNUJ*%0vsj#T%N<@U$YO^a@8OgUs)OdqZ@R+0g`Rh))?puGVNsFy*JC?qqJ5&!9Pga)wl8fA%OY)z{?q>H{+PGfH?OXT@8T}o zSG-QhkCoAlA)Sy7NNXTfU>%w*8Z9gxR)ooq9)tb^g9}%bOad1h?=7uMl4A$O3H6m3 z@1iB==LxbQtSmA;>TB*1X2mDdM6qGxSj&X|j$f`6cSgQrMWAHtA{uF}AEi@V`H`}* zzbJkFSFK*d&DrgObGm%}?Tuw?>~UO4bknN^o9`~}mgP2f>UL&(8I8!s(#Al~@Jp%V zG-5XrChYx>>pinQA|KaWp<8yJc{A5PYo@xHRcJf zt=L8|orEeErOHOJgVJM?laP#16{)uTn0&RGhDQ0W^!hMI-YfEJ;w}p18akd1qVkG-n!SO{Sb9h z_|U~Vrl2TV?fr^DbN5|Gi?w2_pAxjjvX1 ztgf4F^n81aVrZB8LCzSZLE-V7$3VT=+|&AK(r?&mxHk1pbyZhg>%_)u@g!C~c(SPI z4M&g;UrI^x;IKpGKfNY1GLsZ@twWo%sdw4|>=Y?R<}7x!espLQjo*ZS z|J}&<@`aPUmj&nESpf#a+IJOY4Q+GG^V9819zLh|!H>ya{W(nDYx&0EsbkwJ<#*;V zc@VS|M`cRg+`j3*)F|Vj(wiOUQ{;nrE_JwTNMi*2v|GUkb_u+v5c(s4dx z|Fg$8Cp~ujF7b^{mgO(LK5MGmd1Kv+-J{Ft0S#wZyRu#!lfvyE%AXb3=ZfUD9&Se$ zWIZ-~EYsHT;D5-oX7-_VMqym{cJ>J8Dr&sF(yQdu<*=-zO1Ph~pSESpOXT>= zZN=Dv-(lln^KySHZ93~M;$HQ1;@Ygg_@~N+=$7yOE!RcJ>CMy099~dgVwft(NCFT4 zzj9lPlfV&dC)u~I0DwdC{{aC$XHtTLm~L`PQkbg{5;zfInZ1WR0FW`uNs4QF&hHy2 zC{kN4h>)yJzx@5g9QFqNL@=epI^qRUsbX^tN4^9F-n|ad97;ZB0RLW#>n+nVvw>D< zWl#udopr{PrS4O8)lql>xd}|`adB^ObQfiBm%bAGYRiawEq4EyjM|Pjj+8CBU*C7k zC;RmE;d`v?t-PMA7^)3MR;AmktsHjX;bJA6_DgiNTW~C0MD%hUY4BMPRLgpGvPi*^ z%b>aE;r{0E!Ye!cpAj=sDaF1%?d4##IU9ZtT>KCuysIsnG+1sbInIG=$>64CRDIByyFWnQE;E*8!ePGr+ zcXMkCPew-ON$UGYiHel7%0PKEd$PzS9I`&l8=ecWp)jEk=_2*KygYGVYh7R_&Ej`) zVYmxU5y>avYkI*O&)d^+F~&dy@?)=QyllGyFw;<1_oj|Bs-S>T=x85|wrt}XlLLNq z$lA^oz54a{-T2s;=>2Y0duEL;ZcI$f&mA`g@%)>cn@UyIkfkMqPm0XHfBzl`tf~*< z=()sWiMzkLy6W#V{`n}XH&?yn=i(wRu(z^8FBnVxXLc3=0|is91jaem z;J7SNq%O|qZfk3M>_bIOef)Qd!_NMxwli~*9AAiOv?kSMBqor#x;?YwCMYcIQq7sc zJ;azG+cjgYn8UG9UzrFU;tc~UaMh^1s_G4&hbdDqm)Z5n=Q#~5Rne2>i_KALb(pWE zCFW!c7X=uRy}kXU!ht--LkkCzkt&8c`d+^y?NeKA1~?(!XtwAi=b4_KUg4K2I~EU8 z==%0Os`j&vMk6UZwnQAL^f=ITrReK&+;6c z^F-05iN*3-^b&Qt*L^8gN-Ts@H=D(C27rtk)xxdo`Qo1V5fJUGAr%FD}* zeSK*FQmCe9n7dLrn@0ttI%Tmw(V&Pe5vvAR0dEFyz(XKP*&44bo^RTfgU@40@e}wO0_PhSL@1ZZxnza zhM9mvo#KQ&fLvnz$o*Y84y?Mo;UAIO@874hOiI!vkS_6l5Z|qi4utPB#Pf-t zKY()1wdPolMUkT;ZajxpM2`$u-F(lF`=gUnX6G1f+7HpK4MhGe|G>O0;kn5 z=Qukxm0VFpW$Vn3%djN^JaK~Jwt@H>onnaQwx24dZ^KP^(3JAE_1CGt+9>pyYjm`Kk&wkOAaP#=l+^!DYr&d$zqMlqoo+i!X;p2rfY zKt@Iei#(b-v73iS60o>oip!PUx&08B&)P57VfmK4prC+Gju;IM?X66!e*L#^^pv=( zM@Oouuq(b$7w#~(CQVF=G0I!f7-?SL-RX)Tyqx~Ez~K!E6%_*INqRdgE98V#^5dP} zBgi0AwO$1-agK;@8x~#l@`jTjoc+wShH}wCpv9020~0gB9?j~x^VP|F7&I`s_NNse z110X}66ugMv~F&X4r?|1v=n$AW-{QLW*3E0QB*{(3F6}6kuhEE40TOUYlE{$3#|C4 zYFb+K>&4nCEAhdKeq(RHfAqGJzr{(qpk1Y4Lh$5m9m}(0W@cuD8Y$f1DrpoaL?Vxr z%b1TUN*z!3|BC4D?gmi89AZw|aPG-pzmfzz)sGbT8CgpawG`Y`F;cuiliPp)M(SW} z1pzSe#bWEvV*-{@D31>xRtj5#?7(i&U=Iol!?3fnBb~yGINnGz%CD)J@Fy=pb+H9I z0^FG@G0)N4i;FR@+5`;j936}OMvb`AO8M9;kN)`aW4?R8FlQ~|j`VS?*k035nVBIV zdYH8K}Qen47o^VK#y?V7$W;LYH`9hLzevo zDp;XyJ0>9JcTEbY%9gOc{OBu6i-Ca=UpeD+yeeh&ZN9$t&;0yn6q=jx183H zV58^4i;kdLG5`>Jetw?WK`P@&|IE}nhwc}C9*CwrM!$C4KGS%@tljsPlY6<&wAg>DtW0H4=>ncgC`NEzVG5FIz(x)50YO>0 zK#VG8Q|qwbl;^eA$$Aee$`HXM&I~nQP*E*+ss5}EWDUFR@9lBAR1g<(f_E7Gx9r<~}((lrQNuxlYDG%7w(5rvgiwA3ib*9R=k8u0#FV}^D;Ldns zm_id*4LdfSfAx;(hYw_YN?W&`V`F0sH27x5xtDmnb#s{#$Y1eyHp~cZw1HZ?v4!^O znVI9gIo?e3$Mo_3FTsu+Iw1N9-u4uus1jCML6poR7(1K}Bqb$PFYKdpp}jLQ0uzb_ zgVwqNrWY#0*vaM4A_olY^~h{$C=CtGx*LcNLeDwi`XqE?&!5oHAS$$rmv9r6(Um!1 zE>~kIQ1er4P#qgqT}W;LB0lH1R52KQO2q~@Y5M0{KA9L0U(R8RN)l^fDVHQO2M2uS zq!LucDp=#-+t1I>nMFlSbG}*ZS7hG)zJ1L*okT+Uky16JRV8swf|RIHXOzUG68E?7 z--pKb!2QFJb4M4NCr=pCHd9w2A-}Vp<$!BfYs%vFFH&Ajc4TA(ng2Bzn>jLHUHeW} z3n7n`WlH2%BI5|^r1Q+q5fWfSG7UzvfiOf`8z|{^XILfh{BBTOE!nOO)URyTh;rCu z1zjoMl^8$NTm$(0g}3>@_ZsHXH}23-Z14`Dmb^DUZS&1JHwm)*=g;#wUX0LDmh4h` zVEnWU6BE;p`Jo%Q?3U77o7qriU{-o1MVg3(jjJ7V-B%_Jy* zWcfvGSD}rQ$W)g|xBMw9OG-yar!O{7uOdvjSmEts&NBdX0LQ!FyzT96*1>R6{BR;% zjDpwWD%#YLTG5sX(;B*8B3IhPAR$<@d`fIjGpve>b8m`g?>IkqA7lqsqE|JR7~I)m zpp;BpYqa{phxp~D2Q3`_HTTy)%*0$qtl!zn%1V|F(VVCPGtif8Zf(V@o6{e<6;uBJ zim-2uji1yY`1ttd!<~xjvJ@au4>Y;RW*;b}-tF)23nnlm$jafOPPfKuYHC(iy!>nQ zu(?-HuU^PM>*oHHk)hD!@FE?g!M=;3m=pb?<}Y8EEB2!B@<6EFJ3I`g!*ZUmPM)Lzp%LV%OwN0TvdP|8KYE z<)3eZP1l1~HIw1aG&3{PZCW!>+A&q8qgGms9Da65_$mOz&RAN`#~&qoVyLB}KyT&z zk6;aVRTI18^me4PGtkF^*)Q#vMV)vo6UfS7c=1a+929f&!*dcNHwm&#&mU;|$+7@O zM#kBN1=lR?-HUQE00?U}bexYwXa-u2XBQPh!c5`^Wtj!i;90*YIH2G3V!+gRl9_(f zQv=sib4@@%fI_5fB7ph-RUqpaSYJ1nCOf*hV~e3Ln~GFqV`_5IH86O#?Lm4f+V4zA z`}#31hVxoqOuipJ2L}fwEiER1Iez+XD-3{Q-*-D_$}B=Si=i(w@EjUmLH0H`EmTQE z6{TOy^r?S`cYzE{3h$K(FfcHfSP$^U0U z#18Ax`HFW9sEZr=r*eLNBF)Xs@ob??#nE>3AFfxo<0KhCBi}ncO|HqVrM7Ma6Qjg! z_RM~Oz9+P7W>($y7Ghy$HkZqtvf%+W8JNVUmynFnFmS0a87361k!y|RNs2YPoPYir zynXwziqyv1x^s2aR89I}Xh?o8Fkll#D9i2a*RLD^J(RTTl) z(*-@CR&x9B;r-JgP-XZowQmdckpBGr+ii8Cy}n*E6_th#DP*FgrVh?zX>{MG^7i(o zdnyN7IvRY;MF)>Q?`4~B7Fv*rGfZgUv7E?0%WM^YfP=ZGtAA@T26>oMjH#>tho9@Z(W|WzY#_ zqIYCUWi;et(H+C0K~50y{>R$86UF4zr0-lrSXHD!P?HbPWx#vXxd^dxi;B<#5rA+O zK6^?jYEeu`=p!h;Ik~vvuuxq2iUnU5{ps`6++ye=Za~#QVE6J}m&=juOeH7>6%`ff zXz&ZbZHATkzkk`+$LJ4sce`h2Dd!g!NGhu;DtakGBBbNj1fyePHFIS13}C%{ z`BE1ctE)VA#SYrKI=S13&8b++XN}z1-&fM5Y;J1$$fAp8D6HWNI*aJ1;CT!H-1KBuy{ffpabpm z7waEO*$7x%KiI)ICF<3j)M8>C7ImGbH9cf269qEP(1>wdKB}0AUenp-Wf>2T2G0O#yNqA73q*sp82S=*(3=`NJM*+v zb(p`%YioP*JPiljUjW%owQLGx#Ry3Tp+H*va2|gC(48IYz5V?f;0fTQLv=(Z13Z$V zoVMbN?lldZvXKI7!@|;%hnE*EX)xr^pFfvD@nGp)u225`YtxmlTJvWd<}XMSHnZFN z?_a&({1Tv_62DfK2oN)Tf@wKLY!PNCGKX}VT>6UYa*}i7CdI$dO${C17{a0HVvbwzxWB)AUM^9R&%32PF`repLK~bP(!C-GL9W$# zfflkFY*AzGh@zsWpm+uP7wTR^QM_L#zfwU52)n}83Z^N6dIY}gNBU=kKs9u`%?0ze zAWoFQ|7O1-AJEaL7$HYw%Dutm@l9dfdOcnSxh){fbu!hwURHg_3DvZRt1>iP25cU^ V2e*q;zk-{nfSi=FWTk|0(0{RAfOr4^ literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/statusbar/torstatus.cpp b/retroshare-gui/src/gui/statusbar/torstatus.cpp new file mode 100644 index 000000000..5b541a70b --- /dev/null +++ b/retroshare-gui/src/gui/statusbar/torstatus.cpp @@ -0,0 +1,115 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2009 RetroShare Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ +#include "torstatus.h" + +#include +#include +#include +#include + +#include "retroshare/rsconfig.h" +#include "util/misc.h" + +#ifdef RETROTOR +#include "TorControl/TorManager.h" +#include "TorControl/TorControl.h" +#endif + +#include + +TorStatus::TorStatus(QWidget *parent) + : QWidget(parent) +{ + QHBoxLayout *hbox = new QHBoxLayout(); + hbox->setMargin(0); + hbox->setSpacing(6); + + statusTor = new QLabel("" + tr("Tor") + ":", this ); + statusTor->setToolTip(tr("

This version of Retroshare uses Tor to connect to your friends.

")) ; + hbox->addWidget(statusTor); + + torstatusLabel = new QLabel( this ); + torstatusLabel->setPixmap(QPixmap(":/icons/no-tor.png")); + hbox->addWidget(torstatusLabel); + + _compactMode = false; + + setLayout( hbox ); +} + +void TorStatus::getTorStatus() +{ + statusTor->setVisible(!_compactMode); + QString text = _compactMode?statusTor->text():""; + + /* now the extra bit .... switch on check boxes */ + + int S = QFontMetricsF(torstatusLabel->font()).height(); + +#ifdef RETROTOR + // get Tor status + int tor_control_status = Tor::TorManager::instance()->control()->status(); + int torstatus = Tor::TorManager::instance()->control()->torStatus(); + + QString tor_control_status_str,torstatus_str ; + + switch(tor_control_status) + { + default: + case Tor::TorControl::Error : tor_control_status_str = "Error" ; break ; + case Tor::TorControl::NotConnected: tor_control_status_str = "Not connected" ; break ; + case Tor::TorControl::Connecting: tor_control_status_str = "Connecting" ; break ; + case Tor::TorControl::Authenticating: tor_control_status_str = "Authenticating" ; break ; + case Tor::TorControl::Connected: tor_control_status_str = "Connected" ; break ; + } + + switch(torstatus) + { + default: + case Tor::TorControl::TorUnknown: torstatus_str = "Unknown" ; break ; + case Tor::TorControl::TorOffline: torstatus_str = "Tor offline" ; break ; + case Tor::TorControl::TorReady: torstatus_str = "Tor ready" ; break ; + } + +#define MIN_RS_NET_SIZE 10 + + if(torstatus == Tor::TorControl::TorOffline) + { + // RED - some issue. + torstatusLabel->setPixmap(QPixmap(":/icons/tor-stopping.png").scaledToHeight(1.5*S,Qt::SmoothTransformation)); + torstatusLabel->setToolTip( text + tr("Tor is currently offline")); + } + else if(torstatus == Tor::TorControl::TorReady) + { + torstatusLabel->setPixmap(QPixmap(":/icons/tor-on.png").scaledToHeight(1.5*S,Qt::SmoothTransformation)); + torstatusLabel->setToolTip( text + tr("Tor is OK")); + } + else // torstatus == Tor::TorControl::TorUnknown + { + // GRAY. + torstatusLabel->setPixmap(QPixmap(":/icons/no-tor.png").scaledToHeight(1.5*S,Qt::SmoothTransformation)); + torstatusLabel->setToolTip( text + tr("No tor configuration")); + } +#else + torstatusLabel->setPixmap(QPixmap(":/icons/tor-stopping.png").scaledToHeight(S,Qt::SmoothTransformation)); + torstatusLabel->setToolTip( text + tr("Tor is currently offline")); +#endif +} diff --git a/retroshare-gui/src/gui/statusbar/torstatus.h b/retroshare-gui/src/gui/statusbar/torstatus.h new file mode 100644 index 000000000..6728b7cbc --- /dev/null +++ b/retroshare-gui/src/gui/statusbar/torstatus.h @@ -0,0 +1,41 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2009 RetroShare Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#pragma once + +#include + +class QLabel; + +class TorStatus : public QWidget +{ + Q_OBJECT +public: + TorStatus(QWidget *parent = 0); + + void getTorStatus( ); + void setCompactMode(bool compact) {_compactMode = compact; } + +private: + QLabel *torstatusLabel, *statusTor; + bool _compactMode; +}; + diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index a6ed430d2..2fa5aafca 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -581,6 +581,7 @@ HEADERS += rshare.h \ gui/statusbar/peerstatus.h \ gui/statusbar/natstatus.h \ gui/statusbar/dhtstatus.h \ + gui/statusbar/torstatus.h \ gui/statusbar/ratesstatus.h \ gui/statusbar/hashingstatus.h \ gui/statusbar/discstatus.h \ @@ -923,6 +924,7 @@ SOURCES += main.cpp \ gui/statusbar/peerstatus.cpp \ gui/statusbar/natstatus.cpp \ gui/statusbar/dhtstatus.cpp \ + gui/statusbar/torstatus.cpp \ gui/statusbar/ratesstatus.cpp \ gui/statusbar/hashingstatus.cpp \ gui/statusbar/discstatus.cpp \ From 19f1a645f863918c2338b39a340b8358331a2d92 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 19 Jan 2018 13:42:31 +0100 Subject: [PATCH 30/42] fixed update of Tor status in settings --- .../src/gui/settings/AppearancePage.ui | 38 +++++++++---------- .../src/gui/settings/ServerPage.cpp | 12 +++++- retroshare-gui/src/gui/settings/ServerPage.ui | 4 +- retroshare-gui/src/main.cpp | 2 + 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/retroshare-gui/src/gui/settings/AppearancePage.ui b/retroshare-gui/src/gui/settings/AppearancePage.ui index d97b102fd..1813e8d3f 100755 --- a/retroshare-gui/src/gui/settings/AppearancePage.ui +++ b/retroshare-gui/src/gui/settings/AppearancePage.ui @@ -366,13 +366,6 @@
- - - - Show DHT Status - - - @@ -380,13 +373,6 @@ - - - - Show NAT Status - - - @@ -418,17 +404,31 @@ - - + + - Show SysTray on Status Bar + Show NAT Status + + + + + + + Show Operating Mode Status - + - Show Operating Mode Status + Show DHT Status + + + + + + + Show SysTray on Status Bar diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index 62ef905a0..9f74ec670 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -62,12 +62,20 @@ /// #ifdef RETROTOR +const static uint32_t TAB_HIDDEN_SERVICE_OUTGOING = 0; const static uint32_t TAB_HIDDEN_SERVICE_INCOMING = 1; + +const static uint32_t TAB_NETWORK = 0; +const static uint32_t TAB_HIDDEN_SERVICE = 1; const static uint32_t TAB_IP_FILTERS = 99; // This is a trick: these tabs do not exist, so enabling/disabling them has no effect const static uint32_t TAB_RELAYS = 99; #else -const static uint32_t TAB_IP_FILTERS = 1; +const static uint32_t TAB_HIDDEN_SERVICE_OUTGOING = 0; const static uint32_t TAB_HIDDEN_SERVICE_INCOMING = 2; + +const static uint32_t TAB_NETWORK = 0; +const static uint32_t TAB_IP_FILTERS = 1; +const static uint32_t TAB_HIDDEN_SERVICE = 2; const static uint32_t TAB_RELAYS = 3; #endif @@ -908,7 +916,7 @@ void ServerPage::saveAddresses() saveCommon(); - if(ui.tabWidget->currentIndex() == 2) // hidden services tab + if(ui.tabWidget->currentIndex() == TAB_HIDDEN_SERVICE) // hidden services tab updateOutProxyIndicator(); if (mIsHiddenNode) { diff --git a/retroshare-gui/src/gui/settings/ServerPage.ui b/retroshare-gui/src/gui/settings/ServerPage.ui index 5394ce5be..36e114a8f 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.ui +++ b/retroshare-gui/src/gui/settings/ServerPage.ui @@ -26,7 +26,7 @@ - 0 + 2 @@ -810,7 +810,7 @@ behind a firewall or a VPN. - 2 + 0 diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index fb7245dc8..456592c98 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -389,6 +389,8 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); splashScreen.show(); splashScreen.showMessage(rshare.translate("SplashScreen", "Load configuration"), Qt::AlignHCenter | Qt::AlignBottom); + QCoreApplication::processEvents(); + /* stop Retroshare if startup fails */ if (!RsControl::instance()->StartupRetroShare()) { From 6179d22ad50472835266a20b500a5794f3e773c0 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 19 Jan 2018 22:13:40 +0100 Subject: [PATCH 31/42] fixed uninitialized pointer in MainWindow --- retroshare-gui/src/gui/MainWindow.cpp | 33 ++++++++++++++++----------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index 61eb6548f..e8b33b1d5 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -247,27 +247,34 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) if(hiddenmode) { +#ifdef RETROTOR torstatus = new TorStatus(); torstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowTor", QVariant(true)).toBool()); statusBar()->addWidget(torstatus); torstatus->getTorStatus(); +#else + torstatus = NULL ; +#endif + + natstatus = NULL ; + dhtstatus = NULL ; } else + { torstatus = NULL ; -#ifndef RETROTOR - natstatus = new NATStatus(); - if(hiddenmode) natstatus->setVisible(false); - else natstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowNAT", QVariant(true)).toBool()); - statusBar()->addWidget(natstatus); - natstatus->getNATStatus(); - - dhtstatus = new DHTStatus(); - if(hiddenmode) dhtstatus->setVisible(false); - else dhtstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowDHT", QVariant(true)).toBool()); - statusBar()->addWidget(dhtstatus); - dhtstatus->getDHTStatus(); -#endif + natstatus = new NATStatus(); + if(hiddenmode) natstatus->setVisible(false); + else natstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowNAT", QVariant(true)).toBool()); + statusBar()->addWidget(natstatus); + natstatus->getNATStatus(); + + dhtstatus = new DHTStatus(); + if(hiddenmode) dhtstatus->setVisible(false); + else dhtstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowDHT", QVariant(true)).toBool()); + statusBar()->addWidget(dhtstatus); + dhtstatus->getDHTStatus(); + } hashingstatus = new HashingStatus(); hashingstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowHashing", QVariant(true)).toBool()); From 15decacc0d04c01c9b7b6d955cbda9bde7e2cf88 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 20 Jan 2018 16:43:38 +0100 Subject: [PATCH 32/42] attempt to improve the tor statusbar widget --- retroshare-gui/src/TorControl/TorManager.cpp | 19 +-------- retroshare-gui/src/TorControl/TorManager.h | 1 + retroshare-gui/src/gui/MainWindow.cpp | 2 +- .../src/gui/statusbar/torstatus.cpp | 39 +++++++++++++++---- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/retroshare-gui/src/TorControl/TorManager.cpp b/retroshare-gui/src/TorControl/TorManager.cpp index b7b14e5dc..33d4eb4c8 100644 --- a/retroshare-gui/src/TorControl/TorManager.cpp +++ b/retroshare-gui/src/TorControl/TorManager.cpp @@ -161,18 +161,6 @@ bool TorManager::setupHiddenService() std::cerr << "legacy dir not set! Cannot proceed." << std::endl; return false ; } -// if (!keyData.isEmpty()) -// { -// CryptoKey key; -// if (!key.loadFromData(QByteArray::fromBase64(keyData.toLatin1()), CryptoKey::PrivateKey, CryptoKey::DER)) -// { -// qWarning() << "Cannot load service key from configuration"; -// return; -// } -// -// mHiddenService = new Tor::HiddenService(key, legacyDir, this); -// } -// else std::cerr << "Using legacy dir: " << legacyDir.toStdString() << std::endl; @@ -193,11 +181,6 @@ bool TorManager::setupHiddenService() std::cerr << "Got key from legacy dir: " << std::endl; std::cerr << keyData.toStdString() << std::endl; } -// else if (!m_settings->read("initializing").toBool()) -// { -// qWarning() << "Missing private key for initialized identity"; -// return; -// } else { d->hiddenService = new Tor::HiddenService(legacyDir, this); @@ -235,7 +218,7 @@ bool TorManager::setupHiddenService() return true ; } -void hiddenServiceStatusChanged(int old_status,int new_status) +void TorManager::hiddenServiceStatusChanged(int old_status,int new_status) { std::cerr << "Hidden service status changed from " << old_status << " to " << new_status << std::endl; } diff --git a/retroshare-gui/src/TorControl/TorManager.h b/retroshare-gui/src/TorControl/TorManager.h index 254306779..c9b013be1 100644 --- a/retroshare-gui/src/TorControl/TorManager.h +++ b/retroshare-gui/src/TorControl/TorManager.h @@ -93,6 +93,7 @@ public slots: private slots: void hiddenServicePrivateKeyChanged(); + void hiddenServiceStatusChanged(int old_status,int new_status); signals: void configurationNeededChanged(); diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index e8b33b1d5..40ef5a1aa 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -275,7 +275,7 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) statusBar()->addWidget(dhtstatus); dhtstatus->getDHTStatus(); } - + hashingstatus = new HashingStatus(); hashingstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowHashing", QVariant(true)).toBool()); statusBar()->addPermanentWidget(hashingstatus, 1); diff --git a/retroshare-gui/src/gui/statusbar/torstatus.cpp b/retroshare-gui/src/gui/statusbar/torstatus.cpp index 5b541a70b..bb5aefab1 100644 --- a/retroshare-gui/src/gui/statusbar/torstatus.cpp +++ b/retroshare-gui/src/gui/statusbar/torstatus.cpp @@ -60,6 +60,28 @@ void TorStatus::getTorStatus() statusTor->setVisible(!_compactMode); QString text = _compactMode?statusTor->text():""; + /* check local network state. We cannot make sure that Tor is running yet. */ + uint32_t netState = rsConfig -> getNetState(); + bool online ; + + switch(netState) + { + default: + case RSNET_NETSTATE_BAD_UNKNOWN: + case RSNET_NETSTATE_BAD_OFFLINE: online = false ; + break ; + + case RSNET_NETSTATE_WARNING_RESTART: + + case RSNET_NETSTATE_BAD_NATSYM: + case RSNET_NETSTATE_BAD_NODHT_NAT: + case RSNET_NETSTATE_WARNING_NATTED: + case RSNET_NETSTATE_WARNING_NODHT: + case RSNET_NETSTATE_GOOD: + case RSNET_NETSTATE_ADV_FORWARD: online = true ; + break ; + } + /* now the extra bit .... switch on check boxes */ int S = QFontMetricsF(torstatusLabel->font()).height(); @@ -70,15 +92,16 @@ void TorStatus::getTorStatus() int torstatus = Tor::TorManager::instance()->control()->torStatus(); QString tor_control_status_str,torstatus_str ; + bool tor_control_ok ; switch(tor_control_status) { default: - case Tor::TorControl::Error : tor_control_status_str = "Error" ; break ; - case Tor::TorControl::NotConnected: tor_control_status_str = "Not connected" ; break ; - case Tor::TorControl::Connecting: tor_control_status_str = "Connecting" ; break ; - case Tor::TorControl::Authenticating: tor_control_status_str = "Authenticating" ; break ; - case Tor::TorControl::Connected: tor_control_status_str = "Connected" ; break ; + case Tor::TorControl::Error : tor_control_ok = false ; tor_control_status_str = "Error" ; break ; + case Tor::TorControl::NotConnected: tor_control_ok = false ; tor_control_status_str = "Not connected" ; break ; + case Tor::TorControl::Connecting: tor_control_ok = false ; tor_control_status_str = "Connecting" ; break ; + case Tor::TorControl::Authenticating: tor_control_ok = false ; tor_control_status_str = "Authenticating" ; break ; + case Tor::TorControl::Connected: tor_control_ok = true ; tor_control_status_str = "Connected" ; break ; } switch(torstatus) @@ -91,13 +114,15 @@ void TorStatus::getTorStatus() #define MIN_RS_NET_SIZE 10 - if(torstatus == Tor::TorControl::TorOffline) + std::cerr << "(II) tor status: net=" << netState << " tor_control= " << tor_control_status << " tor_status=" << torstatus << std::endl; + + if(torstatus == Tor::TorControl::TorOffline || !online || !tor_control_ok) { // RED - some issue. torstatusLabel->setPixmap(QPixmap(":/icons/tor-stopping.png").scaledToHeight(1.5*S,Qt::SmoothTransformation)); torstatusLabel->setToolTip( text + tr("Tor is currently offline")); } - else if(torstatus == Tor::TorControl::TorReady) + else if(torstatus == Tor::TorControl::TorReady && online && tor_control_ok) { torstatusLabel->setPixmap(QPixmap(":/icons/tor-on.png").scaledToHeight(1.5*S,Qt::SmoothTransformation)); torstatusLabel->setToolTip( text + tr("Tor is OK")); From 0112cf23e5ecc329509331fb392942c0977751f5 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 20 Jan 2018 17:10:47 +0100 Subject: [PATCH 33/42] added check after starting TorManager --- .../src/TorControl/TorControlWindow.cpp | 6 +++++- .../src/TorControl/TorControlWindow.ui | 18 +++++++++--------- retroshare-gui/src/TorControl/TorManager.cpp | 11 ++++++----- retroshare-gui/src/TorControl/TorManager.h | 2 +- retroshare-gui/src/gui/statusbar/torstatus.cpp | 2 -- retroshare-gui/src/main.cpp | 12 ++++++------ 6 files changed, 27 insertions(+), 24 deletions(-) diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp index 4cd626298..61c7b96ea 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.cpp +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -76,7 +76,11 @@ void TorControlDialog::statusChanged() } torStatus_LB->setText(torstatus_str) ; - //torStatus_LB->setText(tor_control_status_str) ; + + if(torstatus == Tor::TorControl::TorUnknown) + torStatus_LB->setToolTip(tr("Check that Tor is accessible in your executable path")) ; + else + torStatus_LB->setToolTip("") ; QVariantMap qvm = mTorManager->control()->bootstrapStatus(); QString bootstrapstatus_str ; diff --git a/retroshare-gui/src/TorControl/TorControlWindow.ui b/retroshare-gui/src/TorControl/TorControlWindow.ui index 7d5f3993a..602146641 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.ui +++ b/retroshare-gui/src/TorControl/TorControlWindow.ui @@ -7,7 +7,7 @@ 0 0 600 - 188 + 228 @@ -54,7 +54,7 @@ - + Tor status: @@ -66,19 +66,19 @@ - TextLabel + Unknown - TextLabel + Not started - + Hidden service address: @@ -88,7 +88,7 @@ - + Tor bootstrap status: @@ -100,12 +100,12 @@ - TextLabel + Not set - + Onion address: @@ -117,7 +117,7 @@ - TextLabel + Not set diff --git a/retroshare-gui/src/TorControl/TorManager.cpp b/retroshare-gui/src/TorControl/TorManager.cpp index 33d4eb4c8..85ff58f7a 100644 --- a/retroshare-gui/src/TorControl/TorManager.cpp +++ b/retroshare-gui/src/TorControl/TorManager.cpp @@ -272,7 +272,7 @@ QString TorManager::errorMessage() const return d->errorMessage; } -void TorManager::start() +bool TorManager::start() { if (!d->errorMessage.isEmpty()) { d->errorMessage.clear(); @@ -304,7 +304,7 @@ void TorManager::start() if (!port) { d->setError(QStringLiteral("Invalid control port settings from environment or configuration")); - return; + return false; } if (address.isNull()) @@ -320,7 +320,7 @@ void TorManager::start() if (executable.isEmpty()) { d->setError(QStringLiteral("Cannot find tor executable")); - return; + return false; } if (!d->process) { @@ -333,13 +333,13 @@ void TorManager::start() if (!QFile::exists(d->dataDir) && !d->createDataDir(d->dataDir)) { d->setError(QStringLiteral("Cannot write data location: %1").arg(d->dataDir)); - return; + return false; } QString defaultTorrc = d->dataDir + QStringLiteral("default_torrc"); if (!QFile::exists(defaultTorrc) && !d->createDefaultTorrc(defaultTorrc)) { d->setError(QStringLiteral("Cannot write data files: %1").arg(defaultTorrc)); - return; + return false; } QFile torrc(d->dataDir + QStringLiteral("torrc")); @@ -353,6 +353,7 @@ void TorManager::start() d->process->setDefaultTorrc(defaultTorrc); d->process->start(); } + return true ; } bool TorManager::getProxyServerInfo(QHostAddress& proxy_server_adress,uint16_t& proxy_server_port) diff --git a/retroshare-gui/src/TorControl/TorManager.h b/retroshare-gui/src/TorControl/TorManager.h index c9b013be1..d81d60d57 100644 --- a/retroshare-gui/src/TorControl/TorManager.h +++ b/retroshare-gui/src/TorControl/TorManager.h @@ -89,7 +89,7 @@ public: bool getProxyServerInfo(QHostAddress& proxy_server_adress,uint16_t& proxy_server_port); public slots: - void start(); + bool start(); private slots: void hiddenServicePrivateKeyChanged(); diff --git a/retroshare-gui/src/gui/statusbar/torstatus.cpp b/retroshare-gui/src/gui/statusbar/torstatus.cpp index bb5aefab1..399243ac4 100644 --- a/retroshare-gui/src/gui/statusbar/torstatus.cpp +++ b/retroshare-gui/src/gui/statusbar/torstatus.cpp @@ -114,8 +114,6 @@ void TorStatus::getTorStatus() #define MIN_RS_NET_SIZE 10 - std::cerr << "(II) tor status: net=" << netState << " tor_control= " << tor_control_status << " tor_status=" << torstatus << std::endl; - if(torstatus == Tor::TorControl::TorOffline || !online || !tor_control_ok) { // RED - some issue. diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 456592c98..df865e416 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -357,7 +357,12 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); RsDirUtil::checkCreateDirectory(std::string(tor_hidden_service_dir.toUtf8())) ; torManager->setupHiddenService(); - torManager->start(); + + if(! torManager->start() || torManager->hasError()) + { + QMessageBox::critical(NULL,QObject::tr("Cannot start Tor Manager!"),QObject::tr("Tor cannot be started on your system: \n\n")+torManager->errorMessage()) ; + return 1 ; + } { TorControlDialog tcd(torManager) ; @@ -368,11 +373,6 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); QCoreApplication::processEvents(); usleep(0.2*1000*1000) ; } -// for(uint32_t i=0;i<10;++i) // give some time (2 secs) to see what's going on -// { -// QCoreApplication::processEvents(); -// usleep(0.2*1000*1000) ; -// } tcd.hide(); From 2c61f3888750b025d3ab68ec5e434ecc3074885a Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 20 Jan 2018 19:22:49 +0100 Subject: [PATCH 34/42] added missing call to set compact mode --- retroshare-gui/src/gui/MainWindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index 40ef5a1aa..6219575b5 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -1617,6 +1617,10 @@ void MainWindow::setCompactStatusMode(bool compact) dhtstatus->setCompactMode(compact); dhtstatus->getDHTStatus(); } + + if(torstatus) + torstatus->setCompactMode(compact) ; + hashingstatus->setCompactMode(compact); ratesstatus->setCompactMode(compact); //opModeStatus: TODO Show only ??? From c1fccef53b48ce09773ea23151241ab93fbd812a Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 20 Jan 2018 19:23:08 +0100 Subject: [PATCH 35/42] added comment about tab numbers --- retroshare-gui/src/gui/settings/ServerPage.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index 9f74ec670..6a019990a 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -61,14 +61,15 @@ /// /// +// Tabs numbers *after* non relevant tabs are removed. So do not use them to add/remove tabs!! #ifdef RETROTOR -const static uint32_t TAB_HIDDEN_SERVICE_OUTGOING = 0; -const static uint32_t TAB_HIDDEN_SERVICE_INCOMING = 1; +static const uint32_t TAB_HIDDEN_SERVICE_OUTGOING = 0; +static const uint32_t TAB_HIDDEN_SERVICE_INCOMING = 1; -const static uint32_t TAB_NETWORK = 0; -const static uint32_t TAB_HIDDEN_SERVICE = 1; -const static uint32_t TAB_IP_FILTERS = 99; // This is a trick: these tabs do not exist, so enabling/disabling them has no effect -const static uint32_t TAB_RELAYS = 99; +static const uint32_t TAB_NETWORK = 0; +static const uint32_t TAB_HIDDEN_SERVICE = 1; +static const uint32_t TAB_IP_FILTERS = 99; // This is a trick: these tabs do not exist, so enabling/disabling them has no effect +static const uint32_t TAB_RELAYS = 99; #else const static uint32_t TAB_HIDDEN_SERVICE_OUTGOING = 0; const static uint32_t TAB_HIDDEN_SERVICE_INCOMING = 2; @@ -90,6 +91,8 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) manager = NULL ; #ifdef RETROTOR + // Here we use absolute numbers instead of consts defined above, because the consts correspond to the tab number *after* this tab removal. + ui.tabWidget->removeTab(3) ; // remove relays. Not useful in Tor mode. ui.tabWidget->removeTab(1) ; // remove IP filters. Not useful in Tor mode. From d0039241d3af8b17d102dead03abec28ef3bbaed Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 27 Jan 2018 20:22:31 +0100 Subject: [PATCH 36/42] replaced usleep() by rstime::rs_usleep() which accepts times >= 1 sec. Should fix problems on windows --- libretroshare/src/crypto/chacha20.cpp | 10 ++-- .../src/file_sharing/directory_updater.cc | 3 +- libretroshare/src/file_sharing/hash_cache.cc | 10 ++-- libretroshare/src/ft/ftcontroller.cc | 3 +- libretroshare/src/ft/ftextralist.cc | 18 ++----- libretroshare/src/gxs/rsdataservice.cc | 14 ++--- libretroshare/src/gxs/rsgenexchange.cc | 3 +- libretroshare/src/gxs/rsgxsnetservice.cc | 3 +- libretroshare/src/libretroshare.pro | 4 +- libretroshare/src/pqi/authgpg.cc | 3 +- libretroshare/src/pqi/pqissludp.cc | 5 +- libretroshare/src/pqi/pqithreadstreamer.cc | 5 +- libretroshare/src/rsserver/p3face-server.cc | 7 +-- .../src/services/autoproxy/p3i2pbob.cc | 3 +- .../services/autoproxy/rsautoproxymonitor.cc | 3 +- libretroshare/src/services/p3idservice.cc | 13 ++--- libretroshare/src/util/rsdir.cc | 7 +-- libretroshare/src/util/rsthreads.cc | 4 +- .../src/util/{rsscopetimer.cc => rstime.cc} | 24 ++++++++- .../src/util/{rsscopetimer.h => rstime.h} | 53 +++++++++++-------- plugins/FeedReader/services/p3FeedReader.cc | 3 +- .../FeedReader/services/p3FeedReaderThread.cc | 8 ++- .../src/TorControl/TorControlWindow.cpp | 3 +- .../src/gui/chat/ChatLobbyDialog.cpp | 5 +- retroshare-gui/src/main.cpp | 3 +- retroshare-gui/src/util/HandleRichText.cpp | 4 +- retroshare-gui/src/util/imageutil.cpp | 6 +-- retroshare-nogui/src/retroshare.cc | 7 +-- 28 files changed, 134 insertions(+), 100 deletions(-) rename libretroshare/src/util/{rsscopetimer.cc => rstime.cc} (82%) rename libretroshare/src/util/{rsscopetimer.h => rstime.h} (61%) diff --git a/libretroshare/src/crypto/chacha20.cpp b/libretroshare/src/crypto/chacha20.cpp index 1240d0cb8..3f12b2086 100644 --- a/libretroshare/src/crypto/chacha20.cpp +++ b/libretroshare/src/crypto/chacha20.cpp @@ -38,7 +38,7 @@ #include "crypto/chacha20.h" #include "util/rsprint.h" #include "util/rsrandom.h" -#include "util/rsscopetimer.h" +#include "util/rstime.h" #define rotl(x,n) { x = (x << n) | (x >> (-n & 31)) ;} @@ -1385,27 +1385,27 @@ bool perform_tests() uint8_t received_tag[16] ; { - RsScopeTimer s("AEAD1") ; + rstime::RsScopeTimer s("AEAD1") ; chacha20_encrypt_rs(key, 1, nonce, ten_megabyte_data,SIZE) ; std::cerr << " Chacha20 encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl; } { - RsScopeTimer s("AEAD2") ; + rstime::RsScopeTimer s("AEAD2") ; AEAD_chacha20_poly1305_rs(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ; std::cerr << " AEAD/poly1305 own encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl; } #if OPENSSL_VERSION_NUMBER >= 0x010100000L && !defined(LIBRESSL_VERSION_NUMBER) { - RsScopeTimer s("AEAD3") ; + rstime::RsScopeTimer s("AEAD3") ; AEAD_chacha20_poly1305_openssl(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ; std::cerr << " AEAD/poly1305 openssl encryption speed: " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl; } #endif { - RsScopeTimer s("AEAD4") ; + rstime::RsScopeTimer s("AEAD4") ; AEAD_chacha20_sha256(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ; std::cerr << " AEAD/sha256 encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl; diff --git a/libretroshare/src/file_sharing/directory_updater.cc b/libretroshare/src/file_sharing/directory_updater.cc index 085f92ebb..6d95961ab 100644 --- a/libretroshare/src/file_sharing/directory_updater.cc +++ b/libretroshare/src/file_sharing/directory_updater.cc @@ -23,6 +23,7 @@ * */ #include "util/folderiterator.h" +#include "util/rstime.h" #include "rsserver/p3face.h" #include "directory_storage.h" @@ -92,7 +93,7 @@ void LocalDirectoryUpdater::data_tick() for(uint32_t i=0;i<10;++i) { - usleep(1*1000*1000); + rstime::rs_usleep(1*1000*1000); { if(mForceUpdate) diff --git a/libretroshare/src/file_sharing/hash_cache.cc b/libretroshare/src/file_sharing/hash_cache.cc index 89a4aec38..f0db680cf 100644 --- a/libretroshare/src/file_sharing/hash_cache.cc +++ b/libretroshare/src/file_sharing/hash_cache.cc @@ -24,7 +24,7 @@ */ #include "util/rsdir.h" #include "util/rsprint.h" -#include "util/rsscopetimer.h" +#include "util/rstime.h" #include "rsserver/p3face.h" #include "pqi/authssl.h" #include "hash_cache.h" @@ -125,7 +125,7 @@ void HashStorage::data_tick() std::cerr << "nothing to hash. Sleeping for " << st << " us" << std::endl; #endif - usleep(st); // when no files to hash, just wait for 2 secs. This avoids a dramatic loop. + rstime::rs_usleep(st); // when no files to hash, just wait for 2 secs. This avoids a dramatic loop. if(st > MAX_INACTIVITY_SLEEP_TIME) { @@ -163,7 +163,7 @@ void HashStorage::data_tick() if(paused) // we need to wait off mutex!! { - usleep(MAX_INACTIVITY_SLEEP_TIME) ; + rstime::rs_usleep(MAX_INACTIVITY_SLEEP_TIME) ; std::cerr << "Hashing process currently paused." << std::endl; return; } @@ -190,7 +190,7 @@ void HashStorage::data_tick() RsServer::notify()->notifyHashingInfo(NOTIFY_HASHTYPE_HASH_FILE, tmpout) ; - double seconds_origin = RsScopeTimer::currentTime() ; + double seconds_origin = rstime::RsScopeTimer::currentTime() ; if(RsDirUtil::getFileHash(job.full_path, hash,size, this)) { @@ -215,7 +215,7 @@ void HashStorage::data_tick() else std::cerr << "ERROR: cannot hash file " << job.full_path << std::endl; - mHashingTime += RsScopeTimer::currentTime() - seconds_origin ; + mHashingTime += rstime::RsScopeTimer::currentTime() - seconds_origin ; mHashedBytes += size ; if(mHashingTime > 3) diff --git a/libretroshare/src/ft/ftcontroller.cc b/libretroshare/src/ft/ftcontroller.cc index 382d13cb6..fb6d54bae 100644 --- a/libretroshare/src/ft/ftcontroller.cc +++ b/libretroshare/src/ft/ftcontroller.cc @@ -40,6 +40,7 @@ #endif #include "util/rsdiscspace.h" #include "util/rsmemory.h" +#include "util/rstime.h" #include "ft/ftcontroller.h" @@ -219,7 +220,7 @@ void ftController::data_tick() /* check the queues */ //Waiting 1 sec before start - usleep(1*1000*1000); // 1 sec + rstime::rs_usleep(1*1000*1000); // 1 sec #ifdef CONTROL_DEBUG //std::cerr << "ftController::run()"; diff --git a/libretroshare/src/ft/ftextralist.cc b/libretroshare/src/ft/ftextralist.cc index cd52f5ce5..b6fec4076 100644 --- a/libretroshare/src/ft/ftextralist.cc +++ b/libretroshare/src/ft/ftextralist.cc @@ -32,6 +32,7 @@ #include "ft/ftextralist.h" #include "rsitems/rsconfigitems.h" #include "util/rsdir.h" +#include "util/rstime.h" #include #include /* for (u)sleep() */ #include @@ -64,12 +65,8 @@ void ftExtraList::data_tick() /* Hash a file */ hashAFile(); -#ifdef WIN32 - Sleep(1); -#else /* microsleep */ - usleep(10); -#endif + rstime::rs_usleep(10); } else { @@ -513,16 +510,7 @@ bool ftExtraList::loadList(std::list& load) delete (*it); /* short sleep */ -#ifndef WINDOWS_SYS -/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ - usleep(1000); /* 1000 per second */ - -#else -/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ - Sleep(1); -#endif -/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ - + rstime::rs_usleep(1000) ; } load.clear() ; return true; diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index c3252a27c..305f8dee1 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -35,7 +35,7 @@ #include #ifdef RS_DATA_SERVICE_DEBUG_TIME -#include +#include #endif #include "rsdataservice.h" @@ -1066,7 +1066,7 @@ bool RsDataService::validSize(RsNxsGrp* grp) const int RsDataService::retrieveNxsGrps(std::map &grp, bool withMeta, bool /* cache */) { #ifdef RS_DATA_SERVICE_DEBUG_TIME - RsScopeTimer timer(""); + rstime::RsScopeTimer timer(""); int resultCount = 0; int requestedGroups = grp.size(); #endif @@ -1166,7 +1166,7 @@ void RsDataService::locked_retrieveGroups(RetroCursor* c, std::vector int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, bool /* cache */, bool withMeta) { #ifdef RS_DATA_SERVICE_DEBUG_TIME - RsScopeTimer timer(""); + rstime::RsScopeTimer timer(""); int resultCount = 0; #endif @@ -1254,7 +1254,7 @@ int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaRes RsStackMutex stack(mDbMutex); #ifdef RS_DATA_SERVICE_DEBUG_TIME - RsScopeTimer timer(""); + rstime::RsScopeTimer timer(""); int resultCount = 0; #endif @@ -1341,7 +1341,7 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) RsStackMutex stack(mDbMutex); #ifdef RS_DATA_SERVICE_DEBUG_TIME - RsScopeTimer timer(""); + rstime::RsScopeTimer timer(""); int resultCount = 0; int requestedGroups = grp.size(); #endif @@ -1549,7 +1549,7 @@ int RsDataService::retrieveGroupIds(std::vector &grpIds) RsStackMutex stack(mDbMutex); #ifdef RS_DATA_SERVICE_DEBUG_TIME - RsScopeTimer timer(""); + rstime::RsScopeTimer timer(""); int resultCount = 0; #endif @@ -1586,7 +1586,7 @@ int RsDataService::retrieveGroupIds(std::vector &grpIds) int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, RsGxsMessageId::std_vector& msgIds) { #ifdef RS_DATA_SERVICE_DEBUG_TIME - RsScopeTimer timer(""); + rstime::RsScopeTimer timer(""); int resultCount = 0; #endif diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index dd4691306..e1d15d614 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -31,6 +31,7 @@ #include "gxssecurity.h" #include "util/contentvalue.h" #include "util/rsprint.h" +#include "util/rstime.h" #include "retroshare/rsgxsflags.h" #include "retroshare/rsgxscircles.h" #include "retroshare/rsgrouter.h" @@ -138,7 +139,7 @@ void RsGenExchange::data_tick() static const double timeDelta = 0.1; // slow tick in sec tick(); - usleep((int) (timeDelta * 1000 *1000)); // timeDelta sec + rstime::rs_usleep((int) (timeDelta * 1000 *1000)); // timeDelta sec } void RsGenExchange::tick() diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index ec26e0081..8f055bc1b 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -210,6 +210,7 @@ #include "retroshare/rspeers.h" #include "pgp/pgpauxutils.h" #include "util/rsdir.h" +#include "util/rstime.h" #include "util/rsmemory.h" #include "util/stacktrace.h" @@ -1787,7 +1788,7 @@ void RsGxsNetService::data_tick() static const double timeDelta = 0.5; //Start waiting as nothing to do in runup - usleep((int) (timeDelta * 1000 * 1000)); // timeDelta sec + rstime::rs_usleep((int) (timeDelta * 1000 * 1000)); // timeDelta sec if(mUpdateCounter >= 120) // 60 seconds { diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 7093f273e..19d2dce27 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -547,7 +547,7 @@ HEADERS += util/folderiterator.h \ util/rsmemcache.h \ util/rstickevent.h \ util/rsrecogn.h \ - util/rsscopetimer.h \ + util/rstime.h \ util/stacktrace.h \ util/rsdeprecate.h \ util/cxx11retrocompat.h @@ -695,7 +695,7 @@ SOURCES += util/folderiterator.cc \ util/rsrandom.cc \ util/rstickevent.cc \ util/rsrecogn.cc \ - util/rsscopetimer.cc + util/rstime.cc upnp_miniupnpc { diff --git a/libretroshare/src/pqi/authgpg.cc b/libretroshare/src/pqi/authgpg.cc index 8553fc127..ccfb8a260 100644 --- a/libretroshare/src/pqi/authgpg.cc +++ b/libretroshare/src/pqi/authgpg.cc @@ -35,6 +35,7 @@ #include "pgp/pgphandler.h" #include +#include #include #include /* for (u)sleep() */ #include @@ -187,7 +188,7 @@ int AuthGPG::GPGInit(const RsPgpId &ownId) void AuthGPG::data_tick() { - usleep(100 * 1000); //100 msec + rstime::rs_usleep(100 * 1000); //100 msec /// every 100 milliseconds processServices(); diff --git a/libretroshare/src/pqi/pqissludp.cc b/libretroshare/src/pqi/pqissludp.cc index 29bd228c9..f14fb82e5 100644 --- a/libretroshare/src/pqi/pqissludp.cc +++ b/libretroshare/src/pqi/pqissludp.cc @@ -35,6 +35,7 @@ #include "util/rsdebug.h" #include "util/rsnet.h" +#include "util/rstime.h" #include "util/rsstring.h" #include "pqi/p3linkmgr.h" @@ -571,7 +572,7 @@ bool pqissludp::moretoread(uint32_t usec) { return true; } - usleep(usec); + rstime::rs_usleep(usec); } /* check for more to read first ... if nothing... check error @@ -655,7 +656,7 @@ bool pqissludp::cansend(uint32_t usec) return true; } - usleep(usec); + rstime::rs_usleep(usec); } rslog(RSL_DEBUG_ALL, pqissludpzone, diff --git a/libretroshare/src/pqi/pqithreadstreamer.cc b/libretroshare/src/pqi/pqithreadstreamer.cc index f99be143b..54ab925e1 100644 --- a/libretroshare/src/pqi/pqithreadstreamer.cc +++ b/libretroshare/src/pqi/pqithreadstreamer.cc @@ -24,6 +24,7 @@ */ +#include "util/rstime.h" #include "pqi/pqithreadstreamer.h" #include @@ -69,7 +70,7 @@ void pqithreadstreamer::data_tick() if (!isactive) { - usleep(DEFAULT_STREAMER_IDLE_SLEEP); + rstime::rs_usleep(DEFAULT_STREAMER_IDLE_SLEEP); return ; } @@ -92,7 +93,7 @@ void pqithreadstreamer::data_tick() if (sleep_period) { - usleep(sleep_period); + rstime::rs_usleep(sleep_period); } } diff --git a/libretroshare/src/rsserver/p3face-server.cc b/libretroshare/src/rsserver/p3face-server.cc index a7aad022c..d7578b8fd 100644 --- a/libretroshare/src/rsserver/p3face-server.cc +++ b/libretroshare/src/rsserver/p3face-server.cc @@ -25,6 +25,7 @@ */ +#include "util/rstime.h" #include "rsserver/p3face.h" #include "retroshare/rsplugin.h" @@ -134,11 +135,7 @@ RsServer::~RsServer() /* Thread Fn: Run the Core */ void RsServer::data_tick() { -#ifndef WINDOWS_SYS - usleep((int) (mTimeDelta * 1000000)); -#else - Sleep((int) (mTimeDelta * 1000)); -#endif + rstime::rs_usleep(mTimeDelta * 1000000); double ts = getCurrentTS(); double delta = ts - mLastts; diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index 32be374f4..917b8a8a7 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -8,6 +8,7 @@ #include "util/radix32.h" #include "util/radix64.h" #include "util/rsdebug.h" +#include "util/rstime.h" #include "util/rsprint.h" #include "util/rsrandom.h" @@ -39,7 +40,7 @@ static struct RsLog::logInfo i2pBobLogInfo = {RsLog::Default, "p3I2pBob"}; static const time_t selfCheckPeroid = 30; void doSleep(useconds_t timeToSleepMS) { - usleep((useconds_t) (timeToSleepMS * 1000)); + rstime::rs_usleep((useconds_t) (timeToSleepMS * 1000)); } p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr) diff --git a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc index 0f5eb22d5..d4d3f87ce 100644 --- a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc +++ b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc @@ -1,6 +1,7 @@ #include "rsautoproxymonitor.h" #include /* for usleep() */ +#include "util/rstime.h" rsAutoProxyMonitor *rsAutoProxyMonitor::mInstance = NULL; @@ -93,7 +94,7 @@ void rsAutoProxyMonitor::stopAllRSShutdown() // wait for shutdown of all services uint32_t t = 0, timeout = 15; do { - usleep(1000 * 1000); + rstime::rs_usleep(1000 * 1000); RS_STACK_MUTEX(mLock); std::cout << "(II) waiting for auto proxy service(s) to shut down " << t << "/" << timeout << " (remaining: " << mProxies.size() << ")" << std::endl; if (mProxies.empty()) diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 2b37b181e..71b0e2274 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -34,6 +34,7 @@ #include "util/rsstring.h" #include "util/radix64.h" #include "util/rsdir.h" +#include "util/rstime.h" #include "crypto/hashstream.h" #include "gxs/gxssecurity.h" #include "retroshare/rspeers.h" @@ -1071,7 +1072,7 @@ bool p3IdService::signData(const uint8_t *data,uint32_t data_size,const RsGxsId& #ifdef DEBUG_IDS std::cerr << " Cannot get key. Waiting for caching. try " << i << "/6" << std::endl; #endif - usleep(500 * 1000) ; // sleep for 500 msec. + rstime::rs_usleep(500 * 1000) ; // sleep for 500 msec. } else break ; @@ -1110,7 +1111,7 @@ bool p3IdService::validateData(const uint8_t *data,uint32_t data_size,const RsTl #ifdef DEBUG_IDS std::cerr << " Cannot get key. Waiting for caching. try " << i << "/6" << std::endl; #endif - if(force_load) usleep(500 * 1000) ; // sleep for 500 msec. + if(force_load) rstime::rs_usleep(500 * 1000) ; // sleep for 500 msec. } else break ; @@ -1151,7 +1152,7 @@ bool p3IdService::encryptData( const uint8_t *decrypted_data, if(getKey(encryption_key_id,encryption_key)) break ; else - usleep(500*1000) ; // sleep half a sec. + rstime::rs_usleep(500*1000) ; // sleep half a sec. if(encryption_key.keyId.isNull()) { @@ -1222,7 +1223,7 @@ bool p3IdService::encryptData( const uint8_t* decrypted_data, } if(keyNotYetFoundIds.empty()) break; - else usleep(500*1000); + else rstime::rs_usleep(500*1000); } if(!keyNotYetFoundIds.empty()) @@ -1279,7 +1280,7 @@ bool p3IdService::decryptData( const uint8_t *encrypted_data, int maxRounds = force_load ? 6 : 1; for(int i=0; i= 30) return false ; @@ -917,7 +918,7 @@ RsStackFileLock::RsStackFileLock(const std::string& file_path) while(RsDirUtil::createLockFile(file_path,_file_handle)) { std::cerr << "Cannot acquire file lock " << file_path << ", waiting 1 sec." << std::endl; - usleep(1 * 1000 * 1000) ; // 1 sec + rstime::rs_usleep(1 * 1000 * 1000) ; // 1 sec } #ifdef RSDIR_DEBUG std::cerr << "Acquired file handle " << _file_handle << ", lock file:" << file_path << std::endl; @@ -1321,7 +1322,7 @@ bool RsDirUtil::renameWideFile(const std::wstring& from, const std::wstring& to) #endif /* set errno? */ return false ; - usleep(100 * 1000); //100 msec + rstime::rs_usleep(100 * 1000); //100 msec if (loops >= 30) return false ; diff --git a/libretroshare/src/util/rsthreads.cc b/libretroshare/src/util/rsthreads.cc index 8899ee01c..39eca594a 100644 --- a/libretroshare/src/util/rsthreads.cc +++ b/libretroshare/src/util/rsthreads.cc @@ -30,6 +30,8 @@ #include #include +#include "util/rstime.h" + #ifdef __APPLE__ int __attribute__((weak)) pthread_setname_np(const char *__buf) ; int RS_pthread_setname_np(pthread_t /*__target_thread*/, const char *__buf) { @@ -289,7 +291,7 @@ void RsQueueThread::data_tick() THREAD_DEBUG << "RsQueueThread::data_tick() no work: sleeping for: " << mLastSleep << " ms" << std::endl; #endif } - usleep(mLastSleep * 1000); // mLastSleep msec + rstime::rs_usleep(mLastSleep * 1000); // mLastSleep msec } void RsMutex::unlock() diff --git a/libretroshare/src/util/rsscopetimer.cc b/libretroshare/src/util/rstime.cc similarity index 82% rename from libretroshare/src/util/rsscopetimer.cc rename to libretroshare/src/util/rstime.cc index b3ce8fbc3..74808afb9 100644 --- a/libretroshare/src/util/rsscopetimer.cc +++ b/libretroshare/src/util/rstime.cc @@ -24,8 +24,28 @@ */ #include +#include #include -#include "rsscopetimer.h" +#include +#include "rstime.h" + +namespace rstime { + +int rs_usleep(uint32_t micro_seconds) +{ + while(micro_seconds >= 1000000) + { + // usleep cannot be called with 1000000 or more. + + usleep(500000) ; + usleep(500000) ; + + micro_seconds -= 1000000 ; + } + usleep(micro_seconds) ; + + return 0 ; +} RsScopeTimer::RsScopeTimer(const std::string& name) { @@ -57,3 +77,5 @@ double RsScopeTimer::duration() { return currentTime() - _seconds; } + +} diff --git a/libretroshare/src/util/rsscopetimer.h b/libretroshare/src/util/rstime.h similarity index 61% rename from libretroshare/src/util/rsscopetimer.h rename to libretroshare/src/util/rstime.h index 875a8bb5e..4359a28ff 100644 --- a/libretroshare/src/util/rsscopetimer.h +++ b/libretroshare/src/util/rstime.h @@ -23,29 +23,40 @@ * */ -// Use this class to measure and display time duration of a given environment: -// -// { -// RsScopeTimer timer("callToMeasure()") ; -// -// callToMeasure() ; -// } -// - #include -class RsScopeTimer -{ -public: - RsScopeTimer(const std::string& name); - ~RsScopeTimer(); +namespace rstime { - void start(); - double duration(); + /*! + * \brief This is a cross-system definition of usleep, which accepts any 32 bits number of micro-seconds. + */ - static double currentTime(); + int rs_usleep(uint32_t micro_seconds); -private: - std::string _name ; - double _seconds ; -}; + /* Use this class to measure and display time duration of a given environment: + + { + RsScopeTimer timer("callToMeasure()") ; + + callToMeasure() ; + } + + */ + + class RsScopeTimer + { + public: + RsScopeTimer(const std::string& name); + ~RsScopeTimer(); + + void start(); + double duration(); + + static double currentTime(); + + private: + std::string _name ; + double _seconds ; + }; + +} diff --git a/plugins/FeedReader/services/p3FeedReader.cc b/plugins/FeedReader/services/p3FeedReader.cc index efa3b6688..256a1e285 100644 --- a/plugins/FeedReader/services/p3FeedReader.cc +++ b/plugins/FeedReader/services/p3FeedReader.cc @@ -26,6 +26,7 @@ #include "retroshare/rsiface.h" #include "retroshare/rsgxsforums.h" #include "util/rsstring.h" +#include "util/rstime.h" #include "gxs/rsgenexchange.h" #include @@ -2240,7 +2241,7 @@ bool p3FeedReader::waitForToken(uint32_t token) break; } - usleep(500 * 1000); // sleep for 500 msec + rstime::rs_usleep(500 * 1000); // sleep for 500 msec } return false; diff --git a/plugins/FeedReader/services/p3FeedReaderThread.cc b/plugins/FeedReader/services/p3FeedReaderThread.cc index 9ec1106ef..b8db8db46 100644 --- a/plugins/FeedReader/services/p3FeedReaderThread.cc +++ b/plugins/FeedReader/services/p3FeedReaderThread.cc @@ -22,6 +22,7 @@ #include "p3FeedReaderThread.h" #include "rsFeedReaderItems.h" #include "util/rsstring.h" +#include "util/rstime.h" #include "util/CURLWrapper.h" #include "util/XMLWrapper.h" #include "util/HTMLWrapper.h" @@ -51,11 +52,8 @@ p3FeedReaderThread::~p3FeedReaderThread() void p3FeedReaderThread::data_tick() { -#ifdef WIN32 - Sleep(1000); -#else - usleep(1000000); -#endif + rstime::rs_usleep(1000000); + /* every second */ switch (mType) { diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp index 61c7b96ea..368537a95 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.cpp +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -7,6 +7,7 @@ #include #include +#include "util/rstime.h" #include "TorControlWindow.h" #include "TorManager.h" @@ -152,7 +153,7 @@ TorControlDialog::TorStatus TorControlDialog::checkForTor() { switch(mTorManager->control()->torStatus()) { - case Tor::TorControl::TorReady: usleep(1*1000*1000);return TOR_STATUS_OK ; + case Tor::TorControl::TorReady: rstime::rs_usleep(1*1000*1000);return TOR_STATUS_OK ; default: return TOR_STATUS_UNKNOWN ; } diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index 93028d20c..918939917 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -46,7 +46,8 @@ #include "util/HandleRichText.h" #include "util/QtVersion.h" -#include +#include "retroshare/rsnotify.h" +#include "util/rstime.h" #include #include @@ -339,7 +340,7 @@ void ChatLobbyDialog::init(const ChatId &/*id*/, const QString &/*title*/) if(rsIdentity->getIdDetails(gxs_id,details)) break ; else - usleep(1000*300) ; + rstime::rs_usleep(1000*300) ; ui.chatWidget->setName(QString::fromUtf8(details.mNickname.c_str())); //ui.chatWidget->addToolsAction(ui.actionChangeNickname); diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index df865e416..f64adb8ed 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -46,6 +46,7 @@ #include "lang/languagesupport.h" #include "util/RsGxsUpdateBroadcast.h" #include "util/rsdir.h" +#include "util/rstime.h" #ifdef RETROTOR #include "TorControl/TorManager.h" @@ -371,7 +372,7 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); while(tcd.checkForTor() != TorControlDialog::TOR_STATUS_OK || tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) // runs until some status is reached: either tor works, or it fails. { QCoreApplication::processEvents(); - usleep(0.2*1000*1000) ; + rstime::rs_usleep(0.2*1000*1000) ; } tcd.hide(); diff --git a/retroshare-gui/src/util/HandleRichText.cpp b/retroshare-gui/src/util/HandleRichText.cpp index cbe524cf7..2ab1dcb42 100644 --- a/retroshare-gui/src/util/HandleRichText.cpp +++ b/retroshare-gui/src/util/HandleRichText.cpp @@ -36,7 +36,7 @@ #include "gui/RetroShareLink.h" #include "util/ObjectPainter.h" #include "util/imageutil.h" -#include "util/rsscopetimer.h" +#include "util/rstime.h" #include @@ -1151,7 +1151,7 @@ bool RsHtml::makeEmbeddedImage(const QString &fileName, QString &embeddedImage, /** Converts image to embedded image HTML fragment **/ bool RsHtml::makeEmbeddedImage(const QImage &originalImage, QString &embeddedImage, const int maxPixels, const int maxBytes) { - RsScopeTimer s("Embed image"); + rstime::RsScopeTimer s("Embed image"); QImage opt; return ImageUtil::optimizeSize(embeddedImage, originalImage, opt, maxPixels, maxBytes); } diff --git a/retroshare-gui/src/util/imageutil.cpp b/retroshare-gui/src/util/imageutil.cpp index ca2716b09..d32da5a97 100644 --- a/retroshare-gui/src/util/imageutil.cpp +++ b/retroshare-gui/src/util/imageutil.cpp @@ -1,6 +1,6 @@ #include "imageutil.h" #include "util/misc.h" -#include "util/rsscopetimer.h" +#include "util/rstime.h" #include #include @@ -113,7 +113,7 @@ bool ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &opti int ImageUtil::checkSize(QString &embeddedImage, const QImage &img, int maxBytes) { - RsScopeTimer st("Check size"); + rstime::RsScopeTimer st("Check size"); QByteArray bytearray; QBuffer buffer(&bytearray); @@ -166,7 +166,7 @@ void ImageUtil::quantization(const QImage &img, QVector &palette) int bits = 4; // bits/pixel int samplesize = 100000; //only take this many color samples - RsScopeTimer st("Quantization"); + rstime::RsScopeTimer st("Quantization"); QSet colors; //collect color information diff --git a/retroshare-nogui/src/retroshare.cc b/retroshare-nogui/src/retroshare.cc index ef02bb623..65d8c6168 100644 --- a/retroshare-nogui/src/retroshare.cc +++ b/retroshare-nogui/src/retroshare.cc @@ -30,7 +30,8 @@ #include "notifytxt.h" #include -#include +#include "util/argstream.h" +#include "util/rstime.h" #include #ifdef WINDOWS_SYS #include @@ -105,7 +106,7 @@ int main(int argc, char **argv) while(ctrl_mod.processShouldExit() == false) { - usleep(1000*1000); + rstime::rs_usleep(1000*1000); if(!tac.isRunning() && !already) { @@ -224,7 +225,7 @@ int main(int argc, char **argv) #endif } - usleep(1000); + rstime::rs_usleep(1000); } return 1; From 8f7582588ad1b7d5071eb3089a9a145bff2786e3 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 27 Jan 2018 20:59:11 +0100 Subject: [PATCH 37/42] fixed windows compilation --- libretroshare/src/util/rstime.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/libretroshare/src/util/rstime.cc b/libretroshare/src/util/rstime.cc index 74808afb9..067466d65 100644 --- a/libretroshare/src/util/rstime.cc +++ b/libretroshare/src/util/rstime.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include "rstime.h" namespace rstime { From bf8bd4b023626a8970921b7e2ca27ec304a6be70 Mon Sep 17 00:00:00 2001 From: Phenom Date: Wed, 7 Feb 2018 19:00:08 +0100 Subject: [PATCH 38/42] Add Only Connected in FriendSelectionWidget. Add Select All if Multi Selection allowed. Clean Some Code duplicated from RSTreeWidget. --- .../src/gui/common/FriendSelectionWidget.cpp | 83 +++++++++---------- .../src/gui/common/FriendSelectionWidget.h | 4 +- .../src/gui/common/RSTreeWidget.cpp | 75 +++++++++++++++-- retroshare-gui/src/gui/common/RSTreeWidget.h | 7 ++ 4 files changed, 119 insertions(+), 50 deletions(-) diff --git a/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp b/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp index dce1b39f4..5bd3c1789 100644 --- a/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp +++ b/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp @@ -45,11 +45,12 @@ #define IDDIALOG_IDLIST 1 -#define ROLE_ID Qt::UserRole -#define ROLE_SORT_GROUP Qt::UserRole + 1 -#define ROLE_SORT_STANDARD_GROUP Qt::UserRole + 2 -#define ROLE_SORT_NAME Qt::UserRole + 3 -#define ROLE_SORT_STATE Qt::UserRole + 4 +#define ROLE_ID Qt::UserRole +#define ROLE_SORT_GROUP Qt::UserRole + 1 +#define ROLE_SORT_STANDARD_GROUP Qt::UserRole + 2 +#define ROLE_SORT_NAME Qt::UserRole + 3 +#define ROLE_SORT_STATE Qt::UserRole + 4 +#define ROLE_FILTER_REASON Qt::UserRole + 5 #define IMAGE_GROUP16 ":/images/user/group16.png" #define IMAGE_FRIENDINFO ":/images/peerdetails_16x16.png" @@ -109,10 +110,15 @@ FriendSelectionWidget::FriendSelectionWidget(QWidget *parent) mActionSortByState->setCheckable(true); connect(mActionSortByState, SIGNAL(toggled(bool)), this, SLOT(sortByState(bool))); ui->friendList->addContextMenuAction(mActionSortByState); + mActionFilterConnected = new QAction(tr("Filter only connected"), this); + mActionFilterConnected->setCheckable(true); + connect(mActionFilterConnected, SIGNAL(toggled(bool)), this, SLOT(filterConnected(bool))); + ui->friendList->addContextMenuAction(mActionFilterConnected); /* initialize list */ ui->friendList->setColumnCount(COLUMN_COUNT); ui->friendList->headerItem()->setText(COLUMN_NAME, tr("Name")); + ui->friendList->setFilterReasonRole(ROLE_FILTER_REASON); /* sort list by name ascending */ ui->friendList->sortItems(COLUMN_NAME, Qt::AscendingOrder); @@ -216,8 +222,8 @@ static void initSslItem(QTreeWidgetItem *item, const RsPeerDetails &detail, cons item->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1); item->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0); - item->setData(COLUMN_NAME, ROLE_SORT_STATE, (state != (int) RS_STATUS_OFFLINE) ? 0 : 1); item->setData(COLUMN_NAME, ROLE_SORT_NAME, name); + item->setData(COLUMN_NAME, ROLE_SORT_STATE, state); } void FriendSelectionWidget::fillList() @@ -359,8 +365,8 @@ void FriendSelectionWidget::secured_fillList() groupItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 0); groupItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, (groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? 0 : 1); - groupItem->setData(COLUMN_NAME, ROLE_SORT_STATE, 0); groupItem->setData(COLUMN_NAME, ROLE_SORT_NAME, groupName); + groupItem->setData(COLUMN_NAME, ROLE_SORT_STATE, 0); if (mListModus == MODUS_CHECK) { groupItem->setCheckState(0, Qt::Unchecked); @@ -426,8 +432,8 @@ void FriendSelectionWidget::secured_fillList() gpgItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1); gpgItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0); - gpgItem->setData(COLUMN_NAME, ROLE_SORT_STATE, (state != (int) RS_STATUS_OFFLINE) ? 0 : 1); gpgItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name); + gpgItem->setData(COLUMN_NAME, ROLE_SORT_STATE, state); if (mListModus == MODUS_CHECK) { gpgItem->setCheckState(0, Qt::Unchecked); @@ -561,9 +567,9 @@ void FriendSelectionWidget::secured_fillList() gxsItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1); gxsItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0); + gxsItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name); //TODO: online state for gxs items gxsItem->setData(COLUMN_NAME, ROLE_SORT_STATE, 1); - gxsItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name); if (mListModus == MODUS_CHECK) gxsItem->setCheckState(0, Qt::Unchecked); @@ -615,9 +621,9 @@ void FriendSelectionWidget::secured_fillList() gxsItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1); gxsItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0); + gxsItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name); //TODO: online state for gxs items gxsItem->setData(COLUMN_NAME, ROLE_SORT_STATE, 1); - gxsItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name); if (mListModus == MODUS_CHECK) gxsItem->setCheckState(0, Qt::Unchecked); @@ -650,6 +656,7 @@ void FriendSelectionWidget::secured_fillList() mInFillList = false; ui->friendList->resort(); + filterConnected(isFilterConnected()); emit contentChanged(); } @@ -751,7 +758,7 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status) item->setTextColor(COLUMN_NAME, color); item->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(gpgStatus))); - item->setData(COLUMN_NAME, ROLE_SORT_STATE, (gpgStatus != (int) RS_STATUS_OFFLINE) ? 0 : 1); + item->setData(COLUMN_NAME, ROLE_SORT_STATE, gpgStatus); bFoundGPG = true; } @@ -770,7 +777,7 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status) item->setTextColor(COLUMN_NAME, color); item->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(status))); - item->setData(COLUMN_NAME, ROLE_SORT_STATE, (status != (int) RS_STATUS_OFFLINE) ? 0 : 1); + item->setData(COLUMN_NAME, ROLE_SORT_STATE, status); bFoundSSL = true; } @@ -799,6 +806,7 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status) } ui->friendList->resort(); + filterConnected(isFilterConnected()); } void FriendSelectionWidget::addContextMenuAction(QAction *action) @@ -810,7 +818,7 @@ void FriendSelectionWidget::contextMenuRequested(const QPoint &/*pos*/) { QMenu *contextMenu = new QMenu(this); - if (mListModus == MODUS_CHECK) { + if (mListModus == MODUS_MULTI) { contextMenu->addAction(QIcon(), tr("Mark all"), this, SLOT(selectAll())); contextMenu->addAction(QIcon(), tr("Mark none"), this, SLOT(deselectAll())); } @@ -953,37 +961,9 @@ void FriendSelectionWidget::itemChanged(QTreeWidgetItem *item, int column) void FriendSelectionWidget::filterItems(const QString& text) { - int count = ui->friendList->topLevelItemCount(); - for (int index = 0; index < count; ++index) { - filterItem(ui->friendList->topLevelItem(index), text); - } -} - -bool FriendSelectionWidget::filterItem(QTreeWidgetItem *item, const QString &text) -{ - bool visible = true; - - if (text.isEmpty() == false) { - if (item->text(0).contains(text, Qt::CaseInsensitive) == false) { - visible = false; - } - } - - int visibleChildCount = 0; - int count = item->childCount(); - for (int index = 0; index < count; ++index) { - if (filterItem(item->child(index), text)) { - ++visibleChildCount; - } - } - - if (visible || visibleChildCount) { - item->setHidden(false); - } else { - item->setHidden(true); - } - - return (visible || visibleChildCount); + ui->friendList->filterItems(COLUMN_NAME, text); + ui->friendList->resort(); + filterConnected(isFilterConnected()); } int FriendSelectionWidget::selectedItemCount() @@ -1168,9 +1148,24 @@ void FriendSelectionWidget::sortByState(bool sort) mActionSortByState->setChecked(sort); ui->friendList->resort(); + filterConnected(isFilterConnected()); } bool FriendSelectionWidget::isSortByState() { return mActionSortByState->isChecked(); } + +void FriendSelectionWidget::filterConnected(bool filter) +{ + ui->friendList->filterMinValItems(COLUMN_NAME, filter ? RS_STATUS_AWAY : RS_STATUS_OFFLINE, ROLE_SORT_STATE); + + mActionFilterConnected->setChecked(filter); + + ui->friendList->resort(); +} + +bool FriendSelectionWidget::isFilterConnected() +{ + return mActionFilterConnected->isChecked(); +} diff --git a/retroshare-gui/src/gui/common/FriendSelectionWidget.h b/retroshare-gui/src/gui/common/FriendSelectionWidget.h index c83aa716e..5cb3198f0 100644 --- a/retroshare-gui/src/gui/common/FriendSelectionWidget.h +++ b/retroshare-gui/src/gui/common/FriendSelectionWidget.h @@ -82,6 +82,7 @@ public: void start(); bool isSortByState(); + bool isFilterConnected(); int selectedItemCount(); std::string selectedId(IdType &idType); @@ -130,6 +131,7 @@ signals: public slots: void sortByState(bool sort); + void filterConnected(bool filter); private slots: void groupsChanged(int type); @@ -144,7 +146,6 @@ private slots: private: void fillList(); void secured_fillList(); - bool filterItem(QTreeWidgetItem *item, const QString &text); void selectedIds(IdType idType, std::set &ids, bool onlyDirectSelected); void setSelectedIds(IdType idType, const std::set &ids, bool add); @@ -161,6 +162,7 @@ private: bool mInSslItemChanged; bool mInFillList; QAction *mActionSortByState; + QAction *mActionFilterConnected; /* Color definitions (for standard see qss.default) */ QColor mTextColorOnline; diff --git a/retroshare-gui/src/gui/common/RSTreeWidget.cpp b/retroshare-gui/src/gui/common/RSTreeWidget.cpp index a261bff80..e4bd8be36 100644 --- a/retroshare-gui/src/gui/common/RSTreeWidget.cpp +++ b/retroshare-gui/src/gui/common/RSTreeWidget.cpp @@ -34,6 +34,7 @@ RSTreeWidget::RSTreeWidget(QWidget *parent) : QTreeWidget(parent) { mEnableColumnCustomize = false; mSettingsVersion = 0; // disabled + mFilterReasonRole = -1; // disabled QHeaderView *h = header(); h->setContextMenuPolicy(Qt::CustomContextMenu); @@ -84,6 +85,12 @@ void RSTreeWidget::mousePressEvent(QMouseEvent *event) QTreeWidget::mousePressEvent(event); } +void RSTreeWidget::setFilterReasonRole(int role /*=-1*/) +{ + if (role > Qt::UserRole) + mFilterReasonRole = role; +} + void RSTreeWidget::filterItems(int filterColumn, const QString &text, int role) { int count = topLevelItemCount(); @@ -101,6 +108,13 @@ void RSTreeWidget::filterItems(int filterColumn, const QString &text, int role) bool RSTreeWidget::filterItem(QTreeWidgetItem *item, int filterColumn, const QString &text, int role) { bool itemVisible = true; + //Get who hide this item + int filterReason = 0; + if (mFilterReasonRole >= Qt::UserRole) + filterReason = item->data(filterColumn, mFilterReasonRole).toInt(); + //Remove this filter for last test + if (filterReason & FILTER_REASON_TEXT) + filterReason -= FILTER_REASON_TEXT; if (!text.isEmpty()) { if (!item->data(filterColumn, role).toString().contains(text, Qt::CaseInsensitive)) { @@ -116,11 +130,62 @@ bool RSTreeWidget::filterItem(QTreeWidgetItem *item, int filterColumn, const QSt } } - if (itemVisible || visibleChildCount) { - item->setHidden(false); - } else { - item->setHidden(true); + if (!itemVisible && !visibleChildCount) { + filterReason |= FILTER_REASON_TEXT; } + item->setHidden(filterReason != 0); + //Update hiding reason + if (mFilterReasonRole >= Qt::UserRole) + item->setData(filterColumn, mFilterReasonRole, filterReason); + + return (itemVisible || visibleChildCount); +} + +void RSTreeWidget::filterMinValItems(int filterColumn, const double &value, int role) +{ + int count = topLevelItemCount(); + for (int index = 0; index < count; ++index) { + filterMinValItem(topLevelItem(index), filterColumn, value, role); + } + + QTreeWidgetItem *item = currentItem(); + if (item && item->isHidden()) { + // active item is hidden, deselect it + setCurrentItem(NULL); + } +} + +bool RSTreeWidget::filterMinValItem(QTreeWidgetItem *item, int filterColumn, const double &value, int role) +{ + bool itemVisible = true; + //Get who hide this item + int filterReason = 0; + if (mFilterReasonRole >= Qt::UserRole) + filterReason = item->data(filterColumn, mFilterReasonRole).toInt(); + //Remove this filter for last test + if (filterReason & FILTER_REASON_MINVAL) + filterReason -= FILTER_REASON_MINVAL; + + bool ok = false; + if ((item->data(filterColumn, role).toDouble(&ok) < value) && ok ) { + itemVisible = false; + } + + int visibleChildCount = 0; + int count = item->childCount(); + for (int index = 0; index < count; ++index) { + if (filterMinValItem(item->child(index), filterColumn, value, role)) { + ++visibleChildCount; + } + } + + if (!itemVisible && !visibleChildCount) { + filterReason |= FILTER_REASON_MINVAL; + } + item->setHidden(filterReason != 0); + //Update hiding reason + if (mFilterReasonRole >= Qt::UserRole) + item->setData(filterColumn, mFilterReasonRole, filterReason); return (itemVisible || visibleChildCount); } @@ -294,6 +359,6 @@ void RSTreeWidget::columnVisible() void RSTreeWidget::resort() { if (isSortingEnabled()) { - sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); + sortItems(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); } } diff --git a/retroshare-gui/src/gui/common/RSTreeWidget.h b/retroshare-gui/src/gui/common/RSTreeWidget.h index cffa9975f..2d42088b9 100644 --- a/retroshare-gui/src/gui/common/RSTreeWidget.h +++ b/retroshare-gui/src/gui/common/RSTreeWidget.h @@ -24,6 +24,9 @@ #include +#define FILTER_REASON_TEXT 0x0001 +#define FILTER_REASON_MINVAL 0x0002 + /* Subclassing QTreeWidget */ class RSTreeWidget : public QTreeWidget { @@ -35,7 +38,9 @@ public: QString placeholderText() { return mPlaceholderText; } void setPlaceholderText(const QString &text); + void setFilterReasonRole(int role = -1); void filterItems(int filterColumn, const QString &text, int role = Qt::DisplayRole); + void filterMinValItems(int filterColumn, const double &value, int role = Qt::DisplayRole); void setSettingsVersion(qint32 version); void processSettings(bool load); @@ -58,6 +63,7 @@ signals: private: bool filterItem(QTreeWidgetItem *item, int filterColumn, const QString &text, int role); + bool filterMinValItem(QTreeWidgetItem *item, int filterColumn, const double &value, int role); private slots: void headerContextMenuRequested(const QPoint &pos); @@ -74,6 +80,7 @@ private: QMap mColumnCustomizable; QList mContextMenuActions; QList mContextMenuMenus; + int mFilterReasonRole; }; #endif From faf45174c708f1e22179d37ea80bb75456769431 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 8 Feb 2018 15:26:21 +0100 Subject: [PATCH 39/42] proper error handlign when Tor is not available --- retroshare-gui/src/TorControl/TorControlWindow.cpp | 12 +++++++++++- retroshare-gui/src/TorControl/TorControlWindow.h | 3 ++- retroshare-gui/src/main.cpp | 9 ++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/TorControl/TorControlWindow.cpp b/retroshare-gui/src/TorControl/TorControlWindow.cpp index 368537a95..6da6b8d7a 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.cpp +++ b/retroshare-gui/src/TorControl/TorControlWindow.cpp @@ -24,6 +24,7 @@ TorControlDialog::TorControlDialog(Tor::TorManager *tm,QWidget *parent) QObject::connect(tm->control(),SIGNAL(disconnected()),this,SLOT(statusChanged())); QObject::connect(tm->control(),SIGNAL(bootstrapStatusChanged()),this,SLOT(statusChanged())); QObject::connect(tm->control(),SIGNAL(connectivityChanged()),this,SLOT(statusChanged())); + QObject::connect(tm ,SIGNAL(errorChanged()),this,SLOT(statusChanged())); //QTimer::singleShot(2000,this,SLOT(checkForHiddenService())) ; @@ -58,6 +59,9 @@ void TorControlDialog::statusChanged() QString tor_control_status_str,torstatus_str ; + if(mTorManager->hasError()) + mErrorMsg = mTorManager->errorMessage() ; + switch(tor_control_status) { default: @@ -149,8 +153,14 @@ void TorControlDialog::showLog() std::cerr << "Connexion Proxy: " << mTorManager->control()->socksAddress().toString().toStdString() << ":" << mTorManager->control()->socksPort() << std::endl; } -TorControlDialog::TorStatus TorControlDialog::checkForTor() +TorControlDialog::TorStatus TorControlDialog::checkForTor(QString& error_msg) { + if(!mErrorMsg.isNull()) + { + error_msg = mErrorMsg ; + return TorControlDialog::TOR_STATUS_FAIL ; + } + switch(mTorManager->control()->torStatus()) { case Tor::TorControl::TorReady: rstime::rs_usleep(1*1000*1000);return TOR_STATUS_OK ; diff --git a/retroshare-gui/src/TorControl/TorControlWindow.h b/retroshare-gui/src/TorControl/TorControlWindow.h index c7b6c024f..c4e8ce522 100644 --- a/retroshare-gui/src/TorControl/TorControlWindow.h +++ b/retroshare-gui/src/TorControl/TorControlWindow.h @@ -29,7 +29,7 @@ public: // Should be called multiple times in a loop until it returns something else than *_UNKNOWN - TorStatus checkForTor() ; + TorStatus checkForTor(QString& error_msg) ; HiddenServiceStatus checkForHiddenService() ; protected slots: @@ -38,6 +38,7 @@ protected slots: void onIncomingConnection(); private: + QString mErrorMsg ; HiddenServiceStatus mHiddenServiceStatus ; Tor::TorManager *mTorManager ; diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index f64adb8ed..54979f983 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -367,12 +367,19 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); { TorControlDialog tcd(torManager) ; + QString error_msg ; tcd.show(); - while(tcd.checkForTor() != TorControlDialog::TOR_STATUS_OK || tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) // runs until some status is reached: either tor works, or it fails. + while(tcd.checkForTor(error_msg) != TorControlDialog::TOR_STATUS_OK || tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) // runs until some status is reached: either tor works, or it fails. { QCoreApplication::processEvents(); rstime::rs_usleep(0.2*1000*1000) ; + + if(!error_msg.isNull()) + { + QMessageBox::critical(NULL,QObject::tr("Cannot start Tor"),QObject::tr("Sorry but Tor cannot be started on your system!\n\nThe error reported is:\"")+error_msg+"\"") ; + return 1; + } } tcd.hide(); From 4beadfe47ac2cdd63a066b8336876f76e2f5c5a0 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 10 Feb 2018 14:28:15 +0100 Subject: [PATCH 40/42] updated changelog --- build_scripts/Debian+Ubuntu/changelog | 101 ++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/build_scripts/Debian+Ubuntu/changelog b/build_scripts/Debian+Ubuntu/changelog index 1d20e719e..c92f9b330 100644 --- a/build_scripts/Debian+Ubuntu/changelog +++ b/build_scripts/Debian+Ubuntu/changelog @@ -1,5 +1,106 @@ retroshare (0.6.3-1.XXXXXX~YYYYYY) YYYYYY; urgency=low + 9352a7c csoler Thu, 8 Feb 2018 10:34:46 +0100 Merge pull request #1168 from PhenomRetroShare/Add_ConnFilterInFriendSel + bf8bd4b Phenom Wed, 7 Feb 2018 19:00:08 +0100 Add Only Connected in FriendSelectionWidget. + 7bb8eb0 csoler Wed, 7 Feb 2018 16:06:54 +0100 Merge pull request #1166 from PhenomRetroShare/Add_ChatRoomRSLink + 02b61b2 csoler Wed, 7 Feb 2018 15:58:12 +0100 Merge pull request #1164 from aral/patch-1 + a496e6f Phenom Sun, 4 Feb 2018 17:51:26 +0100 Add Chat Room RSLink + ed88b34 Aral B Sun, 4 Feb 2018 10:37:45 +0100 Fix typo in Mac install guide + b662e66 Gioacc Fri, 2 Feb 2018 00:20:14 +0100 Qml app fix disappearing sidebar buttons + 6c85075 csoler Thu, 1 Feb 2018 21:35:54 +0100 lobby->room in Identities dialog + 36e20db Gioacc Thu, 1 Feb 2018 21:26:36 +0100 Fix some glitches in qml app menu + 6e093c7 Gioacc Thu, 1 Feb 2018 14:59:08 +0100 Qml token manager removed unuseful debug message + 2d00532 Gioacc Thu, 1 Feb 2018 14:42:46 +0100 Qml app fix sidebar buttons hiding behaviour + 1c698bf Gioacc Thu, 1 Feb 2018 14:31:07 +0100 Qml App add option to control DHT behaviour + 9a9fcca Gioacc Thu, 1 Feb 2018 14:22:33 +0100 Qml App token manager offer unregister token API + 1e3d2c2 csoler Tue, 30 Jan 2018 20:55:01 +0100 Merge pull request #1160 from G10h4ck/android_service_cleaning + 6f91b93 Gioacc Tue, 30 Jan 2018 20:07:51 +0100 Add some sanity check in libresapiclient + 4d60850 Gioacc Tue, 30 Jan 2018 18:25:04 +0100 More cleanup of .pro files + 0012586 Gioacc Tue, 30 Jan 2018 18:24:03 +0100 Add support for SQLCipher on Android + ebfe50f Gioacc Tue, 30 Jan 2018 18:11:31 +0100 Make .pro files compiler agnostic on Android + da2fc01 Gioacc Tue, 30 Jan 2018 18:04:24 +0100 Cleanup a bit libresapi.pro + 180a5b1 Gioacc Tue, 30 Jan 2018 18:02:55 +0100 Remove unnecessary dependencies in android-notify-service + feae9f5 Gioacc Tue, 30 Jan 2018 00:36:19 +0100 Fix some compiler warnings + fc5ed14 Gioacc Mon, 29 Jan 2018 22:44:04 +0100 Android toolchain builder libraries update + fa71ed2 Gioacc Mon, 29 Jan 2018 13:26:43 +0100 Install bdboot.txt in Android + 2d8493f Gioacc Mon, 29 Jan 2018 10:56:12 +0100 Add link on how help confused gdb to give stacktrace + efe78f5 csoler Sun, 28 Jan 2018 21:54:56 +0100 slight optimization to showEvent() and save/restore visible items in file lists + d598a01 Gioacc Sun, 28 Jan 2018 11:38:14 +0100 ApiLocalListener do some sanity check on listen + 5a63ce8 Gioacc Sun, 28 Jan 2018 11:36:51 +0100 Android service avoid shouldexit timer using all CPU available + 3e5ed6a Gioacc Fri, 26 Jan 2018 00:18:31 +0100 Update Androig gdb debug instructions + c39b3e5 Gioacc Thu, 25 Jan 2018 16:20:25 +0100 Better debug messages for Android app + ac9a843 Gioacc Thu, 25 Jan 2018 15:50:12 +0100 Gracefully handle signals in retroshare-android-service + 8c21bfc Gioacc Thu, 25 Jan 2018 15:18:12 +0100 Avoid crash on stop in ApiServerLocal + c1d8d6a Gioacc Thu, 25 Jan 2018 15:14:09 +0100 Properly run Qt event loop + d80a806 csoler Thu, 25 Jan 2018 09:37:31 +0100 Merge pull request #1159 from csoler/v0.6-FileLists + 11eef05 csoler Wed, 24 Jan 2018 22:02:49 +0100 fixed bug causing hidden/expanded items to be reset by show() event in SharedFilesDialog + 1fbd9d1 csoler Wed, 24 Jan 2018 21:26:35 +0100 fixed hiding of top level items when searching + f139685 csoler Wed, 24 Jan 2018 21:14:26 +0100 added a fair limit to search in FL in order to avoid crazy costs + d93e259 csoler Wed, 24 Jan 2018 00:26:22 +0100 fixed expanding/collapsing of items on search + 1ee353c csoler Tue, 23 Jan 2018 22:18:35 +0100 improved efficiency of search in tree visualization mode. Re-enabled the search for testing purpose. + 725abad csoler Tue, 23 Jan 2018 22:18:02 +0100 fixed a bug in filterItems that caused searched files to generate an error in the console + 9b286c4 Gioacc Tue, 23 Jan 2018 11:13:03 +0100 add to README that DHT is not working on android + 000bbbd Gioacc Tue, 23 Jan 2018 10:33:00 +0100 Add link to Android debugging documentation + 7afa19e csoler Sun, 21 Jan 2018 22:23:08 +0100 removed search from tree view in file lists, until I find some way to do it more efficiently + 7448ff4 csoler Sun, 21 Jan 2018 19:07:37 +0100 re-enabled search in file lists tree view + d21a5e5 csoler Sat, 20 Jan 2018 19:25:52 +0100 Merge pull request #1157 from PhenomRetroShare/Fix_IconCacheInFilesDefs + f74ee5c Phenom Sat, 20 Jan 2018 17:21:37 +0100 Move File Icon Cache in FilesDefs + 7652821 Phenom Sat, 20 Jan 2018 17:18:50 +0100 Revert "patch from sss to cache TransfersDialog QIcons" + 4c626e0 csoler Mon, 15 Jan 2018 23:17:09 +0100 Merge pull request #1152 from csoler/v0.6-SecurityFixes + 841fee6 csoler Mon, 15 Jan 2018 23:13:42 +0100 fixed possible crash due to accessing deleted memory in database cache access + 7cac367 csoler Sun, 14 Jan 2018 22:39:50 +0100 removed warnign about bad service string when the service string is actually empty + 388b2c2 csoler Fri, 12 Jan 2018 22:47:42 +0100 patch from sss to cache TransfersDialog QIcons + 783e918 csoler Fri, 12 Jan 2018 22:19:52 +0100 Merge pull request #1151 from csoler/v0.6-SecurityFixes + bbd8afe csoler Thu, 11 Jan 2018 18:14:20 +0100 Merge pull request #1150 from chelovechishko/unfocus_chat_text_edit + 173336e csoler Thu, 11 Jan 2018 18:12:22 +0100 Merge pull request #1148 from chelovechishko/qdarkstyle_fix + b4ff14c csoler Thu, 11 Jan 2018 18:06:48 +0100 Merge pull request #1144 from PhenomRetroShare/Fix_DisableYesButtonOnInvite + bb9dcbb Phenom Fri, 5 Jan 2018 14:45:29 +0100 Disable Yes button on chat room invitation if no Id selected. + add9c1e chelov Wed, 10 Jan 2018 20:53:43 +0900 chatwidget: do not set focus to edit when it is not necessary + 4eea5a8 csoler Wed, 10 Jan 2018 00:10:08 +0100 removed consts in GrpMetaCache pointers, and made it possible to always re=use cache entries, possibly updating them + 553ab93 csoler Tue, 9 Jan 2018 22:18:01 +0100 Merge pull request #1149 from csoler/v0.6-SecurityFixes + 506190a csoler Tue, 9 Jan 2018 22:11:11 +0100 fixed bug causing failure of flag actions on groups + ed81b4c csoler Tue, 9 Jan 2018 21:49:15 +0100 removed delete causing read of deleted memory + 51c7942 csoler Mon, 8 Jan 2018 19:08:10 +0100 Merge pull request #1146 from csoler/v0.6-SecurityFixes + e261d45 chelov Mon, 8 Jan 2018 16:16:10 +0900 gui: fix networkdialog colors once more in qdarkstyle.qss + f8f61cc chelov Mon, 8 Jan 2018 16:02:40 +0900 gui: fix colors for idtree of people in qdarkstyle.qss + 884bbb4 chelov Mon, 8 Jan 2018 15:58:04 +0900 gui: make friendlist more readable in some places in qdarkstyle.qss + 622316a chelov Mon, 8 Jan 2018 15:49:05 +0900 gui: improve readability of sharemanager for qdarkstyle.qss + 5e57cb4 csoler Sun, 7 Jan 2018 23:02:22 +0100 fixed gxs unit tests + 85b94d7 csoler Sun, 7 Jan 2018 22:36:49 +0100 fixed test compilation + 89c538d csoler Sun, 7 Jan 2018 22:36:38 +0100 fixed double deletion problem causing crashes + b42b8e3 csoler Sun, 7 Jan 2018 21:41:41 +0100 moved memory ownership of RsGxsGrpMetaData down into RsGxsDataAccess. Avoids many copy-constructors of RsTlvSecurityKey. Will probably spare a lot of CPU on windows + c3e300e Gioacc Sat, 6 Jan 2018 22:53:26 +0100 Merge pull request #1140 from Emotyco/libresapi_small_corrections + 67fc6a3 Konrad Sat, 6 Jan 2018 19:29:56 +0100 Fixed in Libresapi: Double declaration of StateToken in FileSharingHandler + 575a416 Konrad Sat, 6 Jan 2018 19:09:44 +0100 Changed in Libresapi: Used Doxigen style comments + d53993c Konrad Sat, 6 Jan 2018 18:39:47 +0100 Changed in Libresapi: Pointer to RsNotify object into reference + 57f41d9 csoler Fri, 5 Jan 2018 21:27:18 +0100 Merge pull request #1145 from PhenomRetroShare/Fix_ClearPersonDetailIfNoSelection + 4026040 Konrad Fri, 5 Jan 2018 20:44:48 +0100 Libresapi: Extended ChatInfo class to contain own identity used in chat + 4f902bb Phenom Fri, 5 Jan 2018 17:48:18 +0100 Clear Person Detail when no selection + 0078b9c csoler Wed, 3 Jan 2018 20:33:25 +0100 Merge pull request #1143 from csoler/v0.6-SecurityFixes + 98d1d08 csoler Wed, 3 Jan 2018 20:32:37 +0100 removed extra links from chat widget, since normal links can be used now to DL through encrypted tunnels + ee81eef csoler Wed, 3 Jan 2018 18:42:04 +0100 Merge pull request #1142 from csoler/v0.6-SecurityFixes + ab60f49 csoler Wed, 3 Jan 2018 18:37:43 +0100 prevent sending/receiving of IP addresses to/at hidden nodes + 0a92710 csoler Wed, 3 Jan 2018 15:03:23 +0100 Merge pull request #1141 from csoler/v0.6-SecurityFixes + 0f6006d csoler Wed, 3 Jan 2018 15:01:04 +0100 prevent subscribing to a signed chat room without a signed identity + eea0c64 csoler Wed, 3 Jan 2018 14:05:13 +0100 require signed identity to respond to a signed chat room invite. Avoids "god mode" bug. + 96e7507 Konrad Mon, 1 Jan 2018 23:38:07 +0100 Added in Libresapi: Short comment to FileSharingHandler + 9bb6adc Konrad Mon, 1 Jan 2018 23:27:46 +0100 Added in Libresapi: Missing mutex locking in TransfersHandler + 6a61e0a Konrad Mon, 1 Jan 2018 23:20:26 +0100 Changed in Libresapi: Locking mutex using macro instead of RsStackMutex object creation + 74a56f6 Konrad Fri, 29 Dec 2017 16:07:39 +0100 Changed in Libresapi: Closing distant connection (chat) requires now ChatId that is used in other functions, instead of DistantCharPeerId + 4b25684 Konrad Fri, 29 Dec 2017 16:03:45 +0100 Added in Libresapi: Functions to get and set default identity for lobby + b24d772 Konrad Wed, 27 Dec 2017 22:38:04 +0100 Added in Libresapi: Getting node name in PeersHandler + 2db25d4 Konrad Wed, 27 Dec 2017 22:37:14 +0100 Added in Libresapi: StateToken refreshing to TransferHandler + 53118e5 Konrad Wed, 27 Dec 2017 22:35:51 +0100 Added in Libresapi: Missing bracket in ChatHandler + 92df847 Konrad Wed, 27 Dec 2017 22:33:23 +0100 Added in Libresapi: StateTokens to FileSharingHandler + 55385d7 Konrad Wed, 27 Dec 2017 22:31:17 +0100 Added in Libresapi: Marking particular message as read + 49cacc4 csoler Sun, 24 Dec 2017 12:04:15 +0100 fixed compilation on ubuntu precise + 122f6af csoler Sun, 24 Dec 2017 11:06:03 +0100 fixed compilation on ubuntu precise + 72d64c7 csoler Sun, 24 Dec 2017 10:36:08 +0100 updated changelog + + -- Retroshare Dev Team Sat, 10 Feb 2018 14:00:00 +0100 + +retroshare (0.6.3-1.20171224.72d64c7d~artful) precise; urgency=low + c2d5579 csoler Thu, 21 Dec 2017 17:06:32 +0100 storage of chat room icons in local variables to avoid re-reading them from qrc everytime (patch from sss) acd8355 Gioacc Wed, 20 Dec 2017 18:24:28 +0100 Add some documentation on how to debug retroshare on android c0d8333 csoler Mon, 18 Dec 2017 16:10:52 +0100 Merge pull request #1136 from csoler/v0.6-FT From 5f106c4769d87883c6742c992df0ef282f4f82a4 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 10 Feb 2018 15:42:24 +0100 Subject: [PATCH 41/42] fixed compilation on ubuntu precise --- retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.h b/retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.h index e67eeeee8..e442bded9 100644 --- a/retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.h +++ b/retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.h @@ -1,6 +1,8 @@ #ifndef PGPID_ITEM_PROXY_H #define PGPID_ITEM_PROXY_H +#include "util/cxx11retrocompat.h" + #include class pgpid_item_proxy : From a2eb14545949a8858c0dd3dd85d824cb2e4c221c Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 11 Feb 2018 20:40:38 +0100 Subject: [PATCH 42/42] fixed option in .pri for retrotor configuration --- retroshare.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare.pri b/retroshare.pri index 4f94b4c21..8427243b0 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -237,7 +237,7 @@ rs_autologin { } retrotor { - DEFINES *= RS_ONLYHIDDENNODE + CONFIG *= rs_onlyhiddennode } rs_onlyhiddennode {