simplied/improved reputation system. Now ids can be banned based on their owner node using a single checkbox in the Person tab, with immediate effect

This commit is contained in:
csoler 2016-08-04 11:43:35 +02:00
parent c4ef4d7743
commit 7545ad4d11
11 changed files with 407 additions and 196 deletions

View File

@ -50,12 +50,13 @@ public:
};
virtual bool setOwnOpinion(const RsGxsId& key_id, const Opinion& op) =0;
virtual bool getReputationInfo(const RsGxsId& id,const RsPgpId& owner_id,ReputationInfo& info) =0 ;
virtual bool getReputationInfo(const RsGxsId& id, const RsPgpId &ownerNode, ReputationInfo& info) =0;
// parameters
virtual void setNodeAutoBanThreshold(uint32_t n) =0;
virtual uint32_t nodeAutoBanThreshold() =0;
// virtual void setNodeAutoBanThreshold(uint32_t n) =0;
// virtual uint32_t nodeAutoBanThreshold() =0;
virtual void setNodeAutoPositiveOpinionForContacts(bool b) =0;
virtual bool nodeAutoPositiveOpinionForContacts() =0;
virtual float nodeAutoBanIdentitiesLimit() =0;
@ -64,7 +65,10 @@ public:
// This one is a proxy designed to allow fast checking of a GXS id.
// it basically returns true if assessment is not ASSESSMENT_OK
virtual bool isIdentityBanned(const RsGxsId& id,const RsPgpId& owner_node) =0;
virtual bool isIdentityBanned(const RsGxsId& id) =0;
virtual bool isNodeBanned(const RsPgpId& id) =0;
virtual void banNode(const RsPgpId& id,bool b) =0;
};
// To access reputations from anywhere

View File

