put some notes and comments in the code for what is to be done

This commit is contained in:
csoler 2016-05-17 00:00:15 -04:00
parent f44ccbe756
commit 89472d6502
6 changed files with 235 additions and 14 deletions

View File

@ -187,6 +187,7 @@ void RsGenExchange::tick()
processGroupUpdatePublish(); processGroupUpdatePublish();
processGroupDelete(); processGroupDelete();
processMessageDelete();
processRecvdData(); processRecvdData();
@ -1620,6 +1621,11 @@ void RsGenExchange::deleteGroup(uint32_t& token, RsGxsGrpItem* grpItem)
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
} }
void RsGenExchange::deleteMsgs(uint32_t& token, const GxsMsgReq& msgs)
{
token = mDataAccess->generatePublicToken();
mMsgDeletePublish.push_back(MsgDeletePublish(msgs, token));
}
void RsGenExchange::publishMsg(uint32_t& token, RsGxsMsgItem *msgItem) void RsGenExchange::publishMsg(uint32_t& token, RsGxsMsgItem *msgItem)
{ {
@ -2188,6 +2194,7 @@ void RsGenExchange::processRoutingClues()
mTrackingClues.clear() ; mTrackingClues.clear() ;
} }
void RsGenExchange::processGroupDelete() void RsGenExchange::processGroupDelete()
{ {
RS_STACK_MUTEX(mGenMtx) ; RS_STACK_MUTEX(mGenMtx) ;
@ -2234,6 +2241,52 @@ void RsGenExchange::processGroupDelete()
mGroupDeletePublish.clear(); mGroupDeletePublish.clear();
} }
void RsGenExchange::processMessageDelete()
{
RS_STACK_MUTEX(mGenMtx) ;
#ifdef TODO
typedef std::pair<bool, RsGxsGroupId> GrpNote;
std::map<uint32_t, GrpNote> toNotify;
#endif
for( std::vector<MsgDeletePublish>::iterator vit = mMsgDeletePublish.begin(); vit != mMsgDeletePublish.end(); ++vit)
{
#ifdef TODO
uint32_t token = (*vit).mToken;
const RsGxsGroupId& groupId = gdp.grpItem->meta.mGroupId;
toNotify.insert(std::make_pair( token, GrpNote(true, groupId)));
#endif
mDataStore->removeMsgs( (*vit).mMsgs );
}
#warning TODO: notify for deleted messages
#ifdef SUSPENDED
std::list<RsGxsGroupId> grpDeleted;
std::map<uint32_t, GrpNote>::iterator mit = toNotify.begin();
for(; mit != toNotify.end(); ++mit)
{
GrpNote& note = mit->second;
uint8_t status = note.first ? RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE
: RsTokenService::GXS_REQUEST_V2_STATUS_FAILED;
mGrpNotify.insert(std::make_pair(mit->first, note.second));
mDataAccess->updatePublicRequestStatus(mit->first, status);
if(note.first)
grpDeleted.push_back(note.second);
}
if(!grpDeleted.empty())
{
RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PUBLISH, false);
gc->mGrpIdList = grpDeleted;
mNotifications.push_back(gc);
}
#endif
mMsgDeletePublish.clear();
}
bool RsGenExchange::checkKeys(const RsTlvSecurityKeySet& keySet) bool RsGenExchange::checkKeys(const RsTlvSecurityKeySet& keySet)
{ {

View File

@ -535,6 +535,14 @@ public:
*/ */
void publishMsg(uint32_t& token, RsGxsMsgItem* msgItem); void publishMsg(uint32_t& token, RsGxsMsgItem* msgItem);
/*!
* Deletes the messages \n
* This will induce a related change message \n
* @param token
* @param msgs
*/
void deleteMsgs(uint32_t& token, const GxsMsgReq& msgs);
protected: protected:
/*! /*!
* This represents the group before its signature is calculated * This represents the group before its signature is calculated
@ -657,6 +665,7 @@ private:
void processGroupUpdatePublish(); void processGroupUpdatePublish();
void processGroupDelete(); void processGroupDelete();
void processMessageDelete();
void processRoutingClues(); void processRoutingClues();
void publishMsgs(); void publishMsgs();
@ -869,6 +878,7 @@ private:
std::vector<GroupUpdatePublish> mGroupUpdatePublish; std::vector<GroupUpdatePublish> mGroupUpdatePublish;
std::vector<GroupDeletePublish> mGroupDeletePublish; std::vector<GroupDeletePublish> mGroupDeletePublish;
std::vector<MsgDeletePublish> mMsgDeletePublish;
std::map<RsGxsId,std::set<RsPeerId> > mRoutingClues ; std::map<RsGxsId,std::set<RsPeerId> > mRoutingClues ;
std::list<std::pair<RsGxsMessageId,RsPeerId> > mTrackingClues ; std::list<std::pair<RsGxsMessageId,RsPeerId> > mTrackingClues ;

View File

@ -761,6 +761,7 @@ void RsGxsNetService::syncWithPeers()
RsNxsItem *encrypted_item = NULL ; RsNxsItem *encrypted_item = NULL ;
uint32_t status ; uint32_t status ;
#warning pass on the group id here so as to know which list to encrypt to (admin/members)
if(encryptSingleNxsItem(msg, encrypt_to_this_circle_id, encrypted_item, status)) if(encryptSingleNxsItem(msg, encrypt_to_this_circle_id, encrypted_item, status))
sendItem(encrypted_item) ; sendItem(encrypted_item) ;
else else
@ -1270,6 +1271,7 @@ bool RsGxsNetService::locked_createTransactionFromPending(GrpCircleIdRequestVett
RsNxsItem *encrypted_item = NULL ; RsNxsItem *encrypted_item = NULL ;
uint32_t status = RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN ; uint32_t status = RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN ;
#warning pass on the group id here so as to know which list to encrypt to (admin/members)
if(encryptSingleNxsItem(gItem, entry.mCircleId, encrypted_item,status)) if(encryptSingleNxsItem(gItem, entry.mCircleId, encrypted_item,status))
{ {
itemL.push_back(encrypted_item) ; itemL.push_back(encrypted_item) ;
@ -1321,6 +1323,7 @@ bool RsGxsNetService::locked_createTransactionFromPending(MsgCircleIdsRequestVet
RsNxsItem *encrypted_item = NULL ; RsNxsItem *encrypted_item = NULL ;
uint32_t status = RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN ; uint32_t status = RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN ;
#warning pass on the group id here so as to know which list to encrypt to (admin/members)
if(encryptSingleNxsItem(mItem,msgPend->mCircleId,encrypted_item,status)) if(encryptSingleNxsItem(mItem,msgPend->mCircleId,encrypted_item,status))
{ {
itemL.push_back(encrypted_item) ; itemL.push_back(encrypted_item) ;
@ -3678,6 +3681,7 @@ bool RsGxsNetService::encryptSingleNxsItem(RsNxsItem *item, const RsGxsCircleId&
std::list<RsGxsId> recipients ; std::list<RsGxsId> recipients ;
#warning recipients should take the destination group ID as parameter and use it to know if is will use the admin list or the members list.
if(!mCircles->recipients(destination_circle,recipients)) if(!mCircles->recipients(destination_circle,recipients))
{ {
std::cerr << " (EE) Cannot encrypt transaction: recipients list not available. Should re-try later." << std::endl; std::cerr << " (EE) Cannot encrypt transaction: recipients list not available. Should re-try later." << std::endl;
@ -4047,7 +4051,7 @@ void RsGxsNetService::handleRecvSyncGroup(RsNxsSyncGrpReqItem *item)
#endif #endif
RsNxsItem *encrypted_item = NULL ; RsNxsItem *encrypted_item = NULL ;
uint32_t status = RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN ; uint32_t status = RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN ;
#warning pass on the group id here so as to know which list to encrypt to (admin/members)
if(encryptSingleNxsItem(gItem, grpMeta->mCircleId, encrypted_item,status)) if(encryptSingleNxsItem(gItem, grpMeta->mCircleId, encrypted_item,status))
{ {
itemL.push_back(encrypted_item) ; itemL.push_back(encrypted_item) ;
@ -4471,6 +4475,7 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_
RsNxsItem *encrypted_item = NULL ; RsNxsItem *encrypted_item = NULL ;
uint32_t status = RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN ; uint32_t status = RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN ;
#warning pass on the group id here so as to know which list to encrypt to (admin/members)
if(encryptSingleNxsItem(mItem, grpMeta->mCircleId, encrypted_item,status)) if(encryptSingleNxsItem(mItem, grpMeta->mCircleId, encrypted_item,status))
{ {
itemL.push_back(encrypted_item) ; itemL.push_back(encrypted_item) ;

View File

@ -162,4 +162,15 @@ public:
uint32_t mToken; uint32_t mToken;
}; };
class MsgDeletePublish
{
public:
MsgDeletePublish(const GxsMsgReq& msgs, uint32_t token)
: mMsgs(msgs), mToken(token) {}
GxsMsgReq mMsgs ;
uint32_t mToken;
};
#endif /* GXSUTIL_H_ */ #endif /* GXSUTIL_H_ */

View File

@ -75,6 +75,7 @@ RsGxsCircles *rsGxsCircles = NULL;
#define CIRCLEREQ_CACHELOAD 0x0001 #define CIRCLEREQ_CACHELOAD 0x0001
#define CIRCLEREQ_CIRCLE_LIST 0x0002 #define CIRCLEREQ_CIRCLE_LIST 0x0002
#define CIRCLEREQ_MESSAGE_DATA 0x0003
//#define CIRCLEREQ_PGPHASH 0x0010 //#define CIRCLEREQ_PGPHASH 0x0010
//#define CIRCLEREQ_REPUTATION 0x0020 //#define CIRCLEREQ_REPUTATION 0x0020
@ -406,6 +407,11 @@ bool p3GxsCircles::isRecipient(const RsGxsCircleId &circleId, const RsGxsId& id)
return false; return false;
} }
// This function (will) use the destination group for the transaction in order to decide which list of
// keys to ecnrypt to. When sending to a self-restricted group, the list of recipients is extended to
// the admin list rather than just the members list.
#warning TODO
bool p3GxsCircles::recipients(const RsGxsCircleId& circleId, std::list<RsGxsId>& gxs_ids) bool p3GxsCircles::recipients(const RsGxsCircleId& circleId, std::list<RsGxsId>& gxs_ids)
{ {
RsGxsCircleDetails details ; RsGxsCircleDetails details ;
@ -586,13 +592,14 @@ bool RsGxsCircleCache::getAllowedPeersList(std::list<RsPgpId>& friendlist) const
bool RsGxsCircleCache::isAllowedPeer(const RsGxsId& id) const bool RsGxsCircleCache::isAllowedPeer(const RsGxsId& id) const
{ {
if(mUnprocessedPeers.find(id) != mUnprocessedPeers.end()) std::map<RsGxsId,RsGxsCircleMembershipStatus>::const_iterator it = mMembershipStatusMap.find(id) ;
return true ;
if(mAllowedGxsIds.find(id) != mAllowedGxsIds.end())
return true ;
if(it == mMembershipStatusMap.end())
return false ; return false ;
// Peers are admitted if in admin list. This is the condition for messages to propagate.
return !!(it->second & GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST) ;
} }
bool RsGxsCircleCache::isAllowedPeer(const RsPgpId &id) const bool RsGxsCircleCache::isAllowedPeer(const RsPgpId &id) const
@ -856,8 +863,7 @@ bool p3GxsCircles::cache_request_load(const RsGxsCircleId &id)
{ {
if (age < MIN_CIRCLE_LOAD_GAP) if (age < MIN_CIRCLE_LOAD_GAP)
{ {
RsTickEvent::schedule_in(CIRCLE_EVENT_CACHELOAD, RsTickEvent::schedule_in(CIRCLE_EVENT_CACHELOAD, MIN_CIRCLE_LOAD_GAP - age);
MIN_CIRCLE_LOAD_GAP - age);
return true; return true;
} }
} }
@ -1242,6 +1248,23 @@ bool p3GxsCircles::cache_reloadids(const RsGxsCircleId &circleId)
return true; return true;
} }
bool p3GxsCircles::checkCircleCacheForMembershipUpdate(RsGxsCircleCache& cache)
{
if(cache.mLastUpdatedMembership_TS + < now)
{
// this should be called regularly
uint32_t token ;
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
std::list<RsGxsGroupId> grpIds ;
grpIds.push_back(grp) ;
RsGenExchange::getTokenService()->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, grpIds);
GxsTokenQueue::queueRequest(token, CIRCLEREQ_MESSAGE_DATA);
}
return true ;
}
/* We need to AutoSubscribe if the Circle is relevent to us */ /* We need to AutoSubscribe if the Circle is relevent to us */
@ -1752,6 +1775,10 @@ void p3GxsCircles::handleResponse(uint32_t token, uint32_t req_type)
load_CircleIdList(token); load_CircleIdList(token);
break; break;
case CIRCLEREQ_MESSAGE_DATA:
processMembershipRequests(token);
break;
case CIRCLEREQ_CACHELOAD: case CIRCLEREQ_CACHELOAD:
cache_load_for_token(token); cache_load_for_token(token);
break; break;
@ -1838,8 +1865,22 @@ void p3GxsCircles::handle_event(uint32_t event_type, const std::string &elabel)
// - compatibility with self-restricted circles: // - compatibility with self-restricted circles:
// * subscription should be based on admin list, so that non subscribed peers still receive the invitation // * subscription should be based on admin list, so that non subscribed peers still receive the invitation
// //
// - two possible subscription models for circle member list (Restricted forums only propagate to members):
// 1 - list of admin who have not opposed subscription
// - solves propagation issue. Only admin see data. They can however unsubscribe using a negative req. Admin needs to remove them.
// - bad for security. Admin can refuse to remove them => back to square one
// 2 - list of admin who have also requested membership
// - propagation is ok. On restricted circle, the circle msgs/group should be sent to admin list, instead of member list.
// - solves membership issue since people need to actively be in the group.
// => choose 2
// - forum group : encrypted for Member list
// - circle group : clear / encrypted for admin list (for self-restricted)
// We decide between the two by comparing the group we're sending and the circle id it is restricted to.
//
// - Use cases // - Use cases
// * user sees group (not self restricted) and requests to subscribe => RS subscribes the group and the user can propagate the response // * user sees group (not self restricted) and requests to subscribe => RS subscribes the group and the user can propagate the response
// * user is invited to self-restricted circle. He will see it and can subscribe, so he will be in admin list and receive e.g. forum posts.
// *
// //
// - Threat model // - 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 user forges a new subscription request: NP-hard as it needs to break the RSA key of the GXS id.
@ -1848,6 +1889,23 @@ void p3GxsCircles::handle_event(uint32_t event_type, const std::string &elabel)
// => not possible. Either this existing old susbscription already exists, or it has been replaced by a more recent one, which // => 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. // 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. // * 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.
// * a malicious user creates a circle with an incriminating name/content and adds everyone in it
// => people can oppose their membership in the circle using a msg
//
//
// - the table below summarizes the various choices: forum and circle propagation when restricted to a circle, and group subscribe to the circle
//
// +------------------------------+-----------------------------+
// | User in admin list | User not in admin list |
// +-------------+------------------------------+-----------------------------+
// | User request| Forum Grp/Msg: YES | Forum Grp/Msg: NO |
// | Subscription| Circle Grp/Msg: YES/YES | Circle Grp/Msg: YES/NO |
// | | Grp Subscribed: YES | Grp Subscribed: YES |
// +-------------+------------------------------+-----------------------------+
// | No request | Forum Grp/Msg: NO | Forum Grp/Msg: NO |
// | Subscription| Circle Grp/Msg: YES/YES | Circle Grp/Msg: YES/NO |
// | | Grp Subscribed: NO | Grp Subscribed: NO |
// +-------------+------------------------------+-----------------------------+
bool p3GxsCircles::pushCircleMembershipRequest(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id,uint32_t request_type) bool p3GxsCircles::pushCircleMembershipRequest(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id,uint32_t request_type)
{ {
@ -1911,6 +1969,78 @@ bool p3GxsCircles::cancelCircleMembership(const RsGxsId& own_gxsid,const RsGxsCi
} }
bool p3GxsCircles::processMembershipRequests(uint32_t token)
{
// Go through membership request messages and process them according to the following rule:
// * for each ID only keep the latest membership request. Delete the older ones.
// * for each circle, keep a list of IDs sorted into membership categories (e.g. keep updated flags for each IDs)
// Because msg loading is async-ed, the job in split in two methods: one calls the loading, the other one handles the loaded data.
GxsMsgDataMap msgItems ;
if(!RsGenExchange::getMsgData(token, msgItems))
{
std::cerr << "(EE) Cannot get msg data for circle. Something's weird." << std::endl;
return ;
}
GxsMsgReq messages_to_delete ;
for(GxsMsgDataMap::const_iterator it(msgItems.begin());it!=msgItems.end();++it)
{
RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/
std::cerr << "Circle ID: " << it->first << std::endl;
RsGxsCircleId cid = it->first ;
if (!mCircleCache.is_cached(cid))
{
std::cerr << "(EE) Circle is not in cache!" << std::endl;
continue ;
}
// Find the circle ID in cache and process the list of messages to keep the latest order in time.
RsGxsCircleCache& data = mCircleCache.ref(cid);
for(uint32_t i=0;i<it->second.size();++i)
{
RsGxsCircleSubscriptionRequestItem *item = dynamic_cast<RsGxsCircleSubscriptionRequestItem*>(it->second[i]) ;
if(item == NULL)
{
std::cerr << "(EE) item is not a RsGxsCircleSubscriptionRequestItem. Weird." << std::endl;
continue ;
}
RsGxsCircleSubscriptionStatusInfo& info(data.mSubscriptions[item->meta.mAuthorId]) ;
if(info.subscription_TS < item->time_stamp)
{
info.subscription_TS = item->time_stamp ;
if(item->subscription_type == RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_SUBSCRIBE)
info.subscription_flags |= GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED;
else if(item->subscription_type == RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_UNSUBSCRIBE)
info.subscription_flags &= ~GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED;
else
std::cerr << "(EE) unknown subscription order type " << item->subscription_type << " for circle " << cid << " by id " << item->meta.mAuthorId << std::endl;
}
else if(info.subscription_TS > item->time_stamp)
{
std::cerr << " scheduling for deletion" << std::endl;
messages_to_delete[RsGxsGroupId(cid)].push_back(it->second[i]->meta.mMsgId) ;
}
}
data.mLastUpdatedMembershipTS = time(NULL) ;
}
RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/
mDataStore->removeMsgs(messages_to_delete);
}

View File

@ -124,6 +124,15 @@
/* Permissions is part of GroupMetaData /* Permissions is part of GroupMetaData
*/ */
class RsGxsCircleMembershipStatus
{
public:
RsGxsCircleMembershipStatus() : subscription_TS(0), subscription_flags(0) {}
time_t last_subscription_TS ;
uint32_t subscription_flags ; // combination of GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST and GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED
};
class RsGxsCircleCache class RsGxsCircleCache
{ {
public: public:
@ -153,9 +162,10 @@ class RsGxsCircleCache
std::set<RsGxsCircleId> mUnprocessedCircles; std::set<RsGxsCircleId> mUnprocessedCircles;
std::set<RsGxsCircleId> mProcessedCircles; std::set<RsGxsCircleId> mProcessedCircles;
#endif #endif
std::set<RsGxsId> mUnprocessedPeers; std::map<RsGxsId,RsGxsCircleMembershipStatus> mMembershipStatusMap;
time_t mLastUpdateMembershipTS ; // last time the subscribe messages have been requested. Should be reset when new messages arrive.
std::set<RsGxsId> mAllowedGxsIds; std::set<RsGxsId> mAllowedGxsIds; // IDs that are allowed in the circle and have requested membership. This is the official members list.
std::set<RsPgpId> mAllowedNodes; std::set<RsPgpId> mAllowedNodes;
RsPeerId mOriginator ; // peer who sent the data, in case we need to ask for ids RsPeerId mOriginator ; // peer who sent the data, in case we need to ask for ids
@ -224,6 +234,7 @@ virtual RsServiceInfo getServiceInfo();
// Load data. // Load data.
bool request_CircleIdList(); bool request_CircleIdList();
bool load_CircleIdList(uint32_t token); bool load_CircleIdList(uint32_t token);
bool processMembershipRequests(uint32_t token);
// Need some crazy arsed cache to store the circle info. // Need some crazy arsed cache to store the circle info.
// so we don't have to keep loading groups. // so we don't have to keep loading groups.
@ -237,6 +248,7 @@ virtual RsServiceInfo getServiceInfo();
bool cache_reloadids(const RsGxsCircleId &circleId); bool cache_reloadids(const RsGxsCircleId &circleId);
bool checkCircleCacheForAutoSubscribe(RsGxsCircleCache &cache); bool checkCircleCacheForAutoSubscribe(RsGxsCircleCache &cache);
bool checkCircleCacheForMembershipUpdate(RsGxsCircleCache& cache);
p3IdService *mIdentities; // Needed for constructing Circle Info, p3IdService *mIdentities; // Needed for constructing Circle Info,