Merge branch 'master' into cmake_build

This commit is contained in:
G10h4ck 2022-01-10 15:46:57 +01:00 committed by GitHub
commit 6f813efddf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
183 changed files with 8423 additions and 7181 deletions

View File

@ -28,11 +28,7 @@ DESTDIR = lib
!include("use_libbitdht.pri"):error("Including") !include("use_libbitdht.pri"):error("Including")
QMAKE_CXXFLAGS *= -Wall -DBE_DEBUG QMAKE_CXXFLAGS *= -DBE_DEBUG
# treat warnings as error for better removing
#QMAKE_CFLAGS += -Werror
#QMAKE_CXXFLAGS += -Werror
################################# Linux ########################################## ################################# Linux ##########################################
linux-* { linux-* {
@ -84,10 +80,6 @@ win32 {
# These have been replaced by _WIN32 && __MINGW32__ # These have been replaced by _WIN32 && __MINGW32__
#DEFINES *= WINDOWS_SYS WIN32 STATICLIB MINGW #DEFINES *= WINDOWS_SYS WIN32 STATICLIB MINGW
# Switch on extra warnings
QMAKE_CFLAGS += -Wextra
QMAKE_CXXFLAGS += -Wextra
# Switch off optimization for release version # Switch off optimization for release version
QMAKE_CXXFLAGS_RELEASE -= -O2 QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE += -O0 QMAKE_CXXFLAGS_RELEASE += -O0

View File

@ -347,6 +347,7 @@ list(
util/rsurl.cc util/rsurl.cc
util/folderiterator.cc util/folderiterator.cc
util/rsdir.cc util/rsdir.cc
util/rsfile.cc
util/dnsresolver.cc util/dnsresolver.cc
util/extaddrfinder.cc util/extaddrfinder.cc
util/rsdebug.cc util/rsdebug.cc

View File

@ -151,6 +151,10 @@ int p3BitDht::setRelayMode(RsDhtRelayMode mode)
pushRelayServers(); pushRelayServers();
mUdpBitDht->setDhtMode(BITDHT_MODE_RELAYSERVERS_SERVER); mUdpBitDht->setDhtMode(BITDHT_MODE_RELAYSERVERS_SERVER);
break; break;
case RsDhtRelayMode::ENABLED:
case RsDhtRelayMode::DISABLED:
case RsDhtRelayMode::MASK:
break;
} }
{ {

View File

@ -657,7 +657,6 @@ bool ftController::completeFile(const RsFileHash& hash)
uint32_t period = 0; uint32_t period = 0;
TransferRequestFlags flags ; TransferRequestFlags flags ;
TransferRequestFlags extraflags ; TransferRequestFlags extraflags ;
uint32_t completeCount = 0;
{ {
RS_STACK_MUTEX(ctrlMutex); RS_STACK_MUTEX(ctrlMutex);
@ -780,7 +779,6 @@ bool ftController::completeFile(const RsFileHash& hash)
/* switch map */ /* switch map */
mCompleted[fc->mHash] = fc; mCompleted[fc->mHash] = fc;
completeCount = mCompleted.size();
mDownloads.erase(it); mDownloads.erase(it);

View File

@ -2049,6 +2049,10 @@ bool ftServer::receiveSearchRequest(
return RsServiceSerializer::serialise( return RsServiceSerializer::serialise(
&resIt, searchResultData, &searchResultDataLen ); &resIt, searchResultData, &searchResultDataLen );
} }
#else
(void) searchRequestData;
(void) searchRequestDataLen;
(void) maxAllowsHits;
#endif // def RS_DEEP_FILES_INDEX #endif // def RS_DEEP_FILES_INDEX
searchResultData = nullptr; searchResultData = nullptr;

View File

@ -107,7 +107,7 @@ p3discovery2::p3discovery2(
addSerialType(new RsDiscSerialiser()); addSerialType(new RsDiscSerialiser());
// Add self into PGP FriendList. // Add self into PGP FriendList.
mFriendList[AuthGPG::getAuthGPG()->getGPGOwnId()] = DiscPgpInfo(); mFriendList[AuthPGP::getPgpOwnId()] = DiscPgpInfo();
} }
@ -219,7 +219,7 @@ void p3discovery2::removeFriend(const RsPeerId &sslId)
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
/* pgp peer without any ssl entries -> check if they are still a real friend */ /* pgp peer without any ssl entries -> check if they are still a real friend */
if (!(AuthGPG::getAuthGPG()->isGPGAccepted(pgpId))) if (!(AuthPGP::isPGPAccepted(pgpId)))
{ {
#ifdef P3DISC_DEBUG #ifdef P3DISC_DEBUG
std::cerr << "p3discovery2::addFriend() pgpId is no longer a friend, removing"; std::cerr << "p3discovery2::addFriend() pgpId is no longer a friend, removing";
@ -604,8 +604,8 @@ void p3discovery2::updatePgpFriendList()
std::list<RsPgpId>::iterator lit; std::list<RsPgpId>::iterator lit;
std::map<RsPgpId, DiscPgpInfo>::iterator it; std::map<RsPgpId, DiscPgpInfo>::iterator it;
RsPgpId ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId(); RsPgpId ownPgpId = AuthPGP::getPgpOwnId();
AuthGPG::getAuthGPG()->getGPGAcceptedList(pgpList); AuthPGP::getPgpAcceptedList(pgpList);
pgpList.push_back(ownPgpId); pgpList.push_back(ownPgpId);
// convert to set for ordering. // convert to set for ordering.
@ -723,7 +723,7 @@ void p3discovery2::processPGPList(const RsPeerId &fromId, const RsDiscPgpListIte
std::set<RsPgpId>::const_iterator fit; std::set<RsPgpId>::const_iterator fit;
for(fit = item->pgpIdSet.ids.begin(); fit != item->pgpIdSet.ids.end(); ++fit) for(fit = item->pgpIdSet.ids.begin(); fit != item->pgpIdSet.ids.end(); ++fit)
{ {
if (!AuthGPG::getAuthGPG()->isGPGId(*fit)) if (!AuthPGP::isPGPId(*fit))
{ {
#ifdef P3DISC_DEBUG #ifdef P3DISC_DEBUG
std::cerr << "p3discovery2::processPGPList() requesting certificate for PgpId: " << *fit; std::cerr << "p3discovery2::processPGPList() requesting certificate for PgpId: " << *fit;
@ -1058,11 +1058,11 @@ void p3discovery2::recvPGPCertificateRequest( const RsPeerId& fromId, const RsDi
return; return;
} }
RsPgpId ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId(); RsPgpId ownPgpId = AuthPGP::getPgpOwnId();
for(const RsPgpId& pgpId : item->pgpIdSet.ids) for(const RsPgpId& pgpId : item->pgpIdSet.ids)
if (pgpId == ownPgpId) if (pgpId == ownPgpId)
sendPGPCertificate(pgpId, fromId); sendPGPCertificate(pgpId, fromId);
else if(ps.vs_disc != RS_VS_DISC_OFF && AuthGPG::getAuthGPG()->isGPGAccepted(pgpId)) else if(ps.vs_disc != RS_VS_DISC_OFF && AuthPGP::isPGPAccepted(pgpId))
sendPGPCertificate(pgpId, fromId); sendPGPCertificate(pgpId, fromId);
else else
std::cerr << "(WW) not sending certificate " << pgpId << " asked by friend " << fromId << " because this either this cert is not a friend, or discovery is off" << std::endl; std::cerr << "(WW) not sending certificate " << pgpId << " asked by friend " << fromId << " because this either this cert is not a friend, or discovery is off" << std::endl;
@ -1078,7 +1078,7 @@ void p3discovery2::sendPGPCertificate(const RsPgpId &aboutId, const RsPeerId &to
unsigned char *bin_data; unsigned char *bin_data;
size_t bin_len; size_t bin_len;
if(!AuthGPG::getAuthGPG()->exportPublicKey(aboutId,bin_data,bin_len,false,true)) if(!AuthPGP::exportPublicKey(aboutId,bin_data,bin_len,false,true))
{ {
std::cerr << "(EE) cannot export public key " << aboutId << " requested by peer " << toId << std::endl; std::cerr << "(EE) cannot export public key " << aboutId << " requested by peer " << toId << std::endl;
return ; return ;
@ -1098,7 +1098,7 @@ void p3discovery2::recvPGPCertificate(const RsPeerId& fromId, RsDiscPgpKeyItem*
std::string cert_name; std::string cert_name;
std::list<RsPgpId> cert_signers; std::list<RsPgpId> cert_signers;
if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock( (unsigned char*)item->bin_data,item->bin_len, cert_pgp_id, cert_name, cert_signers )) if(!AuthPGP::getPgpDetailsFromBinaryBlock( (unsigned char*)item->bin_data,item->bin_len, cert_pgp_id, cert_name, cert_signers ))
{ {
std::cerr << "(EE) cannot parse own PGP key sent by " << fromId << std::endl; std::cerr << "(EE) cannot parse own PGP key sent by " << fromId << std::endl;
return; return;
@ -1147,7 +1147,7 @@ void p3discovery2::recvPGPCertificate(const RsPeerId& fromId, RsDiscPgpKeyItem*
// otherwise the connection should already be accepted. This only happens when the short invite peer sends its own PGP key. // otherwise the connection should already be accepted. This only happens when the short invite peer sends its own PGP key.
if(det.skip_pgp_signature_validation) if(det.skip_pgp_signature_validation)
AuthGPG::getAuthGPG()->AllowConnection(det.gpg_id,true); AuthPGP::AllowConnection(det.gpg_id,true);
} }
/************* from pqiServiceMonitor *******************/ /************* from pqiServiceMonitor *******************/

View File

@ -512,6 +512,9 @@ void p3GRouter::receiveTurtleData(const RsTurtleGenericTunnelItem *gitem, const
std::cerr << " Received data for hash : " << hash << std::endl; std::cerr << " Received data for hash : " << hash << std::endl;
std::cerr << " Virtual peer id : " << virtual_peer_id << std::endl; std::cerr << " Virtual peer id : " << virtual_peer_id << std::endl;
std::cerr << " Direction : " << direction << std::endl; std::cerr << " Direction : " << direction << std::endl;
#else
(void) hash;
(void) direction;
#endif #endif
// turtle data is received. // turtle data is received.

View File

@ -1186,6 +1186,7 @@ bool RsGenExchange::checkAuthenFlag(const PrivacyBitPos& pos, const uint8_t& fla
} }
} }
#ifdef TO_REMOVE
static void addMessageChanged(std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &msgs, const std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &msgChanged) static void addMessageChanged(std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &msgs, const std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &msgChanged)
{ {
if (msgs.empty()) { if (msgs.empty()) {
@ -1203,7 +1204,6 @@ static void addMessageChanged(std::map<RsGxsGroupId, std::set<RsGxsMessageId> >
} }
} }
#ifdef TO_REMOVE
void RsGenExchange::receiveChanges(std::vector<RsGxsNotify*>& changes) void RsGenExchange::receiveChanges(std::vector<RsGxsNotify*>& changes)
{ {
std::cerr << "*********************************** RsGenExchange::receiveChanges()" << std::endl; std::cerr << "*********************************** RsGenExchange::receiveChanges()" << std::endl;
@ -1780,7 +1780,7 @@ void RsGenExchange::receiveNewMessages(const std::vector<RsNxsMsg *>& messages)
} }
} }
void RsGenExchange::receiveDistantSearchResults(TurtleRequestId id,const RsGxsGroupId &grpId) void RsGenExchange::receiveDistantSearchResults(TurtleRequestId id,const RsGxsGroupId &/*grpId*/)
{ {
std::cerr << __PRETTY_FUNCTION__ << " received result for request " << std::hex << id << std::dec << ": this method should be overloaded in the client service, but it is not. This is a bug!" << std::endl; std::cerr << __PRETTY_FUNCTION__ << " received result for request " << std::hex << id << std::dec << ": this method should be overloaded in the client service, but it is not. This is a bug!" << std::endl;
} }

View File

@ -1730,15 +1730,6 @@ void RsGxsNetService::recvNxsItemQueue()
#endif #endif
/* Handle pull request and other new items here to not mess with all the /* Handle pull request and other new items here to not mess with all the
* old nested code and items hell */ * old nested code and items hell */
switch(static_cast<RsNxsSubtype>(item->PacketSubType()))
{
case RsNxsSubtype::PULL_REQUEST:
std::unique_ptr<RsNxsPullRequestItem> pullItem(
static_cast<RsNxsPullRequestItem*>(item) );
handlePullRequest(std::move(pullItem));
continue;
}
// RsNxsItem needs dynamic_cast, since they have derived siblings. // RsNxsItem needs dynamic_cast, since they have derived siblings.
// //
RsNxsItem *ni = dynamic_cast<RsNxsItem*>(item) ; RsNxsItem *ni = dynamic_cast<RsNxsItem*>(item) ;
@ -1784,7 +1775,8 @@ void RsGxsNetService::recvNxsItemQueue()
case RS_PKT_SUBTYPE_NXS_SYNC_GRP_STATS_ITEM: handleRecvSyncGrpStatistics (dynamic_cast<RsNxsSyncGrpStatsItem*>(ni)) ; break ; case RS_PKT_SUBTYPE_NXS_SYNC_GRP_STATS_ITEM: handleRecvSyncGrpStatistics (dynamic_cast<RsNxsSyncGrpStatsItem*>(ni)) ; break ;
case RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM: handleRecvSyncGroup (dynamic_cast<RsNxsSyncGrpReqItem*>(ni)) ; break ; case RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM: handleRecvSyncGroup (dynamic_cast<RsNxsSyncGrpReqItem*>(ni)) ; break ;
case RS_PKT_SUBTYPE_NXS_SYNC_MSG_REQ_ITEM: handleRecvSyncMessage (dynamic_cast<RsNxsSyncMsgReqItem*>(ni),item_was_encrypted) ; break ; case RS_PKT_SUBTYPE_NXS_SYNC_MSG_REQ_ITEM: handleRecvSyncMessage (dynamic_cast<RsNxsSyncMsgReqItem*>(ni),item_was_encrypted) ; break ;
case RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM:handleRecvPublishKeys (dynamic_cast<RsNxsGroupPublishKeyItem*>(ni)) ; break ; case RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM: handleRecvPublishKeys (dynamic_cast<RsNxsGroupPublishKeyItem*>(ni)) ; break ;
case RS_PKT_SUBTYPE_NXS_SYNC_PULL_REQUEST_ITEM: handlePullRequest (dynamic_cast<RsNxsPullRequestItem*>(ni)) ; break ;
default: default:
if(ni->PacketSubType() != RS_PKT_SUBTYPE_NXS_ENCRYPTED_DATA_ITEM) if(ni->PacketSubType() != RS_PKT_SUBTYPE_NXS_ENCRYPTED_DATA_ITEM)
@ -4277,6 +4269,9 @@ bool RsGxsNetService::locked_checkResendingOfUpdates(const RsPeerId& pid,const R
{ {
#ifdef NXS_NET_DEBUG_0 #ifdef NXS_NET_DEBUG_0
GXSNETDEBUG_PG(pid,grpId) << "(II) peer " << pid << " already sent the same TS " << (long int)now-(long int)rec.mTs << " secs ago for that group ID. Will not send msg list again for a while to prevent clogging..." << std::endl; GXSNETDEBUG_PG(pid,grpId) << "(II) peer " << pid << " already sent the same TS " << (long int)now-(long int)rec.mTs << " secs ago for that group ID. Will not send msg list again for a while to prevent clogging..." << std::endl;
#else
(void) pid;
(void) grpId;
#endif #endif
return false; return false;
} }
@ -4439,7 +4434,9 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_
uint32_t transN = locked_getTransactionId(); uint32_t transN = locked_getTransactionId();
RsGxsCircleId should_encrypt_to_this_circle_id ; RsGxsCircleId should_encrypt_to_this_circle_id ;
#ifndef RS_GXS_SEND_ALL
rstime_t now = time(NULL) ; rstime_t now = time(NULL) ;
#endif
#ifndef RS_GXS_SEND_ALL #ifndef RS_GXS_SEND_ALL
uint32_t max_send_delay = locked_getGrpConfig(item->grpId).msg_req_delay; // we should use "sync" but there's only one variable used in the GUI: the req one. uint32_t max_send_delay = locked_getGrpConfig(item->grpId).msg_req_delay; // we should use "sync" but there's only one variable used in the GUI: the req one.
@ -4704,7 +4701,7 @@ bool RsGxsNetService::checkPermissionsForFriendGroup(const RsPeerId& sslId,const
if(!grpMeta.mInternalCircle.isNull()) if(!grpMeta.mInternalCircle.isNull())
{ {
RsGroupInfo ginfo ; RsGroupInfo ginfo ;
RsPgpId pgpId = mPgpUtils->getPGPId(sslId) ; RsPgpId pgpId = mPgpUtils->getPgpId(sslId) ;
#ifdef NXS_NET_DEBUG_4 #ifdef NXS_NET_DEBUG_4
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << " Group internal circle: " << grpMeta.mInternalCircle << ", We're owner. Sending to everyone in the group." << std::endl; GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << " Group internal circle: " << grpMeta.mInternalCircle << ", We're owner. Sending to everyone in the group." << std::endl;
@ -5114,8 +5111,7 @@ std::error_condition RsGxsNetService::requestPull(std::set<RsPeerId> peers)
for(auto& peerId: std::as_const(peers)) for(auto& peerId: std::as_const(peers))
{ {
auto item = new RsNxsPullRequestItem( auto item = new RsNxsPullRequestItem(mServType);
static_cast<RsServiceType>(mServType) );
item->PeerId(peerId); item->PeerId(peerId);
generic_sendItem(item); generic_sendItem(item);
} }
@ -5123,8 +5119,7 @@ std::error_condition RsGxsNetService::requestPull(std::set<RsPeerId> peers)
return std::error_condition(); return std::error_condition();
} }
void RsGxsNetService::handlePullRequest( void RsGxsNetService::handlePullRequest(RsNxsPullRequestItem *item)
std::unique_ptr<RsNxsPullRequestItem> item )
{ {
checkUpdatesFromPeers(std::set<RsPeerId>{item->PeerId()}); checkUpdatesFromPeers(std::set<RsPeerId>{item->PeerId()});
} }

View File

@ -432,7 +432,11 @@ private:
*/ */
void handleRecvPublishKeys(RsNxsGroupPublishKeyItem*) ; void handleRecvPublishKeys(RsNxsGroupPublishKeyItem*) ;
void handlePullRequest(std::unique_ptr<RsNxsPullRequestItem> item); /*!
* Handles a nxs pull request item from a given friend/tunnel
* @param item contaims keys/grp info
*/
void handlePullRequest(RsNxsPullRequestItem *item);
/** E: item handlers **/ /** E: item handlers **/

View File

@ -223,7 +223,7 @@ bool GrpCircleVetting::canSend(
{ {
if(mCircles->isLoaded(circleId)) if(mCircles->isLoaded(circleId))
{ {
const RsPgpId& pgpId = mPgpUtils->getPGPId(peerId); const RsPgpId& pgpId = mPgpUtils->getPgpId(peerId);
return mCircles->canSend(circleId, pgpId,should_encrypt); return mCircles->canSend(circleId, pgpId,should_encrypt);
} }
@ -302,7 +302,7 @@ bool MsgCircleIdsRequestVetting::cleared()
if(filtered_out_msgs>0) if(filtered_out_msgs>0)
std::cerr << "(WW) " << filtered_out_msgs << " messages not sent because they are signed by author(s) not member of that circle " << mCircleId << std::endl; std::cerr << "(WW) " << filtered_out_msgs << " messages not sent because they are signed by author(s) not member of that circle " << mCircleId << std::endl;
RsPgpId pgpId = mPgpUtils->getPGPId(mPeerId); RsPgpId pgpId = mPgpUtils->getPgpId(mPeerId);
bool can_send_res = mCircles->canSend(mCircleId, pgpId,mShouldEncrypt); bool can_send_res = mCircles->canSend(mCircleId, pgpId,mShouldEncrypt);
if(mShouldEncrypt) // that means the circle is external if(mShouldEncrypt) // that means the circle is external

View File

@ -340,7 +340,7 @@ bool RsGxsIntegrityCheck::check(uint16_t service_type, RsGixs *mgixs, RsGeneralD
} }
bool RsGxsSinglePassIntegrityCheck::check( bool RsGxsSinglePassIntegrityCheck::check(
uint16_t service_type, RsGixs* mgixs, RsGeneralDataService* mds, uint16_t /*service_type*/, RsGixs* /*mgixs*/, RsGeneralDataService* mds,
std::vector<RsGxsGroupId>& grpsToDel, GxsMsgReq& msgsToDel ) std::vector<RsGxsGroupId>& grpsToDel, GxsMsgReq& msgsToDel )
{ {
#ifdef DEBUG_GXSUTIL #ifdef DEBUG_GXSUTIL

View File

@ -4,21 +4,20 @@
!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") !include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri")
TEMPLATE = lib TEMPLATE = lib
CONFIG -= qt
libretroshare_shared { libretroshare_shared {
CONFIG += shared CONFIG += shared
} else { } else {
CONFIG += staticlib CONFIG += staticlib
} }
CONFIG -= qt
TARGET = retroshare TARGET = retroshare
TARGET_PRL = libretroshare TARGET_PRL = libretroshare
DESTDIR = lib DESTDIR = lib
!include("use_libretroshare.pri"):error("Including") !include("use_libretroshare.pri"):error("Including")
# treat warnings as error for better removing QMAKE_CXXFLAGS += -fPIC
#QMAKE_CFLAGS += -Werror
#QMAKE_CXXFLAGS += -Werror
## Uncomment to enable Unfinished Services. ## Uncomment to enable Unfinished Services.
#CONFIG += wikipoos #CONFIG += wikipoos
@ -166,7 +165,7 @@ HEADERS += $$PUBLIC_HEADERS
linux-* { linux-* {
CONFIG += link_pkgconfig CONFIG += link_pkgconfig
QMAKE_CXXFLAGS *= -Wall -D_FILE_OFFSET_BITS=64 QMAKE_CXXFLAGS *= -D_FILE_OFFSET_BITS=64
QMAKE_CC = $${QMAKE_CXX} QMAKE_CC = $${QMAKE_CXX}
no_sqlcipher { no_sqlcipher {
@ -247,10 +246,6 @@ win32-g++|win32-clang-g++ {
MOC_DIR = temp/moc MOC_DIR = temp/moc
!libretroshare_shared:DEFINES *= STATICLIB !libretroshare_shared:DEFINES *= STATICLIB
# Switch on extra warnings
QMAKE_CFLAGS += -Wextra
QMAKE_CXXFLAGS += -Wextra
# Switch off optimization for release version # Switch off optimization for release version
QMAKE_CXXFLAGS_RELEASE -= -O2 QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE += -O0 QMAKE_CXXFLAGS_RELEASE += -O0
@ -363,7 +358,10 @@ HEADERS += chat/distantchat.h \
HEADERS += pqi/authssl.h \ HEADERS += pqi/authssl.h \
pqi/authgpg.h \ pqi/authgpg.h \
pgp/pgphandler.h \ pgp/pgphandler.h \
pgp/openpgpsdkhandler.h \
pgp/pgpkeyutil.h \ pgp/pgpkeyutil.h \
pqi/pqifdbin.h \
pqi/rstcpsocket.h \
pgp/rscertificate.h \ pgp/rscertificate.h \
pgp/pgpauxutils.h \ pgp/pgpauxutils.h \
pqi/p3cfgmgr.h \ pqi/p3cfgmgr.h \
@ -482,6 +480,7 @@ HEADERS += util/folderiterator.h \
util/rsmemory.h \ util/rsmemory.h \
util/smallobject.h \ util/smallobject.h \
util/rsdir.h \ util/rsdir.h \
util/rsfile.h \
util/argstream.h \ util/argstream.h \
util/rsdiscspace.h \ util/rsdiscspace.h \
util/rsnet.h \ util/rsnet.h \
@ -535,12 +534,15 @@ SOURCES += chat/distantchat.cc \
SOURCES += pqi/authgpg.cc \ SOURCES += pqi/authgpg.cc \
pqi/authssl.cc \ pqi/authssl.cc \
pgp/pgphandler.cc \ pgp/pgphandler.cc \
pgp/openpgpsdkhandler.cc \
pgp/pgpkeyutil.cc \ pgp/pgpkeyutil.cc \
pgp/rscertificate.cc \ pgp/rscertificate.cc \
pgp/pgpauxutils.cc \ pgp/pgpauxutils.cc \
pqi/p3cfgmgr.cc \ pqi/p3cfgmgr.cc \
pqi/p3peermgr.cc \ pqi/p3peermgr.cc \
pqi/p3linkmgr.cc \ pqi/p3linkmgr.cc \
pqi/pqifdbin.cc \
pqi/rstcpsocket.cc \
pqi/p3netmgr.cc \ pqi/p3netmgr.cc \
pqi/p3notify.cc \ pqi/p3notify.cc \
pqi/pqiqos.cc \ pqi/pqiqos.cc \
@ -633,6 +635,7 @@ SOURCES += util/folderiterator.cc \
util/rsexpr.cc \ util/rsexpr.cc \
util/smallobject.cc \ util/smallobject.cc \
util/rsdir.cc \ util/rsdir.cc \
util/rsfile.cc \
util/rsdiscspace.cc \ util/rsdiscspace.cc \
util/rsnet.cc \ util/rsnet.cc \
util/rsnet_ss.cc \ util/rsnet_ss.cc \
@ -714,6 +717,41 @@ SOURCES += rsitems/rsnxsitems.cc \
gxs/rsgxsrequesttypes.cc \ gxs/rsgxsrequesttypes.cc \
gxs/rsnxsobserver.cpp gxs/rsnxsobserver.cpp
# Tor
HEADERS += retroshare/rstor.h
HEADERS += tor/AddOnionCommand.h \
tor/AuthenticateCommand.h \
tor/CryptoKey.h \
tor/GetConfCommand.h \
tor/HiddenService.h \
tor/PendingOperation.h \
tor/ProtocolInfoCommand.h \
tor/TorTypes.h \
tor/SetConfCommand.h \
tor/StrUtil.h \
tor/bytearray.h \
tor/TorControl.h \
tor/TorControlCommand.h \
tor/TorControlSocket.h \
tor/TorManager.h \
tor/TorProcess.h
SOURCES += tor/AddOnionCommand.cpp \
tor/AuthenticateCommand.cpp \
tor/GetConfCommand.cpp \
tor/HiddenService.cpp \
tor/ProtocolInfoCommand.cpp \
tor/SetConfCommand.cpp \
tor/TorControlCommand.cpp \
tor/TorControl.cpp \
tor/TorControlSocket.cpp \
tor/TorManager.cpp \
tor/TorProcess.cpp \
tor/CryptoKey.cpp \
tor/PendingOperation.cpp \
tor/StrUtil.cpp
# gxs tunnels # gxs tunnels
HEADERS += gxstunnel/p3gxstunnel.h \ HEADERS += gxstunnel/p3gxstunnel.h \
gxstunnel/rsgxstunnelitems.h \ gxstunnel/rsgxstunnelitems.h \

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,116 @@
/*******************************************************************************
* libretroshare/src/pgp: pgphandler.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2018 Cyril Soler <csoler@users.sourceforge.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <stdint.h>
#include <string>
#include <list>
#include <map>
#include <set>
#include "util/rsthreads.h"
#include "pgp/pgphandler.h"
#include "retroshare/rstypes.h"
extern "C" {
// we should make sure later on to get rid of these structures in the .h
#include "openpgpsdk/keyring.h"
}
/// This class offer an abstract pgp handler to be used in RetroShare.
class OpenPGPSDKHandler: public PGPHandler
{
public:
OpenPGPSDKHandler( const std::string& path_to_public_keyring,
const std::string& path_to_secret_keyring,
const std::string& path_to_trust_database,
const std::string& pgp_lock_file) ;
virtual ~OpenPGPSDKHandler() ;
//================================================================================================//
// Implemented API from PGPHandler //
//================================================================================================//
//virtual std::string makeRadixEncodedPGPKey(uint32_t key_index,bool include_signatures) override;
virtual bool removeKeysFromPGPKeyring(const std::set<RsPgpId>& key_ids,std::string& backup_file,uint32_t& error_code) override;
virtual bool availableGPGCertificatesWithPrivateKeys(std::list<RsPgpId>& ids) override;
virtual bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passphrase, RsPgpId& pgpId, const int keynumbits, std::string& errString) override;
virtual std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const override;
virtual bool exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures ) const override;
virtual bool exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_key_id) const override;
virtual bool exportGPGKeyPairToString( std::string& data, const RsPgpId& exportedKeyId, bool includeSignatures, std::string& errorMsg ) const override;
virtual bool getGPGDetailsFromBinaryBlock(const unsigned char *mem_block,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) const override;
virtual bool importGPGKeyPair(const std::string& filename,RsPgpId& imported_key_id,std::string& import_error) override;
virtual bool importGPGKeyPairFromString(const std::string &data, RsPgpId &imported_key_id, std::string &import_error) override;
virtual bool LoadCertificateFromBinaryData(const unsigned char *data,uint32_t data_len,RsPgpId& id,std::string& error_string) override;
virtual bool LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& id,std::string& error_string) override;
virtual bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) override;
virtual bool encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len, unsigned char *encrypted_data, unsigned int *encrypted_data_len) override;
virtual bool decryptDataBin(const RsPgpId& /*key_id*/,const void *encrypted_data, const uint32_t encrypted_len, unsigned char *data, unsigned int *data_len) override;
virtual bool decryptTextFromFile(const RsPgpId&,std::string& text,const std::string& inputfile) override;
virtual bool SignDataBin(const RsPgpId& id,const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen,bool use_raw_signature, std::string reason /* = "" */) override;
virtual bool privateSignCertificate(const RsPgpId& ownId,const RsPgpId& id_of_key_to_sign) override;
virtual bool VerifySignBin(const void *literal_data, uint32_t literal_data_length, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& key_fingerprint) override;
virtual bool getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const override;
virtual bool haveSecretKey(const RsPgpId& id) const override;
virtual bool syncDatabase() override;
private:
bool locked_syncPublicKeyring() ;
void initCertificateInfo(PGPCertificateInfo& cert,const ops_keydata_t *keydata,uint32_t i) ;
bool LoadCertificate(const unsigned char *data,uint32_t data_len,bool armoured,RsPgpId& id,std::string& error_string) ;
// Returns true if the signatures have been updated
//
bool validateAndUpdateSignatures(PGPCertificateInfo& cert,const ops_keydata_t *keydata) ;
/** Check public/private key and import them into the keyring
* @param keyring keyring with the new public/private key pair. Will be freed by the function.
* @param imported_key_id PGP id of the imported key
* @param import_error human readbale error message
* @returns true on success
* */
bool checkAndImportKeyPair(ops_keyring_t *keyring, RsPgpId& imported_key_id,std::string& import_error);
const ops_keydata_t *locked_getPublicKey(const RsPgpId&,bool stamp_the_key) const;
const ops_keydata_t *locked_getSecretKey(const RsPgpId&) const ;
void locked_mergeKeyringFromDisk(ops_keyring_t *keyring, std::map<RsPgpId,PGPCertificateInfo>& kmap, const std::string& keyring_file) ;
bool locked_addOrMergeKey(ops_keyring_t *keyring,std::map<RsPgpId,PGPCertificateInfo>& kmap,const ops_keydata_t *keydata) ;
// Members.
//
ops_keyring_t *_pubring ;
ops_keyring_t *_secring ;
void printOPSKeys() const;
// Helper functions.
//
static std::string makeRadixEncodedPGPKey(const ops_keydata_t *key,bool include_signatures) ;
static ops_keyring_t *allocateOPSKeyring() ;
static void addNewKeyToOPSKeyring(ops_keyring_t*, const ops_keydata_t&) ;
static bool mergeKeySignatures(ops_keydata_t *dst,const ops_keydata_t *src) ; // returns true if signature lists are different
};

View File

@ -34,17 +34,17 @@ PgpAuxUtilsImpl::PgpAuxUtilsImpl()
const RsPgpId& PgpAuxUtilsImpl::getPGPOwnId() const RsPgpId& PgpAuxUtilsImpl::getPGPOwnId()
{ {
return AuthGPG::getAuthGPG()->getGPGOwnId(); return AuthPGP::getPgpOwnId();
} }
RsPgpId PgpAuxUtilsImpl::getPGPId(const RsPeerId& sslid) RsPgpId PgpAuxUtilsImpl::getPgpId(const RsPeerId& sslid)
{ {
return rsPeers->getGPGId(sslid); return rsPeers->getGPGId(sslid);
} }
bool PgpAuxUtilsImpl::getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const bool PgpAuxUtilsImpl::getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const
{ {
return AuthGPG::getAuthGPG()->getKeyFingerprint(id, fp); return AuthPGP::getKeyFingerprint(id, fp);
} }
bool PgpAuxUtilsImpl::VerifySignBin(const void *data, bool PgpAuxUtilsImpl::VerifySignBin(const void *data,
@ -54,17 +54,17 @@ bool PgpAuxUtilsImpl::VerifySignBin(const void *data,
const PGPFingerprintType& withfingerprint) const PGPFingerprintType& withfingerprint)
{ {
return AuthGPG::getAuthGPG()->VerifySignBin(data, len, sign, signlen, withfingerprint); return AuthPGP::VerifySignBin(data, len, sign, signlen, withfingerprint);
} }
bool PgpAuxUtilsImpl::getGPGAllList(std::list<RsPgpId> &ids) bool PgpAuxUtilsImpl::getPgpAllList(std::list<RsPgpId> &ids)
{ {
return AuthGPG::getAuthGPG()->getGPGAllList(ids); return AuthPGP::getPgpAllList(ids);
} }
bool PgpAuxUtilsImpl::parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const bool PgpAuxUtilsImpl::parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const
{ {
return AuthGPG::getAuthGPG()->parseSignature(sign,signlen,issuer); return AuthPGP::parseSignature(sign,signlen,issuer);
} }

View File

@ -35,8 +35,8 @@ class PgpAuxUtils
virtual ~PgpAuxUtils(){} virtual ~PgpAuxUtils(){}
virtual const RsPgpId &getPGPOwnId() = 0; virtual const RsPgpId &getPGPOwnId() = 0;
virtual RsPgpId getPGPId(const RsPeerId& sslid) = 0; virtual RsPgpId getPgpId(const RsPeerId& sslid) = 0;
virtual bool getGPGAllList(std::list<RsPgpId> &ids) = 0; virtual bool getPgpAllList(std::list<RsPgpId> &ids) = 0;
virtual bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const = 0; virtual bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const = 0;
virtual bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const =0; virtual bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const =0;
@ -49,12 +49,12 @@ public:
PgpAuxUtilsImpl(); PgpAuxUtilsImpl();
virtual const RsPgpId &getPGPOwnId(); virtual const RsPgpId &getPGPOwnId();
virtual RsPgpId getPGPId(const RsPeerId& sslid); virtual RsPgpId getPgpId(const RsPeerId& sslid);
virtual bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const ; virtual bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const ;
virtual bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const; virtual bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const;
virtual bool VerifySignBin(const void *data, uint32_t len, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint); virtual bool VerifySignBin(const void *data, uint32_t len, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint);
virtual bool getGPGAllList(std::list<RsPgpId> &ids); virtual bool getPgpAllList(std::list<RsPgpId> &ids);
}; };

File diff suppressed because it is too large Load Diff

View File

@ -29,12 +29,6 @@
#include <util/rsthreads.h> #include <util/rsthreads.h>
#include <retroshare/rstypes.h> #include <retroshare/rstypes.h>
extern "C" {
#include <openpgpsdk/types.h>
#include <openpgpsdk/keyring.h>
#include <openpgpsdk/keyring_local.h>
}
typedef std::string (*PassphraseCallback)(void *data, const char *uid_title, const char *uid_hint, const char *passphrase_info, int prev_was_bad,bool *cancelled) ; typedef std::string (*PassphraseCallback)(void *data, const char *uid_title, const char *uid_hint, const char *passphrase_info, int prev_was_bad,bool *cancelled) ;
class PGPCertificateInfo class PGPCertificateInfo
@ -56,9 +50,11 @@ class PGPCertificateInfo
mutable rstime_t _time_stamp ; // last time the key was used (received, used for signature verification, etc) mutable rstime_t _time_stamp ; // last time the key was used (received, used for signature verification, etc)
PGPFingerprintType _fpr; /* fingerprint */ PGPFingerprintType _fpr; /* fingerprint */
// RsPgpId _key_id ;
uint32_t _key_index ; // index to array of keys in the public keyring // Index to array of keys in the public keyring. Dependign on the specific implementation
// of how the keyring is stored, this may be used differently.
uint32_t _key_index ;
static const uint32_t PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION = 0x0001 ; static const uint32_t PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION = 0x0001 ;
static const uint32_t PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE = 0x0002 ; static const uint32_t PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE = 0x0002 ;
@ -87,46 +83,80 @@ public:
virtual ~PGPHandler() ; virtual ~PGPHandler() ;
//=======================================================================================//
// Methods that needs to be derived depending on how PGP is implemented //
//=======================================================================================//
// Removes the given keys from the keyring. Also backup the keyring to a file which name is automatically generated
// and given pack for proper display.
//
virtual bool removeKeysFromPGPKeyring(const std::set<RsPgpId>& key_ids,std::string& backup_file,uint32_t& error_code) =0;
//virtual std::string makeRadixEncodedPGPKey(uint32_t key_index,bool include_signatures) =0;
virtual bool availableGPGCertificatesWithPrivateKeys(std::list<RsPgpId>& ids)=0;
virtual bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString) =0;
virtual std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const=0;
/** The caller is in charge of freeing `mem` once finished */
virtual bool exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures ) const =0;
virtual bool exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_key_id) const=0;
virtual bool exportGPGKeyPairToString( std::string& data, const RsPgpId& exportedKeyId, bool includeSignatures, std::string& errorMsg ) const =0;
// Gets info about the key. Who are the signers, what's the owner's name, etc.
//
virtual bool getGPGDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) const =0;
virtual bool importGPGKeyPair(const std::string& filename,RsPgpId& imported_id,std::string& import_error) =0;
/** /**
* @param ids list of gpg certificate ids (note, not the actual certificates) * @param ids list of gpg certificate ids (note, not the actual certificates)
*/ */
bool getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&) = NULL) const ;
bool haveSecretKey(const RsPgpId& id) const ;
bool importGPGKeyPair(const std::string& filename,RsPgpId& imported_id,std::string& import_error) ; virtual bool importGPGKeyPairFromString(const std::string& data,RsPgpId& imported_id,std::string& import_error) =0;
bool importGPGKeyPairFromString(const std::string& data,RsPgpId& imported_id,std::string& import_error) ;
bool exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_id) const ;
bool exportGPGKeyPairToString(
std::string& data, const RsPgpId& exportedKeyId,
bool includeSignatures, std::string& errorMsg ) const;
bool availableGPGCertificatesWithPrivateKeys(std::list<RsPgpId>& ids); virtual bool LoadCertificateFromString(const std::string& pem, RsPgpId& gpg_id, std::string& error_string)=0;
bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString) ; virtual bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string)=0;
bool LoadCertificateFromString(const std::string& pem, RsPgpId& gpg_id, std::string& error_string); virtual bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) =0;
bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string); virtual bool decryptTextFromFile(const RsPgpId& key_id,std::string& text,const std::string& encrypted_inputfile) =0;
std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const ;
/** The caller is in charge of freeing `mem` once finished */
bool exportPublicKey( const RsPgpId& id,
unsigned char*& mem, size_t& mem_size,
bool armoured, bool include_signatures) const;
bool parseSignature(unsigned char *sign, unsigned int signlen,RsPgpId& issuer_id) ;
bool SignDataBin(const RsPgpId& id, const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, bool make_raw_signature=false, std::string reason = "") ;
bool VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& withfingerprint) ;
bool privateSignCertificate(const RsPgpId& own_id,const RsPgpId& id_of_key_to_sign) ;
// The client should supply a memory chunk to store the data. The length will be updated to the real length of the data. // The client should supply a memory chunk to store the data. The length will be updated to the real length of the data.
// //
bool encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len virtual bool encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len , unsigned char *encrypted_data, unsigned int *encrypted_data_len) =0;
, unsigned char *encrypted_data, unsigned int *encrypted_data_len) ; virtual bool decryptDataBin(const RsPgpId& key_id,const void *encrypted_data, const uint32_t encrypted_len , unsigned char *data, unsigned int *data_len) =0;
bool decryptDataBin(const RsPgpId& key_id,const void *encrypted_data, const uint32_t encrypted_len
, unsigned char *data, unsigned int *data_len) ;
bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) ; virtual bool SignDataBin(const RsPgpId& id, const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, bool make_raw_signature=false, std::string reason = "") =0;
bool decryptTextFromFile(const RsPgpId& key_id,std::string& text,const std::string& encrypted_inputfile) ; virtual bool privateSignCertificate(const RsPgpId& own_id,const RsPgpId& id_of_key_to_sign) =0;
virtual bool VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& withfingerprint) =0;
/**
* @brief Get PGP fingerprint for the given key
* @param id PGP 64bit key id
* @param fp storage for the retrived key fingerpring, the contained value
* is meaningfull only if true is returned
* @return true if the key was found, false if not
*/
virtual bool getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const=0;
virtual bool haveSecretKey(const RsPgpId& id) const =0;
// Syncs the keyrings and trust database between memory and disk. The algorithm is:
// 1 - lock the keyrings
// 2 - compare file modification dates with last writing date
// - if file is modified, load it, and merge with memory
// 3 - look into memory modification flags
// - if flag says keyring has changed, write to disk
//
virtual bool syncDatabase() =0;
//=======================================================================================//
// Common methods to PGPHandler //
//=======================================================================================//
bool getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&) = NULL) const ;
bool parseSignature(unsigned char *sign, unsigned int signlen,RsPgpId& issuer_id) ;
void setAcceptConnexion(const RsPgpId&,bool) ; void setAcceptConnexion(const RsPgpId&,bool) ;
@ -135,11 +165,6 @@ public:
void locked_updateOwnSignatureFlag(PGPCertificateInfo&, const RsPgpId&, PGPCertificateInfo&, const RsPgpId&) ; void locked_updateOwnSignatureFlag(PGPCertificateInfo&, const RsPgpId&, PGPCertificateInfo&, const RsPgpId&) ;
// Removes the given keys from the keyring. Also backup the keyring to a file which name is automatically generated
// and given pack for proper display.
//
bool removeKeysFromPGPKeyring(const std::set<RsPgpId>& key_ids,std::string& backup_file,uint32_t& error_code) ;
//bool isKeySupported(const RsPgpId& id) const ; //bool isKeySupported(const RsPgpId& id) const ;
bool privateTrustCertificate(const RsPgpId& id,int valid_level) ; bool privateTrustCertificate(const RsPgpId& id,int valid_level) ;
@ -174,66 +199,18 @@ public:
*/ */
static RsPgpId pgpIdFromFingerprint(const RsPgpFingerprint& f); static RsPgpId pgpIdFromFingerprint(const RsPgpFingerprint& f);
/**
* @brief Get PGP fingerprint for the given key
* @param id PGP 64bit key id
* @param fp storage for the retrived key fingerpring, the contained value
* is meaningfull only if true is returned
* @return true if the key was found, false if not
*/
bool getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const;
// Gets info about the key. Who are the signers, what's the owner's name, etc.
//
bool getGPGDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) const ;
// Debug stuff. // Debug stuff.
virtual bool printKeys() const ; virtual bool printKeys() const ;
// Syncs the keyrings and trust database between memory and disk. The algorithm is: protected:
// 1 - lock the keyrings
// 2 - compare file modification dates with last writing date
// - if file is modified, load it, and merge with memory
// 3 - look into memory modification flags
// - if flag says keyring has changed, write to disk
//
bool syncDatabase() ;
private:
bool LoadCertificate(const unsigned char *bin_data,uint32_t bin_data_len, bool armoured, RsPgpId& gpg_id, std::string& error_string);
void initCertificateInfo(PGPCertificateInfo& cert,const ops_keydata_t *keydata,uint32_t i) ;
// Returns true if the signatures have been updated
//
bool validateAndUpdateSignatures(PGPCertificateInfo& cert,const ops_keydata_t *keydata) ;
/** Check public/private key and import them into the keyring
* @param keyring keyring with the new public/private key pair. Will be freed by the function.
* @param imported_key_id PGP id of the imported key
* @param import_error human readbale error message
* @returns true on success
* */
bool checkAndImportKeyPair(ops_keyring_t *keyring, RsPgpId& imported_key_id,std::string& import_error);
const ops_keydata_t *locked_getPublicKey(const RsPgpId&,bool stamp_the_key) const;
const ops_keydata_t *locked_getSecretKey(const RsPgpId&) const ;
void locked_readPrivateTrustDatabase() ; void locked_readPrivateTrustDatabase() ;
bool locked_writePrivateTrustDatabase() ; bool locked_writePrivateTrustDatabase() ;
bool locked_syncPublicKeyring() ;
bool locked_syncTrustDatabase() ; bool locked_syncTrustDatabase() ;
void locked_mergeKeyringFromDisk(ops_keyring_t *keyring, std::map<RsPgpId,PGPCertificateInfo>& kmap, const std::string& keyring_file) ;
bool locked_addOrMergeKey(ops_keyring_t *keyring,std::map<RsPgpId,PGPCertificateInfo>& kmap,const ops_keydata_t *keydata) ;
// Members. // Members.
// //
mutable RsMutex pgphandlerMtx ; mutable RsMutex pgphandlerMtx ;
ops_keyring_t *_pubring ;
ops_keyring_t *_secring ;
std::map<RsPgpId,PGPCertificateInfo> _public_keyring_map ; // used for fast access to keys. Gives the index in the keyring. std::map<RsPgpId,PGPCertificateInfo> _public_keyring_map ; // used for fast access to keys. Gives the index in the keyring.
std::map<RsPgpId,PGPCertificateInfo> _secret_keyring_map ; std::map<RsPgpId,PGPCertificateInfo> _secret_keyring_map ;
@ -249,11 +226,5 @@ public:
rstime_t _secring_last_update_time ; rstime_t _secring_last_update_time ;
rstime_t _trustdb_last_update_time ; rstime_t _trustdb_last_update_time ;
// Helper functions.
//
static std::string makeRadixEncodedPGPKey(const ops_keydata_t *key,bool include_signatures) ;
static ops_keyring_t *allocateOPSKeyring() ;
static void addNewKeyToOPSKeyring(ops_keyring_t*, const ops_keydata_t&) ;
static PassphraseCallback _passphrase_callback ; static PassphraseCallback _passphrase_callback ;
static bool mergeKeySignatures(ops_keydata_t *dst,const ops_keydata_t *src) ; // returns true if signature lists are different
}; };

View File

@ -46,7 +46,7 @@
//const rstime_t STORE_KEY_TIMEOUT = 1 * 60 * 60; //store key is call around every hour //const rstime_t STORE_KEY_TIMEOUT = 1 * 60 * 60; //store key is call around every hour
AuthGPG *AuthGPG::_instance = NULL ; AuthPGP *AuthPGP::_instance = NULL ;
void cleanupZombies(int numkill); // function to cleanup zombies under OSX. void cleanupZombies(int numkill); // function to cleanup zombies under OSX.
@ -54,34 +54,46 @@ void cleanupZombies(int numkill); // function to cleanup zombies under OSX.
/* Function to sign X509_REQ via GPGme. */ /* Function to sign X509_REQ via GPGme. */
bool AuthGPG::decryptTextFromFile(std::string& text,const std::string& inputfile) int AuthPGP::availablePgpCertificatesWithPrivateKeys(std::list<RsPgpId>& pgpIds)
{ {
return PGPHandler::decryptTextFromFile(mOwnGpgId,text,inputfile) ; return instance()->mPgpHandler->availableGPGCertificatesWithPrivateKeys(pgpIds);
}
bool AuthPGP::getPgpDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers)
{
return instance()->mPgpHandler->getGPGDetailsFromBinaryBlock(mem,mem_size,key_id,name,signers);
}
void AuthPGP::registerToConfigMgr(const std::string& fname,p3ConfigMgr *CfgMgr)
{
CfgMgr->addConfiguration(fname, instance());
}
bool AuthPGP::decryptTextFromFile(std::string& text,const std::string& inputfile)
{
return instance()->mPgpHandler->decryptTextFromFile(instance()->mOwnGpgId,text,inputfile) ;
} }
bool AuthGPG::removeKeysFromPGPKeyring(const std::set<RsPgpId>& pgp_ids,std::string& backup_file,uint32_t& error_code) bool AuthPGP::removeKeysFromPGPKeyring(const std::set<RsPgpId>& pgp_ids,std::string& backup_file,uint32_t& error_code)
{ {
// std::list<RsPgpId> pids ; // std::list<RsPgpId> pids ;
// //
// for(std::list<RsPgpId>::const_iterator it(pgp_ids.begin());it!=pgp_ids.end();++it) // for(std::list<RsPgpId>::const_iterator it(pgp_ids.begin());it!=pgp_ids.end();++it)
// pids.push_back(RsPgpId(*it)) ; // pids.push_back(RsPgpId(*it)) ;
return PGPHandler::removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ; return instance()->mPgpHandler->removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ;
} }
// bool AuthGPG::decryptTextFromString(std::string& encrypted_text,std::string& output) // bool AuthGPG::decryptTextFromString(std::string& encrypted_text,std::string& output)
// { // {
// return PGPHandler::decryptTextFromString(mOwnGpgId,encrypted_text,output) ; // return instance()->mPgpHandler->decryptTextFromString(mOwnGpgId,encrypted_text,output) ;
// } // }
bool AuthGPG::encryptTextToFile(const std::string& text,const std::string& outfile) bool AuthPGP::encryptTextToFile(const std::string& text,const std::string& outfile)
{ {
return PGPHandler::encryptTextToFile(mOwnGpgId,text,outfile) ; return instance()->mPgpHandler->encryptTextToFile(instance()->mOwnGpgId,text,outfile) ;
} }
// bool AuthGPG::encryptTextToString(const std::string& pgp_id,const std::string& text,std::string& outstr) // bool AuthGPG::encryptTextToString(const std::string& pgp_id,const std::string& text,std::string& outstr)
// { // {
// return PGPHandler::encryptTextToString(RsPgpId(pgp_id),text,outstr) ; // return instance()->mPgpHandler->encryptTextToString(RsPgpId(pgp_id),text,outstr) ;
// } // }
std::string pgp_pwd_callback(void * /*hook*/, const char *uid_title, const char *uid_hint, const char * /*passphrase_info*/, int prev_was_bad,bool *cancelled) std::string pgp_pwd_callback(void * /*hook*/, const char *uid_title, const char *uid_hint, const char * /*passphrase_info*/, int prev_was_bad,bool *cancelled)
@ -95,7 +107,7 @@ std::string pgp_pwd_callback(void * /*hook*/, const char *uid_title, const char
return password ; return password ;
} }
void AuthGPG::init( void AuthPGP::init(
const std::string& path_to_public_keyring, const std::string& path_to_public_keyring,
const std::string& path_to_secret_keyring, const std::string& path_to_secret_keyring,
const std::string& path_to_trustdb, const std::string& path_to_trustdb,
@ -107,14 +119,14 @@ void AuthGPG::init(
std::cerr << "AuthGPG::init() called twice!" << std::endl ; std::cerr << "AuthGPG::init() called twice!" << std::endl ;
} }
// if(cb) PGPHandler::setPassphraseCallback(cb);else // if(cb) instance()->mPgpHandler->setPassphraseCallback(cb);else
PGPHandler::setPassphraseCallback(pgp_pwd_callback); instance()->mPgpHandler->setPassphraseCallback(pgp_pwd_callback);
_instance = new AuthGPG( path_to_public_keyring, _instance = new AuthPGP( path_to_public_keyring,
path_to_secret_keyring, path_to_secret_keyring,
path_to_trustdb, pgp_lock_file ); path_to_trustdb, pgp_lock_file );
} }
void AuthGPG::exit() void AuthPGP::exit()
{ {
if(_instance) if(_instance)
{ {
@ -124,9 +136,8 @@ void AuthGPG::exit()
} }
} }
AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& path_to_secret_keyring,const std::string& path_to_trustdb,const std::string& pgp_lock_file) AuthPGP::AuthPGP(const std::string& path_to_public_keyring,const std::string& path_to_secret_keyring,const std::string& path_to_trustdb,const std::string& pgp_lock_file)
:p3Config(), :p3Config(),
PGPHandler(path_to_public_keyring,path_to_secret_keyring,path_to_trustdb,pgp_lock_file),
gpgMtxService("AuthGPG-service"), gpgMtxService("AuthGPG-service"),
gpgMtxEngine("AuthGPG-engine"), gpgMtxEngine("AuthGPG-engine"),
gpgMtxData("AuthGPG-data"), gpgMtxData("AuthGPG-data"),
@ -135,6 +146,8 @@ AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& pa
_force_sync_database(false), _force_sync_database(false),
mCount(0) mCount(0)
{ {
mPgpHandler = new OpenPGPSDKHandler(path_to_public_keyring,path_to_secret_keyring,path_to_trustdb,pgp_lock_file);
start("AuthGPG"); start("AuthGPG");
} }
@ -149,7 +162,7 @@ AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& pa
//{ //{
// std::list<RsPgpId> pids ; // std::list<RsPgpId> pids ;
// //
// PGPHandler::availableGPGCertificatesWithPrivateKeys(pids) ; // mPgpHandler->availableGPGCertificatesWithPrivateKeys(pids) ;
// //
// for(std::list<RsPgpId>::const_iterator it(pids.begin());it!=pids.end();++it) // for(std::list<RsPgpId>::const_iterator it(pids.begin());it!=pids.end();++it)
// ids.push_back( (*it).toStdString() ) ; // ids.push_back( (*it).toStdString() ) ;
@ -165,17 +178,17 @@ AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& pa
* This function must be called successfully (return == 1) * This function must be called successfully (return == 1)
* before anything else can be done. (except above fn). * before anything else can be done. (except above fn).
*/ */
int AuthGPG::GPGInit(const RsPgpId &ownId) int AuthPGP::PgpInit(const RsPgpId &ownId)
{ {
#ifdef DEBUG_AUTHGPG #ifdef DEBUG_AUTHGPG
std::cerr << "AuthGPG::GPGInit() called with own gpg id : " << ownId.toStdString() << std::endl; std::cerr << "AuthGPG::GPGInit() called with own gpg id : " << ownId.toStdString() << std::endl;
#endif #endif
mOwnGpgId = RsPgpId(ownId); instance()->mOwnGpgId = ownId;
//force the validity of the private key. When set to unknown, it caused signature and text encryptions bugs //force the validity of the private key. When set to unknown, it caused signature and text encryptions bugs
privateTrustCertificate(ownId, 5); instance()->privateTrustCertificate(ownId, 5);
updateOwnSignatureFlag(mOwnGpgId) ; instance()->mPgpHandler->updateOwnSignatureFlag(ownId) ;
#ifdef DEBUG_AUTHGPG #ifdef DEBUG_AUTHGPG
std::cerr << "AuthGPG::GPGInit finished." << std::endl; std::cerr << "AuthGPG::GPGInit finished." << std::endl;
@ -184,11 +197,11 @@ int AuthGPG::GPGInit(const RsPgpId &ownId)
return 1; return 1;
} }
AuthGPG::~AuthGPG() AuthPGP::~AuthPGP()
{ {
} }
void AuthGPG::threadTick() void AuthPGP::threadTick()
{ {
rstime::rs_usleep(100 * 1000); //100 msec rstime::rs_usleep(100 * 1000); //100 msec
@ -204,13 +217,13 @@ void AuthGPG::threadTick()
/// - checks whether the keyring has changed on disk. /// - checks whether the keyring has changed on disk.
/// - merges/updates according to status. /// - merges/updates according to status.
/// ///
PGPHandler::syncDatabase() ; mPgpHandler->syncDatabase() ;
mCount = 0; mCount = 0;
_force_sync_database = false ; _force_sync_database = false ;
}//if (++count >= 100 || _force_sync_database) }//if (++count >= 100 || _force_sync_database)
} }
void AuthGPG::processServices() void AuthPGP::processServices()
{ {
AuthGPGOperation *operation = NULL; AuthGPGOperation *operation = NULL;
AuthGPGService *service = NULL; AuthGPGService *service = NULL;
@ -251,7 +264,7 @@ void AuthGPG::processServices()
/* don't bother loading - if we already have the certificate */ /* don't bother loading - if we already have the certificate */
if (isGPGId(loadOrSave->m_certGpgId)) if (mPgpHandler->isGPGId(loadOrSave->m_certGpgId))
{ {
#ifdef GPG_DEBUG #ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::processServices() Skipping load - already have it" << std::endl; std::cerr << "AuthGPGimpl::processServices() Skipping load - already have it" << std::endl;
@ -305,66 +318,66 @@ void AuthGPG::processServices()
delete operation; delete operation;
} }
bool AuthGPG::DoOwnSignature(const void *data, unsigned int datalen, void *buf_sigout, unsigned int *outl, std::string reason /* = "" */) bool AuthPGP::DoOwnSignature(const void *data, unsigned int datalen, void *buf_sigout, unsigned int *outl, std::string reason /* = "" */)
{ {
return PGPHandler::SignDataBin(mOwnGpgId,data,datalen,(unsigned char *)buf_sigout,outl,false,reason) ; return instance()->mPgpHandler->SignDataBin(mOwnGpgId,data,datalen,(unsigned char *)buf_sigout,outl,false,reason) ;
} }
/* import to GnuPG and other Certificates */ /* import to GnuPG and other Certificates */
bool AuthGPG::VerifySignature(const void *data, int datalen, const void *sig, unsigned int siglen, const PGPFingerprintType& withfingerprint) bool AuthPGP::VerifySignature(const void *data, int datalen, const void *sig, unsigned int siglen, const PGPFingerprintType& withfingerprint)
{ {
return PGPHandler::VerifySignBin((unsigned char*)data,datalen,(unsigned char*)sig,siglen,withfingerprint) ; return instance()->mPgpHandler->VerifySignBin((unsigned char*)data,datalen,(unsigned char*)sig,siglen,withfingerprint) ;
} }
bool AuthGPG::parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id) bool AuthPGP::parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id)
{ {
return PGPHandler::parseSignature((unsigned char*)sig,siglen,issuer_id) ; return instance()->mPgpHandler->parseSignature((unsigned char*)sig,siglen,issuer_id) ;
} }
bool AuthGPG::exportProfile(const std::string& fname,const RsPgpId& exported_id) bool AuthPGP::exportProfile(const std::string& fname,const RsPgpId& exported_id)
{ {
return PGPHandler::exportGPGKeyPair(fname,exported_id) ; return instance()->mPgpHandler->exportGPGKeyPair(fname,exported_id) ;
} }
bool AuthGPG::exportIdentityToString( bool AuthPGP::exportIdentityToString(
std::string& data, const RsPgpId& pgpId, bool includeSignatures, std::string& data, const RsPgpId& pgpId, bool includeSignatures,
std::string& errorMsg ) std::string& errorMsg )
{ {
return PGPHandler::exportGPGKeyPairToString( return instance()->mPgpHandler->exportGPGKeyPairToString(
data, pgpId, includeSignatures, errorMsg); data, pgpId, includeSignatures, errorMsg);
} }
bool AuthGPG::importProfile(const std::string& fname,RsPgpId& imported_id,std::string& import_error) bool AuthPGP::importProfile(const std::string& fname,RsPgpId& imported_id,std::string& import_error)
{ {
return PGPHandler::importGPGKeyPair(fname,imported_id,import_error) ; return instance()->mPgpHandler->importGPGKeyPair(fname,imported_id,import_error) ;
} }
bool AuthGPG::importProfileFromString(const std::string &data, RsPgpId &gpg_id, std::string &import_error) bool AuthPGP::importProfileFromString(const std::string &data, RsPgpId &gpg_id, std::string &import_error)
{ {
return PGPHandler::importGPGKeyPairFromString(data, gpg_id, import_error); return instance()->mPgpHandler->importGPGKeyPairFromString(data, gpg_id, import_error);
} }
bool AuthGPG::active() bool AuthPGP::active()
{ {
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
return gpgKeySelected; return instance()->gpgKeySelected;
} }
bool AuthGPG::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString) bool AuthPGP::GeneratePgpCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString)
{ {
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/ RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
return PGPHandler::GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString) ; return instance()->mPgpHandler->GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString) ;
} }
/**** These Two are common */ /**** These Two are common */
std::string AuthGPG::getGPGName(const RsPgpId& id,bool *success) std::string AuthPGP::getPgpName(const RsPgpId& id,bool *success)
{ {
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
const PGPCertificateInfo *info = getCertificateInfo(id) ; const PGPCertificateInfo *info = instance()->mPgpHandler->getCertificateInfo(id) ;
if(info != NULL) if(info != NULL)
{ {
@ -378,11 +391,25 @@ std::string AuthGPG::getGPGName(const RsPgpId& id,bool *success)
} }
} }
/**** These Two are common */ AuthPGP *AuthPGP::instance()
std::string AuthGPG::getGPGEmail(const RsPgpId& id,bool *success)
{ {
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ if(!_instance)
const PGPCertificateInfo *info = getCertificateInfo(id) ; {
RsFatal() << "AuthGPG::instance() called before AuthGPG::init()! This should not happen." << std::endl;
return nullptr;
}
return _instance;
}
bool AuthPGP::isPGPId(const RsPgpId& id)
{
return instance()->mPgpHandler->isGPGId(id);
}
/**** These Two are common */
std::string AuthPGP::getPgpEmail(const RsPgpId& id,bool *success)
{
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
const PGPCertificateInfo *info = instance()->mPgpHandler->getCertificateInfo(id) ;
if(info != NULL) if(info != NULL)
{ {
@ -398,30 +425,30 @@ std::string AuthGPG::getGPGEmail(const RsPgpId& id,bool *success)
/**** GPG versions ***/ /**** GPG versions ***/
const RsPgpId& AuthGPG::getGPGOwnId() const RsPgpId& AuthPGP::getPgpOwnId()
{ {
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
return mOwnGpgId ; return instance()->mOwnGpgId ;
} }
std::string AuthGPG::getGPGOwnName() std::string AuthPGP::getPgpOwnName()
{ {
return getGPGName(mOwnGpgId) ; return getPgpName(instance()->mOwnGpgId) ;
} }
bool AuthGPG::getGPGAllList(std::list<RsPgpId> &ids) bool AuthPGP::getPgpAllList(std::list<RsPgpId> &ids)
{ {
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
PGPHandler::getGPGFilteredList(ids) ; instance()->mPgpHandler->getGPGFilteredList(ids) ;
return true; return true;
} }
const PGPCertificateInfo *AuthGPG::getCertInfoFromStdString(const std::string& pgp_id) const const PGPCertificateInfo *AuthPGP::getCertInfoFromStdString(const std::string& pgp_id) const
{ {
try try
{ {
return PGPHandler::getCertificateInfo(RsPgpId(pgp_id)) ; return instance()->mPgpHandler->getCertificateInfo(RsPgpId(pgp_id)) ;
} }
catch(std::exception& e) catch(std::exception& e)
{ {
@ -429,13 +456,13 @@ const PGPCertificateInfo *AuthGPG::getCertInfoFromStdString(const std::string& p
return NULL ; return NULL ;
} }
} }
bool AuthGPG::haveSecretKey(const RsPgpId& id) const bool AuthPGP::haveSecretKey(const RsPgpId& id)
{ {
return PGPHandler::haveSecretKey(id) ; return instance()->mPgpHandler->haveSecretKey(id) ;
} }
bool AuthGPG::isKeySupported(const RsPgpId& id) const bool AuthPGP::isKeySupported(const RsPgpId& id)
{ {
const PGPCertificateInfo *pc = getCertificateInfo(id) ; const PGPCertificateInfo *pc = instance()->mPgpHandler->getCertificateInfo(id) ;
if(pc == NULL) if(pc == NULL)
return false ; return false ;
@ -443,11 +470,11 @@ bool AuthGPG::isKeySupported(const RsPgpId& id) const
return !(pc->_flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_UNSUPPORTED_ALGORITHM) ; return !(pc->_flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_UNSUPPORTED_ALGORITHM) ;
} }
bool AuthGPG::getGPGDetails(const RsPgpId& pgp_id, RsPeerDetails &d) bool AuthPGP::getPgpDetails(const RsPgpId& pgp_id, RsPeerDetails &d)
{ {
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
const PGPCertificateInfo *pc = PGPHandler::getCertificateInfo(pgp_id) ; const PGPCertificateInfo *pc = instance()->mPgpHandler->getCertificateInfo(pgp_id) ;
if(pc == NULL) if(pc == NULL)
return false ; return false ;
@ -474,28 +501,26 @@ bool AuthGPG::getGPGDetails(const RsPgpId& pgp_id, RsPeerDetails &d)
return true; return true;
} }
bool AuthGPG::getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&)) bool AuthPGP::getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&))
{ {
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ return instance()->mPgpHandler->getGPGFilteredList(list,filter) ;
return PGPHandler::getGPGFilteredList(list,filter) ;
} }
static bool filter_Validity(const PGPCertificateInfo& /*info*/) { return true ; } //{ return info._validLvl >= PGPCertificateInfo::GPGME_VALIDITY_MARGINAL ; } static bool filter_Validity(const PGPCertificateInfo& /*info*/) { return true ; } //{ return info._validLvl >= PGPCertificateInfo::GPGME_VALIDITY_MARGINAL ; }
static bool filter_Accepted(const PGPCertificateInfo& info) { return info._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION ; } static bool filter_Accepted(const PGPCertificateInfo& info) { return info._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION ; }
static bool filter_OwnSigned(const PGPCertificateInfo& info) { return info._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE ; } static bool filter_OwnSigned(const PGPCertificateInfo& info) { return info._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE ; }
bool AuthGPG::getGPGValidList(std::list<RsPgpId> &ids) bool AuthPGP::getPgpValidList(std::list<RsPgpId> &ids)
{ {
return getGPGFilteredList(ids,&filter_Validity); return getGPGFilteredList(ids,&filter_Validity);
} }
bool AuthGPG::getGPGAcceptedList(std::list<RsPgpId> &ids) bool AuthPGP::getPgpAcceptedList(std::list<RsPgpId> &ids)
{ {
return getGPGFilteredList(ids,&filter_Accepted); return getGPGFilteredList(ids,&filter_Accepted);
} }
bool AuthGPG::getGPGSignedList(std::list<RsPgpId> &ids) bool AuthPGP::getPgpSignedList(std::list<RsPgpId> &ids)
{ {
return getGPGFilteredList(ids,&filter_OwnSigned); return getGPGFilteredList(ids,&filter_OwnSigned);
} }
@ -504,9 +529,9 @@ bool AuthGPG::getGPGSignedList(std::list<RsPgpId> &ids)
// { // {
// RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ // RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
// #ifdef LIMIT_CERTIFICATE_SIZE // #ifdef LIMIT_CERTIFICATE_SIZE
// certificate = PGPHandler::SaveCertificateToString(RsPgpId(id),false) ; // certificate = instance()->mPgpHandler->SaveCertificateToString(RsPgpId(id),false) ;
// #else // #else
// certificate = PGPHandler::SaveCertificateToString(RsPgpId(id),true) ; // certificate = instance()->mPgpHandler->SaveCertificateToString(RsPgpId(id),true) ;
// #endif // #endif
// //
// // #ifdef LIMIT_CERTIFICATE_SIZE // // #ifdef LIMIT_CERTIFICATE_SIZE
@ -528,20 +553,20 @@ bool AuthGPG::getGPGSignedList(std::list<RsPgpId> &ids)
/* SKTAN : do not know how to use std::string id */ /* SKTAN : do not know how to use std::string id */
std::string AuthGPG::SaveCertificateToString(const RsPgpId &id,bool include_signatures) std::string AuthPGP::SaveCertificateToString(const RsPgpId &id,bool include_signatures)
{ {
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/ RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
return PGPHandler::SaveCertificateToString(id,include_signatures) ; return instance()->mPgpHandler->SaveCertificateToString(id,include_signatures) ;
} }
/* import to GnuPG and other Certificates */ /* import to GnuPG and other Certificates */
bool AuthGPG::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string) bool AuthPGP::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string)
{ {
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/ RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
if(PGPHandler::LoadCertificateFromBinaryData(data,data_len,gpg_id,error_string)) if(instance()->mPgpHandler->LoadCertificateFromBinaryData(data,data_len,gpg_id,error_string))
{ {
updateOwnSignatureFlag(gpg_id,mOwnGpgId) ; instance()->mPgpHandler->updateOwnSignatureFlag(gpg_id,instance()->mOwnGpgId) ;
return true ; return true ;
} }
@ -549,13 +574,13 @@ bool AuthGPG::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_l
} }
/* import to GnuPG and other Certificates */ /* import to GnuPG and other Certificates */
bool AuthGPG::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,std::string& error_string) bool AuthPGP::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,std::string& error_string)
{ {
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/ RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
if(PGPHandler::LoadCertificateFromString(str,gpg_id,error_string)) if(instance()->mPgpHandler->LoadCertificateFromString(str,gpg_id,error_string))
{ {
updateOwnSignatureFlag(gpg_id,mOwnGpgId) ; instance()->mPgpHandler->updateOwnSignatureFlag(gpg_id,instance()->mOwnGpgId) ;
return true ; return true ;
} }
@ -576,7 +601,7 @@ bool AuthGPG::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,
/*************************************/ /*************************************/
/* These take PGP Ids */ /* These take PGP Ids */
bool AuthGPG::AllowConnection(const RsPgpId& gpg_id, bool accept) bool AuthPGP::AllowConnection(const RsPgpId& gpg_id, bool accept)
{ {
#ifdef GPG_DEBUG #ifdef GPG_DEBUG
std::cerr << "AuthGPG::AllowConnection(" << gpg_id << ")" << std::endl; std::cerr << "AuthGPG::AllowConnection(" << gpg_id << ")" << std::endl;
@ -584,11 +609,11 @@ bool AuthGPG::AllowConnection(const RsPgpId& gpg_id, bool accept)
/* Was a "Reload Certificates" here -> be shouldn't be needed -> and very expensive, try without. */ /* Was a "Reload Certificates" here -> be shouldn't be needed -> and very expensive, try without. */
{ {
RsStackMutex stack(gpgMtxData); RsStackMutex stack(instance()->gpgMtxData);
PGPHandler::setAcceptConnexion(gpg_id,accept) ; instance()->mPgpHandler->setAcceptConnexion(gpg_id,accept) ;
} }
IndicateConfigChanged(); instance()->IndicateConfigChanged();
RsServer::notify()->notifyListChange(NOTIFY_LIST_FRIENDS, accept ? NOTIFY_TYPE_ADD : NOTIFY_TYPE_DEL); RsServer::notify()->notifyListChange(NOTIFY_LIST_FRIENDS, accept ? NOTIFY_TYPE_ADD : NOTIFY_TYPE_DEL);
@ -596,16 +621,16 @@ bool AuthGPG::AllowConnection(const RsPgpId& gpg_id, bool accept)
} }
/* These take PGP Ids */ /* These take PGP Ids */
bool AuthGPG::SignCertificateLevel0(const RsPgpId &id) bool AuthPGP::SignCertificateLevel0(const RsPgpId &id)
{ {
#ifdef GPG_DEBUG #ifdef GPG_DEBUG
std::cerr << "AuthGPG::SignCertificat(" << id << ")" << std::endl; std::cerr << "AuthGPG::SignCertificat(" << id << ")" << std::endl;
#endif #endif
return privateSignCertificate(id) ; return instance()->privateSignCertificate(id) ;
} }
bool AuthGPG::RevokeCertificate(const RsPgpId &id) bool AuthPGP::RevokeCertificate(const RsPgpId &id)
{ {
/* remove unused parameter warnings */ /* remove unused parameter warnings */
(void) id; (void) id;
@ -617,46 +642,59 @@ bool AuthGPG::RevokeCertificate(const RsPgpId &id)
return false; return false;
} }
bool AuthGPG::TrustCertificate(const RsPgpId& id, int trustlvl) bool AuthPGP::TrustCertificate(const RsPgpId& id, int trustlvl)
{ {
#ifdef GPG_DEBUG #ifdef GPG_DEBUG
std::cerr << "AuthGPG::TrustCertificate(" << id << ", " << trustlvl << ")" << std::endl; std::cerr << "AuthGPG::TrustCertificate(" << id << ", " << trustlvl << ")" << std::endl;
#endif #endif
return privateTrustCertificate(id, trustlvl) ; return instance()->privateTrustCertificate(id, trustlvl) ;
} }
bool AuthGPG::encryptDataBin(const RsPgpId& pgp_id,const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen) bool AuthPGP::encryptDataBin(const RsPgpId& pgp_id,const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen)
{ {
return PGPHandler::encryptDataBin(RsPgpId(pgp_id),data,datalen,sign,signlen) ; return instance()->mPgpHandler->encryptDataBin(RsPgpId(pgp_id),data,datalen,sign,signlen) ;
} }
bool AuthGPG::decryptDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen) bool AuthPGP::decryptDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen)
{ {
return PGPHandler::decryptDataBin(mOwnGpgId,data,datalen,sign,signlen) ; return instance()->mPgpHandler->decryptDataBin(instance()->mOwnGpgId,data,datalen,sign,signlen) ;
} }
bool AuthGPG::SignDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen, std::string reason /*= ""*/) bool AuthPGP::SignDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen, std::string reason /*= ""*/)
{ {
return DoOwnSignature(data, datalen, sign, signlen, reason); return instance()->DoOwnSignature(data, datalen, sign, signlen, reason);
} }
bool AuthGPG::VerifySignBin(const void *data, uint32_t datalen, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint) bool AuthPGP::exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures )
{ {
return VerifySignature(data, datalen, sign, signlen, withfingerprint); return instance()->mPgpHandler->exportPublicKey(id,mem_block,mem_size,armoured,include_signatures);
}
bool AuthPGP::isPgpPubKeyAvailable(const RsPgpId& pgp_id)
{
return instance()->mPgpHandler->isPgpPubKeyAvailable(pgp_id);
}
bool AuthPGP::getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp)
{
return instance()->mPgpHandler->getKeyFingerprint(id,fp);
}
bool AuthPGP::VerifySignBin(const void *data, uint32_t datalen, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint)
{
return instance()->VerifySignature(data, datalen, sign, signlen, withfingerprint);
} }
/* Sign/Trust stuff */ /* Sign/Trust stuff */
int AuthGPG::privateSignCertificate(const RsPgpId &id) int AuthPGP::privateSignCertificate(const RsPgpId &id)
{ {
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
int ret = PGPHandler::privateSignCertificate(mOwnGpgId,id) ; int ret = mPgpHandler->privateSignCertificate(mOwnGpgId,id) ;
_force_sync_database = true ; _force_sync_database = true ;
return ret ; return ret ;
} }
/* revoke the signature on Certificate */ /* revoke the signature on Certificate */
int AuthGPG::privateRevokeCertificate(const RsPgpId &/*id*/) int AuthPGP::privateRevokeCertificate(const RsPgpId &/*id*/)
{ {
//RsStackMutex stack(gpgMtx); /******* LOCKED ******/ //RsStackMutex stack(gpgMtx); /******* LOCKED ******/
std::cerr << __PRETTY_FUNCTION__ << ": not implemented!" << std::endl; std::cerr << __PRETTY_FUNCTION__ << ": not implemented!" << std::endl;
@ -664,7 +702,7 @@ int AuthGPG::privateRevokeCertificate(const RsPgpId &/*id*/)
return 0; return 0;
} }
int AuthGPG::privateTrustCertificate(const RsPgpId& id, int trustlvl) int AuthPGP::privateTrustCertificate(const RsPgpId& id, int trustlvl)
{ {
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
@ -672,10 +710,10 @@ int AuthGPG::privateTrustCertificate(const RsPgpId& id, int trustlvl)
// The trust level is only a user-defined property that has nothing to // The trust level is only a user-defined property that has nothing to
// do with the fact that we allow connections or not. // do with the fact that we allow connections or not.
if(!isGPGAccepted(id)) if(!isPGPAccepted(id))
return 0; return 0;
int res = PGPHandler::privateTrustCertificate(id,trustlvl) ; int res = instance()->mPgpHandler->privateTrustCertificate(id,trustlvl) ;
_force_sync_database = true ; _force_sync_database = true ;
return res ; return res ;
} }
@ -684,20 +722,24 @@ int AuthGPG::privateTrustCertificate(const RsPgpId& id, int trustlvl)
// -------------------------------- Config functions ------------------------------ // // -------------------------------- Config functions ------------------------------ //
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
// //
RsSerialiser *AuthGPG::setupSerialiser() RsSerialiser *AuthPGP::setupSerialiser()
{ {
RsSerialiser *rss = new RsSerialiser ; RsSerialiser *rss = new RsSerialiser ;
rss->addSerialType(new RsGeneralConfigSerialiser()); rss->addSerialType(new RsGeneralConfigSerialiser());
return rss ; return rss ;
} }
bool AuthPGP::isPGPAccepted(const RsPgpId& id)
{
return instance()->mPgpHandler->isGPGAccepted(id);
}
bool AuthGPG::saveList(bool& cleanup, std::list<RsItem*>& lst) bool AuthPGP::saveList(bool& cleanup, std::list<RsItem*>& lst)
{ {
#ifdef GPG_DEBUG #ifdef GPG_DEBUG
std::cerr << "AuthGPG::saveList() called" << std::endl ; std::cerr << "AuthGPG::saveList() called" << std::endl ;
#endif #endif
std::list<RsPgpId> ids ; std::list<RsPgpId> ids ;
getGPGAcceptedList(ids) ; // needs to be done before the lock getPgpAcceptedList(ids) ; // needs to be done before the lock
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/ RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
@ -722,7 +764,7 @@ bool AuthGPG::saveList(bool& cleanup, std::list<RsItem*>& lst)
return true; return true;
} }
bool AuthGPG::loadList(std::list<RsItem*>& load) bool AuthPGP::loadList(std::list<RsItem*>& load)
{ {
#ifdef GPG_DEBUG #ifdef GPG_DEBUG
std::cerr << "AuthGPG::loadList() Item Count: " << load.size() << std::endl; std::cerr << "AuthGPG::loadList() Item Count: " << load.size() << std::endl;
@ -745,7 +787,7 @@ bool AuthGPG::loadList(std::list<RsItem*>& load)
std::list<RsTlvKeyValue>::iterator kit; std::list<RsTlvKeyValue>::iterator kit;
for(kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) for(kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit)
if (kit->key != mOwnGpgId.toStdString()) if (kit->key != mOwnGpgId.toStdString())
PGPHandler::setAcceptConnexion(RsPgpId(kit->key), (kit->value == "TRUE")); instance()->mPgpHandler->setAcceptConnexion(RsPgpId(kit->key), (kit->value == "TRUE"));
} }
delete (*it); delete (*it);
} }
@ -753,16 +795,16 @@ bool AuthGPG::loadList(std::list<RsItem*>& load)
return true; return true;
} }
bool AuthGPG::addService(AuthGPGService *service) bool AuthPGP::addService(AuthGPGService *service)
{ {
RsStackMutex stack(gpgMtxService); /********* LOCKED *********/ RsStackMutex stack(instance()->gpgMtxService); /********* LOCKED *********/
if (std::find(services.begin(), services.end(), service) != services.end()) { if (std::find(instance()->services.begin(), instance()->services.end(), service) != instance()->services.end()) {
/* it exists already! */ /* it exists already! */
return false; return false;
} }
services.push_back(service); instance()->services.push_back(service);
return true; return true;
} }

View File

@ -34,7 +34,7 @@
#include "util/rsthreads.h" #include "util/rsthreads.h"
#include "pqi/p3cfgmgr.h" #include "pqi/p3cfgmgr.h"
#include "pgp/pgphandler.h" #include "pgp/openpgpsdkhandler.h"
#define MAX_GPG_SIGNATURE_SIZE 4096 #define MAX_GPG_SIGNATURE_SIZE 4096
@ -89,7 +89,7 @@ public:
virtual void setGPGOperation(AuthGPGOperation *operation) = 0; virtual void setGPGOperation(AuthGPGOperation *operation) = 0;
}; };
class AuthGPG: public p3Config, public RsTickingThread, public PGPHandler class AuthPGP: public p3Config, public RsTickingThread
{ {
public: public:
static void init(const std::string& path_to_pubring, static void init(const std::string& path_to_pubring,
@ -97,8 +97,11 @@ public:
const std::string& path_to_trustdb, const std::string& path_to_trustdb,
const std::string& pgp_lock_file); const std::string& pgp_lock_file);
static void registerToConfigMgr(const std::string& fname,p3ConfigMgr *CfgMgr);
static void exit(); static void exit();
static AuthGPG *getAuthGPG() { return _instance ; }
static bool isPGPId(const RsPgpId& id) ;
static bool isPGPAccepted(const RsPgpId& id) ;
/** /**
* @param ids list of gpg certificate ids (note, not the actual certificates) * @param ids list of gpg certificate ids (note, not the actual certificates)
@ -118,7 +121,7 @@ public:
* (see storage at the end of the class) * (see storage at the end of the class)
* *
****/ ****/
virtual bool active(); static bool active();
// /* Initialize */ // /* Initialize */
// virtual bool InitAuth (); // virtual bool InitAuth ();
@ -126,8 +129,11 @@ public:
/* Init by generating new Own PGP Cert, or selecting existing PGP Cert */ /* Init by generating new Own PGP Cert, or selecting existing PGP Cert */
virtual int GPGInit(const RsPgpId &ownId); static int PgpInit(const RsPgpId &ownId);
virtual bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString); static bool GeneratePgpCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString);
static bool getPgpDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) ;
static int availablePgpCertificatesWithPrivateKeys(std::list<RsPgpId>& pgpIds);
/*********************************************************************************/ /*********************************************************************************/
/************************* STAGE 3 ***********************************************/ /************************* STAGE 3 ***********************************************/
@ -140,29 +146,33 @@ public:
* provide access to details in cache list. * provide access to details in cache list.
* *
****/ ****/
virtual std::string getGPGName(const RsPgpId &pgp_id,bool *success = NULL); static std::string getPgpName(const RsPgpId &pgp_id,bool *success = NULL);
virtual std::string getGPGEmail(const RsPgpId &pgp_id,bool *success = NULL); static std::string getPgpEmail(const RsPgpId &pgp_id,bool *success = NULL);
static bool exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures );
/* PGP web of trust management */ /* PGP web of trust management */
virtual const RsPgpId& getGPGOwnId(); static const RsPgpId& getPgpOwnId();
virtual std::string getGPGOwnName(); static std::string getPgpOwnName();
//virtual std::string getGPGOwnEmail(); //virtual std::string getGPGOwnEmail();
virtual bool isKeySupported(const RsPgpId &id) const ; static bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) ;
virtual bool haveSecretKey(const RsPgpId &id) const ; static bool isKeySupported(const RsPgpId &id) ;
virtual bool getGPGDetails(const RsPgpId& id, RsPeerDetails &d); static bool isPgpPubKeyAvailable(const RsPgpId& pgp_id);
virtual bool getGPGAllList(std::list<RsPgpId> &ids); static bool haveSecretKey(const RsPgpId &id) ;
virtual bool getGPGValidList(std::list<RsPgpId> &ids); static bool getPgpDetails(const RsPgpId& id, RsPeerDetails &d);
virtual bool getGPGAcceptedList(std::list<RsPgpId> &ids); static bool getPgpAllList(std::list<RsPgpId> &ids);
virtual bool getGPGSignedList(std::list<RsPgpId> &ids); static bool getPgpValidList(std::list<RsPgpId> &ids);
virtual bool importProfile(const std::string& filename,RsPgpId& gpg_id,std::string& import_error) ; static bool getPgpAcceptedList(std::list<RsPgpId> &ids);
virtual bool importProfileFromString(const std::string& data,RsPgpId& gpg_id,std::string& import_error) ; static bool getPgpSignedList(std::list<RsPgpId> &ids);
virtual bool exportProfile(const std::string& filename,const RsPgpId& gpg_id) ; static bool importProfile(const std::string& filename,RsPgpId& gpg_id,std::string& import_error) ;
virtual bool exportIdentityToString( static bool importProfileFromString(const std::string& data,RsPgpId& gpg_id,std::string& import_error) ;
static bool exportProfile(const std::string& filename,const RsPgpId& gpg_id) ;
static bool exportIdentityToString(
std::string& data, const RsPgpId& pgpId, bool includeSignatures, std::string& data, const RsPgpId& pgpId, bool includeSignatures,
std::string& errorMsg ); std::string& errorMsg );
virtual bool removeKeysFromPGPKeyring(const std::set<RsPgpId> &pgp_ids,std::string& backup_file,uint32_t& error_code) ; static bool removeKeysFromPGPKeyring(const std::set<RsPgpId> &pgp_ids,std::string& backup_file,uint32_t& error_code) ;
/*********************************************************************************/ /*********************************************************************************/
/************************* STAGE 4 ***********************************************/ /************************* STAGE 4 ***********************************************/
@ -171,9 +181,9 @@ public:
* STAGE 4: Loading and Saving Certificates. (Strings and Files) * STAGE 4: Loading and Saving Certificates. (Strings and Files)
* *
****/ ****/
virtual bool LoadCertificateFromString(const std::string &pem, RsPgpId& gpg_id,std::string& error_string); static bool LoadCertificateFromString(const std::string &pem, RsPgpId& gpg_id,std::string& error_string);
virtual bool LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string); static bool LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string);
virtual std::string SaveCertificateToString(const RsPgpId &id,bool include_signatures) ; static std::string SaveCertificateToString(const RsPgpId &id,bool include_signatures) ;
// Cached certificates. // Cached certificates.
//bool getCachedGPGCertificate(const RsPgpId &id, std::string &certificate); //bool getCachedGPGCertificate(const RsPgpId &id, std::string &certificate);
@ -188,12 +198,12 @@ public:
* done in gpgroot already. * done in gpgroot already.
* *
****/ ****/
virtual bool AllowConnection(const RsPgpId &gpg_id, bool accept); static bool AllowConnection(const RsPgpId &gpg_id, bool accept);
virtual bool SignCertificateLevel0(const RsPgpId &id); static bool SignCertificateLevel0(const RsPgpId &id);
virtual bool RevokeCertificate(const RsPgpId &id); /* Particularly hard - leave for later */ static bool RevokeCertificate(const RsPgpId &id); /* Particularly hard - leave for later */
virtual bool TrustCertificate(const RsPgpId& id, int trustlvl); //trustlvl is 2 for none, 3 for marginal and 4 for full trust static bool TrustCertificate(const RsPgpId& id, int trustlvl); //trustlvl is 2 for none, 3 for marginal and 4 for full trust
/*********************************************************************************/ /*********************************************************************************/
/************************* STAGE 7 ***********************************************/ /************************* STAGE 7 ***********************************************/
@ -204,39 +214,39 @@ public:
* There should also be Encryption Functions... (do later). * There should also be Encryption Functions... (do later).
* *
****/ ****/
virtual bool SignDataBin(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = ""); static bool SignDataBin(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "");
virtual bool VerifySignBin(const void*, uint32_t, unsigned char*, unsigned int, const PGPFingerprintType& withfingerprint); static bool VerifySignBin(const void*, uint32_t, unsigned char*, unsigned int, const PGPFingerprintType& withfingerprint);
virtual bool parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id); static bool parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id);
virtual bool encryptDataBin(const RsPgpId& pgp_id,const void *data, const uint32_t len, unsigned char *encr, unsigned int *encrlen); static bool encryptDataBin(const RsPgpId& pgp_id,const void *data, const uint32_t len, unsigned char *encr, unsigned int *encrlen);
virtual bool decryptDataBin(const void *data, const uint32_t len, unsigned char *decr, unsigned int *decrlen); static bool decryptDataBin(const void *data, const uint32_t len, unsigned char *decr, unsigned int *decrlen);
virtual bool decryptTextFromFile( std::string& text,const std::string& filename); static bool decryptTextFromFile( std::string& text,const std::string& filename);
virtual bool encryptTextToFile (const std::string& text,const std::string& filename); static bool encryptTextToFile (const std::string& text,const std::string& filename);
// virtual bool decryptTextFromString( std::string& encrypted_text,std::string& clear_string); // virtual bool decryptTextFromString( std::string& encrypted_text,std::string& clear_string);
// virtual bool encryptTextToString (const std::string& pgp_id,const std::string& clear_text,std::string& encrypted_string); // virtual bool encryptTextToString (const std::string& pgp_id,const std::string& clear_text,std::string& encrypted_string);
bool getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&) = NULL) ; static bool getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&) = NULL) ;
//END of PGP public functions //END of PGP public functions
/* GPG service */ /* GPG service */
virtual bool addService(AuthGPGService *service) ; static bool addService(AuthGPGService *service) ;
// This is for debug purpose only. Don't use it !! // This is for debug purpose only. Don't use it !!
static void setAuthGPG_debug(AuthGPG *auth_gpg) { _instance = auth_gpg ; } static void setAuthGPG_debug(AuthPGP *auth_gpg) { _instance = auth_gpg ; }
protected: protected:
AuthGPG(const std::string& path_to_pubring, const std::string& path_to_secring,const std::string& path_to_trustdb,const std::string& pgp_lock_file); AuthPGP(const std::string& path_to_pubring, const std::string& path_to_secring,const std::string& path_to_trustdb,const std::string& pgp_lock_file);
virtual ~AuthGPG(); virtual ~AuthPGP();
/*****************************************************************/ /*****************************************************************/
/*********************** p3config ******************************/ /*********************** p3config ******************************/
/* Key Functions to be overloaded for Full Configuration */ /* Key Functions to be overloaded for Full Configuration */
virtual RsSerialiser *setupSerialiser(); virtual RsSerialiser *setupSerialiser() override;
virtual bool saveList(bool &cleanup, std::list<RsItem *>&); virtual bool saveList(bool &cleanup, std::list<RsItem *>&) override;
virtual bool loadList(std::list<RsItem *>& load); virtual bool loadList(std::list<RsItem *>& load) override;
/*****************************************************************/ /*****************************************************************/
private: private:
@ -274,8 +284,7 @@ private:
void threadTick() override; /// @see RsTickingThread void threadTick() override; /// @see RsTickingThread
private: private:
static AuthPGP *instance();
static AuthGPG *instance_gpg; // pointeur vers le singleton
RsMutex gpgMtxService; RsMutex gpgMtxService;
RsMutex gpgMtxEngine; RsMutex gpgMtxEngine;
@ -290,6 +299,8 @@ private:
rstime_t mStoreKeyTime; rstime_t mStoreKeyTime;
PGPHandler *mPgpHandler;
RsPgpId mOwnGpgId; RsPgpId mOwnGpgId;
bool gpgKeySelected; bool gpgKeySelected;
bool _force_sync_database ; bool _force_sync_database ;
@ -297,7 +308,7 @@ private:
std::list<AuthGPGService*> services ; std::list<AuthGPGService*> services ;
static AuthGPG *_instance ; static AuthPGP *_instance ;
}; };
#endif #endif

View File

@ -759,8 +759,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
//long version = 0x00; //long version = 0x00;
unsigned long chtype = MBSTRING_UTF8; unsigned long chtype = MBSTRING_UTF8;
X509_NAME *issuer_name = X509_NAME_new(); X509_NAME *issuer_name = X509_NAME_new();
X509_NAME_add_entry_by_txt(issuer_name, "CN", chtype, X509_NAME_add_entry_by_txt(issuer_name, "CN", chtype, (unsigned char *) AuthPGP::getPgpOwnId().toStdString().c_str(), -1, -1, 0);
(unsigned char *) AuthGPG::getAuthGPG()->getGPGOwnId().toStdString().c_str(), -1, -1, 0);
/**** /****
X509_NAME_add_entry_by_NID(issuer_name, 48, 0, X509_NAME_add_entry_by_NID(issuer_name, 48, 0,
(unsigned char *) "email@email.com", -1, -1, 0); (unsigned char *) "email@email.com", -1, -1, 0);
@ -770,7 +769,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
(unsigned char *) "loc", -1, -1, 0); (unsigned char *) "loc", -1, -1, 0);
****/ ****/
std::cerr << "AuthSSLimpl::SignX509Req() Issuer name: " << AuthGPG::getAuthGPG()->getGPGOwnId().toStdString() << std::endl; std::cerr << "AuthSSLimpl::SignX509Req() Issuer name: " << AuthPGP::getPgpOwnId().toStdString() << std::endl;
#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_002 #ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_002
static const uint64_t CERTIFICATE_SERIAL_NUMBER = RS_CERTIFICATE_VERSION_NUMBER_07_0001 ; static const uint64_t CERTIFICATE_SERIAL_NUMBER = RS_CERTIFICATE_VERSION_NUMBER_07_0001 ;
@ -945,7 +944,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
std::cerr << "Buffers Allocated" << std::endl; std::cerr << "Buffers Allocated" << std::endl;
/* NOW Sign via GPG Functions */ /* NOW Sign via GPG Functions */
if (!AuthGPG::getAuthGPG()->SignDataBin(buf_in, inl, buf_sigout, (unsigned int *) &sigoutl,"AuthSSLimpl::SignX509ReqWithGPG()")) if (!AuthPGP::SignDataBin(buf_in, inl, buf_sigout, (unsigned int *) &sigoutl,"AuthSSLimpl::SignX509ReqWithGPG()"))
{ {
sigoutl = 0; sigoutl = 0;
goto err; goto err;
@ -1040,7 +1039,7 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,bool verbose, uint32_t& diagnostic)
{ {
RsPgpId issuer = RsX509Cert::getCertIssuer(*x509); RsPgpId issuer = RsX509Cert::getCertIssuer(*x509);
RsPeerDetails pd; RsPeerDetails pd;
if (!AuthGPG::getAuthGPG()->getGPGDetails(issuer, pd)) if (!AuthPGP::getPgpDetails(issuer, pd))
{ {
RsInfo() << __PRETTY_FUNCTION__ << " X509 NOT authenticated : " RsInfo() << __PRETTY_FUNCTION__ << " X509 NOT authenticated : "
<< "AuthGPG::getAuthGPG()->getGPGDetails(" << issuer << "AuthGPG::getAuthGPG()->getGPGDetails(" << issuer
@ -1185,9 +1184,7 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,bool verbose, uint32_t& diagnostic)
// passed, verify the signature itself // passed, verify the signature itself
if (!AuthGPG::getAuthGPG()->VerifySignBin( if (!AuthPGP::VerifySignBin( signed_data, signed_data_length, signature->data, static_cast<unsigned int>(signature->length), pd.fpr ))
signed_data, signed_data_length, signature->data,
static_cast<unsigned int>(signature->length), pd.fpr ))
{ {
diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE; diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE;
goto err; goto err;
@ -1383,7 +1380,7 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx)
std::cerr << "******* VerifyX509Callback cert: " << std::hex << ctx->cert <<std::dec << std::endl; std::cerr << "******* VerifyX509Callback cert: " << std::hex << ctx->cert <<std::dec << std::endl;
#endif #endif
if ( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && !AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) ) if ( !isSslOnlyFriend && pgpId != AuthPGP::getPgpOwnId() && !AuthPGP::isPGPAccepted(pgpId) )
{ {
std::string errMsg = "Connection attempt signed by PGP key id: " + std::string errMsg = "Connection attempt signed by PGP key id: " +
pgpId.toStdString() + " not accepted because it is not" pgpId.toStdString() + " not accepted because it is not"

View File

@ -812,11 +812,11 @@ int p3PeerMgrIMPL::getFriendCount(bool ssl, bool online)
// count all gpg id's // count all gpg id's
std::list<RsPgpId> gpgIds; std::list<RsPgpId> gpgIds;
AuthGPG::getAuthGPG()->getGPGAcceptedList(gpgIds); AuthPGP::getPgpAcceptedList(gpgIds);
// add own gpg id, if we have more than one location // add own gpg id, if we have more than one location
std::list<RsPeerId> ownSslIds; std::list<RsPeerId> ownSslIds;
getAssociatedPeers(AuthGPG::getAuthGPG()->getGPGOwnId(), ownSslIds); getAssociatedPeers(AuthPGP::getPgpOwnId(), ownSslIds);
return gpgIds.size() + ((ownSslIds.size() > 0) ? 1 : 0); return gpgIds.size() + ((ownSslIds.size() > 0) ? 1 : 0);
} }
@ -962,7 +962,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg
// check that the PGP key is known // check that the PGP key is known
if(!AuthGPG::getAuthGPG()->isGPGId(gpg_id)) if(!AuthPGP::isPGPId(gpg_id))
{ {
RsErr() << "Trying to add SSL id (" << id << ") to be validated with unknown PGP key (" << gpg_id << ". This is a bug!" << std::endl; RsErr() << "Trying to add SSL id (" << id << ") to be validated with unknown PGP key (" << gpg_id << ". This is a bug!" << std::endl;
return false; return false;
@ -970,7 +970,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg
//Authentication is now tested at connection time, we don't store the ssl cert anymore //Authentication is now tested at connection time, we don't store the ssl cert anymore
// //
if (!AuthGPG::getAuthGPG()->isGPGAccepted(gpg_id) && gpg_id != AuthGPG::getAuthGPG()->getGPGOwnId()) if (!AuthPGP::isPGPAccepted(gpg_id) && gpg_id != AuthPGP::getPgpOwnId())
{ {
#ifdef PEER_DEBUG #ifdef PEER_DEBUG
std::cerr << "p3PeerMgrIMPL::addFriend() gpg is not accepted" << std::endl; std::cerr << "p3PeerMgrIMPL::addFriend() gpg is not accepted" << std::endl;
@ -1024,7 +1024,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg
pstate.id = id; pstate.id = id;
pstate.gpg_id = gpg_id; pstate.gpg_id = gpg_id;
pstate.name = AuthGPG::getAuthGPG()->getGPGName(gpg_id); pstate.name = AuthPGP::getPgpName(gpg_id);
pstate.vs_disc = vs_disc; pstate.vs_disc = vs_disc;
pstate.vs_dht = vs_dht; pstate.vs_dht = vs_dht;
@ -1126,8 +1126,8 @@ bool p3PeerMgrIMPL::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_
* superficially set to true the PGP signature verification would have been * superficially set to true the PGP signature verification would have been
* skipped and the attacker connection would be accepted. * skipped and the attacker connection would be accepted.
* If the PGP key is available add it as full friend. */ * If the PGP key is available add it as full friend. */
if(AuthGPG::getAuthGPG()->isPgpPubKeyAvailable(pgp_id)) if(AuthPGP::isPgpPubKeyAvailable(pgp_id))
AuthGPG::getAuthGPG()->AllowConnection(pgp_id, true); AuthPGP::AllowConnection(pgp_id, true);
else else
pstate.skip_pgp_signature_validation = true; pstate.skip_pgp_signature_validation = true;
@ -2470,7 +2470,7 @@ bool p3PeerMgrIMPL::loadList(std::list<RsItem *>& load)
setOwnNetworkMode(pitem->netMode); setOwnNetworkMode(pitem->netMode);
setOwnVisState(pitem->vs_disc, pitem->vs_dht); setOwnVisState(pitem->vs_disc, pitem->vs_dht);
mOwnState.gpg_id = AuthGPG::getAuthGPG()->getGPGOwnId(); mOwnState.gpg_id = AuthPGP::getPgpOwnId();
mOwnState.location = AuthSSL::getAuthSSL()->getOwnLocation(); mOwnState.location = AuthSSL::getAuthSSL()->getOwnLocation();
} }
else else
@ -2642,7 +2642,7 @@ bool p3PeerMgrIMPL::loadList(std::list<RsItem *>& load)
#endif #endif
for(uint32_t i=0;i<sitem->pgp_ids.size();++i) for(uint32_t i=0;i<sitem->pgp_ids.size();++i)
if(AuthGPG::getAuthGPG()->isGPGAccepted(sitem->pgp_ids[i]) || sitem->pgp_ids[i] == AuthGPG::getAuthGPG()->getGPGOwnId()) if(AuthPGP::isPGPAccepted(sitem->pgp_ids[i]) || sitem->pgp_ids[i] == AuthPGP::getPgpOwnId())
{ {
mFriendsPermissionFlags[sitem->pgp_ids[i]] = sitem->service_flags[i] ; mFriendsPermissionFlags[sitem->pgp_ids[i]] = sitem->service_flags[i] ;
#ifdef PEER_DEBUG #ifdef PEER_DEBUG
@ -2684,7 +2684,7 @@ bool p3PeerMgrIMPL::loadList(std::list<RsItem *>& load)
for(auto group_pair:groupList) for(auto group_pair:groupList)
{ {
for(auto profileIdIt(group_pair.second.peerIds.begin());profileIdIt!=group_pair.second.peerIds.end();) for(auto profileIdIt(group_pair.second.peerIds.begin());profileIdIt!=group_pair.second.peerIds.end();)
if(AuthGPG::getAuthGPG()->isGPGAccepted(*profileIdIt) || *profileIdIt == AuthGPG::getAuthGPG()->getGPGOwnId()) if(AuthPGP::isPGPAccepted(*profileIdIt) || *profileIdIt == AuthPGP::getPgpOwnId())
++profileIdIt; ++profileIdIt;
else else
{ {

View File

@ -0,0 +1,341 @@
/*******************************************************************************
* libretroshare/src/file_sharing: fsbio.cc *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2021 by 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 Lesser 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
******************************************************************************/
#include "util/rsprint.h"
#include "util/rsfile.h"
#include "pqi/pqifdbin.h"
RsFdBinInterface::RsFdBinInterface(int file_descriptor, bool is_socket)
: mCLintConnt(file_descriptor),mIsSocket(is_socket),mIsActive(false)
{
mTotalReadBytes=0;
mTotalInBufferBytes=0;
mTotalWrittenBytes=0;
mTotalOutBufferBytes=0;
if(file_descriptor!=0)
setSocket(file_descriptor);
}
void RsFdBinInterface::setSocket(int s)
{
if(mIsActive != 0)
{
RsErr() << "Changing socket to active FsBioInterface! Canceling all pending R/W data." ;
close();
}
#ifndef WINDOWS_SYS
int flags = fcntl(s,F_GETFL);
if(!(flags & O_NONBLOCK))
{
RsWarn() << "Trying to use a blocking file descriptor in RsFdBinInterface. This is not going to work! Setting the socket to be non blocking.";
unix_fcntl_nonblock(s);
}
#else
// On windows, there is no way to determine whether a socket is blocking or not, so we set it to non blocking whatsoever.
if (mIsSocket) {
unix_fcntl_nonblock(s);
} else {
RsFileUtil::set_fd_nonblock(s);
}
#endif
mCLintConnt = s;
mIsActive = (s!=0);
}
int RsFdBinInterface::tick()
{
if(!mIsActive)
{
RsErr() << "Ticking a non active FsBioInterface!" ;
return 0;
}
// 2 - read incoming data pending on existing connections
int res=0;
res += read_pending();
res += write_pending();
return res;
}
int RsFdBinInterface::read_pending()
{
char inBuffer[1025];
memset(inBuffer,0,1025);
ssize_t readbytes;
#if WINDOWS_SYS
if (mIsSocket)
// Windows needs recv for sockets
readbytes = recv(mCLintConnt, inBuffer, sizeof(inBuffer), 0);
else
#endif
readbytes = read(mCLintConnt, inBuffer, sizeof(inBuffer)); // Needs read instead of recv which is only for sockets.
// Sockets should be set to non blocking by the client process.
if(readbytes == 0)
{
RsDbg() << "Reached END of the stream!" ;
RsDbg() << "Closing!" ;
close();
return mTotalInBufferBytes;
}
if(readbytes < 0)
{
if(errno != 0 && errno != EWOULDBLOCK && errno != EAGAIN)
#ifdef WINDOWS_SYS
// A non blocking read to file descriptor gets ERROR_NO_DATA for empty data
if (mIsSocket == true || GetLastError() != ERROR_NO_DATA)
#endif
RsErr() << "read() failed. Errno=" << errno ;
return mTotalInBufferBytes;
}
#ifdef DEBUG_FS_BIN
RsDbg() << "clintConnt: " << mCLintConnt << ", readbytes: " << readbytes ;
#endif
// display some debug info
if(readbytes > 0)
{
#ifdef DEBUG_FS_BIN
RsDbg() << "Received the following bytes: " << RsUtil::BinToHex( reinterpret_cast<unsigned char*>(inBuffer),readbytes,50) << std::endl;
RsDbg() << "Received the following bytes: " << std::string(inBuffer,readbytes) << std::endl;
#endif
void *ptr = malloc(readbytes);
if(!ptr)
throw std::runtime_error("Cannot allocate memory! Go buy some RAM!");
memcpy(ptr,inBuffer,readbytes);
in_buffer.push_back(std::make_pair(ptr,readbytes));
mTotalInBufferBytes += readbytes;
mTotalReadBytes += readbytes;
#ifdef DEBUG_FS_BIN
RsDbg() << "Socket: " << mCLintConnt << ". Total read: " << mTotalReadBytes << ". Buffer size: " << mTotalInBufferBytes ;
#endif
}
return mTotalInBufferBytes;
}
int RsFdBinInterface::write_pending()
{
if(out_buffer.empty())
return mTotalOutBufferBytes;
auto& p = out_buffer.front();
int written;
#if WINDOWS_SYS
if (mIsSocket)
// Windows needs send for sockets
written = send(mCLintConnt, (char*) p.first, p.second, 0);
else
#endif
written = write(mCLintConnt, p.first, p.second);
if(written < 0)
{
if(errno != EWOULDBLOCK && errno != EAGAIN)
RsErr() << "write() failed. Errno=" << errno ;
return mTotalOutBufferBytes;
}
if(written == 0)
{
RsErr() << "write() failed. Nothing sent.";
return mTotalOutBufferBytes;
}
#ifdef DEBUG_FS_BIN
RsDbg() << "clintConnt: " << mCLintConnt << ", written: " << written ;
#endif
// display some debug info
#ifdef DEBUG_FS_BIN
RsDbg() << "Sent the following bytes: " << RsUtil::BinToHex( reinterpret_cast<unsigned char*>(p.first),written,50) << std::endl;
#endif
if(written < p.second)
{
void *ptr = malloc(p.second - written);
if(!ptr)
throw std::runtime_error("Cannot allocate memory! Go buy some RAM!");
memcpy(ptr,static_cast<unsigned char *>(p.first) + written,p.second - written);
free(p.first);
out_buffer.front().first = ptr;
out_buffer.front().second = p.second - written;
}
else
{
free(p.first);
out_buffer.pop_front();
}
mTotalOutBufferBytes -= written;
mTotalWrittenBytes += written;
return mTotalOutBufferBytes;
}
RsFdBinInterface::~RsFdBinInterface()
{
clean();
}
void RsFdBinInterface::clean()
{
for(auto p:in_buffer) free(p.first);
for(auto p:out_buffer) free(p.first);
in_buffer.clear();
out_buffer.clear();
}
int RsFdBinInterface::readline(void *data, int len)
{
int n=0;
for(auto p:in_buffer)
for(int i=0;i<p.second;++i,++n)
if((n+1==len) || static_cast<unsigned char*>(p.first)[i] == '\n')
return readdata(data,n+1);
return 0;
}
int RsFdBinInterface::readdata(void *data, int len)
{
// read incoming bytes in the buffer
int total_len = 0;
while(total_len < len)
{
if(in_buffer.empty())
{
mTotalInBufferBytes -= total_len;
return total_len;
}
// If the remaining buffer is too large, chop of the beginning of it.
if(total_len + in_buffer.front().second > len)
{
memcpy(&(static_cast<unsigned char *>(data)[total_len]),in_buffer.front().first,len - total_len);
void *ptr = malloc(in_buffer.front().second - (len - total_len));
memcpy(ptr,&(static_cast<unsigned char*>(in_buffer.front().first)[len - total_len]),in_buffer.front().second - (len - total_len));
free(in_buffer.front().first);
in_buffer.front().first = ptr;
in_buffer.front().second -= len-total_len;
mTotalInBufferBytes -= len;
return len;
}
else // copy everything
{
memcpy(&(static_cast<unsigned char *>(data)[total_len]),in_buffer.front().first,in_buffer.front().second);
total_len += in_buffer.front().second;
free(in_buffer.front().first);
in_buffer.pop_front();
}
}
mTotalInBufferBytes -= len;
return len;
}
int RsFdBinInterface::senddata(void *data, int len)
{
// shouldn't we better send in multiple packets, similarly to how we read?
if(len == 0)
{
RsErr() << "Calling FsBioInterface::senddata() with null size or null data pointer";
return 0;
}
void *ptr = malloc(len);
if(!ptr)
{
RsErr() << "Cannot allocate data of size " << len ;
return 0;
}
memcpy(ptr,data,len);
out_buffer.push_back(std::make_pair(ptr,len));
mTotalOutBufferBytes += len;
return len;
}
int RsFdBinInterface::netstatus()
{
return mIsActive; // dummy response.
}
int RsFdBinInterface::isactive()
{
return mIsActive ;
}
bool RsFdBinInterface::moretoread(uint32_t /* usec */)
{
return mTotalInBufferBytes > 0;
}
bool RsFdBinInterface::moretowrite(uint32_t /* usec */)
{
return mTotalOutBufferBytes > 0 ;
}
bool RsFdBinInterface::cansend(uint32_t)
{
return isactive();
}
int RsFdBinInterface::close()
{
RsDbg() << "Stopping network interface" << std::endl;
mIsActive = false;
mCLintConnt = 0;
clean();
return 1;
}

View File

@ -0,0 +1,83 @@
/*******************************************************************************
* libretroshare/src/file_sharing: fsbio.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2021 by 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 Lesser 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
******************************************************************************/
#include "pqi/pqi_base.h"
class RsFdBinInterface: public BinInterface
{
public:
RsFdBinInterface(int file_descriptor, bool is_socket);
~RsFdBinInterface();
// Implements BinInterface methods
int tick() override;
// Schedule data to be sent at the next tick(). The caller keeps memory ownership.
//
int senddata(void *data, int len) override;
// Obtains new data from the interface. "data" needs to be initialized for room
// to len bytes. The returned value is the actual size of what was read.
//
int readdata(void *data, int len) override;
// Read at most len bytes only if \n is encountered within that range. Otherwise, nothing is changed.
//
int readline(void *data, int len) ;
int netstatus() override;
int isactive() override;
bool moretoread(uint32_t usec) override;
bool moretowrite(uint32_t usec) ;
bool cansend(uint32_t usec) override;
int close() override;
/**
* If hashing data
**/
RsFileHash gethash() override { return RsFileHash() ; }
uint64_t bytecount() override { return mTotalReadBytes; }
bool bandwidthLimited() override { return false; }
protected:
void setSocket(int s);
void clean();
private:
int read_pending();
int write_pending();
int mCLintConnt;
bool mIsSocket;
bool mIsActive;
uint32_t mTotalReadBytes;
uint32_t mTotalInBufferBytes;
uint32_t mTotalWrittenBytes;
uint32_t mTotalOutBufferBytes;
std::list<std::pair<void *,int> > in_buffer;
std::list<std::pair<void *,int> > out_buffer;
};

View File

@ -273,7 +273,6 @@ int inet_aton(const char *name, struct in_addr *addr)
#ifdef WINDOWS_SYS #ifdef WINDOWS_SYS
# include <winsock2.h> # include <winsock2.h>
# include <iphlpapi.h> # include <iphlpapi.h>
# pragma comment(lib, "IPHLPAPI.lib")
#elif defined(__ANDROID__) && __ANDROID_API__ < 24 #elif defined(__ANDROID__) && __ANDROID_API__ < 24
/// @See: android_ifaddrs/README.adoc /// @See: android_ifaddrs/README.adoc
# include "rs_android/ifaddrs-android.h" # include "rs_android/ifaddrs-android.h"

View File

@ -23,22 +23,6 @@
#include "util/rsdebug.h" #include "util/rsdebug.h"
#include "util/rsstring.h" #include "util/rsstring.h"
#include <sstream>
#include <sys/time.h>
static double getCurrentTS()
{
#ifndef WINDOWS_SYS
struct timeval cts_tmp;
gettimeofday(&cts_tmp, NULL);
double cts = (cts_tmp.tv_sec) + ((double) cts_tmp.tv_usec) / 1000000.0;
#else
struct _timeb timebuf;
_ftime( &timebuf);
double cts = (timebuf.time) + ((double) timebuf.millitm) / 1000.0;
#endif
return cts;
}
#ifdef SERVICE_DEBUG #ifdef SERVICE_DEBUG
const int pqiservicezone = 60478; const int pqiservicezone = 60478;
#endif #endif

View File

@ -1213,8 +1213,7 @@ int pqissl::Authorise_SSL_Connection()
} }
RsPgpId pgpId = RsX509Cert::getCertIssuer(*peercert); RsPgpId pgpId = RsX509Cert::getCertIssuer(*peercert);
if( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && if( !isSslOnlyFriend && pgpId != AuthPGP::getPgpOwnId() && !AuthPGP::isPGPAccepted(pgpId) )
!AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) )
{ {
RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId
<< " is not friend. It is very unlikely to happen at this " << " is not friend. It is very unlikely to happen at this "

View File

@ -797,8 +797,7 @@ int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info)
exit(failure); exit(failure);
} }
if( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && if( !isSslOnlyFriend && pgpId != AuthPGP::getPgpOwnId() && !AuthPGP::isPGPAccepted(pgpId) )
!AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) )
{ {
RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId
<< " is not friend. It is very unlikely to happen at this " << " is not friend. It is very unlikely to happen at this "

View File

@ -586,9 +586,9 @@ bool pqisslproxy::connect_parameter(uint32_t type, const std::string &value)
if (type == NET_PARAM_CONNECT_DOMAIN_ADDRESS) if (type == NET_PARAM_CONNECT_DOMAIN_ADDRESS)
{ {
#ifdef PROXY_DEBUG_LOG
std::string out; std::string out;
rs_sprintf(out, "pqisslproxy::connect_parameter() Peer: %s DOMAIN_ADDRESS: %s", PeerId().toStdString().c_str(), value.c_str()); rs_sprintf(out, "pqisslproxy::connect_parameter() Peer: %s DOMAIN_ADDRESS: %s", PeerId().toStdString().c_str(), value.c_str());
#ifdef PROXY_DEBUG_LOG
rslog(RSL_WARNING, pqisslproxyzone, out); rslog(RSL_WARNING, pqisslproxyzone, out);
#endif #endif
mDomainAddress = value; mDomainAddress = value;

View File

@ -0,0 +1,100 @@
/******************************* BEGIN WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#else
#include <ws2tcpip.h>
// Missing defines in MinGW
#ifndef MSG_WAITALL
#define MSG_WAITALL 8
#endif
#endif
/********************************* END WINDOWS/UNIX SPECIFIC PART ******************/
#include <string.h>
#include <iostream>
#include "rstcpsocket.h"
RsTcpSocket::RsTcpSocket(const std::string& tcp_address,uint16_t tcp_port)
:RsFdBinInterface(0, true),mState(DISCONNECTED),mConnectAddress(tcp_address),mConnectPort(tcp_port),mSocket(0)
{
}
RsTcpSocket::RsTcpSocket()
:RsFdBinInterface(0, true),mState(DISCONNECTED),mConnectAddress("0.0.0.0"),mConnectPort(0),mSocket(0)
{
}
bool RsTcpSocket::connect(const std::string& tcp_address,uint16_t tcp_port)
{
if(mState == CONNECTED)
close();
mConnectPort = tcp_port;
mConnectAddress = tcp_address;
return connect();
}
bool RsTcpSocket::connect()
{
int CreateSocket = 0;
char dataReceived[1024];
struct sockaddr_in ipOfServer;
memset(dataReceived, '0' ,sizeof(dataReceived));
if((CreateSocket = socket(AF_INET, SOCK_STREAM, 0))< 0)
{
printf("Socket not created \n");
return false;
}
ipOfServer.sin_family = AF_INET;
ipOfServer.sin_port = htons(mConnectPort);
ipOfServer.sin_addr.s_addr = inet_addr(mConnectAddress.c_str());
if(::connect(CreateSocket, (struct sockaddr *)&ipOfServer, sizeof(ipOfServer))<0)
{
printf("Connection failed due to port and ip problems, or server is not available. Socket=%d,ConnectPort=%d,ConnectAddress=%s Errno=%d\n",mSocket,mConnectPort,mConnectAddress.c_str(),errno);
return false;
}
mState = CONNECTED;
unix_fcntl_nonblock(CreateSocket);
setSocket(CreateSocket);
return true;
}
int RsTcpSocket::close()
{
RsFdBinInterface::close();
mState = DISCONNECTED;
return !::close(mSocket);
}
RsThreadedTcpSocket::RsThreadedTcpSocket(const std::string& tcp_address,uint16_t tcp_port)
: RsTcpSocket(tcp_address,tcp_port)
{
}
RsThreadedTcpSocket::RsThreadedTcpSocket() : RsTcpSocket()
{
}
void RsThreadedTcpSocket::run()
{
while(!shouldStop() && connectionState() == CONNECTED)
{
tick();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
RsWarn() << "Connection to " << connectAddress() << ":" << connectPort() << " is now closed.";
}
RsThreadedTcpSocket::~RsThreadedTcpSocket()
{
fullstop(); // fully wait for stopping.
close();
}

View File

@ -0,0 +1,46 @@
#include <string>
#include "util/rsthreads.h"
#include "pqi/pqifdbin.h"
class RsTcpSocket: public RsFdBinInterface
{
public:
RsTcpSocket(const std::string& tcp_address,uint16_t tcp_port);
RsTcpSocket();
virtual ~RsTcpSocket()=default;
enum State: uint8_t {
UNKNOWN = 0x00,
DISCONNECTED = 0x01,
CONNECTED = 0x02
};
// Return true when OK, false otherwise.
bool connect();
bool connect(const std::string& tcp_address,uint16_t tcp_port);
// Returns 1 when OK, 0 otherwise.
int close();
State connectionState() const { return mState; }
const std::string& connectAddress() const { return mConnectAddress ; }
uint16_t connectPort() const { return mConnectPort ; }
private:
State mState;
std::string mConnectAddress;
uint16_t mConnectPort;
int mSocket;
};
class RsThreadedTcpSocket: public RsTcpSocket, public RsThread
{
public:
RsThreadedTcpSocket(const std::string& tcp_address,uint16_t tcp_port);
RsThreadedTcpSocket();
virtual ~RsThreadedTcpSocket();
virtual void run() override;
};

View File

@ -103,9 +103,15 @@ enum class RsEventType : uint32_t
/// @see rspeers.h /// @see rspeers.h
NETWORK = 16, NETWORK = 16,
/// @see RsMailTagEvent
MAIL_TAG = 17,
/** Emitted to update library clients about file hashing being completed */ /** Emitted to update library clients about file hashing being completed */
FILE_HASHING_COMPLETED = 20, FILE_HASHING_COMPLETED = 20,
/// @see rspeers.h
TOR_MANAGER = 21,
__MAX /// Used internally, keep last __MAX /// Used internally, keep last
}; };

View File

@ -159,6 +159,7 @@ public:
ERR_ALREADY_RUNNING, /// Another istance is running already ERR_ALREADY_RUNNING, /// Another istance is running already
ERR_CANT_ACQUIRE_LOCK, /// Another istance is already running? ERR_CANT_ACQUIRE_LOCK, /// Another istance is already running?
ERR_NO_AVAILABLE_ACCOUNT, /// Used in retroshare-service -U list when no account is available ERR_NO_AVAILABLE_ACCOUNT, /// Used in retroshare-service -U list when no account is available
ERR_CANNOT_CONFIGURE_TOR, /// cannot start/configure Tor for an auto-tor node
ERR_UNKNOWN /// Unkown error, maybe password is wrong? ERR_UNKNOWN /// Unkown error, maybe password is wrong?
}; };
@ -184,6 +185,7 @@ public:
static bool isPortable(); static bool isPortable();
static bool isWindowsXP(); static bool isWindowsXP();
static bool collectEntropy(uint32_t bytes) ; static bool collectEntropy(uint32_t bytes) ;
static bool startAutoTor();
/*! /*!
* \brief lockFilePath * \brief lockFilePath
@ -218,6 +220,7 @@ public:
static void setAutoLogin(bool autoLogin); static void setAutoLogin(bool autoLogin);
static bool RsClearAutoLogin() ; static bool RsClearAutoLogin() ;
static std::string executablePath() ;
private: private:
/** @brief Lock profile directory /** @brief Lock profile directory
* param[in] accountDir account directory to lock * param[in] accountDir account directory to lock

View File

@ -308,6 +308,9 @@ enum class RsMailStatusEventCode: uint8_t
/// An error occurred attempting to sign the message /// An error occurred attempting to sign the message
SIGNATURE_FAILED = 0x04, SIGNATURE_FAILED = 0x04,
MESSAGE_CHANGED = 0x05,
TAG_CHANGED = 0x06,
}; };
struct RsMailStatusEvent : RsEvent struct RsMailStatusEvent : RsEvent
@ -329,6 +332,32 @@ struct RsMailStatusEvent : RsEvent
~RsMailStatusEvent() override = default; ~RsMailStatusEvent() override = default;
}; };
enum class RsMailTagEventCode: uint8_t
{
TAG_ADDED = 0x00,
TAG_CHANGED = 0x01,
TAG_REMOVED = 0x02,
};
struct RsMailTagEvent : RsEvent
{
RsMailTagEvent() : RsEvent(RsEventType::MAIL_TAG) {}
RsMailTagEventCode mMailTagEventCode;
std::set<std::string> mChangedMsgTagIds;
/// @see RsEvent
void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx) override
{
RsEvent::serial_process(j, ctx);
RS_SERIAL_PROCESS(mChangedMsgTagIds);
RS_SERIAL_PROCESS(mMailTagEventCode);
}
~RsMailTagEvent() override = default;
};
#define RS_CHAT_PUBLIC 0x0001 #define RS_CHAT_PUBLIC 0x0001
#define RS_CHAT_PRIVATE 0x0002 #define RS_CHAT_PRIVATE 0x0002
#define RS_CHAT_AVATAR_AVAILABLE 0x0004 #define RS_CHAT_AVATAR_AVAILABLE 0x0004

View File

@ -128,14 +128,12 @@ const uint32_t RS_MESSAGE_CONNECT_ATTEMPT = 0x0001;
const int NOTIFY_LIST_NEIGHBOURS = 1; const int NOTIFY_LIST_NEIGHBOURS = 1;
const int NOTIFY_LIST_FRIENDS = 2; const int NOTIFY_LIST_FRIENDS = 2;
const int NOTIFY_LIST_SEARCHLIST = 4; const int NOTIFY_LIST_SEARCHLIST = 4;
const int NOTIFY_LIST_MESSAGELIST = 5;
const int NOTIFY_LIST_CHANNELLIST = 6; const int NOTIFY_LIST_CHANNELLIST = 6;
const int NOTIFY_LIST_TRANSFERLIST = 7; const int NOTIFY_LIST_TRANSFERLIST = 7;
const int NOTIFY_LIST_CONFIG = 8; const int NOTIFY_LIST_CONFIG = 8;
const int NOTIFY_LIST_DIRLIST_LOCAL = 9; const int NOTIFY_LIST_DIRLIST_LOCAL = 9;
const int NOTIFY_LIST_DIRLIST_FRIENDS = 10; const int NOTIFY_LIST_DIRLIST_FRIENDS = 10;
const int NOTIFY_LIST_FORUMLIST_LOCKED = 11; // use connect with Qt::QueuedConnection const int NOTIFY_LIST_FORUMLIST_LOCKED = 11; // use connect with Qt::QueuedConnection
const int NOTIFY_LIST_MESSAGE_TAGS = 12;
const int NOTIFY_LIST_PUBLIC_CHAT = 13; const int NOTIFY_LIST_PUBLIC_CHAT = 13;
const int NOTIFY_LIST_PRIVATE_INCOMING_CHAT = 14; const int NOTIFY_LIST_PRIVATE_INCOMING_CHAT = 14;
const int NOTIFY_LIST_PRIVATE_OUTGOING_CHAT = 15; const int NOTIFY_LIST_PRIVATE_OUTGOING_CHAT = 15;

View File

@ -0,0 +1,182 @@
#pragma once
// This code stands as an interface for the automatic configuration
// of Tor hidden services to be used by retroshare.
//
// The correct way to use it is to:
//
// 1 - properly set data and hidden service directories. This allowd the TorManager
// to save its keys for the hidden service, or to load one that has previously been created
//
// 2 - call setupHiddenService(). This creates/loads the hidden service.
//
// 3 - call RsTor::start()
//
// 4 - loop/wait until RsTor::getHiddenServiceStatus(service_id)
// returns RsTorHiddenServiceStatus::ONLINE
//
// 5 - call RsTor::getHiddenserviceInfo to properly setup RS internal ports and addresses:
//
// RsTor::getHiddenServiceInfo(service_id,onion_address,service_port,service_target_address,service_target_port);
// RsTor::getProxyServerInfo(proxy_server_address,proxy_server_port) ;
//
// rsPeers->setLocalAddress(rsPeers->getOwnId(), service_target_address, service_target_port);
// rsPeers->setHiddenNode(rsPeers->getOwnId(), onion_address, service_port);
// rsPeers->setProxyServer(RS_HIDDEN_TYPE_TOR, proxy_server_address,proxy_server_port) ;
#include "retroshare/rsevents.h"
namespace Tor {
class TorManager;
}
enum class RsTorManagerEventCode: uint8_t
{
UNKNOWN = 0x00,
TOR_STATUS_CHANGED = 0x01,
BOOTSTRAP_STATUS_CHANGED = 0x02,
TOR_CONNECTIVITY_CHANGED = 0x03,
TOR_MANAGER_ERROR = 0x04,
CONFIGURATION_NEEDED = 0x05,
TOR_MANAGER_STOPPED = 0x06,
};
// Status of the Tor hidden service setup/loaded by RS
enum class RsTorHiddenServiceStatus: uint8_t {
ERROR = 0x00,
NOT_CREATED = 0x01,
OFFLINE = 0x02,
ONLINE = 0x03
};
// Status of the connection/authentication between RS and the Tor service
enum class RsTorConnectivityStatus: uint8_t {
ERROR = 0x00,
NOT_CONNECTED = 0x01,
CONNECTING = 0x02,
SOCKET_CONNECTED = 0x03,
AUTHENTICATING = 0x04,
AUTHENTICATED = 0x05,
HIDDEN_SERVICE_READY = 0x06,
UNKNOWN = 0x07
};
// Status of the Tor service with which RS is talking.
enum class RsTorStatus: uint8_t {
UNKNOWN = 0x00,
OFFLINE = 0x01,
READY = 0x02
};
struct RsTorManagerEvent: public RsEvent
{
RsTorManagerEvent(): RsEvent(RsEventType::TOR_MANAGER),
mTorManagerEventType(RsTorManagerEventCode::UNKNOWN)
{}
RsTorManagerEventCode mTorManagerEventType;
RsTorConnectivityStatus mTorConnectivityStatus;
RsTorStatus mTorStatus;
std::string mErrorMessage;
///* @see RsEvent @see RsSerializable
void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx ) override
{
RsEvent::serial_process(j, ctx);
RS_SERIAL_PROCESS(mTorManagerEventType);
RS_SERIAL_PROCESS(mTorConnectivityStatus);
RS_SERIAL_PROCESS(mTorStatus);
RS_SERIAL_PROCESS(mErrorMessage);
}
~RsTorManagerEvent() = default;
};
class RsTor
{
public:
/*!
* \brief isTorAvailable
* \return true if a Tor executble has been found. False otherwise.
*/
static bool isTorAvailable() ;
/*!
* \brief torStatus
* \return Status of the Tor service used by RS
*/
static RsTorStatus torStatus() ;
/*!
* \brief torConnectivityStatus
* \return Status of the connectivity/authentication between RS and Tor
*/
static RsTorConnectivityStatus torConnectivityStatus() ;
static void setTorDataDirectory(const std::string& dir);
static void setHiddenServiceDirectory(const std::string& dir);
static bool setupHiddenService();
/*!
* \brief getProxyServerInfo
* \param server_address Address of the proxy used by RS to send data in the Tor network. Usually 127.0.0.1
* \param server_port Port of the proxy used by RS to send data in the Tor network. Usually 9050.
*/
static void getProxyServerInfo(std::string& server_address, uint16_t& server_port);
/*!
* \brief getHiddenServiceStatus
* \param service_id onion address of the hidden service (if the service is OFFLINE or ONLINE)
* \return Status of the created/loaded hidden service.
*/
static RsTorHiddenServiceStatus getHiddenServiceStatus(std::string& service_id);
/*!
* \brief start
* Launches the Tor management threads.
*/
static bool start();
/*!
* \brief stop
* Stop the Tor management threads.
*/
static void stop();
/*!
* \brief getHiddenServiceInfo
* Gets information about the hidden service setup by RS to run.
* \param service_id
* \param service_onion_address
* \param service_port
* \param service_target_address
* \param target_port
* \return
*/
static bool getHiddenServiceInfo(std::string& service_id,
std::string& service_onion_address,
uint16_t& service_port,
std::string& service_target_address,
uint16_t& target_port);
/*!
* \brief bootstrapStatus
* \return Log messages of the Tor bootstrapping status.
*/
static std::map<std::string,std::string> bootstrapStatus();
static std::list<std::string> logMessages();
static std::string socksAddress();
static uint16_t socksPort();
static bool hasError();
static std::string errorMessage();
private:
static Tor::TorManager *instance();
};

View File

@ -64,12 +64,6 @@ RsItem *RsNxsSerialiser::create_item(uint16_t service_id,uint8_t item_subtype) c
if(service_id != SERVICE_TYPE) if(service_id != SERVICE_TYPE)
return NULL ; return NULL ;
switch(static_cast<RsNxsSubtype>(item_subtype))
{
case RsNxsSubtype::PULL_REQUEST:
return new RsNxsPullRequestItem(static_cast<RsServiceType>(service_id));
}
switch(item_subtype) switch(item_subtype)
{ {
case RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM: return new RsNxsSyncGrpReqItem(SERVICE_TYPE) ; case RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM: return new RsNxsSyncGrpReqItem(SERVICE_TYPE) ;
@ -82,6 +76,7 @@ RsItem *RsNxsSerialiser::create_item(uint16_t service_id,uint8_t item_subtype) c
case RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM:return new RsNxsGroupPublishKeyItem(SERVICE_TYPE) ; case RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM:return new RsNxsGroupPublishKeyItem(SERVICE_TYPE) ;
case RS_PKT_SUBTYPE_NXS_ENCRYPTED_DATA_ITEM: return new RsNxsEncryptedDataItem(SERVICE_TYPE) ; case RS_PKT_SUBTYPE_NXS_ENCRYPTED_DATA_ITEM: return new RsNxsEncryptedDataItem(SERVICE_TYPE) ;
case RS_PKT_SUBTYPE_NXS_SYNC_GRP_STATS_ITEM: return new RsNxsSyncGrpStatsItem(SERVICE_TYPE) ; case RS_PKT_SUBTYPE_NXS_SYNC_GRP_STATS_ITEM: return new RsNxsSyncGrpStatsItem(SERVICE_TYPE) ;
case RS_PKT_SUBTYPE_NXS_SYNC_PULL_REQUEST_ITEM: return new RsNxsPullRequestItem(SERVICE_TYPE) ;
default: default:
return NULL; return NULL;

View File

@ -35,11 +35,6 @@
#include "serialiser/rstlvkeys.h" #include "serialiser/rstlvkeys.h"
#include "gxs/rsgxsdata.h" #include "gxs/rsgxsdata.h"
enum class RsNxsSubtype : uint8_t
{
PULL_REQUEST = 0x90 /// @see RsNxsPullRequestItem
};
// These items have "flag type" numbers, but this is not used. // These items have "flag type" numbers, but this is not used.
// TODO: refactor as C++11 enum class // TODO: refactor as C++11 enum class
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM = 0x01; const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM = 0x01;
@ -53,6 +48,7 @@ const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_MSG_REQ_ITEM = 0x10;
const uint8_t RS_PKT_SUBTYPE_NXS_MSG_ITEM = 0x20; const uint8_t RS_PKT_SUBTYPE_NXS_MSG_ITEM = 0x20;
const uint8_t RS_PKT_SUBTYPE_NXS_TRANSAC_ITEM = 0x40; const uint8_t RS_PKT_SUBTYPE_NXS_TRANSAC_ITEM = 0x40;
const uint8_t RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM = 0x80; const uint8_t RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM = 0x80;
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_PULL_REQUEST_ITEM = 0x90;
#ifdef RS_DEAD_CODE #ifdef RS_DEAD_CODE
@ -370,13 +366,10 @@ public:
/*! /*!
* Used to request to a peer pull updates from us ASAP without waiting GXS sync * Used to request to a peer pull updates from us ASAP without waiting GXS sync
* timer */ * timer */
struct RsNxsPullRequestItem: RsItem class RsNxsPullRequestItem: public RsNxsItem
{ {
explicit RsNxsPullRequestItem(RsServiceType servtype): public:
RsItem( RS_PKT_VERSION_SERVICE, explicit RsNxsPullRequestItem(uint16_t servtype): RsNxsItem(servtype, RS_PKT_SUBTYPE_NXS_SYNC_PULL_REQUEST_ITEM) {}
servtype,
static_cast<uint8_t>(RsNxsSubtype::PULL_REQUEST),
QOS_PRIORITY_RS_GXS_NET ) {}
/// @see RsSerializable /// @see RsSerializable
void serial_process( RsGenericSerializer::SerializeJob, void serial_process( RsGenericSerializer::SerializeJob,
@ -388,8 +381,9 @@ struct RsNxsPullRequestItem: RsItem
* Used to respond to a RsGrpMsgsReq * Used to respond to a RsGrpMsgsReq
* with message items satisfying request * with message items satisfying request
*/ */
struct RsNxsMsg : RsNxsItem class RsNxsMsg : public RsNxsItem
{ {
public:
explicit RsNxsMsg(uint16_t servtype) explicit RsNxsMsg(uint16_t servtype)
: RsNxsItem(servtype, RS_PKT_SUBTYPE_NXS_MSG_ITEM) : RsNxsItem(servtype, RS_PKT_SUBTYPE_NXS_MSG_ITEM)
, pos(0), count(0), meta(servtype), msg(servtype), metaData(NULL) , pos(0), count(0), meta(servtype), msg(servtype), metaData(NULL)

View File

@ -118,7 +118,7 @@ void RsServer::rsGlobalShutDown()
// if(mWire) mWire->join(); // if(mWire) mWire->join();
// #endif // #endif
AuthGPG::exit(); AuthPGP::exit();
mShutdownCallback(0); mShutdownCallback(0);
} }

View File

@ -254,7 +254,7 @@ bool p3Peers::setPeerMaximumRates(const RsPgpId& pid,uint32_t maxUploadRate,uint
bool p3Peers::haveSecretKey(const RsPgpId& id) bool p3Peers::haveSecretKey(const RsPgpId& id)
{ {
return AuthGPG::getAuthGPG()->haveSecretKey(id); return AuthPGP::haveSecretKey(id);
} }
/* There are too many dependancies of this function /* There are too many dependancies of this function
@ -273,7 +273,7 @@ bool p3Peers::getPeerDetails(const RsPeerId& id, RsPeerDetails &d)
if (id == sOwnId) if (id == sOwnId)
{ {
mPeerMgr->getOwnNetStatus(ps); mPeerMgr->getOwnNetStatus(ps);
ps.gpg_id = AuthGPG::getAuthGPG()->getGPGOwnId(); ps.gpg_id = AuthPGP::getPgpOwnId();
} }
else if (!mPeerMgr->getFriendNetStatus(id, ps)) else if (!mPeerMgr->getFriendNetStatus(id, ps))
{ {
@ -559,17 +559,17 @@ bool p3Peers::isProxyAddress(const uint32_t type, const sockaddr_storage& addr)
bool p3Peers::isKeySupported(const RsPgpId& id) bool p3Peers::isKeySupported(const RsPgpId& id)
{ {
return AuthGPG::getAuthGPG()->isKeySupported(id); return AuthPGP::isKeySupported(id);
} }
std::string p3Peers::getGPGName(const RsPgpId &gpg_id) std::string p3Peers::getGPGName(const RsPgpId &gpg_id)
{ {
/* get from mAuthMgr as it should have more peers? */ /* get from mAuthMgr as it should have more peers? */
return AuthGPG::getAuthGPG()->getGPGName(gpg_id); return AuthPGP::getPgpName(gpg_id);
} }
bool p3Peers::isPgpFriend(const RsPgpId& pgpId) bool p3Peers::isPgpFriend(const RsPgpId& pgpId)
{ return AuthGPG::getAuthGPG()->isGPGAccepted(pgpId); } { return AuthPGP::isPGPAccepted(pgpId); }
bool p3Peers::isSslOnlyFriend(const RsPeerId& sslId) bool p3Peers::isSslOnlyFriend(const RsPeerId& sslId)
{ {
@ -597,7 +597,7 @@ std::string p3Peers::getPeerName(const RsPeerId& ssl)
#endif #endif
std::string name; std::string name;
if (ssl == AuthSSL::getAuthSSL()->OwnId()) if (ssl == AuthSSL::getAuthSSL()->OwnId())
return AuthGPG::getAuthGPG()->getGPGOwnName(); return AuthPGP::getPgpOwnName();
if (mPeerMgr->getPeerName(ssl, name)) if (mPeerMgr->getPeerName(ssl, name))
{ {
@ -617,7 +617,7 @@ bool p3Peers::getGPGAllList(std::list<RsPgpId> &ids)
#endif #endif
/* get from mAuthMgr */ /* get from mAuthMgr */
AuthGPG::getAuthGPG()->getGPGAllList(ids); AuthPGP::getPgpAllList(ids);
return true; return true;
} }
@ -628,7 +628,7 @@ bool p3Peers::getGPGValidList(std::list<RsPgpId> &ids)
#endif #endif
/* get from mAuthMgr */ /* get from mAuthMgr */
AuthGPG::getAuthGPG()->getGPGValidList(ids); AuthPGP::getPgpValidList(ids);
return true; return true;
} }
@ -639,14 +639,14 @@ bool p3Peers::getGPGSignedList(std::list<RsPgpId> &ids)
#endif #endif
/* get from mAuthMgr */ /* get from mAuthMgr */
AuthGPG::getAuthGPG()->getGPGSignedList(ids); AuthPGP::getPgpSignedList(ids);
return true; return true;
} }
bool p3Peers::getPgpFriendList(std::vector<RsPgpId>& pgpIds) bool p3Peers::getPgpFriendList(std::vector<RsPgpId>& pgpIds)
{ {
std::list<RsPgpId> ids; std::list<RsPgpId> ids;
if(AuthGPG::getAuthGPG()->getGPGAcceptedList(ids)) if(AuthPGP::getPgpAcceptedList(ids))
{ {
pgpIds.clear(); pgpIds.clear();
std::copy(ids.begin(), ids.end(), std::back_inserter(pgpIds)); std::copy(ids.begin(), ids.end(), std::back_inserter(pgpIds));
@ -660,7 +660,7 @@ bool p3Peers::getGPGAcceptedList(std::list<RsPgpId> &ids)
#ifdef P3PEERS_DEBUG #ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::getGPGAcceptedList()" << std::endl; std::cerr << "p3Peers::getGPGAcceptedList()" << std::endl;
#endif #endif
AuthGPG::getAuthGPG()->getGPGAcceptedList(ids); AuthPGP::getPgpAcceptedList(ids);
return true; return true;
} }
@ -676,7 +676,7 @@ bool p3Peers::getAssociatedSSLIds(const RsPgpId &gpg_id, std::list<RsPeerId> &id
bool p3Peers::gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason /* = "" */) bool p3Peers::gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason /* = "" */)
{ {
return AuthGPG::getAuthGPG()->SignDataBin(data,len,sign,signlen, reason); return AuthPGP::SignDataBin(data,len,sign,signlen, reason);
} }
RsPgpId p3Peers::pgpIdFromFingerprint(const RsPgpFingerprint& fpr) RsPgpId p3Peers::pgpIdFromFingerprint(const RsPgpFingerprint& fpr)
@ -691,7 +691,7 @@ bool p3Peers::getGPGDetails(const RsPgpId &pgp_id, RsPeerDetails &d)
#endif #endif
/* get from mAuthMgr */ /* get from mAuthMgr */
bool res = AuthGPG::getAuthGPG()->getGPGDetails(pgp_id, d); bool res = AuthPGP::getPgpDetails(pgp_id, d);
d.isOnlyGPGdetail = true ; d.isOnlyGPGdetail = true ;
d.service_perm_flags = mPeerMgr->servicePermissionFlags(pgp_id) ; d.service_perm_flags = mPeerMgr->servicePermissionFlags(pgp_id) ;
@ -706,7 +706,7 @@ const RsPgpId& p3Peers::getGPGOwnId()
#endif #endif
/* get from mAuthMgr */ /* get from mAuthMgr */
return AuthGPG::getAuthGPG()->getGPGOwnId(); return AuthPGP::getPgpOwnId();
} }
RsPgpId p3Peers::getGPGId(const RsPeerId& sslid) RsPgpId p3Peers::getGPGId(const RsPeerId& sslid)
@ -718,7 +718,7 @@ RsPgpId p3Peers::getGPGId(const RsPeerId& sslid)
/* get from mAuthMgr */ /* get from mAuthMgr */
if (sslid == AuthSSL::getAuthSSL()->OwnId()) if (sslid == AuthSSL::getAuthSSL()->OwnId())
{ {
return AuthGPG::getAuthGPG()->getGPGOwnId(); return AuthPGP::getPgpOwnId();
} }
peerState pcs; peerState pcs;
if (mPeerMgr->getFriendNetStatus(sslid, pcs)) if (mPeerMgr->getFriendNetStatus(sslid, pcs))
@ -739,12 +739,12 @@ bool p3Peers::addFriend(const RsPeerId &ssl_id, const RsPgpId &gpg_id,ServicePe
#ifdef P3PEERS_DEBUG #ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::addFriend() with : id : " << id << "; gpg_id : " << gpg_id << std::endl; std::cerr << "p3Peers::addFriend() with : id : " << id << "; gpg_id : " << gpg_id << std::endl;
#endif #endif
if(AuthGPG::getAuthGPG()->isGPGId(gpg_id)) if(AuthPGP::isPGPId(gpg_id))
{ {
#ifdef P3PEERS_DEBUG #ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::addFriend() Authorising GPG Id: " << gpg_id << std::endl; std::cerr << "p3Peers::addFriend() Authorising GPG Id: " << gpg_id << std::endl;
#endif #endif
if (AuthGPG::getAuthGPG()->AllowConnection(gpg_id, true)) if (AuthPGP::AllowConnection(gpg_id, true))
{ {
#ifdef P3PEERS_DEBUG #ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::addFriend() Authorization OK." << std::endl; std::cerr << "p3Peers::addFriend() Authorization OK." << std::endl;
@ -797,7 +797,7 @@ bool p3Peers::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_id,con
bool p3Peers::removeKeysFromPGPKeyring(const std::set<RsPgpId>& pgp_ids,std::string& backup_file,uint32_t& error_code) bool p3Peers::removeKeysFromPGPKeyring(const std::set<RsPgpId>& pgp_ids,std::string& backup_file,uint32_t& error_code)
{ {
return AuthGPG::getAuthGPG()->removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ; return AuthPGP::removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ;
} }
bool p3Peers::removeFriendLocation(const RsPeerId &sslId) bool p3Peers::removeFriendLocation(const RsPeerId &sslId)
@ -817,7 +817,7 @@ bool p3Peers::removeFriend(const RsPgpId& gpgId)
#ifdef P3PEERS_DEBUG #ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::removeFriend() " << gpgId << std::endl; std::cerr << "p3Peers::removeFriend() " << gpgId << std::endl;
#endif #endif
if (gpgId == AuthGPG::getAuthGPG()->getGPGOwnId()) { if (gpgId == AuthPGP::getPgpOwnId()) {
std::cerr << "p3Peers::removeFriend() ERROR we're not going to remove our own GPG id." << std::endl; std::cerr << "p3Peers::removeFriend() ERROR we're not going to remove our own GPG id." << std::endl;
return false; return false;
} }
@ -825,7 +825,7 @@ bool p3Peers::removeFriend(const RsPgpId& gpgId)
#ifdef P3PEERS_DEBUG #ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::removeFriend() Removing GPG Id: " << gpgId << std::endl; std::cerr << "p3Peers::removeFriend() Removing GPG Id: " << gpgId << std::endl;
#endif #endif
if (AuthGPG::getAuthGPG()->AllowConnection(gpgId, false)) if (AuthPGP::AllowConnection(gpgId, false))
{ {
#ifdef P3PEERS_DEBUG #ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::removeFriend() OK." << std::endl; std::cerr << "p3Peers::removeFriend() OK." << std::endl;
@ -1113,9 +1113,7 @@ std::string p3Peers::getPGPKey(const RsPgpId& pgp_id,bool include_signatures)
rs_owner_ptr<unsigned char> mem_block = nullptr; rs_owner_ptr<unsigned char> mem_block = nullptr;
size_t mem_block_size = 0; size_t mem_block_size = 0;
if( !AuthGPG::getAuthGPG()->exportPublicKey( if( !AuthPGP::exportPublicKey( RsPgpId(pgp_id), mem_block, mem_block_size, false, include_signatures ) )
RsPgpId(pgp_id), mem_block, mem_block_size,
false, include_signatures ) )
{ {
RsErr() << __PRETTY_FUNCTION__ RsErr() << __PRETTY_FUNCTION__
<< " Failure retriving certificate for id " << pgp_id << " Failure retriving certificate for id " << pgp_id
@ -1146,8 +1144,7 @@ bool p3Peers::GetPGPBase64StringAndCheckSum(
rs_owner_ptr<unsigned char> mem_block = nullptr; rs_owner_ptr<unsigned char> mem_block = nullptr;
size_t mem_block_size = 0; size_t mem_block_size = 0;
if(!AuthGPG::getAuthGPG()->exportPublicKey( if(!AuthPGP::exportPublicKey( gpg_id,mem_block,mem_block_size,false,false ))
gpg_id,mem_block,mem_block_size,false,false ))
return false; return false;
RsBase64::encode(mem_block, mem_block_size, gpg_base64_string, true, false); RsBase64::encode(mem_block, mem_block_size, gpg_base64_string, true, false);
@ -1644,7 +1641,7 @@ std::string p3Peers::GetRetroshareInvite( const RsPeerId& sslId, RetroshareInvit
unsigned char *mem_block = nullptr; unsigned char *mem_block = nullptr;
size_t mem_block_size = 0; size_t mem_block_size = 0;
if(!AuthGPG::getAuthGPG()->exportPublicKey( RsPgpId(detail.gpg_id), mem_block, mem_block_size, false, !!(invite_flags & RetroshareInviteFlags::PGP_SIGNATURES) )) if(!AuthPGP::exportPublicKey( RsPgpId(detail.gpg_id), mem_block, mem_block_size, false, !!(invite_flags & RetroshareInviteFlags::PGP_SIGNATURES) ))
{ {
std::cerr << "Cannot output certificate for id \"" << detail.gpg_id std::cerr << "Cannot output certificate for id \"" << detail.gpg_id
<< "\". Sorry." << std::endl; << "\". Sorry." << std::endl;
@ -1680,7 +1677,7 @@ bool p3Peers::loadCertificateFromString(
} }
RsPgpId gpgid; RsPgpId gpgid;
bool res = AuthGPG::getAuthGPG()->LoadCertificateFromString( crt->armouredPGPKey(), gpgid, error_string ); bool res = AuthPGP::LoadCertificateFromString( crt->armouredPGPKey(), gpgid, error_string );
gpg_id = gpgid; gpg_id = gpgid;
ssl_id = crt->sslid(); ssl_id = crt->sslid();
@ -1697,7 +1694,7 @@ bool p3Peers::loadCertificateFromString(
} }
bool p3Peers::loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string ) bool p3Peers::loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string )
{ {
bool res = AuthGPG::getAuthGPG()->LoadPGPKeyFromBinaryData( bin_key_data,bin_key_len, gpg_id, error_string ); bool res = AuthPGP::LoadPGPKeyFromBinaryData( bin_key_data,bin_key_len, gpg_id, error_string );
if(res) if(res)
mPeerMgr->notifyPgpKeyReceived(gpg_id); mPeerMgr->notifyPgpKeyReceived(gpg_id);
@ -1716,9 +1713,7 @@ bool p3Peers::loadDetailsFromStringCert( const std::string &certstr,
RsCertificate& cert = *certPtr; RsCertificate& cert = *certPtr;
if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock( if(!AuthPGP::getPgpDetailsFromBinaryBlock( cert.pgp_key(), cert.pgp_key_size(), pd.gpg_id, pd.name, pd.gpgSigners ))
cert.pgp_key(), cert.pgp_key_size(),
pd.gpg_id, pd.name, pd.gpgSigners ))
return false; return false;
Dbg4() << __PRETTY_FUNCTION__ << " Parsing cert for sslid, location, ext " Dbg4() << __PRETTY_FUNCTION__ << " Parsing cert for sslid, location, ext "
@ -1796,7 +1791,7 @@ bool p3Peers::signGPGCertificate(const RsPgpId &id, const std::string &gpg_pass
rsNotify->cachePgpPassphrase(gpg_passphrase); rsNotify->cachePgpPassphrase(gpg_passphrase);
rsNotify->setDisableAskPassword(true); rsNotify->setDisableAskPassword(true);
bool res = AuthGPG::getAuthGPG()->SignCertificateLevel0(id); bool res = AuthPGP::SignCertificateLevel0(id);
rsNotify->clearPgpPassphrase(); rsNotify->clearPgpPassphrase();
rsNotify->setDisableAskPassword(false); rsNotify->setDisableAskPassword(false);
@ -1810,7 +1805,7 @@ bool p3Peers::trustGPGCertificate(const RsPgpId &id, uint32_t trustlvl)
std::cerr << "p3Peers::TrustCertificate() " << id; std::cerr << "p3Peers::TrustCertificate() " << id;
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
return AuthGPG::getAuthGPG()->TrustCertificate(id, trustlvl); return AuthPGP::TrustCertificate(id, trustlvl);
} }
/* Group Stuff */ /* Group Stuff */

View File

@ -140,7 +140,7 @@ bool p3ServerConfig::setConfigurationOption(uint32_t key, const std::string &opt
int p3ServerConfig::getConfigNetStatus(RsConfigNetStatus &status) int p3ServerConfig::getConfigNetStatus(RsConfigNetStatus &status)
{ {
status.ownId = AuthSSL::getAuthSSL()->OwnId(); status.ownId = AuthSSL::getAuthSSL()->OwnId();
status.ownName = AuthGPG::getAuthGPG()->getGPGOwnName(); status.ownName = AuthPGP::getPgpOwnName();
// Details from PeerMgr. // Details from PeerMgr.
peerState pstate; peerState pstate;

View File

@ -731,10 +731,10 @@ static bool checkAccount(const std::string &accountdir, AccountDetails &account,
if(! RsAccounts::GetPGPLoginDetails(account.mPgpId, account.mPgpName, account.mPgpEmail)) if(! RsAccounts::GetPGPLoginDetails(account.mPgpId, account.mPgpName, account.mPgpEmail))
return false ; return false ;
if(!AuthGPG::getAuthGPG()->haveSecretKey(account.mPgpId)) if(!AuthPGP::haveSecretKey(account.mPgpId))
return false ; return false ;
if(!AuthGPG::getAuthGPG()->isKeySupported(account.mPgpId)) if(!AuthPGP::isKeySupported(account.mPgpId))
{ {
std::string keystring = account.mPgpId.toStdString() + " " + account.mPgpName + "&#60;" + account.mPgpEmail ; std::string keystring = account.mPgpId.toStdString() + " " + account.mPgpName + "&#60;" + account.mPgpEmail ;
unsupported_keys[keystring].push_back("Location: " + account.mLocation + "&nbsp;&nbsp;(" + account.mSslId.toStdString() + ")") ; unsupported_keys[keystring].push_back("Location: " + account.mLocation + "&nbsp;&nbsp;(" + account.mSslId.toStdString() + ")") ;
@ -882,8 +882,9 @@ static bool checkAccount(const std::string &accountdir, AccountDetails &account,
/* Generating GPGme Account */ /* Generating GPGme Account */
int RsAccountsDetail::GetPGPLogins(std::list<RsPgpId> &pgpIds) { int RsAccountsDetail::GetPGPLogins(std::list<RsPgpId>& pgpIds)
AuthGPG::getAuthGPG()->availableGPGCertificatesWithPrivateKeys(pgpIds); {
AuthPGP::availablePgpCertificatesWithPrivateKeys(pgpIds);
return 1; return 1;
} }
@ -894,10 +895,10 @@ int RsAccountsDetail::GetPGPLoginDetails(const RsPgpId& id, std::string &na
#endif #endif
bool ok = true ; bool ok = true ;
name = AuthGPG::getAuthGPG()->getGPGName(id,&ok); name = AuthPGP::getPgpName(id,&ok);
if(!ok) if(!ok)
return 0 ; return 0 ;
email = AuthGPG::getAuthGPG()->getGPGEmail(id,&ok); email = AuthPGP::getPgpEmail(id,&ok);
if(!ok) if(!ok)
return 0 ; return 0 ;
@ -917,7 +918,7 @@ bool RsAccountsDetail::SelectPGPAccount(const RsPgpId& pgpId)
{ {
bool retVal = false; bool retVal = false;
if (0 < AuthGPG::getAuthGPG() -> GPGInit(pgpId)) if (0 < AuthPGP::PgpInit(pgpId))
{ {
retVal = true; retVal = true;
#ifdef DEBUG_ACCOUNTS #ifdef DEBUG_ACCOUNTS
@ -937,7 +938,7 @@ bool RsAccountsDetail::SelectPGPAccount(const RsPgpId& pgpId)
bool RsAccountsDetail::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString) bool RsAccountsDetail::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString)
{ {
return AuthGPG::getAuthGPG()->GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString); return AuthPGP::GeneratePgpCertificate(name, email, passwd, pgpId, keynumbits, errString);
} }
// PGP Support Functions. // PGP Support Functions.
@ -949,24 +950,24 @@ void RsAccountsDetail::getUnsupportedKeys(std::map<std::string,std::vector<std::
bool RsAccountsDetail::exportIdentity(const std::string& fname,const RsPgpId& id) bool RsAccountsDetail::exportIdentity(const std::string& fname,const RsPgpId& id)
{ {
return AuthGPG::getAuthGPG()->exportProfile(fname,id); return AuthPGP::exportProfile(fname,id);
} }
bool RsAccountsDetail::importIdentity(const std::string& fname,RsPgpId& id,std::string& import_error) bool RsAccountsDetail::importIdentity(const std::string& fname,RsPgpId& id,std::string& import_error)
{ {
return AuthGPG::getAuthGPG()->importProfile(fname,id,import_error); return AuthPGP::importProfile(fname,id,import_error);
} }
bool RsAccountsDetail::importIdentityFromString(const std::string &data, RsPgpId &imported_pgp_id, std::string &import_error) bool RsAccountsDetail::importIdentityFromString(const std::string &data, RsPgpId &imported_pgp_id, std::string &import_error)
{ {
return AuthGPG::getAuthGPG()->importProfileFromString(data, imported_pgp_id, import_error); return AuthPGP::importProfileFromString(data, imported_pgp_id, import_error);
} }
bool RsAccountsDetail::exportIdentityToString( bool RsAccountsDetail::exportIdentityToString(
std::string& data, const RsPgpId& pgpId, bool includeSignatures, std::string& data, const RsPgpId& pgpId, bool includeSignatures,
std::string& errorMsg ) std::string& errorMsg )
{ {
return AuthGPG::getAuthGPG()->exportIdentityToString( return AuthPGP::exportIdentityToString(
data, pgpId, includeSignatures, errorMsg ); data, pgpId, includeSignatures, errorMsg );
} }
@ -1057,7 +1058,7 @@ bool RsAccountsDetail::GenerateSSLCertificate(const RsPgpId& pgp_id, const s
int nbits = 4096; int nbits = 4096;
//std::string pgp_name = AuthGPG::getAuthGPG()->getGPGName(pgp_id); //std::string pgp_name = AuthGPG::getGPGName(pgp_id);
// Create the filename ..... // Create the filename .....
// Temporary Directory for creating files.... // Temporary Directory for creating files....
@ -1332,7 +1333,7 @@ bool RsAccounts::init(const std::string& opt_base_dir,int& error_code)
if(!RsDirUtil::checkCreateDirectory(pgp_dir)) if(!RsDirUtil::checkCreateDirectory(pgp_dir))
throw std::runtime_error("Cannot create pgp directory " + pgp_dir) ; throw std::runtime_error("Cannot create pgp directory " + pgp_dir) ;
AuthGPG::init( pgp_dir + "/retroshare_public_keyring.gpg", AuthPGP::init( pgp_dir + "/retroshare_public_keyring.gpg",
pgp_dir + "/retroshare_secret_keyring.gpg", pgp_dir + "/retroshare_secret_keyring.gpg",
pgp_dir + "/retroshare_trustdb.gpg", pgp_dir + "/retroshare_trustdb.gpg",
pgp_dir + "/lock"); pgp_dir + "/lock");

View File

@ -44,6 +44,7 @@
#include "util/folderiterator.h" #include "util/folderiterator.h"
#include "util/rsstring.h" #include "util/rsstring.h"
#include "retroshare/rsinit.h" #include "retroshare/rsinit.h"
#include "retroshare/rstor.h"
#include "retroshare/rsnotify.h" #include "retroshare/rsnotify.h"
#include "retroshare/rsiface.h" #include "retroshare/rsiface.h"
#include "plugins/pluginmanager.h" #include "plugins/pluginmanager.h"
@ -144,6 +145,7 @@ struct RsInitConfig
{} {}
RsFileHash main_executable_hash; RsFileHash main_executable_hash;
std::string mainExecutablePath;
#ifdef WINDOWS_SYS #ifdef WINDOWS_SYS
bool portable; bool portable;
@ -305,6 +307,7 @@ int RsInit::InitRetroShare(const RsConfigOptions& conf)
rsInitConfig->optBaseDir = conf.optBaseDir; rsInitConfig->optBaseDir = conf.optBaseDir;
rsInitConfig->jsonApiPort = conf.jsonApiPort; rsInitConfig->jsonApiPort = conf.jsonApiPort;
rsInitConfig->jsonApiBindAddress = conf.jsonApiBindAddress; rsInitConfig->jsonApiBindAddress = conf.jsonApiBindAddress;
rsInitConfig->mainExecutablePath = conf.main_executable_path;
#ifdef PTW32_STATIC_LIB #ifdef PTW32_STATIC_LIB
// for static PThreads under windows... we need to init the library... // for static PThreads under windows... we need to init the library...
@ -512,7 +515,7 @@ RsInit::LoadCertificateStatus RsInit::LockAndLoadCertificates(
if(!RsAccounts::GetAccountDetails(accountId, pgpId, pgpName, pgpEmail, location)) if(!RsAccounts::GetAccountDetails(accountId, pgpId, pgpName, pgpEmail, location))
throw RsInit::ERR_UNKNOWN; // invalid PreferredAccount; throw RsInit::ERR_UNKNOWN; // invalid PreferredAccount;
if(0 == AuthGPG::getAuthGPG() -> GPGInit(pgpId)) if(0 == AuthPGP::PgpInit(pgpId))
throw RsInit::ERR_UNKNOWN; // PGP Error. throw RsInit::ERR_UNKNOWN; // PGP Error.
LoadCertificateStatus retVal = LoadCertificateStatus retVal =
@ -912,8 +915,8 @@ int RsServer::StartupRetroShare()
/* History Manager */ /* History Manager */
mHistoryMgr = new p3HistoryMgr(); mHistoryMgr = new p3HistoryMgr();
mPeerMgr = new p3PeerMgrIMPL( AuthSSL::getAuthSSL()->OwnId(), mPeerMgr = new p3PeerMgrIMPL( AuthSSL::getAuthSSL()->OwnId(),
AuthGPG::getAuthGPG()->getGPGOwnId(), AuthPGP::getPgpOwnId(),
AuthGPG::getAuthGPG()->getGPGOwnName(), AuthPGP::getPgpOwnName(),
AuthSSL::getAuthSSL()->getOwnLocation()); AuthSSL::getAuthSSL()->getOwnLocation());
mNetMgr = new p3NetMgrIMPL(); mNetMgr = new p3NetMgrIMPL();
mLinkMgr = new p3LinkMgrIMPL(mPeerMgr, mNetMgr); mLinkMgr = new p3LinkMgrIMPL(mPeerMgr, mNetMgr);
@ -1613,7 +1616,8 @@ int RsServer::StartupRetroShare()
//mConfigMgr->addConfiguration("ftserver.cfg", ftserver); //mConfigMgr->addConfiguration("ftserver.cfg", ftserver);
// //
mConfigMgr->addConfiguration("gpg_prefs.cfg" , AuthGPG::getAuthGPG()); AuthPGP::registerToConfigMgr(std::string("gpg_prefs.cfg"),mConfigMgr);
mConfigMgr->addConfiguration("gxsnettunnel.cfg", mGxsNetTunnel); mConfigMgr->addConfiguration("gxsnettunnel.cfg", mGxsNetTunnel);
mConfigMgr->addConfiguration("peers.cfg" , mPeerMgr); mConfigMgr->addConfiguration("peers.cfg" , mPeerMgr);
mConfigMgr->addConfiguration("general.cfg" , mGeneralConfig); mConfigMgr->addConfiguration("general.cfg" , mGeneralConfig);
@ -1799,7 +1803,7 @@ int RsServer::StartupRetroShare()
/* Add AuthGPG services */ /* Add AuthGPG services */
/**************************************************************************/ /**************************************************************************/
//AuthGPG::getAuthGPG()->addService(mDisc); //AuthGPG::addService(mDisc);
/**************************************************************************/ /**************************************************************************/
/* Force Any Last Configuration Options */ /* Force Any Last Configuration Options */
@ -1930,6 +1934,52 @@ int RsServer::StartupRetroShare()
return 1; return 1;
} }
std::string RsInit::executablePath()
{
return rsInitConfig->mainExecutablePath;
}
bool RsInit::startAutoTor()
{
std::cerr << "(II) node is an automated Tor node => launching Tor auto-configuration." << std::endl;
// Now that we know the Tor service running, and we know the SSL id, we can make sure it provides a viable hidden service
std::string tor_hidden_service_dir = RsAccounts::AccountDirectory() + "/hidden_service/" ;
RsTor::setTorDataDirectory(RsAccounts::ConfigDirectory() + "/tor/");
RsTor::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)) ;
if(! RsTor::start() || RsTor::hasError())
{
std::cerr << "(EE) Tor cannot be started on your system: "+RsTor::errorMessage() << std::endl ;
return false ;
}
std::cerr << "(II) Tor has been started." << std::endl;
// now start/create the hidden service as needed.
std::string service_id;
RsTor::setupHiddenService();
while(RsTor::torStatus() != RsTorStatus::READY && RsTor::getHiddenServiceStatus(service_id) != RsTorHiddenServiceStatus::ONLINE) // runs until some status is reached: either tor works, or it fails.
{
rstime::rs_usleep(0.5*1000*1000) ;
std::cerr << "(II) Hidden service ID: " << service_id << ", status: " << (int)RsTor::getHiddenServiceStatus(service_id) << std::endl;
if(RsTor::hasError())
{
std::string error_msg = RsTor::errorMessage();
std::cerr << "(EE) Tor hidden service cannot be started: " << error_msg << std::endl;
return false;
}
// process Qt event loop to deal with messages of online/offline info
// QCoreApplication::processEvents();
}
return true;
}
RsInit::LoadCertificateStatus RsLoginHelper::attemptLogin(const RsPeerId& account, const std::string& password) RsInit::LoadCertificateStatus RsLoginHelper::attemptLogin(const RsPeerId& account, const std::string& password)
{ {
if(isLoggedIn()) return RsInit::ERR_ALREADY_RUNNING; if(isLoggedIn()) return RsInit::ERR_ALREADY_RUNNING;
@ -1949,6 +1999,16 @@ RsInit::LoadCertificateStatus RsLoginHelper::attemptLogin(const RsPeerId& accoun
rsNotify->setDisableAskPassword(false) ; rsNotify->setDisableAskPassword(false) ;
rsNotify->clearPgpPassphrase() ; rsNotify->clearPgpPassphrase() ;
bool is_hidden_node = false;
bool is_auto_tor = false ;
bool is_first_time = false ;
RsAccounts::getCurrentAccountOptions(is_hidden_node,is_auto_tor,is_first_time);
if(is_auto_tor)
if(!RsInit::startAutoTor())
return RsInit::ERR_CANNOT_CONFIGURE_TOR;
if(ret == RsInit::OK && RsControl::instance()->StartupRetroShare() == 1) if(ret == RsInit::OK && RsControl::instance()->StartupRetroShare() == 1)
return RsInit::OK; return RsInit::OK;

View File

@ -60,8 +60,7 @@ bool RsLoginHandler::checkAndStoreSSLPasswdIntoGPGFile(
return true ; return true ;
} }
bool ok = AuthGPG::getAuthGPG()->encryptTextToFile( bool ok = AuthPGP::encryptTextToFile( ssl_passwd, getSSLPasswdFileName(ssl_id));
ssl_passwd, getSSLPasswdFileName(ssl_id));
if (!ok) std::cerr << "Encrypting went wrong !" << std::endl; if (!ok) std::cerr << "Encrypting went wrong !" << std::endl;
@ -90,7 +89,7 @@ bool RsLoginHandler::getSSLPasswdFromGPGFile(const RsPeerId& ssl_id,std::string&
#endif #endif
std::string plain; std::string plain;
if ( AuthGPG::getAuthGPG()->decryptTextFromFile( plain, getSSLPasswdFileName(ssl_id)) ) if ( AuthPGP::decryptTextFromFile( plain, getSSLPasswdFileName(ssl_id)) )
{ {
sslPassword = plain; sslPassword = plain;
#ifdef DEBUG_RSLOGINHANDLER #ifdef DEBUG_RSLOGINHANDLER

View File

@ -236,7 +236,7 @@ bool p3GxsCircles::createCircle(
bool p3GxsCircles::checkCircleParamConsistency( const std::string& circleName, RsGxsCircleType circleType, bool p3GxsCircles::checkCircleParamConsistency( const std::string& circleName, RsGxsCircleType circleType,
const RsGxsCircleId& restrictedId, const RsGxsCircleId& restrictedId,
const RsGxsId& authorId, const std::set<RsGxsId>& gxsIdMembers, const RsGxsId& /*authorId*/, const std::set<RsGxsId>& gxsIdMembers,
const std::set<RsPgpId>& localMembers ) const const std::set<RsPgpId>& localMembers ) const
{ {
if(circleName.empty()) if(circleName.empty())

View File

@ -1067,7 +1067,7 @@ bool p3IdService::createIdentity(uint32_t& token, RsIdentityParameters &params)
if(params.isPgpLinked) if(params.isPgpLinked)
{ {
ssdata.pgp.pgpId = AuthGPG::getAuthGPG()->getGPGOwnId(); ssdata.pgp.pgpId = AuthPGP::getPgpOwnId();
ssdata.pgp.lastCheckTs = time(nullptr); ssdata.pgp.lastCheckTs = time(nullptr);
} }
@ -3619,7 +3619,7 @@ RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(
unsigned int sign_size = MAX_SIGN_SIZE; unsigned int sign_size = MAX_SIGN_SIZE;
memset(signarray,0,MAX_SIGN_SIZE) ; // just in case. memset(signarray,0,MAX_SIGN_SIZE) ; // just in case.
int result = AuthGPG::getAuthGPG()->SignDataBin( int result = AuthPGP::SignDataBin(
static_cast<const void*>(hash.toByteArray()), static_cast<const void*>(hash.toByteArray()),
hash.SIZE_IN_BYTES, signarray, &sign_size, hash.SIZE_IN_BYTES, signarray, &sign_size,
__PRETTY_FUNCTION__ ) __PRETTY_FUNCTION__ )
@ -4096,7 +4096,7 @@ void p3IdService::getPgpIdList()
#endif // DEBUG_IDS #endif // DEBUG_IDS
std::list<RsPgpId> list; std::list<RsPgpId> list;
mPgpUtils->getGPGAllList(list); mPgpUtils->getPgpAllList(list);
RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/
@ -4593,7 +4593,7 @@ void p3IdService::generateDummy_FriendPGP()
// Now Generate for friends. // Now Generate for friends.
std::list<RsPgpId> gpgids; std::list<RsPgpId> gpgids;
std::list<RsPgpId>::const_iterator it; std::list<RsPgpId>::const_iterator it;
mPgpUtils->getGPGAllList(gpgids); mPgpUtils->getPgpAllList(gpgids);
RsGxsIdGroup id; RsGxsIdGroup id;

View File

@ -220,8 +220,6 @@ void p3MsgService::processIncomingMsg(RsMsgItem *mi)
for(std::list<RsTlvFileItem>::const_iterator it(mi->attachment.items.begin());it!=mi->attachment.items.end();++it) for(std::list<RsTlvFileItem>::const_iterator it(mi->attachment.items.begin());it!=mi->attachment.items.end();++it)
rsFiles->FileRequest((*it).name,(*it).hash,(*it).filesize,std::string(),RS_FILE_REQ_ANONYMOUS_ROUTING,srcIds) ; rsFiles->FileRequest((*it).name,(*it).hash,(*it).filesize,std::string(),RS_FILE_REQ_ANONYMOUS_ROUTING,srcIds) ;
} }
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_ADD);
} }
bool p3MsgService::checkAndRebuildPartialMessage(RsMsgItem *ci) bool p3MsgService::checkAndRebuildPartialMessage(RsMsgItem *ci)
@ -283,16 +281,11 @@ int p3MsgService::incomingMsgs()
void p3MsgService::handleIncomingItem(RsMsgItem *mi) void p3MsgService::handleIncomingItem(RsMsgItem *mi)
{ {
bool changed = false ;
// only returns true when a msg is complete. // only returns true when a msg is complete.
if(checkAndRebuildPartialMessage(mi)) if(checkAndRebuildPartialMessage(mi))
{ {
processIncomingMsg(mi); processIncomingMsg(mi);
changed = true ;
} }
if(changed)
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
} }
void p3MsgService::statusChange(const std::list<pqiServicePeer> &plist) void p3MsgService::statusChange(const std::list<pqiServicePeer> &plist)
@ -350,7 +343,6 @@ void p3MsgService::checkSizeAndSendMessage(RsMsgItem *msg)
int p3MsgService::checkOutgoingMessages() int p3MsgService::checkOutgoingMessages()
{ {
bool changed = false;
std::list<RsMsgItem*> output_queue; std::list<RsMsgItem*> output_queue;
auto pEvent = std::make_shared<RsMailStatusEvent>(); auto pEvent = std::make_shared<RsMailStatusEvent>();
@ -400,7 +392,6 @@ int p3MsgService::checkOutgoingMessages()
{ {
(mit->second)->msgFlags &= ~RS_MSG_FLAGS_PENDING; (mit->second)->msgFlags &= ~RS_MSG_FLAGS_PENDING;
toErase.push_back(mit->first); toErase.push_back(mit->first);
changed = true;
} }
else else
{ {
@ -442,9 +433,6 @@ int p3MsgService::checkOutgoingMessages()
else else
checkSizeAndSendMessage(*it); checkSizeAndSendMessage(*it);
if(changed)
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
if(rsEvents && !pEvent->mChangedMsgIds.empty()) if(rsEvents && !pEvent->mChangedMsgIds.empty())
rsEvents->postEvent(pEvent); rsEvents->postEvent(pEvent);
@ -954,8 +942,6 @@ bool p3MsgService::removeMsgId(const std::string &mid)
setMessageTag(mid, 0, false); setMessageTag(mid, 0, false);
setMsgParentId(msgId, 0); setMsgParentId(msgId, 0);
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
} }
if(rsEvents && !pEvent->mChangedMsgIds.empty()) if(rsEvents && !pEvent->mChangedMsgIds.empty())
@ -968,7 +954,6 @@ bool p3MsgService::markMsgIdRead(const std::string &mid, bool unreadByUser)
{ {
std::map<uint32_t, RsMsgItem *>::iterator mit; std::map<uint32_t, RsMsgItem *>::iterator mit;
uint32_t msgId = atoi(mid.c_str()); uint32_t msgId = atoi(mid.c_str());
bool changed = false;
{ {
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
@ -992,18 +977,18 @@ bool p3MsgService::markMsgIdRead(const std::string &mid, bool unreadByUser)
if (mi->msgFlags != msgFlags) if (mi->msgFlags != msgFlags)
{ {
changed = true;
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
auto pEvent = std::make_shared<RsMailStatusEvent>();
pEvent->mMailStatusEventCode = RsMailStatusEventCode::MESSAGE_CHANGED;
pEvent->mChangedMsgIds.insert(mid);
rsEvents->postEvent(pEvent);
} }
} else { } else {
return false; return false;
} }
} /* UNLOCKED */ } /* UNLOCKED */
if (changed) {
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
}
return true; return true;
} }
@ -1012,8 +997,6 @@ bool p3MsgService::setMsgFlag(const std::string &mid, uint32_t flag, uint32_t
std::map<uint32_t, RsMsgItem *>::iterator mit; std::map<uint32_t, RsMsgItem *>::iterator mit;
uint32_t msgId = atoi(mid.c_str()); uint32_t msgId = atoi(mid.c_str());
bool changed = false;
{ {
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
@ -1033,15 +1016,15 @@ bool p3MsgService::setMsgFlag(const std::string &mid, uint32_t flag, uint32_t
mit->second->msgFlags |= flag; mit->second->msgFlags |= flag;
if (mit->second->msgFlags != oldFlag) { if (mit->second->msgFlags != oldFlag) {
changed = true;
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
auto pEvent = std::make_shared<RsMailStatusEvent>();
pEvent->mMailStatusEventCode = RsMailStatusEventCode::MESSAGE_CHANGED;
pEvent->mChangedMsgIds.insert(mid);
rsEvents->postEvent(pEvent);
} }
} /* UNLOCKED */ } /* UNLOCKED */
if (changed) {
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
}
return true; return true;
} }
@ -1137,7 +1120,10 @@ uint32_t p3MsgService::sendMessage(RsMsgItem* item)
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST, NOTIFY_TYPE_ADD); // deprecated auto pEvent = std::make_shared<RsMailStatusEvent>();
pEvent->mMailStatusEventCode = RsMailStatusEventCode::MESSAGE_SENT;
pEvent->mChangedMsgIds.insert(std::to_string(item->msgId));
rsEvents->postEvent(pEvent);
return item->msgId; return item->msgId;
} }
@ -1175,8 +1161,11 @@ uint32_t p3MsgService::sendDistantMessage(RsMsgItem *item, const RsGxsId& from)
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
RsServer::notify()->notifyListChange( NOTIFY_LIST_MESSAGELIST, auto pEvent = std::make_shared<RsMailStatusEvent>();
NOTIFY_TYPE_ADD ); pEvent->mMailStatusEventCode = RsMailStatusEventCode::MESSAGE_SENT;
pEvent->mChangedMsgIds.insert(std::to_string(item->msgId));
rsEvents->postEvent(pEvent);
return item->msgId; return item->msgId;
} }
@ -1210,8 +1199,6 @@ bool p3MsgService::MessageSend(MessageInfo &info)
// Update info for caller // Update info for caller
info.msgId = std::to_string(msg->msgId); info.msgId = std::to_string(msg->msgId);
info .msgflags = msg->msgFlags; info .msgflags = msg->msgFlags;
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_ADD);// deprecated. Should be removed. Oct. 28, 2020
} }
auto pEvent = std::make_shared<RsMailStatusEvent>(); auto pEvent = std::make_shared<RsMailStatusEvent>();
@ -1418,10 +1405,9 @@ bool p3MsgService::MessageToDraft(MessageInfo &info, const std::string &msgParen
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
// RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
auto pEvent = std::make_shared<RsMailStatusEvent>(); auto pEvent = std::make_shared<RsMailStatusEvent>();
pEvent->mMailStatusEventCode = RsMailStatusEventCode::MESSAGE_SENT; pEvent->mMailStatusEventCode = RsMailStatusEventCode::MESSAGE_SENT;
pEvent->mChangedMsgIds.insert(std::to_string(msg->msgId));
rsEvents->postEvent(pEvent); rsEvents->postEvent(pEvent);
return true; return true;
@ -1452,7 +1438,7 @@ bool p3MsgService::getMessageTagTypes(MsgTagType& tags)
bool p3MsgService::setMessageTagType(uint32_t tagId, std::string& text, uint32_t rgb_color) bool p3MsgService::setMessageTagType(uint32_t tagId, std::string& text, uint32_t rgb_color)
{ {
int nNotifyType = 0; auto ev = std::make_shared<RsMailTagEvent>();
{ {
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
@ -1475,7 +1461,8 @@ bool p3MsgService::setMessageTagType(uint32_t tagId, std::string& text, uint32
mTags.insert(std::pair<uint32_t, RsMsgTagType*>(tagId, tagType)); mTags.insert(std::pair<uint32_t, RsMsgTagType*>(tagId, tagType));
nNotifyType = NOTIFY_TYPE_ADD; ev->mMailTagEventCode = RsMailTagEventCode::TAG_ADDED;
ev->mChangedMsgTagIds.insert(std::to_string(tagId));
} else { } else {
if (mit->second->text != text || mit->second->rgb_color != rgb_color) { if (mit->second->text != text || mit->second->rgb_color != rgb_color) {
/* modify existing tag */ /* modify existing tag */
@ -1489,16 +1476,17 @@ bool p3MsgService::setMessageTagType(uint32_t tagId, std::string& text, uint32
} }
mit->second->rgb_color = rgb_color; mit->second->rgb_color = rgb_color;
nNotifyType = NOTIFY_TYPE_MOD; ev->mMailTagEventCode = RsMailTagEventCode::TAG_CHANGED;
ev->mChangedMsgTagIds.insert(std::to_string(tagId));
} }
} }
} /* UNLOCKED */ } /* UNLOCKED */
if (nNotifyType) { if (!ev->mChangedMsgTagIds.empty()) {
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGE_TAGS, nNotifyType); rsEvents->postEvent(ev);
return true; return true;
} }
@ -1513,6 +1501,9 @@ bool p3MsgService::removeMessageTagType(uint32_t tagId)
return false; return false;
} }
auto msgEvent = std::make_shared<RsMailStatusEvent>();
msgEvent->mMailStatusEventCode = RsMailStatusEventCode::TAG_CHANGED;
{ {
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
@ -1540,7 +1531,10 @@ bool p3MsgService::removeMessageTagType(uint32_t tagId)
delete(tag); delete(tag);
mMsgTags.erase(mit1++); mMsgTags.erase(mit1++);
continue; }
if (msgEvent->mChangedMsgIds.find(std::to_string(mit1->first)) == msgEvent->mChangedMsgIds.end()) {
msgEvent->mChangedMsgIds.insert(std::to_string(mit1->first));
} }
} }
++mit1; ++mit1;
@ -1554,7 +1548,14 @@ bool p3MsgService::removeMessageTagType(uint32_t tagId)
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGE_TAGS, NOTIFY_TYPE_DEL); auto ev = std::make_shared<RsMailTagEvent>();
ev->mMailTagEventCode = RsMailTagEventCode::TAG_REMOVED;
ev->mChangedMsgTagIds.insert(std::to_string(tagId));
rsEvents->postEvent(ev);
if (!msgEvent->mChangedMsgIds.empty()) {
rsEvents->postEvent(msgEvent);
}
return true; return true;
} }
@ -1595,7 +1596,8 @@ bool p3MsgService::setMessageTag(const std::string &msgId, uint32_t tagId, bool
} }
} }
int nNotifyType = 0; auto ev = std::make_shared<RsMailStatusEvent>();
ev->mMailStatusEventCode = RsMailStatusEventCode::TAG_CHANGED;
{ {
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
@ -1614,7 +1616,7 @@ bool p3MsgService::setMessageTag(const std::string &msgId, uint32_t tagId, bool
mMsgTags.insert(std::pair<uint32_t, RsMsgTags*>(tag->msgId, tag)); mMsgTags.insert(std::pair<uint32_t, RsMsgTags*>(tag->msgId, tag));
nNotifyType = NOTIFY_TYPE_ADD; ev->mChangedMsgIds.insert(msgId);
} }
} else { } else {
RsMsgTags* tag = mit->second; RsMsgTags* tag = mit->second;
@ -1632,18 +1634,18 @@ bool p3MsgService::setMessageTag(const std::string &msgId, uint32_t tagId, bool
tag->tagIds.push_back(tagId); tag->tagIds.push_back(tagId);
/* keep the list sorted */ /* keep the list sorted */
tag->tagIds.sort(); tag->tagIds.sort();
nNotifyType = NOTIFY_TYPE_ADD; ev->mChangedMsgIds.insert(msgId);
} }
} else { } else {
if (tagId == 0) { if (tagId == 0) {
/* remove all */ /* remove all */
delete(tag); delete(tag);
mMsgTags.erase(mit); mMsgTags.erase(mit);
nNotifyType = NOTIFY_TYPE_DEL; ev->mChangedMsgIds.insert(msgId);
} else { } else {
if (lit != tag->tagIds.end()) { if (lit != tag->tagIds.end()) {
tag->tagIds.erase(lit); tag->tagIds.erase(lit);
nNotifyType = NOTIFY_TYPE_DEL; ev->mChangedMsgIds.insert(msgId);
if (tag->tagIds.empty()) { if (tag->tagIds.empty()) {
/* remove empty tag */ /* remove empty tag */
@ -1657,10 +1659,10 @@ bool p3MsgService::setMessageTag(const std::string &msgId, uint32_t tagId, bool
} /* UNLOCKED */ } /* UNLOCKED */
if (nNotifyType) { if (!ev->mChangedMsgIds.empty()) {
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGE_TAGS, nNotifyType); rsEvents->postEvent(ev);
return true; return true;
} }
@ -1687,8 +1689,9 @@ bool p3MsgService::MessageToTrash(const std::string &mid, bool bTrash)
std::map<uint32_t, RsMsgItem *>::iterator mit; std::map<uint32_t, RsMsgItem *>::iterator mit;
uint32_t msgId = atoi(mid.c_str()); uint32_t msgId = atoi(mid.c_str());
bool bChanged = false;
bool bFound = false; bool bFound = false;
auto pEvent = std::make_shared<RsMailStatusEvent>();
pEvent->mMailStatusEventCode = RsMailStatusEventCode::MESSAGE_CHANGED;
{ {
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
@ -1711,23 +1714,25 @@ bool p3MsgService::MessageToTrash(const std::string &mid, bool bTrash)
if (bTrash) { if (bTrash) {
if ((mi->msgFlags & RS_MSG_FLAGS_TRASH) == 0) { if ((mi->msgFlags & RS_MSG_FLAGS_TRASH) == 0) {
mi->msgFlags |= RS_MSG_FLAGS_TRASH; mi->msgFlags |= RS_MSG_FLAGS_TRASH;
bChanged = true; pEvent->mChangedMsgIds.insert(std::to_string(mi->msgId));
} }
} else { } else {
if (mi->msgFlags & RS_MSG_FLAGS_TRASH) { if (mi->msgFlags & RS_MSG_FLAGS_TRASH) {
mi->msgFlags &= ~RS_MSG_FLAGS_TRASH; mi->msgFlags &= ~RS_MSG_FLAGS_TRASH;
bChanged = true; pEvent->mChangedMsgIds.insert(std::to_string(mi->msgId));
} }
} }
} }
} }
if (bChanged) { if (!pEvent->mChangedMsgIds.empty()) {
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
checkOutgoingMessages(); checkOutgoingMessages();
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD); if(rsEvents) {
rsEvents->postEvent(pEvent);
}
} }
return bFound; return bFound;
@ -2111,14 +2116,12 @@ void p3MsgService::notifyDataStatus( const GRouterMsgPropagationId& id,
msgOutgoing.erase(it2); msgOutgoing.erase(it2);
#endif #endif
RsServer::notify()->notifyListChange( NOTIFY_LIST_MESSAGELIST,
NOTIFY_TYPE_ADD );
IndicateConfigChanged(); IndicateConfigChanged();
if(rsEvents) if(rsEvents)
{ {
auto pEvent = std::make_shared<RsMailStatusEvent>(); auto pEvent = std::make_shared<RsMailStatusEvent>();
pEvent->mMailStatusEventCode = RsMailStatusEventCode::NEW_MESSAGE; pEvent->mMailStatusEventCode = RsMailStatusEventCode::MESSAGE_CHANGED;
pEvent->mChangedMsgIds.insert(std::to_string(msg_id)); pEvent->mChangedMsgIds.insert(std::to_string(msg_id));
rsEvents->postEvent(pEvent); rsEvents->postEvent(pEvent);
} }
@ -2267,8 +2270,6 @@ bool p3MsgService::notifyGxsTransSendStatus( RsGxsTransId mailId,
} }
} }
RsServer::notify()->notifyListChange( NOTIFY_LIST_MESSAGELIST,
NOTIFY_TYPE_ADD );
IndicateConfigChanged(); IndicateConfigChanged();
} }
else if( status >= GxsTransSendStatus::FAILED_RECEIPT_SIGNATURE ) else if( status >= GxsTransSendStatus::FAILED_RECEIPT_SIGNATURE )

View File

@ -38,19 +38,19 @@
using namespace Tor; using namespace Tor;
AddOnionCommand::AddOnionCommand(HiddenService *service) AddOnionCommand::AddOnionCommand(HiddenService *service)
: m_service(service) : m_service(service), mSucceeded([](){}), mFailed([](int){})
{ {
Q_ASSERT(m_service); assert(m_service);
} }
bool AddOnionCommand::isSuccessful() const bool AddOnionCommand::isSuccessful() const
{ {
return statusCode() == 250 && m_errorMessage.isEmpty(); return statusCode() == 250 && m_errorMessage.empty();
} }
QByteArray AddOnionCommand::build() ByteArray AddOnionCommand::build()
{ {
QByteArray out("ADD_ONION"); ByteArray out("ADD_ONION");
if (m_service->privateKey().isLoaded()) { if (m_service->privateKey().isLoaded()) {
out += " "; out += " ";
@ -61,42 +61,44 @@ QByteArray AddOnionCommand::build()
out += " NEW:BEST"; // this is v3, but without control of key type. Generates a RSA1024 key on older Tor versions. out += " NEW:BEST"; // this is v3, but without control of key type. Generates a RSA1024 key on older Tor versions.
} }
foreach (const HiddenService::Target &target, m_service->targets()) { for(const HiddenService::Target& target: m_service->targets())
{
out += " Port="; out += " Port=";
out += QByteArray::number(target.servicePort); out += RsUtil::NumberToString(target.servicePort);
out += ","; out += ",";
out += target.targetAddress.toString().toLatin1(); out += target.targetAddress;
out += ":"; out += ":";
out += QByteArray::number(target.targetPort); out += RsUtil::NumberToString(target.targetPort);
} }
out.append("\r\n"); out.append("\r\n");
return out; return out;
} }
void AddOnionCommand::onReply(int statusCode, const QByteArray &data) void AddOnionCommand::onReply(int statusCode, const ByteArray &data)
{ {
TorControlCommand::onReply(statusCode, data); TorControlCommand::onReply(statusCode, data);
if (statusCode != 250) { if (statusCode != 250) {
m_errorMessage = QString::fromLatin1(data); m_errorMessage = data.toString();
return; return;
} }
const QByteArray keyPrefix("PrivateKey="); const ByteArray keyPrefix("PrivateKey=");
const QByteArray sidPrefix("ServiceID="); const ByteArray sidPrefix("ServiceID=");
if(data.startsWith("ServiceID=")){ if(data.startsWith(sidPrefix))
QByteArray service_id = data.mid(sidPrefix.size()); {
ByteArray service_id = data.mid(sidPrefix.size());
m_service->setServiceId(service_id); m_service->setServiceId(service_id);
} }
if (data.startsWith(keyPrefix)) { if (data.startsWith(keyPrefix))
{
QByteArray keyData(data.mid(keyPrefix.size())); ByteArray keyData(data.mid(keyPrefix.size()));
CryptoKey key; CryptoKey key;
if (!key.loadFromTorMessage(keyData)) { if (!key.loadFromTorMessage(keyData)) {
m_errorMessage = QStringLiteral("Key structure check failed"); m_errorMessage = "Key structure check failed";
return; return;
} }
@ -108,9 +110,9 @@ void AddOnionCommand::onFinished(int statusCode)
{ {
TorControlCommand::onFinished(statusCode); TorControlCommand::onFinished(statusCode);
if (isSuccessful()) if (isSuccessful())
emit succeeded(); mSucceeded();
else else
emit failed(statusCode); mFailed(statusCode);
} }

View File

@ -30,13 +30,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef ADDONIONCOMMAND_H #pragma once
#define ADDONIONCOMMAND_H
#include "TorControlCommand.h" #include "TorControlCommand.h"
#include <QList>
#include <QPair>
#include <QVariant>
namespace Tor namespace Tor
{ {
@ -45,33 +41,26 @@ class HiddenService;
class AddOnionCommand : public TorControlCommand 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: public:
AddOnionCommand(HiddenService *service); AddOnionCommand(HiddenService *service);
QByteArray build(); ByteArray build();
QString errorMessage() const { return m_errorMessage; } std::string errorMessage() const { return m_errorMessage; }
bool isSuccessful() const; bool isSuccessful() const;
signals: void set_succeeded_callback(const std::function<void(void)>& f) { mSucceeded=f;}
void succeeded(); void set_failed_callback(const std::function<void(int)>& f) { mFailed=f;}
void failed(int code);
protected: protected:
HiddenService *m_service; HiddenService *m_service;
QString m_errorMessage; std::string m_errorMessage;
virtual void onReply(int statusCode, const QByteArray &data); std::function<void(void)> mSucceeded;
std::function<void(int)> mFailed;
virtual void onReply(int statusCode, const ByteArray &data);
virtual void onFinished(int statusCode); virtual void onFinished(int statusCode);
}; };
} }
#endif // ADDONIONCOMMAND_H

View File

@ -38,27 +38,29 @@ AuthenticateCommand::AuthenticateCommand()
{ {
} }
QByteArray AuthenticateCommand::build(const QByteArray &data) ByteArray AuthenticateCommand::build(const ByteArray& data)
{ {
if (data.isNull()) if (data.isNull())
return QByteArray("AUTHENTICATE\r\n"); return ByteArray("AUTHENTICATE\r\n");
return QByteArray("AUTHENTICATE ") + data.toHex() + "\r\n"; return ByteArray("AUTHENTICATE ") + data.toHex() + "\r\n";
} }
void AuthenticateCommand::onReply(int statusCode, const QByteArray &data) void AuthenticateCommand::onReply(int statusCode, const ByteArray &data)
{ {
TorControlCommand::onReply(statusCode, data); TorControlCommand::onReply(statusCode, data);
m_statusMessage = QString::fromLatin1(data); m_statusMessage = data.toString();
} }
void AuthenticateCommand::onFinished(int statusCode) void AuthenticateCommand::onFinished(int statusCode)
{ {
if (statusCode == 515) { if (statusCode == 515) {
m_statusMessage = QStringLiteral("Authentication failed - incorrect password"); m_statusMessage = "Authentication failed - incorrect password";
} else if (statusCode != 250) { }
if (m_statusMessage.isEmpty()) else if (statusCode != 250)
m_statusMessage = QStringLiteral("Authentication failed (error %1").arg(statusCode); {
if (m_statusMessage.empty())
m_statusMessage = "Authentication failed (error " + RsUtil::NumberToString(statusCode) + ")";
} }
TorControlCommand::onFinished(statusCode); TorControlCommand::onFinished(statusCode);
} }

View File

@ -30,9 +30,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef AUTHENTICATECOMMAND_H #pragma once
#define AUTHENTICATECOMMAND_H
#include "bytearray.h"
#include "TorControlCommand.h" #include "TorControlCommand.h"
namespace Tor namespace Tor
@ -40,24 +40,20 @@ namespace Tor
class AuthenticateCommand : public TorControlCommand class AuthenticateCommand : public TorControlCommand
{ {
Q_OBJECT
public: public:
AuthenticateCommand(); AuthenticateCommand();
QByteArray build(const QByteArray &data = QByteArray()); ByteArray build(const ByteArray& data = ByteArray());
bool isSuccessful() const { return statusCode() == 250; } bool isSuccessful() const { return statusCode() == 250; }
QString errorMessage() const { return m_statusMessage; } std::string errorMessage() const { return m_statusMessage; }
protected: protected:
virtual void onReply(int statusCode, const QByteArray &data); virtual void onReply(int statusCode, const ByteArray &data);
virtual void onFinished(int statusCode); virtual void onFinished(int statusCode);
private: private:
QString m_statusMessage; std::string m_statusMessage;
}; };
} }
#endif // AUTHENTICATECOMMAND_H

View File

@ -0,0 +1,153 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* 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 <iostream>
#include "CryptoKey.h"
#include <openssl/bn.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include "stdio.h"
#include "util/rsdebug.h"
#include "util/rsrandom.h"
#include "util/rsdir.h"
#include "retroshare/rsids.h"
#include "bytearray.h"
#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
CryptoKey::CryptoKey()
{
}
CryptoKey::~CryptoKey()
{
clear();
}
void CryptoKey::clear()
{
key_data.clear();
}
bool CryptoKey::loadFromFile(const std::string& path)
{
FILE *file = fopen(path.c_str(),"r");
if (!file)
{
RsWarn() << "Failed to open Tor key file " << path << ": errno = " << errno ;
return false;
}
ByteArray data ;
int c;
while(EOF != (c=fgetc(file)))
data.push_back((unsigned char)c);
fclose(file);
if(data.startsWith("-----BEGIN RSA PRIVATE KEY-----"))
{
std::cerr << "Note: Reading/converting Tor v2 key format." << std::endl;
// This to be compliant with old format. New format is oblivious to the type of key so we dont need a header
data = data.replace(ByteArray("-----BEGIN RSA PRIVATE KEY-----"),ByteArray());
data = data.replace(ByteArray("-----END RSA PRIVATE KEY-----"),ByteArray());
data = data.replace(ByteArray("\n"),ByteArray());
data = data.replace(ByteArray("\t"),ByteArray());
data = ByteArray("RSA1024:")+data;
}
std::cerr << "Have read the following key: " << std::endl;
std::cerr << data.toString() << std::endl;
key_data = data;
return true;
}
bool CryptoKey::loadFromTorMessage(const ByteArray& b)
{
// note: We should probably check the structure a bit more, for security.
std::cerr << "Loading new key:" << std::endl;
if(b.startsWith("RSA1024"))
std::cerr << " type: RSA-1024 (Tor v2)" << std::endl;
else if(b.startsWith("ED25519-V3"))
std::cerr << " type: ED25519-V3 (Tor v3)" << std::endl;
else if(b.indexOf(':'))
{
std::cerr << " unknown type, or bad syntax in key: \"" << b.left(b.indexOf(':')).toString() << "\". Not accepted." << std::endl;
return false;
}
key_data = b;
return true;
}
/* Cryptographic hash of a password as expected by Tor's HashedControlPassword */
ByteArray torControlHashedPassword(const ByteArray &password)
{
ByteArray salt(8);
RsRandom::random_bytes(&salt[0],8);
uint32_t count = ((uint32_t)16 + (96 & 15)) << ((96 >> 4) + 6);
SHA_CTX hash;
SHA1_Init(&hash);
ByteArray tmp = salt + password;
while (count)
{
int c = std::min((size_t)count, tmp.size());
SHA1_Update(&hash, reinterpret_cast<const void*>(tmp.data()), 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 ByteArray("16:") + salt.toHex().toUpper() + ByteArray("60") + ByteArray(md, 20).toHex().toUpper();
}

View File

@ -30,22 +30,35 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef SECURERNG_H #pragma once
#define SECURERNG_H
#include <QByteArray> #include "bytearray.h"
class SecureRNG class CryptoKey
{ {
public: public:
static bool seed(); enum KeyType {
PrivateKey,
PublicKey
};
static void random(char *buf, int size); enum KeyFormat {
static QByteArray random(int size); PEM,
DER
};
static QByteArray randomPrintable(int length); CryptoKey();
static unsigned randomInt(unsigned max); ~CryptoKey();
static quint64 randomInt64(quint64 max);
bool loadFromFile(const std::string &path);
void clear();
const ByteArray bytes() const { return key_data; }
bool loadFromTorMessage(const ByteArray& b);
bool isLoaded() const { return !key_data.isNull(); }
private:
ByteArray key_data;
}; };
#endif // SECURERNG_H ByteArray torControlHashedPassword(const ByteArray &password);

View File

@ -32,7 +32,6 @@
#include "GetConfCommand.h" #include "GetConfCommand.h"
#include "StrUtil.h" #include "StrUtil.h"
#include <QDebug>
using namespace Tor; using namespace Tor;
@ -41,25 +40,25 @@ GetConfCommand::GetConfCommand(Type t)
{ {
} }
QByteArray GetConfCommand::build(const QByteArray &key) ByteArray GetConfCommand::build(const std::string &key)
{ {
return build(QList<QByteArray>() << key); return build(std::list<std::string> { key } );
} }
QByteArray GetConfCommand::build(const QList<QByteArray> &keys) ByteArray GetConfCommand::build(const std::list<std::string> &keys)
{ {
QByteArray out; ByteArray out;
if (type == GetConf) { if (type == GetConf) {
out = "GETCONF"; out = "GETCONF";
} else if (type == GetInfo) { } else if (type == GetInfo) {
out = "GETINFO"; out = "GETINFO";
} else { } else {
Q_ASSERT(false); assert(false);
return out; return out;
} }
foreach (const QByteArray &key, keys) { for(const ByteArray &key: keys) {
out.append(' '); out.push_back(' ');
out.append(key); out.append(key);
} }
@ -67,49 +66,29 @@ QByteArray GetConfCommand::build(const QList<QByteArray> &keys)
return out; return out;
} }
void GetConfCommand::onReply(int statusCode, const QByteArray &data) void GetConfCommand::onReply(int statusCode, const ByteArray &data)
{ {
TorControlCommand::onReply(statusCode, data); TorControlCommand::onReply(statusCode, data);
if (statusCode != 250) if (statusCode != 250)
return; return;
int kep = data.indexOf('='); int kep = data.indexOf('=');
QString key = QString::fromLatin1(data.mid(0, kep)); std::string key = data.mid(0, kep).toString();
QVariant value; std::string value;
if (kep >= 0) if (kep >= 0)
value = QString::fromLatin1(unquotedString(data.mid(kep + 1))); value = unquotedString(data.mid(kep + 1)).toString();
m_lastKey = key; m_lastKey = key;
QVariantMap::iterator it = m_results.find(key); m_results[key].push_back(value);
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) void GetConfCommand::onDataLine(const ByteArray &data)
{ {
if (m_lastKey.isEmpty()) { if (m_lastKey.empty()) {
qWarning() << "torctrl: Unexpected data line in GetConf command"; RsWarn() << "torctrl: Unexpected data line in GetConf command";
return; return;
} }
m_results[m_lastKey].push_back(data.toString());
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() void GetConfCommand::onDataFinished()
@ -117,8 +96,13 @@ void GetConfCommand::onDataFinished()
m_lastKey.clear(); m_lastKey.clear();
} }
QVariant GetConfCommand::get(const QByteArray &key) const std::list<std::string> GetConfCommand::get(const std::string& key) const
{ {
return m_results.value(QString::fromLatin1(key)); auto it = m_results.find(key);
if(it != m_results.end())
return it->second;
else
return std::list<std::string>();
} }

View File

@ -30,23 +30,16 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef GETCONFCOMMAND_H #pragma once
#define GETCONFCOMMAND_H
#include <map>
#include "TorControlCommand.h" #include "TorControlCommand.h"
#include <QList>
#include <QVariantMap>
namespace Tor namespace Tor
{ {
class GetConfCommand : public TorControlCommand class GetConfCommand : public TorControlCommand
{ {
Q_OBJECT
Q_DISABLE_COPY(GetConfCommand)
Q_PROPERTY(QVariantMap results READ results CONSTANT)
public: public:
enum Type { enum Type {
GetConf, GetConf,
@ -56,22 +49,20 @@ public:
GetConfCommand(Type type); GetConfCommand(Type type);
QByteArray build(const QByteArray &key); ByteArray build(const std::string &key);
QByteArray build(const QList<QByteArray> &keys); ByteArray build(const std::list<std::string> &keys);
const QVariantMap &results() const { return m_results; } const std::map<std::string,std::list<std::string> > &results() const { return m_results; }
QVariant get(const QByteArray &key) const; std::list<std::string> get(const std::string &key) const;
protected: protected:
virtual void onReply(int statusCode, const QByteArray &data); virtual void onReply(int statusCode, const ByteArray &data);
virtual void onDataLine(const QByteArray &data); virtual void onDataLine(const ByteArray &data);
virtual void onDataFinished(); virtual void onDataFinished();
private: private:
QVariantMap m_results; std::map<std::string,std::list<std::string> > m_results;
QString m_lastKey; std::string m_lastKey;
}; };
} }
#endif // GETCONFCOMMAND_H

View File

@ -32,34 +32,32 @@
#include "HiddenService.h" #include "HiddenService.h"
#include "TorControl.h" #include "TorControl.h"
#include "TorSocket.h"
#include "CryptoKey.h" #include "CryptoKey.h"
#include "Useful.h" #include "util/rsdir.h"
#include <QDir>
#include <QFile> #include <fstream>
#include <QTimer>
#include <QDebug>
using namespace Tor; using namespace Tor;
HiddenService::HiddenService(QObject *parent) HiddenService::HiddenService(HiddenServiceClient *client)
: QObject(parent), m_status(NotCreated) : m_status(NotCreated), m_client(client)
{ {
} }
HiddenService::HiddenService(const QString &path, QObject *parent) HiddenService::HiddenService(HiddenServiceClient *client,const std::string& path)
: QObject(parent), m_dataPath(path), m_status(NotCreated) : m_dataPath(path), m_status(NotCreated), m_client(client)
{ {
/* Set the initial status and, if possible, load the hostname */ /* Set the initial status and, if possible, load the hostname */
if (QDir(m_dataPath).exists(QLatin1String("private_key"))) { if(RsDirUtil::fileExists(m_dataPath + "/private_key"))
{
loadPrivateKey(); loadPrivateKey();
if (!m_hostname.isEmpty()) if (!m_hostname.empty())
m_status = Offline; m_status = Offline;
} }
} }
HiddenService::HiddenService(const CryptoKey &privateKey, const QString &path, QObject *parent) HiddenService::HiddenService(HiddenServiceClient *client,const CryptoKey &privateKey, const std::string &path)
: QObject(parent), m_dataPath(path), m_status(NotCreated) : m_dataPath(path), m_status(NotCreated), m_client(client)
{ {
setPrivateKey(privateKey); setPrivateKey(privateKey);
m_status = Offline; m_status = Offline;
@ -73,69 +71,89 @@ void HiddenService::setStatus(Status newStatus)
Status old = m_status; Status old = m_status;
m_status = newStatus; m_status = newStatus;
emit statusChanged(m_status, old); if(m_client)
m_client->hiddenServiceStatusChanged(m_status,old); //emit statusChanged(m_status, old);
if (m_status == Online) if (m_status == Online)
emit serviceOnline(); if(m_client)
m_client->hiddenServiceOnline(); //emit serviceOnline();
} }
void HiddenService::addTarget(const Target &target) void HiddenService::addTarget(const Target &target)
{ {
m_targets.append(target); m_targets.push_back(target);
} }
void HiddenService::addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort) void HiddenService::addTarget(uint16_t servicePort, std::string targetAddress, uint16_t targetPort)
{ {
Target t = { targetAddress, servicePort, targetPort }; Target t = { targetAddress, servicePort, targetPort };
m_targets.append(t); m_targets.push_back(t);
} }
void HiddenService::setServiceId(const QByteArray& sid) void HiddenService::setServiceId(const ByteArray& sid)
{ {
m_service_id = sid; m_service_id = sid;
m_hostname = sid + ".onion"; m_hostname = sid.toString() + ".onion";
emit hostnameChanged(); if(m_client)
m_client->hiddenServiceHostnameChanged(); // emit hostnameChanged();
} }
void HiddenService::setPrivateKey(const CryptoKey &key) void HiddenService::setPrivateKey(const CryptoKey &key)
{ {
if (m_privateKey.isLoaded()) { if (m_privateKey.isLoaded()) {
BUG() << "Cannot change the private key on an existing HiddenService"; RsErr() << "Cannot change the private key on an existing HiddenService";
return; return;
} }
#ifdef TO_REMOVE
if (!key.isPrivate()) {
BUG() << "Cannot create a hidden service with a public key";
return;
}
#endif
m_privateKey = key; m_privateKey = key;
emit privateKeyChanged(); if(m_client)
m_client->hiddenServicePrivateKeyChanged(); //emit privateKeyChanged();
} }
void HiddenService::loadPrivateKey() bool HiddenService::loadPrivateKey()
{ {
if (m_privateKey.isLoaded() || m_dataPath.isEmpty()) if (m_privateKey.isLoaded() || m_dataPath.empty())
return; return false;
bool ok = m_privateKey.loadFromFile(m_dataPath + QLatin1String("/private_key")); bool ok = m_privateKey.loadFromFile(m_dataPath + "/private_key");
if (!ok) { if (!ok) {
qWarning() << "Failed to load hidden service key"; RsWarn() << "Failed to load hidden service key";
return; return false;
} }
emit privateKeyChanged(); // Also load the onion address stored in "hostname" file. This is not needed, except for early display
// of the onion address, since the onion address will be re-computed by Tor (to the same value) when the
// service is published.
std::ifstream i((m_dataPath + "/hostname").c_str());
if(i)
{
std::string s;
i >> s;
if(ByteArray(s).endsWith(ByteArray(".onion")))
{
m_hostname = s;
m_service_id = s.substr(0,s.length() - std::string(".onion").length());
RsDbg() << "Read existing hostname: " << m_hostname;
}
i.close();
}
if(m_client)
m_client->hiddenServicePrivateKeyChanged(); // emit privateKeyChanged();
return true;
} }
void HiddenService::servicePublished() void HiddenService::servicePublished()
{ {
loadPrivateKey(); loadPrivateKey();
if (m_hostname.isEmpty()) { if (m_hostname.empty()) {
std::cerr << "Failed to read hidden service hostname" << std::endl; std::cerr << "Failed to read hidden service hostname" << std::endl;
return; return;
} }

View File

@ -30,31 +30,35 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef HIDDENSERVICE_H #pragma once
#define HIDDENSERVICE_H
#include <QObject>
#include <QHostAddress>
#include <QList>
#include "CryptoKey.h" #include "CryptoKey.h"
#include "bytearray.h"
namespace Tor namespace Tor
{ {
class TorSocket; // This class is used to receive synchroneous notifications from the hidden service.
// Each client should implement its own notification handling.
class HiddenService : public QObject class HiddenServiceClient
{ {
Q_OBJECT public:
Q_DISABLE_COPY(HiddenService) virtual void hiddenServiceStatusChanged(int /* newStatus */, int /* oldStatus */) =0;
virtual void hiddenServiceOnline() =0;
virtual void hiddenServicePrivateKeyChanged() =0;
virtual void hiddenServiceHostnameChanged() =0;
};
friend class TorControlPrivate; class HiddenService
{
friend class TorControl;
public: public:
struct Target struct Target
{ {
QHostAddress targetAddress; std::string targetAddress;
quint16 servicePort, targetPort; uint16_t servicePort, targetPort;
}; };
enum Status enum Status
@ -64,45 +68,42 @@ public:
Online /* Published */ Online /* Published */
}; };
HiddenService(QObject *parent = 0); HiddenService(HiddenServiceClient *client);
HiddenService(const QString &dataPath, QObject *parent = 0); HiddenService(HiddenServiceClient *client, const std::string &dataPath);
HiddenService(const CryptoKey &privateKey, const QString &dataPath = QString(), QObject *parent = 0); HiddenService(HiddenServiceClient *client, const CryptoKey &privateKey, const std::string &dataPath = std::string());
Status status() const { return m_status; } Status status() const { return m_status; }
const QString& hostname() const { return m_hostname; } const std::string& hostname() const { return m_hostname; }
const QString serviceId() const { return QString(m_service_id); } const std::string serviceId() const { return m_service_id.toString(); }
const QString& dataPath() const { return m_dataPath; } const std::string& dataPath() const { return m_dataPath; }
CryptoKey privateKey() { return m_privateKey; } CryptoKey privateKey() { return m_privateKey; }
void setPrivateKey(const CryptoKey &privateKey); void setPrivateKey(const CryptoKey &privateKey);
void setServiceId(const QByteArray& sid); void setServiceId(const ByteArray &sid);
const QList<Target> &targets() const { return m_targets; } const std::list<Target> &targets() const { return m_targets; }
void addTarget(const Target &target); void addTarget(const Target &target);
void addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort); void addTarget(uint16_t servicePort, std::string targetAddress, uint16_t targetPort);
signals:
void statusChanged(int newStatus, int oldStatus);
void serviceOnline();
void privateKeyChanged();
void hostnameChanged();
private slots:
void servicePublished(); void servicePublished();
private: private:
QString m_dataPath; std::string m_dataPath;
QList<Target> m_targets; std::list<Target> m_targets;
QString m_hostname; std::string m_hostname;
Status m_status; Status m_status;
CryptoKey m_privateKey; CryptoKey m_privateKey;
QByteArray m_service_id; ByteArray m_service_id;
void loadPrivateKey(); bool loadPrivateKey();
void setStatus(Status newStatus); void setStatus(Status newStatus);
HiddenServiceClient *m_client;
// make the object non copyable
HiddenService(const HiddenService&) {}
HiddenService& operator=(const HiddenService&) { return *this ; }
}; };
} }
#endif // HIDDENSERVICE_H

View File

@ -30,10 +30,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <assert.h>
#include "PendingOperation.h" #include "PendingOperation.h"
PendingOperation::PendingOperation(QObject *parent) PendingOperation::PendingOperation()
: QObject(parent), m_finished(false) : m_finished(false),mFinishedCallback([](){}), mSuccessCallback([](){}),mErrorCallback([](const std::string&){})
{ {
} }
@ -44,41 +45,44 @@ bool PendingOperation::isFinished() const
bool PendingOperation::isSuccess() const bool PendingOperation::isSuccess() const
{ {
return m_finished && m_errorMessage.isNull(); return m_finished && m_errorMessage.empty();
} }
bool PendingOperation::isError() const bool PendingOperation::isError() const
{ {
return m_finished && !m_errorMessage.isNull(); return m_finished && !m_errorMessage.empty();
} }
QString PendingOperation::errorMessage() const std::string PendingOperation::errorMessage() const
{ {
return m_errorMessage; return m_errorMessage;
} }
void PendingOperation::finishWithError(const QString &message) void PendingOperation::finishWithError(const std::string &message)
{ {
if (message.isEmpty()) if (message.empty())
m_errorMessage = QStringLiteral("Unknown Error"); m_errorMessage = "Unknown Error";
m_errorMessage = message; m_errorMessage = message;
if (!m_finished) { if (!m_finished) {
m_finished = true; m_finished = true;
emit finished();
emit error(m_errorMessage); mErrorCallback(m_errorMessage);
mFinishedCallback();
} }
} }
void PendingOperation::finishWithSuccess() void PendingOperation::finishWithSuccess()
{ {
Q_ASSERT(m_errorMessage.isNull()); assert(m_errorMessage.empty());
if (!m_finished) { if (!m_finished) {
m_finished = true; m_finished = true;
emit finished();
if (isSuccess()) if (isSuccess())
emit success(); mSuccessCallback();
mFinishedCallback();
} }
} }

View File

@ -30,10 +30,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef PENDINGOPERATION_H #pragma once
#define PENDINGOPERATION_H
#include <QObject> #include <functional>
#include <string>
/* Represents an asynchronous operation for reporting status /* Represents an asynchronous operation for reporting status
* *
@ -48,40 +48,27 @@
* PendingOperation will emit finished() and one of success() or * PendingOperation will emit finished() and one of success() or
* error() when completed. * error() when completed.
*/ */
class PendingOperation : public QObject class PendingOperation
{ {
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: public:
PendingOperation(QObject *parent = 0); PendingOperation();
bool isFinished() const; bool isFinished() const;
bool isSuccess() const; bool isSuccess() const;
bool isError() const; bool isError() const;
QString errorMessage() const; std::string errorMessage() const;
signals: void finishWithError(const std::string &errorMessage);
// 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(); void finishWithSuccess();
void set_finished_callback(const std::function<void(void)>& f) { mFinishedCallback = f; }
private: private:
bool m_finished; bool m_finished;
QString m_errorMessage; std::string m_errorMessage;
std::function<void(void)> mFinishedCallback;
std::function<void(void)> mSuccessCallback;
std::function<void(const std::string&)> mErrorCallback;
}; };
Q_DECLARE_METATYPE(PendingOperation*)
#endif

View File

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

View File

@ -30,11 +30,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef PROTOCOLINFOCOMMAND_H #pragma once
#define PROTOCOLINFOCOMMAND_H
#include "TorControlCommand.h" #include "TorControlCommand.h"
#include <QFlags> #include "retroshare/rsflags.h"
namespace Tor namespace Tor
{ {
@ -43,36 +42,31 @@ class TorControl;
class ProtocolInfoCommand : public TorControlCommand class ProtocolInfoCommand : public TorControlCommand
{ {
Q_OBJECT
Q_DISABLE_COPY(ProtocolInfoCommand)
public: public:
enum AuthMethod enum
{ {
AuthUnknown = 0, AuthUnknown = 0x0,
AuthNull = 0x1, AuthNull = 0x1,
AuthHashedPassword = 0x2, AuthHashedPassword = 0x2,
AuthCookie = 0x4 AuthCookie = 0x4
}; };
Q_DECLARE_FLAGS(AuthMethods, AuthMethod) typedef uint8_t AuthMethod;
ProtocolInfoCommand(TorControl *manager); ProtocolInfoCommand(TorControl *manager);
QByteArray build(); ByteArray build();
AuthMethods authMethods() const { return m_authMethods; } AuthMethod authMethods() const { return m_authMethods; }
QString torVersion() const { return m_torVersion; } std::string torVersion() const { return m_torVersion; }
QString cookieFile() const { return m_cookieFile; } std::string cookieFile() const { return m_cookieFile; }
protected: protected:
virtual void onReply(int statusCode, const QByteArray &data); virtual void onReply(int statusCode, const ByteArray &data);
private: private:
TorControl *manager; TorControl *manager;
AuthMethods m_authMethods; AuthMethod m_authMethods;
QString m_torVersion; std::string m_torVersion;
QString m_cookieFile; std::string m_cookieFile;
}; };
} }
#endif // PROTOCOLINFOCOMMAND_H

View File

@ -36,7 +36,7 @@
using namespace Tor; using namespace Tor;
SetConfCommand::SetConfCommand() SetConfCommand::SetConfCommand()
: m_resetMode(false) : m_resetMode(false), mConfSucceeded([](){}), mConfFailed([](int){})
{ {
} }
@ -50,57 +50,44 @@ bool SetConfCommand::isSuccessful() const
return statusCode() == 250; return statusCode() == 250;
} }
QByteArray SetConfCommand::build(const QByteArray &key, const QByteArray &value) ByteArray SetConfCommand::build(const std::string &key, const std::string &value)
{ {
return build(QList<QPair<QByteArray, QByteArray> >() << qMakePair(key, value)); return build(std::list<std::pair<std::string, std::string> > { std::make_pair(key, value) } );
} }
QByteArray SetConfCommand::build(const QVariantMap &data) ByteArray SetConfCommand::build(const std::list<std::pair<std::string, std::string> >& data)
{ {
QList<QPair<QByteArray, QByteArray> > out; ByteArray out(m_resetMode ? "RESETCONF" : "SETCONF");
for (QVariantMap::ConstIterator it = data.begin(); it != data.end(); it++) { for (auto& p:data)
QByteArray key = it.key().toLatin1(); {
out += " " ;
out += p.first;
if (static_cast<QMetaType::Type>(it.value().type()) == QMetaType::QVariantList) { if (!p.second.empty())
QVariantList values = it.value().value<QVariantList>(); {
foreach (const QVariant &value, values) out += "=" ;
out.append(qMakePair(key, value.toString().toLatin1())); out += quotedString(p.second);
} else {
out.append(qMakePair(key, it.value().toString().toLatin1()));
} }
} }
return build(out);
}
QByteArray SetConfCommand::build(const QList<QPair<QByteArray, QByteArray> > &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"); out.append("\r\n");
return out; return out;
} }
void SetConfCommand::onReply(int statusCode, const QByteArray &data) void SetConfCommand::onReply(int statusCode, const ByteArray &data)
{ {
TorControlCommand::onReply(statusCode, data); TorControlCommand::onReply(statusCode, data);
if (statusCode != 250) if (statusCode != 250)
m_errorMessage = QString::fromLatin1(data); m_errorMessage = data.toString();
} }
void SetConfCommand::onFinished(int statusCode) void SetConfCommand::onFinished(int statusCode)
{ {
TorControlCommand::onFinished(statusCode); TorControlCommand::onFinished(statusCode);
if (isSuccessful()) if (isSuccessful())
emit setConfSucceeded(); mConfSucceeded();
else else
emit setConfFailed(statusCode); mConfFailed(statusCode);
} }

View File

@ -30,49 +30,39 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef SETCONFCOMMAND_H #pragma once
#define SETCONFCOMMAND_H
#include <functional>
#include "TorControlCommand.h" #include "TorControlCommand.h"
#include <QList>
#include <QPair>
#include <QVariant>
namespace Tor namespace Tor
{ {
class SetConfCommand : public TorControlCommand 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: public:
SetConfCommand(); SetConfCommand();
void setResetMode(bool resetMode); void setResetMode(bool resetMode);
QByteArray build(const QByteArray &key, const QByteArray &value); ByteArray build(const std::string &key, const std::string &value);
QByteArray build(const QVariantMap &data); ByteArray build(const std::list<std::pair<std::string, std::string> > &data);
QByteArray build(const QList<QPair<QByteArray, QByteArray> > &data);
QString errorMessage() const { return m_errorMessage; } std::string errorMessage() const { return m_errorMessage; }
bool isSuccessful() const; bool isSuccessful() const;
signals: void set_ConfSucceeded_callback(const std::function<void(void)>& f) { mConfSucceeded=f; }
void setConfSucceeded(); void set_ConfFailed_callback (const std::function<void(int code)>& f){ mConfFailed=f; }
void setConfFailed(int code);
protected: protected:
QString m_errorMessage; std::string m_errorMessage;
bool m_resetMode; bool m_resetMode;
virtual void onReply(int statusCode, const QByteArray &data); std::function<void(void)> mConfSucceeded;
std::function<void(int code)> mConfFailed;
virtual void onReply(int statusCode, const ByteArray &data);
virtual void onFinished(int statusCode); virtual void onFinished(int statusCode);
}; };
} }
#endif // SETCONFCOMMAND_H

View File

@ -32,14 +32,14 @@
#include "StrUtil.h" #include "StrUtil.h"
QByteArray quotedString(const QByteArray &string) ByteArray quotedString(const ByteArray &string)
{ {
QByteArray out; ByteArray out;
out.reserve(string.size() * 2); out.reserve(string.size() * 2);
out.append('"'); out.push_back('"');
for (int i = 0; i < string.size(); ++i) for (ByteArray::size_type i = 0; i < string.size(); ++i)
{ {
switch (string[i]) switch (string[i])
{ {
@ -50,48 +50,48 @@ QByteArray quotedString(const QByteArray &string)
out.append("\\\\"); out.append("\\\\");
break; break;
default: default:
out.append(string[i]); out.push_back(string[i]);
break; break;
} }
} }
out.append('"'); out.push_back('"');
return out; return out;
} }
QByteArray unquotedString(const QByteArray &string) ByteArray unquotedString(const ByteArray& string)
{ {
if (string.size() < 2 || string[0] != '"') if (string.size() < 2 || string[0] != '"')
return string; return string;
QByteArray out; ByteArray out;
out.reserve(string.size() - 2); out.reserve(string.size() - 2);
for (int i = 1; i < string.size(); ++i) for (ByteArray::size_type i = 1; i < string.size(); ++i)
{ {
switch (string[i]) switch (string[i])
{ {
case '\\': case '\\':
if (++i < string.size()) if (++i < string.size())
out.append(string[i]); out.push_back(string[i]);
break; break;
case '"': case '"':
return out; return out;
default: default:
out.append(string[i]); out.push_back(string[i]);
} }
} }
return out; return out;
} }
QList<QByteArray> splitQuotedStrings(const QByteArray &input, char separator) std::list<ByteArray> splitQuotedStrings(const ByteArray &input, char separator)
{ {
QList<QByteArray> out; std::list<ByteArray> out;
bool inquote = false; bool inquote = false;
int start = 0; ByteArray::size_type start = 0;
for (int i = 0; i < input.size(); ++i) for (ByteArray::size_type i = 0; i < input.size(); ++i)
{ {
switch (input[i]) switch (input[i])
{ {
@ -106,13 +106,13 @@ QList<QByteArray> splitQuotedStrings(const QByteArray &input, char separator)
if (!inquote && input[i] == separator) if (!inquote && input[i] == separator)
{ {
out.append(input.mid(start, i - start)); out.push_back(input.mid(start, i - start));
start = i+1; start = i+1;
} }
} }
if (start < input.size()) if (start < input.size())
out.append(input.mid(start)); out.push_back(input.mid(start));
return out; return out;
} }

View File

@ -33,14 +33,15 @@
#ifndef STRINGUTIL_H #ifndef STRINGUTIL_H
#define STRINGUTIL_H #define STRINGUTIL_H
#include <QByteArray> #include <list>
#include <QList>
QByteArray quotedString(const QByteArray &string); #include "bytearray.h"
ByteArray quotedString(const ByteArray &string);
/* Return the unquoted contents of a string, either until an end quote or an unescaped separator character. */ /* Return the unquoted contents of a string, either until an end quote or an unescaped separator character. */
QByteArray unquotedString(const QByteArray &string); ByteArray unquotedString(const ByteArray &string);
QList<QByteArray> splitQuotedStrings(const QByteArray &input, char separator); std::list<ByteArray> splitQuotedStrings(const ByteArray& input, char separator);
#endif // STRINGUTIL_H #endif // STRINGUTIL_H

View File

@ -0,0 +1,793 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* 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 <time.h>
#include <fstream>
#include "util/rsdir.h"
#include "retroshare/rstor.h"
#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 "StrUtil.h"
#include "PendingOperation.h"
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;
TorControl::TorControl()
: mControlPort(0),mSocksPort(0),mStatus(NotConnected), mTorStatus(TorUnknown),mHasOwnership(false)
{
mSocket = new TorControlSocket(this);
}
TorControl::~TorControl()
{
delete(mSocket);
}
static RsTorConnectivityStatus torConnectivityStatus(Tor::TorControl::Status t)
{
switch(t)
{
default:
case TorControl::Error: return RsTorConnectivityStatus::ERROR;
case TorControl::NotConnected: return RsTorConnectivityStatus::NOT_CONNECTED;
case TorControl::Connecting: return RsTorConnectivityStatus::CONNECTING;
case TorControl::SocketConnected: return RsTorConnectivityStatus::SOCKET_CONNECTED;
case TorControl::Authenticating: return RsTorConnectivityStatus::AUTHENTICATING;
case TorControl::Authenticated: return RsTorConnectivityStatus::AUTHENTICATED;
case TorControl::HiddenServiceReady: return RsTorConnectivityStatus::HIDDEN_SERVICE_READY;
case TorControl::Unknown: return RsTorConnectivityStatus::UNKNOWN;
}
}
static RsTorStatus torStatus(Tor::TorControl::TorStatus t)
{
switch(t)
{
default:
case TorControl::TorUnknown: return RsTorStatus::UNKNOWN;
case TorControl::TorOffline: return RsTorStatus::OFFLINE;
case TorControl::TorReady: return RsTorStatus::READY;
}
}
void TorControl::setStatus(TorControl::Status n)
{
if (n == mStatus)
return;
TorControl::Status old = mStatus;
mStatus = n;
if (old == TorControl::Error)
mErrorMessage.clear();
std::cerr << "Setting status to s=" << mStatus << " val=" << (int)torConnectivityStatus(mStatus) << std::endl;
if(rsEvents)
{
auto ev = std::make_shared<RsTorManagerEvent>();
ev->mTorManagerEventType = RsTorManagerEventCode::TOR_STATUS_CHANGED;
ev->mTorStatus = ::torStatus(mTorStatus);
ev->mTorConnectivityStatus = torConnectivityStatus(mStatus);
rsEvents->sendEvent(ev);
}
mStatusChanged_callback(mStatus, old);
}
void TorControl::setTorStatus(TorControl::TorStatus n)
{
if (n == mTorStatus)
return;
RsDbg() << "Setting TorStatus=" << n ;
mTorStatus = n;
if(rsEvents)
{
auto ev = std::make_shared<RsTorManagerEvent>();
ev->mTorManagerEventType = RsTorManagerEventCode::TOR_STATUS_CHANGED;
ev->mTorStatus = ::torStatus(mTorStatus);
ev->mTorConnectivityStatus = torConnectivityStatus(mStatus);
rsEvents->sendEvent(ev);
}
}
void TorControl::setError(const std::string &message)
{
mErrorMessage = message;
setStatus(TorControl::Error);
RsWarn() << "torctrl: Error:" << mErrorMessage;
}
TorControl::Status TorControl::status() const
{
return mStatus;
}
TorControl::TorStatus TorControl::torStatus() const
{
return mTorStatus;
}
std::string TorControl::torVersion() const
{
return mTorVersion;
}
std::string TorControl::errorMessage() const
{
return mErrorMessage;
}
bool TorControl::hasConnectivity() const
{
return torStatus() == TorReady && !mSocksAddress.empty();
}
std::string TorControl::socksAddress() const
{
return mSocksAddress;
}
uint16_t TorControl::socksPort() const
{
return mSocksPort;
}
std::list<HiddenService*> TorControl::hiddenServices() const
{
return mServices;
}
std::map<std::string,std::string> TorControl::bootstrapStatus() const
{
return mBootstrapStatus;
}
void TorControl::setAuthPassword(const ByteArray &password)
{
mAuthPassword = password;
}
void TorControl::connect(const std::string &address, uint16_t port)
{
if (status() > Connecting)
{
torCtrlDebug() << "Ignoring TorControl::connect due to existing connection" << std::endl;
return;
}
mTorAddress = address;
mControlPort = port;
setTorStatus(TorUnknown);
if(mSocket->isRunning())
mSocket->fullstop();
setStatus(Connecting);
if(mSocket->connectToHost(address, port))
{
setStatus(SocketConnected);
setTorStatus(TorOffline); // connected and running, but not yet ready
}
}
void TorControl::reconnect()
{
assert(!mTorAddress.empty() && mControlPort);
if (mTorAddress.empty() || !mControlPort || status() >= Connecting)
return;
setStatus(Connecting);
mSocket->connectToHost(mTorAddress, mControlPort);
}
void TorControl::authenticateReply(TorControlCommand *sender)
{
AuthenticateCommand *command = dynamic_cast<AuthenticateCommand*>(sender);
assert(command);
assert(mStatus == TorControl::Authenticating);
if (!command)
return;
if (!command->isSuccessful()) {
setError(command->errorMessage());
return;
}
torCtrlDebug() << "torctrl: Authentication successful" << std::endl;
setStatus(TorControl::Authenticated);
TorControlCommand *clientEvents = new TorControlCommand;
clientEvents->set_replyLine_callback([this](int code, const ByteArray &data) { statusEvent(code,data);});
mSocket->registerEvent(ByteArray("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 (mHasOwnership)
saveConfiguration();
}
void TorControl::authenticate()
{
assert(mStatus == TorControl::SocketConnected);
setStatus(TorControl::Authenticating);
torCtrlDebug() << "torctrl: Connected socket; querying information for authentication" << std::endl;
ProtocolInfoCommand *command = new ProtocolInfoCommand(this);
command->set_finished_callback( [this](TorControlCommand *sender) { protocolInfoReply(sender); });
command->set_replyLine_callback([this](int code, const ByteArray &data) { statusEvent(code,data); });
mSocket->sendCommand(command, command->build());
}
void TorControl::socketDisconnected()
{
/* Clear some internal state */
mTorVersion.clear();
mSocksAddress.clear();
mSocksPort = 0;
setTorStatus(TorControl::TorUnknown);
/* This emits the disconnected() signal as well */
setStatus(TorControl::NotConnected);
}
void TorControl::socketError(const std::string& s)
{
setError("Connection failed: " + s);
}
void TorControl::protocolInfoReply(TorControlCommand *sender)
{
ProtocolInfoCommand *info = dynamic_cast<ProtocolInfoCommand*>(sender);
if (!info)
return;
mTorVersion = info->torVersion();
if (mStatus == TorControl::Authenticating)
{
AuthenticateCommand *auth = new AuthenticateCommand;
auth->set_finished_callback( [this](TorControlCommand *sender) { authenticateReply(sender); });
ByteArray data;
ProtocolInfoCommand::AuthMethod methods = info->authMethods();
if(methods & ProtocolInfoCommand::AuthNull)
{
torCtrlDebug() << "torctrl: Using null authentication" << std::endl;
data = auth->build();
}
else if ((methods & ProtocolInfoCommand::AuthCookie) && !info->cookieFile().empty())
{
std::string cookieFile = info->cookieFile();
std::string cookieError;
torCtrlDebug() << "torctrl: Using cookie authentication with file" << cookieFile << std::endl;
FILE *f = fopen(cookieFile.c_str(),"r");
if(f)
{
std::string cookie;
char c;
while((c=getc(f))!=EOF)
cookie += c;
fclose(f);
/* 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 = "Unexpected file size";
}
else
cookieError = "Cannot open file " + cookieFile + ". errno=" + RsUtil::NumberToString(errno);
if (!cookieError.empty() || 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 & ProtocolInfoCommand::AuthHashedPassword) && !mAuthPassword.empty())
{
torCtrlDebug() << "torctrl: Unable to read authentication cookie file:" << cookieError << std::endl;
goto usePasswordAuth;
}
setError("Unable to read authentication cookie file: " + cookieError);
delete auth;
return;
}
}
else if ((methods & ProtocolInfoCommand::AuthHashedPassword) && !mAuthPassword.empty())
{
usePasswordAuth:
torCtrlDebug() << "torctrl: Using hashed password authentication with AuthPasswd=\"" << mAuthPassword.toString() << "\"" << std::endl;
data = auth->build(mAuthPassword);
}
else
{
if (methods & ProtocolInfoCommand::AuthHashedPassword)
setError("Tor requires a control password to connect, but no password is configured.");
else
setError("Tor is not configured to accept any supported authentication methods.");
delete auth;
return;
}
mSocket->sendCommand(auth, data);
}
}
void TorControl::getTorInfo()
{
assert(isConnected());
GetConfCommand *command = new GetConfCommand(GetConfCommand::GetInfo);
//connect(command, &TorControlCommand::finished, this, &TorControl::getTorInfoReply);
command->set_finished_callback( [this](TorControlCommand *sender) { getTorInfoReply(sender); });
command->set_replyLine_callback([this](int code, const ByteArray &data) { statusEvent(code,data); });
std::list<std::string> keys{ "status/circuit-established","status/bootstrap-phase" };
keys.push_back("net/listeners/socks");
mSocket->sendCommand(command, command->build(keys));
}
void TorControl::getTorInfoReply(TorControlCommand *sender)
{
GetConfCommand *command = dynamic_cast<GetConfCommand*>(sender);
if (!command)
return;
std::list<ByteArray> listenAddresses = splitQuotedStrings(command->get("net/listeners/socks").front(), ' ');
for (const auto& add:listenAddresses) {
ByteArray value = unquotedString(add);
int sepp = value.indexOf(':');
std::string address(value.mid(0, sepp).toString());
uint16_t port = (uint16_t)value.mid(sepp+1).toInt();
/* 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 (mSocksAddress.empty() || address == mSocket->peerAddress()) {
mSocksAddress = address;
mSocksPort = port;
if (address == mSocket->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 (!mSocksAddress.empty()) {
torCtrlDebug() << "torctrl: SOCKS address is " << mSocksAddress << ":" << mSocksPort << std::endl;
if(rsEvents)
{
auto ev = std::make_shared<RsTorManagerEvent>();
ev->mTorManagerEventType = RsTorManagerEventCode::TOR_CONNECTIVITY_CHANGED;
ev->mTorConnectivityStatus = torConnectivityStatus(mStatus);
ev->mTorStatus = ::torStatus(mTorStatus);
rsEvents->sendEvent(ev);
}
}
if (ByteArray(command->get("status/circuit-established").front()).toInt() == 1)
{
torCtrlDebug() << "torctrl: Tor indicates that circuits have been established; state is TorReady" << std::endl;
setTorStatus(TorControl::TorReady);
}
// else
// setTorStatus(TorControl::TorOffline);
auto bootstrap = command->get("status/bootstrap-phase");
if (!bootstrap.empty())
updateBootstrap(splitQuotedStrings(bootstrap.front(), ' '));
}
void TorControl::addHiddenService(HiddenService *service)
{
if (std::find(mServices.begin(),mServices.end(),service) != mServices.end())
return;
mServices.push_back(service);
}
void TorControl::publishServices()
{
torCtrlDebug() << "Publish Services... " ;
assert(isConnected());
if (mServices.empty())
{
std::cerr << "No service regstered!" << std::endl;
return;
}
std::cerr << std::endl;
if (torVersionAsNewAs("0.2.7")) {
for(HiddenService *service: mServices)
{
if (service->hostname().empty())
torCtrlDebug() << "torctrl: Creating a new hidden service" << std::endl;
else
torCtrlDebug() << "torctrl: Publishing hidden service: " << service->hostname() << std::endl;
AddOnionCommand *onionCommand = new AddOnionCommand(service);
//protocolInfoReplyQObject::connect(onionCommand, &AddOnionCommand::succeeded, service, &HiddenService::servicePublished);
onionCommand->set_succeeded_callback( [this,service]() { checkHiddenService(service) ; });
mSocket->sendCommand(onionCommand, onionCommand->build());
}
} else {
torCtrlDebug() << "torctrl: Using legacy SETCONF hidden service configuration for tor" << mTorVersion << std::endl;
SetConfCommand *command = new SetConfCommand;
std::list<std::pair<std::string,std::string> > torConfig;
for(HiddenService *service: mServices)
{
if (service->dataPath().empty())
continue;
if (service->privateKey().isLoaded() && !RsDirUtil::fileExists(service->dataPath() + "/private_key")) {
// This case can happen if tor is downgraded after the profile is created
RsWarn() << "Cannot publish ephemeral hidden services with this version of tor; skipping";
continue;
}
torCtrlDebug() << "torctrl: Configuring hidden service at" << service->dataPath() << std::endl;
torConfig.push_back(std::make_pair("HiddenServiceDir", service->dataPath()));
const std::list<HiddenService::Target> &targets = service->targets();
for (auto tit:targets)
{
std::string target = RsUtil::NumberToString(tit.servicePort) + " "
+tit.targetAddress + ":"
+RsUtil::NumberToString(tit.targetPort);
torConfig.push_back(std::make_pair("HiddenServicePort", target));
}
command->set_ConfSucceeded_callback( [this,service]() { checkHiddenService(service); });
//QObject::connect(command, &SetConfCommand::setConfSucceeded, service, &HiddenService::servicePublished);
}
if (!torConfig.empty())
mSocket->sendCommand(command, command->build(torConfig));
}
}
void TorControl::checkHiddenService(HiddenService *service)
{
service->servicePublished();
if(service->status() == HiddenService::Online)
{
RsDbg() << "Hidden service published and ready!" ;
setStatus(TorControl::HiddenServiceReady);
}
}
void TorControl::shutdown()
{
if (!hasOwnership()) {
RsWarn() << "torctrl: Ignoring shutdown command for a tor instance I don't own";
return;
}
mSocket->sendCommand(ByteArray("SIGNAL SHUTDOWN\r\n"));
}
void TorControl::shutdownSync()
{
if (!hasOwnership()) {
RsWarn() << "torctrl: Ignoring shutdown command for a tor instance I don't own";
return;
}
shutdown();
while (mSocket->moretowrite(0))
std::this_thread::sleep_for(std::chrono::milliseconds(100));
mSocket->close();
}
void TorControl::statusEvent(int /* code */, const ByteArray &data)
{
std::list<ByteArray> tokens = splitQuotedStrings(data.trimmed(), ' ');
if (tokens.size() < 3)
return;
const ByteArray& tok2 = *(++(++tokens.begin()));
torCtrlDebug() << "torctrl: status event:" << data.trimmed().toString() << " tok2=\"" << tok2.toString() << "\"" << std::endl;
if (tok2 == "CIRCUIT_ESTABLISHED")
setTorStatus(TorControl::TorReady);
else if (tok2 == "CIRCUIT_NOT_ESTABLISHED")
setTorStatus(TorControl::TorOffline);
else if (tok2 == "BOOTSTRAP")
{
tokens.pop_front();
updateBootstrap(tokens);
}
}
void TorControl::updateBootstrap(const std::list<ByteArray> &data)
{
std::cerr << "********** Updating bootstrap status ************" << std::endl;
mBootstrapStatus.clear();
// WARN or NOTICE
mBootstrapStatus["severity"] = (*data.begin()).toString();
auto dat = data.begin();
++dat;
for(;dat!=data.end();++dat) { // for(int i = 1; i < data.size(); i++) {
int equals = (*dat).indexOf('=');
ByteArray key = (*dat).mid(0, equals);
ByteArray value;
if (equals >= 0)
value = unquotedString((*dat).mid(equals + 1));
mBootstrapStatus[key.toLower().toString()] = value.toString();
}
if(rsEvents)
{
auto ev = std::make_shared<RsTorManagerEvent>();
ev->mTorManagerEventType = RsTorManagerEventCode::BOOTSTRAP_STATUS_CHANGED;
ev->mTorConnectivityStatus = torConnectivityStatus(mStatus);
ev->mTorStatus = ::torStatus(mTorStatus);
rsEvents->sendEvent(ev);
}
}
TorControlCommand *TorControl::getConfiguration(const std::string& options)
{
GetConfCommand *command = new GetConfCommand(GetConfCommand::GetConf);
command->set_replyLine_callback([this](int code, const ByteArray &data) { statusEvent(code,data); });
mSocket->sendCommand(command, command->build(options));
return command;
}
TorControlCommand *TorControl::setConfiguration(const std::list<std::pair<std::string,std::string> >& options)
{
SetConfCommand *command = new SetConfCommand;
command->setResetMode(true);
mSocket->sendCommand(command, command->build(options));
return command;
}
namespace Tor {
class SaveConfigOperation : public PendingOperation
{
public:
SaveConfigOperation()
: PendingOperation(), command(0)
{
}
void start(TorControlSocket *socket)
{
assert(!command);
command = new GetConfCommand(GetConfCommand::GetInfo);
command->set_finished_callback([this](TorControlCommand *sender){ configTextReply(sender); });
socket->sendCommand(command, command->build(std::list<std::string> { "config-text" , "config-file" } ));
}
void configTextReply(TorControlCommand * /*sender*/)
{
assert(command);
if (!command)
return;
auto lpath = command->get("config-file");
std::string path = (lpath.empty()?std::string():lpath.front());
if (path.empty()) {
finishWithError("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
auto filename = RsDirUtil::getFileName(path);
if(filename != "torrc" || !RsDirUtil::fileExists(path))
{
finishWithError("Refusing to write torrc to unacceptable path " + path);
return;
}
std::ofstream file(path);
if (!file.is_open()) {
finishWithError("Failed opening torrc file for writing: permissions error?");
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
};
auto configText = command->get("config-text") ;
for(const auto& value: configText)
{
ByteArray line(value);
bool skip = false;
for (const char **key = bannedKeys; *key; key++) {
if (line.startsWith(*key)) {
skip = true;
break;
}
}
if (skip)
continue;
file << line.toString() << std::endl;
}
file.close();
torCtrlDebug() << "torctrl: Wrote torrc file" << std::endl;
finishWithSuccess();
}
private:
GetConfCommand *command;
};
}
PendingOperation *TorControl::saveConfiguration()
{
if (!hasOwnership()) {
RsWarn() << "torctrl: Ignoring save configuration command for a tor instance I don't own";
return 0;
}
SaveConfigOperation *operation = new SaveConfigOperation();
operation->set_finished_callback( [operation]() { delete operation; });
operation->start(mSocket);
return operation;
}
bool TorControl::hasOwnership() const
{
return mHasOwnership;
}
void TorControl::takeOwnership()
{
mHasOwnership = true;
mSocket->sendCommand(ByteArray("TAKEOWNERSHIP\r\n"));
// Reset PID-based polling
std::list<std::pair<std::string,std::string> > options;
options.push_back(std::make_pair("__OwningControllerProcess",std::string()));
setConfiguration(options);
}
bool TorControl::torVersionAsNewAs(const std::string& match) const
{
auto split = ByteArray(torVersion()).split(ByteArray(".-"));
auto matchSplit = ByteArray(match).split(ByteArray(".-"));
int split_size = split.size();
auto b_split(split.begin());
auto b_matchsplit(matchSplit.begin());
for(int i=0;;)
{
int currentVal,matchVal;
bool ok1 = RsUtil::StringToInt((*b_split).toString(),currentVal);
bool ok2 = RsUtil::StringToInt((*b_matchsplit).toString(),matchVal);
if (!ok1 || !ok2)
return false;
if (currentVal > matchVal)
return true;
if (currentVal < matchVal)
return false;
++i;
if(i >= split_size)
return false;
++b_split;
++b_matchsplit;
}
// Versions are equal, up to the length of match
return true;
}

View File

@ -0,0 +1,152 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* 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.
*/
#pragma once
#include <iostream>
#include "PendingOperation.h"
#include "bytearray.h"
#include "TorControlSocket.h"
namespace Tor
{
class HiddenService;
class TorControlSocket;
class TorControlCommand;
class TorControl : public TorControlSocketClient
{
public:
enum Status
{
Error = 0x00,
NotConnected = 0x01,
Connecting = 0x02,
SocketConnected = 0x03,
Authenticating = 0x04,
Authenticated = 0x05,
HiddenServiceReady = 0x06,
Unknown = 0x07
};
enum TorStatus
{
TorUnknown = 0x00,
TorOffline = 0x01,
TorReady = 0x02
};
explicit TorControl();
virtual ~TorControl();
/* Information */
Status status() const;
TorStatus torStatus() const;
std::string torVersion() const;
bool torVersionAsNewAs(const std::string &version) const;
std::string errorMessage() const;
bool hasConnectivity() const;
std::string socksAddress() const;
uint16_t socksPort() const;
/* Authentication */
void setAuthPassword(const ByteArray& password);
/* Connection */
bool isConnected() const { return status() >= Authenticated; }
void connect(const std::string &address, uint16_t port);
void authenticate();
/* 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 */
std::list<HiddenService*> hiddenServices() const;
void addHiddenService(HiddenService *service);
std::map<std::string, std::string> bootstrapStatus() const;
TorControlCommand *getConfiguration(const std::string &options);
TorControlCommand *setConfiguration(const std::list<std::pair<std::string, std::string> > &options);
PendingOperation *saveConfiguration();
void set_statusChanged_callback(const std::function<void(int,int)>& f) { mStatusChanged_callback = f ;}
void set_connected_callback(const std::function<void(void)>& f) { mConnected_callback = f ;}
void set_disconnected_callback(const std::function<void(void)>& f) { mDisconnected_callback = f ;}
virtual void socketError(const std::string &s) override;
/* Instruct Tor to shutdown */
void shutdown();
/* Call shutdown(), and wait synchronously for the command to be written */
void shutdownSync();
void reconnect();
void getTorInfo();
private:
TorControlSocket *mSocket;
std::string mTorAddress;
std::string mErrorMessage;
std::string mTorVersion;
ByteArray mAuthPassword;
std::string mSocksAddress;
std::list<HiddenService*> mServices;
uint16_t mControlPort, mSocksPort;
TorControl::Status mStatus;
TorControl::TorStatus mTorStatus;
std::map<std::string,std::string> mBootstrapStatus;
bool mHasOwnership;
void checkHiddenService(HiddenService *service);
void getTorInfoReply(TorControlCommand *sender);
void setStatus(TorControl::Status n);
void statusEvent(int code, const ByteArray &data);
void setTorStatus(TorControl::TorStatus n);
void updateBootstrap(const std::list<ByteArray>& data);
void setError(const std::string& message);
void publishServices();
void protocolInfoReply(TorControlCommand *sender);
void socketDisconnected();
void authenticateReply(TorControlCommand *sender);
std::function<void(int,int)> mStatusChanged_callback;
std::function<void(void)> mConnected_callback;
std::function<void(void)> mDisconnected_callback;
};
}

View File

@ -31,33 +31,33 @@
*/ */
#include "TorControlCommand.h" #include "TorControlCommand.h"
#include <QDebug>
using namespace Tor; using namespace Tor;
TorControlCommand::TorControlCommand() TorControlCommand::TorControlCommand()
: m_finalStatus(0) : m_finalStatus(0),
mReplyLine ( std::function<void(int, const ByteArray &)>([](int, const ByteArray &){})),
mFinished ( std::function<void(TorControlCommand*)>([](TorControlCommand*){}))
{ {
} }
void TorControlCommand::onReply(int statusCode, const QByteArray &data) void TorControlCommand::onReply(int statusCode, const ByteArray &data)
{ {
emit replyLine(statusCode, data); mReplyLine(statusCode, data);
} }
void TorControlCommand::onFinished(int statusCode) void TorControlCommand::onFinished(int statusCode)
{ {
m_finalStatus = statusCode; m_finalStatus = statusCode;
emit finished(); mFinished(this);
} }
void TorControlCommand::onDataLine(const QByteArray &data) void TorControlCommand::onDataLine(const ByteArray &/*data*/)
{ {
Q_UNUSED(data);
} }
void TorControlCommand::onDataFinished() void TorControlCommand::onDataFinished()
{ {
qWarning() << "torctrl: Unexpected data response for command"; RsWarn() << "torctrl: Unexpected data response for command";
} }

View File

@ -30,41 +30,44 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef TORCONTROLCOMMAND_H #pragma once
#define TORCONTROLCOMMAND_H
#include <QObject> #include <functional>
#include <QByteArray> #include "bytearray.h"
namespace Tor namespace Tor
{ {
class TorControlCommand : public QObject class ProtocolInfoCommand;
{
Q_OBJECT
Q_DISABLE_COPY(TorControlCommand)
class TorControlCommand
{
friend class TorControlSocket; friend class TorControlSocket;
public: public:
TorControlCommand(); TorControlCommand();
virtual ~TorControlCommand()=default;
int statusCode() const { return m_finalStatus; } int statusCode() const { return m_finalStatus; }
signals: void set_replyLine_callback( const std::function<void(int statusCode, const ByteArray &data)>& f) { mReplyLine=f ; }
void replyLine(int statusCode, const QByteArray &data); void set_finished_callback( const std::function<void(TorControlCommand *sender)>& f) { mFinished=f; };
void finished();
protected: public:
virtual void onReply(int statusCode, const QByteArray &data); virtual void onReply(int statusCode, const ByteArray &data);
virtual void onFinished(int statusCode); virtual void onFinished(int statusCode);
virtual void onDataLine(const QByteArray &data); virtual void onDataLine(const ByteArray &data);
virtual void onDataFinished(); virtual void onDataFinished();
private: private:
int m_finalStatus; int m_finalStatus;
// Disable copy
TorControlCommand(const TorControlCommand&){}
TorControlCommand& operator=(const TorControlCommand&){ return *this; }
std::function<void(int statusCode, const ByteArray &data)> mReplyLine;
std::function<void(TorControlCommand *sender)> mFinished;
}; };
} }
#endif // TORCONTROLCOMMAND_H

View File

@ -34,15 +34,12 @@
#include "TorControlSocket.h" #include "TorControlSocket.h"
#include "TorControlCommand.h" #include "TorControlCommand.h"
#include <QDebug>
using namespace Tor; using namespace Tor;
TorControlSocket::TorControlSocket(QObject *parent) TorControlSocket::TorControlSocket(TorControlSocketClient *client)
: QTcpSocket(parent), currentCommand(0), inDataReply(false) : RsThreadedTcpSocket(),currentCommand(0), inDataReply(false),mClient(client)
{ {
connect(this, SIGNAL(readyRead()), this, SLOT(process()));
connect(this, SIGNAL(disconnected()), this, SLOT(clear()));
} }
TorControlSocket::~TorControlSocket() TorControlSocket::~TorControlSocket()
@ -50,24 +47,43 @@ TorControlSocket::~TorControlSocket()
clear(); clear();
} }
void TorControlSocket::sendCommand(TorControlCommand *command, const QByteArray &data) bool TorControlSocket::connectToHost(const std::string& tcp_address,uint16_t tcp_port)
{ {
Q_ASSERT(data.endsWith("\r\n")); if(RsTcpSocket::connect(tcp_address,tcp_port))
{
start("TorControlSocket");
return true;
}
else
return false;
commandQueue.append(command); }
write(data); std::string TorControlSocket::peerAddress() const
{
if(connectionState() == State::CONNECTED)
return connectAddress();
else
return std::string();
}
void TorControlSocket::sendCommand(TorControlCommand *command, const ByteArray& data)
{
assert(data.endsWith(ByteArray("\r\n")));
std::cerr << "[TOR CTRL] Sent: \"" << QString(data.trimmed()).toStdString() << "\"" << std::endl; commandQueue.push_back(command);
senddata((void*)data.data(),data.size());
std::cerr << "[TOR CTRL] Sent: \"" << data.trimmed().toString() << "\"" << std::endl;
} }
void TorControlSocket::registerEvent(const QByteArray &event, TorControlCommand *command) void TorControlSocket::registerEvent(const ByteArray &event, TorControlCommand *command)
{ {
eventCommands.insert(event, command); eventCommands.insert(std::make_pair(event, command));
QByteArray data("SETEVENTS"); ByteArray data("SETEVENTS");
foreach (const QByteArray &key, eventCommands.keys()) { for(auto it:eventCommands)
{
data += ' '; data += ' ';
data += key; data += it.first;
} }
data += "\r\n"; data += "\r\n";
@ -76,30 +92,53 @@ void TorControlSocket::registerEvent(const QByteArray &event, TorControlCommand
void TorControlSocket::clear() void TorControlSocket::clear()
{ {
qDeleteAll(commandQueue); for(auto cmd:commandQueue) delete cmd;
commandQueue.clear(); commandQueue.clear();
qDeleteAll(eventCommands);
for(auto cmd:eventCommands) delete cmd.second;
eventCommands.clear(); eventCommands.clear();
inDataReply = false; inDataReply = false;
currentCommand = 0; currentCommand = 0;
} }
void TorControlSocket::setError(const QString &message) void TorControlSocket::setError(const std::string &message)
{ {
m_errorMessage = message; m_errorMessage = message;
emit error(message); mClient->socketError(message);
abort(); abort();
} }
ByteArray TorControlSocket::readline(int s)
{
ByteArray b(s);
int real_size;
if(! (real_size = RsTcpSocket::readline(b.data(),s)))
return ByteArray();
else
{
b.resize(real_size);
return b;
}
}
void TorControlSocket::process() void TorControlSocket::process()
{ {
for (;;) { for (;;) {
if (!canReadLine()) if (!moretoread(0))
return; return;
QByteArray line = readLine(5120); ByteArray line = readline(5120);
if (!line.endsWith("\r\n")) {
setError(QStringLiteral("Invalid control message syntax")); if(line.empty()) // This happens when the incoming buffer isn't empty yet doesn't have a full line already.
{
std::this_thread::sleep_for(std::chrono::milliseconds(50));
continue;
}
if (!line.endsWith(ByteArray("\r\n"))) {
setError("Invalid control message syntax");
return; return;
} }
line.chop(2); line.chop(2);
@ -118,7 +157,7 @@ void TorControlSocket::process()
} }
if (line.size() < 4) { if (line.size() < 4) {
setError(QStringLiteral("Invalid control message syntax")); setError("Invalid control message syntax");
return; return;
} }
@ -131,7 +170,7 @@ void TorControlSocket::process()
line = line.mid(4); line = line.mid(4);
if (!isFinalReply && !inDataReply && type != '-') { if (!isFinalReply && !inDataReply && type != '-') {
setError(QStringLiteral("Invalid control message syntax")); setError("Invalid control message syntax");
return; return;
} }
@ -140,10 +179,15 @@ void TorControlSocket::process()
if (!currentCommand) { if (!currentCommand) {
int space = line.indexOf(' '); int space = line.indexOf(' ');
if (space > 0) if (space > 0)
currentCommand = eventCommands.value(line.mid(0, space)); {
auto it = eventCommands.find(line.mid(0, space).toString());
if(it != eventCommands.end())
currentCommand = it->second;
}
if (!currentCommand) { if (!currentCommand) {
qWarning() << "torctrl: Ignoring unknown event"; RsWarn() << "torctrl: Ignoring unknown event";
continue; continue;
} }
} }
@ -156,23 +200,36 @@ void TorControlSocket::process()
continue; continue;
} }
if (commandQueue.isEmpty()) { if (commandQueue.empty()) {
qWarning() << "torctrl: Received unexpected data"; RsWarn() << "torctrl: Received unexpected data";
continue; continue;
} }
TorControlCommand *command = commandQueue.first(); TorControlCommand *command = commandQueue.front();
if (command) if (command)
command->onReply(statusCode, line); command->onReply(statusCode, line);
if (inDataReply) { if (inDataReply) {
currentCommand = command; currentCommand = command;
} else if (isFinalReply) { } else if (isFinalReply) {
commandQueue.takeFirst(); commandQueue.pop_front();
if (command) { if (command) {
command->onFinished(statusCode); command->onFinished(statusCode);
command->deleteLater(); delete command; // should we "delete later" ?
} }
} }
} }
} }
int TorControlSocket::tick()
{
bool rw = RsTcpSocket::tick();
if(moretoread(0))
process();
if(!rw)
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // temporisation when nothing happens
return 0; // not sure about what we should return here.
}

View File

@ -30,48 +30,58 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef TORCONTROLSOCKET_H #pragma once
#define TORCONTROLSOCKET_H
#include <QTcpSocket> #include "pqi/rstcpsocket.h"
#include <QQueue> #include "bytearray.h"
namespace Tor namespace Tor
{ {
class TorControlCommand; class TorControlCommand;
class TorControlSocket : public QTcpSocket class TorControlSocketClient
{ {
Q_OBJECT
public: public:
explicit TorControlSocket(QObject *parent = 0); virtual void socketError(const std::string& s) = 0;
};
class TorControlSocket : public RsThreadedTcpSocket
{
public:
explicit TorControlSocket(TorControlSocketClient *client);
virtual ~TorControlSocket(); virtual ~TorControlSocket();
QString errorMessage() const { return m_errorMessage; } std::string errorMessage() const { return m_errorMessage; }
void registerEvent(const QByteArray &event, TorControlCommand *handler); bool connectToHost(const std::string& tcp_address,uint16_t tcp_port);
void registerEvent(const ByteArray &event, TorControlCommand *handler);
void sendCommand(const QByteArray &data) { sendCommand(0, data); } void sendCommand(const ByteArray& data) { sendCommand(0, data); }
void sendCommand(TorControlCommand *command, const QByteArray &data); void sendCommand(TorControlCommand *command, const ByteArray &data);
signals: ByteArray readline(int s);
void error(const QString &message);
// threaded TcpSocket
virtual int tick() override;
std::string peerAddress() const;
const std::string& errorString() const { return m_errorMessage ;}
private slots:
void process(); void process();
void clear(); void clear();
private: private:
QQueue<TorControlCommand*> commandQueue; std::list<TorControlCommand*> commandQueue;
QHash<QByteArray,TorControlCommand*> eventCommands; std::map<ByteArray,TorControlCommand*> eventCommands;
QString m_errorMessage; std::string m_errorMessage;
TorControlCommand *currentCommand; TorControlCommand *currentCommand;
bool inDataReply; bool inDataReply;
TorControlSocketClient *mClient;
void setError(const QString &message); void setError(const std::string& message);
}; };
} }
#endif // TORCONTROLSOCKET_H

View File

@ -0,0 +1,877 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* 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 <iostream>
#include <fstream>
#include <stdio.h>
// This works on linux only. I have no clue how to do that on windows. Anyway, this
// is only needed for an assert that should normaly never be triggered.
#if !defined(_WIN32) && !defined(__MINGW32__)
#include <sys/syscall.h>
#endif
#include "util/rsdir.h"
#include "retroshare/rsinit.h"
#include "TorManager.h"
#include "TorProcess.h"
#include "TorControl.h"
#include "CryptoKey.h"
#include "HiddenService.h"
#include "GetConfCommand.h"
using namespace Tor;
static TorManager *rsTor = nullptr;
namespace Tor
{
class TorManagerPrivate : public TorProcessClient
{
public:
TorManager *q;
TorProcess *process;
TorControl *control;
std::string dataDir;
std::string hiddenServiceDir;
std::list<std::string> logMessages;
std::string errorMessage;
bool configNeeded;
HiddenService *hiddenService ;
explicit TorManagerPrivate(TorManager *parent = 0);
virtual ~TorManagerPrivate();
std::string torExecutablePath() const;
bool createDataDir(const std::string &path);
bool createDefaultTorrc(const std::string &path);
void setError(const std::string &errorMessage);
virtual void processStateChanged(int state) override;
virtual void processErrorChanged(const std::string &errorMessage) override;
virtual void processLogMessage(const std::string &message) override;
//public slots:
void controlStatusChanged(int status);
void getConfFinished(TorControlCommand *sender);
};
}
TorManager::TorManager()
: d(new TorManagerPrivate(this))
{
}
TorManager::~TorManager()
{
delete(d);
}
TorManagerPrivate::TorManagerPrivate(TorManager *parent)
: q(parent)
, process(0)
, control(new TorControl())
, configNeeded(false)
, hiddenService(NULL)
{
control->set_statusChanged_callback([this](int new_status,int /*old_status*/) { controlStatusChanged(new_status); });
}
TorManagerPrivate::~TorManagerPrivate()
{
delete(control);
}
TorManager *TorManager::instance()
{
static TorManager *p = 0;
if (!p)
p = new TorManager();
return p;
}
TorControl *TorManager::control()
{
return d->control;
}
TorProcess *TorManager::process()
{
return d->process;
}
std::string TorManager::torDataDirectory() const
{
return d->dataDir;
}
void TorManager::setTorDataDirectory(const std::string &path)
{
d->dataDir = path;
if (!d->dataDir.empty() && !ByteArray(d->dataDir).endsWith('/'))
d->dataDir += '/';
}
std::string TorManager::hiddenServiceDirectory() const
{
return d->hiddenServiceDir;
}
void TorManager::setHiddenServiceDirectory(const std::string &path)
{
d->hiddenServiceDir = path;
if (!d->hiddenServiceDir.empty() && !(d->hiddenServiceDir.back() == '/'))
d->hiddenServiceDir += '/';
}
static bool test_listening_port(const std::string& /*address*/,uint16_t port)
{
int sockfd;
struct sockaddr_in serv_addr ;
/* First call to socket() function */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
return false;
/* Initialize socket structure */
memset((char *) &serv_addr, 0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port);
/* Now bind the host address using bind() call.*/
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
close(sockfd);
return false;
}
unix_fcntl_nonblock(sockfd);
int res = listen(sockfd,5);
close(sockfd);
if(!res)
return true;
return false;
}
bool TorManager::setupHiddenService()
{
if(d->hiddenService != NULL)
{
RsErr() << "TorManager: setupHiddenService() called twice! Not doing anything this time." ;
return true ;
}
std::string keyData ;//= m_settings->read("serviceKey").toString();
std::string legacyDir = d->hiddenServiceDir;
RsDbg() << "TorManager: setting up hidden service." << std::endl;
if(legacyDir.empty())
{
RsErr() << "legacy dir not set! Cannot proceed." ;
return false ;
}
RsDbg() << "Using legacy dir: " << legacyDir ;
auto key_path = RsDirUtil::makePath(legacyDir,"/private_key");
if (!legacyDir.empty() && RsDirUtil::fileExists(key_path))
{
std::cerr << "Attempting to load key from legacy filesystem format from file \"" << key_path << "\"" << std::endl;
d->hiddenService = new Tor::HiddenService(this,legacyDir);
if(!d->hiddenService->privateKey().bytes().empty())
{
RsDbg() << "Got key from legacy dir: " ;
RsDbg() << d->hiddenService->privateKey().bytes().toHex().toString() ;
}
else
RsWarn() << "Failed to load existing hidden service. Creating a new one." ;
}
else
{
d->hiddenService = new Tor::HiddenService(this,legacyDir);
RsDbg() << "Creating new hidden service." << std::endl;
}
assert(d->hiddenService);
// Generally, these are not used, and we bind to localhost and port 0
// for an automatic (and portable) selection.
std::string address = "127.0.0.1"; // we only listen from localhost
unsigned short hidden_service_port = 7934;//(quint16)m_settings->read("localListenPort").toInt();
do
{
hidden_service_port = 1025 + (RsRandom::random_u32() >> 17);
std::cerr << "Testing listening address:port " << address << ":" << hidden_service_port ;
std::cerr.flush();
}
while(!test_listening_port(address,hidden_service_port));
std::cerr << ": OK - Adding hidden service to TorControl." << std::endl;
// Note: 9878 is quite arbitrary, but since each RS node generates its own hidden service, all of them
// can use the same port without any conflict.
d->hiddenService->addTarget(9878, "127.0.0.1",hidden_service_port);
control()->addHiddenService(d->hiddenService);
return true ;
}
void TorManager::hiddenServiceStatusChanged(int new_status,int old_status)
{
std::cerr << "Hidden service status changed from " << old_status << " to " << new_status << std::endl;
if(rsEvents)
{
auto ev = std::make_shared<RsTorManagerEvent>();
ev->mTorManagerEventType = RsTorManagerEventCode::TOR_STATUS_CHANGED;
ev->mTorConnectivityStatus = RsTorConnectivityStatus::HIDDEN_SERVICE_READY;
ev->mTorStatus = RsTorStatus::READY;
rsEvents->sendEvent(ev);
}
}
void TorManager::hiddenServicePrivateKeyChanged()
{
if(!d->hiddenService)
return ;
std::string key = d->hiddenService->privateKey().bytes().toString();
std::ofstream s(d->hiddenServiceDir + "/private_key");
#ifdef TO_REMOVE
s << "-----BEGIN RSA PRIVATE KEY-----" << endl;
for(int i=0;i<key.length();i+=64)
s << key.mid(i,64) << endl ;
s << "-----END RSA PRIVATE KEY-----" << endl;
#endif
s << key ;
s.close();
std::cerr << "Hidden service private key changed!" << std::endl;
std::cerr << key << std::endl;
}
void TorManager::hiddenServiceHostnameChanged()
{
if(!d->hiddenService)
return ;
std::string outfile2_name = RsDirUtil::makePath(d->hiddenServiceDir,"/hostname") ;
std::ofstream of(outfile2_name);
std::string hostname(d->hiddenService->hostname());
of << hostname << std::endl;
of.close();
std::cerr << "Hidden service hostname changed: " << hostname << std::endl;
}
bool TorManager::configurationNeeded() const
{
return d->configNeeded;
}
const std::list<std::string>& TorManager::logMessages() const
{
return d->logMessages;
}
bool TorManager::hasError() const
{
return !d->errorMessage.empty();
}
std::string TorManager::errorMessage() const
{
return d->errorMessage;
}
bool TorManager::startTorManager()
{
if (!d->errorMessage.empty()) {
d->errorMessage.clear();
//emit errorChanged(); // not needed because there's no error to handle
}
#ifdef TODO
SettingsObject settings("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(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("Invalid control port settings from environment or configuration");
return false;
}
if (address.isNull())
address = QHostAddress::LocalHost;
d->control->setAuthPassword(password);
d->control->connect(address, port);
}
else
#endif
{
// Launch a bundled Tor instance
std::string executable = d->torExecutablePath();
std::cerr << "Executable path: " << executable << std::endl;
if (executable.empty()) {
d->setError("Cannot find tor executable");
return false;
}
if (!d->process) {
d->process = new TorProcess(d);
// QObject::connect(d->process, SIGNAL(stateChanged(int)), d, SLOT(processStateChanged(int)));
// QObject::connect(d->process, SIGNAL(errorMessageChanged(std::string)), d, SLOT(processErrorChanged(std::string)));
// QObject::connect(d->process, SIGNAL(logMessage(std::string)), d, SLOT(processLogMessage(std::string)));
}
if (!RsDirUtil::checkCreateDirectory(d->dataDir))
{
d->setError(std::string("Cannot write data location: ") + d->dataDir);
return false;
}
std::string defaultTorrc = RsDirUtil::makePath(d->dataDir,"default_torrc");
if (!RsDirUtil::fileExists(defaultTorrc) && !d->createDefaultTorrc(defaultTorrc))
{
d->setError("Cannot write data files: "+defaultTorrc);
return false;
}
std::string torrc = RsDirUtil::makePath(d->dataDir,"torrc");
uint64_t file_size;
bool torrc_exists = RsDirUtil::checkFile(torrc,file_size);
if(!torrc_exists || torrc.size() == 0)
{
d->configNeeded = true;
if(rsEvents)
{
auto ev = std::make_shared<RsTorManagerEvent>();
ev->mTorManagerEventType = RsTorManagerEventCode::CONFIGURATION_NEEDED;
ev->mTorConnectivityStatus = RsTorConnectivityStatus::UNKNOWN;
ev->mTorStatus = RsTorStatus::UNKNOWN;
rsEvents->sendEvent(ev);
}
//emit configurationNeededChanged();
}
std::cerr << "Starting Tor process:" << std::endl;
std::cerr << " Tor executable path: " << executable << std::endl;
std::cerr << " Tor data directory : " << d->dataDir << std::endl;
std::cerr << " Tor default torrc : " << defaultTorrc << std::endl;
d->process->setExecutable(executable);
d->process->setDataDir(d->dataDir);
d->process->setDefaultTorrc(defaultTorrc);
}
std::cerr << "Starting Tor manager thread:" << std::endl;
RsThread::start("TorManager");
return true ;
}
void TorManager::run()
{
d->process->start();
while(!shouldStop())
{
threadTick();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
d->control->shutdownSync();
d->process->stop();
if(rsEvents)
{
auto ev = std::make_shared<RsTorManagerEvent>();
ev->mTorManagerEventType = RsTorManagerEventCode::TOR_MANAGER_STOPPED;
rsEvents->sendEvent(ev);
}
}
void TorManager::threadTick()
{
d->process->tick();
if(d->process->state() != TorProcess::Ready)
return;
switch(d->control->status())
{
case TorControl::Unknown:
case TorControl::Connecting:
break;
case TorControl::NotConnected:
RsDbg() << "Connecting to tor process at " << d->process->controlHost() << ":" << d->process->controlPort() << "..." ;
d->control->connect(d->process->controlHost(),d->process->controlPort());
break;
case TorControl::SocketConnected:
RsDbg() << "Connection established." ;
if(d->hiddenService == nullptr)
{
RsDbg() << "Setting up hidden service" ;
setupHiddenService();
}
d->control->setAuthPassword(d->process->controlPassword());
d->control->authenticate();
break;
case TorControl::Authenticating:
RsDbg() << "Authenticating..." ;
break;
case TorControl::Authenticated:
RsDbg() << "Authenticated. Looking for hidden services.";
break;
case TorControl::HiddenServiceReady:
if(d->control->torStatus() < TorControl::TorReady)
{
d->control->getTorInfo(); // forces TorControl to check its state.
std::this_thread::sleep_for(std::chrono::seconds(1));
}
break;
case TorControl::Error:
d->control->shutdown();
d->control->reconnect();
break;
}
}
bool TorManager::getProxyServerInfo(std::string& 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(std::string& service_id,std::string& service_onion_address,uint16_t& service_port, std::string& service_target_address,uint16_t& target_port)
{
auto 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)->serviceId();
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)
{
RsInfo() << "state: " << state << " passwd=\"" << process->controlPassword().toString() << "\" " << process->controlHost()
<< ":" << process->controlPort() << std::endl;
if (state == TorProcess::Ready) {
control->setAuthPassword(process->controlPassword());
control->connect(process->controlHost(), process->controlPort());
}
}
void TorManagerPrivate::processErrorChanged(const std::string &errorMessage)
{
std::cerr << "tor error:" << errorMessage << std::endl;
setError(errorMessage);
}
void TorManagerPrivate::processLogMessage(const std::string &message)
{
std::cerr << "tor:" << message << std::endl;
if (logMessages.size() >= 50)
logMessages.pop_front();
auto p = message.find_first_of('\n');
logMessages.push_back((p==std::string::npos)?message:message.substr(0,p));
}
void TorManagerPrivate::controlStatusChanged(int status)
{
if (status == TorControl::Authenticated) {
if (!configNeeded) {
// If DisableNetwork is 1, trigger configurationNeeded
auto cmd = control->getConfiguration("DisableNetwork");
cmd->set_finished_callback( [this](TorControlCommand *sender) { getConfFinished(sender) ; });
}
if (process) {
// Take ownership via this control socket
control->takeOwnership();
}
}
}
void TorManagerPrivate::getConfFinished(TorControlCommand *sender)
{
GetConfCommand *command = dynamic_cast<GetConfCommand*>(sender);
if (!command)
return;
int n;
for(auto str:command->get("DisableNetwork"))
if(RsUtil::StringToInt(str,n) && n==1 && !configNeeded)
{
configNeeded = true;
if(rsEvents)
{
auto ev = std::make_shared<RsTorManagerEvent>();
ev->mTorManagerEventType = RsTorManagerEventCode::CONFIGURATION_NEEDED;
ev->mTorConnectivityStatus = RsTorConnectivityStatus::UNKNOWN;
ev->mTorStatus = RsTorStatus::UNKNOWN;
rsEvents->sendEvent(ev);
}
}
}
std::string TorManagerPrivate::torExecutablePath() const
{
std::string path;
#ifdef TODO
SettingsObject settings("tor");
path = settings.read("executablePath").toString();
if (!path.isEmpty() && QFile::exists(path))
return path;
#endif
#ifdef WINDOWS_SYS
std::string filename("/tor/tor.exe");
#else
std::string filename("/tor");
#endif
path = RsDirUtil::getDirectory(RsInit::executablePath());
std::string tor_exe_path = RsDirUtil::makePath(path,filename);
if (RsDirUtil::fileExists(tor_exe_path))
return tor_exe_path;
#ifdef BUNDLED_TOR_PATH
path = BUNDLED_TOR_PATH;
tor_exe_path = RsDirUtil::makePath(path,filename);
if (RsDirUtil::fileExists(tor_exe_path))
return tor_exe_path;
#endif
#ifdef __APPLE__
// on MacOS, try traditional brew installation path
path = "/usr/local/opt/tor/bin" ;
tor_exe_path = RsDirUtil::makePath(path,filename);
if (RsDirUtil::fileExists(tor_exe_path))
return tor_exe_path;
#endif
#ifdef __linux__
// On linux try system-installed tor /usr/bin/tor
if(RsDirUtil::fileExists("/usr/bin/tor"))
return std::string("/usr/bin/tor");
#endif
RsErr() << "Could not find Tor executable anywhere!" ;
// Try $PATH
return filename.substr(1);
}
bool TorManagerPrivate::createDataDir(const std::string &path)
{
return RsDirUtil::checkCreateDirectory(path);
}
bool TorManagerPrivate::createDefaultTorrc(const std::string &path)
{
static const char defaultTorrcContent[] =
"SocksPort auto\n"
"AvoidDiskWrites 1\n"
// "DisableNetwork 1\n" // (cyril) I removed this because it prevents Tor to bootstrap.
"__ReloadTorrcOnSIGHUP 0\n";
FILE *f = fopen(path.c_str(),"w");
if (!f)
return false;
fprintf(f,"%s",defaultTorrcContent);
fclose(f);
return true;
}
void TorManagerPrivate::setError(const std::string &message)
{
errorMessage = message;
if(rsEvents)
{
auto ev = std::make_shared<RsTorManagerEvent>();
ev->mTorManagerEventType = RsTorManagerEventCode::TOR_MANAGER_ERROR;
ev->mErrorMessage = message;
rsEvents->sendEvent(ev);
}
//emit q->errorChanged();
}
bool RsTor::isTorAvailable()
{
return !instance()->d->torExecutablePath().empty();
}
bool RsTor::getHiddenServiceInfo(std::string& service_id,
std::string& service_onion_address,
uint16_t& service_port,
std::string& service_target_address,
uint16_t& target_port)
{
std::string sid;
std::string soa;
std::string sta;
if(!instance()->getHiddenServiceInfo(sid,soa,service_port,sta,target_port))
return false;
service_id = sid;
service_onion_address = soa;
service_target_address = sta;
return true;
}
std::list<std::string> RsTor::logMessages()
{
return instance()->logMessages();
}
std::string RsTor::socksAddress()
{
return instance()->control()->socksAddress();
}
uint16_t RsTor::socksPort()
{
return instance()->control()->socksPort();
}
RsTorStatus RsTor::torStatus()
{
TorControl::TorStatus ts = instance()->control()->torStatus();
switch(ts)
{
case TorControl::TorOffline: return RsTorStatus::OFFLINE;
case TorControl::TorReady: return RsTorStatus::READY;
default:
case TorControl::TorUnknown: return RsTorStatus::UNKNOWN;
}
}
RsTorConnectivityStatus RsTor::torConnectivityStatus()
{
TorControl::Status ts = instance()->control()->status();
switch(ts)
{
default:
case Tor::TorControl::Error : return RsTorConnectivityStatus::ERROR;
case Tor::TorControl::NotConnected : return RsTorConnectivityStatus::NOT_CONNECTED;
case Tor::TorControl::Authenticating: return RsTorConnectivityStatus::AUTHENTICATING;
case Tor::TorControl::Connecting: return RsTorConnectivityStatus::CONNECTING;
case Tor::TorControl::Authenticated : return RsTorConnectivityStatus::AUTHENTICATED;
case Tor::TorControl::HiddenServiceReady : return RsTorConnectivityStatus::HIDDEN_SERVICE_READY;
}
}
bool RsTor::setupHiddenService()
{
return instance()->setupHiddenService();
}
RsTorHiddenServiceStatus RsTor::getHiddenServiceStatus(std::string& service_id)
{
service_id.clear();
auto list = instance()->control()->hiddenServices();
if(list.empty())
return RsTorHiddenServiceStatus::NOT_CREATED;
service_id = (*list.begin())->serviceId();
switch((*list.begin())->status())
{
default:
case Tor::HiddenService::NotCreated: return RsTorHiddenServiceStatus::NOT_CREATED;
case Tor::HiddenService::Offline : return RsTorHiddenServiceStatus::OFFLINE;
case Tor::HiddenService::Online : return RsTorHiddenServiceStatus::ONLINE;
}
}
std::map<std::string,std::string> RsTor::bootstrapStatus()
{
return instance()->control()->bootstrapStatus();
}
bool RsTor::hasError()
{
return instance()->hasError();
}
std::string RsTor::errorMessage()
{
return instance()->errorMessage();
}
void RsTor::getProxyServerInfo(std::string& server_address, uint16_t& server_port)
{
std::string qserver_address;
instance()->getProxyServerInfo(qserver_address,server_port);
server_address = qserver_address;
}
bool RsTor::start()
{
return instance()->startTorManager();
}
void RsTor::stop()
{
if (rsTor) {
if (rsTor->isRunning()) {
rsTor->fullstop();
}
delete(rsTor);
rsTor= nullptr;
}
}
void RsTor::setTorDataDirectory(const std::string& dir)
{
instance()->setTorDataDirectory(dir);
}
void RsTor::setHiddenServiceDirectory(const std::string& dir)
{
instance()->setHiddenServiceDirectory(dir);
}
TorManager *RsTor::instance()
{
#if !defined(_WIN32) && !defined(__MINGW32__)
assert(getpid() == syscall(SYS_gettid));// make sure we're not in a thread
#endif
if(rsTor == nullptr)
rsTor = new TorManager;
return rsTor;
}

View File

@ -32,12 +32,10 @@
// This code has been further modified to fit Retroshare context. // This code has been further modified to fit Retroshare context.
#ifndef TORMANAGER_H #pragma once
#define TORMANAGER_H
#include <QObject> #include "retroshare/rstor.h"
#include <QStringList> #include "HiddenService.h"
#include <QHostAddress>
namespace Tor namespace Tor
{ {
@ -48,31 +46,21 @@ class TorManagerPrivate;
/* Run/connect to an instance of Tor according to configuration, and manage /* Run/connect to an instance of Tor according to configuration, and manage
* UI interaction, first time configuration, etc. */ * UI interaction, first time configuration, etc. */
class TorManager : public QObject
class TorManager : public HiddenServiceClient, public RsThread, public RsTor
{ {
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 torDataDirectory READ torDataDirectory WRITE setTorDataDirectory)
public: public:
static bool isTorAvailable() ;
static TorManager *instance(); static TorManager *instance();
virtual ~TorManager();
TorProcess *process(); TorProcess *process();
TorControl *control(); TorControl *control();
std::string torDataDirectory() const;
void setTorDataDirectory(const std::string &path);
QString torDataDirectory() const; std::string hiddenServiceDirectory() const;
void setTorDataDirectory(const QString &path); void setHiddenServiceDirectory(const std::string &path);
QString hiddenServiceDirectory() const;
void setHiddenServiceDirectory(const QString &path);
// Starts a hidden service, loading it from the config directory that has been set earlier. // Starts a hidden service, loading it from the config directory that has been set earlier.
bool setupHiddenService() ; bool setupHiddenService() ;
@ -80,32 +68,30 @@ public:
// True on first run or when the Tor configuration wizard needs to be shown // True on first run or when the Tor configuration wizard needs to be shown
bool configurationNeeded() const; bool configurationNeeded() const;
QStringList logMessages() const; const std::list<std::string>& logMessages() const;
bool hasError() const; bool hasError() const;
QString errorMessage() const; std::string errorMessage() const;
bool getHiddenServiceInfo(QString& service_id,QString& service_onion_address,uint16_t& service_port, QHostAddress& service_target_address,uint16_t& target_port); bool getHiddenServiceInfo(std::string& service_id,std::string& service_onion_address,uint16_t& service_port, std::string& service_target_address,uint16_t& target_port);
bool getProxyServerInfo(QHostAddress& proxy_server_adress,uint16_t& proxy_server_port); bool getProxyServerInfo(std::string &proxy_server_adress, uint16_t& proxy_server_port);
public slots: bool startTorManager();
bool start();
private slots: virtual void hiddenServiceOnline() override {} // do nothing here.
void hiddenServicePrivateKeyChanged(); virtual void hiddenServicePrivateKeyChanged() override;
void hiddenServiceHostnameChanged(); virtual void hiddenServiceHostnameChanged() override;
void hiddenServiceStatusChanged(int old_status,int new_status); virtual void hiddenServiceStatusChanged(int new_status, int old_status) override;
signals: // Thread stuff
void configurationNeededChanged();
void errorChanged(); virtual void run() override;
void threadTick() ;
private: private:
explicit TorManager(QObject *parent = 0); explicit TorManager();
TorManagerPrivate *d; TorManagerPrivate *d;
friend class RsTor;
}; };
} }
#endif
#

View File

@ -0,0 +1,510 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* 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 <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include "util/rsdir.h"
#include "util/rsfile.h"
#include "pqi/pqifdbin.h"
#include "TorProcess.h"
#include "CryptoKey.h"
#ifdef WINDOWS_SYS
#include "util/rsstring.h"
#include <fcntl.h>
#define pipe(fds) _pipe(fds, 1024, _O_BINARY)
#endif
using namespace Tor;
static const int INTERVAL_BETWEEN_CONTROL_PORT_READ_TRIES = 5; // try every 5 secs.
TorProcess::TorProcess(TorProcessClient *client)
: m_client(client), mState(TorProcess::NotStarted), mControlPort(0), mLastTryReadControlPort(0)
{
mControlPortReadNbTries=0;
}
TorProcess::~TorProcess()
{
if (state() > NotStarted)
stop();
}
std::string TorProcess::executable() const
{
return mExecutable;
}
void TorProcess::setExecutable(const std::string &path)
{
mExecutable = path;
}
std::string TorProcess::dataDir() const
{
return mDataDir;
}
void TorProcess::setDataDir(const std::string &path)
{
mDataDir = path;
}
std::string TorProcess::defaultTorrc() const
{
return mDefaultTorrc;
}
void TorProcess::setDefaultTorrc(const std::string &path)
{
mDefaultTorrc = path;
}
std::list<std::string> TorProcess::extraSettings() const
{
return mExtraSettings;
}
void TorProcess::setExtraSettings(const std::list<std::string> &settings)
{
mExtraSettings = settings;
}
TorProcess::State TorProcess::state() const
{
return mState;
}
std::string TorProcess::errorMessage() const
{
return mErrorMessage;
}
// Does a popen, but dup all file descriptors (STDIN STDOUT and STDERR) to the
// FDs supplied by the parent process
int popen3(int fd[3],const std::vector<std::string>& args,TorProcessHandle& pid)
{
RsErr() << "Launching Tor in background..." ;
int i, e;
int p[3][2];
// set all the FDs to invalid
for(i=0; i<3; i++)
p[i][0] = p[i][1] = -1;
// create the pipes
for(int i=0; i<3; i++)
if(pipe(p[i]))
goto error;
#ifdef WINDOWS_SYS
// Set up members of the PROCESS_INFORMATION structure.
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.hStdInput = (HANDLE) _get_osfhandle(p[STDIN_FILENO][0]);
si.hStdOutput = (HANDLE) _get_osfhandle(p[STDOUT_FILENO][1]);
si.hStdError = (HANDLE) _get_osfhandle(p[STDERR_FILENO][1]);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
if (si.hStdInput != INVALID_HANDLE_VALUE &&
si.hStdOutput != INVALID_HANDLE_VALUE &&
si.hStdError != INVALID_HANDLE_VALUE) {
// build commandline
std::string cmd;
for (std::vector<std::string>::const_iterator it = args.begin(); it != args.end(); ++it) {
if (it != args.begin()) {
cmd += " ";
}
cmd += *it;
}
std::wstring wcmd;
if (!librs::util::ConvertUtf8ToUtf16(cmd, wcmd)) {
goto error;
}
WINBOOL success = CreateProcess(nullptr,
(LPWSTR) wcmd.c_str(), // command line
nullptr, // process security attributes
nullptr, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
nullptr, // use parent's environment
nullptr, // use parent's current directory
&si, // STARTUPINFO pointer
&pi); // receives PROCESS_INFORMATION
if (success) {
pid = pi.hProcess;
CloseHandle(pi.hThread);
fd[STDIN_FILENO] = p[STDIN_FILENO][1];
close(p[STDIN_FILENO][0]);
fd[STDOUT_FILENO] = p[STDOUT_FILENO][0];
close(p[STDOUT_FILENO][1]);
fd[STDERR_FILENO] = p[STDERR_FILENO][0];
close(p[STDERR_FILENO][1]);
// success
return 0;
}
}
// fall through error
#else
{
const char *arguments[args.size()+1];
int n=0;
// We first pushed everything into a vector of strings to save the pointers obtained from string returning methods
// by the time the process is launched.
for(uint32_t i=0;i<args.size();++i)
arguments[n++]= args[i].data();
arguments[n] = nullptr;
// and fork
pid = fork();
if(-1 == pid)
goto error;
// in the parent?
if(pid)
{
// parent
fd[STDIN_FILENO] = p[STDIN_FILENO][1];
close(p[STDIN_FILENO][0]);
fd[STDOUT_FILENO] = p[STDOUT_FILENO][0];
close(p[STDOUT_FILENO][1]);
fd[STDERR_FILENO] = p[STDERR_FILENO][0];
close(p[STDERR_FILENO][1]);
// success
return 0;
}
else
{
RsErr() << "Launching sub-process..." ;
// child
dup2(p[STDIN_FILENO][0],STDIN_FILENO);
close(p[STDIN_FILENO][1]);
dup2(p[STDOUT_FILENO][1],STDOUT_FILENO);
close(p[STDOUT_FILENO][0]);
dup2(p[STDERR_FILENO][1],STDERR_FILENO);
close(p[STDERR_FILENO][0]);
// here we try and run it
execv(*arguments,const_cast<char*const*>(arguments));
// if we are there, then we failed to launch our program
perror("Could not launch");
fprintf(stderr," \"%s\"\n",*arguments);
}
}
#endif
error:
e = errno;
// preserve original error
RsErr() << "An error occurred while trying to launch tor in background." ;
for(i=0; i<3; i++) {
close(p[i][0]);
close(p[i][1]);
}
errno = e;
return -1;
}
void TorProcess::start()
{
if (state() > NotStarted)
return;
mErrorMessage.clear();
if (mExecutable.empty() || mDataDir.empty()) {
mErrorMessage = "Tor executable and data directory not specified";
mState = Failed;
if(m_client) m_client->processStateChanged(mState); // emit stateChanged(d->state);
if(m_client) m_client->processErrorChanged(mErrorMessage); // emit errorMessageChanged(d->errorMessage);
return;
}
if (!ensureFilesExist()) {
mState = Failed;
if(m_client) m_client->processErrorChanged(mErrorMessage);// emit errorMessageChanged(d->errorMessage);
if(m_client) m_client->processStateChanged(mState);// emit stateChanged(d->state);
return;
}
ByteArray password = controlPassword();
ByteArray hashedPassword = torControlHashedPassword(password);
if (password.empty() || hashedPassword.empty()) {
mErrorMessage = "Random password generation failed";
mState = Failed;
if(m_client) m_client->processErrorChanged(mErrorMessage);// emit errorMessageChanged(d->errorMessage);
if(m_client) m_client->processStateChanged(mState); // emit stateChanged(d->state);
}
else
RsDbg() << "Using ControlPasswd=\"" << password.toString() << "\", hashed version=\"" << hashedPassword.toString() << "\"" ;
mState = Starting;
if(m_client) m_client->processStateChanged(mState);// emit stateChanged(d->state);
if (RsDirUtil::fileExists(controlPortFilePath()))
RsDirUtil::removeFile(controlPortFilePath());
mControlPort = 0;
mControlHost.clear();
// Launch the process
std::vector<std::string> args;
args.push_back(mExecutable);
if (!mDefaultTorrc.empty())
{
args.push_back("--defaults-torrc");
args.push_back(mDefaultTorrc);
}
args.push_back("-f");
args.push_back(torrcPath());
args.push_back("DataDirectory") ;
args.push_back(mDataDir);
args.push_back("HashedControlPassword") ;
args.push_back(hashedPassword.toString());
args.push_back("ControlPort") ;
args.push_back("auto");
args.push_back("ControlPortWriteToFile");
args.push_back(controlPortFilePath());
args.push_back("__OwningControllerProcess") ;
args.push_back(RsUtil::NumberToString(getpid()));
for(auto s:mExtraSettings)
args.push_back(s);
int fd[3]; // File descriptors array
if(popen3(fd,args,mTorProcessId))
{
RsErr() << "Could not start Tor process. errno=" << errno ;
mState = Failed;
return; // stop the control thread
}
RsFileUtil::set_fd_nonblock(fd[STDOUT_FILENO]);
RsFileUtil::set_fd_nonblock(fd[STDERR_FILENO]);
mStdOutFD = new RsFdBinInterface(fd[STDOUT_FILENO], false);
mStdErrFD = new RsFdBinInterface(fd[STDERR_FILENO], false);
}
void TorProcess::tick()
{
mStdOutFD->tick();
mStdErrFD->tick();
unsigned char buff[1024];
int s;
if((s=mStdOutFD->readline(buff,1024))) logMessage(std::string((char*)buff,s));
if((s=mStdErrFD->readline(buff,1024))) logMessage(std::string((char*)buff,s));
if(!mStdOutFD->isactive() && !mStdErrFD->isactive())
{
RsErr() << "Tor process died. Exiting TorControl process." ;
stop();
return;
}
time_t now = time(nullptr);
if(mControlPortReadNbTries <= 10 && (mControlPort==0 || mControlHost.empty()) && mLastTryReadControlPort + INTERVAL_BETWEEN_CONTROL_PORT_READ_TRIES < now)
{
mLastTryReadControlPort = now;
if(tryReadControlPort())
{
mState = Ready;
m_client->processStateChanged(mState);// stateChanged(mState);
}
else if(mControlPortReadNbTries > 10)
{
mState = Failed;
m_client->processStateChanged(mState);// stateChanged(mState);
}
}
}
void TorProcess::stop()
{
if (state() < Starting)
return;
while(mState == Starting)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
#ifdef WINDOWS_SYS
TerminateProcess (mTorProcessId, 0);
#else
kill(mTorProcessId,SIGTERM);
#endif
RsInfo() << "Tor process has been normally terminated. Exiting.";
mState = NotStarted;
if(m_client) m_client->processStateChanged(mState);// emit stateChanged(d->state);
}
void TorProcess::stateChanged(int newState)
{
if(m_client)
m_client->processStateChanged(newState);
}
void TorProcess::errorMessageChanged(const std::string& errorMessage)
{
if(m_client)
m_client->processErrorChanged(errorMessage);
}
void TorProcess::logMessage(const std::string& message)
{
if(m_client)
m_client->processLogMessage(message);
}
ByteArray TorProcess::controlPassword()
{
if (mControlPassword.empty())
mControlPassword = RsRandom::printable(16);
return mControlPassword;
}
std::string TorProcess::controlHost()
{
return mControlHost;
}
unsigned short TorProcess::controlPort()
{
return mControlPort;
}
bool TorProcess::ensureFilesExist()
{
if(!RsDirUtil::checkCreateDirectory(mDataDir))
{
mErrorMessage = "Cannot create Tor data directory: " + mDataDir;
return false;
}
if (!RsDirUtil::fileExists(torrcPath()))
{
FILE *f = RsDirUtil::rs_fopen(torrcPath().c_str(),"w");
if(!f)
{
mErrorMessage = "Cannot create Tor configuration file: " + torrcPath();
return false;
}
else
fclose(f);
}
return true;
}
std::string TorProcess::torrcPath() const
{
return RsDirUtil::makePath(mDataDir,"torrc");
}
std::string TorProcess::controlPortFilePath() const
{
return RsDirUtil::makePath(mDataDir,"control-port");
}
bool TorProcess::tryReadControlPort()
{
FILE *file = RsDirUtil::rs_fopen(controlPortFilePath().c_str(),"r");
RsDbg() << "Trying to read control port" ;
if(file)
{
char *line = nullptr;
size_t tmp_buffsize = 0;
size_t size = RsFileUtil::rs_getline(&line,&tmp_buffsize,file);
ByteArray data = ByteArray((unsigned char*)line,size).trimmed();
free(line);
fclose(file);
int p;
if (data.startsWith("PORT=") && (p = data.lastIndexOf(':')) > 0) {
mControlHost = data.mid(5, p - 5).toString();
mControlPort = data.mid(p+1).toInt();
if (!mControlHost.empty() && mControlPort > 0)
{
RsDbg() << "Got control host/port = " << mControlHost << ":" << mControlPort ;
return true;
}
}
}
return false;
}

View File

@ -33,24 +33,36 @@
#ifndef TORPROCESS_H #ifndef TORPROCESS_H
#define TORPROCESS_H #define TORPROCESS_H
#include <QObject> #include "bytearray.h"
#include <QHostAddress> #include "util/rsthreads.h"
class RsFdBinInterface ;
#ifdef WINDOWS_SYS
#define TorProcessHandle HANDLE
#else
#define TorProcessHandle pid_t
#endif
namespace Tor namespace Tor
{ {
class TorProcessPrivate; class TorProcessPrivate;
// This class is used to inherit calls from the TorProcess
class TorProcessClient
{
public:
virtual void processStateChanged(int) = 0;
virtual void processErrorChanged(const std::string&) = 0;
virtual void processLogMessage(const std::string&) = 0;
};
/* Launches and controls a Tor instance with behavior suitable for bundling /* Launches and controls a Tor instance with behavior suitable for bundling
* an instance with the application. */ * an instance with the application. */
class TorProcess : public QObject class TorProcess
{ {
Q_OBJECT
Q_ENUMS(State)
Q_PROPERTY(State state READ state NOTIFY stateChanged)
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged)
public: public:
enum State { enum State {
Failed = -1, Failed = -1,
@ -60,38 +72,66 @@ public:
Ready Ready
}; };
explicit TorProcess(QObject *parent = 0); explicit TorProcess(TorProcessClient *client);
virtual ~TorProcess(); virtual ~TorProcess();
QString executable() const; std::string executable() const;
void setExecutable(const QString &path); void setExecutable(const std::string &path);
QString dataDir() const; std::string dataDir() const;
void setDataDir(const QString &path); void setDataDir(const std::string &path);
QString defaultTorrc() const; std::string defaultTorrc() const;
void setDefaultTorrc(const QString &path); void setDefaultTorrc(const std::string &path);
QStringList extraSettings() const; std::list<std::string> extraSettings() const;
void setExtraSettings(const QStringList &settings); void setExtraSettings(const std::list<std::string> &settings);
State state() const; State state() const;
QString errorMessage() const; std::string errorMessage() const;
QHostAddress controlHost(); std::string controlHost();
quint16 controlPort(); unsigned short controlPort();
QByteArray controlPassword(); ByteArray controlPassword();
void stateChanged(int newState);
void errorMessageChanged(const std::string &errorMessage);
void logMessage(const std::string &message);
public slots:
void start(); void start();
void stop(); void stop();
void tick();
signals:
void stateChanged(int newState);
void errorMessageChanged(const QString &errorMessage);
void logMessage(const QString &message);
private: private:
TorProcessPrivate *d; TorProcessClient *m_client;
std::string mExecutable;
std::string mDataDir;
std::string mDefaultTorrc;
std::list<std::string> mExtraSettings;
TorProcess::State mState;
std::string mErrorMessage;
std::string mControlHost;
unsigned short mControlPort;
ByteArray mControlPassword;
int controlPortAttempts;
std::string torrcPath() const;
std::string controlPortFilePath() const;
bool ensureFilesExist();
TorProcessHandle mTorProcessId;
time_t mLastTryReadControlPort ;
int mControlPortReadNbTries ;
void processStarted();
void processFinished();
void processError(std::string error);
void processReadable();
bool tryReadControlPort();
RsFdBinInterface *mStdOutFD;
RsFdBinInterface *mStdErrFD;
}; };
} }

View File

@ -0,0 +1,142 @@
#pragma once
#include <vector>
#include <sstream>
#include <string>
#include <stdexcept>
namespace Tor
{
class NonCopiable {
public:
NonCopiable(){}
virtual ~NonCopiable()=default;
private:
NonCopiable(const NonCopiable& nc) {}
virtual NonCopiable& operator=(const NonCopiable& nc) { return *this ; }
};
class TorByteArray: public std::vector<unsigned char>
{
public:
TorByteArray(const unsigned char *data,uint32_t len)
{
clear();
for(uint32_t i=0;i<len;++i)
push_back(data[i]);
}
explicit TorByteArray(const std::string& s)
{
clear();
for(uint32_t i=0;i<s.length();++i)
push_back(s[i]);
}
TorByteArray(uint32_t s,unsigned char c)
{
clear();
resize(s,c);
}
TorByteArray() { clear() ; }
bool startsWith(const TorByteArray& s) const
{
if(s.size() > size())
return false;
for(uint32_t i=0;i<s.size();++i)
if(s[i] != data()[i])
return false;
return true;
}
int indexOf(unsigned char c) const
{
for(uint32_t i=0;i<size();++i)
if(data()[i] == c)
return i;
return -1;
}
const TorByteArray& operator+= (unsigned char s) { push_back(s); return *this ;}
TorByteArray left(uint32_t n) const
{
auto res = TorByteArray();
for(size_t i=0;i<std::min((size_t)n,size());++i)
res.push_back(data()[i]);
return res;
}
const TorByteArray& operator+=(const TorByteArray& t)
{
for(uint32_t i=0;i<t.size();++i)
push_back(t.data()[i]);
return *this;
}
const TorByteArray& append(const std::string& s) { return operator+=(TorByteArray(s)); }
const TorByteArray& append(char s) { return operator+=(s); }
TorByteArray operator+(const TorByteArray& t) const
{
auto res = *this;
for(uint32_t i=0;i<t.size();++i)
res.push_back(t[i]);
return res;
}
std::string toStdString() const
{
return std::string((const char *)data(),size());
}
bool contains(const TorByteArray& b) const
{
if(b.size() > size())
return false;
for(uint32_t i=0;i<size()-b.size();++i)
{
bool c = true;
for(uint32_t j=0;j<b.size();++j)
if(b[j] != data()[i+j])
{
c = false;
break;
}
if(c)
return true;
}
return false;
}
TorByteArray mid(uint32_t start,int length=-1) const
{
if(length==-1)
return TorByteArray(data()+start,size()-start);
if(length < 0 || start + length > size())
throw std::runtime_error("Length out of range in TorByteArray::mid()");
TorByteArray b;
for(uint32_t i=0;i<(uint32_t)length;++i)
b.push_back(data()[i+start]);
return b;
}
static TorByteArray number(uint64_t n)
{
std::ostringstream o;
o << n ;
return TorByteArray(o.str());
}
};
typedef std::string TorHostAddress;
}

View File

@ -30,11 +30,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef UTILS_USEFUL_H #pragma once
#define UTILS_USEFUL_H
#include <QtGlobal> #include "util/rsdebug.h"
#include <QDebug>
/* Print a warning for bug conditions, and assert on a debug build. /* Print a warning for bug conditions, and assert on a debug build.
* *
@ -50,7 +48,7 @@
* triggered unless the code or logic is wrong. * triggered unless the code or logic is wrong.
*/ */
#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) #if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
# define BUG() Explode(__FILE__,__LINE__), qWarning() << "BUG:" # define BUG() Explode(__FILE__,__LINE__), RsWarn() << "BUG:"
namespace { namespace {
class Explode class Explode
{ {
@ -59,13 +57,10 @@ public:
int line; int line;
Explode(const char *file, int line) : file(file), line(line) { } Explode(const char *file, int line) : file(file), line(line) { }
~Explode() { ~Explode() {
qt_assert("something broke!", file, line); RsErr() << "something broke! in file " << file << line;
} }
}; };
} }
#else #else
# define BUG() qWarning() << "BUG:" # define BUG() qWarning() << "BUG:"
#endif #endif
#endif

View File

@ -0,0 +1,195 @@
#pragma once
#include <stdlib.h>
#include <string.h>
#include <string>
#include <algorithm>
#include <vector>
#include <list>
#include "util/rsprint.h"
#include "util/rsdebug.h"
// This class re-implements QByteArray from Qt library.
class ByteArray: public std::vector<unsigned char>
{
public:
ByteArray() =default;
explicit ByteArray(int n) : std::vector<unsigned char>(n) {}
explicit ByteArray(const unsigned char *d,int n) : std::vector<unsigned char>(n) { memcpy(data(),d,n); }
virtual ~ByteArray() =default;
ByteArray(const std::string& c) { resize(c.size()); memcpy(data(),c.c_str(),c.size()); }
const ByteArray& operator=(const std::string& c) { resize(c.size()); memcpy(data(),c.c_str(),c.size()); return *this; }
bool isNull() const { return empty(); }
ByteArray toHex() const { return ByteArray(RsUtil::BinToHex(data(),size(),0)); }
std::string toString() const { std::string res; for(auto c:*this) res += c; return res; }
ByteArray operator+(const ByteArray& b) const { auto res(*this); for(unsigned char c:b) res.push_back(c); return res; }
ByteArray operator+(const std::string& b) const { return operator+(ByteArray(b)); }
void append(const ByteArray& b) { for(auto c:b) push_back(c); }
void append(const char *b) { for(uint32_t n=0;b[n]!=0;++n) push_back(b[n]); }
template<class T> void append(const T) = delete;// Prevents any implicit when calling the preceding functions which actually causes real bugs.
ByteArray& operator+=(char b) { push_back(b); return *this; }
ByteArray& operator+=(const ByteArray& b) { for(auto c:b) push_back(c); return *this; }
ByteArray& operator+=(const char *b) { for(uint32_t n=0;b[n]!=0;++n) push_back(b[n]); return *this;}
ByteArray left(uint32_t l) const { auto res = *this; res.resize(std::min((uint32_t)size(),l)); return res; }
ByteArray toUpper() const { auto res = *this; for(uint32_t i=0;i<size();++i) if( res[i]<='z' && res[i]>='a') res[i] += int('A')-int('a'); return res; }
ByteArray toLower() const { auto res = *this; for(uint32_t i=0;i<size();++i) if( res[i]<='Z' && res[i]>='A') res[i] += int('a')-int('A'); return res; }
int toInt() const
{
std::istringstream is(toString().c_str());
int res = -1;
is >> res ;
return res;
}
bool endsWith(const ByteArray& b) const { return size() >= b.size() && !memcmp(&data()[size()-b.size()],b.data(),b.size()); }
bool endsWith(char b) const { return size() > 0 && back()==b; }
bool startsWith(const ByteArray& b) const { return b.size() <= size() && !strncmp((char*)b.data(),(char*)data(),std::min(size(),b.size())); }
bool startsWith(const char *b) const
{
for(uint32_t n=0;b[n]!=0;++n)
if(n >= size() || b[n]!=(*this)[n])
return false;
return true;
}
bool operator==(const char *b) const
{
uint32_t n;
for(n=0;b[n]!=0;++n)
if(n >= size() || b[n]!=(*this)[n])
return false;
return n==size();
}
ByteArray mid(uint32_t n,int s=-1) const
{
ByteArray res((s>=0)?s:(size()-n));
memcpy(res.data(),&data()[n],res.size());
return res;
}
int indexOf(unsigned char c,int from=0) const
{
for(uint32_t i=from;i<size();++i)
if((*this)[i]==c)
return (int)i;
return -1;
}
ByteArray replace(const ByteArray& b1,const ByteArray& b2)
{
if(b1.empty())
{
RsErr() << "Attempting to replace an empty string!";
return *this;
}
ByteArray res ;
for(uint32_t i=0;i+b1.size()<=size();)
if(!memcmp(&(*this)[i],b1.data(),b1.size()))
{
res.append(b2);
i += b1.size();
}
else
res.push_back((*this)[i++]);
return res;
}
// Splits the byte array using sep as separator.
std::list<ByteArray> split(unsigned char sep)
{
std::list<ByteArray> res;
ByteArray current_block;
for(uint32_t i=0;i<size();++i)
if(operator[](i) == sep)
{
res.push_back(current_block);
current_block.clear();
}
else
current_block += (*this)[i];
if(!current_block.empty())
res.push_back(current_block);
return res;
}
// Splits the byte array using any of the characters in sep as separators.
std::list<ByteArray> split(const ByteArray& sep)
{
std::list<ByteArray> res;
ByteArray current_block;
for(uint32_t i=0;i<size();++i)
if(std::find(sep.begin(),sep.end(),operator[](i)) != sep.end())
{
res.push_back(current_block);
current_block.clear();
}
else
current_block += operator[](i);
if(!current_block.empty())
res.push_back(current_block);
return res;
}
// Removes the following characters from the beginning and from the end of the array:
// '\t', '\n', '\v', '\f', '\r', and ' '.
ByteArray trimmed() const
{
auto res(*this);
while(!res.empty() && ( res.back() == '\t' || res.back() == '\n' || res.back() == '\v'
|| res.back() == '\f' || res.back() == '\r' || res.back() == ' ' ) )
res.pop_back();
uint32_t i=0;
for(;i<res.size();++i)
if(res[i] != '\t' && res[i] != '\n' && res[i] != '\v' && res[i] != '\f' && res[i] != '\r' && res[i] != ' ')
break;
return res.mid(i);
}
// Removes n bytes from the end of the array
void chop(uint32_t n)
{
resize(std::max(0,(int)size() - (int)n));
}
// Returns the last index of a given byte, -1 if not found.
int lastIndexOf(unsigned char s)
{
for(int i=size()-1;i>=0;--i)
if(operator[](i) == s)
return i;
return -1;
}
};

View File

@ -1043,7 +1043,7 @@ void p3turtle::performLocalSearch(
} }
} }
void p3turtle::performLocalSearch_generic(RsTurtleGenericSearchRequestItem *item, uint32_t& req_result_count, std::list<RsTurtleSearchResultItem*>& result,uint32_t& max_allowed_hits) void p3turtle::performLocalSearch_generic(RsTurtleGenericSearchRequestItem *item, uint32_t& /*req_result_count*/, std::list<RsTurtleSearchResultItem*>& result,uint32_t& max_allowed_hits)
{ {
unsigned char *search_result_data = NULL ; unsigned char *search_result_data = NULL ;
uint32_t search_result_data_len = 0 ; uint32_t search_result_data_len = 0 ;

View File

@ -184,7 +184,6 @@ bool RetroDb::execSQL(const std::string &query){
} }
uint32_t delta = 3;
rstime_t stamp = time(NULL); rstime_t stamp = time(NULL);
bool timeOut = false, ok = false; bool timeOut = false, ok = false;

View File

@ -47,6 +47,8 @@
#include "retroshare/rsnotify.h" #include "retroshare/rsnotify.h"
#include "rsthreads.h" #include "rsthreads.h"
#include "rs_android/largefile_retrocompat.hpp"
#if defined(WIN32) || defined(__CYGWIN__) #if defined(WIN32) || defined(__CYGWIN__)
#include "util/rsstring.h" #include "util/rsstring.h"
#include "wtypes.h" #include "wtypes.h"
@ -59,7 +61,12 @@
#define canonicalize_file_name(p) realpath(p, NULL) #define canonicalize_file_name(p) realpath(p, NULL)
#endif #endif
#include "rs_android/largefile_retrocompat.hpp" #ifdef WINDOWS_SYS
#define FIND_OF_DIRECTORY_SEPARATOR "/\\\0"
#else
#define FIND_OF_DIRECTORY_SEPARATOR '/'
#endif
/**** /****
* #define RSDIR_DEBUG 1 * #define RSDIR_DEBUG 1
@ -69,7 +76,7 @@
bool std::filesystem::create_directories(const std::string& path) bool std::filesystem::create_directories(const std::string& path)
{ {
for( std::string::size_type lastIndex = 0; lastIndex < std::string::npos; for( std::string::size_type lastIndex = 0; lastIndex < std::string::npos;
lastIndex = path.find('/', lastIndex) ) lastIndex = path.find_first_of(FIND_OF_DIRECTORY_SEPARATOR, lastIndex) )
{ {
std::string&& curDir = path.substr(0, ++lastIndex); std::string&& curDir = path.substr(0, ++lastIndex);
if(!RsDirUtil::checkCreateDirectory(curDir)) if(!RsDirUtil::checkCreateDirectory(curDir))
@ -85,6 +92,25 @@ bool std::filesystem::create_directories(const std::string& path)
# include <filesystem> # include <filesystem>
#endif // __cplusplus < 201703L #endif // __cplusplus < 201703L
std::string RsDirUtil::getFileName(const std::string& full_file_path)
{
std::string::size_type n = full_file_path.find_last_of(FIND_OF_DIRECTORY_SEPARATOR);
if(n == std::string::npos)
return full_file_path;
else
return full_file_path.substr(n+1);
}
std::string RsDirUtil::getDirectory(const std::string& full_file_path)
{
std::string::size_type n = full_file_path.find_last_of(FIND_OF_DIRECTORY_SEPARATOR);
if(n == std::string::npos)
return std::string();
else
return full_file_path.substr(0,n);
}
std::string RsDirUtil::getTopDir(const std::string& dir) std::string RsDirUtil::getTopDir(const std::string& dir)
{ {
std::string top; std::string top;
@ -93,10 +119,10 @@ std::string RsDirUtil::getTopDir(const std::string& dir)
*/ */
int i,j; int i,j;
int len = dir.length(); int len = dir.length();
for(j = len - 1; (j > 0) && (dir[j] == '/'); j--) ; for(j = len - 1; (j > 0) && RsDirUtil::isDirectorySeparator(dir[j]); j--) ;
for(i = j; (i > 0) && (dir[i] != '/'); i--) ; for(i = j; (i > 0) && !RsDirUtil::isDirectorySeparator(dir[i]); i--) ;
if (dir[i] == '/') if (RsDirUtil::isDirectorySeparator(dir[i]))
i++; i++;
for(; i <= j; i++) for(; i <= j; i++)
@ -126,9 +152,9 @@ const char *RsDirUtil::scanf_string_for_uint(int bytes)
bool RsDirUtil::splitDirFromFile(const std::string& full_path,std::string& dir, std::string& file) bool RsDirUtil::splitDirFromFile(const std::string& full_path,std::string& dir, std::string& file)
{ {
int i = full_path.rfind('/', full_path.size()-1); std::string::size_type i = full_path.find_last_of(FIND_OF_DIRECTORY_SEPARATOR, full_path.size()-1);
if(i == full_path.size()-1) // '/' not found! if(i == std::string::npos) // '/' not found!
{ {
file = full_path ; file = full_path ;
dir = "." ; dir = "." ;
@ -147,13 +173,13 @@ void RsDirUtil::removeTopDir(const std::string& dir, std::string& path)
/* remove the subdir: [/][dir1.../]<top>[/] /* remove the subdir: [/][dir1.../]<top>[/]
*/ */
int j = dir.find_last_not_of('/'); int j = dir.find_last_not_of(FIND_OF_DIRECTORY_SEPARATOR);
int i = dir.rfind('/', j); int i = dir.find_last_of(FIND_OF_DIRECTORY_SEPARATOR, j);
/* remove any more slashes */ /* remove any more slashes */
if (i > 0) if (i > 0)
{ {
i = dir.find_last_not_of('/', i); i = dir.find_last_not_of(FIND_OF_DIRECTORY_SEPARATOR, i);
} }
if (i > 0) if (i > 0)
@ -170,8 +196,8 @@ std::string RsDirUtil::getRootDir(const std::string& dir)
*/ */
int i,j; int i,j;
int len = dir.length(); int len = dir.length();
for(i = 0; (i < len) && (dir[i] == '/'); i++) ; for(i = 0; (i < len) && RsDirUtil::isDirectorySeparator(dir[i]); i++) ;
for(j = i; (j < len) && (dir[j] != '/'); j++) ; for(j = i; (j < len) && !RsDirUtil::isDirectorySeparator(dir[j]); j++) ;
if (i == j) if (i == j)
return root; /* empty */ return root; /* empty */
for(; i < j; i++) for(; i < j; i++)
@ -188,12 +214,12 @@ std::string RsDirUtil::removeRootDir(const std::string& path)
std::string output; std::string output;
/* chew leading '/'s */ /* chew leading '/'s */
for(i = 0; (i < len) && (path[i] == '/'); i++) ; for(i = 0; (i < len) && RsDirUtil::isDirectorySeparator(path[i]); i++) ;
if (i == len) if (i == len)
return output; /* empty string */ return output; /* empty string */
for(j = i; (j < len) && (path[j] != '/'); j++) ; /* run to next '/' */ for(j = i; (j < len) && !RsDirUtil::isDirectorySeparator(path[j]); j++) ; /* run to next '/' */
for(; (j < len) && (path[j] == '/'); j++) ; /* chew leading '/'s */ for(; (j < len) && RsDirUtil::isDirectorySeparator(path[j]); j++) ; /* chew leading '/'s */
for(; j < len; j++) for(; j < len; j++)
{ {
@ -214,7 +240,7 @@ std::string RsDirUtil::removeRootDirs(const std::string& path, const std::string
if ((root.length() < 1) || (path.length() < 1)) if ((root.length() < 1) || (path.length() < 1))
return notroot; return notroot;
if ((path[0] == '/') && (root[0] != '/')) if (RsDirUtil::isDirectorySeparator(path[0]) && !RsDirUtil::isDirectorySeparator(root[0]))
{ {
i++; i++;
} }
@ -233,7 +259,7 @@ std::string RsDirUtil::removeRootDirs(const std::string& path, const std::string
return notroot; return notroot;
} }
if (path[i] == '/') if (RsDirUtil::isDirectorySeparator(path[i]))
{ {
i++; i++;
} }
@ -257,7 +283,7 @@ int RsDirUtil::breakupDirList(const std::string& path,
unsigned int i; unsigned int i;
for(i = 0; i < path.length(); i++) for(i = 0; i < path.length(); i++)
{ {
if (path[i] == '/') if (RsDirUtil::isDirectorySeparator(path[i]))
{ {
if (i - start > 0) if (i - start > 0)
{ {
@ -872,11 +898,26 @@ std::string RsDirUtil::convertPathToUnix(std::string path)
return path; return path;
} }
bool RsDirUtil::isDirectorySeparator(const char &c)
{
if (c == '/') {
return true;
}
#ifdef WINDOWS_SYS
if (c == '\\') {
return true;
}
#endif
return false;
}
std::string RsDirUtil::makePath(const std::string &path1, const std::string &path2) std::string RsDirUtil::makePath(const std::string &path1, const std::string &path2)
{ {
std::string path = path1; std::string path = path1;
if (path.empty() == false && *path.rbegin() != '/') { if (path.empty() == false && !RsDirUtil::isDirectorySeparator(*path.rbegin())) {
path += "/"; path += "/";
} }
path += path2; path += path2;
@ -1013,10 +1054,10 @@ std::wstring RsDirUtil::getWideTopDir(std::wstring dir)
*/ */
int i,j; int i,j;
int len = dir.length(); int len = dir.length();
for(j = len - 1; (j > 0) && (dir[j] == '/'); j--); for(j = len - 1; (j > 0) && RsDirUtil::isDirectorySeparator(dir[j]); j--);
for(i = j; (i > 0) && (dir[i] != '/'); i--); for(i = j; (i > 0) && !RsDirUtil::isDirectorySeparator(dir[i]); i--);
if (dir[i] == '/') if (RsDirUtil::isDirectorySeparator(dir[i]))
i++; i++;
for(; i <= j; i++) for(; i <= j; i++)
@ -1035,11 +1076,11 @@ std::wstring RsDirUtil::removeWideTopDir(std::wstring dir)
*/ */
int i,j; int i,j;
int len = dir.length(); int len = dir.length();
for(j = len - 1; (j > 0) && (dir[j] == '/'); j--); for(j = len - 1; (j > 0) && RsDirUtil::isDirectorySeparator(dir[j]); j--);
for(i = j; (i >= 0) && (dir[i] != '/'); i--); for(i = j; (i >= 0) && !RsDirUtil::isDirectorySeparator(dir[i]); i--);
/* remove any more slashes */ /* remove any more slashes */
for(; (i >= 0) && (dir[i] == '/'); i--); for(; (i >= 0) && RsDirUtil::isDirectorySeparator(dir[i]); i--);
for(j = 0; j <= i; j++) for(j = 0; j <= i; j++)
{ {
@ -1057,8 +1098,8 @@ std::wstring RsDirUtil::getWideRootDir(std::wstring dir)
*/ */
int i,j; int i,j;
int len = dir.length(); int len = dir.length();
for(i = 0; (i < len) && (dir[i] == '/'); i++); for(i = 0; (i < len) && RsDirUtil::isDirectorySeparator(dir[i]); i++);
for(j = i; (j < len) && (dir[j] != '/'); j++); for(j = i; (j < len) && !RsDirUtil::isDirectorySeparator(dir[j]); j++);
if (i == j) if (i == j)
return root; /* empty */ return root; /* empty */
for(; i < j; i++) for(; i < j; i++)
@ -1075,12 +1116,12 @@ std::wstring RsDirUtil::removeWideRootDir(std::wstring path)
std::wstring output; std::wstring output;
/* chew leading '/'s */ /* chew leading '/'s */
for(i = 0; (i < len) && (path[i] == '/'); i++); for(i = 0; (i < len) && RsDirUtil::isDirectorySeparator(path[i]); i++);
if (i == len) if (i == len)
return output; /* empty string */ return output; /* empty string */
for(j = i; (j < len) && (path[j] != '/'); j++); /* run to next '/' */ for(j = i; (j < len) && !RsDirUtil::isDirectorySeparator(path[j]); j++); /* run to next '/' */
for(; (j < len) && (path[j] == '/'); j++); /* chew leading '/'s */ for(; (j < len) && RsDirUtil::isDirectorySeparator(path[j]); j++); /* chew leading '/'s */
for(; j < len; j++) for(; j < len; j++)
{ {
@ -1101,7 +1142,7 @@ std::wstring RsDirUtil::removeWideRootDirs(std::wstring path, std::wstring root)
if ((root.length() < 1) || (path.length() < 1)) if ((root.length() < 1) || (path.length() < 1))
return notroot; return notroot;
if ((path[0] == '/') && (root[0] != '/')) if (RsDirUtil::isDirectorySeparator(path[0]) && !RsDirUtil::isDirectorySeparator(root[0]))
{ {
i++; i++;
} }
@ -1120,7 +1161,7 @@ std::wstring RsDirUtil::removeWideRootDirs(std::wstring path, std::wstring root)
return notroot; return notroot;
} }
if (path[i] == '/') if (RsDirUtil::isDirectorySeparator(path[i]))
{ {
i++; i++;
} }
@ -1144,7 +1185,7 @@ int RsDirUtil::breakupWideDirList(std::wstring path,
unsigned int i; unsigned int i;
for(i = 0; i < path.length(); i++) for(i = 0; i < path.length(); i++)
{ {
if (path[i] == '/') if (RsDirUtil::isDirectorySeparator(path[i]))
{ {
if (i - start > 0) if (i - start > 0)
{ {

View File

@ -58,12 +58,20 @@ class RsStackFileLock
namespace RsDirUtil { namespace RsDirUtil {
// Returns the name of the directory on top of the given path (as opposed to the full path to that directory)
std::string getTopDir(const std::string&); std::string getTopDir(const std::string&);
std::string getRootDir(const std::string&); std::string getRootDir(const std::string&);
std::string removeRootDir(const std::string& path); std::string removeRootDir(const std::string& path);
void removeTopDir(const std::string& dir, std::string &path); void removeTopDir(const std::string& dir, std::string &path);
std::string removeRootDirs(const std::string& path, const std::string& root); std::string removeRootDirs(const std::string& path, const std::string& root);
// Returns the filename at the end of the path. An empty string is returned if the path is a directory path.
std::string getFileName(const std::string& full_file_path);
// Returns the directory (full path) that contains the given path (filename or directory).
// If a directory is supplied, the same path is returned.
std::string getDirectory(const std::string& full_file_path);
// Renames file from to file to. Files should be on the same file system. // Renames file from to file to. Files should be on the same file system.
// returns true if succeed, false otherwise. // returns true if succeed, false otherwise.
bool renameFile(const std::string& from,const std::string& to) ; bool renameFile(const std::string& from,const std::string& to) ;
@ -107,6 +115,12 @@ rstime_t lastWriteTime(
std::error_condition& errc = RS_DEFAULT_STORAGE_PARAM(std::error_condition) ); std::error_condition& errc = RS_DEFAULT_STORAGE_PARAM(std::error_condition) );
bool checkDirectory(const std::string& dir); bool checkDirectory(const std::string& dir);
/*!
* \brief checkCreateDirectory
* \param dir
* \return false when the directory does not exist and could not be created.
*/
bool checkCreateDirectory(const std::string& dir); bool checkCreateDirectory(const std::string& dir);
// Removes all symbolic links along the path and computes the actual location of the file/dir passed as argument. // Removes all symbolic links along the path and computes the actual location of the file/dir passed as argument.
@ -159,6 +173,7 @@ bool getWideFileHash(std::wstring filepath, RsFileHash &hash, u
FILE *rs_fopen(const char* filename, const char* mode); FILE *rs_fopen(const char* filename, const char* mode);
std::string convertPathToUnix(std::string path); std::string convertPathToUnix(std::string path);
bool isDirectorySeparator(const char &c);
/** Concatenate two path pieces putting '/' separator between them only if /** Concatenate two path pieces putting '/' separator between them only if
* needed */ * needed */

View File

@ -0,0 +1,107 @@
/*******************************************************************************
* libretroshare/src/util: rsfile.cc *
* *
* libretroshare: retroshare core library *
* *
* 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 Lesser 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include "util/rsfile.h"
#ifdef WINDOWS_SYS
#include <wtypes.h>
#include <io.h>
#include <namedpipeapi.h>
#include <errno.h>
#else
#include <fcntl.h>
#endif
int RsFileUtil::set_fd_nonblock(int fd)
{
int ret = 0;
/******************* OS SPECIFIC PART ******************/
#ifdef WINDOWS_SYS
DWORD mode = PIPE_NOWAIT;
WINBOOL result = SetNamedPipeHandleState((HANDLE) _get_osfhandle(fd), &mode, nullptr, nullptr);
if (!result) {
ret = -1;
}
#else // ie UNIX
int flags = fcntl(fd, F_GETFL);
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#endif
return ret;
}
ssize_t RsFileUtil::rs_getline(char **lineptr, size_t *n, FILE *stream)
{
/******************* OS SPECIFIC PART ******************/
#ifdef WINDOWS_SYS
if (lineptr == nullptr || n == nullptr || stream == nullptr) {
errno = EINVAL;
return -1;
}
if (*lineptr == nullptr || *n < 1) {
*n = BUFSIZ;
*lineptr = (char*) malloc(*n);
if (*lineptr == nullptr) {
*n = 0;
return -1;
}
}
char *ptr = *lineptr;
while (true) {
int c = fgetc(stream);
if (c == -1) {
if (feof(stream)) {
*ptr = '\0';
return (ssize_t) (ptr - *lineptr);
}
return -1;
}
*ptr = c;
++ptr;
if (c == '\n') {
*ptr = '\0';
return ptr - *lineptr;
}
if (ptr + 2 >= *lineptr + *n) {
size_t new_size = *n * 2;
ssize_t diff = ptr - *lineptr;
char *new_lineptr = (char*) realloc(*lineptr, new_size);
if (new_lineptr == nullptr) {
return -1;
}
*lineptr = new_lineptr;
*n = new_size;
ptr = new_lineptr + diff;
}
}
#else // ie UNIX
return getline(lineptr, n, stream);
#endif
}

View File

@ -0,0 +1,32 @@
/*******************************************************************************
* libretroshare/src/util: rsfile.h *
* *
* libretroshare: retroshare core library *
* *
* 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 Lesser 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <stdio.h>
namespace RsFileUtil {
int set_fd_nonblock(int fd);
ssize_t rs_getline(char **lineptr, size_t *n, FILE *stream);
}

View File

@ -30,7 +30,7 @@
#define PASS_MAX 512 #define PASS_MAX 512
namespace RsUtil { namespace RsUtil {
std::string rs_getpass(const std::string& prompt,bool no_echo) std::string rs_getpass(const std::string& prompt,bool /*no_echo*/)
{ {
static char getpassbuf [PASS_MAX + 1]; static char getpassbuf [PASS_MAX + 1];
size_t i = 0; size_t i = 0;

View File

@ -22,6 +22,7 @@
#include "util/rsprint.h" #include "util/rsprint.h"
#include "util/rsstring.h" #include "util/rsstring.h"
#include <stdio.h>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <openssl/sha.h> #include <openssl/sha.h>
@ -45,6 +46,13 @@ std::string RsUtil::NumberToString(uint64_t n,bool hex)
return os.str(); return os.str();
} }
bool RsUtil::StringToInt(const std::string& s,int& n)
{
if(sscanf(s.c_str(),"%d",&n) == 1)
return true;
else
return false;
}
std::string RsUtil::BinToHex(const std::string &bin) std::string RsUtil::BinToHex(const std::string &bin)
{ {
return BinToHex(bin.c_str(), bin.length()); return BinToHex(bin.c_str(), bin.length());

View File

@ -36,6 +36,10 @@ std::string BinToHex(const char *arr, const uint32_t len);
std::string BinToHex(const unsigned char *arr, const uint32_t len, uint32_t max_len=0); std::string BinToHex(const unsigned char *arr, const uint32_t len, uint32_t max_len=0);
bool HexToBin(const std::string& input,unsigned char *data, const uint32_t len); bool HexToBin(const std::string& input,unsigned char *data, const uint32_t len);
std::string NumberToString(uint64_t n, bool hex=false); std::string NumberToString(uint64_t n, bool hex=false);
// Returns in n the int that can be read in the string. Returns false when no int is fond.
bool StringToInt(const std::string& s,int& n);
std::string HashId(const std::string &id, bool reverse = false); std::string HashId(const std::string &id, bool reverse = false);
std::vector<uint8_t> BinToSha256(const std::vector<uint8_t> &in); std::vector<uint8_t> BinToSha256(const std::vector<uint8_t> &in);

View File

@ -139,8 +139,12 @@ double RsRandom::random_f64()
/*static*/ std::string RsRandom::printable(uint32_t length) /*static*/ std::string RsRandom::printable(uint32_t length)
{ {
std::string ret(length, 0); std::string res;
random_bytes(reinterpret_cast<uint8_t*>(&ret[0]), length); RsTemporaryMemory mem(length);
for(uint32_t i=0; i<length; ++i) ret[i] = (ret[i] % 94) + 33; random_bytes(mem,length);
return ret;
for(uint32_t i=0; i<length; ++i)
res += (char)(( ((int) ((uint8_t*)mem)[i]) % 94 ) + 33);
return res;
} }

View File

@ -34,6 +34,7 @@
#include <string> #include <string>
// For win32 systems (tested on MingW+Ubuntu) // For win32 systems (tested on MingW+Ubuntu)
#undef stat64
#define stat64 _stati64 #define stat64 _stati64
// Should be in Iphlpapi.h, but mingw doesn't seem to have these // Should be in Iphlpapi.h, but mingw doesn't seem to have these

View File

@ -8,7 +8,7 @@ CONFIG += staticlib
DEFINES *= OPENSSL_NO_IDEA DEFINES *= OPENSSL_NO_IDEA
QMAKE_CXXFLAGS *= -Wall -Werror -W QMAKE_CXXFLAGS *= -Werror -W
TARGET = ops TARGET = ops
DESTDIR = lib DESTDIR = lib

View File

@ -53,10 +53,6 @@ win32 {
LIBS += -L"$$OUT_PWD/../../libretroshare/src/lib" -lretroshare LIBS += -L"$$OUT_PWD/../../libretroshare/src/lib" -lretroshare
} }
# Switch on extra warnings
QMAKE_CFLAGS += -Wextra
QMAKE_CXXFLAGS += -Wextra
CONFIG(debug, debug|release) { CONFIG(debug, debug|release) {
} else { } else {
# Tell linker to use ASLR protection # Tell linker to use ASLR protection

View File

@ -90,7 +90,7 @@ void FeedReaderFeedNotify::msgChanged(uint32_t feedId, const QString &msgId, int
mMutex->unlock(); mMutex->unlock();
} }
FeedItem *FeedReaderFeedNotify::feedItem(FeedHolder *parent) FeedItem *FeedReaderFeedNotify::feedItem(FeedHolder */*parent*/)
{ {
bool msgPending = false; bool msgPending = false;
FeedInfo feedInfo; FeedInfo feedInfo;
@ -119,7 +119,7 @@ FeedItem *FeedReaderFeedNotify::feedItem(FeedHolder *parent)
return new FeedReaderFeedItem(mFeedReader, mNotify, feedInfo, msgInfo); return new FeedReaderFeedItem(mFeedReader, mNotify, feedInfo, msgInfo);
} }
FeedItem *FeedReaderFeedNotify::testFeedItem(FeedHolder *parent) FeedItem *FeedReaderFeedNotify::testFeedItem(FeedHolder */*parent*/)
{ {
FeedInfo feedInfo; FeedInfo feedInfo;
feedInfo.name = tr("Test").toUtf8().constData(); feedInfo.name = tr("Test").toUtf8().constData();

View File

@ -77,8 +77,6 @@ macx {
# ffmpeg (and libavutil: https://github.com/ffms/ffms2/issues/11) # ffmpeg (and libavutil: https://github.com/ffms/ffms2/issues/11)
QMAKE_CXXFLAGS += -D__STDC_CONSTANT_MACROS QMAKE_CXXFLAGS += -D__STDC_CONSTANT_MACROS
QMAKE_CXXFLAGS *= -Wall
SOURCES = VOIPPlugin.cpp \ SOURCES = VOIPPlugin.cpp \
gui/VOIPConfigPanel.cpp \ gui/VOIPConfigPanel.cpp \
services/p3VOIP.cc \ services/p3VOIP.cc \

View File

@ -153,6 +153,8 @@ void QVideoInputDevice::errorHandling(CameraStatus status,QCamera::Error error)
{ {
#ifdef DEBUG_QVIDEODEVICE #ifdef DEBUG_QVIDEODEVICE
std::cerr << "Received msg from camera capture: status=" << (int)status << " error=" << (int)error << std::endl; std::cerr << "Received msg from camera capture: status=" << (int)status << " error=" << (int)error << std::endl;
#else
Q_UNUSED(error);
#endif #endif
if(status == CANNOT_INITIALIZE_CAMERA) if(status == CANNOT_INITIALIZE_CAMERA)
{ {
@ -179,6 +181,8 @@ void QVideoInputDevice::grabFrame(int id,QVideoFrame frame)
#ifdef DEBUG_QVIDEODEVICE #ifdef DEBUG_QVIDEODEVICE
std::cerr << "Frame " << id << ". Pixel format: " << frame.pixelFormat() << ". Size: " << image.size().width() << " x " << image.size().height() << std::endl; // if(frame.pixelFormat() != QVideoFrame::Format_Jpeg) std::cerr << "Frame " << id << ". Pixel format: " << frame.pixelFormat() << ". Size: " << image.size().width() << " x " << image.size().height() << std::endl; // if(frame.pixelFormat() != QVideoFrame::Format_Jpeg)
#else
Q_UNUSED(id);
#endif #endif
if(_video_processor != NULL) if(_video_processor != NULL)

View File

@ -92,6 +92,9 @@ VOIPConfigPanel::VOIPConfigPanel(QWidget * parent, Qt::WindowFlags flags)
inputAudioProcessor = NULL; inputAudioProcessor = NULL;
inputAudioDevice = NULL; inputAudioDevice = NULL;
graph_source = nullptr;
videoInput = nullptr;
videoProcessor = nullptr;
qtTick = NULL; qtTick = NULL;
ui.qcbTransmit->addItem(tr("Continuous"), RsVOIP::AudioTransmitContinous); ui.qcbTransmit->addItem(tr("Continuous"), RsVOIP::AudioTransmitContinous);
@ -209,11 +212,16 @@ VOIPConfigPanel::~VOIPConfigPanel()
void VOIPConfigPanel::clearPipeline() void VOIPConfigPanel::clearPipeline()
{ {
if (qtTick) {
delete qtTick; delete qtTick;
qtTick = nullptr;
}
if (graph_source) {
graph_source->stop() ; graph_source->stop() ;
graph_source->setVideoInput(NULL) ; graph_source->setVideoInput(NULL) ;
graph_source=nullptr; // is deleted by setSource below. This is a bad design. graph_source=nullptr; // is deleted by setSource below. This is a bad design.
}
ui.voipBwGraph->setSource(nullptr); ui.voipBwGraph->setSource(nullptr);
@ -225,8 +233,10 @@ void VOIPConfigPanel::clearPipeline()
videoInput = nullptr; videoInput = nullptr;
} }
if (videoProcessor) {
delete videoProcessor; delete videoProcessor;
videoProcessor = nullptr; videoProcessor = nullptr;
}
if (inputAudioDevice) { if (inputAudioDevice) {
inputAudioDevice->stop(); inputAudioDevice->stop();

View File

@ -1,527 +0,0 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* 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 <iostream>
#include "CryptoKey.h"
#include "SecureRNG.h"
#include "Useful.h"
#include <QtDebug>
#include <QFile>
#include <QByteArray>
#include <openssl/bn.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#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
#ifdef TO_REMOVE
void base32_encode(char *dest, unsigned destlen, const char *src, unsigned srclen);
bool base32_decode(char *dest, unsigned destlen, const char *src, unsigned srclen);
#endif
CryptoKey::CryptoKey()
{
}
CryptoKey::~CryptoKey()
{
clear();
}
#ifdef TO_REMOVE
CryptoKey::Data::~Data()
{
if (key)
{
RSA_free(key);
key = 0;
}
}
#endif
void CryptoKey::clear()
{
key_data.clear();
}
#ifdef TO_REMOVE
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<const uchar*>(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;
}
#endif
bool CryptoKey::loadFromFile(const QString& path)
{
QFile file(path);
if (!file.open(QIODevice::ReadOnly))
{
qWarning() << "Failed to open Tor key file " << path << ": " << file.errorString();
return false;
}
QByteArray data = file.readAll();
file.close();
if(data.contains("-----BEGIN RSA PRIVATE KEY-----"))
{
std::cerr << "Note: Reading/converting Tor v2 key format." << std::endl;
// This to be compliant with old format. New format is oblivious to the type of key so we dont need a header
data = data.replace("-----BEGIN RSA PRIVATE KEY-----",nullptr);
data = data.replace("-----END RSA PRIVATE KEY-----",nullptr);
data = data.replace("\n",nullptr);
data = data.replace("\t",nullptr);
data = "RSA1024:"+data;
}
std::cerr << "Have read the following key: " << std::endl;
std::cerr << QString(data).toStdString() << std::endl;
key_data = data;
return true;
}
bool CryptoKey::loadFromTorMessage(const QByteArray& b)
{
// note: We should probably check the structure a bit more, for security.
std::cerr << "Loading new key:" << std::endl;
if(b.startsWith("RSA1024"))
std::cerr << " type: RSA-1024 (Tor v2)" << std::endl;
else if(b.startsWith("ED25519-V3"))
std::cerr << " type: ED25519-V3 (Tor v3)" << std::endl;
else if(b.indexOf(':'))
{
std::cerr << " unknown type, or bad syntax in key: \"" << b.left(b.indexOf(':')).toStdString() << "\". Not accepted." << std::endl;
return false;
}
key_data = b;
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<const void*>(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<const char*>(md), 20).toHex().toUpper();
}
#ifdef TO_REMOVE
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<const unsigned char*>(buf.constData()), buf.size(),
reinterpret_cast<unsigned char*>(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<const unsigned char*>(data.constData()), data.size(),
reinterpret_cast<unsigned char*>(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<const unsigned char*>(digest.constData()), digest.size(),
reinterpret_cast<unsigned char*>(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<const unsigned char*>(data.constData()), data.size(),
reinterpret_cast<unsigned char*>(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<const uchar*>(digest.constData()), digest.size(),
reinterpret_cast<uchar*>(signature.data()), signature.size(), d->key);
if (r != 1)
return false;
return true;
}
/* 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;
}
#endif

View File

@ -1,106 +0,0 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* 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 <QString>
#include <QSharedData>
#include <QExplicitlySharedDataPointer>
class CryptoKey
{
public:
enum KeyType {
PrivateKey,
PublicKey
};
enum KeyFormat {
PEM,
DER
};
CryptoKey();
~CryptoKey();
#ifdef TO_REMOVE
bool loadFromData(const QByteArray &data, KeyType type, KeyFormat format = PEM);
bool loadFromFile(const QString &path, KeyType type, KeyFormat format = PEM);
#endif
bool loadFromFile(const QString &path);
void clear();
const QByteArray bytes() const { return key_data; }
bool loadFromTorMessage(const QByteArray& b);
bool isLoaded() const { return !key_data.isNull(); }
#ifdef TO_REMOVE
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;
#endif
private:
#ifdef TO_REMOVE
struct Data : public QSharedData
{
typedef struct rsa_st RSA;
RSA *key;
Data(RSA *k = 0) : key(k) { }
~Data();
};
#endif
QByteArray key_data;
#ifdef TO_REMOVE
QExplicitlySharedDataPointer<Data> d;
#endif
};
QByteArray torControlHashedPassword(const QByteArray &password);
#endif // CRYPTOKEY_H

View File

@ -1,147 +0,0 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* 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 <QtDebug>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <limits.h>
#ifdef Q_OS_WIN
#include <wtypes.h>
#include <wincrypt.h>
#endif
#if QT_VERSION >= 0x040700
#include <QElapsedTimer>
#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<BYTE*>(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<unsigned char*>(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<char*>(&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<char*>(value), sizeof(value));
if (value < cutoff)
return value % max;
}
}

View File

@ -1,553 +0,0 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* 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 <QCoreApplication>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QSaveFile>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QTimer>
#include <QDebug>
#include <QPointer>
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<QPair<QStringList, QJsonValue> > 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<QPair<QString,QJsonObject> > 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<SettingsFile> 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"

Some files were not shown because too many files have changed in this diff Show More