@ -74,6 +74,11 @@ void RsGxsReputationUpdateItem::clear()
mOpinions.clear() ;
}
void RsGxsReputationBannedNodeSetItem::clear()
{
mKnownIdentities.TlvClear();
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
@ -128,6 +133,17 @@ std::ostream& RsGxsReputationRequestItem::print(std::ostream &out, uint16_t inde
printRsItemEnd(out, "RsReputationRequestItem", indent);
return out;
}
std::ostream& RsGxsReputationBannedNodeSetItem::print(std::ostream &out, uint16_t indent)
{
printRsItemBase(out, "RsReputationBannedNodeSetItem", indent);
out << "last update: " << time(NULL) - mLastActivityTS << " secs ago." << std::endl;
out << "PGP id: " << mPgpId << std::endl;
out << "Known ids: " << mKnownIdentities.ids.size() << std::endl;
printRsItemEnd(out, "RsReputationRequestItem", indent);
return out;
}
/*************************************************************************/
uint32_t RsGxsReputationConfigItem::serial_size() const
@ -135,8 +151,8 @@ uint32_t RsGxsReputationConfigItem::serial_size() const
uint32_t s = 8; /* header */
s += mPeerId.serial_size() ; // PeerId
s += 4 ; // mLatestUpdate
s += 4 ; // mLastQuery
s += 4 ; // mLatestUpdate
s += 4 ; // mLastQuery
return s ;
}
@ -158,6 +174,17 @@ uint32_t RsGxsReputationSetItem::serial_size() const
return s ;
}
uint32_t RsGxsReputationBannedNodeSetItem::serial_size() const
{
uint32_t s = 8; /* header */
s += RsPgpId::serial_size() ; // mPgpId
s += 4 ; // mLastActivityTS;
s += mKnownIdentities.TlvSize(); // mKnownIdentities
return s ;
}
uint32_t RsGxsReputationUpdateItem::serial_size() const
{
uint32_t s = 8; /* header */
@ -236,6 +263,29 @@ bool RsGxsReputationSetItem::serialise(void *data, uint32_t& pktsize) const
return ok;
}
bool RsGxsReputationBannedNodeSetItem::serialise(void *data, uint32_t& pktsize) const
{
uint32_t tlvsize ;
uint32_t offset=0;
if(!serialise_header(data,pktsize,tlvsize,offset))
return false ;
bool ok = true;
ok &= mPgpId.serialise(data, tlvsize, offset) ;
ok &= setRawUInt32(data, tlvsize, &offset, mLastActivityTS);
ok &= mKnownIdentities.SetTlv(data, tlvsize, &offset) ;
if (offset != tlvsize)
{
ok = false;
std::cerr << "RsGxsReputationSetItem::serialisedata() size error! " << std::endl;
}
return ok;
}
bool RsGxsReputationUpdateItem::serialise(void *data, uint32_t& pktsize) const
{
uint32_t tlvsize ;
@ -308,7 +358,28 @@ RsGxsReputationConfigItem *RsGxsReputationSerialiser::deserialiseReputationConfi
return item;
}
RsGxsReputationBannedNodeSetItem *RsGxsReputationSerialiser::deserialiseReputationBannedNodeSetItem(void *data,uint32_t size)
{
uint32_t offset = 8; // skip the header
uint32_t rssize = getRsItemSize(data);
bool ok = true ;
RsGxsReputationBannedNodeSetItem *item = new RsGxsReputationBannedNodeSetItem() ;
/* add mandatory parts first */
ok &= item->mPgpId.deserialise(data, size, offset) ;
ok &= getRawUInt32(data, size, &offset, &item->mLastActivityTS);
ok &= item->mKnownIdentities.GetTlv(data,size,&offset) ;
if (offset != rssize || !ok)
{
std::cerr << __PRETTY_FUNCTION__ << ": error while deserialising! Item will be dropped." << std::endl;
delete item;
return NULL ;
}
return item;
}
RsGxsReputationSetItem *RsGxsReputationSerialiser::deserialiseReputationSetItem_deprecated(void *data,uint32_t tlvsize)
{
uint32_t offset = 8; // skip the header
@ -462,11 +533,12 @@ RsItem *RsGxsReputationSerialiser::deserialise(void *data, uint32_t *pktsize)
switch(getRsItemSubType(rstype))
{
case RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM : return deserialiseReputationSetItem (data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM_deprecated: return deserialiseReputationSetItem_deprecated(data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_UPDATE_ITEM : return deserialiseReputationUpdateItem (data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_REQUEST_ITEM : return deserialiseReputationRequestItem (data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_CONFIG_ITEM : return deserialiseReputationConfigItem (data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM : return deserialiseReputationSetItem (data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM_deprecated : return deserialiseReputationSetItem_deprecated(data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_BANNED_NODE_SET_ITEM: return deserialiseReputationBannedNodeSetItem(data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_UPDATE_ITEM : return deserialiseReputationUpdateItem (data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_REQUEST_ITEM : return deserialiseReputationRequestItem (data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_CONFIG_ITEM : return deserialiseReputationConfigItem (data, *pktsize);
default:
std::cerr << "RsGxsReputationSerialiser::deserialise(): unknown item subtype " << std::hex<< rstype << std::dec << std::endl;

View File

@ -30,6 +30,7 @@
#include "serialiser/rsserviceids.h"
#include "serialiser/rsserial.h"
#include "serialiser/rstlvidset.h"
#include "retroshare/rsgxsifacetypes.h"
#define RS_PKT_SUBTYPE_GXS_REPUTATION_CONFIG_ITEM 0x01
@ -38,6 +39,7 @@
#define RS_PKT_SUBTYPE_GXS_REPUTATION_REQUEST_ITEM 0x04
#define RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM_deprecated 0x05
#define RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM 0x06
#define RS_PKT_SUBTYPE_GXS_REPUTATION_BANNED_NODE_SET_ITEM 0x07
/**************************************************************************/
class RsReputationItem: public RsItem
@ -118,6 +120,24 @@ public:
RsPgpId mOwnerNodeId;
std::map<RsPeerId, uint32_t> mOpinions; // RsPeerId -> Opinion.
};
class RsGxsReputationBannedNodeSetItem: public RsReputationItem
{
public:
RsGxsReputationBannedNodeSetItem() :RsReputationItem(RS_PKT_SUBTYPE_GXS_REPUTATION_BANNED_NODE_SET_ITEM) {}
virtual ~RsGxsReputationBannedNodeSetItem() {}
virtual void clear();
std::ostream &print(std::ostream &out, uint16_t indent = 0);
virtual bool serialise(void *data,uint32_t& size) const ;
virtual uint32_t serial_size() const ;
RsPgpId mPgpId ;
uint32_t mLastActivityTS ;
RsTlvGxsIdSet mKnownIdentities ;
};
class RsGxsReputationUpdateItem: public RsReputationItem
{
public:
@ -173,6 +193,7 @@ private:
static RsGxsReputationSetItem *deserialiseReputationSetItem_deprecated (void *data, uint32_t size);
static RsGxsReputationUpdateItem *deserialiseReputationUpdateItem (void *data, uint32_t size);
static RsGxsReputationRequestItem *deserialiseReputationRequestItem (void *data, uint32_t size);
static RsGxsReputationBannedNodeSetItem *deserialiseReputationBannedNodeSetItem (void *data, uint32_t size);
};
/**************************************************************************/

View File

@ -139,6 +139,7 @@ static const uint32_t PGP_AUTO_BAN_THRESHOLD_DEFAULT = 2 ; // above t
static const uint32_t IDENTITY_FLAGS_UPDATE_DELAY = 100 ; //
static const uint32_t BANNED_NODES_UPDATE_DELAY = 313 ; // update approx every 5 mins. Chosen to not be a multiple of IDENTITY_FLAGS_UPDATE_DELAY
static const uint32_t REPUTATION_INFO_KEEP_DELAY = 86400*35; // remove old reputation info 5 days after last usage limit, in case the ID would come back..
static const uint32_t BANNED_NODES_INACTIVITY_KEEP = 86400*60; // remove all info about banned nodes after 2 months of inactivity
p3GxsReputation::p3GxsReputation(p3LinkMgr *lm)
:p3Service(), p3Config(),
@ -146,7 +147,7 @@ p3GxsReputation::p3GxsReputation(p3LinkMgr *lm)
{
addSerialType(new RsGxsReputationSerialiser());
mPgpAutoBanThreshold = PGP_AUTO_BAN_THRESHOLD_DEFAULT ;
//mPgpAutoBanThreshold = PGP_AUTO_BAN_THRESHOLD_DEFAULT ;
mRequestTime = 0;
mStoreTime = 0;
mReputationsUpdated = false;
@ -154,6 +155,7 @@ p3GxsReputation::p3GxsReputation(p3LinkMgr *lm)
mLastIdentityFlagsUpdate = time(NULL) - 3;
mAverageActiveFriends = 0 ;
mLastBannedNodesUpdate = 0 ;
mBannedNodesProxyNeedsUpdate = false;
mAutoBanIdentitiesLimit = REPUTATION_ASSESSMENT_THRESHOLD_X1;
mAutoSetPositiveOptionToContacts = true; // default
@ -200,9 +202,15 @@ int p3GxsReputation::tick()
if(now > BANNED_NODES_UPDATE_DELAY+mLastBannedNodesUpdate) // 613 is not a multiple of 100, to avoid piling up work
{
updateIdentityFlags() ; // needed before updateBannedNodesList!
updateBannedNodesList();
updateBannedNodesProxy();
mLastBannedNodesUpdate = now ;
}
if(mBannedNodesProxyNeedsUpdate)
{
updateBannedNodesProxy();
mBannedNodesProxyNeedsUpdate = false ;
}
#ifdef DEBUG_REPUTATION
static time_t last_debug_print = time(NULL) ;
@ -216,21 +224,21 @@ int p3GxsReputation::tick()
return 0;
}
void p3GxsReputation::setNodeAutoBanThreshold(uint32_t n)
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
if(n != mPgpAutoBanThreshold)
{
mLastBannedNodesUpdate = 0 ;
mPgpAutoBanThreshold = n ;
IndicateConfigChanged() ;
}
}
uint32_t p3GxsReputation::nodeAutoBanThreshold()
{
return mPgpAutoBanThreshold ;
}
// void p3GxsReputation::setNodeAutoBanThreshold(uint32_t n)
// {
// RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
//
// if(n != mPgpAutoBanThreshold)
// {
// mLastBannedNodesUpdate = 0 ;
// mPgpAutoBanThreshold = n ;
// IndicateConfigChanged() ;
// }
// }
// uint32_t p3GxsReputation::nodeAutoBanThreshold()
// {
// return mPgpAutoBanThreshold ;
// }
void p3GxsReputation::setNodeAutoPositiveOpinionForContacts(bool b)
{
@ -284,33 +292,21 @@ class ZeroInitCnt
operator uint32_t() const { return cnt ; }
};
void p3GxsReputation::updateBannedNodesList()
void p3GxsReputation::updateBannedNodesProxy()
{
#ifdef DEBUG_REPUTATION
std::cerr << "Updating PGP ban list based on signed GxsIds to ban" << std::endl;
#endif
std::map<RsGxsId, Reputation> tmpreps ;
//#ifdef DEBUG_REPUTATION
// std::cerr << "Updating PGP ban list based on signed GxsIds to ban. Ban threshold = " << mPgpAutoBanThreshold << std::endl;
//#endif
// This function keeps the Banned GXS id proxy up to date.
//
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
tmpreps = mReputations ;
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
std::map<RsPgpId,ZeroInitCnt> pgp_ids_to_ban ;
mPerNodeBannedIdsProxy.clear();
for( std::map<RsGxsId, Reputation>::iterator rit = tmpreps.begin();rit!=tmpreps.end();++rit)
if((rit->second.mIdentityFlags & REPUTATION_IDENTITY_FLAG_PGP_LINKED) && !rit->second.mOwnerNode.isNull() && rit->second.mOwnOpinion == p3GxsReputation::OPINION_NEGATIVE)
++pgp_ids_to_ban[rit->second.mOwnerNode] ;
mBannedPgpIds.clear() ;
if(mPgpAutoBanThreshold > 0)
for(std::map<RsPgpId,ZeroInitCnt>::const_iterator it(pgp_ids_to_ban.begin());it!=pgp_ids_to_ban.end();++it)
{
#ifdef DEBUG_REPUTATION
std::cerr << "PGP Id: " << it->first << ". Ban count=" << it->second << " - " << (( it->second >= mPgpAutoBanThreshold)?"Banned!":"OK" ) << std::endl;
#endif
if(it->second >= mPgpAutoBanThreshold)
mBannedPgpIds.insert(it->first) ;
}
for( std::map<RsPgpId, BannedNodeInfo>::iterator rit = mBannedPgpIds.begin();rit!=mBannedPgpIds.end();++rit)
for(std::set<RsGxsId>::const_iterator it(rit->second.known_identities.begin());it!=rit->second.known_identities.end();++it)
mPerNodeBannedIdsProxy.insert(*it) ;
}
void p3GxsReputation::updateIdentityFlags()
@ -326,7 +322,7 @@ void p3GxsReputation::updateIdentityFlags()
#endif
for( std::map<RsGxsId, Reputation>::iterator rit = mReputations.begin();rit!=mReputations.end();++rit)
if(rit->second.mIdentityFlags & REPUTATION_IDENTITY_FLAG_NEEDS_UPDATE)
if( (rit->second.mIdentityFlags & REPUTATION_IDENTITY_FLAG_NEEDS_UPDATE) && (mPerNodeBannedIdsProxy.find(rit->first) == mPerNodeBannedIdsProxy.end()))
to_update.push_back(rit->first) ;
}
@ -387,9 +383,9 @@ void p3GxsReputation::cleanup()
#endif
std::cerr << "p3GxsReputation::cleanup() " << std::endl;
// remove optionions about identities that do not exist anymore. That will in particular avoid asking p3idservice about deleted
// identities, which would cause an excess of hits to the database.
// We do it in two steps to avoid a deadlock when calling rsIdentity from here.
// Remove opinions about identities that do not exist anymore. That will in particular avoid asking p3idservice about deleted
// identities, which would cause an excess of hits to the database. We do it in two steps to avoid a deadlock when calling rsIdentity from here.
// Also, neutral opinions for banned PGP linked nodes are kept, so as to be able to not request them again.
bool updated = false ;
time_t now = time(NULL) ;
@ -400,15 +396,15 @@ void p3GxsReputation::cleanup()
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
for(std::map<RsGxsId,Reputation>::iterator it(mReputations.begin());it!=mReputations.end();)
if(it->second.mOpinions.empty() && it->second.mOwnOpinion == RsReputations::OPINION_NEUTRAL)
if(it->second.mOpinions.empty() && it->second.mOwnOpinion == RsReputations::OPINION_NEUTRAL && (it->second.mOwnerNode.isNull()))
{
std::map<RsGxsId,Reputation>::iterator tmp(it) ;
#ifdef DEBUG_REPUTATION
std::cerr << " ID " << it->first << ": own is neutral and no opinions from friends => remove entry" << std::endl;
#endif
std::map<RsGxsId,Reputation>::iterator tmp(it) ;
++tmp ;
mReputations.erase(it) ;
it = tmp ;
#ifdef DEBUG_REPUTATION
std::cerr << " ID " << it->first << ": own is neutral and no opinions from friends => remove entry" << std::endl;
#endif
updated = true ;
}
else
@ -424,12 +420,31 @@ void p3GxsReputation::cleanup()
#ifdef DEBUG_REPUTATION
std::cerr << " Identity " << *it << " has a last usage TS of " << now - rsIdentity->getLastUsageTS(*it) << " secs ago: deleting it." << std::endl;
#endif
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
mReputations.erase(*it) ;
updated = true ;
}
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
for(std::map<RsPgpId,BannedNodeInfo>::iterator it(mBannedPgpIds.begin());it!=mBannedPgpIds.end();)
if(it->second.last_activity_TS + BANNED_NODES_INACTIVITY_KEEP < now)
{
#ifdef DEBUG_REPUTATION
std::cerr << " Removing all info about banned node " << it->first << " by lack of activity." << std::endl;
#endif
std::map<RsPgpId,BannedNodeInfo>::iterator tmp(it ) ;
++tmp ;
mBannedPgpIds.erase(it) ;
it = tmp ;
updated = true ;
}
else
++it ;
}
if(updated)
IndicateConfigChanged() ;
}
@ -762,37 +777,63 @@ bool p3GxsReputation::updateLatestUpdate(RsPeerId peerid,time_t latest_update)
* Opinion
****/
bool p3GxsReputation::getReputationInfo(const RsGxsId& gxsid, const RsPgpId& owner_id, RsReputations::ReputationInfo& info)
bool p3GxsReputation::getReputationInfo(const RsGxsId& gxsid, const RsPgpId& ownerNode, RsReputations::ReputationInfo& info)
{
if(gxsid.isNull())
return false ;
time_t now = time(NULL) ;
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
#ifdef DEBUG_REPUTATION
#ifdef DEBUG_REPUTATION2
std::cerr << "getReputationInfo() for " << gxsid << std::endl;
#endif
std::map<RsGxsId,Reputation>::const_iterator it = mReputations.find(gxsid) ;
std::map<RsGxsId,Reputation>::iterator it = mReputations.find(gxsid) ;
RsPgpId owner_id ;
if(it == mReputations.end())
{
info.mOwnOpinion = RsReputations::OPINION_NEUTRAL ;
info.mOverallReputationScore = RsReputations::REPUTATION_THRESHOLD_DEFAULT ;
info.mFriendAverage = REPUTATION_THRESHOLD_DEFAULT ;
info.mFriendAverage = REPUTATION_THRESHOLD_DEFAULT ;
owner_id = ownerNode ;
}
else
{
const Reputation& rep(it->second) ;
Reputation& rep(it->second) ;
info.mOwnOpinion = RsReputations::Opinion(rep.mOwnOpinion) ;
info.mOverallReputationScore = rep.mReputation ;
info.mFriendAverage = rep.mFriendAverage ;
if(rep.mOwnerNode.isNull())
rep.mOwnerNode = ownerNode ;
owner_id = rep.mOwnerNode ;
}
if(!owner_id.isNull() && (mBannedPgpIds.find(owner_id) != mBannedPgpIds.end()))
std::map<RsPgpId,BannedNodeInfo>::iterator it2 ;
if(!owner_id.isNull() && (it2 = mBannedPgpIds.find(owner_id))!=mBannedPgpIds.end())
{
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputations: identity " << gxsid << " is banned because owner node ID " << owner_id << " is banned." << std::endl;
if(it2->second.known_identities.find(gxsid) == it2->second.known_identities.end())
{
it2->second.known_identities.insert(gxsid) ;
it2->second.last_activity_TS = now ;
mBannedNodesProxyNeedsUpdate = true ;
}
info.mAssessment = RsReputations::ASSESSMENT_BAD ;
#ifdef DEBUG_REPUTATION2
std::cerr << "p3GxsReputations: identity " << gxsid << " is banned because owner node ID " << owner_id << " is banned (found in banned nodes list)." << std::endl;
#endif
}
else if(mPerNodeBannedIdsProxy.find(gxsid) != mPerNodeBannedIdsProxy.end())
{
#ifdef DEBUG_REPUTATION2
std::cerr << "p3GxsReputations: identity " << gxsid << " is banned because owner node ID " << owner_id << " is banned (found in proxy)." << std::endl;
#endif
info.mAssessment = RsReputations::ASSESSMENT_BAD ;
}
@ -801,18 +842,46 @@ bool p3GxsReputation::getReputationInfo(const RsGxsId& gxsid, const RsPgpId& own
else
info.mAssessment = RsReputations::ASSESSMENT_OK ;
#ifdef DEBUG_REPUTATION
std::cerr << " information present. OwnOp = " << info.mOwnOpinion << ", overall score=" << info.mAssessment << std::endl;
#ifdef DEBUG_REPUTATION2
std::cerr << " information present. OwnOp = " << info.mOwnOpinion << ", owner node=" << owner_id << ", overall score=" << info.mAssessment << std::endl;
#endif
return true ;
}
bool p3GxsReputation::isIdentityBanned(const RsGxsId &id,const RsPgpId& owner_node)
void p3GxsReputation::banNode(const RsPgpId& id,bool b)
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
if(b)
{
if(mBannedPgpIds.find(id) == mBannedPgpIds.end())
{
mBannedPgpIds[id] = BannedNodeInfo() ;
IndicateConfigChanged();
}
}
else
{
if(mBannedPgpIds.find(id) != mBannedPgpIds.end())
{
mBannedPgpIds.erase(id) ;
IndicateConfigChanged();
}
}
}
bool p3GxsReputation::isNodeBanned(const RsPgpId& id)
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
return mBannedPgpIds.find(id) != mBannedPgpIds.end();
}
bool p3GxsReputation::isIdentityBanned(const RsGxsId &id)
{
RsReputations::ReputationInfo info ;
if(!getReputationInfo(id,owner_node,info))
if(!getReputationInfo(id,RsPgpId(),info))
return false ;
#ifdef DEBUG_REPUTATION
@ -943,12 +1012,23 @@ bool p3GxsReputation::saveList(bool& cleanup, std::list<RsItem*> &savelist)
savelist.push_back(item);
count++;
}
for(std::map<RsPgpId,BannedNodeInfo>::const_iterator it(mBannedPgpIds.begin());it!=mBannedPgpIds.end();++it)
{
RsGxsReputationBannedNodeSetItem *item = new RsGxsReputationBannedNodeSetItem();
item->mPgpId = it->first ;
item->mLastActivityTS = it->second.last_activity_TS;
item->mKnownIdentities.ids = it->second.known_identities;
savelist.push_back(item) ;
}
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ;
RsTlvKeyValue kv;
kv.key = "AUTO_BAN_NODES_THRESHOLD" ;
rs_sprintf(kv.value, "%d", mPgpAutoBanThreshold);
vitem->tlvkvs.pairs.push_back(kv) ;
// kv.key = "AUTO_BAN_NODES_THRESHOLD" ;
// rs_sprintf(kv.value, "%d", mPgpAutoBanThreshold);
// vitem->tlvkvs.pairs.push_back(kv) ;
kv.key = "AUTO_BAN_IDENTITIES_THRESHOLD" ;
rs_sprintf(kv.value, "%f", mAutoBanIdentitiesLimit);
@ -971,7 +1051,7 @@ void p3GxsReputation::saveDone()
bool p3GxsReputation::loadList(std::list<RsItem *>& loadList)
{
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::saveList()" << std::endl;
std::cerr << "p3GxsReputation::loadList()" << std::endl;
#endif
std::list<RsItem *>::iterator it;
std::set<RsPeerId> peerSet;
@ -990,28 +1070,39 @@ bool p3GxsReputation::loadList(std::list<RsItem *>& loadList)
config.mLatestUpdate = item->mLatestUpdate;
config.mLastQuery = 0;
peerSet.insert(peerId);
peerSet.insert(peerId);
}
RsGxsReputationSetItem *set = dynamic_cast<RsGxsReputationSetItem *>(*it);
if (set)
loadReputationSet(set, peerSet);
RsGxsReputationBannedNodeSetItem *itm2 = dynamic_cast<RsGxsReputationBannedNodeSetItem*>(*it) ;
if(itm2 != NULL)
{
BannedNodeInfo& info(mBannedPgpIds[itm2->mPgpId]) ;
info.last_activity_TS = itm2->mLastActivityTS ;
info.known_identities = itm2->mKnownIdentities.ids ;
}
RsConfigKeyValueSet *vitem = dynamic_cast<RsConfigKeyValueSet *>(*it);
if(vitem)
for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit)
{
if(kit->key == "AUTO_BAN_NODES_THRESHOLD")
{
int val ;
if (sscanf(kit->value.c_str(), "%d", &val) == 1)
{
mPgpAutoBanThreshold = val ;
std::cerr << "Setting AutoBanNode threshold to " << val << std::endl ;
mLastBannedNodesUpdate = 0 ; // force update
}
};
// if(kit->key == "AUTO_BAN_NODES_THRESHOLD")
// {
// int val ;
// if (sscanf(kit->value.c_str(), "%d", &val) == 1)
// {
// mPgpAutoBanThreshold = val ;
// std::cerr << "Setting AutoBanNode threshold to " << val << std::endl ;
// mLastBannedNodesUpdate = 0 ; // force update
// }
// };
if(kit->key == "AUTO_BAN_IDENTITIES_THRESHOLD")
{
float val ;
@ -1034,53 +1125,62 @@ bool p3GxsReputation::loadList(std::list<RsItem *>& loadList)
delete (*it);
}
updateBannedNodesProxy();
loadList.clear() ;
return true;
}
bool p3GxsReputation::loadReputationSet(RsGxsReputationSetItem *item, const std::set<RsPeerId> &peerSet)
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
std::map<RsGxsId, Reputation>::iterator rit;
std::map<RsGxsId, Reputation>::iterator rit;
if(item->mGxsId.isNull()) // just a protection against potential errors having put 00000 into ids.
if(item->mGxsId.isNull()) // just a protection against potential errors having put 00000 into ids.
return false ;
/* find matching Reputation */
RsGxsId gxsId(item->mGxsId);
rit = mReputations.find(gxsId);
if (rit != mReputations.end())
{
std::cerr << "ERROR";
std::cerr << std::endl;
}
Reputation &reputation = mReputations[gxsId];
/* find matching Reputation */
RsGxsId gxsId(item->mGxsId);
rit = mReputations.find(gxsId);
if (rit != mReputations.end())
{
std::cerr << "ERROR";
std::cerr << std::endl;
}
// install opinions.
std::map<RsPeerId, uint32_t>::const_iterator oit;
for(oit = item->mOpinions.begin(); oit != item->mOpinions.end(); ++oit)
{
// expensive ... but necessary.
RsPeerId peerId(oit->first);
if (peerSet.end() != peerSet.find(peerId))
reputation.mOpinions[peerId] = safe_convert_uint32t_to_opinion(oit->second);
}
Reputation &reputation = mReputations[gxsId];
reputation.mOwnOpinion = item->mOwnOpinion;
reputation.mOwnOpinionTs = item->mOwnOpinionTS;
reputation.mOwnerNode = item->mOwnerNodeId;
// install opinions.
std::map<RsPeerId, uint32_t>::const_iterator oit;
for(oit = item->mOpinions.begin(); oit != item->mOpinions.end(); ++oit)
{
// expensive ... but necessary.
RsPeerId peerId(oit->first);
if (peerSet.end() != peerSet.find(peerId))
reputation.mOpinions[peerId] = safe_convert_uint32t_to_opinion(oit->second);
}
// if dropping entries has changed the score -> must update.
//float old_reputation = reputation.mReputation ;
//mUpdatedReputations.insert(gxsId) ;
reputation.updateReputation() ;
reputation.mOwnOpinion = item->mOwnOpinion;
reputation.mOwnOpinionTs = item->mOwnOpinionTS;
reputation.mOwnerNode = item->mOwnerNodeId;
reputation.mIdentityFlags = item->mIdentityFlags | REPUTATION_IDENTITY_FLAG_NEEDS_UPDATE;
mUpdated.insert(std::make_pair(reputation.mOwnOpinionTs, gxsId));
return true;
// if dropping entries has changed the score -> must update.
//float old_reputation = reputation.mReputation ;
//mUpdatedReputations.insert(gxsId) ;
reputation.updateReputation() ;
mUpdated.insert(std::make_pair(reputation.mOwnOpinionTs, gxsId));
}
#ifdef DEBUG_REPUTATION
RsReputations::ReputationInfo info ;
getReputationInfo(item->mGxsId,item->mOwnerNodeId,info) ;
std::cerr << item->mGxsId << " : own: " << info.mOwnOpinion << ", owner node: " << item->mOwnerNodeId << ", assessment: " << ((info.mAssessment==ASSESSMENT_BAD)?"BAD":"OK") << std::endl;
#endif
return true;
}
@ -1260,16 +1360,33 @@ void p3GxsReputation::debug_print()
{
std::cerr << "Reputations database: " << std::endl;
std::cerr << " Average number of peers: " << mAverageActiveFriends << std::endl;
std::cerr << " GXS ID data: " << std::endl;
time_t now = time(NULL) ;
for(std::map<RsGxsId,Reputation>::const_iterator it(mReputations.begin());it!=mReputations.end();++it)
{
std::cerr << " ID=" << it->first << ", own: " << it->second.mOwnOpinion << ", Friend average: " << it->second.mFriendAverage << ", global_score: " << it->second.mReputation
<< ", last own update: " << now - it->second.mOwnOpinionTs << " secs ago." << std::endl;
for(std::map<RsPeerId,RsReputations::Opinion>::const_iterator it2(it->second.mOpinions.begin());it2!=it->second.mOpinions.end();++it2)
std::cerr << " " << it->first << ": own: " << it->second.mOwnOpinion << ", Friend average: " << it->second.mFriendAverage << ", global_score: " << it->second.mReputation
<< ", last own update: " << now - it->second.mOwnOpinionTs << " secs ago." << std::endl;
#ifdef DEBUG_REPUTATION2
for(std::map<RsPeerId,RsReputations::Opinion>::const_iterator it2(it->second.mOpinions.begin());it2!=it->second.mOpinions.end();++it2)
std::cerr << " " << it2->first << ": " << it2->second << std::endl;
#endif
}
std::cerr << " Banned RS nodes by ID: " << std::endl;
for(std::map<RsPgpId,BannedNodeInfo>::const_iterator it(mBannedPgpIds.begin());it!=mBannedPgpIds.end();++it)
{
std::cerr << " Node " << it->first << ", last activity: " << now - it->second.last_activity_TS << " secs ago." << std::endl;
for(std::set<RsGxsId>::const_iterator it2(it->second.known_identities.begin());it2!=it->second.known_identities.end();++it2)
std::cerr << " " << *it2 << std::endl;
}
std::cerr << " Per node Banned GXSIds proxy: " << std::endl;
for(std::set<RsGxsId>::const_iterator it(mPerNodeBannedIdsProxy.begin());it!=mPerNodeBannedIdsProxy.end();++it)
std::cerr << " " << *it << std::endl;
}

View File

@ -59,6 +59,12 @@ public:
time_t mLastQuery;
};
struct BannedNodeInfo
{
time_t last_activity_TS ; // updated everytime a node or one of its former identities is required
std::set<RsGxsId> known_identities ; // list of known identities from this node. This is kept for a while, and useful in order to avoid re-asking these keys.
};
class Reputation
{
public:
@ -77,7 +83,7 @@ public:
float mFriendAverage ;
float mReputation;
RsPgpId mOwnerNode;
RsPgpId mOwnerNode;
uint32_t mIdentityFlags;
};
@ -97,11 +103,15 @@ public:
/***** Interface for RsReputations *****/
virtual bool setOwnOpinion(const RsGxsId& key_id, const Opinion& op) ;
virtual bool getReputationInfo(const RsGxsId& id, const RsPgpId &owner_id, ReputationInfo& info) ;
virtual bool isIdentityBanned(const RsGxsId& id, const RsPgpId &owner_node) ;
virtual bool getReputationInfo(const RsGxsId& id, const RsPgpId &ownerNode, ReputationInfo& info) ;
virtual bool isIdentityBanned(const RsGxsId& id) ;
virtual bool isNodeBanned(const RsPgpId& id);
virtual void banNode(const RsPgpId& id,bool b) ;
//virtual void setNodeAutoBanThreshold(uint32_t n) ;
//virtual uint32_t nodeAutoBanThreshold() ;
virtual void setNodeAutoBanThreshold(uint32_t n) ;
virtual uint32_t nodeAutoBanThreshold() ;
virtual void setNodeAutoPositiveOpinionForContacts(bool b) ;
virtual bool nodeAutoPositiveOpinionForContacts() ;
virtual float nodeAutoBanIdentitiesLimit() ;
@ -129,7 +139,8 @@ private:
bool RecvReputations(RsGxsReputationUpdateItem *item);
bool updateLatestUpdate(RsPeerId peerid, time_t latest_update);
void updateActiveFriends() ;
void updateBannedNodesList();
void updateBannedNodesProxy();
// internal update of data. Takes care of cleaning empty boxes.
void locked_updateOpinion(const RsPeerId &from, const RsGxsId &about, RsReputations::Opinion op);
@ -167,8 +178,10 @@ private:
std::set<RsGxsId> mUpdatedReputations;
// PGP Ids auto-banned. This is updated regularly.
std::set<RsPgpId> mBannedPgpIds ;
uint32_t mPgpAutoBanThreshold ;
std::map<RsPgpId,BannedNodeInfo> mBannedPgpIds ;
std::set<RsGxsId> mPerNodeBannedIdsProxy ;
//uint32_t mPgpAutoBanThreshold ;
bool mBannedNodesProxyNeedsUpdate ;
};
#endif //SERVICE_RSGXSREPUTATION_HEADER

View File

@ -51,16 +51,16 @@
* #define GXSID_GEN_DUMMY_DATA 1
****/
#define ID_REQUEST_LIST 0x0001
#define ID_REQUEST_IDENTITY 0x0002
#define ID_REQUEST_LIST 0x0001
#define ID_REQUEST_IDENTITY 0x0002
#define ID_REQUEST_REPUTATION 0x0003
#define ID_REQUEST_OPINION 0x0004
#define ID_REQUEST_OPINION 0x0004
#define GXSID_MAX_CACHE_SIZE 5000
// unused keys are deleted according to some heuristic that should favor known keys, signed keys etc.
static const time_t MAX_KEEP_KEYS_BANNED = 2 * 86400 ; // get rid of banned ids after 2 days. That gives a chance to un-ban someone before he gets kicked out
static const time_t MAX_KEEP_KEYS_BANNED = 1 * 86400 ; // get rid of banned ids after 1 days. That gives a chance to un-ban someone before he gets definitely kicked out
static const time_t MAX_KEEP_KEYS_DEFAULT = 5 * 86400 ; // default for unsigned identities: 5 days
static const time_t MAX_KEEP_KEYS_SIGNED = 8 * 86400 ; // signed identities by unknown key
static const time_t MAX_KEEP_KEYS_SIGNED_KNOWN = 30 * 86400 ; // signed identities by known node keys
@ -324,7 +324,7 @@ public:
time_t now = time(NULL);
const RsGxsId& gxs_id = entry.details.mId ;
bool is_id_banned = rsReputations->isIdentityBanned(gxs_id,entry.details.mPgpId) ;
bool is_id_banned = rsReputations->isIdentityBanned(gxs_id) ;
bool is_own_id = (bool)(entry.details.mFlags & RS_IDENTITY_FLAGS_IS_OWN_ID) ;
bool is_known_id = (bool)(entry.details.mFlags & RS_IDENTITY_FLAGS_PGP_KNOWN) ;
bool is_signed_id = (bool)(entry.details.mFlags & RS_IDENTITY_FLAGS_PGP_LINKED) ;
@ -739,6 +739,18 @@ bool p3IdService::requestKey(const RsGxsId &id, const std::list<RsPeerId>& peers
return true;
else
{
// Normally we should call getIdDetails(), but since the key is not known, we need to digg a possibly old information
// from the reputation system, which keeps its own list of banned keys. Of course, the owner ID is not known at this point.
RsReputations::ReputationInfo info ;
rsReputations->getReputationInfo(id,RsPgpId(),info) ;
if(info.mAssessment == RsReputations::ASSESSMENT_BAD)
{
std::cerr << "(II) not requesting Key " << id << " because it has been banned." << std::endl;
return true;
}
RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/
std::map<RsGxsId,std::list<RsPeerId> >::iterator rit = mIdsNotPresent.find(id) ;

View File

@ -333,6 +333,7 @@ IdDialog::IdDialog(QWidget *parent) :
//connect(ui->treeWidget_membership, SIGNAL(itemSelectionChanged()), this, SLOT(circle_selected()));
connect(ui->treeWidget_membership, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CircleListCustomPopupMenu(QPoint)));
connect(ui->autoBanIdentities_CB, SIGNAL(toggled(bool)), this, SLOT(toggleAutoBanIdentities(bool)));
/* Setup TokenQueue */
@ -349,6 +350,17 @@ IdDialog::IdDialog(QWidget *parent) :
tmer->start(10000) ; // update every 10 secs.
}
void IdDialog::toggleAutoBanIdentities(bool b)
{
RsPgpId id(ui->lineEdit_GpgId->text().left(16).toStdString());
if(!id.isNull())
{
rsReputations->banNode(id,b) ;
requestIdList();
}
}
void IdDialog::updateCirclesDisplay()
{
if(RsAutoUpdatePage::eventsLocked())
@ -1676,6 +1688,8 @@ void IdDialog::insertIdDetails(uint32_t token)
else
ui->lineEdit_GpgId->setText(QString::fromStdString(data.mPgpId.toStdString()) + tr(" [unverified]"));
ui->autoBanIdentities_CB->setVisible(!data.mPgpId.isNull()) ;
time_t now = time(NULL) ;
ui->lineEdit_LastUsed->setText(getHumanReadableDuration(now - data.mLastUsageTS)) ;
ui->headerTextLabel_Person->setText(QString::fromUtf8(data.mMeta.mGroupName.c_str()).left(RSID_MAXIMUM_NICKNAME_SIZE));
@ -1769,6 +1783,8 @@ void IdDialog::insertIdDetails(uint32_t token)
ui->inviteButton->setEnabled(true);
}
ui->autoBanIdentities_CB->setChecked(rsReputations->isNodeBanned(data.mPgpId));
/* now fill in the reputation information */
#ifdef SUSPENDED

