mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-12-14 08:08:53 -05:00
362 lines
14 KiB
C++
362 lines
14 KiB
C++
/*******************************************************************************
|
|
* gui/FriendServer.cpp *
|
|
* *
|
|
* Copyright (c) 2021 Retroshare Team <retroshare.project@gmail.com> *
|
|
* *
|
|
* This program is free software: you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Affero General Public License as *
|
|
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Affero General Public License *
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
|
* *
|
|
*******************************************************************************/
|
|
|
|
#include <QTimer>
|
|
#include <QMovie>
|
|
#include <QMessageBox>
|
|
#include <QTcpSocket>
|
|
#include <QMenu>
|
|
|
|
#include "retroshare/rsfriendserver.h"
|
|
#include "retroshare/rstor.h"
|
|
|
|
#include "util/qtthreadsutils.h"
|
|
#include "util/misc.h"
|
|
#include "gui/common/FilesDefs.h"
|
|
|
|
#include "FriendServerControl.h"
|
|
|
|
#include <iostream>
|
|
|
|
#define ICON_STATUS_UNKNOWN ":/images/ledoff1.png"
|
|
#define ICON_STATUS_OK ":/images/ledon1.png"
|
|
|
|
#define NAME_COLUMN 0
|
|
#define NODE_COLUMN 1
|
|
#define ADDR_COLUMN 2
|
|
#define STAT_COLUMN 3
|
|
|
|
/** Constructor */
|
|
FriendServerControl::FriendServerControl(QWidget *parent)
|
|
: MainPage(parent)
|
|
{
|
|
/* Invoke the Qt Designer generated object setup routine */
|
|
setupUi(this);
|
|
|
|
friendServerOnOff_CB->setEnabled(false); // until FS is connected.
|
|
mCurrentlyCheckingServerAddress = false;
|
|
|
|
if(!rsFriendServer)
|
|
{
|
|
setEnabled(false);
|
|
return;
|
|
}
|
|
|
|
int H = QFontMetricsF(torServerAddress_LE->font()).height();
|
|
|
|
QString help_str = tr("\
|
|
<h1><img width=\"%1\" src=\":/icons/help_64.png\"> Friend Server</h1> \
|
|
<p>This configuration panel allows you to specify the onion address of a \
|
|
friend server. Retroshare will talk to that server anonymously through Tor \
|
|
and use it to acquire a fixed number of friends.</p> \
|
|
<p>The friend server will continue supplying new friends until that number is reached \
|
|
in particular if you add your own friends manually, the friend server may become useless \
|
|
and you will save bandwidth disabling it. When disabling it, you will keep existing friends.</p> \
|
|
<p>The friend server only knows your peer ID and profile public key. It doesn't know your IP address.</p> \
|
|
"
|
|
).arg(QString::number(2*H), QString::number(2*H)) ;
|
|
|
|
registerHelpButton(helpButton,help_str,"Friend Server") ;
|
|
|
|
mConnectionCheckTimer = new QTimer;
|
|
|
|
whileBlocking(autoAccept_CB)->setChecked(rsFriendServer->autoAddFriends());
|
|
|
|
// Init values
|
|
|
|
whileBlocking(torServerFriendsToRequest_SB)->setValue(rsFriendServer->friendsToRequest());
|
|
|
|
// Connect slignals/slots
|
|
|
|
QObject::connect(friendServerOnOff_CB,SIGNAL(toggled(bool)),this,SLOT(onOnOffClick(bool)));
|
|
QObject::connect(torServerFriendsToRequest_SB,SIGNAL(valueChanged(int)),this,SLOT(onFriendsToRequestChanged(int)));
|
|
QObject::connect(torServerAddress_LE,SIGNAL(textEdited(const QString&)),this,SLOT(onOnionAddressEdit(const QString&)));
|
|
QObject::connect(torServerPort_SB,SIGNAL(valueChanged(int)),this,SLOT(onOnionPortEdit(int)));
|
|
QObject::connect(autoAccept_CB,SIGNAL(toggled(bool)),this,SLOT(onAutoAddFriends(bool)));
|
|
|
|
QObject::connect(mConnectionCheckTimer,SIGNAL(timeout()),this,SLOT(checkServerAddress()));
|
|
QObject::connect(status_TW, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(launchStatusContextMenu(QPoint)));
|
|
|
|
mCheckingServerMovie = new QMovie(":/images/loader/circleball-16.gif");
|
|
|
|
// Do not block signal for these two, since we want to trigger a test to initialise the online status.
|
|
torServerAddress_LE->setText(QString::fromStdString(rsFriendServer->friendsServerAddress().c_str()));
|
|
torServerPort_SB->setValue(rsFriendServer->friendsServerPort());
|
|
|
|
updateFriendServerStatusIcon(false);
|
|
|
|
makeFriend_ACT = new QAction(tr("Make friend")); // makes SSL-only friend with the peer
|
|
|
|
QObject::connect(makeFriend_ACT,SIGNAL(triggered()),this,SLOT(makeFriend()));
|
|
|
|
mEventHandlerId_fs = 0;
|
|
|
|
rsEvents->registerEventsHandler( [this](std::shared_ptr<const RsEvent> event)
|
|
{
|
|
RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this );
|
|
}, mEventHandlerId_fs, RsEventType::FRIEND_SERVER );
|
|
|
|
mEventHandlerId_peer = 0;
|
|
|
|
rsEvents->registerEventsHandler( [this](std::shared_ptr<const RsEvent> event)
|
|
{
|
|
RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this );
|
|
}, mEventHandlerId_peer, RsEventType::PEER_CONNECTION );
|
|
}
|
|
|
|
void FriendServerControl::onAutoAddFriends(bool b)
|
|
{
|
|
rsFriendServer->setAutoAddFriends(b);
|
|
}
|
|
void FriendServerControl::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)
|
|
{
|
|
{
|
|
const RsFriendServerEvent *fe = dynamic_cast<const RsFriendServerEvent*>(event.get());
|
|
|
|
if(fe)
|
|
switch(fe->mFriendServerEventType)
|
|
{
|
|
case RsFriendServerEventCode::PEER_INFO_CHANGED: updateContactsStatus();
|
|
break;
|
|
|
|
case RsFriendServerEventCode::FRIEND_SERVER_STATUS_CHANGED: updateFriendServerStatusIcon(fe->mFriendServerStatus == RsFriendServerStatus::ONLINE);
|
|
break;
|
|
|
|
default:
|
|
case RsFriendServerEventCode::UNKNOWN: break;
|
|
}
|
|
}
|
|
|
|
{
|
|
const RsConnectionEvent *pe = dynamic_cast<const RsConnectionEvent*>(event.get());
|
|
|
|
if(pe)
|
|
switch(pe->mConnectionInfoCode)
|
|
{
|
|
case RsConnectionEventCode::PEER_ADDED:
|
|
case RsConnectionEventCode::PEER_REMOVED:
|
|
case RsConnectionEventCode::PEER_CONNECTED: updateContactsStatus();
|
|
break;
|
|
|
|
default: ;
|
|
}
|
|
}
|
|
}
|
|
|
|
FriendServerControl::~FriendServerControl()
|
|
{
|
|
delete mCheckingServerMovie;
|
|
delete mConnectionCheckTimer;
|
|
|
|
rsEvents->unregisterEventsHandler(mEventHandlerId_fs);
|
|
rsEvents->unregisterEventsHandler(mEventHandlerId_peer);
|
|
}
|
|
|
|
void FriendServerControl::launchStatusContextMenu(QPoint p)
|
|
{
|
|
RsPeerId peer_id = getCurrentPeer();
|
|
|
|
RsPeerDetails det;
|
|
if(rsPeers->getPeerDetails(peer_id,det) && det.accept_connection)
|
|
return;
|
|
|
|
QMenu contextMnu(this);
|
|
contextMnu.addAction(makeFriend_ACT);
|
|
|
|
contextMnu.exec(QCursor::pos());
|
|
}
|
|
void FriendServerControl::onOnOffClick(bool b)
|
|
{
|
|
if(b)
|
|
{
|
|
if(passphrase_LE->text().isNull())
|
|
{
|
|
QMessageBox::critical(nullptr,tr("Missing profile passphrase."),tr("Your profile passphrase is missing. Please enter is in the field below before enabling the friend server."));
|
|
whileBlocking(friendServerOnOff_CB)->setCheckState(Qt::Unchecked);
|
|
return;
|
|
}
|
|
rsFriendServer->setProfilePassphrase(passphrase_LE->text().toStdString());
|
|
rsFriendServer->startServer();
|
|
}
|
|
else
|
|
rsFriendServer->stopServer();
|
|
}
|
|
void FriendServerControl::onOnionPortEdit(int)
|
|
{
|
|
// Setup timer to auto-check the friend server address
|
|
|
|
mConnectionCheckTimer->stop();
|
|
mConnectionCheckTimer->setSingleShot(true);
|
|
mConnectionCheckTimer->setInterval(5000); // check in 5 secs unless something is changed in the mean time.
|
|
|
|
mConnectionCheckTimer->start();
|
|
|
|
if(mCheckingServerMovie->fileName() != QString(":/images/loader/circleball-16.gif" ))
|
|
{
|
|
mCheckingServerMovie->setFileName(":/images/loader/circleball-16.gif");
|
|
mCheckingServerMovie->start();
|
|
}
|
|
}
|
|
|
|
void FriendServerControl::onOnionAddressEdit(const QString&)
|
|
{
|
|
while(mCurrentlyCheckingServerAddress)
|
|
{
|
|
std::cerr << " waiting for free slot" << std::endl;
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500)); // wait for ongoing check to finish.
|
|
}
|
|
|
|
std::cerr << "Resetting connection proxy timer" << std::endl;
|
|
|
|
// Setup timer to auto-check the friend server address
|
|
mConnectionCheckTimer->setSingleShot(true);
|
|
mConnectionCheckTimer->setInterval(5000); // check in 5 secs unless something is changed in the mean time.
|
|
mConnectionCheckTimer->start();
|
|
}
|
|
|
|
void FriendServerControl::checkServerAddress()
|
|
{
|
|
std::cerr << "In checkServerAddress() ..." << std::endl;
|
|
|
|
mCurrentlyCheckingServerAddress = true;
|
|
|
|
serverStatusCheckResult_LB->setMovie(mCheckingServerMovie);
|
|
serverStatusCheckResult_LB->setToolTip(tr("Trying to contact friend server\nThis may take up to 1 min.")) ;
|
|
mCheckingServerMovie->setFileName(":/images/loader/circleball-16.gif");
|
|
mCheckingServerMovie->start();
|
|
|
|
RsThread::async( [this]()
|
|
{
|
|
auto port = torServerPort_SB->value();
|
|
auto addr = torServerAddress_LE->text().toStdString();
|
|
|
|
std::cerr << "calling sync test..." << std::endl;
|
|
bool succeed = rsFriendServer->checkServerAddress(addr,port,5000);
|
|
std::cerr << "result is " << succeed << std::endl;
|
|
|
|
RsQThreadUtils::postToObject( [addr,port,succeed,this]()
|
|
{
|
|
if(succeed)
|
|
rsFriendServer->setServerAddress(addr,port);
|
|
|
|
mCheckingServerMovie->stop();
|
|
updateFriendServerStatusIcon(succeed);
|
|
mCurrentlyCheckingServerAddress = false;
|
|
|
|
},this);
|
|
});
|
|
}
|
|
|
|
void FriendServerControl::onNbFriendsToRequestsChanged(int n)
|
|
{
|
|
rsFriendServer->setFriendsToRequest(n);
|
|
}
|
|
|
|
void FriendServerControl::updateFriendServerStatusIcon(bool ok)
|
|
{
|
|
std::cerr << "updating proxy status icon" << std::endl;
|
|
|
|
if(ok)
|
|
{
|
|
serverStatusCheckResult_LB->setToolTip(tr("Friend server is currently reachable.")) ;
|
|
serverStatusCheckResult_LB->setPixmap(QPixmap(ICON_STATUS_OK));
|
|
friendServerOnOff_CB->setEnabled(true);
|
|
status_TW->setEnabled(true);
|
|
}
|
|
else
|
|
{
|
|
rsFriendServer->stopServer();
|
|
serverStatusCheckResult_LB->setToolTip(tr("The proxy is not enabled or broken.\nAre all services up and running fine??\nAlso check your ports!")) ;
|
|
serverStatusCheckResult_LB->setPixmap(QPixmap(ICON_STATUS_UNKNOWN));
|
|
friendServerOnOff_CB->setChecked(false);
|
|
friendServerOnOff_CB->setEnabled(false);
|
|
status_TW->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
void FriendServerControl::updateContactsStatus()
|
|
{
|
|
std::map<RsPeerId,RsFriendServer::RsFsPeerInfo> pinfo = rsFriendServer->getPeersInfo();
|
|
|
|
status_TW->clear();
|
|
int row = 0;
|
|
status_TW->setRowCount(pinfo.size());
|
|
status_TW->setColumnCount(4);
|
|
|
|
status_TW->setHorizontalHeaderItem(NAME_COLUMN,new QTableWidgetItem(QObject::tr("Name")));
|
|
status_TW->setHorizontalHeaderItem(NODE_COLUMN,new QTableWidgetItem(QObject::tr("Node")));
|
|
status_TW->setHorizontalHeaderItem(ADDR_COLUMN,new QTableWidgetItem(QObject::tr("Address")));
|
|
status_TW->setHorizontalHeaderItem(STAT_COLUMN,new QTableWidgetItem(QObject::tr("Status")));
|
|
|
|
for(auto it:pinfo)
|
|
{
|
|
uint32_t err_code=0;
|
|
RsPeerDetails details;
|
|
|
|
rsPeers->parseShortInvite(it.second.mInvite,details,err_code);
|
|
|
|
status_TW->setItem(row,NAME_COLUMN,new QTableWidgetItem(QString::fromStdString(details.name)));
|
|
status_TW->setItem(row,NODE_COLUMN,new QTableWidgetItem(QString::fromStdString(details.id.toStdString())));
|
|
status_TW->setItem(row,ADDR_COLUMN,new QTableWidgetItem(QString::fromStdString(details.hiddenNodeAddress)+":"+QString::number(details.hiddenNodePort)));
|
|
|
|
QString status_string;
|
|
if(details.accept_connection)
|
|
status_string += QString("Friend");
|
|
else
|
|
status_string += QString("Not friend");
|
|
|
|
status_string += QString(" / ");
|
|
|
|
switch(it.second.mPeerLevel)
|
|
{
|
|
case RsFriendServer::PeerFriendshipLevel::NO_KEY: status_string += "Doesn't have my key" ; break;
|
|
case RsFriendServer::PeerFriendshipLevel::HAS_KEY: status_string += "Has my key" ; break;
|
|
case RsFriendServer::PeerFriendshipLevel::HAS_ACCEPTED_KEY: status_string += "Has friended me" ; break;
|
|
default:
|
|
case RsFriendServer::PeerFriendshipLevel::UNKNOWN: status_string += "Unkn" ; break;
|
|
}
|
|
|
|
status_TW->setItem(row,STAT_COLUMN,new QTableWidgetItem(status_string));
|
|
|
|
row++;
|
|
}
|
|
}
|
|
|
|
RsPeerId FriendServerControl::getCurrentPeer()
|
|
{
|
|
QTableWidgetItem *item = status_TW->currentItem();
|
|
|
|
if(!item)
|
|
return RsPeerId();
|
|
|
|
return RsPeerId(status_TW->item(item->row(),NODE_COLUMN)->text().toStdString());
|
|
}
|
|
void FriendServerControl::makeFriend()
|
|
{
|
|
RsPeerId peer_id = getCurrentPeer();
|
|
|
|
rsFriendServer->allowPeer(peer_id);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|