diff --git a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc index 9b62d45ba..bee4c9b59 100644 --- a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc +++ b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc @@ -36,14 +36,11 @@ RsItem *RsDiscSerialiser::create_item( switch(static_cast(item_subtype)) { case RsGossipDiscoveryItemType::PGP_LIST: return new RsDiscPgpListItem(); - case RsGossipDiscoveryItemType::PGP_CERT: return new RsDiscPgpCertItem(); + case RsGossipDiscoveryItemType::PGP_CERT_BINARY: return new RsDiscPgpKeyItem(); case RsGossipDiscoveryItemType::CONTACT: return new RsDiscContactItem(); - case RsGossipDiscoveryItemType::IDENTITY_LIST: - return new RsDiscIdentityListItem(); - case RsGossipDiscoveryItemType::INVITE: - return new RsGossipDiscoveryInviteItem(); - case RsGossipDiscoveryItemType::INVITE_REQUEST: - return new RsGossipDiscoveryInviteRequestItem(); + case RsGossipDiscoveryItemType::IDENTITY_LIST: return new RsDiscIdentityListItem(); + default: + return nullptr; } return nullptr; @@ -65,17 +62,20 @@ void RsDiscPgpListItem::serial_process( RS_SERIAL_PROCESS(pgpIdSet); } -void RsDiscPgpCertItem::clear() +void RsDiscPgpKeyItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { - pgpId.clear(); - pgpCert.clear(); + RsTypeSerializer::serial_process(j,ctx,pgpKeyId,"pgpKeyId") ; + + RsTypeSerializer::TlvMemBlock_proxy prox(bin_data,bin_len) ; + RsTypeSerializer::serial_process(j,ctx,prox,"keyData") ; } - -void RsDiscPgpCertItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) +void RsDiscPgpKeyItem::clear() { - RsTypeSerializer::serial_process(j,ctx,pgpId,"pgpId") ; - RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_PGPCERT,pgpCert,"pgpCert") ; + pgpKeyId.clear(); + free(bin_data); + bin_data = nullptr; + bin_len=0; } void RsDiscContactItem::clear() @@ -146,17 +146,9 @@ void RsDiscIdentityListItem::serial_process(RsGenericSerializer::SerializeJob j, RS_SERIAL_PROCESS(ownIdentityList); } - -RsGossipDiscoveryInviteItem::RsGossipDiscoveryInviteItem() : - RsDiscItem(RsGossipDiscoveryItemType::INVITE) -{ setPriorityLevel(QOS_PRIORITY_RS_DISC_ASK_INFO); } - -RsGossipDiscoveryInviteRequestItem::RsGossipDiscoveryInviteRequestItem() : - RsDiscItem(RsGossipDiscoveryItemType::INVITE_REQUEST) -{ setPriorityLevel(QOS_PRIORITY_RS_DISC_REPLY); } - -RsDiscItem::RsDiscItem(RsGossipDiscoveryItemType subtype) : - RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_DISC, - static_cast(subtype) ) {} +RsDiscItem::RsDiscItem(RsGossipDiscoveryItemType subtype) + : RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_DISC, static_cast(subtype) ) +{ +} RsDiscItem::~RsDiscItem() {} diff --git a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h index 70bf5920a..f5e219b95 100644 --- a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h +++ b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h @@ -25,6 +25,7 @@ #include "serialiser/rsserial.h" #include "serialiser/rstlvidset.h" #include "serialiser/rstlvaddrs.h" +#include "serialiser/rstlvbinary.h" #include "rsitems/rsserviceids.h" #include "rsitems/rsitem.h" #include "rsitems/itempriorities.h" @@ -34,11 +35,10 @@ enum class RsGossipDiscoveryItemType : uint8_t { PGP_LIST = 0x1, - PGP_CERT = 0x2, + PGP_CERT = 0x2, // deprecated CONTACT = 0x5, IDENTITY_LIST = 0x6, - INVITE = 0x7, - INVITE_REQUEST = 0x8 + PGP_CERT_BINARY = 0x9, }; class RsDiscItem: public RsItem @@ -80,20 +80,21 @@ public: RsTlvPgpIdSet pgpIdSet; }; -class RsDiscPgpCertItem: public RsDiscItem +class RsDiscPgpKeyItem: public RsDiscItem { public: - RsDiscPgpCertItem() : RsDiscItem(RsGossipDiscoveryItemType::PGP_CERT) + RsDiscPgpKeyItem() : RsDiscItem(RsGossipDiscoveryItemType::PGP_CERT_BINARY) { setPriorityLevel(QOS_PRIORITY_RS_DISC_PGP_CERT); } - void clear() override; - void serial_process( - RsGenericSerializer::SerializeJob j, - RsGenericSerializer::SerializeContext& ctx) override; + virtual ~RsDiscPgpKeyItem() { delete[](bin_data);bin_data=nullptr;bin_len=0;} - RsPgpId pgpId; - std::string pgpCert; + void clear() override; + void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) override; + + RsPgpId pgpKeyId; // duplicate information for practical reasons + unsigned char *bin_data; // binry key data allocated with new unsigned char[] + uint32_t bin_len; }; class RsDiscContactItem: public RsDiscItem @@ -158,30 +159,6 @@ public: std::list ownIdentityList; }; -struct RsGossipDiscoveryInviteItem : RsDiscItem -{ - RsGossipDiscoveryInviteItem(); - - void serial_process( RsGenericSerializer::SerializeJob j, - RsGenericSerializer::SerializeContext& ctx ) override - { RS_SERIAL_PROCESS(mInvite); } - void clear() override { mInvite.clear(); } - - std::string mInvite; -}; - -struct RsGossipDiscoveryInviteRequestItem : RsDiscItem -{ - RsGossipDiscoveryInviteRequestItem(); - - void serial_process( RsGenericSerializer::SerializeJob j, - RsGenericSerializer::SerializeContext& ctx ) override - { RS_SERIAL_PROCESS(mInviteId); } - void clear() override { mInviteId.clear(); } - - RsPeerId mInviteId; -}; - class RsDiscSerialiser: public RsServiceSerializer { public: diff --git a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc index f3a2cc460..d7cf5f1a7 100644 --- a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc +++ b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc @@ -27,16 +27,15 @@ #include "retroshare/rsiface.h" #include "rsserver/p3face.h" #include "util/rsdebug.h" +#include "retroshare/rspeers.h" /**** * #define P3DISC_DEBUG 1 ****/ +#define P3DISC_DEBUG 1 /*extern*/ std::shared_ptr rsGossipDiscovery(nullptr); -RsGossipDiscovery::~RsGossipDiscovery() {}; - - static bool populateContactInfo( const peerState &detail, RsDiscContactItem *pkt, bool include_ip_information ) @@ -86,9 +85,9 @@ static bool populateContactInfo( const peerState &detail, return true; } -void DiscPgpInfo::mergeFriendList(const std::set &friends) +void DiscPgpInfo::mergeFriendList(const std::set &friends) { - std::set::const_iterator it; + std::set::const_iterator it; for(it = friends.begin(); it != friends.end(); ++it) { mFriendSet.insert(*it); @@ -139,13 +138,13 @@ RsServiceInfo p3discovery2::getServiceInfo() p3discovery2::~p3discovery2() { rsEvents->unregisterEventsHandler(mRsEventsHandle); } -void p3discovery2::addFriend(const SSLID &sslId) +void p3discovery2::addFriend(const RsPeerId &sslId) { - PGPID pgpId = getPGPId(sslId); + RsPgpId pgpId = getPGPId(sslId); RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it; + std::map::iterator it; it = mFriendList.find(pgpId); if (it == mFriendList.end()) { @@ -160,9 +159,9 @@ void p3discovery2::addFriend(const SSLID &sslId) } - /* now add SSLID */ + /* now add RsPeerId */ - std::map::iterator sit; + std::map::iterator sit; sit = it->second.mSslIds.find(sslId); if (sit == it->second.mSslIds.end()) { @@ -187,13 +186,13 @@ void p3discovery2::addFriend(const SSLID &sslId) } } -void p3discovery2::removeFriend(const SSLID &sslId) +void p3discovery2::removeFriend(const RsPeerId &sslId) { - PGPID pgpId = getPGPId(sslId); + RsPgpId pgpId = getPGPId(sslId); RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it; + std::map::iterator it; it = mFriendList.find(pgpId); if (it == mFriendList.end()) { @@ -204,7 +203,7 @@ void p3discovery2::removeFriend(const SSLID &sslId) return; } - std::map::iterator sit; + std::map::iterator sit; sit = it->second.mSslIds.find(sslId); if (sit == it->second.mSslIds.end()) { @@ -239,9 +238,9 @@ void p3discovery2::removeFriend(const SSLID &sslId) } } -PGPID p3discovery2::getPGPId(const SSLID &id) +RsPgpId p3discovery2::getPGPId(const RsPeerId &id) { - PGPID pgpId; + RsPgpId pgpId; mPeerMgr->getGpgId(id, pgpId); return pgpId; } @@ -259,12 +258,10 @@ int p3discovery2::handleIncoming() // While messages read while(nullptr != (item = recvItem())) { - RsDiscPgpListItem* pgplist = nullptr; - RsDiscPgpCertItem* pgpcert = nullptr; - RsDiscContactItem* contact = nullptr; + RsDiscPgpListItem* pgplist = nullptr; + RsDiscPgpKeyItem* pgpkey = nullptr; + RsDiscContactItem* contact = nullptr; RsDiscIdentityListItem* gxsidlst = nullptr; - RsGossipDiscoveryInviteItem* invite = nullptr; - RsGossipDiscoveryInviteRequestItem* inviteReq = nullptr; ++nhandled; @@ -275,16 +272,16 @@ int p3discovery2::handleIncoming() { if (item->PeerId() == contact->sslId) recvOwnContactInfo(item->PeerId(), contact); - else processContactInfo(item->PeerId(), contact); + else + processContactInfo(item->PeerId(), contact); } - else if( (gxsidlst = dynamic_cast(item)) - != nullptr ) + else if( (gxsidlst = dynamic_cast(item)) != nullptr ) { recvIdentityList(item->PeerId(),gxsidlst->ownIdentityList); delete item; } - else if((pgpcert = dynamic_cast(item)) != nullptr) - recvPGPCertificate(item->PeerId(), pgpcert); + else if((pgpkey = dynamic_cast(item)) != nullptr) + recvPGPCertificate(item->PeerId(), pgpkey); else if((pgplist = dynamic_cast(item)) != nullptr) { if (pgplist->mode == RsGossipDiscoveryPgpListMode::FRIENDS) @@ -293,20 +290,10 @@ int p3discovery2::handleIncoming() recvPGPCertificateRequest(pgplist->PeerId(), pgplist); else delete item; } - else if( (invite = dynamic_cast(item)) - != nullptr ) - recvInvite(std::unique_ptr(invite)); - else if( (inviteReq = - dynamic_cast(item)) - != nullptr ) - { - sendInvite(inviteReq->mInviteId, item->PeerId()); - delete item; - } else { - RsWarn() << __PRETTY_FUNCTION__ << " Received unknown item type! " - << std::endl << item << std::endl; + RsWarn() << __PRETTY_FUNCTION__ << " Received unknown item type " << (int)item->PacketSubType() << "! " << std::endl ; + RsWarn() << item << std::endl; delete item; } } @@ -314,7 +301,7 @@ int p3discovery2::handleIncoming() return nhandled; } -void p3discovery2::sendOwnContactInfo(const SSLID &sslid) +void p3discovery2::sendOwnContactInfo(const RsPeerId &sslid) { #ifdef P3DISC_DEBUG @@ -325,9 +312,13 @@ void p3discovery2::sendOwnContactInfo(const SSLID &sslid) if (mPeerMgr->getOwnNetStatus(detail)) { RsDiscContactItem *pkt = new RsDiscContactItem(); + /* Cyril: we dont send our own IP to an hidden node. It will not use it - * anyway. */ + * anyway. Furthermore, a Tor node is not supposed to have any mean to send the IPs of his friend nodes + * to other nodes. This would be a very serious security risk. */ + populateContactInfo(detail, pkt, !rsPeers->isHiddenNode(sslid)); + /* G10h4ck: sending IP information also to hidden nodes has proven very * helpful in the usecase of non hidden nodes, that share a common * hidden trusted node, to discover each other IP. @@ -336,7 +327,6 @@ void p3discovery2::sendOwnContactInfo(const SSLID &sslid) * permission matrix. Disabling this instead will make life more * difficult for average user, that moreover whould have no way to * revert an hardcoded policy. */ - //populateContactInfo(detail, pkt, true); pkt->version = RS_HUMAN_READABLE_VERSION; pkt->PeerId(sslid); @@ -362,8 +352,9 @@ void p3discovery2::sendOwnContactInfo(const SSLID &sslid) } } -void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactItem *item) +void p3discovery2::recvOwnContactInfo(const RsPeerId &fromId, const RsDiscContactItem *item) { + std::unique_ptr pitem(item); // ensures that item will be destroyed whichever door we leave through #ifdef P3DISC_DEBUG std::cerr << "p3discovery2::recvOwnContactInfo()"; @@ -376,6 +367,21 @@ void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactIt std::cerr << " -> location : " << item->location << std::endl; std::cerr << std::endl; #endif + // Check that the "own" ID sent corresponds to the one we think it should be. + // Some of these checks may look superfluous but it's better to risk to check twice than not check at all. + + // was obtained using a short invite. , and that the friend is marked as "ignore PGP validation" because it + RsPeerDetails det ; + if(!rsPeers->getPeerDetails(fromId,det)) + { + RsErr() << "(EE) Cannot obtain details from " << fromId << " who is supposed to be a friend! Dropping the info." << std::endl; + return; + } + if(det.gpg_id != item->pgpId) + { + RsErr() << "(EE) peer " << fromId << " sent own details with PGP key ID " << item->pgpId << " which does not match the known key id " << det.gpg_id << ". Dropping the info." << std::endl; + return; + } // Peer Own Info replaces the existing info, because the // peer is the primary source of his own IPs. @@ -388,21 +394,37 @@ void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactIt updatePeerAddresses(item); + // if the peer is not validated, we stop the exchange here + + if(det.skip_pgp_signature_validation) + { +#ifdef P3DISC_DEBUG + std::cerr << "p3discovery2::recvOwnContactInfo() missing PGP key " << item->pgpId << " from short invite friend " << fromId << ". Requesting it." << std::endl; +#endif + requestPGPCertificate(det.gpg_id, fromId); + return; + } + // This information will be sent out to online peers, at the receipt of their PGPList. // It is important that PGPList is received after the OwnContactItem. // This should happen, but is not enforced by the protocol. - // start peer list exchange. - sendPGPList(fromId); + // Start peer list exchange, if discovery is enabled + + peerState ps; + mPeerMgr->getOwnNetStatus(ps); + + if(ps.vs_disc != RS_VS_DISC_OFF) + sendPGPList(fromId); // Update mDiscStatus. RS_STACK_MUTEX(mDiscMtx); - PGPID pgpId = getPGPId(fromId); - std::map::iterator it = mFriendList.find(pgpId); + RsPgpId pgpId = getPGPId(fromId); + std::map::iterator it = mFriendList.find(pgpId); if (it != mFriendList.end()) { - std::map::iterator sit = it->second.mSslIds.find(fromId); + std::map::iterator sit = it->second.mSslIds.find(fromId); if (sit != it->second.mSslIds.end()) { sit->second.mDiscStatus = item->vs_disc; @@ -421,17 +443,6 @@ void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactIt #endif } } - else - { -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::recvOwnContactInfo()"; - std::cerr << " ERROR missing PGP Entry: " << pgpId; - std::cerr << std::endl; -#endif - } - - // cleanup. - delete item; } void p3discovery2::recvIdentityList(const RsPeerId& pid,const std::list& ids) @@ -502,7 +513,7 @@ void p3discovery2::updatePeerAddressList(const RsDiscContactItem *item) // Starts the Discovery process. // should only be called it DISC2_STATUS_NOT_HIDDEN(OwnInfo.status). -void p3discovery2::sendPGPList(const SSLID &toId) +void p3discovery2::sendPGPList(const RsPeerId &toId) { updatePgpFriendList(); @@ -517,10 +528,17 @@ void p3discovery2::sendPGPList(const SSLID &toId) pkt->mode = RsGossipDiscoveryPgpListMode::FRIENDS; - std::map::const_iterator it; - for(it = mFriendList.begin(); it != mFriendList.end(); ++it) + for(auto it = mFriendList.begin(); it != mFriendList.end(); ++it) { - pkt->pgpIdSet.ids.insert(it->first); + // Check every friend, and only send his PGP key if the friend tells that he wants discovery. Because this action over profiles depends on a node information, + // we check each node of a given progile and only send the profile key if at least one node allows it. + + for(auto it2(it->second.mSslIds.begin());it2!=it->second.mSslIds.end();++it2) + if(it2->second.mDiscStatus != RS_VS_DISC_OFF) + { + pkt->pgpIdSet.ids.insert(it->first); + break; + } } pkt->PeerId(toId); @@ -556,14 +574,14 @@ void p3discovery2::updatePgpFriendList() mLastPgpUpdate = time(NULL); - std::list pgpList; - std::set pgpSet; + std::list pgpList; + std::set pgpSet; - std::set::iterator sit; - std::list::iterator lit; - std::map::iterator it; + std::set::iterator sit; + std::list::iterator lit; + std::map::iterator it; - PGPID ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId(); + RsPgpId ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId(); AuthGPG::getAuthGPG()->getGPGAcceptedList(pgpList); pgpList.push_back(ownPgpId); @@ -573,8 +591,8 @@ void p3discovery2::updatePgpFriendList() pgpSet.insert(*lit); } - std::list pgpToAdd; - std::list pgpToRemove; + std::list pgpToAdd; + std::list pgpToRemove; sit = pgpSet.begin(); @@ -640,7 +658,7 @@ void p3discovery2::updatePgpFriendList() } -void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem *item) +void p3discovery2::processPGPList(const RsPeerId &fromId, const RsDiscPgpListItem *item) { RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ @@ -649,9 +667,8 @@ void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem * std::cerr << std::endl; #endif - std::map::iterator it; - PGPID fromPgpId = getPGPId(fromId); - it = mFriendList.find(fromPgpId); + RsPgpId fromPgpId = getPGPId(fromId); + auto it = mFriendList.find(fromPgpId); if (it == mFriendList.end()) { #ifdef P3DISC_DEBUG @@ -668,9 +685,7 @@ void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem * peerState pstate; mPeerMgr->getOwnNetStatus(pstate); if (pstate.vs_disc != RS_VS_DISC_FULL) - { requestUnknownPgpCerts = false; - } uint32_t linkType = mLinkMgr->getLinkType(fromId); if ((linkType & RS_NET_CONN_SPEED_TRICKLE) || @@ -683,13 +698,13 @@ void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem * if (requestUnknownPgpCerts) { - std::set::const_iterator fit; + std::set::const_iterator fit; for(fit = item->pgpIdSet.ids.begin(); fit != item->pgpIdSet.ids.end(); ++fit) { if (!AuthGPG::getAuthGPG()->isGPGId(*fit)) { #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::processPGPList() requesting PgpId: " << *fit; + std::cerr << "p3discovery2::processPGPList() requesting certificate for PgpId: " << *fit; std::cerr << " from SslId: " << fromId; std::cerr << std::endl; #endif @@ -710,7 +725,7 @@ void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem * * -> Update Other Peers about B. * -> Update B about Other Peers. */ -void p3discovery2::updatePeers_locked(const SSLID &aboutId) +void p3discovery2::updatePeers_locked(const RsPeerId &aboutId) { #ifdef P3DISC_DEBUG @@ -718,10 +733,9 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) std::cerr << std::endl; #endif - PGPID aboutPgpId = getPGPId(aboutId); + RsPgpId aboutPgpId = getPGPId(aboutId); - std::map::const_iterator ait; - ait = mFriendList.find(aboutPgpId); + auto ait = mFriendList.find(aboutPgpId); if (ait == mFriendList.end()) { @@ -732,13 +746,12 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) return; } - std::set mutualFriends; - std::set onlineFriends; - std::set::const_iterator sit; + std::set mutualFriends; + std::set onlineFriends; - const std::set &friendSet = ait->second.mFriendSet; - std::set::const_iterator fit; - for(fit = friendSet.begin(); fit != friendSet.end(); ++fit) + const std::set &friendSet = ait->second.mFriendSet; + + for(auto fit = friendSet.begin(); fit != friendSet.end(); ++fit) { #ifdef P3DISC_DEBUG @@ -746,8 +759,8 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) std::cerr << std::endl; #endif - std::map::const_iterator ffit; - ffit = mFriendList.find(*fit); + auto ffit = mFriendList.find(*fit); + if (ffit == mFriendList.end()) { @@ -755,7 +768,7 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) std::cerr << "p3discovery2::updatePeer_locked() Ignoring not our friend"; std::cerr << std::endl; #endif - // Not our friend, or we have no Locations (SSL) for this PGPID (same difference) + // Not our friend, or we have no Locations (SSL) for this RsPgpId (same difference) continue; } @@ -768,16 +781,14 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) #endif mutualFriends.insert(*fit); - std::map::const_iterator mit; - for(mit = ffit->second.mSslIds.begin(); - mit != ffit->second.mSslIds.end(); ++mit) + for(auto mit = ffit->second.mSslIds.begin(); mit != ffit->second.mSslIds.end(); ++mit) { - SSLID sslid = mit->first; + RsPeerId sslid = mit->first; if (mServiceCtrl->isPeerConnected(getServiceInfo().mServiceType, sslid)) { // TODO IGNORE if sslid == aboutId, or sslid == ownId. #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::updatePeer_locked() Adding Online SSLID: " << sslid; + std::cerr << "p3discovery2::updatePeer_locked() Adding Online RsPeerId: " << sslid; std::cerr << std::endl; #endif onlineFriends.insert(sslid); @@ -791,17 +802,15 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) std::cerr << std::endl; #endif // update aboutId about Other Peers. - for(fit = mutualFriends.begin(); fit != mutualFriends.end(); ++fit) - { + for(auto fit = mutualFriends.begin(); fit != mutualFriends.end(); ++fit) sendContactInfo_locked(*fit, aboutId); - } #ifdef P3DISC_DEBUG std::cerr << "p3discovery2::updatePeer_locked() Updating Online Peers about " << aboutId; std::cerr << std::endl; #endif // update Other Peers about aboutPgpId. - for(sit = onlineFriends.begin(); sit != onlineFriends.end(); ++sit) + for(auto sit = onlineFriends.begin(); sit != onlineFriends.end(); ++sit) { // This could be more efficient, and only be specific about aboutId. // but we'll leave it like this for the moment. @@ -809,13 +818,13 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) } } -void p3discovery2::sendContactInfo_locked(const PGPID &aboutId, const SSLID &toId) +void p3discovery2::sendContactInfo_locked(const RsPgpId &aboutId, const RsPeerId &toId) { #ifdef P3DISC_DEBUG std::cerr << "p3discovery2::sendContactInfo_locked() aboutPGPId: " << aboutId << " toId: " << toId; std::cerr << std::endl; #endif - std::map::const_iterator it; + std::map::const_iterator it; it = mFriendList.find(aboutId); if (it == mFriendList.end()) { @@ -826,7 +835,7 @@ void p3discovery2::sendContactInfo_locked(const PGPID &aboutId, const SSLID &toI return; } - std::map::const_iterator sit; + std::map::const_iterator sit; for(sit = it->second.mSslIds.begin(); sit != it->second.mSslIds.end(); ++sit) { #ifdef P3DISC_DEBUG @@ -882,35 +891,37 @@ void p3discovery2::sendContactInfo_locked(const PGPID &aboutId, const SSLID &toI else { #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::sendContactInfo_locked() SSLID Hidden"; + std::cerr << "p3discovery2::sendContactInfo_locked() RsPeerId Hidden"; std::cerr << std::endl; #endif } } } -void p3discovery2::processContactInfo(const SSLID &fromId, const RsDiscContactItem *item) +void p3discovery2::processContactInfo(const RsPeerId &fromId, const RsDiscContactItem *item) { (void) fromId; // remove unused parameter warnings, debug only RS_STACK_MUTEX(mDiscMtx); + // This case is the node fromId sending information about ourselves to us. There's one good use of this: + // read the IP information the friend knows about us, and use it to extimate our external address. + if (item->sslId == rsPeers->getOwnId()) { if(sockaddr_storage_isExternalNet(item->currentConnectAddress.addr)) - mPeerMgr->addCandidateForOwnExternalAddress( - item->PeerId(), item->currentConnectAddress.addr); + mPeerMgr->addCandidateForOwnExternalAddress(item->PeerId(), item->currentConnectAddress.addr); delete item; return; } - std::map::iterator it; - it = mFriendList.find(item->pgpId); - if (it == mFriendList.end()) + auto it = mFriendList.find(item->pgpId); // is this the PGP id one of our friends? + + if (it == mFriendList.end()) // no it's not. { #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::processContactInfo(" << fromId << ") PGPID: "; + std::cerr << "p3discovery2::processContactInfo(" << fromId << ") RsPgpId: "; std::cerr << item->pgpId << " Not Friend."; std::cerr << std::endl; std::cerr << "p3discovery2::processContactInfo(" << fromId << ") THIS SHOULD NEVER HAPPEN!"; @@ -928,53 +939,55 @@ void p3discovery2::processContactInfo(const SSLID &fromId, const RsDiscContactIt mNetMgr->netAssistFriend(item->sslId,false); /* inform NetMgr that we know this peer */ - mNetMgr->netAssistKnownPeer(item->sslId, item->extAddrV4.addr, - NETASSIST_KNOWN_PEER_FOF | NETASSIST_KNOWN_PEER_OFFLINE); + mNetMgr->netAssistKnownPeer(item->sslId, item->extAddrV4.addr, NETASSIST_KNOWN_PEER_FOF | NETASSIST_KNOWN_PEER_OFFLINE); } delete item; return; } - bool should_notify_discovery = false; - std::map::iterator sit; - sit = it->second.mSslIds.find(item->sslId); - if (sit == it->second.mSslIds.end()) - { - /* insert! */ - DiscSslInfo sslInfo; - it->second.mSslIds[item->sslId] = sslInfo; - //sit = it->second.mSslIds.find(item->sslId); + // The peer the discovery info is about is a friend. We gather the nodes for that profile into the local structure and notify p3peerMgr. + if(!rsPeers->isGPGAccepted(item->pgpId)) // this is an additional check, because the friendship previously depends on the local cache. We need + return ; // fresh information here. + + bool should_notify_discovery = false; + auto sit= it->second.mSslIds.find(item->sslId); + + DiscSslInfo& sslInfo(it->second.mSslIds[item->sslId]); // This line inserts the entry while not removing already existing data + // do not remove it! + + if (!mPeerMgr->isFriend(item->sslId)) + { should_notify_discovery = true; - if (!mPeerMgr->isFriend(item->sslId)) - { - // Add with no disc by default. If friend already exists, it will do nothing - // NO DISC is important - otherwise, we'll just enter a nasty loop, - // where every addition triggers requests, then they are cleaned up, and readded... + // Add with no disc by default. If friend already exists, it will do nothing + // NO DISC is important - otherwise, we'll just enter a nasty loop, + // where every addition triggers requests, then they are cleaned up, and readded... - // This way we get their addresses, but don't advertise them until we get a - // connection. + // This way we get their addresses, but don't advertise them until we get a + // connection. #ifdef P3DISC_DEBUG - std::cerr << "--> Adding to friends list " << item->sslId << " - " << item->pgpId << std::endl; + std::cerr << "--> Adding to friends list " << item->sslId << " - " << item->pgpId << std::endl; #endif - // We pass RS_NODE_PERM_ALL because the PGP id is already a friend, so we should keep the existing - // permission flags. Therefore the mask needs to be 0xffff. + // We pass RS_NODE_PERM_ALL because the PGP id is already a friend, so we should keep the existing + // permission flags. Therefore the mask needs to be 0xffff. - // set last seen to RS_PEER_OFFLINE_NO_DISC minus 1 so that it won't be shared with other friends - // until a first connection is established + // set last seen to RS_PEER_OFFLINE_NO_DISC minus 1 so that it won't be shared with other friends + // until a first connection is established - mPeerMgr->addFriend( item->sslId, item->pgpId, item->netMode, - RS_VS_DISC_OFF, RS_VS_DHT_FULL, - time(NULL) - RS_PEER_OFFLINE_NO_DISC - 1, - RS_NODE_PERM_ALL ); - updatePeerAddresses(item); - } + // This code is a bit dangerous: we add a friend without the insurance that the PGP key that will validate this friend actually has + // the supplied PGP id. Of course, because it comes from a friend, we should trust that friend. Anyway, it is important that + // when connecting the handshake is always doen w.r.t. the known PGP key, and not the one that is indicated in the certificate issuer field. + + mPeerMgr->addFriend( item->sslId, item->pgpId, item->netMode, + RS_VS_DISC_OFF, RS_VS_DHT_FULL, + time(NULL) - RS_PEER_OFFLINE_NO_DISC - 1, + RS_NODE_PERM_ALL ); + + updatePeerAddresses(item); } - updatePeerAddressList(item); - RsServer::notify()->notifyListChange(NOTIFY_LIST_NEIGHBOURS, NOTIFY_TYPE_MOD); if(should_notify_discovery) @@ -985,7 +998,7 @@ void p3discovery2::processContactInfo(const SSLID &fromId, const RsDiscContactIt /* we explictly request certificates, instead of getting them all the time */ -void p3discovery2::requestPGPCertificate(const PGPID &aboutId, const SSLID &toId) +void p3discovery2::requestPGPCertificate(const RsPgpId &aboutId, const RsPeerId &toId) { #ifdef P3DISC_DEBUG std::cerr << "p3discovery2::requestPGPCertificate() aboutId: " << aboutId << " to: " << toId; @@ -1007,45 +1020,113 @@ void p3discovery2::requestPGPCertificate(const PGPID &aboutId, const SSLID &toId sendItem(pkt); } -void p3discovery2::recvPGPCertificateRequest( - const RsPeerId& fromId, const RsDiscPgpListItem* item ) +void p3discovery2::recvPGPCertificateRequest( const RsPeerId& fromId, const RsDiscPgpListItem* item ) { #ifdef P3DISC_DEBUG std::cerr << __PRETTY_FUNCTION__ << " from " << fromId << std::endl; #endif + peerState ps; + mPeerMgr->getOwnNetStatus(ps); + + if(ps.vs_disc == RS_VS_DISC_OFF) + { + std::cerr << "(WW) refusing PGP certificate request from " << fromId << " because discovery is OFF" << std::endl; + return; + } RsPgpId ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId(); for(const RsPgpId& pgpId : item->pgpIdSet.ids) - if (pgpId == ownPgpId || AuthGPG::getAuthGPG()->isGPGAccepted(pgpId)) + if (pgpId == ownPgpId) sendPGPCertificate(pgpId, fromId); + else if(ps.vs_disc != RS_VS_DISC_OFF && AuthGPG::getAuthGPG()->isGPGAccepted(pgpId)) + sendPGPCertificate(pgpId, fromId); + 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; + delete item; } -void p3discovery2::sendPGPCertificate(const PGPID &aboutId, const SSLID &toId) +void p3discovery2::sendPGPCertificate(const RsPgpId &aboutId, const RsPeerId &toId) { - RsDiscPgpCertItem* item = new RsDiscPgpCertItem(); - item->pgpId = aboutId; - item->PeerId(toId); + RsDiscPgpKeyItem *pgp_key_item = new RsDiscPgpKeyItem; - Dbg4() << __PRETTY_FUNCTION__ << " queuing for Cert generation: " - << std::endl << *item << std::endl; + pgp_key_item->PeerId(toId); + pgp_key_item->pgpKeyId = aboutId; + unsigned char *bin_data; + size_t bin_len; - { - RS_STACK_MUTEX(mDiscMtx); - mPendingDiscPgpCertOutList.push_back(item); - } + if(!AuthGPG::getAuthGPG()->exportPublicKey(aboutId,bin_data,bin_len,false,true)) + { + std::cerr << "(EE) cannot export public key " << aboutId << " requested by peer " << toId << std::endl; + return ; + } + + pgp_key_item->bin_data = bin_data; + pgp_key_item->bin_len = bin_len; + + sendItem(pgp_key_item); } -void p3discovery2::recvPGPCertificate( - const SSLID& /*fromId*/, RsDiscPgpCertItem* item ) +void p3discovery2::recvPGPCertificate(const RsPeerId& fromId, RsDiscPgpKeyItem* item ) { + // 1 - check that the cert structure is valid. + + RsPgpId cert_pgp_id; + std::string cert_name; + std::list cert_signers; + + if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock( (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; + return; + } + + if(cert_pgp_id != item->pgpKeyId) + { + std::cerr << "(EE) received a PGP key from " << fromId << " which ID (" << cert_pgp_id << ") is different from the one anounced in the packet (" << item->pgpKeyId << ")!" << std::endl; + return; + } + + // 2 - check if the peer who is sending us a cert is already validated + + RsPeerDetails det; + if(!rsPeers->getPeerDetails(fromId,det)) + { + std::cerr << "(EE) cannot get peer details from friend " << fromId << ": this is very wrong!"<< std::endl; + return; + } + + // We treat own pgp keys right away when they are sent by a friend for which we dont have it. This way we can keep the skip_pgg_signature_validation consistent + + if(det.skip_pgp_signature_validation) + { #ifdef P3DISC_DEBUG - std::cerr << __PRETTY_FUNCTION__ << " queuing for Cert loading" << std::endl; + std::cerr << __PRETTY_FUNCTION__ << " Received own full certificate from short-invite friend " << fromId << std::endl; #endif - /* push this back to be processed by pgp when possible */ - RS_STACK_MUTEX(mDiscMtx); - mPendingDiscPgpCertInList.push_back(item); + // do some extra checks. Dont remove them. They cost nothing as compared to what they could avoid. + + if(item->pgpKeyId != det.gpg_id) + { + std::cerr << "(EE) received a PGP key with ID " << item->pgpKeyId << " from non validated peer " << fromId << ", which should only be allowed to send his own key " << det.gpg_id << std::endl; + return; + } + } + RsPgpId tmp_pgp_id; + std::string error_string; + +#ifdef P3DISC_DEBUG + std::cerr << __PRETTY_FUNCTION__ << "Received PGP key " << cert_pgp_id << " from from friend " << fromId << ". Adding to keyring." << std::endl; +#endif + // now that will add the key *and* set the skip_signature_validation flag at once + rsPeers->loadPgpKeyFromBinaryData((unsigned char*)item->bin_data,item->bin_len, tmp_pgp_id,error_string); // no error should occur at this point because we called loadDetailsFromStringCert() already + delete item; + + // Make sure we allow connections after the key is added. This is not the case otherwise. We only do that if the peer is non validated peer, since + // 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) + AuthGPG::getAuthGPG()->AllowConnection(det.gpg_id,true); } /************* from pqiServiceMonitor *******************/ @@ -1103,8 +1184,8 @@ bool p3discovery2::getDiscFriends(const RsPeerId& id, std::list &proxy RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it; - PGPID pgp_id = getPGPId(id); + std::map::const_iterator it; + RsPgpId pgp_id = getPGPId(id); it = mFriendList.find(pgp_id); if (it == mFriendList.end()) @@ -1113,9 +1194,9 @@ bool p3discovery2::getDiscFriends(const RsPeerId& id, std::list &proxy return false; } - // For each of their friends that we know, grab that set of SSLIDs. - const std::set &friendSet = it->second.mFriendSet; - std::set::const_iterator fit; + // For each of their friends that we know, grab that set of RsPeerId. + const std::set &friendSet = it->second.mFriendSet; + std::set::const_iterator fit; for(fit = friendSet.begin(); fit != friendSet.end(); ++fit) { it = mFriendList.find(*fit); @@ -1124,7 +1205,7 @@ bool p3discovery2::getDiscFriends(const RsPeerId& id, std::list &proxy continue; } - std::map::const_iterator sit; + std::map::const_iterator sit; for(sit = it->second.mSslIds.begin(); sit != it->second.mSslIds.end(); ++sit) { @@ -1138,51 +1219,13 @@ bool p3discovery2::getDiscFriends(const RsPeerId& id, std::list &proxy bool p3discovery2::getWaitingDiscCount(size_t &sendCount, size_t &recvCount) { RS_STACK_MUTEX(mDiscMtx); - sendCount = mPendingDiscPgpCertOutList.size(); - recvCount = mPendingDiscPgpCertInList.size(); + sendCount = 0;//mPendingDiscPgpCertOutList.size(); + recvCount = 0;//mPendingDiscPgpCertInList.size(); return true; } -bool p3discovery2::sendInvite( - const RsPeerId& inviteId, const RsPeerId& toSslId, - std::string& errorMsg ) -{ - RsPeers& mPeers = *rsPeers; - - std::string&& invite = mPeers.GetRetroshareInvite(inviteId); - - if(invite.empty()) - { - errorMsg = "Failure generating invite for peer: " + - inviteId.toStdString() + " are you sure is a friend?"; - RsErr() << __PRETTY_FUNCTION__ << " " << errorMsg << std::endl; - return false; - } - - RsGossipDiscoveryInviteItem* item = new RsGossipDiscoveryInviteItem; - item->PeerId(toSslId); - item->mInvite = mPeers.GetRetroshareInvite(inviteId, true, true); - - return sendItem(item); -} - -bool p3discovery2::requestInvite( - const RsPeerId& inviteId, const RsPeerId& toSslId, - std::string& /*errorMsg*/ ) -{ - Dbg2() << __PRETTY_FUNCTION__ << " inviteId: " << inviteId - << " toSslId: " << toSslId << std::endl; - - RsGossipDiscoveryInviteRequestItem* item = - new RsGossipDiscoveryInviteRequestItem; - item->PeerId(toSslId); - item->mInviteId = inviteId; - - return sendItem(item); -} - -bool p3discovery2::getDiscPgpFriends(const PGPID &pgp_id, std::list &proxyPgpIds) +bool p3discovery2::getDiscPgpFriends(const RsPgpId &pgp_id, std::list &proxyPgpIds) { /* find id -> and extract the neighbour_of ids */ @@ -1191,7 +1234,7 @@ bool p3discovery2::getDiscPgpFriends(const PGPID &pgp_id, std::list &prox RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it; + std::map::const_iterator it; it = mFriendList.find(pgp_id); if (it == mFriendList.end()) { @@ -1199,7 +1242,7 @@ bool p3discovery2::getDiscPgpFriends(const PGPID &pgp_id, std::list &prox return false; } - std::set::const_iterator fit; + std::set::const_iterator fit; for(fit = it->second.mFriendSet.begin(); fit != it->second.mFriendSet.end(); ++fit) { proxyPgpIds.push_back(*fit); @@ -1207,11 +1250,11 @@ bool p3discovery2::getDiscPgpFriends(const PGPID &pgp_id, std::list &prox return true; } -bool p3discovery2::getPeerVersion(const SSLID &peerId, std::string &version) +bool p3discovery2::getPeerVersion(const RsPeerId &peerId, std::string &version) { RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it; + std::map::const_iterator it; it = mLocationMap.find(peerId); if (it == mLocationMap.end()) { @@ -1223,11 +1266,11 @@ bool p3discovery2::getPeerVersion(const SSLID &peerId, std::string &version) return true; } -bool p3discovery2::setPeerVersion(const SSLID &peerId, const std::string &version) +bool p3discovery2::setPeerVersion(const RsPeerId &peerId, const std::string &version) { RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it; + std::map::iterator it; it = mLocationMap.find(peerId); if (it == mLocationMap.end()) { @@ -1239,98 +1282,74 @@ bool p3discovery2::setPeerVersion(const SSLID &peerId, const std::string &versio return true; } -void p3discovery2::recvInvite( - std::unique_ptr inviteItem ) -{ - typedef RsGossipDiscoveryFriendInviteReceivedEvent Evt_t; - if(rsEvents) - rsEvents->postEvent( - std::shared_ptr(new Evt_t(inviteItem->mInvite)) ); -} - void p3discovery2::rsEventsHandler(const RsEvent& event) { - switch(event.mType) - { - // TODO: When an SSL-only friend become online requestInvite(...) - default: break; - } + Dbg3() << __PRETTY_FUNCTION__ << " " << static_cast(event.mType) << std::endl; } /*************************************************************************************/ /* AuthGPGService */ /*************************************************************************************/ -AuthGPGOperation *p3discovery2::getGPGOperation() -{ - { - RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ +// AuthGPGOperation *p3discovery2::getGPGOperation() +// { +// { +// RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ +// +// /* process disc reply in list */ +// if (!mPendingDiscPgpCertInList.empty()) { +// RsDiscPgpCertItem *item = mPendingDiscPgpCertInList.front(); +// mPendingDiscPgpCertInList.pop_front(); +// +// return new AuthGPGOperationLoadOrSave(true, item->pgpId, item->pgpCert, item); +// } +// } +// +// return NULL; +// } - /* process disc reply in list */ - if (!mPendingDiscPgpCertInList.empty()) { - RsDiscPgpCertItem *item = mPendingDiscPgpCertInList.front(); - mPendingDiscPgpCertInList.pop_front(); +// void p3discovery2::setGPGOperation(AuthGPGOperation *operation) +// { +// AuthGPGOperationLoadOrSave *loadOrSave = dynamic_cast(operation); +// if (loadOrSave) +// { +// RsDiscPgpCertItem *item = (RsDiscPgpCertItem *) loadOrSave->m_userdata; +// if (!item) +// { +// return; +// } +// +// if (loadOrSave->m_load) +// { +// +// #ifdef P3DISC_DEBUG +// std::cerr << "p3discovery2::setGPGOperation() Loaded Cert" << std::endl; +// item->print(std::cerr, 5); +// std::cerr << std::endl; +// #endif +// // It has already been processed by PGP. +// delete item; +// } +// else +// { +// // Attaching Certificate. +// item->pgpCert = loadOrSave->m_certGpg; +// +// #ifdef P3DISC_DEBUG +// std::cerr << "p3discovery2::setGPGOperation() Sending Message:" << std::endl; +// item->print(std::cerr, 5); +// #endif +// +// // Send off message +// sendItem(item); +// } +// return; +// } +// +// /* ignore other operations */ +// } - return new AuthGPGOperationLoadOrSave(true, item->pgpId, item->pgpCert, item); - } - } - - { - RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - - /* process disc reply in list */ - if (!mPendingDiscPgpCertOutList.empty()) { - RsDiscPgpCertItem *item = mPendingDiscPgpCertOutList.front(); - mPendingDiscPgpCertOutList.pop_front(); - - return new AuthGPGOperationLoadOrSave(false, item->pgpId, "", item); - } - } - return NULL; -} - -void p3discovery2::setGPGOperation(AuthGPGOperation *operation) -{ - AuthGPGOperationLoadOrSave *loadOrSave = dynamic_cast(operation); - if (loadOrSave) - { - RsDiscPgpCertItem *item = (RsDiscPgpCertItem *) loadOrSave->m_userdata; - if (!item) - { - return; - } - - if (loadOrSave->m_load) - { - -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::setGPGOperation() Loaded Cert" << std::endl; - item->print(std::cerr, 5); - std::cerr << std::endl; -#endif - // It has already been processed by PGP. - delete item; - } - else - { - // Attaching Certificate. - item->pgpCert = loadOrSave->m_certGpg; - -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::setGPGOperation() Sending Message:" << std::endl; - item->print(std::cerr, 5); -#endif - - // Send off message - sendItem(item); - } - return; - } - - /* ignore other operations */ -} - -RsGossipDiscoveryFriendInviteReceivedEvent:: -RsGossipDiscoveryFriendInviteReceivedEvent(const std::string& invite) : +// (cyril) do we still need this?? +RsGossipDiscoveryFriendInviteReceivedEvent::RsGossipDiscoveryFriendInviteReceivedEvent(const std::string& invite) : RsEvent(RsEventType::GOSSIP_DISCOVERY_INVITE_RECEIVED), mInvite(invite) {} diff --git a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h index 6c6864fb9..95773df69 100644 --- a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h +++ b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h @@ -22,6 +22,78 @@ *******************************************************************************/ #pragma once +// +// p3GossipDiscovery is reponsible for facilitating the circulation of public keys between friend nodes. +// +// The service locally holds a cache that stores: +// * the list of friend profiles, in each of which the list of locations with their own discovery flag (which means whether they allow discovery or not) +// * the list of friend nodes, with their version number +// +// Data flow +// ========= +// +// statusChange(std::list&) // called by pqiMonitor when peers are added,removed, or recently connected +// | +// +---- sendOwnContactInfo(RsPeerId) // [On connection] sends own PgpId, discovery flag, list of own signed GxsIds +// | | +// | +---->[to friend] +// | +// +---- locally add/remove cache info // [New/Removed friend] updates the list of friends, along with their own discovery flag +// +// tick() +// | +// +------ handleIncoming() +// | +// +-- recvOwnContactInfo(RsPeerId) // update location, IP addresses of a peer. +// | | +// | +------(if the peer has short_invite flag) +// | | | +// | | +---------requestPGPKey()->[to friend] // requests the full PGP public key, so as to be +// | | // able to validate connections. +// | | +// | +------(if disc != RS_VS_DISC_OFF) +// | | +// | +---------sendPgpList()->[to friend] // sends own list of friend profiles for which at least one location +// | // accepts discovery +// +-- processContactInfo(item->PeerId(), contact); +// | | +// | +------ addFriend() // called on nodes signed by the PGP key mentionned in the disc info +// | | +// | +------ update local discovery info +// | +// +-- recvIdentityList(Gxs Identity List) +// | | +// | +------ mGixs->requestKey(*it,peers,use_info) ; // requestKey() takes care of requesting the GxsIds that are missing +// | +// +-- recvPGPCertificate(item->PeerId(), pgpkey); +// | | +// | +------(if peer has short invite flag) +// | | +// | +--------- add key to keyring, accept connections and notify peerMgr +// | +// +-- processPGPList(pgplist->PeerId(), pgplist); // list of PGP keys of a friend, received from himself +// | | +// | +------ requestPgpCertificate() // request missing keys only +// | | +// | +------ updatePeers_locked(fromId) +// | | +// | +--------- sendContactInfo_locked(from,to) // sends IP information about mutual friends to the origin of the info +// | | +// | +--------- sendContactInfo_locked(to,from) // sends IP information origin to online mutual friends +// | +// +-- recvPGPCertificateRequest(pgplist->PeerId(), pgplist); +// | +// +------ sendPGPCertificate() // only sends the ones we are friend with, and only send own cert +// // if discovery is off +// +// Notes: +// * Tor nodes never send their own IP, and normal nodes never send their IP to Tor nodes either. +// A Tor node may accidentally know the IP of a normal node when it adds its certificate. However, the IP is dropped and not saved in this case. +// Generally speaking, no IP information should leave or transit through a Tor node. +// +// * the decision to call recvOwnContactInfo() or processContactInfo() depends on whether the item's peer id is the one the info is about. This is +// a bit unsafe. We should probably have to different items here especially if the information is not exactly the same. +// #include #include "retroshare/rsgossipdiscovery.h" @@ -36,12 +108,9 @@ class p3ServiceControl; -using PGPID RS_DEPRECATED_FOR(RsPgpId) = RsPgpId; -using SSLID RS_DEPRECATED_FOR(RsPeerId) = RsPeerId; - struct DiscSslInfo { - DiscSslInfo() : mDiscStatus(0) {} + DiscSslInfo() : mDiscStatus(RS_VS_DISC_OFF) {} // default is to not allow discovery, until the peer tells about it uint16_t mDiscStatus; }; @@ -56,16 +125,16 @@ struct DiscPgpInfo { DiscPgpInfo() {} - void mergeFriendList(const std::set &friends); + void mergeFriendList(const std::set &friends); - std::set mFriendSet; - std::map mSslIds; + std::set mFriendSet; + std::map mSslIds; }; class p3discovery2 : - public RsGossipDiscovery, public p3Service, public pqiServiceMonitor, - public AuthGPGService + public RsGossipDiscovery, public p3Service, public pqiServiceMonitor + //public AuthGPGService { public: @@ -87,61 +156,45 @@ virtual RsServiceInfo getServiceInfo(); bool getPeerVersion(const RsPeerId &id, std::string &version); bool getWaitingDiscCount(size_t &sendCount, size_t &recvCount); - /// @see RsGossipDiscovery - bool sendInvite( - const RsPeerId& inviteId, const RsPeerId& toSslId, - std::string& errorMsg = RS_DEFAULT_STORAGE_PARAM(std::string) - ) override; - - /// @see RsGossipDiscovery - bool requestInvite( - const RsPeerId& inviteId, const RsPeerId& toSslId, - std::string& errorMsg = RS_DEFAULT_STORAGE_PARAM(std::string) - ) override; - - /************* from AuthGPService ****************/ -virtual AuthGPGOperation *getGPGOperation(); -virtual void setGPGOperation(AuthGPGOperation *operation); + /************* from AuthGPService ****************/ + // virtual AuthGPGOperation *getGPGOperation(); + // virtual void setGPGOperation(AuthGPGOperation *operation); private: - PGPID getPGPId(const SSLID &id); + RsPgpId getPGPId(const RsPeerId &id); int handleIncoming(); void updatePgpFriendList(); - void addFriend(const SSLID &sslId); - void removeFriend(const SSLID &sslId); + void addFriend(const RsPeerId &sslId); + void removeFriend(const RsPeerId &sslId); void updatePeerAddresses(const RsDiscContactItem *item); void updatePeerAddressList(const RsDiscContactItem *item); - void sendOwnContactInfo(const SSLID &sslid); - void recvOwnContactInfo(const SSLID &fromId, const RsDiscContactItem *item); + void sendOwnContactInfo(const RsPeerId &sslid); + void recvOwnContactInfo(const RsPeerId &fromId, const RsDiscContactItem *item); - void sendPGPList(const SSLID &toId); - void processPGPList(const SSLID &fromId, const RsDiscPgpListItem *item); + void sendPGPList(const RsPeerId &toId); + void processPGPList(const RsPeerId &fromId, const RsDiscPgpListItem *item); - void processContactInfo(const SSLID &fromId, const RsDiscContactItem *info); + void processContactInfo(const RsPeerId &fromId, const RsDiscContactItem *info); - void requestPGPCertificate(const PGPID &aboutId, const SSLID &toId); + // send/recv information - void recvPGPCertificateRequest( - const RsPeerId& fromId, const RsDiscPgpListItem* item ); - - void sendPGPCertificate(const PGPID &aboutId, const SSLID &toId); - void recvPGPCertificate(const SSLID &fromId, RsDiscPgpCertItem *item); + void requestPGPCertificate(const RsPgpId &aboutId, const RsPeerId &toId); + void recvPGPCertificateRequest(const RsPeerId& fromId, const RsDiscPgpListItem* item ); + void sendPGPCertificate(const RsPgpId &aboutId, const RsPeerId &toId); + void recvPGPCertificate(const RsPeerId &fromId, RsDiscPgpKeyItem *item); void recvIdentityList(const RsPeerId& pid,const std::list& ids); - bool setPeerVersion(const SSLID &peerId, const std::string &version); - - void recvInvite(std::unique_ptr inviteItem); + bool setPeerVersion(const RsPeerId &peerId, const std::string &version); void rsEventsHandler(const RsEvent& event); RsEventsHandlerId_t mRsEventsHandle; - p3PeerMgr *mPeerMgr; p3LinkMgr *mLinkMgr; p3NetMgr *mNetMgr; @@ -151,16 +204,18 @@ private: /* data */ RsMutex mDiscMtx; - void updatePeers_locked(const SSLID &aboutId); - void sendContactInfo_locked(const PGPID &aboutId, const SSLID &toId); + void updatePeers_locked(const RsPeerId &aboutId); + void sendContactInfo_locked(const RsPgpId &aboutId, const RsPeerId &toId); rstime_t mLastPgpUpdate; - std::map mFriendList; - std::map mLocationMap; + std::map mFriendList; + std::map mLocationMap; - std::list mPendingDiscPgpCertInList; - std::list mPendingDiscPgpCertOutList; +// This was used to async the receiving of PGP keys, mainly because PGPHandler cross-checks all signatures, so receiving these keys in large loads can be costly +// Because discovery is not running in the main thread, there's no reason to re-async this into another process (e.g. AuthGPG) +// +// std::list mPendingDiscPgpCertInList; protected: RS_SET_CONTEXT_DEBUG_LEVEL(1) diff --git a/libretroshare/src/pgp/pgphandler.cc b/libretroshare/src/pgp/pgphandler.cc index 87bb462e0..48915aa85 100644 --- a/libretroshare/src/pgp/pgphandler.cc +++ b/libretroshare/src/pgp/pgphandler.cc @@ -1037,7 +1037,17 @@ void PGPHandler::addNewKeyToOPSKeyring(ops_keyring_t *kr,const ops_keydata_t& ke kr->nkeys++ ; } +bool PGPHandler::LoadCertificateFromBinaryData(const unsigned char *data,uint32_t data_len,RsPgpId& id,std::string& error_string) +{ + return LoadCertificate(data,data_len,ops_false,id,error_string); +} + bool PGPHandler::LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& id,std::string& error_string) +{ + return LoadCertificate((unsigned char*)(pgp_cert.c_str()),pgp_cert.length(),ops_true,id,error_string); +} + +bool PGPHandler::LoadCertificate(const unsigned char *data,uint32_t data_len,bool armoured,RsPgpId& id,std::string& error_string) { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. #ifdef DEBUG_PGPHANDLER @@ -1046,9 +1056,9 @@ bool PGPHandler::LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& ops_keyring_t *tmp_keyring = allocateOPSKeyring(); ops_memory_t *mem = ops_memory_new() ; - ops_memory_add(mem,(unsigned char *)pgp_cert.c_str(),pgp_cert.length()) ; + ops_memory_add(mem,data,data_len) ; - if(!ops_keyring_read_from_mem(tmp_keyring,ops_true,mem)) + if(!ops_keyring_read_from_mem(tmp_keyring,armoured,mem)) { ops_keyring_free(tmp_keyring) ; free(tmp_keyring) ; @@ -1571,6 +1581,11 @@ void PGPHandler::locked_updateOwnSignatureFlag(PGPCertificateInfo& cert,const Rs cert._flags &= ~PGPCertificateInfo::PGP_CERTIFICATE_FLAG_HAS_SIGNED_ME ; } +RsPgpId PGPHandler::pgpIdFromFingerprint(const PGPFingerprintType& f) +{ + return RsPgpId(f.toByteArray() + _RsIdSize::PGP_FINGERPRINT - _RsIdSize::PGP_ID); +} + bool PGPHandler::getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. diff --git a/libretroshare/src/pgp/pgphandler.h b/libretroshare/src/pgp/pgphandler.h index e0b563a64..fee240e6a 100644 --- a/libretroshare/src/pgp/pgphandler.h +++ b/libretroshare/src/pgp/pgphandler.h @@ -104,6 +104,7 @@ class PGPHandler bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString) ; bool LoadCertificateFromString(const std::string& pem, RsPgpId& gpg_id, std::string& error_string); + bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string); std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const ; bool exportPublicKey(const RsPgpId& id,unsigned char *& mem,size_t& mem_size,bool armoured,bool include_signatures) const ; @@ -153,6 +154,7 @@ class PGPHandler static void setPassphraseCallback(PassphraseCallback cb) ; static PassphraseCallback passphraseCallback() { return _passphrase_callback ; } + static RsPgpId pgpIdFromFingerprint(const PGPFingerprintType& f) ; // Gets info about the key. Who are the signers, what's the owner's name, etc. // @@ -171,6 +173,7 @@ class PGPHandler 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 diff --git a/libretroshare/src/pgp/rscertificate.cc b/libretroshare/src/pgp/rscertificate.cc index 11ada52a6..f3007bb01 100644 --- a/libretroshare/src/pgp/rscertificate.cc +++ b/libretroshare/src/pgp/rscertificate.cc @@ -552,14 +552,22 @@ unsigned short RsCertificate::loc_port_us() const return (int)ipv4_internal_ip_and_port[4]*256 + (int)ipv4_internal_ip_and_port[5] ; } -bool RsCertificate::cleanCertificate( - const std::string& input, std::string& output, Format& format, - int& error_code, bool check_content ) +bool RsCertificate::cleanCertificate( const std::string& input, std::string& output, Format& format, uint32_t& error_code, bool check_content ) { - if(cleanCertificate(input,output,error_code)) + if(cleanRadix64(input,output,error_code)) { + RsPeerDetails details; + + if(rsPeers->parseShortInvite(output,details,error_code)) + { + format = RS_CERTIFICATE_SHORT_RADIX; + return true; + } + format = RS_CERTIFICATE_RADIX; + if(!check_content) return true; + uint32_t errCode; auto crt = RsCertificate::fromString(input, errCode); error_code = static_cast(errCode); @@ -576,7 +584,7 @@ std::string RsCertificate::armouredPGPKey() const // Yeah, this is simple, and that is what's good about the radix format. Can't be broken ;-) // -bool RsCertificate::cleanCertificate(const std::string& instr,std::string& str,int& error_code) +bool RsCertificate::cleanRadix64(const std::string& instr,std::string& str,uint32_t& error_code) { error_code = RS_PEER_CERT_CLEANING_CODE_NO_ERROR ; diff --git a/libretroshare/src/pgp/rscertificate.h b/libretroshare/src/pgp/rscertificate.h index 7f80a30d1..1ba3db633 100644 --- a/libretroshare/src/pgp/rscertificate.h +++ b/libretroshare/src/pgp/rscertificate.h @@ -36,7 +36,7 @@ struct RsPeerDetails; class RsCertificate { public: - typedef enum { RS_CERTIFICATE_OLD_FORMAT, RS_CERTIFICATE_RADIX } Format; + typedef enum { RS_CERTIFICATE_OLD_FORMAT, RS_CERTIFICATE_RADIX, RS_CERTIFICATE_SHORT_RADIX } Format; /** * @brief Create certificate object from certificate string @@ -84,7 +84,7 @@ public: static bool cleanCertificate( const std::string& input, std::string& output, - RsCertificate::Format& format, int& error_code, bool check_content); + RsCertificate::Format& format, uint32_t& error_code, bool check_content); const std::set& locators() const { return mLocators; } @@ -99,8 +99,7 @@ public: private: // new radix format - static bool cleanCertificate( const std::string& input, - std::string& output, int&); + static bool cleanRadix64(const std::string& input, std::string& output, uint32_t &); static void scan_ip( const std::string& ip_string, unsigned short port, unsigned char *destination_memory ); diff --git a/libretroshare/src/pqi/authgpg.cc b/libretroshare/src/pqi/authgpg.cc index bf485a2ad..076cb66b5 100644 --- a/libretroshare/src/pqi/authgpg.cc +++ b/libretroshare/src/pqi/authgpg.cc @@ -534,6 +534,19 @@ bool AuthGPG::getGPGSignedList(std::list &ids) return PGPHandler::SaveCertificateToString(id,include_signatures) ; } +/* import to GnuPG and other Certificates */ +bool AuthGPG::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string) +{ + RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/ + + if(PGPHandler::LoadCertificateFromBinaryData(data,data_len,gpg_id,error_string)) + { + updateOwnSignatureFlag(gpg_id,mOwnGpgId) ; + return true ; + } + + return false ; +} /* import to GnuPG and other Certificates */ bool AuthGPG::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,std::string& error_string) diff --git a/libretroshare/src/pqi/authgpg.h b/libretroshare/src/pqi/authgpg.h index 11b7203dd..871830445 100644 --- a/libretroshare/src/pqi/authgpg.h +++ b/libretroshare/src/pqi/authgpg.h @@ -172,6 +172,7 @@ public: * ****/ virtual 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); virtual std::string SaveCertificateToString(const RsPgpId &id,bool include_signatures) ; // Cached certificates. diff --git a/libretroshare/src/pqi/authssl.cc b/libretroshare/src/pqi/authssl.cc index a5f56800f..0b2fa91ec 100644 --- a/libretroshare/src/pqi/authssl.cc +++ b/libretroshare/src/pqi/authssl.cc @@ -534,7 +534,7 @@ bool AuthSSLimpl::validateOwnCertificate(X509 *x509, EVP_PKEY *pkey) uint32_t diagnostic ; /* standard authentication */ - if (!AuthX509WithGPG(x509,diagnostic)) + if (!AuthX509WithGPG(x509,true,diagnostic)) { std::cerr << "Validate Own certificate ERROR: diagnostic = " << diagnostic << std::endl; return false; @@ -970,7 +970,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/) } -bool AuthSSLimpl::AuthX509WithGPG(X509 *x509, uint32_t& diagnostic) +bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,bool verbose, uint32_t& diagnostic) { RsPgpId issuer = RsX509Cert::getCertIssuer(*x509); RsPeerDetails pd; @@ -1127,11 +1127,12 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509, uint32_t& diagnostic) goto err; } - RsInfo() << __PRETTY_FUNCTION__ << " Verified: " << sigtypestring - << " signature of certificate sslId: " - << RsX509Cert::getCertSslId(*x509) - << ", Version " << std::hex << certificate_version << std::dec - << " using PGP key " << pd.fpr << " " << pd.name << std::endl; + if(verbose) + RsInfo() << " Verified: " << sigtypestring + << " signature of certificate sslId: " + << RsX509Cert::getCertSslId(*x509) + << ", Version " << std::hex << certificate_version << std::dec + << " using PGP key " << pd.fpr << " " << pd.name << std::endl; } EVP_MD_CTX_destroy(ctx); @@ -1196,8 +1197,17 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) RsPeerId sslId = RsX509Cert::getCertSslId(*x509Cert); std::string sslCn = RsX509Cert::getCertIssuerString(*x509Cert); + RsPgpId pgpId(sslCn); + if(sslCn.length() == RsPgpFingerprint::SIZE_IN_BYTES*2) + { + RsPgpFingerprint pgpFpr(sslCn); // we also accept fingerprint format, so that in the future we can switch to fingerprints without backward compatibility issues + + if(!pgpFpr.isNull()) + pgpId = PGPHandler::pgpIdFromFingerprint(pgpFpr); // in the future, we drop PGP ids and keep the fingerprint all along + } + if(sslId.isNull()) { std::string errMsg = "x509Cert has invalid sslId!"; @@ -1233,8 +1243,38 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) return verificationFailed; } + bool isSslOnlyFriend = false; + + // For SSL only friends (ones added through short invites) we check that the fingerprint + // in the key (det.gpg_id) matches the one of the handshake. + { + RsPeerDetails det; + + if(rsPeers->getPeerDetails(sslId,det)) + isSslOnlyFriend = det.skip_pgp_signature_validation; + + if(det.skip_pgp_signature_validation && det.gpg_id != pgpId)// in the future, we should compare fingerprints instead + { + std::string errorMsg = "Peer " + sslId.toStdString() + " trying to connect with issuer ID " + pgpId.toStdString() + + " whereas key ID " + det.gpg_id.toStdString() + " was expected! Refusing connection." ; + + RsErr() << __PRETTY_FUNCTION__ << errorMsg << std::endl; + + if(rsEvents) + { + ev->mSslId = sslId; + ev->mSslCn = sslCn; + ev->mPgpId = pgpId; + ev->mErrorMsg = errorMsg; + rsEvents->postEvent(std::move(ev)); + } + + return verificationFailed; + } + } + uint32_t auth_diagnostic; - if(!AuthX509WithGPG(x509Cert, auth_diagnostic)) + if(!isSslOnlyFriend && !AuthX509WithGPG(x509Cert,true, auth_diagnostic)) { std::string errMsg = "Certificate was rejected because PGP " "signature verification failed with diagnostic: " @@ -1257,8 +1297,7 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) return verificationFailed; } - if ( pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && - !AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) ) + if ( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && !AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) ) { std::string errMsg = "Connection attempt signed by PGP key id: " + pgpId.toStdString() + " not accepted because it is not" @@ -1281,7 +1320,9 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) setCurrentConnectionAttemptInfo(pgpId, sslId, sslCn); LocalStoreCert(x509Cert); - Dbg1() << __PRETTY_FUNCTION__ << " authentication successfull!" << std::endl; + RsInfo() << __PRETTY_FUNCTION__ << " authentication successfull for " + << "sslId: " << sslId << " isSslOnlyFriend: " << isSslOnlyFriend + << std::endl; if(rsEvents) { @@ -1318,7 +1359,7 @@ bool AuthSSLimpl::parseX509DetailsFromFile( } uint32_t diagnostic = 0; - if(!AuthX509WithGPG(x509, diagnostic)) + if(!AuthX509WithGPG(x509,false, diagnostic)) { RsErr() << __PRETTY_FUNCTION__ << " AuthX509WithGPG failed with " << "diagnostic: " << diagnostic << std::endl; @@ -1732,7 +1773,7 @@ bool AuthSSLimpl::loadList(std::list& load) X509 *peer = loadX509FromPEM(kit->value); /* authenticate it */ uint32_t diagnos ; - if (AuthX509WithGPG(peer,diagnos)) + if (AuthX509WithGPG(peer,false,diagnos)) { LocalStoreCert(peer); } diff --git a/libretroshare/src/pqi/authssl.h b/libretroshare/src/pqi/authssl.h index 618d9f7b6..d7973e869 100644 --- a/libretroshare/src/pqi/authssl.h +++ b/libretroshare/src/pqi/authssl.h @@ -140,10 +140,12 @@ public: * @param[in] x509 pointer ti the X509 certificate to check * @param[out] diagnostic one of RS_SSL_HANDSHAKE_DIAGNOSTIC_* diagnostic * codes + * @param[in] verbose if true, prints the authentication result to screen. * @return true if correctly signed, false otherwise */ virtual bool AuthX509WithGPG( X509* x509, + bool verbose, uint32_t& diagnostic = RS_DEFAULT_STORAGE_PARAM(uint32_t) ) = 0; @@ -233,7 +235,7 @@ public: virtual X509* SignX509ReqWithGPG(X509_REQ *req, long days) override; /// @see AuthSSL - bool AuthX509WithGPG(X509 *x509, uint32_t& auth_diagnostic) override; + bool AuthX509WithGPG(X509 *x509, bool verbose, uint32_t& auth_diagnostic) override; /// @see AuthSSL int VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx) override; diff --git a/libretroshare/src/pqi/p3peermgr.cc b/libretroshare/src/pqi/p3peermgr.cc index f0d340f39..1adf191d1 100644 --- a/libretroshare/src/pqi/p3peermgr.cc +++ b/libretroshare/src/pqi/p3peermgr.cc @@ -89,7 +89,7 @@ static const std::string kConfigKeyProxyServerPortI2P = "PROXY_SERVER_PORT_I2P"; void printConnectState(std::ostream &out, peerState &peer); peerState::peerState() - :netMode(RS_NET_MODE_UNKNOWN), vs_disc(RS_VS_DISC_FULL), vs_dht(RS_VS_DHT_FULL), lastcontact(0), + :skip_pgp_signature_validation(false),netMode(RS_NET_MODE_UNKNOWN), vs_disc(RS_VS_DISC_FULL), vs_dht(RS_VS_DHT_FULL), lastcontact(0), hiddenNode(false), hiddenPort(0), hiddenType(RS_HIDDEN_TYPE_NONE) { sockaddr_storage_clear(localaddr); @@ -338,17 +338,31 @@ bool p3PeerMgrIMPL::isFriend(const RsPeerId& id) #ifdef PEER_DEBUG_COMMON std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") called" << std::endl; #endif - RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ + RS_STACK_MUTEX(mPeerMtx); bool ret = (mFriendList.end() != mFriendList.find(id)); #ifdef PEER_DEBUG_COMMON std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") returning : " << ret << std::endl; #endif return ret; } +bool p3PeerMgrIMPL::isSslOnlyFriend(const RsPeerId& id) +{ +#ifdef PEER_DEBUG_COMMON + std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") called" << std::endl; +#endif + RS_STACK_MUTEX(mPeerMtx); + auto it = mFriendList.find(id); + bool ret = it != mFriendList.end() && it->second.skip_pgp_signature_validation ; + +#ifdef PEER_DEBUG_COMMON + std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") returning : " << ret << std::endl; +#endif + return ret; +} bool p3PeerMgrIMPL::getPeerName(const RsPeerId &ssl_id, std::string &name) { - RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ + RS_STACK_MUTEX(mPeerMtx); /* check for existing */ std::map::iterator it; @@ -826,19 +840,6 @@ bool p3PeerMgrIMPL::getFriendNetStatus(const RsPeerId &id, peerState &state) } -bool p3PeerMgrIMPL::getOthersNetStatus(const RsPeerId &id, peerState &state) -{ - RS_STACK_MUTEX(mPeerMtx); - - /* check for existing */ - std::map::iterator it; - it = mOthersList.find(id); - if (it == mOthersList.end()) return false; - - state = it->second; - return true; -} - int p3PeerMgrIMPL::getConnectAddresses( const RsPeerId &id, sockaddr_storage &lAddr, sockaddr_storage &eAddr, pqiIpAddrSet &histAddrs, std::string &dyndns ) @@ -872,8 +873,7 @@ bool p3PeerMgrIMPL::haveOnceConnected() RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check for existing */ - std::map::iterator it; - for(it = mFriendList.begin(); it != mFriendList.end(); ++it) + for(auto it = mFriendList.begin(); it != mFriendList.end(); ++it) { if (it->second.lastcontact > 0) { @@ -896,6 +896,28 @@ bool p3PeerMgrIMPL::haveOnceConnected() } +bool p3PeerMgrIMPL::notifyPgpKeyReceived(const RsPgpId& pgp_id) +{ + RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ + + bool changed = false; + + for(auto it(mFriendList.begin());it!=mFriendList.end();++it) + { + if(it->second.gpg_id == pgp_id) + { + std::cerr << "(WW) notification that full key " << pgp_id << " is available. Reseting short invite flag for peer " << it->first << std::endl; + it->second.skip_pgp_signature_validation = false; + + changed = true; + } + } + + if(changed) + IndicateConfigChanged(); + + return true; +} /*******************************************************************/ /*******************************************************************/ @@ -915,9 +937,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg if (id == AuthSSL::getAuthSSL()->OwnId()) { -#ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::addFriend() cannot add own id as a friend." << std::endl; -#endif + RsErr() << "p3PeerMgrIMPL::addFriend() cannot add own id as a friend. That's a bug!" << std::endl; /* (1) already exists */ return false; } @@ -932,15 +952,27 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg #endif std::map::iterator it; - if (mFriendList.end() != mFriendList.find(id)) + if (mFriendList.end() != (it=mFriendList.find(id))) { -#ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::addFriend() Already Exists" << std::endl; -#endif - /* (1) already exists */ - return true; + // The friend may already be here, including with a short invite (meaning the PGP key is unknown). + + if(it->second.gpg_id != input_gpg_id)// already exists as a friend with a different PGP id!! + { + RsErr() << "Trying to add SSL id (" << id << ") that is already a friend with existing PGP key (" << it->second.gpg_id << ") but using a different PGP key (" << input_gpg_id << "). This is a bug!" << std::endl; + return false; + } + else + return true; /* (1) already exists */ } + // check that the PGP key is known + + if(!AuthGPG::getAuthGPG()->isGPGId(gpg_id)) + { + RsErr() << "Trying to add SSL id (" << id << ") to be validated with unknown PGP key (" << gpg_id << ". This is a bug!" << std::endl; + return false; + } + //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()) @@ -952,61 +984,70 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg return false; } + // after that, we know that we have the key, because AuthGPG wouldn't answer yes for a key it doesn't know. /* check if it is in others */ - if (mOthersList.end() != (it = mOthersList.find(id))) - { - /* (2) in mOthersList -> move over */ +// if (mOthersList.end() != (it = mOthersList.find(id))) +// { +// /* (2) in mOthersList -> move over */ +//#ifdef PEER_DEBUG +// std::cerr << "p3PeerMgrIMPL::addFriend() Move from Others" << std::endl; +//#endif +// if(!it->second.gpg_id.isNull() && it->second.gpg_id != input_gpg_id)// already exists as a friend with a different PGP id!! +// RsErr() << "Trying to add SSL id (" << id << ") that is already known (but not friend) with existing PGP key (" << it->second.gpg_id +// << ") but using a different PGP key (" << input_gpg_id << "). This looks like a bug! The friend will be added again with the new PGP key ID." << std::endl; +// +// mFriendList[id] = it->second; +// mOthersList.erase(it); +// +// it = mFriendList.find(id); +// +// /* setup connectivity parameters */ +// it->second.vs_disc = vs_disc; +// it->second.vs_dht = vs_dht; +// +// it->second.netMode = netMode; +// it->second.lastcontact = lastContact; +// +// it->second.gpg_id = input_gpg_id; +// it->second.skip_pgp_signature_validation = false; +// +// mStatusChanged = true; +// +// notifyLinkMgr = true; +// +// IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ +// } +// else + #ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::addFriend() Move from Others" << std::endl; + std::cerr << "p3PeerMgrIMPL::addFriend() Creating New Entry" << std::endl; #endif - mFriendList[id] = it->second; - mOthersList.erase(it); + /* create a new entry */ + peerState pstate; - it = mFriendList.find(id); + pstate.id = id; + pstate.gpg_id = gpg_id; + pstate.name = AuthGPG::getAuthGPG()->getGPGName(gpg_id); - /* setup connectivity parameters */ - it->second.vs_disc = vs_disc; - it->second.vs_dht = vs_dht; + pstate.vs_disc = vs_disc; + pstate.vs_dht = vs_dht; + pstate.netMode = netMode; + pstate.lastcontact = lastContact; - it->second.netMode = netMode; - it->second.lastcontact = lastContact; + pstate.gpg_id = input_gpg_id; + pstate.skip_pgp_signature_validation = false; - mStatusChanged = true; + /* addr & timestamps -> auto cleared */ - notifyLinkMgr = true; + mFriendList[id] = pstate; - IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ - } - else - { -#ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::addFriend() Creating New Entry" << std::endl; -#endif + mStatusChanged = true; - /* create a new entry */ - peerState pstate; + notifyLinkMgr = true; - pstate.id = id; - pstate.gpg_id = gpg_id; - pstate.name = AuthGPG::getAuthGPG()->getGPGName(gpg_id); - - pstate.vs_disc = vs_disc; - pstate.vs_dht = vs_dht; - pstate.netMode = netMode; - pstate.lastcontact = lastContact; - - /* addr & timestamps -> auto cleared */ - - mFriendList[id] = pstate; - - mStatusChanged = true; - - notifyLinkMgr = true; - - IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ - } + IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ } if (notifyLinkMgr) @@ -1029,6 +1070,93 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg return true; } + +bool p3PeerMgrIMPL::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_id,const RsPeerDetails& dt ) +{ + if(sslId.isNull() || sslId == getOwnId()) + { + RsErr() <<"Attempt to add yourself or a null ID as SSL-only friend (id=" << sslId << ")" << std::endl; + return false; + } + + peerState pstate; + +// { +// RS_STACK_MUTEX(mPeerMtx); +// +// /* If in mOthersList -> move over */ +// auto it = mOthersList.find(sslId); +// if (it != mOthersList.end()) +// { +// pstate = it->second; +// mOthersList.erase(it); +// } +// +// +// } // RS_STACK_MUTEX(mPeerMtx); + + if(!pstate.gpg_id.isNull() && AuthGPG::getAuthGPG()->isGPGAccepted(pstate.gpg_id)) + { + RsErr() << "Trying to add as SSL-only friend a peer which PGP id is already a friend. This means the code is inconsistent. Not doing this!" << std::endl; + return false; + } + + if(pgp_id.isNull()) + { + RsErr() << "Null pgp id for friend added with skip_pgp_signature_validaiton flag. This is not allowed." << std::endl; + return false; + } + + pstate.gpg_id = pgp_id; + pstate.id = sslId; + + if(!dt.name.empty()) pstate.name = dt.name; + if(!dt.dyndns.empty()) pstate.dyndns = dt.dyndns; + pstate.hiddenNode = dt.isHiddenNode; + if(!dt.hiddenNodeAddress.empty()) + pstate.hiddenDomain = dt.hiddenNodeAddress; + if(dt.hiddenNodePort) pstate.hiddenPort = dt.hiddenNodePort; + if(dt.hiddenType) pstate.hiddenType = dt.hiddenType; + if(!dt.location.empty()) pstate.location = dt.location; + + pstate.skip_pgp_signature_validation = true; + + { RS_STACK_MUTEX(mPeerMtx); + + mFriendList[sslId] = pstate; + mStatusChanged = true; + + } // RS_STACK_MUTEX(mPeerMtx); + + IndicateConfigChanged(); + mLinkMgr->addFriend(sslId, dt.vs_dht != RS_VS_DHT_OFF); + + // To update IP addresses is much more confortable to use locators + if(!dt.isHiddenNode) + { + for(const std::string& locator : dt.ipAddressList) + addPeerLocator(sslId, locator); + + if(dt.extPort && !dt.extAddr.empty()) + { + RsUrl locator; + locator.setScheme("ipv4").setHost(dt.extAddr) + .setPort(dt.extPort); + addPeerLocator(sslId, locator); + } + + if(dt.localPort && !dt.localAddr.empty()) + { + RsUrl locator; + locator.setScheme("ipv4").setHost(dt.localAddr) + .setPort(dt.localPort); + addPeerLocator(sslId, locator); + } + } + + return true; +} + bool p3PeerMgrIMPL::removeFriend(const RsPgpId &id) { #ifdef PEER_DEBUG @@ -1059,7 +1187,7 @@ bool p3PeerMgrIMPL::removeFriend(const RsPgpId &id) sslid_toRemove.push_back(it->second.id); - mOthersList[it->second.id] = peer; + //mOthersList[it->second.id] = peer; mStatusChanged = true; //success = true; @@ -1134,7 +1262,7 @@ bool p3PeerMgrIMPL::removeFriend(const RsPeerId &id, bool removePgpId) if(removePgpId) pgpid_toRemove.push_back(it->second.gpg_id); - mOthersList[id] = peer; + //mOthersList[id] = peer; mStatusChanged = true; //success = true; @@ -1194,14 +1322,14 @@ void p3PeerMgrIMPL::printPeerLists(std::ostream &out) out << std::endl; } - out << "p3PeerMgrIMPL::printPeerLists() Others List"; - out << std::endl; - for(it = mOthersList.begin(); it != mOthersList.end(); ++it) - { - out << "\t SSL ID: " << it->second.id; - out << "\t GPG ID: " << it->second.gpg_id; - out << std::endl; - } +// out << "p3PeerMgrIMPL::printPeerLists() Others List"; +// out << std::endl; +// for(it = mOthersList.begin(); it != mOthersList.end(); ++it) +// { +// out << "\t SSL ID: " << it->second.id; +// out << "\t GPG ID: " << it->second.gpg_id; +// out << std::endl; +// } } return; @@ -1383,16 +1511,10 @@ bool p3PeerMgrIMPL::addPeerLocator(const RsPeerId &sslId, const RsUrl& locator) auto it = mFriendList.find(sslId); if (it == mFriendList.end()) { - it = mOthersList.find(sslId); - if (it == mOthersList.end()) - { #ifdef PEER_DEBUG - std::cerr << __PRETTY_FUNCTION__ << "cannot add address " - << "info, peer id: " << sslId << " not found in list" - << std::endl; + std::cerr << __PRETTY_FUNCTION__ << "cannot add address " << "info, peer id: " << sslId << " not found in list" << std::endl; #endif return false; - } } changed = it->second.ipAddrs.updateLocalAddrs(ip); @@ -1440,15 +1562,10 @@ bool p3PeerMgrIMPL::setLocalAddress( const RsPeerId &id, std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { #ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres " - << "info : peer id not found in friend list id: " - << id << std::endl; + std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres " << "info : peer id not found in friend list id: " << id << std::endl; #endif return false; - } } /* "it" points to peer */ @@ -1506,15 +1623,10 @@ bool p3PeerMgrIMPL::setExtAddress( const RsPeerId &id, std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { #ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres " - << "info : peer id not found in friend list id: " << id - << std::endl; + std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres " << "info : peer id not found in friend list id: " << id << std::endl; #endif return false; - } } /* "it" points to peer */ @@ -1561,13 +1673,10 @@ bool p3PeerMgrIMPL::setDynDNS(const RsPeerId &id, const std::string &dyndns) std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { #ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::setDynDNS() cannot add dyn dns info : peer id not found in friend list id: " << id << std::endl; + std::cerr << "p3PeerMgrIMPL::setDynDNS() cannot add dyn dns info : peer id not found in friend list id: " << id << std::endl; #endif - return false; - } + return false; } /* "it" points to peer */ @@ -1602,7 +1711,7 @@ bool p3PeerMgrIMPL::addCandidateForOwnExternalAddress(const RsPeerId &from, cons sockaddr_storage_clear(addr_filtered) ; sockaddr_storage_copyip(addr_filtered,addr) ; -#ifdef PEER_DEBUG +#ifndef PEER_DEBUG std::cerr << "Own external address is " << sockaddr_storage_iptostring(addr_filtered) << ", as reported by friend " << from << std::endl; #endif @@ -1705,7 +1814,7 @@ bool p3PeerMgrIMPL::getExtAddressReportedByFriends(sockaddr_storage &addr, uint8 { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ - uint32_t count ; + uint32_t count =0; locked_computeCurrentBestOwnExtAddressCandidate(addr,count) ; @@ -1776,13 +1885,10 @@ bool p3PeerMgrIMPL::updateAddressList(const RsPeerId& id, const pqiIpAddrSet std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { #ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres info : peer id not found in friend list. id: " << id << std::endl; + std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres info : peer id not found in friend list. id: " << id << std::endl; #endif - return false; - } + return false; } /* "it" points to peer */ @@ -1821,11 +1927,8 @@ bool p3PeerMgrIMPL::updateCurrentAddress(const RsPeerId& id, const pqiIpAddre std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { std::cerr << "p3PeerMgrIMPL::updateCurrentAddress() ERROR peer id not found: " << id << std::endl; return false; - } } if (sockaddr_storage_isPrivateNet(addr.mAddr)) @@ -1868,11 +1971,8 @@ bool p3PeerMgrIMPL::updateLastContact(const RsPeerId& id) std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { std::cerr << "p3PeerMgrIMPL::updateLastContact() ERROR peer id not found: " << id << std::endl; return false; - } } it->second.lastcontact = time(NULL); @@ -1894,10 +1994,7 @@ bool p3PeerMgrIMPL::setNetworkMode(const RsPeerId &id, uint32_t netMode) std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { return false; - } } bool changed = false; @@ -1964,10 +2061,7 @@ bool p3PeerMgrIMPL::setVisState(const RsPeerId &id, uint16_t vs_disc, uint16_ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { return false; - } } else { @@ -2344,7 +2438,20 @@ bool p3PeerMgrIMPL::loadList(std::list& load) #endif /* ************* */ // permission flags is used as a mask for the existing perms, so we set it to 0xffff - addFriend(peer_id, peer_pgp_id, pitem->netMode, pitem->vs_disc, pitem->vs_dht, pitem->lastContact, RS_NODE_PERM_ALL); + + RsPeerDetails det ; + if(!rsPeers->getGPGDetails(peer_pgp_id,det)) + { + // would be better to add flags into RsPeerNetItem so that we already have this information. However, it's possible that the PGP key + // has been added in the meantime, so the peer would be loaded with the right pGP key attached. + + RsInfo() << __PRETTY_FUNCTION__ << " loading SSL-only " << "friend: " << peer_id << " " << pitem->location << std::endl; + addSslOnlyFriend(peer_id,peer_pgp_id); + } + else if(!addFriend( peer_id, peer_pgp_id, pitem->netMode, pitem->vs_disc, pitem->vs_dht, pitem->lastContact, RS_NODE_PERM_ALL )) + { + RsInfo() << __PRETTY_FUNCTION__ << " cannot add friend friend: " << peer_id << " " << pitem->location << ". Somthing's wrong." << std::endl; + } setLocation(pitem->nodePeerId, pitem->location); } diff --git a/libretroshare/src/pqi/p3peermgr.h b/libretroshare/src/pqi/p3peermgr.h index 781dd6115..d5451eaa9 100644 --- a/libretroshare/src/pqi/p3peermgr.h +++ b/libretroshare/src/pqi/p3peermgr.h @@ -76,6 +76,13 @@ class peerState RsPeerId id; RsPgpId gpg_id; + // This flag is used when adding a single SSL cert as friend without adding its PGP key in the friend list. This allows to + // have short invites. However, because this represent a significant security risk, we perform multiple consistency checks + // whenever we use this flag, in particular: + // flat is true <==> friend SSL cert is in the friend list, but PGP id is not in the friend list + + bool skip_pgp_signature_validation; + uint32_t netMode; /* EXT / UPNP / UDP / HIDDEN / INVALID */ /* visState */ uint16_t vs_disc; @@ -127,8 +134,17 @@ public: rstime_t lastContact = 0, ServicePermissionFlags = ServicePermissionFlags(RS_NODE_PERM_DEFAULT) ) = 0; + virtual bool addSslOnlyFriend( + const RsPeerId& sslId, + const RsPgpId& pgpId, + const RsPeerDetails& details = RsPeerDetails() ) = 0; + + // Calling this removed the skip_pgp_signature_validation flag on all peers which PGP key is the one supplied. + virtual bool notifyPgpKeyReceived(const RsPgpId& pgp_key_id) = 0; + virtual bool removeFriend(const RsPeerId &ssl_id, bool removePgpId) = 0; virtual bool isFriend(const RsPeerId& ssl_id) = 0; + virtual bool isSslOnlyFriend(const RsPeerId &ssl_id)=0; virtual bool getAssociatedPeers(const RsPgpId &gpg_id, std::list &ids) = 0; virtual bool removeAllFriendLocations(const RsPgpId &gpgid) = 0; @@ -192,7 +208,6 @@ virtual bool UpdateOwnAddress(const struct sockaddr_storage &local_addr, cons virtual bool getOwnNetStatus(peerState &state) = 0; virtual bool getFriendNetStatus(const RsPeerId &id, peerState &state) = 0; -virtual bool getOthersNetStatus(const RsPeerId &id, peerState &state) = 0; virtual bool getPeerName(const RsPeerId &ssl_id, std::string &name) = 0; virtual bool getGpgId(const RsPeerId &sslId, RsPgpId &gpgId) = 0; @@ -242,10 +257,16 @@ public: virtual bool addFriend(const RsPeerId&ssl_id, const RsPgpId&gpg_id, uint32_t netMode = RS_NET_MODE_UDP, uint16_t vsDisc = RS_VS_DISC_FULL, uint16_t vsDht = RS_VS_DHT_FULL, rstime_t lastContact = 0,ServicePermissionFlags = ServicePermissionFlags(RS_NODE_PERM_DEFAULT)); + + bool addSslOnlyFriend(const RsPeerId& sslId, const RsPgpId &pgp_id, const RsPeerDetails& details = RsPeerDetails() ) override; + + virtual bool notifyPgpKeyReceived(const RsPgpId& pgp_key_id) override; + virtual bool removeFriend(const RsPeerId &ssl_id, bool removePgpId); virtual bool removeFriend(const RsPgpId &pgp_id); virtual bool isFriend(const RsPeerId &ssl_id); + virtual bool isSslOnlyFriend(const RsPeerId &ssl_id); virtual bool getAssociatedPeers(const RsPgpId &gpg_id, std::list &ids); virtual bool removeAllFriendLocations(const RsPgpId &gpgid); @@ -307,7 +328,6 @@ public: virtual bool getOwnNetStatus(peerState &state); virtual bool getFriendNetStatus(const RsPeerId &id, peerState &state); - virtual bool getOthersNetStatus(const RsPeerId &id, peerState &state); virtual bool getPeerName(const RsPeerId& ssl_id, std::string& name); virtual bool getGpgId(const RsPeerId& sslId, RsPgpId& gpgId); @@ -395,7 +415,6 @@ private: peerState mOwnState; std::map mFriendList; // - std::map mOthersList; std::map mReportedOwnAddresses ; diff --git a/libretroshare/src/pqi/p3servicecontrol.cc b/libretroshare/src/pqi/p3servicecontrol.cc index 23dcaf747..9bf3b3c62 100644 --- a/libretroshare/src/pqi/p3servicecontrol.cc +++ b/libretroshare/src/pqi/p3servicecontrol.cc @@ -28,6 +28,8 @@ #include "rsitems/rsnxsitems.h" #include "pqi/p3cfgmgr.h" #include "pqi/pqiservice.h" +#include "retroshare/rspeers.h" +#include "retroshare/rsevents.h" /*******************************/ // #define SERVICECONTROL_DEBUG 1 @@ -756,6 +758,11 @@ bool p3ServiceControl::updateFilterByPeer_locked(const RsPeerId &peerId) mPeerFilterMap[peerId] = peerFilter; } recordFilterChanges_locked(peerId, originalFilter, peerFilter); + + using Evt_t = RsPeerStateChangedEvent; + if(rsEvents) + rsEvents->postEvent(std::unique_ptr(new Evt_t(peerId))); + return true; } diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index b2abcc414..a10e7853a 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -35,7 +35,7 @@ #include "pqi/pqissllistener.h" #include "pqi/p3linkmgr.h" -#include +#include "retroshare/rspeers.h" #include #include @@ -1180,10 +1180,12 @@ int pqissl::Authorise_SSL_Connection() /* At this point the actual connection authentication has already been * performed in AuthSSL::VerifyX509Callback, any furter authentication check - * like the following two are redundant. */ + * like the followings are redundant. */ + + bool isSslOnlyFriend = rsPeers->isSslOnlyFriend(certPeerId); uint32_t authErrCode = 0; - if(!AuthSSL::instance().AuthX509WithGPG(peercert, authErrCode)) + if( !isSslOnlyFriend && !AuthSSL::instance().AuthX509WithGPG(peercert,false, authErrCode) ) { RsFatal() << __PRETTY_FUNCTION__ << " failure verifying peer " << "certificate signature. This should never happen at this " @@ -1195,7 +1197,7 @@ int pqissl::Authorise_SSL_Connection() } RsPgpId pgpId = RsX509Cert::getCertIssuer(*peercert); - if( pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && + if( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && !AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) ) { RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId diff --git a/libretroshare/src/pqi/pqissllistener.cc b/libretroshare/src/pqi/pqissllistener.cc index d1a9e31a9..3d62db9ea 100644 --- a/libretroshare/src/pqi/pqissllistener.cc +++ b/libretroshare/src/pqi/pqissllistener.cc @@ -784,10 +784,13 @@ int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info) #ifdef RS_PQISSL_AUTH_DOUBLE_CHECK /* At this point the actual connection authentication has already been * performed in AuthSSL::VerifyX509Callback, any furter authentication check - * like the following two are redundant. */ + * like the followings are redundant. */ + + bool isSslOnlyFriend = rsPeers->isSslOnlyFriend(newPeerId); uint32_t authErrCode = 0; - if(!AuthSSL::instance().AuthX509WithGPG(peercert, authErrCode)) + if( !isSslOnlyFriend && + !AuthSSL::instance().AuthX509WithGPG(peercert,false, authErrCode) ) { RsFatal() << __PRETTY_FUNCTION__ << " failure verifying peer " << "certificate signature. This should never happen at this " @@ -798,7 +801,7 @@ int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info) exit(failure); } - if( pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && + if( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && !AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) ) { RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId @@ -822,7 +825,7 @@ int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info) else ++it; } - if (found == false) + if (!found) { Dbg1() << __PRETTY_FUNCTION__ << " got secure connection from address: " << info.addr << " with previously unknown SSL certificate: " diff --git a/libretroshare/src/retroshare/rsevents.h b/libretroshare/src/retroshare/rsevents.h index 373788f97..880cade56 100644 --- a/libretroshare/src/retroshare/rsevents.h +++ b/libretroshare/src/retroshare/rsevents.h @@ -63,6 +63,9 @@ enum class RsEventType : uint32_t /// @see RsGxsChanges GXS_CHANGES = 5, + /// Emitted when a peer state changes, @see RsPeers + PEER_STATE_CHANGED = 6, + MAX /// Used to detect invalid event type passed }; diff --git a/libretroshare/src/retroshare/rsgossipdiscovery.h b/libretroshare/src/retroshare/rsgossipdiscovery.h index cf748549c..c9dc9924a 100644 --- a/libretroshare/src/retroshare/rsgossipdiscovery.h +++ b/libretroshare/src/retroshare/rsgossipdiscovery.h @@ -64,6 +64,8 @@ struct RsGossipDiscoveryFriendInviteReceivedEvent : RsEvent class RsGossipDiscovery { public: + virtual ~RsGossipDiscovery() = default; + /** * @brief getDiscFriends get a list of all friends of a given friend * @jsonapi{development} @@ -101,34 +103,4 @@ public: * @return true on success false otherwise */ virtual bool getWaitingDiscCount(size_t& sendCount, size_t& recvCount) = 0; - - /** - * @brief Send RetroShare invite to given peer - * @jsonapi{development} - * @param[in] inviteId id of peer of which send the invite - * @param[in] toSslId ssl id of the destination peer - * @param[out] errorMessage Optional storage for the error message, - * meaningful only on failure. - * @return true on success false otherwise - */ - virtual bool sendInvite( - const RsPeerId& inviteId, const RsPeerId& toSslId, - std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) - ) = 0; - - /** - * @brief Request RetroShare certificate to given peer - * @jsonapi{development} - * @param[in] inviteId id of the peer of which request the invite - * @param[in] toSslId id of the destination of the request - * @param[out] errorMessage Optional storage for the error message, - * meaningful only on failure. - * @return true on success false otherwise - */ - virtual bool requestInvite( - const RsPeerId& inviteId, const RsPeerId& toSslId, - std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) - ) = 0; - - virtual ~RsGossipDiscovery(); }; diff --git a/libretroshare/src/retroshare/rspeers.h b/libretroshare/src/retroshare/rspeers.h index d2b0547ec..b4b0a64d0 100644 --- a/libretroshare/src/retroshare/rspeers.h +++ b/libretroshare/src/retroshare/rspeers.h @@ -31,6 +31,7 @@ #include "util/rsurl.h" #include "util/rsdeprecate.h" #include "util/rstime.h" +#include "retroshare/rsevents.h" class RsPeers; @@ -73,7 +74,7 @@ const uint32_t RS_HIDDEN_TYPE_I2P = 0x0004; /* mask to match all valid hidden types */ const uint32_t RS_HIDDEN_TYPE_MASK = RS_HIDDEN_TYPE_I2P | RS_HIDDEN_TYPE_TOR; -/* Visibility */ +/* Visibility parameter for discovery */ const uint32_t RS_VS_DISC_OFF = 0x0000; const uint32_t RS_VS_DISC_MINIMAL = 0x0001; const uint32_t RS_VS_DISC_FULL = 0x0002; @@ -129,6 +130,8 @@ const uint32_t CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR = 0x16 ; const uint32_t CERTIFICATE_PARSING_ERROR_UNKNOWN_SECTION_PTAG = 0x17 ; const uint32_t CERTIFICATE_PARSING_ERROR_MISSING_CHECKSUM = 0x18 ; const uint32_t CERTIFICATE_PARSING_ERROR_WRONG_VERSION = 0x19 ; +const uint32_t CERTIFICATE_PARSING_ERROR_MISSING_PGP_FINGERPRINT = 0x1a ; +const uint32_t CERTIFICATE_PARSING_ERROR_MISSING_LOCATION_ID = 0x1b ; const uint32_t PGP_KEYRING_REMOVAL_ERROR_NO_ERROR = 0x20 ; const uint32_t PGP_KEYRING_REMOVAL_ERROR_CANT_REMOVE_SECRET_KEYS = 0x21 ; @@ -139,40 +142,40 @@ const uint32_t PGP_KEYRING_REMOVAL_ERROR_DATA_INCONSISTENCY = 0x24 ; /* LinkType Flags */ // CONNECTION -const uint32_t RS_NET_CONN_TRANS_MASK = 0x0000ffff; -const uint32_t RS_NET_CONN_TRANS_TCP_MASK = 0x0000000f; -const uint32_t RS_NET_CONN_TRANS_TCP_UNKNOWN = 0x00000001; -const uint32_t RS_NET_CONN_TRANS_TCP_LOCAL = 0x00000002; -const uint32_t RS_NET_CONN_TRANS_TCP_EXTERNAL = 0x00000004; +const uint32_t RS_NET_CONN_TRANS_MASK = 0x0000ffff; +const uint32_t RS_NET_CONN_TRANS_TCP_MASK = 0x0000000f; +const uint32_t RS_NET_CONN_TRANS_TCP_UNKNOWN = 0x00000001; +const uint32_t RS_NET_CONN_TRANS_TCP_LOCAL = 0x00000002; +const uint32_t RS_NET_CONN_TRANS_TCP_EXTERNAL = 0x00000004; -const uint32_t RS_NET_CONN_TRANS_UDP_MASK = 0x000000f0; -const uint32_t RS_NET_CONN_TRANS_UDP_UNKNOWN = 0x00000010; -const uint32_t RS_NET_CONN_TRANS_UDP_DIRECT = 0x00000020; -const uint32_t RS_NET_CONN_TRANS_UDP_PROXY = 0x00000040; -const uint32_t RS_NET_CONN_TRANS_UDP_RELAY = 0x00000080; +const uint32_t RS_NET_CONN_TRANS_UDP_MASK = 0x000000f0; +const uint32_t RS_NET_CONN_TRANS_UDP_UNKNOWN = 0x00000010; +const uint32_t RS_NET_CONN_TRANS_UDP_DIRECT = 0x00000020; +const uint32_t RS_NET_CONN_TRANS_UDP_PROXY = 0x00000040; +const uint32_t RS_NET_CONN_TRANS_UDP_RELAY = 0x00000080; -const uint32_t RS_NET_CONN_TRANS_OTHER_MASK = 0x00000f00; +const uint32_t RS_NET_CONN_TRANS_OTHER_MASK = 0x00000f00; -const uint32_t RS_NET_CONN_TRANS_UNKNOWN = 0x00001000; +const uint32_t RS_NET_CONN_TRANS_UNKNOWN = 0x00001000; -const uint32_t RS_NET_CONN_SPEED_MASK = 0x000f0000; -const uint32_t RS_NET_CONN_SPEED_UNKNOWN = 0x00000000; -const uint32_t RS_NET_CONN_SPEED_TRICKLE = 0x00010000; -const uint32_t RS_NET_CONN_SPEED_LOW = 0x00020000; -const uint32_t RS_NET_CONN_SPEED_NORMAL = 0x00040000; -const uint32_t RS_NET_CONN_SPEED_HIGH = 0x00080000; +const uint32_t RS_NET_CONN_SPEED_MASK = 0x000f0000; +const uint32_t RS_NET_CONN_SPEED_UNKNOWN = 0x00000000; +const uint32_t RS_NET_CONN_SPEED_TRICKLE = 0x00010000; +const uint32_t RS_NET_CONN_SPEED_LOW = 0x00020000; +const uint32_t RS_NET_CONN_SPEED_NORMAL = 0x00040000; +const uint32_t RS_NET_CONN_SPEED_HIGH = 0x00080000; -const uint32_t RS_NET_CONN_QUALITY_MASK = 0x00f00000; -const uint32_t RS_NET_CONN_QUALITY_UNKNOWN = 0x00000000; +const uint32_t RS_NET_CONN_QUALITY_MASK = 0x00f00000; +const uint32_t RS_NET_CONN_QUALITY_UNKNOWN = 0x00000000; // THIS INFO MUST BE SUPPLIED BY PEERMGR.... -const uint32_t RS_NET_CONN_TYPE_MASK = 0x0f000000; -const uint32_t RS_NET_CONN_TYPE_UNKNOWN = 0x00000000; -const uint32_t RS_NET_CONN_TYPE_ACQUAINTANCE = 0x01000000; -const uint32_t RS_NET_CONN_TYPE_FRIEND = 0x02000000; -const uint32_t RS_NET_CONN_TYPE_SERVER = 0x04000000; -const uint32_t RS_NET_CONN_TYPE_CLIENT = 0x08000000; +const uint32_t RS_NET_CONN_TYPE_MASK = 0x0f000000; +const uint32_t RS_NET_CONN_TYPE_UNKNOWN = 0x00000000; +const uint32_t RS_NET_CONN_TYPE_ACQUAINTANCE = 0x01000000; +const uint32_t RS_NET_CONN_TYPE_FRIEND = 0x02000000; +const uint32_t RS_NET_CONN_TYPE_SERVER = 0x04000000; +const uint32_t RS_NET_CONN_TYPE_CLIENT = 0x08000000; // working state of proxy @@ -204,6 +207,14 @@ std::string RsPeerNetModeString(uint32_t netModel); std::string RsPeerLastConnectString(uint32_t lastConnect); +/* We should definitely split this into 2 sub-structures: + * PGP info (or profile info) with all info related to PGP keys + * peer info: all network related information + * + * Plus top level information: + * isOnlyPgpDetail (this could be obsolete if the methods to query about PGP info is a different function) + * peer Id + */ struct RsPeerDetails : RsSerializable { RsPeerDetails(); @@ -227,6 +238,7 @@ struct RsPeerDetails : RsSerializable uint32_t trustLvl; uint32_t validLvl; + bool skip_pgp_signature_validation; bool ownsign; /* we have signed the remote peer GPG key */ bool hasSignedMe; /* the remote peer has signed my GPG key */ @@ -358,6 +370,23 @@ struct RsGroupInfo : RsSerializable } }; +/** Event emitted when a peer change state */ +struct RsPeerStateChangedEvent : RsEvent +{ + /// @param[in] sslId is of the peer which changed state + RsPeerStateChangedEvent(RsPeerId sslId); + + /// Storage fot the id of the peer that changed state + RsPeerId mSslId; + + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override + { + RsEvent::serial_process(j, ctx); + RS_SERIAL_PROCESS(mSslId); + } +}; + /** The Main Interface Class - for information about your Peers * A peer is another RS instance, means associated with an SSL certificate * A same GPG person can have multiple peer running with different SSL certs @@ -434,6 +463,16 @@ public: */ virtual bool isPgpFriend(const RsPgpId& pgpId) = 0; + /** + * @brief Check if given peer is a trusted SSL node pending PGP approval + * Peers added through short invite remain in this state as long as their + * PGP key is not received and verified/approved by the user. + * @jsonapi{development} + * @param[in] sslId id of the peer to check + * @return true if the node is trusted, false otherwise + */ + virtual bool isSslOnlyFriend(const RsPeerId& sslId) = 0; + virtual std::string getPeerName(const RsPeerId &ssl_id) = 0; virtual std::string getGPGName(const RsPgpId& gpg_id) = 0; @@ -466,6 +505,11 @@ public: virtual bool getAssociatedSSLIds(const RsPgpId& gpg_id, std::list& ids) = 0; virtual bool gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "") = 0; + virtual RsPgpId pgpIdFromFingerprint(const RsPgpFingerprint& fpr) = 0; + + // Note: the two methods below could be unified. The fact that one of them can take an optional RsPeerDetails struct as parameter + // seems quite inconsistent. + /** * @brief Add trusted node * @jsonapi{development} @@ -474,8 +518,26 @@ public: * @param[in] flags service permissions flag * @return false if error occurred, true otherwise */ - virtual bool addFriend( const RsPeerId &sslId, const RsPgpId& gpgId, - ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT ) = 0; + virtual bool addFriend( + const RsPeerId& sslId, const RsPgpId& gpgId, + ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT ) = 0; + + /** + * @brief Add SSL-only trusted node + * When adding an SSL-only node, it is authorized to connect. Every time a + * connection is established the user is notified about the need to verify + * the PGP fingerprint, until she does, at that point the node become a full + * SSL+PGP friend. + * @jsonapi{development} + * @param[in] sslId SSL id of the node to add + * @param[in] pgpId PGP id of the node to add. Will be used for validation when the key is available. + * @param[in] details Optional extra details known about the node to add + * @return false if error occurred, true otherwise + */ + virtual bool addSslOnlyFriend( + const RsPeerId& sslId, + const RsPgpId& pgpId, + const RsPeerDetails& details = RsPeerDetails() ) = 0; /** * @brief Revoke connection trust from to node @@ -597,6 +659,38 @@ public: bool includeSignatures = false, bool includeExtraLocators = true ) = 0; + /** + * @brief Get RetroShare short invite of the given peer + * @jsonapi{development} + * @param[out] invite storage for the generated invite + * @param[in] sslId Id of the peer of which we want to generate an invite, + * a null id (all 0) is passed, an invite for own node is returned. + * @param[in] formatRadix true to get in base64 format false to get URL. + * @param[in] bareBones true to get smallest invite, which miss also + * the information necessary to attempt an outgoing connection, but still + * enough to accept an incoming one. + * @param[in] baseUrl URL into which to sneak in the RetroShare invite + * radix, this is primarly useful to trick other applications into making + * the invite clickable, or to disguise the RetroShare invite into a + * "normal" looking web link. Used only if formatRadix is false. + * @return false if error occurred, true otherwise + */ + virtual bool getShortInvite( + std::string& invite, const RsPeerId& sslId = RsPeerId(), + bool formatRadix = false, bool bareBones = false, + const std::string& baseUrl = "https://retroshare.me/" ) = 0; + + /** + * @brief Parse the give short invite to extract contained information + * @jsonapi{development} + * @param[in] invite string containing the short invite to parse + * @param[out] details storage for the extracted information, consider it + * @param[out] err_code storage for the error code + * @return false if error occurred, true otherwise + */ + virtual bool parseShortInvite( + const std::string& invite, RsPeerDetails& details,uint32_t& err_code ) = 0; + /** * @brief Add trusted node from invite * @jsonapi{development} @@ -640,8 +734,13 @@ public: const std::string& cert, RsPeerDetails& certDetails, uint32_t& errorCode ) = 0; + virtual bool loadPgpKeyFromBinaryData( const unsigned char *bin_key_data, + uint32_t bin_key_len, + RsPgpId& gpg_id, + std::string& error_string )=0; + // Certificate utils - virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code) = 0; + virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,bool& is_short_format,uint32_t& error_code) = 0; virtual bool saveCertificateToFile(const RsPeerId& id, const std::string &fname) = 0; virtual std::string saveCertificateToString(const RsPeerId &id) = 0; @@ -749,6 +848,3 @@ public: RS_DEPRECATED_FOR(isPgpFriend) virtual bool isGPGAccepted(const RsPgpId &gpg_id_is_friend) = 0; }; - - - diff --git a/libretroshare/src/rsserver/p3peers.cc b/libretroshare/src/rsserver/p3peers.cc index ddab5fabf..18d245663 100644 --- a/libretroshare/src/rsserver/p3peers.cc +++ b/libretroshare/src/rsserver/p3peers.cc @@ -41,15 +41,8 @@ #include #include -const std::string CERT_SSL_ID = "--SSLID--"; -const std::string CERT_LOCATION = "--LOCATION--"; -const std::string CERT_LOCAL_IP = "--LOCAL--"; -const std::string CERT_EXT_IP = "--EXT--"; -const std::string CERT_DYNDNS = "--DYNDNS--"; - //static const int MAX_TIME_KEEP_LOCATION_WITHOUT_CONTACT = 30*24*3600 ; // 30 days. - #include "pqi/authssl.h" @@ -137,11 +130,12 @@ bool p3Peers::hasExportMinimal() } /* Updates ... */ -bool p3Peers::FriendsChanged() +bool p3Peers::FriendsChanged(bool add) { #ifdef P3PEERS_DEBUG std::cerr << "p3Peers::FriendsChanged()" << std::endl; #endif + RsServer::notify()->notifyListChange(NOTIFY_LIST_FRIENDS, add? NOTIFY_TYPE_ADD : NOTIFY_TYPE_DEL); /* TODO */ return false; @@ -295,7 +289,18 @@ bool p3Peers::getPeerDetails(const RsPeerId& id, RsPeerDetails &d) /* get from gpg (first), to fill in the sign and trust details */ /* don't return now, we've got fill in the ssl and connection info */ - getGPGDetails(ps.gpg_id, d); + + if(!getGPGDetails(ps.gpg_id, d)) + { + if(!ps.skip_pgp_signature_validation) + return false; + + d.gpg_id = ps.gpg_id ; + d.skip_pgp_signature_validation = true; + } + else + d.skip_pgp_signature_validation = false; + d.isOnlyGPGdetail = false; //get the ssl details @@ -570,6 +575,22 @@ std::string p3Peers::getGPGName(const RsPgpId &gpg_id) bool p3Peers::isPgpFriend(const RsPgpId& pgpId) { return AuthGPG::getAuthGPG()->isGPGAccepted(pgpId); } +bool p3Peers::isSslOnlyFriend(const RsPeerId& sslId) +{ + bool has_ssl_only_flag = mPeerMgr->isSslOnlyFriend(sslId) ; + + if(has_ssl_only_flag) + { + if(isPgpFriend(getGPGId(sslId))) + { + RsErr() << __PRETTY_FUNCTION__ << ": Peer " << sslId << " has SSL-friend-only flag but his PGP id is in the list of friends. This is inconsistent (Bug in the code). Returning false for security reasons." << std::endl; + return false; + } + return true; + } + return false; +} + bool p3Peers::isGPGAccepted(const RsPgpId &gpg_id_is_friend) { return isPgpFriend(gpg_id_is_friend); } @@ -650,6 +671,11 @@ bool p3Peers::gpgSignData(const void *data, const uint32_t len, unsigned char return AuthGPG::getAuthGPG()->SignDataBin(data,len,sign,signlen, reason); } +RsPgpId p3Peers::pgpIdFromFingerprint(const RsPgpFingerprint& fpr) +{ + return PGPHandler::pgpIdFromFingerprint(fpr); +} + bool p3Peers::getGPGDetails(const RsPgpId &pgp_id, RsPeerDetails &d) { #ifdef P3PEERS_DEBUG @@ -687,9 +713,8 @@ RsPgpId p3Peers::getGPGId(const RsPeerId& sslid) return AuthGPG::getAuthGPG()->getGPGOwnId(); } peerState pcs; - if (mPeerMgr->getFriendNetStatus(sslid, pcs) || mPeerMgr->getOthersNetStatus(sslid, pcs)) { + if (mPeerMgr->getFriendNetStatus(sslid, pcs)) return pcs.gpg_id; - } return RsPgpId(); } @@ -741,7 +766,9 @@ bool p3Peers::addFriend(const RsPeerId &ssl_id, const RsPgpId &gpg_id,ServicePe return true; } - /* otherwise - we install as ssl_id..... + FriendsChanged(true); + + /* otherwise - we install as ssl_id..... * If we are adding an SSL certificate. we flag lastcontact as now. * This will cause the SSL certificate to be retained for 30 days... and give the person a chance to connect! * */ @@ -749,6 +776,17 @@ bool p3Peers::addFriend(const RsPeerId &ssl_id, const RsPgpId &gpg_id,ServicePe return mPeerMgr->addFriend(ssl_id, gpg_id, RS_NET_MODE_UDP, RS_VS_DISC_FULL, RS_VS_DHT_FULL, now, perm_flags); } +bool p3Peers::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_id,const RsPeerDetails& details ) +{ + if( mPeerMgr->addSslOnlyFriend(sslId, pgp_id,details)) + { + FriendsChanged(true); + return true; + } + else + return false; +} + bool p3Peers::removeKeysFromPGPKeyring(const std::set& pgp_ids,std::string& backup_file,uint32_t& error_code) { return AuthGPG::getAuthGPG()->removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ; @@ -1104,6 +1142,274 @@ bool p3Peers::GetPGPBase64StringAndCheckSum( const RsPgpId& gpg_id, return true ; } +enum class RsShortInviteFieldType : uint8_t +{ + SSL_ID = 0x00, + PEER_NAME = 0x01, + LOCATOR = 0x02, + PGP_FINGERPRINT = 0x03, + + /* The following will be deprecated, and ported to LOCATOR when generic + * trasport layer will be implemented */ + HIDDEN_LOCATOR = 0x90, + DNS_LOCATOR = 0x91, + EXT4_LOCATOR = 0x92 +}; + +static void addPacketHeader(RsShortInviteFieldType ptag, size_t size, unsigned char *& buf, uint32_t& offset, uint32_t& buf_size) +{ + // Check that the buffer has sufficient size. If not, increase it. + + while(offset + size + 6 >= buf_size) + { + unsigned char *newbuf = new unsigned char[2*buf_size] ; + + memcpy(newbuf, buf, buf_size) ; + buf_size *= 2 ; + delete[] buf ; + buf = newbuf ; + } + + // Write ptag and size + + buf[offset] = static_cast(ptag) ; + offset += 1 ; + + offset += PGPKeyParser::write_125Size(&buf[offset],size) ; +} + +bool p3Peers::getShortInvite( + std::string& invite, const RsPeerId& _sslId, bool formatRadix, + bool bareBones, const std::string& baseUrl ) +{ + RsPeerId sslId = _sslId; + if(sslId.isNull()) sslId = getOwnId(); + + RsPeerDetails tDetails; + if(!getPeerDetails(sslId, tDetails)) return false; + + uint32_t buf_size = 100; + uint32_t offset = 0; + unsigned char *buf = (unsigned char*)malloc(buf_size); + + addPacketHeader(RsShortInviteFieldType::SSL_ID,RsPeerId::SIZE_IN_BYTES,buf,offset,buf_size); + sslId.serialise(buf,buf_size,offset); + + addPacketHeader(RsShortInviteFieldType::PGP_FINGERPRINT,RsPgpFingerprint::SIZE_IN_BYTES,buf,offset,buf_size); + tDetails.fpr.serialise(buf,buf_size,offset); + + addPacketHeader(RsShortInviteFieldType::PEER_NAME,tDetails.name.size(),buf,offset,buf_size); + memcpy(&buf[offset],tDetails.name.c_str(),tDetails.name.size()); + offset += tDetails.name.size(); + + if(!bareBones) + { + /* If is hidden use hidden address and port as locator, else if we have + * a valid dyndns and extPort use that as locator, else if we have a + * valid extAddr and extPort use that as locator, otherwise use most + * recently known locator */ + sockaddr_storage tExt; + if(tDetails.isHiddenNode) + { + addPacketHeader(RsShortInviteFieldType::HIDDEN_LOCATOR,4 + 2 + tDetails.hiddenNodeAddress.size(),buf,offset,buf_size); + + buf[offset+0] = (uint8_t)((tDetails.hiddenType >> 24) & 0xff); + buf[offset+1] = (uint8_t)((tDetails.hiddenType >> 16) & 0xff); + buf[offset+2] = (uint8_t)((tDetails.hiddenType >> 8) & 0xff); + buf[offset+3] = (uint8_t)((tDetails.hiddenType ) & 0xff); + + buf[offset+4] = (uint8_t)((tDetails.hiddenNodePort >> 8) & 0xff); + buf[offset+5] = (uint8_t)((tDetails.hiddenNodePort ) & 0xff); + + memcpy(&buf[offset+6],tDetails.hiddenNodeAddress.c_str(),tDetails.hiddenNodeAddress.size()); + offset += 4 + 2 + tDetails.hiddenNodeAddress.size(); + } + else if( !tDetails.dyndns.empty() && (tDetails.extPort || tDetails.localPort) ) + { + uint16_t tPort = tDetails.extPort ? tDetails.extPort : tDetails.localPort; + + addPacketHeader(RsShortInviteFieldType::DNS_LOCATOR, 2 + tDetails.dyndns.size(),buf,offset,buf_size); + + buf[offset+0] = (uint8_t)((tPort >> 8) & 0xff); + buf[offset+1] = (uint8_t)((tPort ) & 0xff); + + memcpy(&buf[offset+2],tDetails.dyndns.c_str(),tDetails.dyndns.size()); + offset += 2 + tDetails.dyndns.size(); + } + else if( sockaddr_storage_inet_pton(tExt, tDetails.extAddr) && + sockaddr_storage_isValidNet(tExt) && + sockaddr_storage_ipv6_to_ipv4(tExt) && + tDetails.extPort ) + { + uint32_t t4Addr = reinterpret_cast(tExt).sin_addr.s_addr; + + addPacketHeader(RsShortInviteFieldType::EXT4_LOCATOR, 4 + 2,buf,offset,buf_size); + + buf[offset+0] = (uint8_t)((t4Addr >> 24) & 0xff); + buf[offset+1] = (uint8_t)((t4Addr >> 16) & 0xff); + buf[offset+2] = (uint8_t)((t4Addr >> 8) & 0xff); + buf[offset+3] = (uint8_t)((t4Addr ) & 0xff); + + buf[offset+4] = (uint8_t)((tDetails.extPort >> 8) & 0xff); + buf[offset+5] = (uint8_t)((tDetails.extPort ) & 0xff); + + offset += 4+2; + } + else if(!tDetails.ipAddressList.empty()) + { + const std::string& tLc = tDetails.ipAddressList.front(); + std::string tLocator = tLc.substr(0, tLc.find_first_of(" ")-1); + + addPacketHeader(RsShortInviteFieldType::LOCATOR, tLocator.size(),buf,offset,buf_size); + memcpy(&buf[offset],tLocator.c_str(),tLocator.size()); + + offset += tLocator.size(); + } + } + + Radix64::encode(buf, static_cast(offset), invite); + + if(!formatRadix) + { + RsUrl inviteUrl(baseUrl); + inviteUrl.setQueryKV("rsInvite", invite); + invite = inviteUrl.toString(); + } + + return true; +} + +bool p3Peers::parseShortInvite(const std::string& inviteStrUrl, RsPeerDetails& details, uint32_t &err_code ) +{ + if(inviteStrUrl.empty()) + { + RsErr() << __PRETTY_FUNCTION__ << " can't parse empty invite" + << std::endl; + return false; + } + std::string rsInvite = inviteStrUrl; + + RsUrl inviteUrl(inviteStrUrl); + + if(inviteUrl.hasQueryK("rsInvite")) + rsInvite = *inviteUrl.getQueryV("rsInvite"); + + std::vector bf = Radix64::decode(rsInvite); + size_t size = bf.size(); + + unsigned char* buf = bf.data(); + size_t total_s = 0; + + while(total_s < size) + { + RsShortInviteFieldType ptag = RsShortInviteFieldType(buf[0]); + buf = &buf[1]; + + unsigned char *buf2 = buf; + uint32_t s = 0; + + try { s = PGPKeyParser::read_125Size(buf); } + catch (...) + { + err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR; + return false; + } + + total_s += 1 + ( reinterpret_cast(buf) - reinterpret_cast(buf2) ); + + if(total_s > size) + { + err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR; + return false; + } + + Dbg3() << __PRETTY_FUNCTION__ << " Read ptag: " + << static_cast(ptag) + << ", size " << s << ", total_s = " << total_s + << ", expected total = " << size << std::endl; + + switch(ptag) + { + case RsShortInviteFieldType::SSL_ID: + details.id = RsPeerId::fromBufferUnsafe(buf) ; + break; + + case RsShortInviteFieldType::PEER_NAME: + details.name = std::string((char*)buf,s); + break; + + case RsShortInviteFieldType::PGP_FINGERPRINT: + details.fpr = RsPgpFingerprint::fromBufferUnsafe(buf); + details.gpg_id = PGPHandler::pgpIdFromFingerprint(details.fpr); + break; + + case RsShortInviteFieldType::LOCATOR: + { + std::string locatorStr((char*)buf,s); + details.ipAddressList.push_back(locatorStr); + } + break; + + case RsShortInviteFieldType::DNS_LOCATOR: + details.extPort = (((int)buf[0]) << 8) + buf[1]; + details.dyndns = std::string((char*)&buf[2],s-2); + break; + + case RsShortInviteFieldType::EXT4_LOCATOR: + { + uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3]; + sockaddr_in tExtAddr; + tExtAddr.sin_addr.s_addr = t4Addr; + + details.extAddr = rs_inet_ntoa(tExtAddr.sin_addr); + details.extPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5]; + } + break; + + case RsShortInviteFieldType::HIDDEN_LOCATOR: + details.hiddenType = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3]; + details.hiddenNodePort = (((uint32_t)buf[4]) << 8)+ (uint32_t)buf[5]; + + details.hiddenNodeAddress = std::string((char*)&buf[6],s-6); + break; + + } + + buf = &buf[s]; + total_s += s; + } + + // now check if the PGP key is available. If so, add it in the PeerDetails: + + RsPeerDetails pgp_det ; + if(getGPGDetails(PGPHandler::pgpIdFromFingerprint(details.fpr),pgp_det) && pgp_det.fpr == details.fpr) + { + details.issuer = pgp_det.issuer; + details.gpg_id = pgp_det.gpg_id; + details.gpgSigners = pgp_det.gpgSigners; + details.trustLvl = pgp_det.trustLvl; + details.validLvl = pgp_det.validLvl; + details.ownsign = pgp_det.ownsign; + details.hasSignedMe = pgp_det.hasSignedMe; + details.accept_connection = pgp_det.accept_connection; + } + else + details.skip_pgp_signature_validation = true; + + if(details.gpg_id.isNull()) + { + err_code = CERTIFICATE_PARSING_ERROR_MISSING_PGP_FINGERPRINT; + return false; + } + if(details.id.isNull()) + { + err_code = CERTIFICATE_PARSING_ERROR_MISSING_LOCATION_ID; + return false; + } + err_code = CERTIFICATE_PARSING_ERROR_NO_ERROR; + return true; +} + bool p3Peers::acceptInvite( const std::string& invite, ServicePermissionFlags flags ) { @@ -1228,12 +1534,28 @@ bool p3Peers::loadCertificateFromString( } RsPgpId gpgid; - bool res = AuthGPG::getAuthGPG()->LoadCertificateFromString( - crt->armouredPGPKey(), gpgid, error_string ); + bool res = AuthGPG::getAuthGPG()->LoadCertificateFromString( crt->armouredPGPKey(), gpgid, error_string ); gpg_id = gpgid; ssl_id = crt->sslid(); + // now get all friends who declare this key ID to be the one needed to check connections, and clear their "skip_pgp_signature_validation" flag + + if(res) + { + mPeerMgr->notifyPgpKeyReceived(gpgid); + FriendsChanged(true); + } + + return res; +} +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 ); + + if(res) + mPeerMgr->notifyPgpKeyReceived(gpg_id); + return res; } @@ -1290,11 +1612,20 @@ bool p3Peers::loadDetailsFromStringCert( const std::string &certstr, return true; } -bool p3Peers::cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code) +bool p3Peers::cleanCertificate(const std::string &certstr, std::string &cleanCert,bool& is_short_format,uint32_t& error_code) { RsCertificate::Format format ; - return RsCertificate::cleanCertificate(certstr,cleanCert,format,error_code,true) ; + bool res = RsCertificate::cleanCertificate(certstr,cleanCert,format,error_code,true) ; + + if(format == RsCertificate::RS_CERTIFICATE_RADIX) + is_short_format = false; + else if(format == RsCertificate::RS_CERTIFICATE_SHORT_RADIX) + is_short_format = true; + else + return false ; + + return res; } bool p3Peers::saveCertificateToFile(const RsPeerId &id, const std::string &/*fname*/) @@ -1475,7 +1806,7 @@ RsPeerDetails::RsPeerDetails() :isOnlyGPGdetail(false), name(""),email(""),location(""), org(""),authcode(""), - trustLvl(0), validLvl(0),ownsign(false), + trustLvl(0), validLvl(0),skip_pgp_signature_validation(false),ownsign(false), hasSignedMe(false),accept_connection(false), state(0),actAsServer(false), connectPort(0), @@ -1503,4 +1834,5 @@ void p3Peers::setServicePermissionFlags(const RsPgpId& gpg_id,const ServicePermi mPeerMgr->setServicePermissionFlags(gpg_id,flags) ; } - +RsPeerStateChangedEvent::RsPeerStateChangedEvent(RsPeerId sslId) : + RsEvent(RsEventType::PEER_STATE_CHANGED), mSslId(sslId) {} diff --git a/libretroshare/src/rsserver/p3peers.h b/libretroshare/src/rsserver/p3peers.h index a44fb4142..e44e7d23a 100644 --- a/libretroshare/src/rsserver/p3peers.h +++ b/libretroshare/src/rsserver/p3peers.h @@ -48,7 +48,7 @@ public: virtual ~p3Peers() {} /* Updates ... */ - virtual bool FriendsChanged(); + virtual bool FriendsChanged(bool add); virtual bool OthersChanged(); /* Peer Details (Net & Auth) */ @@ -69,6 +69,9 @@ public: virtual bool isFriend(const RsPeerId &id); virtual bool isPgpFriend(const RsPgpId& pgpId); + /// @see RsPeers + bool isSslOnlyFriend(const RsPeerId& sslId) override; + RS_DEPRECATED_FOR(isPgpFriend) virtual bool isGPGAccepted(const RsPgpId &gpg_id_is_friend); @@ -88,8 +91,17 @@ public: virtual bool getAssociatedSSLIds(const RsPgpId& gpg_id, std::list &ids); virtual bool gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "") ; + virtual RsPgpId pgpIdFromFingerprint(const RsPgpFingerprint& fpr) override; + /* Add/Remove Friends */ virtual bool addFriend(const RsPeerId &ssl_id, const RsPgpId &gpg_id,ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT); + + /// @see RsPeers + bool addSslOnlyFriend( + const RsPeerId& sslId, + const RsPgpId& pgp_id, + const RsPeerDetails& details = RsPeerDetails() ) override; + virtual bool removeFriend(const RsPgpId& gpgid); virtual bool removeFriendLocation(const RsPeerId& sslId); @@ -128,6 +140,15 @@ public: virtual bool GetPGPBase64StringAndCheckSum(const RsPgpId& gpg_id,std::string& gpg_base64_string,std::string& gpg_base64_checksum); + /// @see RsPeers + bool getShortInvite( + std::string& invite, const RsPeerId& sslId = RsPeerId(), + bool formatRadix = false, bool bareBones = false, + const std::string& baseUrl = "https://retroshare.me/" ) override; + + /// @see RsPeers + bool parseShortInvite(const std::string& invite, RsPeerDetails& details, uint32_t &err_code ) override; + /// @see RsPeers::acceptInvite virtual bool acceptInvite( const std::string& invite, @@ -136,9 +157,10 @@ public: virtual bool hasExportMinimal(); virtual bool loadCertificateFromString(const std::string& cert, RsPeerId& ssl_id,RsPgpId& pgp_id, std::string& error_string); + virtual bool loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string ); virtual bool loadDetailsFromStringCert(const std::string &cert, RsPeerDetails &pd, uint32_t& error_code); - virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code); + virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert, bool &is_short_format, uint32_t& error_code) override; virtual bool saveCertificateToFile(const RsPeerId &id, const std::string &fname); virtual std::string saveCertificateToString(const RsPeerId &id); diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 8d1d13fd3..e8e2b518f 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1764,7 +1764,7 @@ int RsServer::StartupRetroShare() /* Add AuthGPG services */ /**************************************************************************/ - AuthGPG::getAuthGPG()->addService(mDisc); + //AuthGPG::getAuthGPG()->addService(mDisc); /**************************************************************************/ /* Force Any Last Configuration Options */ diff --git a/libretroshare/src/util/rsthreads.cc b/libretroshare/src/util/rsthreads.cc index 414e0dac6..f825eedeb 100644 --- a/libretroshare/src/util/rsthreads.cc +++ b/libretroshare/src/util/rsthreads.cc @@ -110,6 +110,12 @@ RsThread::~RsThread() { RsErr() << "Deleting a thread that is still running! Something is very wrong here and Retroshare is likely to crash because of this." << std::endl; print_stacktrace(); + + while(isRunning()) + { + std::cerr << "." << std::endl; + rstime::rs_usleep(1000*1000); + } } } diff --git a/retroshare-gui/src/gui/FriendsDialog.cpp b/retroshare-gui/src/gui/FriendsDialog.cpp index 0661c6318..2d196978d 100644 --- a/retroshare-gui/src/gui/FriendsDialog.cpp +++ b/retroshare-gui/src/gui/FriendsDialog.cpp @@ -45,16 +45,12 @@ #include "NetworkDialog.h" #include "gui/common/NewFriendList.h" #include "gui/Identity/IdDialog.h" -#ifdef RS_USE_CIRCLES -#include "gui/Circles/CirclesDialog.h" -#endif /* Images for Newsfeed icons */ //#define IMAGE_NEWSFEED "" //#define IMAGE_NEWSFEED_NEW ":/images/message-state-new.png" #define IMAGE_NETWORK2 ":/icons/png/netgraph.png" #define IMAGE_PEERS ":/icons/png/keyring.png" #define IMAGE_IDENTITY ":/images/identity/identities_32.png" -//#define IMAGE_CIRCLES ":/icons/png/circles.png" /****** * #define FRIENDS_DEBUG 1 @@ -63,8 +59,7 @@ static FriendsDialog *instance = NULL; /** Constructor */ -FriendsDialog::FriendsDialog(QWidget *parent) - : RsAutoUpdatePage(1500,parent) +FriendsDialog::FriendsDialog(QWidget *parent) : MainPage(parent) { /* Invoke the Qt Designer generated object setup routine */ ui.setupUi(this); @@ -159,10 +154,6 @@ void FriendsDialog::activatePage(FriendsDialog::Page page) { case FriendsDialog::IdTab: ui.tabWidget->setCurrentWidget(idDialog) ; break ; -#ifdef RS_USE_CIRCLES - case FriendsDialog::CirclesTab: ui.tabWidget->setCurrentWidget(circlesDialog) ; - break ; -#endif case FriendsDialog::NetworkTab: ui.tabWidget->setCurrentWidget(networkDialog) ; break ; case FriendsDialog::BroadcastTab: ui.tabWidget->setCurrentWidget(networkDialog) ; @@ -200,11 +191,6 @@ void FriendsDialog::processSettings(bool bLoad) Settings->endGroup(); } -void FriendsDialog::showEvent(QShowEvent *event) -{ - RsAutoUpdatePage::showEvent(event); -} - void FriendsDialog::chatMessageReceived(const ChatMessage &msg) { if(msg.chat_id.isBroadcast()) @@ -234,10 +220,6 @@ void FriendsDialog::chatStatusReceived(const ChatId &chat_id, const QString &sta } } -void FriendsDialog::updateDisplay() -{ -} - void FriendsDialog::addFriend() { std::string groupId = ui.friendList->getSelectedGroupId(); diff --git a/retroshare-gui/src/gui/FriendsDialog.h b/retroshare-gui/src/gui/FriendsDialog.h index 8383b18e4..6eb9cdf7a 100644 --- a/retroshare-gui/src/gui/FriendsDialog.h +++ b/retroshare-gui/src/gui/FriendsDialog.h @@ -21,8 +21,6 @@ #ifndef _FRIENDSDIALOG_H #define _FRIENDSDIALOG_H -#include "retroshare-gui/RsAutoUpdatePage.h" - #include "ui_FriendsDialog.h" #define IMAGE_NETWORK ":/icons/png/network.png" @@ -33,7 +31,7 @@ class NetworkView; class IdDialog; class CirclesDialog; -class FriendsDialog : public RsAutoUpdatePage +class FriendsDialog : public MainPage { Q_OBJECT @@ -41,9 +39,7 @@ public: enum Page { /* Fixed numbers for load and save the last page */ IdTab = 0, /** Identities page. */ -#ifdef RS_USE_CIRCLES - CirclesTab = 1, /** Circles page. */ -#endif + // CirclesTab = 1, /** Circles page - DEPRECATED - please keep the numbering. */ NetworkTab = 2, /** Network page. */ NetworkViewTab = 3, /** Network new graph. */ BroadcastTab = 4 /** Old group chat page. */ @@ -61,8 +57,6 @@ public: virtual UserNotify *getUserNotify(QObject *parent); - virtual void updateDisplay() ; // overloaded from RsAutoUpdatePage - static bool isGroupChatActive(); static void groupChatActivate(); @@ -71,14 +65,8 @@ public: NetworkDialog *networkDialog ; NetworkView *networkView ; -#ifdef RS_USE_CIRCLES - CirclesDialog *circlesDialog; -#endif IdDialog *idDialog; -protected: - void showEvent (QShowEvent *event); - private slots: void chatMessageReceived(const ChatMessage& msg); void chatStatusReceived(const ChatId& chat_id, const QString& status_string); diff --git a/retroshare-gui/src/gui/HomePage.cpp b/retroshare-gui/src/gui/HomePage.cpp index 5637a4b18..385e6c075 100644 --- a/retroshare-gui/src/gui/HomePage.cpp +++ b/retroshare-gui/src/gui/HomePage.cpp @@ -48,14 +48,15 @@ HomePage::HomePage(QWidget *parent) : MainPage(parent), ui(new Ui::HomePage), - mIncludeAllIPs(false) + mIncludeAllIPs(false), + mUseShortFormat(true) { ui->setupUi(this); updateOwnCert(); connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addFriend())); - connect(ui->LoadCertFileButton, SIGNAL(clicked()), this, SLOT(loadCert())); + //connect(ui->LoadCertFileButton, SIGNAL(clicked()), this, SLOT(loadCert())); QAction *WebMailAction = new QAction(QIcon(),tr("Invite via WebMail"), this); connect(WebMailAction, SIGNAL(triggered()), this, SLOT(webMail())); @@ -75,11 +76,9 @@ HomePage::HomePage(QWidget *parent) : QObject::connect(ui->userCertEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(certContextMenu(QPoint))); - connect(ui->runStartWizard_PB,SIGNAL(clicked()), this,SLOT(runStartWizard())) ; connect(ui->openwebhelp,SIGNAL(clicked()), this,SLOT(openWebHelp())) ; - ui->runStartWizard_PB->hide(); // until future rework - ui->LoadCertFileButton->hide(); // duplicates functionality => not good. + //ui->LoadCertFileButton->hide(); // duplicates functionality => not good. int S = QFontMetricsF(font()).height(); QString help_str = tr( @@ -109,11 +108,19 @@ void HomePage::certContextMenu(QPoint point) menu.addAction(CopyAction); menu.addAction(SaveAction); + QAction *shortFormatAct = new QAction(QIcon(), tr("Use new (short) certificate format"),this); + connect(shortFormatAct, SIGNAL(triggered()), this, SLOT(toggleUseShortFormat())); + shortFormatAct->setCheckable(true); + shortFormatAct->setChecked(mUseShortFormat); + + menu.addAction(shortFormatAct); + if(!RsAccounts::isHiddenNode()) { - QAction *includeIPsAct = new QAction(QIcon(), mIncludeAllIPs? tr("Include only current IP"):tr("Include all your known IPs"),this); + QAction *includeIPsAct = new QAction(QIcon(), tr("Include all your known IPs"),this); connect(includeIPsAct, SIGNAL(triggered()), this, SLOT(toggleIncludeAllIPs())); includeIPsAct->setCheckable(true); + includeIPsAct->setChecked(mIncludeAllIPs); menu.addAction(includeIPsAct); } @@ -121,6 +128,11 @@ void HomePage::certContextMenu(QPoint point) menu.exec(QCursor::pos()); } +void HomePage::toggleUseShortFormat() +{ + mUseShortFormat = !mUseShortFormat; + updateOwnCert(); +} void HomePage::toggleIncludeAllIPs() { mIncludeAllIPs = !mIncludeAllIPs; @@ -144,11 +156,16 @@ void HomePage::updateOwnCert() return ; } - std::string invite = rsPeers->GetRetroshareInvite(detail.id,false,include_extra_locators); + std::string invite ; + + if(mUseShortFormat) + rsPeers->getShortInvite(invite,rsPeers->getOwnId(),true,!mIncludeAllIPs); + else + invite = rsPeers->GetRetroshareInvite(detail.id,false,include_extra_locators); ui->userCertEdit->setPlainText(QString::fromUtf8(invite.c_str())); - QString description = ConfCertDialog::getCertificateDescription(detail,false,include_extra_locators); + QString description = ConfCertDialog::getCertificateDescription(detail,false,mUseShortFormat,include_extra_locators); ui->userCertEdit->setToolTip(description); } @@ -232,18 +249,13 @@ void HomePage::webMail() connwiz.exec (); } -void HomePage::loadCert() -{ - ConnectFriendWizard connwiz (this); - - connwiz.setStartId(ConnectFriendWizard::Page_Cert); - connwiz.exec (); -} - -void HomePage::runStartWizard() -{ - QuickStartWizard(this).exec(); -} +// void HomePage::loadCert() +// { +// ConnectFriendWizard connwiz (this); +// +// connwiz.setStartId(ConnectFriendWizard::Page_Cert); +// connwiz.exec (); +// } void HomePage::openWebHelp() { diff --git a/retroshare-gui/src/gui/HomePage.h b/retroshare-gui/src/gui/HomePage.h index b90c1081e..58a7c65b9 100644 --- a/retroshare-gui/src/gui/HomePage.h +++ b/retroshare-gui/src/gui/HomePage.h @@ -41,10 +41,10 @@ class HomePage : public MainPage public: explicit HomePage(QWidget *parent); ~HomePage(); - - virtual QIcon iconPixmap() const { return QIcon(":/icons/png/home.png") ; } //MainPage - virtual QString pageName() const { return tr("Home") ; } //MainPage - virtual QString helpText() const { return ""; } //MainPage + + virtual QIcon iconPixmap() const { return QIcon(":/icons/png/home.png") ; } //MainPage + virtual QString pageName() const { return tr("Home") ; } //MainPage + virtual QString helpText() const { return ""; } //MainPage private slots: void certContextMenu(QPoint); @@ -52,18 +52,19 @@ private slots: void runEmailClient(); void copyCert(); void saveCert(); - void addFriend(); - void webMail(); - void loadCert(); - void runStartWizard() ; + void addFriend(); + void webMail(); + //void loadCert(); void openWebHelp() ; void recommendFriends(); - void toggleIncludeAllIPs(); + void toggleIncludeAllIPs(); + void toggleUseShortFormat(); private: Ui::HomePage *ui; - - bool mIncludeAllIPs; + + bool mIncludeAllIPs; + bool mUseShortFormat; }; diff --git a/retroshare-gui/src/gui/HomePage.ui b/retroshare-gui/src/gui/HomePage.ui index da8d7b25d..fea881a6f 100644 --- a/retroshare-gui/src/gui/HomePage.ui +++ b/retroshare-gui/src/gui/HomePage.ui @@ -14,6 +14,25 @@ Form + + + + + 0 + 0 + + + + + + + :/images/logo/logo_web_nobackground.png + + + Qt::AlignCenter + + + @@ -52,7 +71,7 @@ ... - + :/icons/help_64.png:/icons/help_64.png @@ -141,134 +160,6 @@ private and secure decentralized communication platform. - - - - - 0 - 0 - - - - - - - :/images/logo/logo_web_nobackground.png - - - Qt::AlignCenter - - - - - - - Launch startup wizard - - - - :/images/tools_wizard.png:/images/tools_wizard.png - - - - - - - - - - - - - - 11 - - - - - - - Did you receive a certificate from a friend? - - - - - - - Add friends certificate - - - - :/icons/png/invite.png:/icons/png/invite.png - - - - 24 - 24 - - - - Qt::ToolButtonTextBesideIcon - - - false - - - - - - - Add certificate file - - - - :/icons/svg/folders1.svg:/icons/svg/folders1.svg - - - - 24 - 24 - - - - Qt::ToolButtonTextBesideIcon - - - false - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - @@ -316,18 +207,105 @@ private and secure decentralized communication platform. + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + 11 + + + + + + + Did you receive a certificate from a friend? + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add friends certificate + + + + :/icons/png/invite.png:/icons/png/invite.png + + + + 24 + 24 + + + + Qt::ToolButtonTextBesideIcon + + + false + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + label addFrame label_2 addframe - runStartWizard_PB frame helpframe - + diff --git a/retroshare-gui/src/gui/common/FriendList.h b/retroshare-gui/src/gui/common/FriendList.h index 4aed1c43b..3a5c15bbe 100644 --- a/retroshare-gui/src/gui/common/FriendList.h +++ b/retroshare-gui/src/gui/common/FriendList.h @@ -35,6 +35,7 @@ namespace Ui { class RSTreeWidgetItemCompareRole; class QTreeWidgetItem; class QToolButton; +struct PgpItemInfo; class FriendList : public RsAutoUpdatePage { @@ -137,6 +138,7 @@ private: bool importExportFriendlistFileDialog(QString &fileName, bool import); bool exportFriendlist(QString &fileName); bool importFriendlist(QString &fileName, bool &errorPeers, bool &errorGroups); + void manageProfileLocations(QTreeWidgetItem *gpgItem,const RsPgpId& gpg_id,PgpItemInfo& info); private slots: void groupsChanged(); diff --git a/retroshare-gui/src/gui/common/FriendListModel.cpp b/retroshare-gui/src/gui/common/FriendListModel.cpp index bbb3e7339..d7d625121 100644 --- a/retroshare-gui/src/gui/common/FriendListModel.cpp +++ b/retroshare-gui/src/gui/common/FriendListModel.cpp @@ -36,7 +36,8 @@ #include "retroshare/rsexpr.h" #include "retroshare/rsmsgs.h" -//#define DEBUG_MESSAGE_MODEL +//#define DEBUG_MODEL +//#define DEBUG_MODEL_INDEX #define IS_MESSAGE_UNREAD(flags) (flags & (RS_MSG_NEW | RS_MSG_UNREAD_BY_USER)) @@ -292,7 +293,7 @@ QModelIndex RsFriendListModel::index(int row, int column, const QModelIndex& par EntryIndex parent_index ; convertInternalIdToIndex(parent.internalId(),parent_index); -#ifdef DEBUG_MODEL +#ifdef DEBUG_MODEL_INDEX RsDbg() << "Index row=" << row << " col=" << column << " parent=" << parent << std::endl; #endif @@ -300,7 +301,7 @@ QModelIndex RsFriendListModel::index(int row, int column, const QModelIndex& par EntryIndex new_index = parent_index.child(row,mTopLevel); convertIndexToInternalId(new_index,ref); -#ifdef DEBUG_MODEL +#ifdef DEBUG_MODEL_INDEX RsDbg() << " returning " << createIndex(row,column,ref) << std::endl; #endif @@ -588,7 +589,7 @@ QVariant RsFriendListModel::onlineRole(const EntryIndex& e, int col) const QVariant RsFriendListModel::fontRole(const EntryIndex& e, int col) const { -#ifdef DEBUG_MODEL +#ifdef DEBUG_MODEL_INDEX std::cerr << " font role " << e.type << ", (" << (int)e.group_index << ","<< (int)e.profile_index << ","<< (int)e.node_index << ") col="<< col<<": " << std::endl; #endif @@ -613,7 +614,7 @@ public: QVariant RsFriendListModel::displayRole(const EntryIndex& e, int col) const { -#ifdef DEBUG_MODEL +#ifdef DEBUG_MODEL_INDEX std::cerr << " Display role " << e.type << ", (" << (int)e.group_index << ","<< (int)e.profile_index << ","<< (int)e.node_index << ") col="<< col<<": "; AutoEndel x; #endif @@ -640,7 +641,7 @@ QVariant RsFriendListModel::displayRole(const EntryIndex& e, int col) const switch(col) { case COLUMN_THREAD_NAME: -#ifdef DEBUG_MODEL +#ifdef DEBUG_MODEL_INDEX std::cerr << group->group_info.name.c_str() ; #endif @@ -663,7 +664,7 @@ QVariant RsFriendListModel::displayRole(const EntryIndex& e, int col) const if(!profile) return QVariant(); -#ifdef DEBUG_MODEL +#ifdef DEBUG_MODEL_INDEX std::cerr << profile->profile_info.name.c_str() ; #endif switch(col) @@ -683,7 +684,7 @@ QVariant RsFriendListModel::displayRole(const EntryIndex& e, int col) const if(!node) return QVariant(); -#ifdef DEBUG_MODEL +#ifdef DEBUG_MODEL_INDEX std::cerr << node->node_info.location.c_str() ; #endif switch(col) @@ -728,7 +729,7 @@ void RsFriendListModel::checkInternalData(bool force) if(mLocations[i].last_update_ts + NODE_DETAILS_UPDATE_DELAY < now) { #ifdef DEBUG_MODEL - std::cerr << "Updating ID " << node.node_info.id << std::endl; + std::cerr << "Updating ID " << mLocations[i].node_info.id << std::endl; #endif RsPeerId id(mLocations[i].node_info.id); // this avoids zeroing the id field when writing the node data rsPeers->getPeerDetails(id,mLocations[i].node_info); @@ -973,6 +974,55 @@ RsFriendListModel::EntryType RsFriendListModel::getType(const QModelIndex& i) co return e.type; } +std::map::const_iterator RsFriendListModel::createInvalidatedProfile(const RsPgpId& _pgp_id,const RsPgpFingerprint& fpr,std::map& pgp_indices,std::vector& mProfiles) +{ + // This is necessary by the time the full fingerprint is used in PeerNetItem. + + RsPgpId pgp_id; + + if(!fpr.isNull()) + pgp_id = rsPeers->pgpIdFromFingerprint(fpr); + else + pgp_id = _pgp_id; + + auto it2 = pgp_indices.find(pgp_id); + + if(it2 != pgp_indices.end()) + { + std::cerr << "(EE) asked to create an invalidated profile that already exists!" << std::endl; + return it2; + } + + HierarchicalProfileInformation hprof ; + + if(rsPeers->getGPGDetails(pgp_id,hprof.profile_info)) + { + std::cerr << "(EE) asked to create an invalidated profile that already exists!" << std::endl; + return it2; + } + + hprof.profile_info.isOnlyGPGdetail = true; + hprof.profile_info.gpg_id = pgp_id; + + hprof.profile_info.name = tr("Profile ID ").toStdString() + pgp_id.toStdString() + tr(" (Not yet validated)").toStdString(); + hprof.profile_info.issuer = pgp_id; + + hprof.profile_info.fpr = fpr; /* pgp fingerprint */ + + hprof.profile_info.trustLvl = 0; + hprof.profile_info.validLvl = 0; + + pgp_indices[pgp_id] = mProfiles.size(); + mProfiles.push_back(hprof); + + it2 = pgp_indices.find(pgp_id); + +#ifdef DEBUG_MODEL + RsDbg() << " Creating invalidated profile pgp id = " << pgp_id << " (" << hprof.profile_info.name << ") and fingerprint " << fpr << std::endl; +#endif + return it2; +} + std::map::const_iterator RsFriendListModel::checkProfileIndex(const RsPgpId& pgp_id,std::map& pgp_indices,std::vector& mProfiles,bool create) { auto it2 = pgp_indices.find(pgp_id); @@ -1042,7 +1092,11 @@ void RsFriendListModel::updateInternalData() auto it2 = checkProfileIndex(hnode.node_info.gpg_id,pgp_indices,mProfiles,hnode.node_info.gpg_id == rsPeers->getGPGOwnId()); if(it2 == pgp_indices.end()) - continue; + { + // This peer's pgp key hasn't been validated yet. We list such peers at the end. + + it2 = createInvalidatedProfile(hnode.node_info.gpg_id,hnode.node_info.fpr,pgp_indices,mProfiles); + } mProfiles[it2->second].child_node_indices.push_back(mLocations.size()); mLocations.push_back(hnode); diff --git a/retroshare-gui/src/gui/common/FriendListModel.h b/retroshare-gui/src/gui/common/FriendListModel.h index 9ff26391e..5e8d84930 100644 --- a/retroshare-gui/src/gui/common/FriendListModel.h +++ b/retroshare-gui/src/gui/common/FriendListModel.h @@ -164,6 +164,11 @@ private: std::vector& mProfiles, bool create); + std::map::const_iterator createInvalidatedProfile(const RsPgpId& pgp_id, + const RsPgpFingerprint& fpr, + std::map& pgp_indices, + std::vector& mProfiles); + QVariant sizeHintRole (const EntryIndex& e, int col) const; QVariant displayRole (const EntryIndex& e, int col) const; QVariant decorationRole(const EntryIndex& e, int col) const; diff --git a/retroshare-gui/src/gui/common/NewFriendList.cpp b/retroshare-gui/src/gui/common/NewFriendList.cpp index 04d3e444b..38e6ba3fd 100644 --- a/retroshare-gui/src/gui/common/NewFriendList.cpp +++ b/retroshare-gui/src/gui/common/NewFriendList.cpp @@ -441,7 +441,7 @@ void NewFriendList::processSettings(bool load) if (load) // load settings { // states - setShowUnconnected(!Settings->value("hideUnconnected", mProxyModel->showOfflineNodes()).toBool()); + setShowUnconnected(!Settings->value("hideUnconnected", !mProxyModel->showOfflineNodes()).toBool()); setShowState(Settings->value("showState", mModel->getDisplayStatusString()).toBool()); setShowGroups(Settings->value("showGroups", mModel->getDisplayGroups()).toBool()); @@ -458,15 +458,6 @@ void NewFriendList::processSettings(bool load) Settings->setArrayIndex(index); std::string gids = Settings->value("open").toString().toStdString(); - -// RsGroupInfo ginfo ; -// -// if(rsPeers->getGroupInfoByName(gids,ginfo)) // backward compatibility -// addGroupToExpand(ginfo.id) ; -// else if(rsPeers->getGroupInfo(RsNodeGroupId(gids),ginfo)) // backward compatibility -// addGroupToExpand(ginfo.id) ; -// else -// std::cerr << "(EE) Cannot find group info for openned group \"" << gids << "\"" << std::endl; } Settings->endArray(); } @@ -486,15 +477,6 @@ void NewFriendList::processSettings(bool load) // sort Settings->setValue("sortByState", mProxyModel->sortByState()); -// // open groups -// Settings->beginWriteArray("Groups"); -// int arrayIndex = 0; -// std::set expandedPeers; -// getExpandedGroups(expandedPeers); -// foreach (RsNodeGroupId groupId, expandedPeers) { -// Settings->setArrayIndex(arrayIndex++); -// Settings->setValue("open", QString::fromStdString(groupId.toStdString())); -// } Settings->endArray(); } } @@ -719,8 +701,6 @@ void NewFriendList::peerTreeWidgetCustomPopupMenu() contextMenu.addAction(ui->actionExportFriendlist); contextMenu.addAction(ui->actionImportFriendlist); - // contextMenu = ui->peerTreeWidget->createStandardContextMenu(contextMenu); - contextMenu.exec(QCursor::pos()); } diff --git a/retroshare-gui/src/gui/connect/ConfCertDialog.cpp b/retroshare-gui/src/gui/connect/ConfCertDialog.cpp index 907e765cf..072c966d5 100644 --- a/retroshare-gui/src/gui/connect/ConfCertDialog.cpp +++ b/retroshare-gui/src/gui/connect/ConfCertDialog.cpp @@ -89,11 +89,13 @@ ConfCertDialog::ConfCertDialog(const RsPeerId& id, const RsPgpId &pgp_id, QWidge //ui._chat_CB->hide() ; setAttribute(Qt::WA_DeleteOnClose, true); + ui._shortFormat_CB->setChecked(true); connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(applyDialog())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(ui._shouldAddSignatures_CB, SIGNAL(toggled(bool)), this, SLOT(loadInvitePage())); connect(ui._includeIPHistory_CB, SIGNAL(toggled(bool)), this, SLOT(loadInvitePage())); + connect(ui._shortFormat_CB, SIGNAL(toggled(bool)), this, SLOT(loadInvitePage())); ui.avatar->setFrameType(AvatarWidget::NORMAL_FRAME); @@ -270,14 +272,14 @@ void ConfCertDialog::loadInvitePage() // ui.userCertificateText_2->setFont(font); // ui.userCertificateText_2->setText(QString::fromUtf8(pgp_key.c_str())); - std::string invite = rsPeers->GetRetroshareInvite(detail.id, - ui._shouldAddSignatures_CB->isChecked(), - ui._includeIPHistory_CB->isChecked() - ) ; + std::string invite ; - QString infotext = getCertificateDescription(detail,ui._shouldAddSignatures_CB->isChecked(), - ui._includeIPHistory_CB->isChecked() - ); + if(ui._shortFormat_CB->isChecked()) + rsPeers->getShortInvite(invite,detail.id,true,!ui._includeIPHistory_CB->isChecked() ); + else + invite = rsPeers->GetRetroshareInvite(detail.id, ui._shouldAddSignatures_CB->isChecked(), ui._includeIPHistory_CB->isChecked() ) ; + + QString infotext = getCertificateDescription(detail,ui._shouldAddSignatures_CB->isChecked(),ui._shortFormat_CB->isChecked(), ui._includeIPHistory_CB->isChecked() ); ui.userCertificateText->setToolTip(infotext) ; @@ -291,15 +293,20 @@ void ConfCertDialog::loadInvitePage() ui.userCertificateText->setText(QString::fromUtf8(invite.c_str())); } -QString ConfCertDialog::getCertificateDescription(const RsPeerDetails& detail,bool signatures_included,bool include_additional_locators) +QString ConfCertDialog::getCertificateDescription(const RsPeerDetails& detail,bool signatures_included,bool use_short_format,bool include_additional_locators) { //infotext += tr("

Use this certificate to make new friends. Send it by email, or give it hand to hand.

") ; QString infotext = QObject::tr("

This certificate contains:") ; infotext += "

    " ; - infotext += "
  • a Profile key"; + + if(use_short_format) + infotext += "
  • a Profile fingerprint"; + else + infotext += "
  • a Profile key"; + infotext += " (" + QString::fromUtf8(detail.name.c_str()) + "@" + detail.gpg_id.toStdString().c_str()+") " ; - if(signatures_included) + if(signatures_included && !use_short_format) infotext += tr("with")+" "+QString::number(detail.gpgSigners.size()-1)+" "+tr("external signatures
  • ") ; else infotext += "" ; diff --git a/retroshare-gui/src/gui/connect/ConfCertDialog.h b/retroshare-gui/src/gui/connect/ConfCertDialog.h index a52ac3cdb..019e46598 100644 --- a/retroshare-gui/src/gui/connect/ConfCertDialog.h +++ b/retroshare-gui/src/gui/connect/ConfCertDialog.h @@ -58,7 +58,7 @@ public: /* window will destroy itself! */ } static void loadAll(); - static QString getCertificateDescription(const RsPeerDetails& det,bool signatures_included,bool extra_locators_included); + static QString getCertificateDescription(const RsPeerDetails& det, bool signatures_included, bool use_short_format, bool extra_locators_included); signals: void configChanged(); diff --git a/retroshare-gui/src/gui/connect/ConfCertDialog.ui b/retroshare-gui/src/gui/connect/ConfCertDialog.ui index 324f0fcb8..5c11ff46c 100644 --- a/retroshare-gui/src/gui/connect/ConfCertDialog.ui +++ b/retroshare-gui/src/gui/connect/ConfCertDialog.ui @@ -6,8 +6,8 @@ 0 0 - 600 - 584 + 658 + 1120 @@ -389,6 +389,13 @@ + + + + short format + + + diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp index b58e8f94d..f4d1ba6ed 100755 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp @@ -84,14 +84,14 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) : // (csoler) I'm hiding this, since it is not needed anymore with the new Home page. ui->userFrame->hide(); - ui->userFileFrame->hide(); // in homepage dropmenu now +// ui->userFileFrame->hide(); // in homepage dropmenu now // this define comes from Qt example. I don't have mac, so it wasn't tested #ifndef Q_OS_MAC setWizardStyle(ModernStyle); #endif - setStartId(Page_Intro); + setStartId(Page_Text); // at this moment I don't know, what information should be in help // setOption(HaveHelpButton, true); @@ -106,8 +106,8 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) : ui->ErrorMessagePage->registerField("errorMessage", ui->messageLabel, "text"); /* disable not used pages */ - ui->foffRadioButton->hide(); - ui->rsidRadioButton->hide(); + //ui->foffRadioButton->hide(); + //ui->rsidRadioButton->hide(); ui->cp_Label->hide(); ui->requestinfolabel->hide(); @@ -129,6 +129,8 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) : body += "\n" + GetStartedDialog::GetCutBelowText(); body += "\n\n" + QString::fromUtf8(rsPeers->GetRetroshareInvite().c_str()); + mIsShortInvite = false; + std::string advsetting; if(rsConfig->getConfigurationOption(RS_CONFIG_ADVANCED, advsetting) && (advsetting == "YES")) { @@ -147,14 +149,10 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) : switch (rsFiles->filePermDirectDL()) { case RS_FILE_PERM_DIRECT_DL_YES: - ui->_direct_transfer_CB->setIcon(QIcon(":/icons/warning_yellow_128.png")); - ui->_direct_transfer_CB->setToolTip(ui->_direct_transfer_CB->toolTip().append(tr("\nWarning: In your File-Transfer option, you select allow direct download to Yes."))); ui->_direct_transfer_CB_2->setIcon(QIcon(":/icons/warning_yellow_128.png")); ui->_direct_transfer_CB_2->setToolTip(ui->_direct_transfer_CB_2->toolTip().append(tr("\nWarning: In your File-Transfer option, you select allow direct download to Yes."))); break ; case RS_FILE_PERM_DIRECT_DL_NO: - ui->_direct_transfer_CB->setIcon(QIcon(":/icons/warning_yellow_128.png")); - ui->_direct_transfer_CB->setToolTip(ui->_direct_transfer_CB->toolTip().append(tr("\nWarning: In your File-Transfer option, you select allow direct download to No."))); ui->_direct_transfer_CB_2->setIcon(QIcon(":/icons/warning_yellow_128.png")); ui->_direct_transfer_CB_2->setToolTip(ui->_direct_transfer_CB_2->toolTip().append(tr("\nWarning: In your File-Transfer option, you select allow direct download to No."))); break ; @@ -277,7 +275,6 @@ QString ConnectFriendWizard::getErrorString(uint32_t error_code) void ConnectFriendWizard::setCertificate(const QString &certificate, bool friendRequest) { if (certificate.isEmpty()) { - setStartId(Page_Intro); return; } @@ -299,8 +296,6 @@ void ConnectFriendWizard::setCertificate(const QString &certificate, bool friend { mCertificate = certificate.toUtf8().constData(); - // Cyril: I disabled this because it seems to be not used anymore. - //setStartId(friendRequest ? Page_FriendRequest : Page_Conclusion); setStartId(Page_Conclusion); if (friendRequest){ ui->cp_Label->show(); @@ -309,7 +304,33 @@ void ConnectFriendWizard::setCertificate(const QString &certificate, bool friend ui->ConclusionPage->setSubTitle(tr("Details about the request")); } } - } else { + } + else if(rsPeers->parseShortInvite(certificate.toUtf8().constData(),peerDetails,cert_load_error_code)) + { + mIsShortInvite = true; + + if(peerDetails.id == rsPeers->getOwnId()) + { + setField("errorMessage", tr("This is your own certificate! You would not want to make friend with yourself. Wouldn't you?") ) ; + error = false; + setStartId(Page_ErrorMessage); + } + else + { + mCertificate = certificate.toUtf8().constData(); + + setStartId(Page_Conclusion); + + if (friendRequest){ + ui->cp_Label->show(); + ui->requestinfolabel->show(); + setTitleText(ui->ConclusionPage, tr("Friend request")); + ui->ConclusionPage->setSubTitle(tr("Details about the request")); + } + } + } + else + { // error message setField("errorMessage", tr("Certificate Load Failed") + ": \n\n" + getErrorString(cert_load_error_code)) ; setStartId(Page_ErrorMessage); @@ -361,9 +382,6 @@ static void fillGroups(ConnectFriendWizard *wizard, QComboBox *comboBox, const Q void ConnectFriendWizard::initializePage(int id) { switch ((Page) id) { - case Page_Intro: - ui->textRadioButton->setChecked(true); - break; case Page_Text: connect(ui->userCertHelpButton, SIGNAL( clicked()), this, SLOT(showHelpUserCert())); connect(ui->userCertIncludeSignaturesButton, SIGNAL(clicked()), this, SLOT(toggleSignatureState())); @@ -389,53 +407,9 @@ void ConnectFriendWizard::initializePage(int id) cleanFriendCert(); - break; - case Page_Cert: - connect(ui->userFileCreateButton, SIGNAL(clicked()), this, SLOT(generateCertificateCalled())); - connect(ui->friendFileNameOpenButton, SIGNAL(clicked()), this, SLOT(loadFriendCert())); - - ui->friendFileNameEdit->setAcceptFile(true); - - ui->CertificatePage->registerField("friendCertificateFile*", ui->friendFileNameEdit); - break; - case Page_Foff: - ui->userSelectionCB->addItem(tr("Any peer I've not signed")); - ui->userSelectionCB->addItem(tr("Friends of my friends who already trust me")); - ui->userSelectionCB->addItem(tr("Signed peers showing as denied")); - - ui->selectedPeersTW->setHorizontalHeaderItem(0, new QTableWidgetItem(tr(""))); - ui->selectedPeersTW->setHorizontalHeaderItem(1, new QTableWidgetItem(tr("Peer name"))); - ui->selectedPeersTW->setHorizontalHeaderItem(2, new QTableWidgetItem(tr("Also signed by"))); - ui->selectedPeersTW->setHorizontalHeaderItem(3, new QTableWidgetItem(tr("Peer id"))); - - connect(ui->makeFriendButton, SIGNAL(clicked()), this, SLOT(signAllSelectedUsers())); - connect(ui->userSelectionCB, SIGNAL(activated(int)), this, SLOT(updatePeersList(int))); - - updatePeersList(ui->userSelectionCB->currentIndex()); - - ui->FofPage->setComplete(false); - break; - case Page_Rsid: - ui->RsidPage->registerField("friendRSID*", ui->friendRsidEdit); break; case Page_WebMail: - case Page_Email: - { - ui->EmailPage->registerField("addressEdit*", ui->addressEdit); - ui->EmailPage->registerField("subjectEdit*", ui->subjectEdit); - - ui->subjectEdit->setText(tr("RetroShare Invitation")); - ui->inviteTextEdit->setPlainText(GetStartedDialog::GetInviteText()); - - QString body = ui->inviteTextEdit->toPlainText(); - - body += "\n" + GetStartedDialog::GetCutBelowText(); - body += "\n\n" + QString::fromUtf8(rsPeers->GetRetroshareInvite().c_str()); - - ui->inviteTextEdit->setPlainText(body); - } - break; case Page_ErrorMessage: break; case Page_Conclusion: @@ -589,75 +563,6 @@ void ConnectFriendWizard::initializePage(int id) } break; - case Page_FriendRequest: - { - std::cerr << "Friend request page id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl; - - ui->fr_avatar->setFrameType(AvatarWidget::NORMAL_FRAME); - setPixmap(QWizard::LogoPixmap, QPixmap(":/images/user/user_request48.png")); - - ui->fr_signGPGCheckBox->setChecked(false); - - //set the radio button to sign the GPG key - if (peerDetails.accept_connection && !peerDetails.ownsign) { - //gpg key connection is already accepted, don't propose to accept it again - ui->fr_acceptNoSignGPGCheckBox->hide(); - ui->fr_signGPGCheckBox->show(); - ui->fr_acceptNoSignGPGCheckBox->setChecked(false); - } - if (!peerDetails.accept_connection && peerDetails.ownsign) { - //gpg key is already signed, don't propose to sign it again - ui->fr_acceptNoSignGPGCheckBox->setChecked(true); - ui->fr_signGPGCheckBox->hide(); - } - if (!peerDetails.accept_connection && !peerDetails.ownsign) { - ui->fr_acceptNoSignGPGCheckBox->setChecked(true); - ui->fr_signGPGCheckBox->show(); - ui->fr_acceptNoSignGPGCheckBox->show(); - } - if (peerDetails.accept_connection && peerDetails.ownsign) { - ui->fr_acceptNoSignGPGCheckBox->setChecked(false); - ui->fr_acceptNoSignGPGCheckBox->hide(); - ui->fr_signGPGCheckBox->hide(); - } - - ui->fr_nameEdit->setText(QString::fromUtf8(peerDetails.name.c_str())); - ui->fr_emailEdit->setText(QString::fromUtf8(peerDetails.email.c_str())); - - QString loc = QString::fromUtf8(peerDetails.location.c_str()); - if (!loc.isEmpty()) - { - loc += " ("; - loc += QString::fromStdString(peerDetails.id.toStdString()); - loc += ")"; - } - else - { - if (!peerDetails.id.isNull()) - { - loc += QString::fromStdString(peerDetails.id.toStdString()); - } - } - - ui->fr_nodeEdit->setText(loc); - - ui->fr_InfoTopLabel->setText(tr("You have a friend request from") + " " + QString::fromUtf8(peerDetails.name.c_str())); - - fillGroups(this, ui->fr_groupComboBox, groupId); - } - break; - case Page_FriendRecommendations: - ui->frec_recommendList->setHeaderText(tr("Recommend friends")); - ui->frec_recommendList->setModus(FriendSelectionWidget::MODUS_CHECK); - ui->frec_recommendList->setShowType(FriendSelectionWidget::SHOW_GROUP | FriendSelectionWidget::SHOW_SSL); - ui->frec_recommendList->start(); - - ui->frec_toList->setHeaderText(tr("To")); - ui->frec_toList->setModus(FriendSelectionWidget::MODUS_CHECK); - ui->frec_toList->start(); - - ui->frec_messageEdit->setText(MessageComposer::recommendMessage()); - break; } } @@ -694,7 +599,6 @@ bool ConnectFriendWizard::validateCurrentPage() error = true; switch ((Page) currentId()) { - case Page_Intro: case Page_WebMail: break; case Page_Text: @@ -702,7 +606,8 @@ bool ConnectFriendWizard::validateCurrentPage() std::string certstr = ui->friendCertEdit->toPlainText().toUtf8().constData(); uint32_t cert_load_error_code; - if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, cert_load_error_code)) { + if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, cert_load_error_code) || rsPeers->parseShortInvite(certstr,peerDetails,cert_load_error_code)) + { mCertificate = certstr; #ifdef FRIEND_WIZARD_DEBUG std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl; @@ -721,111 +626,10 @@ bool ConnectFriendWizard::validateCurrentPage() error = false; break; } - case Page_Cert: - { - QString fn = ui->friendFileNameEdit->text(); - if (QFile::exists(fn)) { - //Todo: move read from file to p3Peers::loadCertificateFromFile - - // read from file - std::string certstr; - QFile CertFile(fn); - if (CertFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - certstr = QString(CertFile.readAll()).toStdString(); - CertFile.close(); - } - - if (certstr.empty()) { - setField("errorMessage", QString(tr("Certificate Load Failed:can't read from file %1")).arg(fn+" ") ); - error = false; - break; - } - - uint32_t cert_error_code; - if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, cert_error_code)) { - mCertificate = certstr; -#ifdef FRIEND_WIZARD_DEBUG - std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl; -#endif - - if(peerDetails.id == rsPeers->getOwnId()) - { - setField("errorMessage", tr("This is your own certificate! You would not want to make friend with yourself. Wouldn't you?") ) ; - error = false; - } - } else { - setField("errorMessage", QString(tr("Certificate Load Failed:something is wrong with %1")).arg(fn) + " : " + getErrorString(cert_error_code)); - error = false; - } - } else { - setField("errorMessage", QString(tr("Certificate Load Failed:file %1 not found")).arg(fn)); - error = false; - } - break; - } - case Page_Foff: - break; - case Page_Rsid: - { - QString rsidstring = ui->friendRsidEdit->text(); - - if (rsidstring.isEmpty()) { - return false; - } - - // search for peer id in string - RsPeerId rsidstr = PeerDefs::idFromRsid(rsidstring, false); - - if (rsidstr.isNull() || !rsPeers->getPeerDetails(rsidstr, peerDetails)) { - setField("errorMessage", tr("This Peer %1 is not available in your Network").arg(rsidstring)); - error = false; - } - break; - } - case Page_Email: - { - QString mailaddresses = ui->addressEdit->text(); - if (mailaddresses.isEmpty()) { - return false; - } - - QString body = ui->inviteTextEdit->toPlainText(); - - body += "\n" + GetStartedDialog::GetCutBelowText(); - body += "\n\n" + QString::fromUtf8(rsPeers->GetRetroshareInvite().c_str()); - - sendMail (mailaddresses, ui->subjectEdit->text(), body); - } - break; case Page_ErrorMessage: break; case Page_Conclusion: break; - case Page_FriendRequest: - break; - case Page_FriendRecommendations: - { - std::set recommendIds; - ui->frec_recommendList->selectedIds(recommendIds, false); - - if (recommendIds.empty()) { - QMessageBox::warning(this, "RetroShare", tr("Please select at least one friend for recommendation."), QMessageBox::Ok, QMessageBox::Ok); - return false; - } - - std::set toIds; - ui->frec_toList->selectedIds(toIds, false); - - if (toIds.empty()) { - QMessageBox::warning(this, "RetroShare", tr("Please select at least one friend as recipient."), QMessageBox::Ok, QMessageBox::Ok); - return false; - } - - std::set::iterator toId; - for (toId = toIds.begin(); toId != toIds.end(); ++toId) { - MessageComposer::recommendFriend(recommendIds, *toId, ui->frec_messageEdit->toHtml(), true); - } - } } return true; @@ -834,26 +638,10 @@ bool ConnectFriendWizard::validateCurrentPage() int ConnectFriendWizard::nextId() const { switch ((Page) currentId()) { - case Page_Intro: - if (ui->textRadioButton->isChecked()) return Page_Text; - if (ui->certRadioButton->isChecked()) return Page_Cert; - if (ui->foffRadioButton->isChecked()) return Page_Foff; - if (ui->rsidRadioButton->isChecked()) return Page_Rsid; - if (ui->webmailRadioButton->isChecked()) return Page_WebMail; - if (ui->emailRadioButton->isChecked()) return Page_Email; - if (ui->friendRecommendationsRadioButton->isChecked()) return Page_FriendRecommendations; - return ConnectFriendWizard::Page_Foff; - case Page_Text: - case Page_Cert: - case Page_Rsid: - return error ? ConnectFriendWizard::Page_Conclusion : ConnectFriendWizard::Page_ErrorMessage; - case Page_Foff: + case Page_Text: return Page_Conclusion; case Page_WebMail: - case Page_Email: case Page_ErrorMessage: case Page_Conclusion: - case Page_FriendRequest: - case Page_FriendRecommendations: return -1; } @@ -864,12 +652,7 @@ ServicePermissionFlags ConnectFriendWizard::serviceFlags() const { ServicePermissionFlags flags(0) ; - if (hasVisitedPage(Page_FriendRequest)) - { - if( ui->_direct_transfer_CB->isChecked()) flags |= RS_NODE_PERM_DIRECT_DL ; - if( ui->_allow_push_CB->isChecked()) flags |= RS_NODE_PERM_ALLOW_PUSH ; - if( ui->_require_WL_CB->isChecked()) flags |= RS_NODE_PERM_REQUIRE_WL ; - } else if (hasVisitedPage(Page_Conclusion)) { +if (hasVisitedPage(Page_Conclusion)) { if( ui->_direct_transfer_CB_2->isChecked()) flags |= RS_NODE_PERM_DIRECT_DL ; if( ui->_allow_push_CB_2->isChecked()) flags |= RS_NODE_PERM_ALLOW_PUSH ; if( ui->_require_WL_CB_2->isChecked()) flags |= RS_NODE_PERM_REQUIRE_WL ; @@ -888,17 +671,14 @@ void ConnectFriendWizard::accept() sign = ui->signGPGCheckBox->isChecked(); accept_connection = ui->acceptNoSignGPGCheckBox->isChecked(); add_key_to_keyring = ui->addKeyToKeyring_CB->isChecked() ; - } else if (hasVisitedPage(Page_FriendRequest)) { - std::cerr << "ConnectFriendWizard::accept() called with page friend request visited" << std::endl; - - sign = ui->fr_signGPGCheckBox->isChecked(); - accept_connection = ui->fr_acceptNoSignGPGCheckBox->isChecked(); - } else { + } else { QDialog::accept(); return; } - if (!mCertificate.empty() && add_key_to_keyring) + // add the profile pgp key to keyring + + if(!mIsShortInvite && !mCertificate.empty() && add_key_to_keyring) { RsPgpId pgp_id ; RsPeerId ssl_id ; @@ -913,33 +693,45 @@ void ConnectFriendWizard::accept() bool runProgressDialog = false; + // add the peer as friend, either with or without pgp signature validation, depending on whether we have the key or not + // Note: that is different than having a short invite or not. + + // first, set data related to profile key. + if(accept_connection && !peerDetails.gpg_id.isNull()) { std::cerr << "ConclusionPage::validatePage() accepting GPG key for connection." << std::endl; - rsPeers->addFriend(peerDetails.id, peerDetails.gpg_id,serviceFlags()) ; - rsPeers->setServicePermissionFlags(peerDetails.gpg_id,serviceFlags()) ; - if(ui->_addIPToWhiteList_CB_2->isChecked()) - { - sockaddr_storage addr ; - if(sockaddr_storage_ipv4_aton(addr,peerDetails.extAddr.c_str()) && sockaddr_storage_isValidNet(addr)) - { - std::cerr << "ConclusionPage::adding IP " << sockaddr_storage_tostring(addr) << " to whitelist." << std::endl; - rsBanList->addIpRange(addr,ui->_addIPToWhiteList_ComboBox_2->currentIndex(),RSBANLIST_TYPE_WHITELIST,std::string(tr("Added with certificate from %1").arg(ui->nameEdit->text()).toUtf8().constData())); - } - } + if(peerDetails.skip_pgp_signature_validation) + rsPeers->addSslOnlyFriend(peerDetails.id, peerDetails.gpg_id,peerDetails); + else + rsPeers->addFriend(peerDetails.id, peerDetails.gpg_id,serviceFlags()) ; + + rsPeers->setServicePermissionFlags(peerDetails.gpg_id,serviceFlags()) ; + + if(ui->_addIPToWhiteList_CB_2->isChecked()) + { + sockaddr_storage addr ; + if(sockaddr_storage_ipv4_aton(addr,peerDetails.extAddr.c_str()) && sockaddr_storage_isValidNet(addr)) + { + std::cerr << "ConclusionPage::adding IP " << sockaddr_storage_tostring(addr) << " to whitelist." << std::endl; + rsBanList->addIpRange(addr,ui->_addIPToWhiteList_ComboBox_2->currentIndex(),RSBANLIST_TYPE_WHITELIST,std::string(tr("Added with certificate from %1").arg(ui->nameEdit->text()).toUtf8().constData())); + } + } if(sign) { std::cerr << "ConclusionPage::validatePage() signing GPG key." << std::endl; rsPeers->signGPGCertificate(peerDetails.gpg_id); //bye default sign set accept_connection to true; rsPeers->setServicePermissionFlags(peerDetails.gpg_id,serviceFlags()) ; - } + } - if (!groupId.isEmpty()) - rsPeers->assignPeerToGroup(RsNodeGroupId(groupId.toStdString()), peerDetails.gpg_id, true); + if (!groupId.isEmpty()) + rsPeers->assignPeerToGroup(RsNodeGroupId(groupId.toStdString()), peerDetails.gpg_id, true); } + // Then set data related to node location + if ((accept_connection) && (!peerDetails.id.isNull())) { runProgressDialog = true; @@ -970,9 +762,7 @@ void ConnectFriendWizard::accept() rsPeers->setDynDNS(peerDetails.id, peerDetails.dyndns); } for(auto&& ipr : peerDetails.ipAddressList) - rsPeers->addPeerLocator( - peerDetails.id, - RsUrl(ipr.substr(0, ipr.find(' '))) ); + rsPeers->addPeerLocator( peerDetails.id, RsUrl(ipr.substr(0, ipr.find(' '))) ); } } @@ -985,7 +775,6 @@ void ConnectFriendWizard::accept() } NotifyQt::getInstance()->notifyListChange(NOTIFY_LIST_NEIGHBOURS,1) ; - QDialog::accept(); } @@ -1057,19 +846,23 @@ void ConnectFriendWizard::cleanFriendCert() } else { std::string cleanCert; - int error_code; + uint32_t error_code; - if (rsPeers->cleanCertificate(cert, cleanCert, error_code)) { + if (rsPeers->cleanCertificate(cert, cleanCert, mIsShortInvite, error_code)) + { certValid = true; - if (cert != cleanCert) { - disconnect(ui->friendCertEdit, SIGNAL(textChanged()), this, SLOT(friendCertChanged())); + + if (cert != cleanCert) + { QTextCursor textCursor = ui->friendCertEdit->textCursor(); - ui->friendCertEdit->setPlainText(QString::fromUtf8(cleanCert.c_str())); - ui->friendCertEdit->setTextCursor(textCursor); + + whileBlocking(ui->friendCertEdit)->setPlainText(QString::fromUtf8(cleanCert.c_str())); + whileBlocking(ui->friendCertEdit)->setTextCursor(textCursor); + ui->friendCertCleanLabel->setStyleSheet(""); - connect(ui->friendCertEdit, SIGNAL(textChanged()), this, SLOT(friendCertChanged())); } - errorMsg = tr("Certificate appears to be valid"); + errorMsg = tr("Valid certificate") + (mIsShortInvite?" (Short format)":" (plain format with profile key)"); + ui->friendCertCleanLabel->setPixmap(QPixmap(":/images/accepted16.png")); } else { if (error_code > 0) { @@ -1151,6 +944,7 @@ void ConnectFriendWizard::saveCert() ts << ui->userCertEdit->document()->toPlainText(); } +#ifdef TO_BE_REMOVED //========================== CertificatePage ================================= void ConnectFriendWizard::loadFriendCert() @@ -1330,7 +1124,9 @@ void ConnectFriendWizard::signAllSelectedUsers() //============================= RsidPage ===================================== + //============================ Emailpage ===================================== +#endif //========================= ErrorMessagePage ================================= diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.h b/retroshare-gui/src/gui/connect/ConnectFriendWizard.h index 6d9a74e57..5951fd7c2 100755 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.h +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.h @@ -50,7 +50,7 @@ class ConnectFriendWizard : public QWizard Q_PROPERTY(QString titleColor READ titleColor WRITE setTitleColor) public: - enum Page { Page_Intro, Page_Text, Page_Cert, Page_ErrorMessage, Page_Conclusion, Page_Foff, Page_Rsid, Page_WebMail, Page_Email, Page_FriendRequest, Page_FriendRecommendations }; + enum Page { Page_Text, Page_ErrorMessage, Page_Conclusion, Page_WebMail }; ConnectFriendWizard(QWidget *parent = 0); ~ConnectFriendWizard(); @@ -94,22 +94,18 @@ private slots: ServicePermissionFlags serviceFlags() const ; /* CertificatePage */ - void loadFriendCert(); - void generateCertificateCalled(); - - /* FofPage */ - void updatePeersList(int index); - void signAllSelectedUsers(); + //void loadFriendCert(); + //void generateCertificateCalled(); /* ConclusionPage */ void groupCurrentIndexChanged(int index); - + /* WebMailPage */ - void inviteGmail(); - void inviteYahoo(); - void inviteOutlook(); - void inviteAol(); - void inviteYandex(); + void inviteGmail(); + void inviteYahoo(); + void inviteOutlook(); + void inviteAol(); + void inviteYandex(); void toggleAdvanced(); @@ -119,12 +115,14 @@ private: void updateStylesheet(); void setTitleText(QWizardPage *page, const QString &title); bool AdvancedVisible; - + private: bool error; RsPeerDetails peerDetails; std::string mCertificate; + bool mIsShortInvite; + /* Stylesheet */ QString mBannerPixmap; int mTitleFontSize; @@ -141,9 +139,9 @@ private: /* ConclusionPage */ QString groupId; - + /* WebMailPage */ - QString subject; + QString subject; QString body; Ui::ConnectFriendWizard *ui; diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui b/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui index 051e7f979..8aadc22db 100644 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui @@ -6,8 +6,8 @@ 0 0 - 600 - 400 + 1139 + 1171 @@ -17,69 +17,6 @@ :/images/logo/logo_16.png:/images/logo/logo_16.png - - - Add a new Friend - - - This wizard will help you to connect to your friend(s) to RetroShare network.<br>Select how you would like to add a friend: - - - ConnectFriendWizard::Page_Intro - - - - - - Enter the certificate manually - - - - - - - &You get a certificate file from your friend - - - - - - - &Make friend with selected friends of my friends - - - - - - - Enter RetroShare ID manually - - - - - - - &Send an Invitation by Web Mail Providers - - - - - - - &Send an Invitation by Email - (Your friend will receive an email with instructions how to download RetroShare) - - - - - - - Recommend many friends to each other - - - - - RetroShare certificate @@ -386,154 +323,6 @@ - - - Certificate files - - - Use PGP certificates saved in files. - - - ConnectFriendWizard::Page_Cert - - - - - - Import friend's certificate... - - - true - - - - - - You have to generate a file with your certificate and give it to your friend. Also, you can use a file generated before. - - - true - - - - - - - Export my certificate... - - - - - - - - - - Drag and Drop your friends's certificate in this Window or specify path in the box below - - - - - - - - - - - - Browse - - - - - - - - - - Friends of friends - - - Select now who you want to make friends with. - - - ConnectFriendWizard::Page_Foff - - - - - - Show me: - - - - - - - - - - true - - - 4 - - - false - - - - - - - - - - - Make friend with these peers - - - - - - - - RetroShare ID - - - Use RetroShare ID for adding a Friend which is available in your network. - - - ConnectFriendWizard::Page_Rsid - - - - - - Add Friends RetroShare ID... - - - true - - - - - - - - Paste Friends RetroShare ID in the box below - - - - - - - Enter the RetroShare ID of your Friend, e.g. Peer@BDE8D16A46D938CF - - - - - RetroShare is better with Friends @@ -725,281 +514,6 @@ - - - Invite Friends by Email - - - Enter your friends' email addresses (separate each one with a semicolon) - - - ConnectFriendWizard::Page_Email - - - - - - - - Your friends' email addresses: - - - - - - - Enter Friends Email addresses - - - - - - - - - - - Subject: - - - - - - - - - - - - true - - - - - - - - Friend request - - - Details about the request - - - ConnectFriendWizard::Page_FriendRequest - - - - 6 - - - 6 - - - - - - - - You have a friend request from - - - - - - - - - - 96 - 96 - - - - - 96 - 96 - - - - - - - - Peer details - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - Name: - - - - - - - Name - - - - - - - Email: - - - - - - - Node: - - - - - - - Node - - - - - - - Email - - - - - - - - - - - - - - Options - - - - - - - - - 0 - 0 - - - - Add friend to group: - - - - - - - - 0 - 0 - - - - - - - - - - Authenticate friend (Sign PGP Key) - - - - - - - Add as friend to connect with - - - - - - - - - - Options - - - - - - Use as direct source, when available - - - - - - - Auto-download recommended files - - - - - - - Require whitelist clearance to connect - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - To accept the Friend Request, click the Finish button. - - - - - - - Qt::Vertical - - - - 488 - 118 - - - - - - Sorry, some error appeared @@ -1303,7 +817,7 @@ - <html><head/><body><p align="justify">Retroshare periodically checks your friend lists for browsable files matching your transfers, to establish a direct transfer. In this case, your friend knows you're downloading the file.</p><p align="justify">To prevent this behavior for this friend only, uncheck this box. You can still perform a direct transfer if you explicitly ask for it, by e.g. downloading from your friend's file list. This setting is applied to all locations of the same node.</p></body></html> + <html><head/><body><p align="justify">Retroshare periodically checks your friend lists for browsable files matching your transfers, to establish a direct transfer. In this case, your friend knows you're downloading the file.</p><p align="justify">To prevent this behavior for this friend only, uncheck this box. You can still perform a direct transfer if you explicitly ask for it, by e.g. downloading from your friend's file list. This setting is applied to all nodes with the same profile key.</p></body></html> Can be used as direct source @@ -1446,60 +960,6 @@ - - - Friend Recommendations - - - Recommend many friends to each others - - - ConnectFriendWizard::Page_FriendRecommendations - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - - - Message: - - - - - - - - 0 - 0 - - - - - - @@ -1507,23 +967,6 @@ QLabel
    gui/common/StyledLabel.h
    - - FriendSelectionWidget - QWidget -
    gui/common/FriendSelectionWidget.h
    - 1 -
    - - AvatarWidget - QLabel -
    gui/common/AvatarWidget.h
    - 1 -
    - - DropLineEdit - QLineEdit -
    gui/common/DropLineEdit.h
    -
    ConnectFriendPage QWizardPage @@ -1537,8 +980,8 @@
    - + diff --git a/retroshare-gui/src/gui/settings/CryptoPage.cpp b/retroshare-gui/src/gui/settings/CryptoPage.cpp index 9092fa587..3ac626834 100755 --- a/retroshare-gui/src/gui/settings/CryptoPage.cpp +++ b/retroshare-gui/src/gui/settings/CryptoPage.cpp @@ -41,22 +41,25 @@ CryptoPage::CryptoPage(QWidget * parent, Qt::WindowFlags flags) : ConfigPage(parent, flags) { - /* Invoke the Qt Designer generated object setup routine */ - ui.setupUi(this); + /* Invoke the Qt Designer generated object setup routine */ + ui.setupUi(this); -// connect(ui.copykeyButton, SIGNAL(clicked()), this, SLOT(copyPublicKey())); - connect(ui.saveButton, SIGNAL(clicked()), this, SLOT(fileSaveAs())); - connect(ui._includeSignatures_CB, SIGNAL(toggled(bool)), this, SLOT(load())); - connect(ui._includeAllIPs_CB, SIGNAL(toggled(bool)), this, SLOT(load())); - connect(ui._copyLink_PB, SIGNAL(clicked()), this, SLOT(copyRSLink())); - connect(ui.showStats_PB, SIGNAL(clicked()), this, SLOT(showStats())); + ui._shortFormat_CB->setChecked(true); - // hide profile manager as it causes bugs when generating a new profile. - //ui.profile_Button->hide() ; + // connect(ui.copykeyButton, SIGNAL(clicked()), this, SLOT(copyPublicKey())); + connect(ui.saveButton, SIGNAL(clicked()), this, SLOT(fileSaveAs())); + connect(ui._includeSignatures_CB, SIGNAL(toggled(bool)), this, SLOT(load())); + connect(ui._shortFormat_CB, SIGNAL(toggled(bool)), this, SLOT(load())); + connect(ui._includeAllIPs_CB, SIGNAL(toggled(bool)), this, SLOT(load())); + connect(ui._copyLink_PB, SIGNAL(clicked()), this, SLOT(copyRSLink())); + connect(ui.showStats_PB, SIGNAL(clicked()), this, SLOT(showStats())); - connect(ui.createNewNode_PB,SIGNAL(clicked()), this, SLOT(profilemanager())); + // hide profile manager as it causes bugs when generating a new profile. + //ui.profile_Button->hide() ; - ui.onlinesince->setText(DateTime::formatLongDateTime(Rshare::startupTime())); + connect(ui.createNewNode_PB,SIGNAL(clicked()), this, SLOT(profilemanager())); + + ui.onlinesince->setText(DateTime::formatLongDateTime(Rshare::startupTime())); } void CryptoPage::profilemanager() @@ -97,16 +100,21 @@ CryptoPage::~CryptoPage() void CryptoPage::load() { - ui.certplainTextEdit->setPlainText( - QString::fromUtf8( - rsPeers->GetRetroshareInvite( rsPeers->getOwnId(), ui._includeSignatures_CB->isChecked(), ui._includeAllIPs_CB->isChecked() ).c_str() - ) ); + std::string cert ; + + if(ui._shortFormat_CB->isChecked()) + rsPeers->getShortInvite(cert,rsPeers->getOwnId(), true, !ui._includeAllIPs_CB->isChecked()); + else + cert = rsPeers->GetRetroshareInvite( rsPeers->getOwnId(), ui._includeSignatures_CB->isChecked(), ui._includeAllIPs_CB->isChecked() ); + + ui.certplainTextEdit->setPlainText( QString::fromUtf8( cert.c_str() ) ); RsPeerDetails detail; rsPeers->getPeerDetails(rsPeers->getOwnId(),detail); - ui.certplainTextEdit->setToolTip(ConfCertDialog::getCertificateDescription(detail, ui._includeSignatures_CB->isChecked(), ui._includeAllIPs_CB->isChecked() )); + ui.certplainTextEdit->setToolTip(ConfCertDialog::getCertificateDescription(detail, ui._includeSignatures_CB->isChecked(), ui._shortFormat_CB->isChecked(), ui._includeAllIPs_CB->isChecked() )); } + void CryptoPage::copyRSLink() { diff --git a/retroshare-gui/src/gui/settings/CryptoPage.ui b/retroshare-gui/src/gui/settings/CryptoPage.ui index f96b3935a..0e2af06f2 100755 --- a/retroshare-gui/src/gui/settings/CryptoPage.ui +++ b/retroshare-gui/src/gui/settings/CryptoPage.ui @@ -6,7 +6,7 @@ 0 0 - 989 + 1531 678 @@ -460,6 +460,13 @@ + + + + Short format + + +