View File

@ -77,6 +77,7 @@ private slots:
void createExternalCircle();
void showEditExistingCircle();
void updateCirclesDisplay();
void toggleAutoBanIdentities(bool b);
void acceptCircleSubscription() ;
void cancelCircleSubscription() ;

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
<height>872</height>
</rect>
</property>
<property name="sizePolicy">
@ -117,7 +117,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<iconset resource="../icons.qrc">
<normaloff>:/icons/help_64.png</normaloff>:/icons/help_64.png</iconset>
</property>
<property name="checkable">
@ -278,7 +278,7 @@
<string>Reputation</string>
</property>
<property name="textAlignment">
<set>AlignLeading|AlignVCenter</set>
<set>AlignLeft|AlignVCenter</set>
</property>
</column>
</widget>
@ -534,6 +534,13 @@
<string>Reputation</string>
</property>
<layout class="QVBoxLayout" name="reputationGroupBoxVLayout">
<item>
<widget class="QCheckBox" name="autoBanIdentities_CB">
<property name="text">
<string>Auto-Ban all identities from this node</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="reputationGLayout">
<property name="leftMargin">
@ -806,8 +813,8 @@ p, li { white-space: pre-wrap; }
<tabstop>idTreeWidget</tabstop>
</tabstops>
<resources>
<include location="../images.qrc"/>
<include location="../icons.qrc"/>
<include location="../images.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -37,11 +37,6 @@ PeoplePage::~PeoplePage()
/** Saves the changes on this page */
bool PeoplePage::save(QString &/*errmsg*/)
{
if(!ui.identityBan_CB->isChecked())
rsReputations->setNodeAutoBanThreshold(0) ;
else
rsReputations->setNodeAutoBanThreshold(ui.identityBanThreshold_SB->value()) ;
if(ui.autoPositiveOpinion_CB->isChecked())
rsReputations->setNodeAutoPositiveOpinionForContacts(true) ;
else
@ -55,12 +50,9 @@ bool PeoplePage::save(QString &/*errmsg*/)
/** Loads the settings for this page */
void PeoplePage::load()
{
uint32_t ban_limit = rsReputations->nodeAutoBanThreshold() ;
bool auto_positive_contacts = rsReputations->nodeAutoPositiveOpinionForContacts() ;
float node_auto_ban_identities_limit = rsReputations->nodeAutoBanIdentitiesLimit();
ui.identityBan_CB->setChecked(ban_limit > 0) ;
ui.identityBanThreshold_SB->setValue(ban_limit) ;
ui.autoPositiveOpinion_CB->setChecked(auto_positive_contacts);
ui.autoBanIdentitiesLimit_SB->setValue(node_auto_ban_identities_limit);
}

View File

@ -17,50 +17,6 @@
<string>Identities handling</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="identityBan_CB">
<property name="text">
<string>ban all identities of a node when more than</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="identityBanThreshold_SB">
<property name="maximum">
<number>10</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string> of them have a negative opinion</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="autoPositiveOpinion_CB">
<property name="toolTip">