From 9a869890601d2612ffe31d41fddacdc9b499e716 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 10 May 2016 21:24:31 -0400 Subject: [PATCH] first version of circle messages --- libretroshare/src/retroshare/rsgxscircles.h | 4 +- libretroshare/src/services/p3gxscircles.cc | 125 ++++++++++++++++++- libretroshare/src/services/p3gxscircles.h | 5 +- retroshare-gui/src/gui/Identity/IdDialog.cpp | 16 +-- 4 files changed, 134 insertions(+), 16 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxscircles.h b/libretroshare/src/retroshare/rsgxscircles.h index 4ebf45aca..5fa3d280f 100644 --- a/libretroshare/src/retroshare/rsgxscircles.h +++ b/libretroshare/src/retroshare/rsgxscircles.h @@ -136,8 +136,8 @@ virtual bool getCirclePersonalIdList(std::list &circleIds) = 0; /* membership management for external circles */ - virtual bool requestCircleMembership(const RsGxsCircleId& id)=0 ; - virtual bool cancelCircleMembership(const RsGxsCircleId& id)=0 ; + virtual bool requestCircleMembership(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id)=0 ; + virtual bool cancelCircleMembership(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id)=0 ; /* standard load */ virtual bool getGroupData(const uint32_t &token, std::vector &groups) = 0; diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 9746620bd..b71c7fc68 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -1819,15 +1819,132 @@ void p3GxsCircles::handle_event(uint32_t event_type, const std::string &elabel) } } +// Circle membership is requested/denied by posting a message into the cicle group, according to the following rules: +// +// - a subscription request is a RsItem (which serialises into a radix64 message, that is further signed by the group message publishing system) +// The item contains: +// * subscribe order (yes/no), boolean +// * circle ID (this is important, otherwise people can copy subscribe messages from one circle to another) +// * subscribe date +// * subscribe timeout (how long is the message kept. When timed out, the message is removed and subscription cancelled) +// +// - subscribe messages follow the following rules, which are enforced by a timer-based method: +// * subscription requests from a given user are always replaced by the last subscription request +// * a complete list of who's subscribed to a given group is kept, saved, and regularly updated when new subscribe messages are received, or when admin list is changed. +// * getGroupDetails reads this list in order to respond who's subscribed to a group. The list of +// +// - compatibility with self-restricted circles: +// * subscription should be based on admin list, so that non subscribed peers still receive the invitation +// +// - Use cases +// * user sees group (not self restricted) and requests to subscribe => RS subscribes the group and the user can propagate the response +// +// - Threat model +// * a malicious user forges a new subscription request: NP-hard as it needs to break the RSA key of the GXS id. +// * a malicious corrupts a subscription request: NP-hard. Messages are signed. +// * a malicious user copies an old subscription of someone else and inserts it in the system. +// => not possible. Either this existing old susbscription already exists, or it has been replaced by a more recent one, which +// will always replace the old one because of the date. +// * a malicious user removes someone's subscription messages. This is possible, but the mesh nature of the network will allow the message to propagate anyway. -bool p3GxsCircles::requestCircleMembership(const RsGxsCircleId& id) +bool p3GxsCircles::pushCircleMembershipRequest(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id,uint32_t request_type) { -#warning code missing here !!! + // check for some consistency + + if(request_type != RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_SUBSCRIBE && request_type != RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_UNSUBSCRIBE) + return false ; + + std::list own_ids ; + if(!rsIdentity->getOwnIds(own_ids)) + return false ; + + bool found = false ; + for(std::list::const_iterator it(own_ids.begin());it!=own_ids.end() && !found;++it) + found = ( (*it) == own_gxsid) ; + + if(!found) + return false ; + + // Create a subscribe item + + RsGxsCircleSubscriptionRequestItem s ; + + s.time_stamp = time(NULL) ; + s.subscription_request = RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_SUBSCRIBE ; + s.circle_id = id ; + s.time_out = 0 ; // means never + + // Serialise it into a base64 string + + uint32_t pktsize = s.serial_size() ; + + RsTemporaryMemory mem(s.serial_size()) ; + + if(!mem) + return false ; + + s.serialise(mem,pktsize) ; + + std::string msg ; + Radix64::encode(mem,pktsize,msg) ; + + // Create the group message to store and publish it + + RsTemporaryMemory tmpmem(RsGxsCircleId::SIZE_IN_BYTES + RsGxsId::SIZE_IN_BYTES) ; + + if(!tmpmem) + return false ; + + circle_id.serialise(tmpmem,tmpmem.size()) ; + own_gxsid.serialise(tmpmem+RsGxsCircleId::SIZE_IN_BYTES,(int)tmpmem.size()-(int)RsGxsCircleId::SIZE_IN_BYTES) ; + + RsGxsCircleMsgItem* msgItem = new RsGxsCircleMsgItem(); + msgItem->mMsg = msg; + + msgItem->meta.mGroupId = id ; + msgItem->meta.mMsgId.clear(); + msgItem->meta.mThreadId = sha1sum(tmpmem,tmpmem.size()); // make the ID from the hash of the cirle ID and the author ID + msgItem->meta.mAuthorId = own_id; + + // msgItem->meta.mParentId = ; // leave these blank + // msgItem->meta.mOrigMsgId= ; + + std::cerr << "p3GxsCircles::publishSubscribeRequest()" << std::endl; + std::cerr << " GroupId : " << circle_id << std::endl; + std::cerr << " AuthorId : " << msgItem->meta.mAuthorId << std::endl; + std::cerr << " ThreadId : " << msgItem->meta.mThreadId << std::endl; + +#warning Would be nice to wait for a few seconds before publishing, so that the user can potentially cancel a wrong request before it gets piped into the system + //RsGenExchange::publishMsg(token, msgItem); + return true; } -bool p3GxsCircles::cancelCircleMembership(const RsGxsCircleId& id) +bool p3GxsCircles::requestCircleMembership(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id) { -#warning code missing here !!! + return pushCircleMembershipRequest(own_id,circle_id,RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_SUBSCRIBE) ; +} +bool p3GxsCircles::cancelCircleMembership(const RsGxsId& own_id,const RsGxsCircleId& id) +{ + return pushCircleMembershipRequest(own_id,circle_id,RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_UNSUBSCRIBE) ; } + + + + + + + + + + + + + + + + + + + diff --git a/libretroshare/src/services/p3gxscircles.h b/libretroshare/src/services/p3gxscircles.h index f15cd2dc8..f13e0ad1b 100644 --- a/libretroshare/src/services/p3gxscircles.h +++ b/libretroshare/src/services/p3gxscircles.h @@ -194,8 +194,8 @@ virtual RsServiceInfo getServiceInfo(); /* membership management for external circles */ - virtual bool requestCircleMembership(const RsGxsCircleId& id) ; - virtual bool cancelCircleMembership(const RsGxsCircleId& id) ; + virtual bool requestCircleMembership(const RsGxsId &own_gxsid, const RsGxsCircleId& circle_id) ; + virtual bool cancelCircleMembership(const RsGxsId &own_gxsid, const RsGxsCircleId& circle_id) ; /**********************************************/ @@ -204,6 +204,7 @@ virtual RsServiceInfo getServiceInfo(); protected: + bool pushCircleMembershipRequest(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id,uint32_t request_type) ; static uint32_t circleAuthenPolicy(); /** Notifications **/ diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 51f2ebd79..1017a501b 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -436,7 +436,7 @@ void IdDialog::loadCircleGroupMeta(const uint32_t &token) if(am_I_in_circle && item->parent() != mExternalBelongingCircleItem) { #ifdef ID_DEBUG - std::cerr << " Existing group is not in subscribed items although it is subscribed. Removing." << std::endl; + std::cerr << " Existing circle is not in subscribed items although it is subscribed. Removing." << std::endl; #endif delete item ; item = NULL ; @@ -444,7 +444,7 @@ void IdDialog::loadCircleGroupMeta(const uint32_t &token) else if(!am_I_in_circle && item->parent() != mExternalOtherCircleItem) { #ifdef ID_DEBUG - std::cerr << " Existing group is not in subscribed items although it is subscribed. Removing." << std::endl; + std::cerr << " Existing circle is not in subscribed items although it is subscribed. Removing." << std::endl; #endif delete item ; item = NULL ; @@ -467,14 +467,14 @@ void IdDialog::loadCircleGroupMeta(const uint32_t &token) if(am_I_in_circle) { #ifdef ID_DEBUG - std::cerr << " adding item for group " << vit->mGroupId << " to own circles"<< std::endl; + std::cerr << " adding item for circle " << vit->mGroupId << " to own circles"<< std::endl; #endif mExternalBelongingCircleItem->addChild(item); } else { #ifdef ID_DEBUG - std::cerr << " adding item for group " << vit->mGroupId << " to others"<< std::endl; + std::cerr << " adding item for circle " << vit->mGroupId << " to others"<< std::endl; #endif mExternalOtherCircleItem->addChild(item); } @@ -482,7 +482,7 @@ void IdDialog::loadCircleGroupMeta(const uint32_t &token) else if(item->text(CIRCLEGROUP_CIRCLE_COL_GROUPNAME) != QString::fromUtf8(vit->mGroupName.c_str())) { #ifdef ID_DEBUG - std::cerr << " Existing group has a new name. Updating it in the tree." << std::endl; + std::cerr << " Existing circle has a new name. Updating it in the tree." << std::endl; #endif item->setText(CIRCLEGROUP_CIRCLE_COL_GROUPNAME, QString::fromUtf8(vit->mGroupName.c_str())); } @@ -504,17 +504,17 @@ void IdDialog::loadCircleGroupMeta(const uint32_t &token) { case GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED: item->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,QIcon(":icons/bullet_yellow_128.png")) ; - item->setToolTip(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,tr("Your request to be in this group is still pending. You need to wait the administrator to validate it.")) ; + item->setToolTip(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,tr("Your request to be in this circle is pending. You need to wait for the administrator to validate it.")) ; break ; case GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST: item->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,QIcon(":icons/bullet_blue_128.png")) ; - item->setToolTip(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,tr("You are invited to this group by the administrator. Right click to join the group.")) ; + item->setToolTip(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,tr("You are invited to this circle by the administrator. Right click to join the circle.")) ; break ; case GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST | GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED: item->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,QIcon(":icons/bullet_green_128.png")) ; - item->setToolTip(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,tr("You are a member of this group.")) ; + item->setToolTip(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,tr("You are a validated member of this circle.")) ; break ; default: