Merge pull request #612 from csoler/v0.6-Reputations

V0.6 reputations
This commit is contained in:
csoler 2016-12-31 13:48:17 +01:00 committed by GitHub
commit 85e6f61f02
47 changed files with 1243 additions and 564 deletions

View File

@ -138,7 +138,7 @@ bool DistributedChatService::handleRecvChatLobbyMsgItem(RsChatMsgItem *ci)
return false ; return false ;
} }
if(rsIdentity->isBanned(cli->signature.keyId)) if(rsIdentity->overallReputationLevel(cli->signature.keyId) == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
{ {
std::cerr << "(WW) Received lobby msg/item from banned identity " << cli->signature.keyId << ". Dropping it." << std::endl; std::cerr << "(WW) Received lobby msg/item from banned identity " << cli->signature.keyId << ". Dropping it." << std::endl;
return false ; return false ;
@ -220,7 +220,7 @@ bool DistributedChatService::checkSignature(RsChatLobbyBouncingObject *obj,const
// network pre-request key to allow message authentication. // network pre-request key to allow message authentication.
mGixs->requestKey(obj->signature.keyId,peer_list); mGixs->requestKey(obj->signature.keyId,peer_list,"Needed for chat lobby "+RsUtil::NumberToString(obj->lobby_id,true));
uint32_t size = obj->signed_serial_size() ; uint32_t size = obj->signed_serial_size() ;
RsTemporaryMemory memory(size) ; RsTemporaryMemory memory(size) ;
@ -238,7 +238,7 @@ bool DistributedChatService::checkSignature(RsChatLobbyBouncingObject *obj,const
uint32_t error_status ; uint32_t error_status ;
if(!mGixs->validateData(memory,obj->signed_serial_size(),obj->signature,false,error_status)) if(!mGixs->validateData(memory,obj->signed_serial_size(),obj->signature,false,"Chat lobby "+RsUtil::NumberToString(obj->lobby_id,true),error_status))
{ {
bool res = false ; bool res = false ;
@ -647,7 +647,7 @@ void DistributedChatService::handleRecvChatLobbyEventItem(RsChatLobbyEventItem *
#endif #endif
time_t now = time(NULL) ; time_t now = time(NULL) ;
if(rsIdentity->isBanned(item->signature.keyId)) if(rsIdentity->overallReputationLevel(item->signature.keyId) == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
{ {
std::cerr << "(WW) Received lobby msg/item from banned identity " << item->signature.keyId << ". Dropping it." << std::endl; std::cerr << "(WW) Received lobby msg/item from banned identity " << item->signature.keyId << ". Dropping it." << std::endl;
return ; return ;

View File

@ -1555,7 +1555,7 @@ void p3GRouter::handleIncomingReceiptItem(RsGRouterSignedReceiptItem *receipt_it
uint32_t error_status ; uint32_t error_status ;
if(! verifySignedDataItem(receipt_item,error_status)) if(! verifySignedDataItem(receipt_item,"GRouter incoming receipt item",error_status))
if( (it->second.routing_flags & GRouterRoutingInfo::ROUTING_FLAGS_IS_ORIGIN) || (error_status != RsGixs::RS_GIXS_ERROR_KEY_NOT_AVAILABLE)) if( (it->second.routing_flags & GRouterRoutingInfo::ROUTING_FLAGS_IS_ORIGIN) || (error_status != RsGixs::RS_GIXS_ERROR_KEY_NOT_AVAILABLE))
{ {
std::cerr << " checking receipt signature : FAILED. Receipt is dropped. Error status=" << error_status << std::endl; std::cerr << " checking receipt signature : FAILED. Receipt is dropped. Error status=" << error_status << std::endl;
@ -1711,7 +1711,7 @@ void p3GRouter::handleIncomingDataItem(RsGRouterGenericDataItem *data_item)
#endif #endif
uint32_t error_status ; uint32_t error_status ;
if(!verifySignedDataItem(data_item,error_status)) // we should get proper flags out of this if(!verifySignedDataItem(data_item,"Incoming distant message",error_status)) // we should get proper flags out of this
{ {
std::cerr << " verifying item signature: FAILED! Droping that item" ; std::cerr << " verifying item signature: FAILED! Droping that item" ;
std::cerr << " You probably received a message from a person you don't have key." << std::endl; std::cerr << " You probably received a message from a person you don't have key." << std::endl;
@ -1980,11 +1980,11 @@ bool p3GRouter::signDataItem(RsGRouterAbstractMsgItem *item,const RsGxsId& signi
return false ; return false ;
} }
} }
bool p3GRouter::verifySignedDataItem(RsGRouterAbstractMsgItem *item,uint32_t& error_status) bool p3GRouter::verifySignedDataItem(RsGRouterAbstractMsgItem *item,const std::string& info,uint32_t& error_status)
{ {
try try
{ {
if(rsIdentity->isBanned(item->signature.keyId)) if(rsIdentity->overallReputationLevel(item->signature.keyId) == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
{ {
std::cerr << "(WW) received global router message from banned identity " << item->signature.keyId << ". Rejecting the message." << std::endl; std::cerr << "(WW) received global router message from banned identity " << item->signature.keyId << ". Rejecting the message." << std::endl;
return false ; return false ;
@ -1999,7 +1999,7 @@ bool p3GRouter::verifySignedDataItem(RsGRouterAbstractMsgItem *item,uint32_t& er
if(!item->serialise_signed_data(data,data_size)) if(!item->serialise_signed_data(data,data_size))
throw std::runtime_error("Cannot serialise signed data.") ; throw std::runtime_error("Cannot serialise signed data.") ;
if(!mGixs->validateData(data,data_size,item->signature,true,error_status)) if(!mGixs->validateData(data,data_size,item->signature,true,info, error_status))
{ {
switch(error_status) switch(error_status)
{ {
@ -2010,7 +2010,7 @@ bool p3GRouter::verifySignedDataItem(RsGRouterAbstractMsgItem *item,uint32_t& er
std::cerr << "(EE) Key for GXS Id " << item->signature.keyId << " is not available. Cannot verify. Asking key to peer " << item->PeerId() << std::endl; std::cerr << "(EE) Key for GXS Id " << item->signature.keyId << " is not available. Cannot verify. Asking key to peer " << item->PeerId() << std::endl;
mGixs->requestKey(item->signature.keyId,peer_ids) ; // request the key around mGixs->requestKey(item->signature.keyId,peer_ids,info) ; // request the key around
} }
break ; break ;
case RsGixs::RS_GIXS_ERROR_SIGNATURE_MISMATCH: std::cerr << "(EE) Signature mismatch. Spoofing/Corrupted/MITM?." << std::endl; case RsGixs::RS_GIXS_ERROR_SIGNATURE_MISMATCH: std::cerr << "(EE) Signature mismatch. Spoofing/Corrupted/MITM?." << std::endl;
@ -2116,7 +2116,7 @@ bool p3GRouter::sendData(const RsGxsId& destination,const GRouterServiceId& clie
// Verify the signature. If that fails, there's a bug somewhere!! // Verify the signature. If that fails, there's a bug somewhere!!
uint32_t error_status; uint32_t error_status;
if(!verifySignedDataItem(data_item,error_status)) if(!verifySignedDataItem(data_item,"GRouter own signature check for outgoing msg",error_status))
{ {
std::cerr << "Cannot verify data item that was just signed. Some error occured!" << std::endl; std::cerr << "Cannot verify data item that was just signed. Some error occured!" << std::endl;
delete data_item; delete data_item;

View File

@ -254,7 +254,7 @@ private:
// signs an item with the given key. // signs an item with the given key.
bool signDataItem(RsGRouterAbstractMsgItem *item,const RsGxsId& id) ; bool signDataItem(RsGRouterAbstractMsgItem *item,const RsGxsId& id) ;
bool verifySignedDataItem(RsGRouterAbstractMsgItem *item, uint32_t &error_status) ; bool verifySignedDataItem(RsGRouterAbstractMsgItem *item, const std::string &info, uint32_t &error_status) ;
bool encryptDataItem(RsGRouterGenericDataItem *item,const RsGxsId& destination_key) ; bool encryptDataItem(RsGRouterGenericDataItem *item,const RsGxsId& destination_key) ;
bool decryptDataItem(RsGRouterGenericDataItem *item) ; bool decryptDataItem(RsGRouterGenericDataItem *item) ;

View File

@ -86,14 +86,14 @@ RsGenExchange::RsGenExchange(RsGeneralDataService *gds, RsNetworkExchangeService
CREATE_FAIL(0), CREATE_FAIL(0),
CREATE_SUCCESS(1), CREATE_SUCCESS(1),
CREATE_FAIL_TRY_LATER(2), CREATE_FAIL_TRY_LATER(2),
SIGN_MAX_ATTEMPTS(5), SIGN_MAX_WAITING_TIME(60),
SIGN_FAIL(0), SIGN_FAIL(0),
SIGN_SUCCESS(1), SIGN_SUCCESS(1),
SIGN_FAIL_TRY_LATER(2), SIGN_FAIL_TRY_LATER(2),
VALIDATE_FAIL(0), VALIDATE_FAIL(0),
VALIDATE_SUCCESS(1), VALIDATE_SUCCESS(1),
VALIDATE_FAIL_TRY_LATER(2), VALIDATE_FAIL_TRY_LATER(2),
VALIDATE_MAX_ATTEMPTS(5) VALIDATE_MAX_WAITING_TIME(60)
{ {
mDataAccess = new RsGxsDataAccess(gds); mDataAccess = new RsGxsDataAccess(gds);
@ -472,8 +472,8 @@ int RsGenExchange::createGroupSignatures(RsTlvKeySignatureSet& signSet, RsTlvBin
if(GxsSecurity::getSignature((char*)grpData.bin_data, grpData.bin_len, authorKey, sign)) if(GxsSecurity::getSignature((char*)grpData.bin_data, grpData.bin_len, authorKey, sign))
{ {
id_ret = SIGN_SUCCESS; id_ret = SIGN_SUCCESS;
mGixs->timeStampKey(grpMeta.mAuthorId) ; mGixs->timeStampKey(grpMeta.mAuthorId,"Creation of group author signature for GrpId" + grpMeta.mGroupId.toStdString()) ;
signSet.keySignSet[INDEX_AUTHEN_IDENTITY] = sign; signSet.keySignSet[INDEX_AUTHEN_IDENTITY] = sign;
} }
else else
id_ret = SIGN_FAIL; id_ret = SIGN_FAIL;
@ -640,7 +640,7 @@ int RsGenExchange::createMsgSignatures(RsTlvKeySignatureSet& signSet, RsTlvBinar
if(GxsSecurity::getSignature((char*)msgData.bin_data, msgData.bin_len, authorKey, sign)) if(GxsSecurity::getSignature((char*)msgData.bin_data, msgData.bin_len, authorKey, sign))
{ {
id_ret = SIGN_SUCCESS; id_ret = SIGN_SUCCESS;
mGixs->timeStampKey(msgMeta.mAuthorId) ; mGixs->timeStampKey(msgMeta.mAuthorId,"Creating author signature in group " + msgMeta.mGroupId.toStdString() + ", msg " + msgMeta.mMsgId.toStdString()) ;
signSet.keySignSet[INDEX_AUTHEN_IDENTITY] = sign; signSet.keySignSet[INDEX_AUTHEN_IDENTITY] = sign;
} }
else else
@ -857,7 +857,7 @@ int RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, const uin
{ {
RsTlvKeySignature sign = metaData.signSet.keySignSet[INDEX_AUTHEN_IDENTITY]; RsTlvKeySignature sign = metaData.signSet.keySignSet[INDEX_AUTHEN_IDENTITY];
idValidate &= GxsSecurity::validateNxsMsg(*msg, sign, authorKey); idValidate &= GxsSecurity::validateNxsMsg(*msg, sign, authorKey);
mGixs->timeStampKey(metaData.mAuthorId) ; mGixs->timeStampKey(metaData.mAuthorId,"Validation of author signature, service: " + rsServiceControl->getServiceName(serviceFullType()) + ". Grp="+metaData.mGroupId.toStdString()+", msg="+metaData.mMsgId.toStdString()) ;
} }
else else
{ {
@ -882,20 +882,13 @@ int RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, const uin
else else
{ {
// now check reputation of the message author // now check reputation of the message author. The reputation will need to be at least as high as this value for the msg to validate.
float reputation_threshold = RsReputations::REPUTATION_THRESHOLD_DEFAULT; // At validation step, we accept all messages, except the ones signed by locally rejected identities.
if( (signFlag & GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_GPG_KNOWN) && !(details.mFlags & RS_IDENTITY_FLAGS_PGP_KNOWN)) if(details.mReputation.mOverallReputationLevel == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
reputation_threshold = RsReputations::REPUTATION_THRESHOLD_ANTI_SPAM;
else if( (signFlag & GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_GPG) && !(details.mFlags & RS_IDENTITY_FLAGS_PGP_LINKED))
reputation_threshold = RsReputations::REPUTATION_THRESHOLD_ANTI_SPAM;
else
reputation_threshold = RsReputations::REPUTATION_THRESHOLD_DEFAULT;
if(details.mReputation.mOverallReputationScore < reputation_threshold)
{ {
#ifdef GEN_EXCH_DEBUG #ifdef GEN_EXCH_DEBUG
std::cerr << "RsGenExchange::validateMsg(): message from " << metaData.mAuthorId << ", rejected because reputation score (" << details.mReputation.mOverallReputationScore <<") is below the accepted threshold (" << reputation_threshold << ")" << std::endl; std::cerr << "RsGenExchange::validateMsg(): message from " << metaData.mAuthorId << ", rejected because reputation score (" << details.mReputation.mOverallReputationLevel <<") is below the accepted threshold (" << reputation_threshold << ")" << std::endl;
#endif #endif
idValidate = false ; idValidate = false ;
} }
@ -905,13 +898,13 @@ int RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, const uin
#endif #endif
} }
} }
} }
else else
{ {
std::list<RsPeerId> peers; std::list<RsPeerId> peers;
peers.push_back(msg->PeerId()); peers.push_back(msg->PeerId());
mGixs->requestKey(metaData.mAuthorId, peers); mGixs->requestKey(metaData.mAuthorId, peers,"Validation of author signature, service: " + rsServiceControl->getServiceName(serviceFullType()) + ". Grp="+metaData.mGroupId.toStdString()+", msg="+metaData.mMsgId.toStdString());
#ifdef GEN_EXCH_DEBUG #ifdef GEN_EXCH_DEBUG
std::cerr << ", Key missing. Retry later." << std::endl; std::cerr << ", Key missing. Retry later." << std::endl;
@ -988,7 +981,7 @@ int RsGenExchange::validateGrp(RsNxsGrp* grp)
#ifdef GEN_EXCH_DEBUG #ifdef GEN_EXCH_DEBUG
std::cerr << " key ID validation result: " << idValidate << std::endl; std::cerr << " key ID validation result: " << idValidate << std::endl;
#endif #endif
mGixs->timeStampKey(metaData.mAuthorId) ; mGixs->timeStampKey(metaData.mAuthorId,"Group author signature validation. GrpId=" + metaData.mGroupId.toStdString()) ;
} }
else else
{ {
@ -1006,7 +999,7 @@ int RsGenExchange::validateGrp(RsNxsGrp* grp)
#endif #endif
std::list<RsPeerId> peers; std::list<RsPeerId> peers;
peers.push_back(grp->PeerId()); peers.push_back(grp->PeerId());
mGixs->requestKey(metaData.mAuthorId, peers); mGixs->requestKey(metaData.mAuthorId, peers,"Group author signature validation. GrpId=" + metaData.mGroupId.toStdString());
return VALIDATE_FAIL_TRY_LATER; return VALIDATE_FAIL_TRY_LATER;
} }
} }
@ -1485,7 +1478,7 @@ void RsGenExchange::notifyNewGroups(std::vector<RsNxsGrp *> &groups)
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
GxsPendingItem<RsNxsGrp*, RsGxsGroupId> gpsi(grp, grp->grpId); GxsPendingItem<RsNxsGrp*, RsGxsGroupId> gpsi(grp, grp->grpId,time(NULL));
mReceivedGrps.push_back(gpsi); mReceivedGrps.push_back(gpsi);
} }
else else
@ -1623,6 +1616,10 @@ uint32_t RsGenExchange::getDefaultSyncPeriod()
} }
} }
RsReputations::ReputationLevel RsGenExchange::minReputationForForwardingMessages(uint32_t group_sign_flags,uint32_t identity_sign_flags)
{
return RsNetworkExchangeService::minReputationForForwardingMessages(group_sign_flags,identity_sign_flags);
}
uint32_t RsGenExchange::getSyncPeriod(const RsGxsGroupId& grpId) uint32_t RsGenExchange::getSyncPeriod(const RsGxsGroupId& grpId)
{ {
RS_STACK_MUTEX(mGenMtx) ; RS_STACK_MUTEX(mGenMtx) ;
@ -1926,7 +1923,9 @@ bool RsGenExchange::processGrpMask(const RsGxsGroupId& grpId, ContentValue &grpC
void RsGenExchange::publishMsgs() void RsGenExchange::publishMsgs()
{ {
RS_STACK_MUTEX(mGenMtx) ; RS_STACK_MUTEX(mGenMtx) ;
time_t now = time(NULL);
// stick back msgs pending signature // stick back msgs pending signature
typedef std::map<uint32_t, GxsPendingItem<RsGxsMsgItem*, uint32_t> > PendSignMap; typedef std::map<uint32_t, GxsPendingItem<RsGxsMsgItem*, uint32_t> > PendSignMap;
@ -1995,22 +1994,20 @@ void RsGenExchange::publishMsgs()
// sign attempt // sign attempt
if(pit == mMsgPendingSign.end()) if(pit == mMsgPendingSign.end())
{ {
GxsPendingItem<RsGxsMsgItem*, uint32_t> gsi(msgItem, token); GxsPendingItem<RsGxsMsgItem*, uint32_t> gsi(msgItem, token,time(NULL));
mMsgPendingSign.insert(std::make_pair(token, gsi)); mMsgPendingSign.insert(std::make_pair(token, gsi));
} }
else else
{ {
// remove from attempts queue if over sign // remove from attempts queue if over sign
// attempts limit // attempts limit
if(pit->second.mAttempts == SIGN_MAX_ATTEMPTS) if(pit->second.mFirstTryTS + SIGN_MAX_WAITING_TIME < now)
{ {
std::cerr << "Pending signature grp=" << pit->second.mItem->meta.mGroupId << ", msg=" << pit->second.mItem->meta.mMsgId << ", has exceeded validation time limit. The author's key can probably not be obtained. This is unexpected." << std::endl;
mMsgPendingSign.erase(token); mMsgPendingSign.erase(token);
tryLater = false; tryLater = false;
} }
else
{
++pit->second.mAttempts;
}
} }
createOk = false; createOk = false;
@ -2656,28 +2653,22 @@ void RsGenExchange::processRecvdMessages()
{ {
RS_STACK_MUTEX(mGenMtx) ; RS_STACK_MUTEX(mGenMtx) ;
time_t now = time(NULL);
#ifdef GEN_EXCH_DEBUG #ifdef GEN_EXCH_DEBUG
if(!mMsgPendingValidate.empty()) if(!mMsgPendingValidate.empty())
std::cerr << "processing received messages" << std::endl; std::cerr << "processing received messages" << std::endl;
#endif #endif
NxsMsgPendingVect::iterator pend_it = mMsgPendingValidate.begin(); NxsMsgPendingVect::iterator pend_it = mMsgPendingValidate.begin();
#ifdef GEN_EXCH_DEBUG
if(!mMsgPendingValidate.empty())
std::cerr << " pending validation" << std::endl;
#endif
for(; pend_it != mMsgPendingValidate.end();) for(; pend_it != mMsgPendingValidate.end();)
{ {
GxsPendingItem<RsNxsMsg*, RsGxsGrpMsgIdPair>& gpsi = *pend_it; GxsPendingItem<RsNxsMsg*, RsGxsGrpMsgIdPair>& gpsi = *pend_it;
#ifdef GEN_EXCH_DEBUG if(gpsi.mFirstTryTS + VALIDATE_MAX_WAITING_TIME < now)
std::cerr << " grp=" << gpsi.mId.first << ", msg=" << gpsi.mId.second << ", attempts=" << gpsi.mAttempts ;
#endif
if(gpsi.mAttempts == VALIDATE_MAX_ATTEMPTS)
{ {
#ifdef GEN_EXCH_DEBUG std::cerr << "Pending validation grp=" << gpsi.mId.first << ", msg=" << gpsi.mId.second << ", has exceeded validation time limit. The author's key can probably not be obtained. This is unexpected." << std::endl;
std::cerr << " = max! deleting." << std::endl;
#endif
delete gpsi.mItem; delete gpsi.mItem;
pend_it = mMsgPendingValidate.erase(pend_it); pend_it = mMsgPendingValidate.erase(pend_it);
} }
@ -2839,16 +2830,12 @@ void RsGenExchange::processRecvdMessages()
// first check you haven't made too many attempts // first check you haven't made too many attempts
NxsMsgPendingVect::iterator vit = std::find( NxsMsgPendingVect::iterator vit = std::find(mMsgPendingValidate.begin(), mMsgPendingValidate.end(), id);
mMsgPendingValidate.begin(), mMsgPendingValidate.end(), id);
if(vit == mMsgPendingValidate.end()) if(vit == mMsgPendingValidate.end())
{ {
GxsPendingItem<RsNxsMsg*, RsGxsGrpMsgIdPair> item(msg, id); GxsPendingItem<RsNxsMsg*, RsGxsGrpMsgIdPair> item(msg, id,time(NULL));
mMsgPendingValidate.push_back(item); mMsgPendingValidate.push_back(item);
}else
{
vit->mAttempts++;
} }
} }
} }
@ -2981,18 +2968,16 @@ void RsGenExchange::processRecvdGroups()
std::cerr << " failed to validate incoming grp, trying again. grpId: " << grp->grpId << std::endl; std::cerr << " failed to validate incoming grp, trying again. grpId: " << grp->grpId << std::endl;
#endif #endif
if(gpsi.mAttempts == VALIDATE_MAX_ATTEMPTS) if(gpsi.mFirstTryTS + VALIDATE_MAX_WAITING_TIME < time(NULL))
{ {
#ifdef GEN_EXCH_DEBUG #ifdef GEN_EXCH_DEBUG
std::cerr << " max attempts " << VALIDATE_MAX_ATTEMPTS << " reached. Will delete group " << grp->grpId << std::endl; std::cerr << " validation time got group " << grp->grpId << " exceeded maximum. Will delete group " << std::endl;
#endif #endif
delete grp; delete grp;
erase = true; erase = true;
} }
else else
{
erase = false; erase = false;
}
} }
} }
else else
@ -3147,7 +3132,7 @@ bool RsGenExchange::updateValid(RsGxsGrpMetaData& oldGrpMeta, RsNxsGrp& newGrp)
// also check this is the latest published group // also check this is the latest published group
bool latest = newGrp.metaData->mPublishTs > oldGrpMeta.mPublishTs; bool latest = newGrp.metaData->mPublishTs > oldGrpMeta.mPublishTs;
mGixs->timeStampKey(newGrp.metaData->mAuthorId) ; mGixs->timeStampKey(newGrp.metaData->mAuthorId,"Validation of signature for updated grp " + oldGrpMeta.mGroupId.toStdString()) ;
return GxsSecurity::validateNxsGrp(newGrp, adminSign, keyMit->second) && latest; return GxsSecurity::validateNxsGrp(newGrp, adminSign, keyMit->second) && latest;
} }

View File

@ -43,17 +43,10 @@ template<class GxsItem, typename Identity = std::string>
class GxsPendingItem class GxsPendingItem
{ {
public: public:
GxsPendingItem(GxsItem item, Identity id) : GxsPendingItem(GxsItem item, Identity id,time_t ts) :
mItem(item), mId(id), mAttempts(0) mItem(item), mId(id), mFirstTryTS(ts)
{} {}
GxsPendingItem(const GxsPendingItem& gpsi)
{
this->mItem = gpsi.mItem;
this->mId = gpsi.mId;
this->mAttempts = gpsi.mAttempts;
}
bool operator==(const Identity& id) bool operator==(const Identity& id)
{ {
return this->mId == id; return this->mId == id;
@ -61,7 +54,7 @@ public:
GxsItem mItem; GxsItem mItem;
Identity mId; Identity mId;
uint8_t mAttempts; time_t mFirstTryTS;
}; };
class GxsGrpPendingSign class GxsGrpPendingSign
@ -656,6 +649,9 @@ public:
virtual void setSyncPeriod(const RsGxsGroupId& grpId,uint32_t age_in_secs) ; virtual void setSyncPeriod(const RsGxsGroupId& grpId,uint32_t age_in_secs) ;
uint16_t serviceType() const { return mServType ; } uint16_t serviceType() const { return mServType ; }
uint32_t serviceFullType() const { return ((uint32_t)mServType << 8) + (((uint32_t) RS_PKT_VERSION_SERVICE) << 24); }
virtual RsReputations::ReputationLevel minReputationForForwardingMessages(uint32_t group_sign_flags,uint32_t identity_flags);
protected: protected:
/** Notifications **/ /** Notifications **/
@ -880,9 +876,9 @@ private:
private: private:
const uint8_t CREATE_FAIL, CREATE_SUCCESS, CREATE_FAIL_TRY_LATER, SIGN_MAX_ATTEMPTS; const uint8_t CREATE_FAIL, CREATE_SUCCESS, CREATE_FAIL_TRY_LATER, SIGN_MAX_WAITING_TIME;
const uint8_t SIGN_FAIL, SIGN_SUCCESS, SIGN_FAIL_TRY_LATER; const uint8_t SIGN_FAIL, SIGN_SUCCESS, SIGN_FAIL_TRY_LATER;
const uint8_t VALIDATE_FAIL, VALIDATE_SUCCESS, VALIDATE_FAIL_TRY_LATER, VALIDATE_MAX_ATTEMPTS; const uint8_t VALIDATE_FAIL, VALIDATE_SUCCESS, VALIDATE_FAIL_TRY_LATER, VALIDATE_MAX_WAITING_TIME;
private: private:

View File

@ -117,7 +117,7 @@ public:
*/ */
virtual bool signData(const uint8_t *data,uint32_t data_size,const RsGxsId& signer_id,RsTlvKeySignature& signature,uint32_t& signing_error) = 0 ; virtual bool signData(const uint8_t *data,uint32_t data_size,const RsGxsId& signer_id,RsTlvKeySignature& signature,uint32_t& signing_error) = 0 ;
virtual bool validateData(const uint8_t *data,uint32_t data_size,const RsTlvKeySignature& signature,bool force_load,uint32_t& signing_error) = 0 ; virtual bool validateData(const uint8_t *data,uint32_t data_size,const RsTlvKeySignature& signature,bool force_load,const std::string& info_string,uint32_t& signing_error) = 0 ;
virtual bool encryptData(const uint8_t *clear_data,uint32_t clear_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& encryption_error) = 0 ; virtual bool encryptData(const uint8_t *clear_data,uint32_t clear_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& encryption_error) = 0 ;
virtual bool decryptData(const uint8_t *encrypted_data,uint32_t encrypted_data_size,uint8_t *& clear_data,uint32_t& clear_data_size,const RsGxsId& encryption_key_id,uint32_t& encryption_error) = 0 ; virtual bool decryptData(const uint8_t *encrypted_data,uint32_t encrypted_data_size,uint8_t *& clear_data,uint32_t& clear_data_size,const RsGxsId& encryption_key_id,uint32_t& encryption_error) = 0 ;
@ -125,7 +125,7 @@ public:
virtual bool getOwnIds(std::list<RsGxsId>& ids) = 0; virtual bool getOwnIds(std::list<RsGxsId>& ids) = 0;
virtual bool isOwnId(const RsGxsId& key_id) = 0 ; virtual bool isOwnId(const RsGxsId& key_id) = 0 ;
virtual void timeStampKey(const RsGxsId& key_id) = 0 ; virtual void timeStampKey(const RsGxsId& key_id,const std::string& reason) = 0 ;
// Key related interface - used for validating msgs and groups. // Key related interface - used for validating msgs and groups.
/*! /*!
@ -149,7 +149,7 @@ public:
* @param keyref the KeyRef of the key being requested * @param keyref the KeyRef of the key being requested
* @return will * @return will
*/ */
virtual bool requestKey(const RsGxsId &id, const std::list<RsPeerId> &peers) = 0; virtual bool requestKey(const RsGxsId &id, const std::list<RsPeerId> &peers,const std::string& info) = 0;
virtual bool requestPrivateKey(const RsGxsId &id) = 0; virtual bool requestPrivateKey(const RsGxsId &id) = 0;

View File

@ -1954,8 +1954,6 @@ void RsGxsNetService::updateServerSyncTS()
for(std::map<RsGxsGroupId, RsGxsGrpMetaData*>::const_iterator mit = gxsMap.begin();mit != gxsMap.end(); ++mit) for(std::map<RsGxsGroupId, RsGxsGrpMetaData*>::const_iterator mit = gxsMap.begin();mit != gxsMap.end(); ++mit)
{ {
//const RsGxsGroupId& grpId = mit->first;
// Check if the group is subscribed and restricted to a circle. If the circle has changed, update the // Check if the group is subscribed and restricted to a circle. If the circle has changed, update the
// global TS to reflect that change to clients who may be able to see/subscribe to that particular group. // global TS to reflect that change to clients who may be able to see/subscribe to that particular group.
@ -2810,16 +2808,13 @@ void RsGxsNetService::locked_genReqMsgTransaction(NxsTransaction* tr)
if(reqListSize < (int)MAX_REQLIST_SIZE && msgIdSet.find(msgId) == msgIdSet.end()) if(reqListSize < (int)MAX_REQLIST_SIZE && msgIdSet.find(msgId) == msgIdSet.end())
{ {
// if reputation is in reputations cache then proceed
// or if there isn't an author (note as author requirement is
// enforced at service level, if no author is needed then reputation
// filtering is optional)
bool noAuthor = syncItem->authorId.isNull(); bool noAuthor = syncItem->authorId.isNull();
#ifdef NXS_NET_DEBUG_1 #ifdef NXS_NET_DEBUG_1
GXSNETDEBUG_PG(item->PeerId(),grpId) << ", reqlist size=" << reqListSize << ", message not present." ; GXSNETDEBUG_PG(item->PeerId(),grpId) << ", reqlist size=" << reqListSize << ", message not present." ;
#endif #endif
// grp meta must be present if author present // grp meta must be present if author present
if(!noAuthor && grpMeta == NULL) if(!noAuthor && grpMeta == NULL)
{ {
#ifdef NXS_NET_DEBUG_1 #ifdef NXS_NET_DEBUG_1
@ -2828,7 +2823,13 @@ void RsGxsNetService::locked_genReqMsgTransaction(NxsTransaction* tr)
continue; continue;
} }
if(rsIdentity && rsIdentity->isBanned(syncItem->authorId)) // The algorithm on request of message is:
//
// - always re-check for author ban level
// - if author is locally banned, do not download.
// - if author is not locally banned, download, whatever friends' opinion might be.
if(rsIdentity && rsIdentity->overallReputationLevel(syncItem->authorId) == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
{ {
#ifdef NXS_NET_DEBUG_1 #ifdef NXS_NET_DEBUG_1
GXSNETDEBUG_PG(item->PeerId(),grpId) << ", Identity " << syncItem->authorId << " is banned. Not requesting message!" << std::endl; GXSNETDEBUG_PG(item->PeerId(),grpId) << ", Identity " << syncItem->authorId << " is banned. Not requesting message!" << std::endl;
@ -2844,7 +2845,7 @@ void RsGxsNetService::locked_genReqMsgTransaction(NxsTransaction* tr)
continue ; continue ;
} }
#ifdef TO_BE_REMOVED
if(mReputations->haveReputation(syncItem->authorId) || noAuthor) if(mReputations->haveReputation(syncItem->authorId) || noAuthor)
{ {
GixsReputation rep; GixsReputation rep;
@ -2859,17 +2860,20 @@ void RsGxsNetService::locked_genReqMsgTransaction(NxsTransaction* tr)
// at genexchange side of things // at genexchange side of things
if(rep.score >= (int)grpMeta->mReputationCutOff || noAuthor) if(rep.score >= (int)grpMeta->mReputationCutOff || noAuthor)
{ {
#ifdef NXS_NET_DEBUG_1
GXSNETDEBUG_PG(item->PeerId(),grpId) << ", passed! Adding message to req list." << std::endl;
#endif #endif
RsNxsSyncMsgItem* msgItem = new RsNxsSyncMsgItem(mServType); #ifdef NXS_NET_DEBUG_1
msgItem->grpId = grpId; GXSNETDEBUG_PG(item->PeerId(),grpId) << ", passed! Adding message to req list." << std::endl;
msgItem->msgId = msgId; #endif
msgItem->flag = RsNxsSyncMsgItem::FLAG_REQUEST; RsNxsSyncMsgItem* msgItem = new RsNxsSyncMsgItem(mServType);
msgItem->transactionNumber = transN; msgItem->grpId = grpId;
msgItem->PeerId(peerFrom); msgItem->msgId = msgId;
reqList.push_back(msgItem); msgItem->flag = RsNxsSyncMsgItem::FLAG_REQUEST;
++reqListSize ; msgItem->transactionNumber = transN;
msgItem->PeerId(peerFrom);
reqList.push_back(msgItem);
++reqListSize ;
#ifdef TO_BE_REMOVED
} }
#ifdef NXS_NET_DEBUG_1 #ifdef NXS_NET_DEBUG_1
else else
@ -2889,6 +2893,7 @@ void RsGxsNetService::locked_genReqMsgTransaction(NxsTransaction* tr)
entry.mMsgId = syncItem->msgId; entry.mMsgId = syncItem->msgId;
toVet.push_back(entry); toVet.push_back(entry);
} }
#endif
} }
#ifdef NXS_NET_DEBUG_1 #ifdef NXS_NET_DEBUG_1
else else
@ -3061,13 +3066,14 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr)
} }
// FIXTESTS global variable rsReputations not available in unittests! // FIXTESTS global variable rsReputations not available in unittests!
if(!grpSyncItem->authorId.isNull() && rsIdentity && rsIdentity->isBanned(grpSyncItem->authorId)) #warning Update the code below to correctly send/recv dependign on reputation
{ if(!grpSyncItem->authorId.isNull() && rsIdentity && rsIdentity->overallReputationLevel(grpSyncItem->authorId) == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
{
#ifdef NXS_NET_DEBUG_0 #ifdef NXS_NET_DEBUG_0
GXSNETDEBUG_PG(tr->mTransaction->PeerId(),grpId) << " Identity " << grpSyncItem->authorId << " is banned. Not syncing group." << std::endl; GXSNETDEBUG_PG(tr->mTransaction->PeerId(),grpId) << " Identity " << grpSyncItem->authorId << " is banned. Not syncing group." << std::endl;
#endif #endif
continue ; continue ;
} }
if( (mGrpAutoSync && !haveItem) || latestVersion) if( (mGrpAutoSync && !haveItem) || latestVersion)
{ {
@ -4202,59 +4208,83 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_
uint32_t transN = locked_getTransactionId(); uint32_t transN = locked_getTransactionId();
RsGxsCircleId should_encrypt_to_this_circle_id ; RsGxsCircleId should_encrypt_to_this_circle_id ;
time_t now = time(NULL) ;
uint32_t max_send_delay = mServerGrpConfigMap[item->grpId].msg_req_delay; // we should use "sync" but there's only one variable used in the GUI: the req one.
if(canSendMsgIds(msgMetas, *grpMeta, peer, should_encrypt_to_this_circle_id)) if(canSendMsgIds(msgMetas, *grpMeta, peer, should_encrypt_to_this_circle_id))
{ {
for(std::vector<RsGxsMsgMetaData*>::iterator vit = msgMetas.begin();vit != msgMetas.end(); ++vit) for(std::vector<RsGxsMsgMetaData*>::iterator vit = msgMetas.begin();vit != msgMetas.end(); ++vit)
if(item->createdSinceTS < (*vit)->mPublishTs) {
RsGxsMsgMetaData* m = *vit;
RsIdentityDetails details ;
if(!rsIdentity->getIdDetails(m->mAuthorId,details))
{ {
RsGxsMsgMetaData* m = *vit; std::cerr << /* GXSNETDEBUG_PG(item->PeerId(),item->grpId) << */ " not sending grp message ID " << (*vit)->mMsgId << ", because the identity of the author is not accessible (unknown/not cached)" << std::endl;
continue ;
RsNxsSyncMsgItem* mItem = new RsNxsSyncMsgItem(mServType);
mItem->flag = RsNxsSyncGrpItem::FLAG_RESPONSE;
mItem->grpId = m->mGroupId;
mItem->msgId = m->mMsgId;
mItem->authorId = m->mAuthorId;
mItem->PeerId(peer);
mItem->transactionNumber = transN;
if(!should_encrypt_to_this_circle_id.isNull())
{
#ifdef NXS_NET_DEBUG_7
GXSNETDEBUG_PG(item->PeerId(),item->grpId) << " sending info item for msg id " << mItem->msgId << ". Transaction will be encrypted for group " << should_encrypt_to_this_circle_id << std::endl;
#endif
RsNxsItem *encrypted_item = NULL ;
uint32_t status = RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN ;
if(encryptSingleNxsItem(mItem, grpMeta->mCircleId,m->mGroupId, encrypted_item,status))
{
itemL.push_back(encrypted_item) ;
delete mItem ;
}
else
{
// Something's not ready (probably the circle content. We could put on a vetting list, but actually the client will re-ask the list asap.
std::cerr << " (EE) Cannot encrypt msg meta data. MsgId=" << mItem->msgId << ", grpId=" << mItem->grpId << ", circleId=" << should_encrypt_to_this_circle_id << ". Dropping the whole list." << std::endl;
for(std::list<RsNxsItem*>::const_iterator it(itemL.begin());it!=itemL.end();++it)
delete *it ;
itemL.clear() ;
break ;
}
}
else
{
#ifdef NXS_NET_DEBUG_7
GXSNETDEBUG_PG(item->PeerId(),item->grpId) << " sending info item for msg id " << mItem->msgId << " in clear." << std::endl;
#endif
itemL.push_back(mItem);
}
} }
if(details.mReputation.mOverallReputationLevel < minReputationForForwardingMessages(grpMeta->mSignFlags, details.mFlags))
{
//#ifdef NXS_NET_DEBUG_0
std::cerr << /* GXSNETDEBUG_PG(item->PeerId(),item->grpId) << */ " not sending item ID " << (*vit)->mMsgId << ", because the author is flags " << std::hex << details.mFlags << std::dec << " and reputation level " << details.mReputation.mOverallReputationLevel << std::endl;
//#endif
continue ;
}
// Check publish TS
if(item->createdSinceTS > (*vit)->mPublishTs || (*vit)->mPublishTs + max_send_delay < now)
{
#ifdef NXS_NET_DEBUG_0 #ifdef NXS_NET_DEBUG_0
else GXSNETDEBUG_PG(item->PeerId(),item->grpId) << " not sending item ID " << (*vit)->mMsgId << ", because it is too old (publishTS = " << (time(NULL)-(*vit)->mPublishTs)/86400 << " days ago" << std::endl;
GXSNETDEBUG_PG(item->PeerId(),item->grpId) << " not sending item ID " << (*vit)->mMsgId << ", because it is too old (publishTS = " << (time(NULL)-(*vit)->mPublishTs)/86400 << " days ago" << std::endl;
#endif #endif
continue ;
}
RsNxsSyncMsgItem* mItem = new RsNxsSyncMsgItem(mServType);
mItem->flag = RsNxsSyncGrpItem::FLAG_RESPONSE;
mItem->grpId = m->mGroupId;
mItem->msgId = m->mMsgId;
mItem->authorId = m->mAuthorId;
mItem->PeerId(peer);
mItem->transactionNumber = transN;
if(!should_encrypt_to_this_circle_id.isNull())
{
#ifdef NXS_NET_DEBUG_7
GXSNETDEBUG_PG(item->PeerId(),item->grpId) << " sending info item for msg id " << mItem->msgId << ". Transaction will be encrypted for group " << should_encrypt_to_this_circle_id << std::endl;
#endif
RsNxsItem *encrypted_item = NULL ;
uint32_t status = RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN ;
if(encryptSingleNxsItem(mItem, grpMeta->mCircleId,m->mGroupId, encrypted_item,status))
{
itemL.push_back(encrypted_item) ;
delete mItem ;
}
else
{
// Something's not ready (probably the circle content. We could put on a vetting list, but actually the client will re-ask the list asap.
std::cerr << " (EE) Cannot encrypt msg meta data. MsgId=" << mItem->msgId << ", grpId=" << mItem->grpId << ", circleId=" << should_encrypt_to_this_circle_id << ". Dropping the whole list." << std::endl;
for(std::list<RsNxsItem*>::const_iterator it(itemL.begin());it!=itemL.end();++it)
delete *it ;
itemL.clear() ;
break ;
}
}
else
{
#ifdef NXS_NET_DEBUG_7
GXSNETDEBUG_PG(item->PeerId(),item->grpId) << " sending info item for msg id " << mItem->msgId << " in clear." << std::endl;
#endif
itemL.push_back(mItem);
}
}
} }
#ifdef NXS_NET_DEBUG_0 #ifdef NXS_NET_DEBUG_0
else else

View File

@ -139,7 +139,7 @@ bool RsGxsIntegrityCheck::check()
GxsMsgReq msgIds; GxsMsgReq msgIds;
GxsMsgReq grps; GxsMsgReq grps;
std::set<RsGxsId> used_gxs_ids ; std::map<RsGxsId,RsGxsGroupId> used_gxs_ids ;
std::set<RsGxsGroupId> subscribed_groups ; std::set<RsGxsGroupId> subscribed_groups ;
// compute hash and compare to stored value, if it fails then simply add it // compute hash and compare to stored value, if it fails then simply add it
@ -171,8 +171,8 @@ bool RsGxsIntegrityCheck::check()
GXSUTIL_DEBUG() << "TimeStamping group authors' key ID " << grp->metaData->mAuthorId << " in group ID " << grp->grpId << std::endl; GXSUTIL_DEBUG() << "TimeStamping group authors' key ID " << grp->metaData->mAuthorId << " in group ID " << grp->grpId << std::endl;
#endif #endif
if(rsIdentity!=NULL && !rsIdentity->isBanned(grp->metaData->mAuthorId)) if(rsIdentity!=NULL && rsIdentity->overallReputationLevel(grp->metaData->mAuthorId) > RsReputations::REPUTATION_LOCALLY_NEGATIVE)
used_gxs_ids.insert(grp->metaData->mAuthorId) ; used_gxs_ids.insert(std::make_pair(grp->metaData->mAuthorId,grp->grpId)) ;
} }
} }
} }
@ -269,8 +269,8 @@ bool RsGxsIntegrityCheck::check()
#ifdef DEBUG_GXSUTIL #ifdef DEBUG_GXSUTIL
GXSUTIL_DEBUG() << "TimeStamping message authors' key ID " << msg->metaData->mAuthorId << " in message " << msg->msgId << ", group ID " << msg->grpId<< std::endl; GXSUTIL_DEBUG() << "TimeStamping message authors' key ID " << msg->metaData->mAuthorId << " in message " << msg->msgId << ", group ID " << msg->grpId<< std::endl;
#endif #endif
if(rsIdentity!=NULL && !rsIdentity->isBanned(msg->metaData->mAuthorId)) if(rsIdentity!=NULL && rsIdentity->overallReputationLevel(msg->metaData->mAuthorId) > RsReputations::REPUTATION_LOCALLY_NEGATIVE)
used_gxs_ids.insert(msg->metaData->mAuthorId) ; used_gxs_ids.insert(std::make_pair(msg->metaData->mAuthorId,msg->metaData->mGroupId)) ;
} }
delete msg; delete msg;
@ -297,9 +297,9 @@ bool RsGxsIntegrityCheck::check()
std::list<RsPeerId> connected_friends ; std::list<RsPeerId> connected_friends ;
rsPeers->getOnlineList(connected_friends) ; rsPeers->getOnlineList(connected_friends) ;
std::vector<RsGxsId> gxs_ids ; std::vector<std::pair<RsGxsId,RsGxsGroupId> > gxs_ids ;
for(std::set<RsGxsId>::const_iterator it(used_gxs_ids.begin());it!=used_gxs_ids.end();++it) for(std::map<RsGxsId,RsGxsGroupId>::const_iterator it(used_gxs_ids.begin());it!=used_gxs_ids.end();++it)
{ {
gxs_ids.push_back(*it) ; gxs_ids.push_back(*it) ;
#ifdef DEBUG_GXSUTIL #ifdef DEBUG_GXSUTIL
@ -321,9 +321,9 @@ bool RsGxsIntegrityCheck::check()
GXSUTIL_DEBUG() << " requesting ID " << gxs_ids[n] ; GXSUTIL_DEBUG() << " requesting ID " << gxs_ids[n] ;
#endif #endif
if(!mGixs->haveKey(gxs_ids[n])) // checks if we have it already in the cache (conservative way to ensure that we atually have it) if(!mGixs->haveKey(gxs_ids[n].first)) // checks if we have it already in the cache (conservative way to ensure that we atually have it)
{ {
mGixs->requestKey(gxs_ids[n],connected_friends); mGixs->requestKey(gxs_ids[n].first,connected_friends,"Author in service \"" + rsServiceControl->getServiceName(mGenExchangeClient->serviceFullType())+"\" (group ID " + gxs_ids[n].second.toStdString() + ")" ) ;
++nb_requested_not_in_cache ; ++nb_requested_not_in_cache ;
#ifdef DEBUG_GXSUTIL #ifdef DEBUG_GXSUTIL
@ -335,12 +335,8 @@ bool RsGxsIntegrityCheck::check()
#ifdef DEBUG_GXSUTIL #ifdef DEBUG_GXSUTIL
GXSUTIL_DEBUG() << " ... already in cache" << std::endl; GXSUTIL_DEBUG() << " ... already in cache" << std::endl;
#endif #endif
// Note: we could time_stamp even in the case where the id is not cached. Anyway, it's not really a problem here, since IDs have a high chance of
// behing eventually stamped.
mGixs->timeStampKey(gxs_ids[n]) ;
} }
mGixs->timeStampKey(gxs_ids[n].first,"Author in service \"" + rsServiceControl->getServiceName(mGenExchangeClient->serviceFullType())+"\" (group ID " + gxs_ids[n].second.toStdString() + ")");
gxs_ids[n] = gxs_ids[gxs_ids.size()-1] ; gxs_ids[n] = gxs_ids[gxs_ids.size()-1] ;
gxs_ids.pop_back() ; gxs_ids.pop_back() ;

View File

@ -34,6 +34,8 @@
#include <map> #include <map>
#include "services/p3service.h" #include "services/p3service.h"
#include "retroshare/rsreputations.h"
#include "retroshare/rsidentity.h"
#include "rsgds.h" #include "rsgds.h"
/*! /*!
@ -159,6 +161,55 @@ public:
* \return * \return
*/ */
virtual bool stampMsgServerUpdateTS(const RsGxsGroupId& gid) =0; virtual bool stampMsgServerUpdateTS(const RsGxsGroupId& gid) =0;
/*!
* \brief minReputationForForwardingMessages
* Encodes the policy for sending/requesting messages depending on anti-spam settings.
*
* \param group_sign_flags Sign flags from the group meta data
* \param identity_flags Flags of the identity
* \return
*/
static RsReputations::ReputationLevel minReputationForRequestingMessages(uint32_t /* group_sign_flags */, uint32_t /* identity_flags */)
{
// We always request messages, except if the author identity is locally banned.
return RsReputations::REPUTATION_REMOTELY_NEGATIVE;
}
static RsReputations::ReputationLevel minReputationForForwardingMessages(uint32_t group_sign_flags, uint32_t identity_flags)
{
// If anti-spam is enabled, do not send messages from authors with bad reputation. The policy is to only forward messages if the reputation of the author is at least
// equal to the minimal reputation in the table below (R=remotely, L=locally, P=positive, N=negative, O=neutral) :
//
//
// +----------------------------------------------------+
// | Identity flags |
// +----------------------------------------------------+
// | Anonymous Signed Signed+Known |
// +-------------+-----------+----------------------------------------------------+
// | |NONE | O O O |
// | Forum flags |GPG_AUTHED | RP O O |
// | |GPG_KNOWN | RP RP O |
// +-------------+-----------+----------------------------------------------------+
//
if(identity_flags & RS_IDENTITY_FLAGS_PGP_KNOWN)
return RsReputations::REPUTATION_NEUTRAL;
else if(identity_flags & RS_IDENTITY_FLAGS_PGP_LINKED)
{
if(group_sign_flags & GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_GPG_KNOWN)
return RsReputations::REPUTATION_REMOTELY_POSITIVE;
else
return RsReputations::REPUTATION_NEUTRAL;
}
else
{
if( (group_sign_flags & GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_GPG_KNOWN) || (group_sign_flags & GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_GPG))
return RsReputations::REPUTATION_REMOTELY_POSITIVE;
else
return RsReputations::REPUTATION_NEUTRAL;
}
}
}; };
#endif // RSGNP_H #endif // RSGNP_H

View File

@ -937,7 +937,7 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item)
std::cerr << "(SS) Signature was verified and it doesn't check! This is a security issue!" << std::endl; std::cerr << "(SS) Signature was verified and it doesn't check! This is a security issue!" << std::endl;
return ; return ;
} }
mGixs->timeStampKey(item->signature.keyId) ; mGixs->timeStampKey(item->signature.keyId,"Used to validate GXS tunnel DH half-key.") ;
#ifdef DEBUG_GXS_TUNNEL #ifdef DEBUG_GXS_TUNNEL
std::cerr << " Signature checks! Sender's ID = " << senders_id << std::endl; std::cerr << " Signature checks! Sender's ID = " << senders_id << std::endl;

View File

@ -362,6 +362,20 @@ void p3ServiceControl::getServiceChanges(std::set<RsPeerId> &updateSet)
mUpdatedSet.clear(); mUpdatedSet.clear();
} }
std::string p3ServiceControl::getServiceName(uint32_t service_id)
{
RsStackMutex stack(mCtrlMtx); /***** LOCK STACK MUTEX ****/
std::map<uint32_t, RsServiceInfo>::const_iterator it = mOwnServices.find(service_id) ;
if(it == mOwnServices.end())
{
std::cerr << "(EE) Cannot find own service for ID = " << std::hex << service_id << std::dec << std::endl;
return std::string();
}
return it->second.mServiceName;
}
bool p3ServiceControl::getOwnServices(RsPeerServiceInfo &info) bool p3ServiceControl::getOwnServices(RsPeerServiceInfo &info)
{ {

View File

@ -85,6 +85,7 @@ virtual const RsPeerId& getOwnId();
*/ */
virtual bool getOwnServices(RsPeerServiceInfo &info); virtual bool getOwnServices(RsPeerServiceInfo &info);
virtual std::string getServiceName(uint32_t service_id) ;
// This is what is passed to peers, can be displayed by GUI too. // This is what is passed to peers, can be displayed by GUI too.
virtual bool getServicesAllowed(const RsPeerId &peerId, RsPeerServiceInfo &info); virtual bool getServicesAllowed(const RsPeerId &peerId, RsPeerServiceInfo &info);

View File

@ -61,37 +61,36 @@ std::ostream &operator<<(std::ostream &out, const RsGxsForumMsg &msg);
class RsGxsForums: public RsGxsIfaceHelper class RsGxsForums: public RsGxsIfaceHelper
{ {
public: public:
RsGxsForums(RsGxsIface *gxs) RsGxsForums(RsGxsIface *gxs)
:RsGxsIfaceHelper(gxs) { return; } :RsGxsIfaceHelper(gxs) { return; }
virtual ~RsGxsForums() { return; } virtual ~RsGxsForums() { return; }
/* Specific Service Data */ /* Specific Service Data */
virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsForumGroup> &groups) = 0; virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsForumGroup> &groups) = 0;
virtual bool getMsgData(const uint32_t &token, std::vector<RsGxsForumMsg> &msgs) = 0; virtual bool getMsgData(const uint32_t &token, std::vector<RsGxsForumMsg> &msgs) = 0;
//Not currently used //Not currently used
//virtual bool getRelatedMessages(const uint32_t &token, std::vector<RsGxsForumMsg> &msgs) = 0; //virtual bool getRelatedMessages(const uint32_t &token, std::vector<RsGxsForumMsg> &msgs) = 0;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
virtual void setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& msgId, bool read) = 0; virtual void setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& msgId, bool read) = 0;
//virtual bool setMessageStatus(const std::string &msgId, const uint32_t status, const uint32_t statusMask); //virtual bool setMessageStatus(const std::string &msgId, const uint32_t status, const uint32_t statusMask);
//virtual bool setGroupSubscribeFlags(const std::string &groupId, uint32_t subscribeFlags, uint32_t subscribeMask); //virtual bool setGroupSubscribeFlags(const std::string &groupId, uint32_t subscribeFlags, uint32_t subscribeMask);
//virtual bool groupRestoreKeys(const std::string &groupId); //virtual bool groupRestoreKeys(const std::string &groupId);
//virtual bool groupShareKeys(const std::string &groupId, std::list<std::string>& peers); //virtual bool groupShareKeys(const std::string &groupId, std::list<std::string>& peers);
virtual bool createGroup(uint32_t &token, RsGxsForumGroup &group) = 0; virtual bool createGroup(uint32_t &token, RsGxsForumGroup &group) = 0;
virtual bool createMsg(uint32_t &token, RsGxsForumMsg &msg) = 0; virtual bool createMsg(uint32_t &token, RsGxsForumMsg &msg) = 0;
/*!
/*!
* To update forum group with new information * To update forum group with new information
* @param token the token used to check completion status of update * @param token the token used to check completion status of update
* @param group group to be updated, groupId element must be set or will be rejected * @param group group to be updated, groupId element must be set or will be rejected
* @return false groupId not set, true if set and accepted (still check token for completion) * @return false groupId not set, true if set and accepted (still check token for completion)
*/ */
virtual bool updateGroup(uint32_t &token, RsGxsForumGroup &group) = 0; virtual bool updateGroup(uint32_t &token, RsGxsForumGroup &group) = 0;
}; };

View File

@ -27,6 +27,7 @@
#ifndef RSGXSIFACE_H_ #ifndef RSGXSIFACE_H_
#define RSGXSIFACE_H_ #define RSGXSIFACE_H_
#include "retroshare/rsreputations.h"
#include "retroshare/rsgxsservice.h" #include "retroshare/rsgxsservice.h"
#include "gxs/rsgxsdata.h" #include "gxs/rsgxsdata.h"
#include "retroshare/rsgxsifacetypes.h" #include "retroshare/rsgxsifacetypes.h"
@ -181,6 +182,8 @@ public:
virtual uint32_t getDefaultSyncPeriod() = 0; virtual uint32_t getDefaultSyncPeriod() = 0;
virtual uint32_t getSyncPeriod(const RsGxsGroupId& grpId) = 0; virtual uint32_t getSyncPeriod(const RsGxsGroupId& grpId) = 0;
virtual void setSyncPeriod(const RsGxsGroupId& grpId,uint32_t age_in_secs) = 0; virtual void setSyncPeriod(const RsGxsGroupId& grpId,uint32_t age_in_secs) = 0;
virtual RsReputations::ReputationLevel minReputationForForwardingMessages(uint32_t group_sign_flags,uint32_t identity_flags)=0;
}; };

View File

@ -27,6 +27,7 @@
*/ */
#include "retroshare/rsgxsiface.h" #include "retroshare/rsgxsiface.h"
#include "retroshare/rsreputations.h"
#include "rsgxsflags.h" #include "rsgxsflags.h"
/*! /*!
@ -236,6 +237,10 @@ public:
mGxs->setSyncPeriod(grpId,age_in_secs); mGxs->setSyncPeriod(grpId,age_in_secs);
} }
RsReputations::ReputationLevel minReputationForForwardingMessages(uint32_t group_sign_flags,uint32_t identity_flags)
{
return mGxs->minReputationForForwardingMessages(group_sign_flags,identity_flags);
}
private: private:
RsGxsIface* mGxs; RsGxsIface* mGxs;

View File

@ -184,8 +184,6 @@ public:
// Cyril: Reputation details. At some point we might want to merge information // Cyril: Reputation details. At some point we might want to merge information
// between the two into a single global score. Since the old reputation system // between the two into a single global score. Since the old reputation system
// is not finished yet, I leave this in place. We should decide what to do with it. // is not finished yet, I leave this in place. We should decide what to do with it.
GxsReputation mReputation_oldSystem; // this is the old "mReputation" field, which apparently is not used.
RsReputations::ReputationInfo mReputation; RsReputations::ReputationInfo mReputation;
// avatar // avatar
@ -193,6 +191,7 @@ public:
// last usage // last usage
time_t mLastUsageTS ; time_t mLastUsageTS ;
std::map<std::string,time_t> mUseCases ;
}; };
@ -254,7 +253,14 @@ public:
virtual bool setAsRegularContact(const RsGxsId& id,bool is_a_contact) = 0 ; virtual bool setAsRegularContact(const RsGxsId& id,bool is_a_contact) = 0 ;
virtual bool isARegularContact(const RsGxsId& id) = 0 ; virtual bool isARegularContact(const RsGxsId& id) = 0 ;
virtual bool isBanned(const RsGxsId& id) =0;
/*!
* \brief overallReputationLevel
* Returns the overall reputation level of the supplied identity. See rsreputations.h
* \param id
* \return
*/
virtual RsReputations::ReputationLevel overallReputationLevel(const RsGxsId& id)=0;
virtual time_t getLastUsageTS(const RsGxsId &id) =0; virtual time_t getLastUsageTS(const RsGxsId &id) =0;
// Specific RsIdentity Functions.... // Specific RsIdentity Functions....

View File

@ -36,17 +36,28 @@ public:
// This is the interface file for the reputation system // This is the interface file for the reputation system
// //
enum Opinion { OPINION_NEGATIVE = 0, OPINION_NEUTRAL = 1, OPINION_POSITIVE = 2 } ; enum Opinion { OPINION_NEGATIVE = 0, OPINION_NEUTRAL = 1, OPINION_POSITIVE = 2 } ;
enum Assessment { ASSESSMENT_BAD = 0, ASSESSMENT_OK = 1 } ;
enum ReputationLevel { REPUTATION_LOCALLY_NEGATIVE = 0x00, // local opinion is positive
REPUTATION_REMOTELY_NEGATIVE = 0x01, // local opinion is neutral and friends are positive in average
REPUTATION_NEUTRAL = 0x02, // no reputation information ;
REPUTATION_REMOTELY_POSITIVE = 0x03, // local opinion is neutral and friends are negative in average
REPUTATION_LOCALLY_POSITIVE = 0x04, // local opinion is negative
REPUTATION_UNKNOWN = 0x05 // missing info
};
struct ReputationInfo struct ReputationInfo
{ {
ReputationInfo() : mOwnOpinion(OPINION_NEUTRAL), mOverallReputationScore(REPUTATION_THRESHOLD_DEFAULT), mFriendAverage(REPUTATION_THRESHOLD_DEFAULT),mAssessment(ASSESSMENT_OK){} ReputationInfo() : mOwnOpinion(OPINION_NEUTRAL), mFriendAverageScore(REPUTATION_THRESHOLD_DEFAULT),mOverallReputationLevel(REPUTATION_NEUTRAL){}
RsReputations::Opinion mOwnOpinion ; RsReputations::Opinion mOwnOpinion ;
float mOverallReputationScore ;
float mFriendAverage ; uint32_t mFriendsPositiveVotes ;
RsReputations::Assessment mAssessment; // this should help clients in taking decisions uint32_t mFriendsNegativeVotes ;
float mFriendAverageScore ;
RsReputations::ReputationLevel mOverallReputationLevel; // this should help clients in taking decisions
}; };
virtual bool setOwnOpinion(const RsGxsId& key_id, const Opinion& op) =0; virtual bool setOwnOpinion(const RsGxsId& key_id, const Opinion& op) =0;
@ -54,16 +65,16 @@ public:
// parameters // parameters
// virtual void setNodeAutoBanThreshold(uint32_t n) =0;
// virtual uint32_t nodeAutoBanThreshold() =0;
virtual void setNodeAutoPositiveOpinionForContacts(bool b) =0; virtual void setNodeAutoPositiveOpinionForContacts(bool b) =0;
virtual bool nodeAutoPositiveOpinionForContacts() =0; virtual bool nodeAutoPositiveOpinionForContacts() =0;
virtual float nodeAutoBanIdentitiesLimit() =0;
virtual void setNodeAutoBanIdentitiesLimit(float f) =0;
// This one is a proxy designed to allow fast checking of a GXS id. virtual uint32_t thresholdForRemotelyNegativeReputation()=0;
// it basically returns true if assessment is not ASSESSMENT_OK virtual uint32_t thresholdForRemotelyPositiveReputation()=0;
virtual void setThresholdForRemotelyNegativeReputation(uint32_t thresh)=0;
virtual void setThresholdForRemotelyPositiveReputation(uint32_t thresh)=0;
// 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) =0; virtual bool isIdentityBanned(const RsGxsId& id) =0;

View File

@ -108,6 +108,7 @@ class RsServiceControl
virtual ~RsServiceControl() { return; } virtual ~RsServiceControl() { return; }
virtual bool getOwnServices(RsPeerServiceInfo &info) = 0; virtual bool getOwnServices(RsPeerServiceInfo &info) = 0;
virtual std::string getServiceName(uint32_t service_id) = 0;
virtual bool getServicesAllowed(const RsPeerId &peerId, RsPeerServiceInfo &info) = 0; virtual bool getServicesAllowed(const RsPeerId &peerId, RsPeerServiceInfo &info) = 0;
virtual bool getServicesProvided(const RsPeerId &peerId, RsPeerServiceInfo &info) = 0; virtual bool getServicesProvided(const RsPeerId &peerId, RsPeerServiceInfo &info) = 0;

View File

@ -1094,7 +1094,7 @@ bool p3GxsCircles::locked_processLoadingCacheEntry(RsGxsCircleCache& cache)
rsPeers->getOnlineList(peers) ; rsPeers->getOnlineList(peers) ;
} }
mIdentities->requestKey(pit->first, peers); mIdentities->requestKey(pit->first, peers,"Membership status check in Circle "+cache.mCircleName+" ("+cache.mCircleId.toStdString()+")");
//isUnprocessedPeers = true; //isUnprocessedPeers = true;
} }
} }

View File

@ -141,6 +141,9 @@ static const uint32_t BANNED_NODES_UPDATE_DELAY = 313 ; // update
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 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 static const uint32_t BANNED_NODES_INACTIVITY_KEEP = 86400*60; // remove all info about banned nodes after 2 months of inactivity
static const uint32_t REPUTATION_DEFAULT_MIN_VOTES_FOR_REMOTELY_POSITIVE = 1; // min difference in votes that makes friends opinion globally positive
static const uint32_t REPUTATION_DEFAULT_MIN_VOTES_FOR_REMOTELY_NEGATIVE = 1; // min difference in votes that makes friends opinion globally negative
p3GxsReputation::p3GxsReputation(p3LinkMgr *lm) p3GxsReputation::p3GxsReputation(p3LinkMgr *lm)
:p3Service(), p3Config(), :p3Service(), p3Config(),
mReputationMtx("p3GxsReputation"), mLinkMgr(lm) mReputationMtx("p3GxsReputation"), mLinkMgr(lm)
@ -157,8 +160,9 @@ p3GxsReputation::p3GxsReputation(p3LinkMgr *lm)
mLastBannedNodesUpdate = 0 ; mLastBannedNodesUpdate = 0 ;
mBannedNodesProxyNeedsUpdate = false; mBannedNodesProxyNeedsUpdate = false;
mAutoBanIdentitiesLimit = REPUTATION_ASSESSMENT_THRESHOLD_X1;
mAutoSetPositiveOptionToContacts = true; // default mAutoSetPositiveOptionToContacts = true; // default
mMinVotesForRemotelyPositive = REPUTATION_DEFAULT_MIN_VOTES_FOR_REMOTELY_POSITIVE;
mMinVotesForRemotelyNegative = REPUTATION_DEFAULT_MIN_VOTES_FOR_REMOTELY_NEGATIVE;
} }
const std::string GXS_REPUTATION_APP_NAME = "gxsreputation"; const std::string GXS_REPUTATION_APP_NAME = "gxsreputation";
@ -256,27 +260,6 @@ bool p3GxsReputation::nodeAutoPositiveOpinionForContacts()
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/ RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
return mAutoSetPositiveOptionToContacts ; return mAutoSetPositiveOptionToContacts ;
} }
float p3GxsReputation::nodeAutoBanIdentitiesLimit()
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
return mAutoBanIdentitiesLimit - 1.0f;
}
void p3GxsReputation::setNodeAutoBanIdentitiesLimit(float f)
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
if(f < -1.0 || f >= 0.0)
{
std::cerr << "(EE) Unexpected value for auto ban identities limit: " << f << std::endl;
return ;
}
if(f != mAutoBanIdentitiesLimit)
{
mLastBannedNodesUpdate = 0 ;
mAutoBanIdentitiesLimit = f+1.0 ;
IndicateConfigChanged() ;
}
}
int p3GxsReputation::status() int p3GxsReputation::status()
{ {
@ -795,8 +778,9 @@ bool p3GxsReputation::getReputationInfo(const RsGxsId& gxsid, const RsPgpId& own
if(it == mReputations.end()) if(it == mReputations.end())
{ {
info.mOwnOpinion = RsReputations::OPINION_NEUTRAL ; info.mOwnOpinion = RsReputations::OPINION_NEUTRAL ;
info.mOverallReputationScore = RsReputations::REPUTATION_THRESHOLD_DEFAULT ; info.mFriendAverageScore = REPUTATION_THRESHOLD_DEFAULT ;
info.mFriendAverage = REPUTATION_THRESHOLD_DEFAULT ; info.mFriendsNegativeVotes = 0 ;
info.mFriendsPositiveVotes = 0 ;
owner_id = ownerNode ; owner_id = ownerNode ;
} }
@ -805,8 +789,9 @@ bool p3GxsReputation::getReputationInfo(const RsGxsId& gxsid, const RsPgpId& own
Reputation& rep(it->second) ; Reputation& rep(it->second) ;
info.mOwnOpinion = RsReputations::Opinion(rep.mOwnOpinion) ; info.mOwnOpinion = RsReputations::Opinion(rep.mOwnOpinion) ;
info.mOverallReputationScore = rep.mReputation ; info.mFriendAverageScore = rep.mFriendAverage ;
info.mFriendAverage = rep.mFriendAverage ; info.mFriendsNegativeVotes = rep.mFriendsNegative ;
info.mFriendsPositiveVotes = rep.mFriendsPositive ;
if(rep.mOwnerNode.isNull()) if(rep.mOwnerNode.isNull())
rep.mOwnerNode = ownerNode ; rep.mOwnerNode = ownerNode ;
@ -814,33 +799,67 @@ bool p3GxsReputation::getReputationInfo(const RsGxsId& gxsid, const RsPgpId& own
owner_id = rep.mOwnerNode ; owner_id = rep.mOwnerNode ;
} }
// now compute overall score and reputation
// 0 - check for own opinion. If positive or negative, it decides on the result
if(info.mOwnOpinion == RsReputations::OPINION_NEGATIVE)
{
// own opinion is always read in priority
info.mOverallReputationLevel = RsReputations::REPUTATION_LOCALLY_NEGATIVE ;
return true ;
}
if(info.mOwnOpinion == RsReputations::OPINION_POSITIVE)
{
// own opinion is always read in priority
info.mOverallReputationLevel = RsReputations::REPUTATION_LOCALLY_POSITIVE ;
return true ;
}
// 1 - check for banned PGP ids.
std::map<RsPgpId,BannedNodeInfo>::iterator it2 ; std::map<RsPgpId,BannedNodeInfo>::iterator it2 ;
if(!owner_id.isNull() && (it2 = mBannedPgpIds.find(owner_id))!=mBannedPgpIds.end()) if(!owner_id.isNull() && (it2 = mBannedPgpIds.find(owner_id))!=mBannedPgpIds.end())
{ {
// Check if current identity is present in the list of known identities for this banned node.
if(it2->second.known_identities.find(gxsid) == it2->second.known_identities.end()) if(it2->second.known_identities.find(gxsid) == it2->second.known_identities.end())
{ {
it2->second.known_identities.insert(gxsid) ; it2->second.known_identities.insert(gxsid) ;
it2->second.last_activity_TS = now ; it2->second.last_activity_TS = now ;
// if so, update
mBannedNodesProxyNeedsUpdate = true ; mBannedNodesProxyNeedsUpdate = true ;
} }
info.mAssessment = RsReputations::ASSESSMENT_BAD ;
#ifdef DEBUG_REPUTATION2 #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; std::cerr << "p3GxsReputations: identity " << gxsid << " is banned because owner node ID " << owner_id << " is banned (found in banned nodes list)." << std::endl;
#endif #endif
info.mOverallReputationLevel = RsReputations::REPUTATION_LOCALLY_NEGATIVE ;
return true ;
} }
else if(mPerNodeBannedIdsProxy.find(gxsid) != mPerNodeBannedIdsProxy.end()) // also check the proxy
if(mPerNodeBannedIdsProxy.find(gxsid) != mPerNodeBannedIdsProxy.end())
{ {
#ifdef DEBUG_REPUTATION2 #ifdef DEBUG_REPUTATION2
std::cerr << "p3GxsReputations: identity " << gxsid << " is banned because owner node ID " << owner_id << " is banned (found in proxy)." << std::endl; std::cerr << "p3GxsReputations: identity " << gxsid << " is banned because owner node ID " << owner_id << " is banned (found in proxy)." << std::endl;
#endif #endif
info.mAssessment = RsReputations::ASSESSMENT_BAD ; info.mOverallReputationLevel = RsReputations::REPUTATION_LOCALLY_NEGATIVE ;
return true;
} }
else if(info.mOverallReputationScore <= mAutoBanIdentitiesLimit) // 2 - now, our own opinion is neutral, which means we rely on what our friends tell
info.mAssessment = RsReputations::ASSESSMENT_BAD ;
if(info.mFriendsPositiveVotes >= info.mFriendsNegativeVotes + mMinVotesForRemotelyPositive)
info.mOverallReputationLevel = RsReputations::REPUTATION_REMOTELY_POSITIVE ;
else if(info.mFriendsPositiveVotes + mMinVotesForRemotelyNegative <= info.mFriendsNegativeVotes)
info.mOverallReputationLevel = RsReputations::REPUTATION_REMOTELY_NEGATIVE ;
else else
info.mAssessment = RsReputations::ASSESSMENT_OK ; info.mOverallReputationLevel = RsReputations::REPUTATION_NEUTRAL ;
#ifdef DEBUG_REPUTATION2 #ifdef DEBUG_REPUTATION2
std::cerr << " information present. OwnOp = " << info.mOwnOpinion << ", owner node=" << owner_id << ", overall score=" << info.mAssessment << std::endl; std::cerr << " information present. OwnOp = " << info.mOwnOpinion << ", owner node=" << owner_id << ", overall score=" << info.mAssessment << std::endl;
@ -849,6 +868,36 @@ bool p3GxsReputation::getReputationInfo(const RsGxsId& gxsid, const RsPgpId& own
return true ; return true ;
} }
uint32_t p3GxsReputation::thresholdForRemotelyNegativeReputation()
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
return mMinVotesForRemotelyNegative ;
}
uint32_t p3GxsReputation::thresholdForRemotelyPositiveReputation()
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
return mMinVotesForRemotelyPositive ;
}
void p3GxsReputation::setThresholdForRemotelyPositiveReputation(uint32_t thresh)
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
if(mMinVotesForRemotelyPositive == thresh || thresh==0)
return ;
mMinVotesForRemotelyPositive = thresh ;
IndicateConfigChanged();
}
void p3GxsReputation::setThresholdForRemotelyNegativeReputation(uint32_t thresh)
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
if(mMinVotesForRemotelyNegative == thresh || thresh==0)
return ;
mMinVotesForRemotelyNegative = thresh ;
IndicateConfigChanged();
}
void p3GxsReputation::banNode(const RsPgpId& id,bool b) void p3GxsReputation::banNode(const RsPgpId& id,bool b)
{ {
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/ RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
@ -887,7 +936,7 @@ bool p3GxsReputation::isIdentityBanned(const RsGxsId &id)
#ifdef DEBUG_REPUTATION #ifdef DEBUG_REPUTATION
std::cerr << "isIdentityBanned(): returning " << (info.mAssessment == RsReputations::ASSESSMENT_BAD) << " for GXS id " << id << std::endl; std::cerr << "isIdentityBanned(): returning " << (info.mAssessment == RsReputations::ASSESSMENT_BAD) << " for GXS id " << id << std::endl;
#endif #endif
return info.mAssessment == RsReputations::ASSESSMENT_BAD ; return info.mOverallReputationLevel == RsReputations::REPUTATION_LOCALLY_NEGATIVE ;
} }
bool p3GxsReputation::setOwnOpinion(const RsGxsId& gxsid, const RsReputations::Opinion& opinion) bool p3GxsReputation::setOwnOpinion(const RsGxsId& gxsid, const RsReputations::Opinion& opinion)
@ -1026,13 +1075,14 @@ bool p3GxsReputation::saveList(bool& cleanup, std::list<RsItem*> &savelist)
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ; RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ;
RsTlvKeyValue kv; RsTlvKeyValue 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" ; kv.key = "AUTO_REMOTELY_POSITIVE_THRESHOLD" ;
rs_sprintf(kv.value, "%f", mAutoBanIdentitiesLimit); rs_sprintf(kv.value, "%d", mMinVotesForRemotelyPositive);
vitem->tlvkvs.pairs.push_back(kv) ; vitem->tlvkvs.pairs.push_back(kv) ;
kv.key = "AUTO_REMOTELY_NEGATIVE_THRESHOLD" ;
rs_sprintf(kv.value, "%d", mMinVotesForRemotelyNegative);
vitem->tlvkvs.pairs.push_back(kv) ;
kv.key = "AUTO_POSITIVE_CONTACTS" ; kv.key = "AUTO_POSITIVE_CONTACTS" ;
kv.value = mAutoSetPositiveOptionToContacts?"YES":"NO"; kv.value = mAutoSetPositiveOptionToContacts?"YES":"NO";
@ -1093,27 +1143,24 @@ bool p3GxsReputation::loadList(std::list<RsItem *>& loadList)
if(vitem) if(vitem)
for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit)
{ {
// if(kit->key == "AUTO_BAN_NODES_THRESHOLD") if(kit->key == "AUTO_REMOTELY_POSITIVE_THRESHOLD")
// { {
// int val ; int val ;
// if (sscanf(kit->value.c_str(), "%d", &val) == 1) if (sscanf(kit->value.c_str(), "%d", &val) == 1)
// { {
// mPgpAutoBanThreshold = val ; mMinVotesForRemotelyPositive = val ;
// std::cerr << "Setting AutoBanNode threshold to " << val << std::endl ; std::cerr << "Setting mMinVotesForRemotelyPositive threshold to " << val << std::endl ;
// mLastBannedNodesUpdate = 0 ; // force update }
// } };
// }; if(kit->key == "AUTO_REMOTELY_NEGATIVE_THRESHOLD")
if(kit->key == "AUTO_BAN_IDENTITIES_THRESHOLD") {
{ int val ;
float val ; if (sscanf(kit->value.c_str(), "%d", &val) == 1)
{
if (sscanf(kit->value.c_str(), "%f", &val) == 1) mMinVotesForRemotelyNegative = val ;
{ std::cerr << "Setting mMinVotesForRemotelyNegative threshold to " << val << std::endl ;
mAutoBanIdentitiesLimit = val ; }
std::cerr << "Setting AutoBanIdentity threshold to " << val << std::endl ; };
mLastBannedNodesUpdate = 0 ; // force update
}
};
if(kit->key == "AUTO_POSITIVE_CONTACTS") if(kit->key == "AUTO_POSITIVE_CONTACTS")
{ {
mAutoSetPositiveOptionToContacts = (kit->value == "YES"); mAutoSetPositiveOptionToContacts = (kit->value == "YES");
@ -1292,11 +1339,22 @@ void Reputation::updateReputation()
int friend_total = 0; int friend_total = 0;
mFriendsNegative = 0 ;
mFriendsPositive = 0 ;
// accounts for all friends. Neutral opinions count for 1-1=0 // accounts for all friends. Neutral opinions count for 1-1=0
// because the average is performed over only accessible peers (not the total number) we need to shift to 1 // because the average is performed over only accessible peers (not the total number) we need to shift to 1
for(std::map<RsPeerId,RsReputations::Opinion>::const_iterator it(mOpinions.begin());it!=mOpinions.end();++it) for(std::map<RsPeerId,RsReputations::Opinion>::const_iterator it(mOpinions.begin());it!=mOpinions.end();++it)
{
if(it->second == RsReputations::OPINION_NEGATIVE)
++mFriendsNegative ;
if(it->second == RsReputations::OPINION_POSITIVE)
++mFriendsPositive ;
friend_total += it->second - 1; friend_total += it->second - 1;
}
if(mOpinions.empty()) // includes the case of no friends! if(mOpinions.empty()) // includes the case of no friends!
mFriendAverage = 1.0f ; mFriendAverage = 1.0f ;
@ -1351,9 +1409,9 @@ void Reputation::updateReputation()
// now compute a bias for PGP-signed ids. // now compute a bias for PGP-signed ids.
if(mOwnOpinion == RsReputations::OPINION_NEUTRAL) if(mOwnOpinion == RsReputations::OPINION_NEUTRAL)
mReputation = mFriendAverage ; mReputationScore = mFriendAverage ;
else else
mReputation = (float)mOwnOpinion ; mReputationScore = (float)mOwnOpinion ;
} }
void p3GxsReputation::debug_print() void p3GxsReputation::debug_print()
@ -1366,7 +1424,7 @@ void p3GxsReputation::debug_print()
for(std::map<RsGxsId,Reputation>::const_iterator it(mReputations.begin());it!=mReputations.end();++it) for(std::map<RsGxsId,Reputation>::const_iterator it(mReputations.begin());it!=mReputations.end();++it)
{ {
std::cerr << " " << it->first << ": own: " << it->second.mOwnOpinion << ", Friend average: " << it->second.mFriendAverage << ", global_score: " << it->second.mReputation std::cerr << " " << it->first << ": own: " << it->second.mOwnOpinion << ", Friend average: " << it->second.mFriendAverage << ", global_score: " << it->second.mReputationScore
<< ", last own update: " << now - it->second.mOwnOpinionTs << " secs ago." << std::endl; << ", last own update: " << now - it->second.mOwnOpinionTs << " secs ago." << std::endl;
#ifdef DEBUG_REPUTATION2 #ifdef DEBUG_REPUTATION2
for(std::map<RsPeerId,RsReputations::Opinion>::const_iterator it2(it->second.mOpinions.begin());it2!=it->second.mOpinions.end();++it2) for(std::map<RsPeerId,RsReputations::Opinion>::const_iterator it2(it->second.mOpinions.begin());it2!=it->second.mOpinions.end();++it2)

View File

@ -69,10 +69,10 @@ class Reputation
{ {
public: public:
Reputation() Reputation()
:mOwnOpinion(RsReputations::OPINION_NEUTRAL), mOwnOpinionTs(0),mFriendAverage(1.0f), mReputation(RsReputations::OPINION_NEUTRAL),mIdentityFlags(REPUTATION_IDENTITY_FLAG_NEEDS_UPDATE){ } :mOwnOpinion(RsReputations::OPINION_NEUTRAL), mOwnOpinionTs(0),mFriendAverage(1.0f), mReputationScore(RsReputations::OPINION_NEUTRAL),mIdentityFlags(REPUTATION_IDENTITY_FLAG_NEEDS_UPDATE){ }
Reputation(const RsGxsId& /*about*/) Reputation(const RsGxsId& /*about*/)
:mOwnOpinion(RsReputations::OPINION_NEUTRAL), mOwnOpinionTs(0),mFriendAverage(1.0f), mReputation(RsReputations::OPINION_NEUTRAL),mIdentityFlags(REPUTATION_IDENTITY_FLAG_NEEDS_UPDATE){ } :mOwnOpinion(RsReputations::OPINION_NEUTRAL), mOwnOpinionTs(0),mFriendAverage(1.0f), mReputationScore(RsReputations::OPINION_NEUTRAL),mIdentityFlags(REPUTATION_IDENTITY_FLAG_NEEDS_UPDATE){ }
void updateReputation(); void updateReputation();
@ -80,12 +80,15 @@ public:
int32_t mOwnOpinion; int32_t mOwnOpinion;
time_t mOwnOpinionTs; time_t mOwnOpinionTs;
float mFriendAverage ; float mFriendAverage ;
float mReputation; uint32_t mFriendsPositive ; // number of positive vites from friends
uint32_t mFriendsNegative ; // number of negative vites from friends
RsPgpId mOwnerNode; float mReputationScore;
uint32_t mIdentityFlags; RsPgpId mOwnerNode;
uint32_t mIdentityFlags;
}; };
@ -109,13 +112,13 @@ public:
virtual bool isNodeBanned(const RsPgpId& id); virtual bool isNodeBanned(const RsPgpId& id);
virtual void banNode(const RsPgpId& id,bool b) ; virtual void banNode(const RsPgpId& id,bool b) ;
//virtual void setNodeAutoBanThreshold(uint32_t n) ;
//virtual uint32_t nodeAutoBanThreshold() ;
virtual void setNodeAutoPositiveOpinionForContacts(bool b) ; virtual void setNodeAutoPositiveOpinionForContacts(bool b) ;
virtual bool nodeAutoPositiveOpinionForContacts() ; virtual bool nodeAutoPositiveOpinionForContacts() ;
virtual float nodeAutoBanIdentitiesLimit() ;
virtual void setNodeAutoBanIdentitiesLimit(float f) ; uint32_t thresholdForRemotelyNegativeReputation();
uint32_t thresholdForRemotelyPositiveReputation();
void setThresholdForRemotelyNegativeReputation(uint32_t thresh);
void setThresholdForRemotelyPositiveReputation(uint32_t thresh);
/***** overloaded from p3Service *****/ /***** overloaded from p3Service *****/
virtual int tick(); virtual int tick();
@ -180,8 +183,10 @@ private:
// PGP Ids auto-banned. This is updated regularly. // PGP Ids auto-banned. This is updated regularly.
std::map<RsPgpId,BannedNodeInfo> mBannedPgpIds ; std::map<RsPgpId,BannedNodeInfo> mBannedPgpIds ;
std::set<RsGxsId> mPerNodeBannedIdsProxy ; std::set<RsGxsId> mPerNodeBannedIdsProxy ;
//uint32_t mPgpAutoBanThreshold ;
bool mBannedNodesProxyNeedsUpdate ; bool mBannedNodesProxyNeedsUpdate ;
uint32_t mMinVotesForRemotelyPositive ;
uint32_t mMinVotesForRemotelyNegative ;
}; };
#endif //SERVICE_RSGXSREPUTATION_HEADER #endif //SERVICE_RSGXSREPUTATION_HEADER

View File

@ -128,8 +128,9 @@ RsIdentity *rsIdentity = NULL;
/* delays */ /* delays */
#define CACHETEST_PERIOD 60 #define CACHETEST_PERIOD 60
#define DELAY_BETWEEN_CONFIG_UPDATES 300 #define DELAY_BETWEEN_CONFIG_UPDATES 300
#define GXS_MAX_KEY_TS_USAGE_MAP_SIZE 5
#define OWNID_RELOAD_DELAY 10 #define OWNID_RELOAD_DELAY 10
@ -255,23 +256,47 @@ void p3IdService::slowIndicateConfigChanged()
} }
time_t p3IdService::locked_getLastUsageTS(const RsGxsId& gxs_id) time_t p3IdService::locked_getLastUsageTS(const RsGxsId& gxs_id)
{ {
std::map<RsGxsId,time_t>::const_iterator it = mKeysTS.find(gxs_id) ; std::map<RsGxsId,keyTSInfo>::const_iterator it = mKeysTS.find(gxs_id) ;
if(it == mKeysTS.end()) if(it == mKeysTS.end())
return 0 ; return 0 ;
else else
return it->second ; return it->second.TS ;
} }
void p3IdService::timeStampKey(const RsGxsId& gxs_id) void p3IdService::timeStampKey(const RsGxsId& gxs_id, const std::string& reason)
{ {
if(rsReputations->isIdentityBanned(gxs_id) ) if(rsReputations->isIdentityBanned(gxs_id) )
{ {
std::cerr << "(II) p3IdService:timeStampKey(): refusing to time stamp key " << gxs_id << " because it is banned." << std::endl; std::cerr << "(II) p3IdService:timeStampKey(): refusing to time stamp key " << gxs_id << " because it is banned." << std::endl;
return ; return ;
} }
std::cerr << "(II) time stamping key " << gxs_id << " for the following reason: " << reason << std::endl;
RS_STACK_MUTEX(mIdMtx) ; RS_STACK_MUTEX(mIdMtx) ;
mKeysTS[gxs_id] = time(NULL) ;
time_t now = time(NULL) ;
keyTSInfo& info(mKeysTS[gxs_id]) ;
info.TS = now ;
info.usage_map[reason] = now;
while(info.usage_map.size() > GXS_MAX_KEY_TS_USAGE_MAP_SIZE)
{
// This is very costly, but normally the outerloop should never be rolled more than once.
std::map<std::string,time_t>::iterator best_it ;
time_t best_time = now+1;
for(std::map<std::string,time_t>::iterator it(info.usage_map.begin());it!=info.usage_map.end();++it)
if(it->second < best_time)
{
best_time = it->second ;
best_it = it;
}
info.usage_map.erase(best_it) ;
}
slowIndicateConfigChanged() ; slowIndicateConfigChanged() ;
} }
@ -286,7 +311,7 @@ bool p3IdService::loadList(std::list<RsItem*>& items)
if( (lii = dynamic_cast<RsGxsIdLocalInfoItem*>(*it)) != NULL) if( (lii = dynamic_cast<RsGxsIdLocalInfoItem*>(*it)) != NULL)
{ {
for(std::map<RsGxsId,time_t>::const_iterator it2 = lii->mTimeStamps.begin();it2!=lii->mTimeStamps.end();++it2) for(std::map<RsGxsId,time_t>::const_iterator it2 = lii->mTimeStamps.begin();it2!=lii->mTimeStamps.end();++it2)
mKeysTS.insert(*it2) ; mKeysTS[it2->first].TS = it2->second;
mContacts = lii->mContacts ; mContacts = lii->mContacts ;
} }
@ -307,7 +332,10 @@ bool p3IdService::saveList(bool& cleanup,std::list<RsItem*>& items)
RS_STACK_MUTEX(mIdMtx) ; RS_STACK_MUTEX(mIdMtx) ;
cleanup = true ; cleanup = true ;
RsGxsIdLocalInfoItem *item = new RsGxsIdLocalInfoItem ; RsGxsIdLocalInfoItem *item = new RsGxsIdLocalInfoItem ;
item->mTimeStamps = mKeysTS ;
for(std::map<RsGxsId,keyTSInfo>::const_iterator it(mKeysTS.begin());it!=mKeysTS.end();++it)
item->mTimeStamps[it->first] = it->second.TS;
item->mContacts = mContacts ; item->mContacts = mContacts ;
items.push_back(item) ; items.push_back(item) ;
@ -317,7 +345,7 @@ bool p3IdService::saveList(bool& cleanup,std::list<RsItem*>& items)
class IdCacheEntryCleaner class IdCacheEntryCleaner
{ {
public: public:
IdCacheEntryCleaner(const std::map<RsGxsId,time_t>& last_usage_TSs) : mLastUsageTS(last_usage_TSs) {} IdCacheEntryCleaner(const std::map<RsGxsId,p3IdService::keyTSInfo>& last_usage_TSs) : mLastUsageTS(last_usage_TSs) {}
bool processEntry(RsGxsIdCache& entry) bool processEntry(RsGxsIdCache& entry)
{ {
@ -338,11 +366,11 @@ public:
return true ; return true ;
} }
std::map<RsGxsId,time_t>::const_iterator it = mLastUsageTS.find(gxs_id) ; std::map<RsGxsId,p3IdService::keyTSInfo>::const_iterator it = mLastUsageTS.find(gxs_id) ;
bool no_ts = (it == mLastUsageTS.end()) ; bool no_ts = (it == mLastUsageTS.end()) ;
time_t last_usage_ts = no_ts?0:(it->second); time_t last_usage_ts = no_ts?0:(it->second.TS);
time_t max_keep_time ; time_t max_keep_time ;
if(no_ts) if(no_ts)
@ -370,7 +398,7 @@ public:
} }
std::list<RsGxsId> ids_to_delete ; std::list<RsGxsId> ids_to_delete ;
const std::map<RsGxsId,time_t>& mLastUsageTS; const std::map<RsGxsId,p3IdService::keyTSInfo>& mLastUsageTS;
}; };
void p3IdService::cleanUnusedKeys() void p3IdService::cleanUnusedKeys()
@ -495,7 +523,7 @@ void p3IdService::notifyChanges(std::vector<RsGxsNotify *> &changes)
// also time_stamp the key that this group represents // also time_stamp the key that this group represents
timeStampKey(RsGxsId(*git)) ; timeStampKey(RsGxsId(*git),"Group meta data changed") ;
++git; ++git;
} }
@ -552,7 +580,16 @@ bool p3IdService::getIdDetails(const RsGxsId &id, RsIdentityDetails &details)
rsReputations->setOwnOpinion(id,RsReputations::OPINION_POSITIVE) ; rsReputations->setOwnOpinion(id,RsReputations::OPINION_POSITIVE) ;
details = data.details; details = data.details;
details.mLastUsageTS = locked_getLastUsageTS(id) ;
std::map<RsGxsId,keyTSInfo>::const_iterator it = mKeysTS.find(id) ;
if(it == mKeysTS.end())
details.mLastUsageTS = 0 ;
else
{
details.mLastUsageTS = it->second.TS ;
details.mUseCases = it->second.usage_map ;
}
// one utf8 symbol can be at most 4 bytes long - would be better to measure real unicode length !!! // one utf8 symbol can be at most 4 bytes long - would be better to measure real unicode length !!!
if(details.mNickname.length() > RSID_MAXIMUM_NICKNAME_SIZE*4) if(details.mNickname.length() > RSID_MAXIMUM_NICKNAME_SIZE*4)
@ -570,15 +607,12 @@ bool p3IdService::getIdDetails(const RsGxsId &id, RsIdentityDetails &details)
return false; return false;
} }
bool p3IdService::isBanned(const RsGxsId &id) RsReputations::ReputationLevel p3IdService::overallReputationLevel(const RsGxsId &id)
{ {
RsIdentityDetails det ; RsIdentityDetails det ;
getIdDetails(id,det) ; getIdDetails(id,det) ;
#ifdef DEBUG_REPUTATION return det.mReputation.mOverallReputationLevel ;
std::cerr << "isIdentityBanned(): returning " << (det.mReputation.mAssessment == RsReputations::ASSESSMENT_BAD) << " for GXS id " << id << std::endl;
#endif
return det.mReputation.mAssessment == RsReputations::ASSESSMENT_BAD ;
} }
bool p3IdService::isOwnId(const RsGxsId& id) bool p3IdService::isOwnId(const RsGxsId& id)
@ -752,7 +786,7 @@ static void mergeIds(std::map<RsGxsId,std::list<RsPeerId> >& idmap,const RsGxsId
old_peers.push_back(*it) ; old_peers.push_back(*it) ;
} }
bool p3IdService::requestKey(const RsGxsId &id, const std::list<RsPeerId>& peers) bool p3IdService::requestKey(const RsGxsId &id, const std::list<RsPeerId>& peers,const std::string& info)
{ {
if(id.isNull()) if(id.isNull())
{ {
@ -773,12 +807,12 @@ bool p3IdService::requestKey(const RsGxsId &id, const std::list<RsPeerId>& peers
RsReputations::ReputationInfo info ; RsReputations::ReputationInfo info ;
rsReputations->getReputationInfo(id,RsPgpId(),info) ; rsReputations->getReputationInfo(id,RsPgpId(),info) ;
if(info.mAssessment == RsReputations::ASSESSMENT_BAD) if(info.mOverallReputationLevel == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
{ {
std::cerr << "(II) not requesting Key " << id << " because it has been banned." << std::endl; std::cerr << "(II) not requesting Key " << id << " because it has been banned." << std::endl;
{ {
RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/ RS_STACK_MUTEX(mIdMtx); /********** STACK LOCKED MTX ******/
mIdsNotPresent.erase(id) ; mIdsNotPresent.erase(id) ;
} }
return true; return true;
@ -796,6 +830,10 @@ bool p3IdService::requestKey(const RsGxsId &id, const std::list<RsPeerId>& peers
return true ; return true ;
} }
} }
{
RS_STACK_MUTEX(mIdMtx); /********** STACK LOCKED MTX ******/
mKeysTS[id].usage_map["Requested to friends: "+info] = time(NULL) ;
}
return cache_request_load(id, peers); return cache_request_load(id, peers);
} }
@ -892,10 +930,10 @@ bool p3IdService::signData(const uint8_t *data,uint32_t data_size,const RsGxsId&
return false ; return false ;
} }
error_status = RS_GIXS_ERROR_NO_ERROR ; error_status = RS_GIXS_ERROR_NO_ERROR ;
timeStampKey(own_gxs_id) ; timeStampKey(own_gxs_id,"Own GXS id") ;
return true ; return true ;
} }
bool p3IdService::validateData(const uint8_t *data,uint32_t data_size,const RsTlvKeySignature& signature,bool force_load,uint32_t& signing_error) bool p3IdService::validateData(const uint8_t *data,uint32_t data_size,const RsTlvKeySignature& signature,bool force_load,const std::string& info_string,uint32_t& signing_error)
{ {
// RsIdentityDetails details ; // RsIdentityDetails details ;
// getIdDetails(signature.keyId,details); // getIdDetails(signature.keyId,details);
@ -929,7 +967,7 @@ bool p3IdService::validateData(const uint8_t *data,uint32_t data_size,const RsTl
} }
signing_error = RS_GIXS_ERROR_NO_ERROR ; signing_error = RS_GIXS_ERROR_NO_ERROR ;
timeStampKey(signature.keyId) ; timeStampKey(signature.keyId,"Used in signature checking: "+info_string ) ;
return true ; return true ;
} }
bool p3IdService::encryptData(const uint8_t *decrypted_data,uint32_t decrypted_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& error_status) bool p3IdService::encryptData(const uint8_t *decrypted_data,uint32_t decrypted_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& error_status)
@ -957,7 +995,7 @@ bool p3IdService::encryptData(const uint8_t *decrypted_data,uint32_t decrypted_d
return false ; return false ;
} }
error_status = RS_GIXS_ERROR_NO_ERROR ; error_status = RS_GIXS_ERROR_NO_ERROR ;
timeStampKey(encryption_key_id) ; timeStampKey(encryption_key_id,"Used to encrypt data") ;
return true ; return true ;
} }
@ -989,7 +1027,7 @@ bool p3IdService::decryptData(const uint8_t *encrypted_data,uint32_t encrypted_d
return false ; return false ;
} }
error_status = RS_GIXS_ERROR_NO_ERROR ; error_status = RS_GIXS_ERROR_NO_ERROR ;
timeStampKey(key_id) ; timeStampKey(key_id,"Used to decrypt data") ;
return true ; return true ;
} }
@ -2399,7 +2437,8 @@ bool p3IdService::cache_load_ownids(uint32_t token)
// This prevents automatic deletion to get rid of them. // This prevents automatic deletion to get rid of them.
// In other words, own ids are always used. // In other words, own ids are always used.
mKeysTS[RsGxsId(item->meta.mGroupId)] = time(NULL) ;
mKeysTS[RsGxsId(item->meta.mGroupId)].TS = time(NULL) ;
} }
delete item ; delete item ;
} }
@ -2493,7 +2532,7 @@ bool p3IdService::cachetest_handlerequest(uint32_t token)
if (!haveKey(*vit)) if (!haveKey(*vit))
{ {
std::list<RsPeerId> nullpeers; std::list<RsPeerId> nullpeers;
requestKey(*vit, nullpeers); requestKey(*vit, nullpeers,"Cache test in p3IdService");
#ifdef DEBUG_IDS #ifdef DEBUG_IDS
std::cerr << "p3IdService::cachetest_request() Requested Key Id: " << *vit; std::cerr << "p3IdService::cachetest_request() Requested Key Id: " << *vit;
@ -2691,7 +2730,7 @@ RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(RsGxsGrpIte
std::cerr << std::endl; std::cerr << std::endl;
return SERVICE_CREATE_FAIL; return SERVICE_CREATE_FAIL;
} }
mKeysTS[RsGxsId(item->meta.mGroupId)] = time(NULL) ; mKeysTS[RsGxsId(item->meta.mGroupId)].TS = time(NULL) ;
/********************* TEMP HACK UNTIL GXS FILLS IN GROUP_ID *****************/ /********************* TEMP HACK UNTIL GXS FILLS IN GROUP_ID *****************/
@ -2851,7 +2890,7 @@ RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(RsGxsGrpIte
if (std::find(mOwnIds.begin(), mOwnIds.end(), gxsId) == mOwnIds.end()) if (std::find(mOwnIds.begin(), mOwnIds.end(), gxsId) == mOwnIds.end())
{ {
mOwnIds.push_back(gxsId); mOwnIds.push_back(gxsId);
mKeysTS[gxsId] = time(NULL) ; mKeysTS[gxsId].TS = time(NULL) ;
} }
} }

View File

@ -274,7 +274,7 @@ public:
virtual bool setAsRegularContact(const RsGxsId& id,bool is_a_contact) ; virtual bool setAsRegularContact(const RsGxsId& id,bool is_a_contact) ;
virtual bool isARegularContact(const RsGxsId& id) ; virtual bool isARegularContact(const RsGxsId& id) ;
virtual bool isBanned(const RsGxsId& id) ; virtual RsReputations::ReputationLevel overallReputationLevel(const RsGxsId& id);
virtual time_t getLastUsageTS(const RsGxsId &id) ; virtual time_t getLastUsageTS(const RsGxsId &id) ;
/**************** RsGixs Implementation ***************/ /**************** RsGixs Implementation ***************/
@ -287,7 +287,7 @@ public:
virtual bool isOwnId(const RsGxsId& key_id) ; virtual bool isOwnId(const RsGxsId& key_id) ;
virtual bool signData(const uint8_t *data,uint32_t data_size,const RsGxsId& signer_id,RsTlvKeySignature& signature,uint32_t& signing_error) ; virtual bool signData(const uint8_t *data,uint32_t data_size,const RsGxsId& signer_id,RsTlvKeySignature& signature,uint32_t& signing_error) ;
virtual bool validateData(const uint8_t *data,uint32_t data_size,const RsTlvKeySignature& signature,bool force_load,uint32_t& signing_error) ; virtual bool validateData(const uint8_t *data,uint32_t data_size,const RsTlvKeySignature& signature,bool force_load,const std::string& info_string,uint32_t& signing_error) ;
virtual bool encryptData(const uint8_t *decrypted_data,uint32_t decrypted_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& encryption_error) ; virtual bool encryptData(const uint8_t *decrypted_data,uint32_t decrypted_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& encryption_error) ;
virtual bool decryptData(const uint8_t *encrypted_data,uint32_t encrypted_data_size,uint8_t *& decrypted_data,uint32_t& decrypted_data_size,const RsGxsId& encryption_key_id,uint32_t& encryption_error) ; virtual bool decryptData(const uint8_t *encrypted_data,uint32_t encrypted_data_size,uint8_t *& decrypted_data,uint32_t& decrypted_data_size,const RsGxsId& encryption_key_id,uint32_t& encryption_error) ;
@ -298,7 +298,7 @@ public:
virtual bool getKey(const RsGxsId &id, RsTlvPublicRSAKey &key); virtual bool getKey(const RsGxsId &id, RsTlvPublicRSAKey &key);
virtual bool getPrivateKey(const RsGxsId &id, RsTlvPrivateRSAKey &key); virtual bool getPrivateKey(const RsGxsId &id, RsTlvPrivateRSAKey &key);
virtual bool requestKey(const RsGxsId &id, const std::list<RsPeerId> &peers); virtual bool requestKey(const RsGxsId &id, const std::list<RsPeerId> &peers, const std::string &info);
virtual bool requestPrivateKey(const RsGxsId &id); virtual bool requestPrivateKey(const RsGxsId &id);
@ -467,7 +467,7 @@ private:
void cleanUnusedKeys() ; void cleanUnusedKeys() ;
void slowIndicateConfigChanged() ; void slowIndicateConfigChanged() ;
virtual void timeStampKey(const RsGxsId& id) ; virtual void timeStampKey(const RsGxsId& id,const std::string& reason) ;
time_t locked_getLastUsageTS(const RsGxsId& gxs_id); time_t locked_getLastUsageTS(const RsGxsId& gxs_id);
std::string genRandomId(int len = 20); std::string genRandomId(int len = 20);
@ -507,10 +507,19 @@ private:
private: private:
struct keyTSInfo
{
keyTSInfo() : TS(0) {}
time_t TS ;
std::map<std::string,time_t> usage_map ;
};
friend class IdCacheEntryCleaner;
std::map<uint32_t, std::set<RsGxsGroupId> > mIdsPendingCache; std::map<uint32_t, std::set<RsGxsGroupId> > mIdsPendingCache;
std::map<uint32_t, std::list<RsGxsGroupId> > mGroupNotPresent; std::map<uint32_t, std::list<RsGxsGroupId> > mGroupNotPresent;
std::map<RsGxsId, std::list<RsPeerId> > mIdsNotPresent; std::map<RsGxsId, std::list<RsPeerId> > mIdsNotPresent;
std::map<RsGxsId,time_t> mKeysTS ; std::map<RsGxsId,keyTSInfo> mKeysTS ;
// keep a list of regular contacts. This is useful to sort IDs, and allow some services to priviledged ids only. // keep a list of regular contacts. This is useful to sort IDs, and allow some services to priviledged ids only.
std::set<RsGxsId> mContacts; std::set<RsGxsId> mContacts;

View File

@ -36,9 +36,13 @@
#include <sys/timeb.h> #include <sys/timeb.h>
#endif #endif
std::string RsUtil::NumberToString(uint64_t n) std::string RsUtil::NumberToString(uint64_t n,bool hex)
{ {
std::ostringstream os ; std::ostringstream os ;
if(hex)
os << std::hex ;
os << n ; os << n ;
os.flush() ; os.flush() ;

View File

@ -36,7 +36,7 @@ namespace RsUtil {
std::string BinToHex(const std::string &bin); std::string BinToHex(const std::string &bin);
std::string BinToHex(const char *arr, const uint32_t len); std::string BinToHex(const char *arr, const uint32_t len);
std::string BinToHex(const unsigned char *arr, const uint32_t len); std::string BinToHex(const unsigned char *arr, const uint32_t len);
std::string NumberToString(uint64_t n); std::string NumberToString(uint64_t n, bool hex=false);
std::string HashId(const std::string &id, bool reverse = false); std::string HashId(const std::string &id, bool reverse = false);
//std::string AccurateTimeString(); //std::string AccurateTimeString();

View File

@ -264,10 +264,9 @@ void IdDetailsDialog::insertIdDetails(uint32_t token)
RsReputations::ReputationInfo info ; RsReputations::ReputationInfo info ;
rsReputations->getReputationInfo(RsGxsId(data.mMeta.mGroupId),data.mPgpId,info) ; rsReputations->getReputationInfo(RsGxsId(data.mMeta.mGroupId),data.mPgpId,info) ;
ui->neighborNodesOpinion_TF->setText(QString::number(info.mOverallReputationScore-1.0f)); #warning (csoler) Do we need to do this? This code is apparently not used.
ui->neighborNodesOpinion_TF->setText(QString::number(info.mFriendAverageScore));
ui->overallOpinion_TF->setText(QString::number(info.mOverallReputationScore-1.0f) +" ("+ ui->overallOpinion_TF->setText(QString::number(info.mOverallReputationLevel));
((info.mAssessment == RsReputations::ASSESSMENT_OK)? tr("OK") : tr("Banned")) +")" ) ;
switch(info.mOwnOpinion) switch(info.mOwnOpinion)
{ {

View File

@ -26,6 +26,8 @@
#include <QMessageBox> #include <QMessageBox>
#include <QMenu> #include <QMenu>
#include <QWidgetAction> #include <QWidgetAction>
#include <QStyledItemDelegate>
#include <QPainter>
#include "IdDialog.h" #include "IdDialog.h"
#include "ui_IdDialog.h" #include "ui_IdDialog.h"
@ -127,6 +129,7 @@ class TreeWidgetItem : public QTreeWidgetItem {
} }
} }
}; };
/** Constructor */ /** Constructor */
IdDialog::IdDialog(QWidget *parent) : IdDialog::IdDialog(QWidget *parent) :
RsGxsUpdateBroadcastPage(rsIdentity, parent), RsGxsUpdateBroadcastPage(rsIdentity, parent),
@ -142,12 +145,15 @@ IdDialog::IdDialog(QWidget *parent) :
ownItem = new QTreeWidgetItem(); ownItem = new QTreeWidgetItem();
ownItem->setText(0, tr("My own identities")); ownItem->setText(0, tr("My own identities"));
ownItem->setData(RSID_COL_VOTES, Qt::DecorationRole,0xff); // this is in order to prevent displaying a reputaiton icon next to these items.
allItem = new QTreeWidgetItem(); allItem = new QTreeWidgetItem();
allItem->setText(0, tr("All")); allItem->setText(0, tr("All"));
allItem->setData(RSID_COL_VOTES, Qt::DecorationRole,0xff);
contactsItem = new QTreeWidgetItem(); contactsItem = new QTreeWidgetItem();
contactsItem->setText(0, tr("My contacts")); contactsItem->setText(0, tr("My contacts"));
contactsItem->setData(RSID_COL_VOTES, Qt::DecorationRole,0xff);
ui->treeWidget_membership->clear(); ui->treeWidget_membership->clear();
@ -318,6 +324,8 @@ IdDialog::IdDialog(QWidget *parent) :
ui->idTreeWidget->setColumnWidth(RSID_COL_IDTYPE, 18 * fontWidth); ui->idTreeWidget->setColumnWidth(RSID_COL_IDTYPE, 18 * fontWidth);
ui->idTreeWidget->setColumnWidth(RSID_COL_VOTES, 7 * fontWidth); ui->idTreeWidget->setColumnWidth(RSID_COL_VOTES, 7 * fontWidth);
ui->idTreeWidget->setItemDelegateForColumn(RSID_COL_VOTES,new ReputationItemDelegate(RsReputations::ReputationLevel(0xff))) ;
//QHeaderView_setSectionResizeMode(ui->idTreeWidget->header(), QHeaderView::ResizeToContents); //QHeaderView_setSectionResizeMode(ui->idTreeWidget->header(), QHeaderView::ResizeToContents);
mIdQueue = new TokenQueue(rsIdentity->getTokenService(), this); mIdQueue = new TokenQueue(rsIdentity->getTokenService(), this);
@ -1392,7 +1400,8 @@ bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item,
bool isOwnId = (data.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN); bool isOwnId = (data.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN);
RsIdentityDetails idd ; RsIdentityDetails idd ;
rsIdentity->getIdDetails(RsGxsId(data.mMeta.mGroupId),idd) ; rsIdentity->getIdDetails(RsGxsId(data.mMeta.mGroupId),idd) ;
bool isBanned = idd.mReputation.mAssessment == RsReputations::ASSESSMENT_BAD;
bool isBanned = idd.mReputation.mOverallReputationLevel == RsReputations::REPUTATION_LOCALLY_NEGATIVE;
uint32_t item_flags = 0 ; uint32_t item_flags = 0 ;
/* do filtering */ /* do filtering */
@ -1462,7 +1471,7 @@ bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item,
item->setData(RSID_COL_KEYID, Qt::UserRole,QVariant(item_flags)) ; item->setData(RSID_COL_KEYID, Qt::UserRole,QVariant(item_flags)) ;
item->setTextAlignment(RSID_COL_VOTES, Qt::AlignRight | Qt::AlignVCenter); item->setTextAlignment(RSID_COL_VOTES, Qt::AlignRight | Qt::AlignVCenter);
item->setData(RSID_COL_VOTES,Qt::DisplayRole, QString::number(idd.mReputation.mOverallReputationScore - 1.0f,'f',3)); item->setData(RSID_COL_VOTES,Qt::DecorationRole, idd.mReputation.mOverallReputationLevel);
if(isOwnId) if(isOwnId)
{ {
@ -1836,10 +1845,24 @@ void IdDialog::insertIdDetails(uint32_t token)
RsReputations::ReputationInfo info ; RsReputations::ReputationInfo info ;
rsReputations->getReputationInfo(RsGxsId(data.mMeta.mGroupId),data.mPgpId,info) ; rsReputations->getReputationInfo(RsGxsId(data.mMeta.mGroupId),data.mPgpId,info) ;
ui->neighborNodesOpinion_TF->setText(QString::number(info.mFriendAverage - 1.0f)); QString frep_string ;
if(info.mFriendsPositiveVotes > 0) frep_string += QString::number(info.mFriendsPositiveVotes) + tr(" positive ") ;
if(info.mFriendsNegativeVotes > 0) frep_string += QString::number(info.mFriendsNegativeVotes) + tr(" negative ") ;
ui->overallOpinion_TF->setText(QString::number(info.mOverallReputationScore - 1.0f) +" ("+ if(info.mFriendsPositiveVotes==0 && info.mFriendsNegativeVotes==0)
((info.mAssessment == RsReputations::ASSESSMENT_OK)? tr("OK") : tr("Banned")) +")" ) ; frep_string = tr("No votes from friends") ;
ui->neighborNodesOpinion_TF->setText(frep_string) ;
switch(info.mOverallReputationLevel)
{
case RsReputations::REPUTATION_LOCALLY_POSITIVE: ui->overallOpinion_TF->setText(tr("Positive")) ; break ;
case RsReputations::REPUTATION_LOCALLY_NEGATIVE: ui->overallOpinion_TF->setText(tr("Negative (Banned by you)")) ; break ;
case RsReputations::REPUTATION_REMOTELY_POSITIVE: ui->overallOpinion_TF->setText(tr("Positive (according to your friends)")) ; break ;
case RsReputations::REPUTATION_REMOTELY_NEGATIVE: ui->overallOpinion_TF->setText(tr("Negative (according to your friends)")) ; break ;
default:
case RsReputations::REPUTATION_NEUTRAL: ui->overallOpinion_TF->setText(tr("Neutral")) ; break ;
}
switch(info.mOwnOpinion) switch(info.mOwnOpinion)
{ {
@ -1849,6 +1872,24 @@ void IdDialog::insertIdDetails(uint32_t token)
default: default:
std::cerr << "Unexpected value in own opinion: " << info.mOwnOpinion << std::endl; std::cerr << "Unexpected value in own opinion: " << info.mOwnOpinion << std::endl;
} }
// now fill in usage cases
RsIdentityDetails det ;
rsIdentity->getIdDetails(RsGxsId(data.mMeta.mGroupId),det) ;
QString usage_txt ;
std::map<time_t,std::string> rmap ;
for(std::map<std::string,time_t>::const_iterator it(det.mUseCases.begin());it!=det.mUseCases.end();++it)
rmap.insert(std::make_pair(it->second,it->first)) ;
for(std::map<time_t,std::string>::const_iterator it(rmap.begin());it!=rmap.end();++it)
usage_txt += QString("<b>")+ getHumanReadableDuration(now - data.mLastUsageTS) + "</b> \t: " + QString::fromStdString(it->second) + "<br/>" ;
if(usage_txt.isNull())
usage_txt = tr("<b>[No record in current session]</b>") ;
ui->usageStatistics_TB->setText(usage_txt) ;
} }
void IdDialog::modifyReputation() void IdDialog::modifyReputation()
@ -1900,6 +1941,22 @@ void IdDialog::modifyReputation()
return; return;
} }
void IdDialog::navigate(const RsGxsId& gxs_id)
{
std::cerr << "IdDialog::navigate to " << gxs_id.toStdString() << std::endl;
// in order to do this, we just select the correct ID in the ID list
QList<QTreeWidgetItem*> select = ui->idTreeWidget->findItems(QString::fromStdString(gxs_id.toStdString()),Qt::MatchExactly | Qt::MatchRecursive | Qt::MatchWrap,RSID_COL_KEYID) ;
if(select.empty())
{
std::cerr << "Cannot find item with ID " << gxs_id << " in ID list." << std::endl;
return ;
}
ui->idTreeWidget->setCurrentItem(*select.begin(),true);
}
void IdDialog::updateDisplay(bool complete) void IdDialog::updateDisplay(bool complete)
{ {
/* Update identity list */ /* Update identity list */

View File

@ -62,6 +62,7 @@ public:
void loadRequest(const TokenQueue *queue, const TokenRequest &req); void loadRequest(const TokenQueue *queue, const TokenRequest &req);
void navigate(const RsGxsId& gxs_id) ; // shows the info about this particular ID
protected: protected:
virtual void updateDisplay(bool complete); virtual void updateDisplay(bool complete);

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1269</width> <width>1269</width>
<height>911</height> <height>1040</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -485,14 +485,14 @@
<item row="8" column="1"> <item row="8" column="1">
<widget class="QCheckBox" name="autoBanIdentities_CB"> <widget class="QCheckBox" name="autoBanIdentities_CB">
<property name="text"> <property name="text">
<string>Auto-Ban all identities from this node</string> <string>Auto-Ban all identities signed by the same node</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="0"> <item row="9" column="0">
<widget class="QLabel" name="neighborNodesOpinion_LB"> <widget class="QLabel" name="neighborNodesOpinion_LB">
<property name="text"> <property name="text">
<string>Neighbor nodes:</string> <string>Friend votes:</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -595,6 +595,18 @@ p, li { white-space: pre-wrap; }
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Usage statistics</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTextBrowser" name="usageStatistics_TB"/>
</item>
</layout>
</widget>
</item>
<item> <item>
<spacer name="reputationVSpacer"> <spacer name="reputationVSpacer">
<property name="orientation"> <property name="orientation">

View File

@ -352,7 +352,6 @@ void MainWindow::initStackedPage()
addPage(peopleDialog = new PeopleDialog(ui->stackPages), grp, &notify); addPage(peopleDialog = new PeopleDialog(ui->stackPages), grp, &notify);
#endif #endif
IdDialog *idDialog = NULL;
addPage(idDialog = new IdDialog(ui->stackPages), grp, &notify); addPage(idDialog = new IdDialog(ui->stackPages), grp, &notify);
//#ifdef RS_USE_CIRCLES //#ifdef RS_USE_CIRCLES
@ -878,6 +877,9 @@ void SetForegroundWindowInternal(HWND hWnd)
case Friends: case Friends:
_instance->ui->stackPages->setCurrentPage( _instance->friendsDialog ); _instance->ui->stackPages->setCurrentPage( _instance->friendsDialog );
break; break;
case People:
_instance->ui->stackPages->setCurrentPage( _instance->idDialog );
break;
case ChatLobby: case ChatLobby:
_instance->ui->stackPages->setCurrentPage( _instance->chatLobbyDialog ); _instance->ui->stackPages->setCurrentPage( _instance->chatLobbyDialog );
break; break;
@ -974,6 +976,8 @@ void SetForegroundWindowInternal(HWND hWnd)
return _instance->friendsDialog->networkDialog; return _instance->friendsDialog->networkDialog;
case Friends: case Friends:
return _instance->friendsDialog; return _instance->friendsDialog;
case People:
return _instance->idDialog;
case ChatLobby: case ChatLobby:
return _instance->chatLobbyDialog; return _instance->chatLobbyDialog;
case Transfers: case Transfers:

View File

@ -51,6 +51,7 @@ class GxsChannelDialog ;
class GxsForumsDialog ; class GxsForumsDialog ;
class PostedDialog; class PostedDialog;
class FriendsDialog; class FriendsDialog;
class IdDialog;
class ChatLobbyWidget; class ChatLobbyWidget;
class ChatDialog; class ChatDialog;
class NetworkDialog; class NetworkDialog;
@ -103,6 +104,7 @@ public:
Links = 10, /** Links page. */ Links = 10, /** Links page. */
#endif #endif
Posted = 11, /** Posted links */ Posted = 11, /** Posted links */
People = 12 /** People page. */
}; };
/** Create main window */ /** Create main window */
@ -137,6 +139,7 @@ public:
NewsFeed *newsFeed; NewsFeed *newsFeed;
FriendsDialog *friendsDialog; FriendsDialog *friendsDialog;
TransfersDialog *transfersDialog; TransfersDialog *transfersDialog;
IdDialog *idDialog ;
ChatLobbyWidget *chatLobbyDialog; ChatLobbyWidget *chatLobbyDialog;
MessagesDialog *messagesDialog; MessagesDialog *messagesDialog;
SharedFilesDialog *sharedfilesDialog; SharedFilesDialog *sharedfilesDialog;

View File

@ -418,7 +418,7 @@ void GxsCommentTreeWidget::service_loadThread(const uint32_t &token)
std::cerr << "GxsCommentTreeWidget::service_loadThread() Got Comment: " << comment.mMeta.mMsgId; std::cerr << "GxsCommentTreeWidget::service_loadThread() Got Comment: " << comment.mMeta.mMsgId;
std::cerr << std::endl; std::cerr << std::endl;
GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(NULL) ; GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(NULL,GxsIdDetails::ICON_TYPE_ALL) ;
QString text; QString text;
{ {

View File

@ -48,6 +48,13 @@
#define IMAGE_DEV_PATCHER ":/images/tags/dev-patcher.png" #define IMAGE_DEV_PATCHER ":/images/tags/dev-patcher.png"
#define IMAGE_DEV_DEVELOPER ":/images/tags/developer.png" #define IMAGE_DEV_DEVELOPER ":/images/tags/developer.png"
#define REPUTATION_LOCALLY_POSITIVE_ICON ":/icons/bullet_green_yellow_star_128.png"
#define REPUTATION_REMOTELY_POSITIVE_ICON ":/icons/bullet_green_128.png"
#define REPUTATION_NEUTRAL_ICON ":/icons/bullet_grey_128.png"
#define REPUTATION_REMOTELY_NEGATIVE_ICON ":/icons/yellow_biohazard64.png"
#define REPUTATION_LOCALLY_NEGATIVE_ICON ":/icons/red_biohazard64.png"
#define REPUTATION_VOID ":/icons/void_128.png"
#define TIMER_INTERVAL 500 #define TIMER_INTERVAL 500
#define MAX_ATTEMPTS 10 #define MAX_ATTEMPTS 10
#define MAX_PROCESS_COUNT_PER_TIMER 50 #define MAX_PROCESS_COUNT_PER_TIMER 50
@ -60,6 +67,35 @@ const int kRecognTagType_Dev_Translator = 3;
const int kRecognTagType_Dev_Patcher = 4; const int kRecognTagType_Dev_Patcher = 4;
const int kRecognTagType_Dev_Developer = 5; const int kRecognTagType_Dev_Developer = 5;
void ReputationItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_ASSERT(index.isValid());
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
// disable default icon
opt.icon = QIcon();
// draw default item
QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, 0);
const QRect r = option.rect;
// get pixmap
unsigned int icon_index = qvariant_cast<unsigned int>(index.data(Qt::DecorationRole));
if(icon_index > mMaxLevelToDisplay)
return ;
QIcon icon = GxsIdDetails::getReputationIcon(RsReputations::ReputationLevel(icon_index),0xff);
QPixmap pix = icon.pixmap(r.size());
// draw pixmap at center of item
const QPoint p = QPoint((r.width() - pix.width())/2, (r.height() - pix.height())/2);
painter->drawPixmap(r.topLeft() + p, pix);
}
/* The global object */ /* The global object */
GxsIdDetails *GxsIdDetails::mInstance = NULL ; GxsIdDetails *GxsIdDetails::mInstance = NULL ;
@ -904,7 +940,7 @@ bool GxsIdDetails::MakeIdDesc(const RsGxsId &id, bool doIcons, QString &str, QLi
QString GxsIdDetails::getName(const RsIdentityDetails &details) QString GxsIdDetails::getName(const RsIdentityDetails &details)
{ {
if(rsIdentity->isBanned(details.mId)) if(details.mReputation.mOverallReputationLevel == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
return tr("[Banned]") ; return tr("[Banned]") ;
QString name = QString::fromUtf8(details.mNickname.c_str()).left(RSID_MAXIMUM_NICKNAME_SIZE); QString name = QString::fromUtf8(details.mNickname.c_str()).left(RSID_MAXIMUM_NICKNAME_SIZE);
@ -923,7 +959,7 @@ QString GxsIdDetails::getComment(const RsIdentityDetails &details)
QString comment; QString comment;
QString nickname ; QString nickname ;
bool banned = rsIdentity->isBanned(details.mId) ; bool banned = (details.mReputation.mOverallReputationLevel == RsReputations::REPUTATION_LOCALLY_NEGATIVE);
if(details.mNickname.empty()) if(details.mNickname.empty())
nickname = tr("[Unknown]") ; nickname = tr("[Unknown]") ;
@ -958,17 +994,38 @@ QString nickname ;
return comment; return comment;
} }
void GxsIdDetails::getIcons(const RsIdentityDetails &details, QList<QIcon> &icons,uint32_t icon_types) QIcon GxsIdDetails::getReputationIcon(RsReputations::ReputationLevel icon_index,uint32_t min_reputation)
{
if(icon_index >= min_reputation)
return QIcon(REPUTATION_VOID);
switch(icon_index)
{
case RsReputations::REPUTATION_LOCALLY_NEGATIVE: return QIcon(REPUTATION_LOCALLY_NEGATIVE_ICON) ; break ;
case RsReputations::REPUTATION_LOCALLY_POSITIVE: return QIcon(REPUTATION_LOCALLY_POSITIVE_ICON) ; break ;
case RsReputations::REPUTATION_REMOTELY_POSITIVE: return QIcon(REPUTATION_REMOTELY_POSITIVE_ICON) ; break ;
case RsReputations::REPUTATION_REMOTELY_NEGATIVE: return QIcon(REPUTATION_REMOTELY_NEGATIVE_ICON) ; break ;
case RsReputations::REPUTATION_NEUTRAL: return QIcon(REPUTATION_NEUTRAL_ICON) ; break ;
default:
std::cerr << "Asked for unidentified icon index " << icon_index << std::endl;
return QIcon(); // dont draw anything
}
}
void GxsIdDetails::getIcons(const RsIdentityDetails &details, QList<QIcon> &icons,uint32_t icon_types,uint32_t minimal_required_reputation)
{ {
QPixmap pix ; QPixmap pix ;
if(rsIdentity->isBanned(details.mId)) if(details.mReputation.mOverallReputationLevel == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
{ {
icons.clear() ; icons.clear() ;
icons.push_back(QIcon(IMAGE_BANNED)) ; icons.push_back(QIcon(IMAGE_BANNED)) ;
return ; return ;
} }
if(icon_types & ICON_TYPE_REPUTATION)
icons.push_back(getReputationIcon(details.mReputation.mOverallReputationLevel,minimal_required_reputation)) ;
if(icon_types & ICON_TYPE_AVATAR) if(icon_types & ICON_TYPE_AVATAR)
{ {
if(details.mAvatar.mSize == 0 || !pix.loadFromData(details.mAvatar.mData, details.mAvatar.mSize, "PNG")) if(details.mAvatar.mSize == 0 || !pix.loadFromData(details.mAvatar.mData, details.mAvatar.mSize, "PNG"))

View File

@ -29,6 +29,7 @@
#include <QVariant> #include <QVariant>
#include <QIcon> #include <QIcon>
#include <QString> #include <QString>
#include <QStyledItemDelegate>
#include <retroshare/rsidentity.h> #include <retroshare/rsidentity.h>
@ -45,16 +46,31 @@ enum GxsIdDetailsType
typedef void (*GxsIdDetailsCallbackFunction)(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &data); typedef void (*GxsIdDetailsCallbackFunction)(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &data);
// This class allows to draw the item in a reputation column using an appropriate size. The max_level_to_display parameter allows to replace
// the icon by an empty icon when needed. This allows to keep the focus on the critical icons only.
class ReputationItemDelegate: public QStyledItemDelegate
{
public:
ReputationItemDelegate(RsReputations::ReputationLevel max_level_to_display) : mMaxLevelToDisplay(max_level_to_display) {}
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
private:
uint32_t mMaxLevelToDisplay ;
};
class GxsIdDetails : public QObject class GxsIdDetails : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
static const int ICON_TYPE_AVATAR = 0x0001 ; static const int ICON_TYPE_AVATAR = 0x0001 ;
static const int ICON_TYPE_PGP = 0x0002 ; static const int ICON_TYPE_PGP = 0x0002 ;
static const int ICON_TYPE_RECOGN = 0x0004 ; static const int ICON_TYPE_RECOGN = 0x0004 ;
static const int ICON_TYPE_ALL = 0x0007 ; static const int ICON_TYPE_REPUTATION = 0x0008 ;
static const int ICON_TYPE_REDACTED= 0x0008 ; static const int ICON_TYPE_ALL = 0x000f ;
GxsIdDetails(); GxsIdDetails();
virtual ~GxsIdDetails(); virtual ~GxsIdDetails();
@ -67,7 +83,13 @@ public:
static QString getName(const RsIdentityDetails &details); static QString getName(const RsIdentityDetails &details);
static QString getComment(const RsIdentityDetails &details); static QString getComment(const RsIdentityDetails &details);
static void getIcons(const RsIdentityDetails &details, QList<QIcon> &icons,uint32_t icon_types=ICON_TYPE_ALL);
/*!
* \brief getIcons
* Returns the list of icons to display along with the ID name. The types of icons to show is a compound of the ICON_TYPE_* flags.
* If reputation is needed and exceeds the minimal reputation, an empty/void icon is showsn . This allow to only show reputation for IDs for which a problem exists.
*/
static void getIcons(const RsIdentityDetails &details, QList<QIcon> &icons, uint32_t icon_types=ICON_TYPE_ALL, uint32_t minimal_required_reputation=0xff);
static QString getEmptyIdText(); static QString getEmptyIdText();
static QString getLoadingText(const RsGxsId &id); static QString getLoadingText(const RsGxsId &id);
@ -76,6 +98,7 @@ public:
static QString getNameForType(GxsIdDetailsType type, const RsIdentityDetails &details); static QString getNameForType(GxsIdDetailsType type, const RsIdentityDetails &details);
static QIcon getLoadingIcon(const RsGxsId &id); static QIcon getLoadingIcon(const RsGxsId &id);
static QIcon getReputationIcon(RsReputations::ReputationLevel icon_index, uint32_t min_reputation);
static void GenerateCombinedPixmap(QPixmap &pixmap, const QList<QIcon> &icons, int iconSize); static void GenerateCombinedPixmap(QPixmap &pixmap, const QList<QIcon> &icons, int iconSize);

View File

@ -35,12 +35,6 @@ GxsIdRSTreeWidgetItem::GxsIdRSTreeWidgetItem(const RSTreeWidgetItemCompareRole *
init(); init();
} }
GxsIdRSTreeWidgetItem::GxsIdRSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, uint32_t icon_mask,QTreeWidgetItem *parent)
: QObject(NULL), RSTreeWidgetItem(compareRole, parent), mColumn(0), mIconTypeMask(icon_mask)
{
init();
}
void GxsIdRSTreeWidgetItem::init() void GxsIdRSTreeWidgetItem::init()
{ {
mIdFound = false; mIdFound = false;
@ -116,14 +110,14 @@ void GxsIdRSTreeWidgetItem::setId(const RsGxsId &id, int column, bool retryWhenF
void GxsIdRSTreeWidgetItem::updateBannedState() void GxsIdRSTreeWidgetItem::updateBannedState()
{ {
if(mBannedState != rsIdentity->isBanned(mId)) if(mBannedState != (rsIdentity->overallReputationLevel(mId) == RsReputations::REPUTATION_LOCALLY_NEGATIVE))
forceUpdate() ; forceUpdate() ;
} }
void GxsIdRSTreeWidgetItem::forceUpdate() void GxsIdRSTreeWidgetItem::forceUpdate()
{ {
mIdFound = false; mIdFound = false;
mBannedState = rsIdentity->isBanned(mId) ; mBannedState = (rsIdentity->overallReputationLevel(mId) == RsReputations::REPUTATION_LOCALLY_NEGATIVE);
startProcess(); startProcess();
} }
@ -169,7 +163,7 @@ QVariant GxsIdRSTreeWidgetItem::data(int column, int role) const
if(mId.isNull()) if(mId.isNull())
return RSTreeWidgetItem::data(column, role); return RSTreeWidgetItem::data(column, role);
else if(rsIdentity->isBanned(mId)) else if(rsIdentity->overallReputationLevel(mId) == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
pix = QImage(BANNED_IMAGE) ; pix = QImage(BANNED_IMAGE) ;
else if (mAvatar.mSize == 0 || !pix.loadFromData(mAvatar.mData, mAvatar.mSize, "PNG")) else if (mAvatar.mSize == 0 || !pix.loadFromData(mAvatar.mData, mAvatar.mSize, "PNG"))
pix = GxsIdDetails::makeDefaultIcon(mId); pix = GxsIdDetails::makeDefaultIcon(mId);

View File

@ -40,8 +40,7 @@ class GxsIdRSTreeWidgetItem : public QObject, public RSTreeWidgetItem
Q_OBJECT Q_OBJECT
public: public:
GxsIdRSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, uint32_t icon_mask=GxsIdDetails::ICON_TYPE_ALL,QTreeWidget *parent = NULL); GxsIdRSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, uint32_t icon_mask,QTreeWidget *parent = NULL);
GxsIdRSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, uint32_t icon_mask,QTreeWidgetItem *parent);
void setId(const RsGxsId &id, int column, bool retryWhenFailed); void setId(const RsGxsId &id, int column, bool retryWhenFailed);
bool getId(RsGxsId &id); bool getId(RsGxsId &id);

View File

@ -23,6 +23,7 @@
#include <QMessageBox> #include <QMessageBox>
#include <QKeyEvent> #include <QKeyEvent>
#include <QScrollBar> #include <QScrollBar>
#include <QPainter>
#include "GxsForumThreadWidget.h" #include "GxsForumThreadWidget.h"
#include "ui_GxsForumThreadWidget.h" #include "ui_GxsForumThreadWidget.h"
@ -33,9 +34,11 @@
#include "gui/common/RSElidedItemDelegate.h" #include "gui/common/RSElidedItemDelegate.h"
#include "gui/settings/rsharesettings.h" #include "gui/settings/rsharesettings.h"
#include "gui/gxs/GxsIdTreeWidgetItem.h" #include "gui/gxs/GxsIdTreeWidgetItem.h"
#include "gui/Identity/IdDialog.h"
#include "gui/gxs/GxsIdDetails.h" #include "gui/gxs/GxsIdDetails.h"
#include "util/HandleRichText.h" #include "util/HandleRichText.h"
#include "CreateGxsForumMsg.h" #include "CreateGxsForumMsg.h"
#include "gui/MainWindow.h"
#include "gui/msgs/MessageComposer.h" #include "gui/msgs/MessageComposer.h"
#include "util/DateTime.h" #include "util/DateTime.h"
#include "gui/common/UIStateHelper.h" #include "gui/common/UIStateHelper.h"
@ -54,26 +57,34 @@
//#define DEBUG_FORUMS //#define DEBUG_FORUMS
/* Images for context menu icons */ /* Images for context menu icons */
#define IMAGE_MESSAGE ":/images/mail_new.png" #define IMAGE_MESSAGE ":/images/mail_new.png"
#define IMAGE_MESSAGEREPLY ":/images/mail_reply.png" #define IMAGE_MESSAGEREPLY ":/images/mail_reply.png"
#define IMAGE_MESSAGEREMOVE ":/images/mail_delete.png" #define IMAGE_MESSAGEREMOVE ":/images/mail_delete.png"
#define IMAGE_DOWNLOAD ":/images/start.png" #define IMAGE_DOWNLOAD ":/images/start.png"
#define IMAGE_DOWNLOADALL ":/images/startall.png" #define IMAGE_DOWNLOADALL ":/images/startall.png"
#define IMAGE_COPYLINK ":/images/copyrslink.png" #define IMAGE_COPYLINK ":/images/copyrslink.png"
#define IMAGE_BIOHAZARD ":/icons/yellow_biohazard64.png" #define IMAGE_BIOHAZARD ":/icons/yellow_biohazard64.png"
#define IMAGE_WARNING_YELLOW ":/icons/warning_yellow_128.png"
#define IMAGE_WARNING_RED ":/icons/warning_red_128.png"
#define IMAGE_WARNING_UNKNOWN ":/icons/bullet_grey_128.png"
#define IMAGE_VOID ":/icons/void_128.png"
#define IMAGE_POSITIVE_OPINION ":/icons/png/thumbs-up.png"
#define IMAGE_NEUTRAL_OPINION ":/icons/png/thumbs-neutral.png"
#define IMAGE_NEGATIVE_OPINION ":/icons/png/thumbs-down.png"
#define VIEW_LAST_POST 0 #define VIEW_LAST_POST 0
#define VIEW_THREADED 1 #define VIEW_THREADED 1
#define VIEW_FLAT 2 #define VIEW_FLAT 2
/* Thread constants */ /* Thread constants */
#define COLUMN_THREAD_COUNT 6 #define COLUMN_THREAD_TITLE 0
#define COLUMN_THREAD_TITLE 0 #define COLUMN_THREAD_READ 1
#define COLUMN_THREAD_READ 1 #define COLUMN_THREAD_DATE 2
#define COLUMN_THREAD_DATE 2 #define COLUMN_THREAD_DISTRIBUTION 3
#define COLUMN_THREAD_AUTHOR 3 #define COLUMN_THREAD_AUTHOR 4
#define COLUMN_THREAD_SIGNED 4 #define COLUMN_THREAD_SIGNED 5
#define COLUMN_THREAD_CONTENT 5 #define COLUMN_THREAD_CONTENT 6
#define COLUMN_THREAD_COUNT 7
#define COLUMN_THREAD_DATA 0 // column for storing the userdata like msgid and parentid #define COLUMN_THREAD_DATA 0 // column for storing the userdata like msgid and parentid
@ -88,18 +99,61 @@
#define ROLE_THREAD_COUNT 4 #define ROLE_THREAD_COUNT 4
class DistributionItemDelegate: public QStyledItemDelegate
{
public:
DistributionItemDelegate() {}
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_ASSERT(index.isValid());
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
// disable default icon
opt.icon = QIcon();
// draw default item
QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, 0);
const QRect r = option.rect;
QIcon icon ;
// get pixmap
unsigned int warning_level = qvariant_cast<unsigned int>(index.data(Qt::DecorationRole));
switch(warning_level)
{
case 0: icon = QIcon(IMAGE_VOID); break;
case 1: icon = QIcon(IMAGE_WARNING_YELLOW); break;
case 2: icon = QIcon(IMAGE_WARNING_RED); break;
default:
case 3: icon = QIcon(IMAGE_WARNING_UNKNOWN); break;
}
QPixmap pix = icon.pixmap(r.size());
// draw pixmap at center of item
const QPoint p = QPoint((r.width() - pix.width())/2, (r.height() - pix.height())/2);
painter->drawPixmap(r.topLeft() + p, pix);
}
};
GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget *parent) : GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget *parent) :
GxsMessageFrameWidget(rsGxsForums, parent), GxsMessageFrameWidget(rsGxsForums, parent),
ui(new Ui::GxsForumThreadWidget) ui(new Ui::GxsForumThreadWidget)
{ {
ui->setupUi(this); ui->setupUi(this);
mTokenTypeGroupData = nextTokenType(); mTokenTypeGroupData = nextTokenType();
mTokenTypeInsertThreads = nextTokenType(); mTokenTypeInsertThreads = nextTokenType();
mTokenTypeMessageData = nextTokenType(); mTokenTypeMessageData = nextTokenType();
mTokenTypeReplyMessage = nextTokenType(); mTokenTypeReplyMessage = nextTokenType();
mTokenTypeReplyForumMessage = nextTokenType(); mTokenTypeReplyForumMessage = nextTokenType();
mTokenTypeBanAuthor = nextTokenType(); mTokenTypeShowAuthorInPeople = nextTokenType();
mTokenTypeNegativeAuthor = nextTokenType();
mTokenTypeNeutralAuthor = nextTokenType();
mTokenTypePositiveAuthor = nextTokenType();
setUpdateWhenInvisible(true); setUpdateWhenInvisible(true);
@ -137,6 +191,8 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget
mThreadCompareRole = new RSTreeWidgetItemCompareRole; mThreadCompareRole = new RSTreeWidgetItemCompareRole;
mThreadCompareRole->setRole(COLUMN_THREAD_DATE, ROLE_THREAD_SORT); mThreadCompareRole->setRole(COLUMN_THREAD_DATE, ROLE_THREAD_SORT);
ui->threadTreeWidget->setItemDelegateForColumn(COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ;
connect(ui->threadTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(threadListCustomPopupMenu(QPoint))); connect(ui->threadTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(threadListCustomPopupMenu(QPoint)));
connect(ui->postText, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuTextBrowser(QPoint))); connect(ui->postText, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuTextBrowser(QPoint)));
@ -219,6 +275,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget
available posts from your subscribed friends, and make the \ available posts from your subscribed friends, and make the \
forum visible to all other friends.</p><p>Afterwards you can unsubscribe from the context menu of the forum list at left.</p>")); forum visible to all other friends.</p><p>Afterwards you can unsubscribe from the context menu of the forum list at left.</p>"));
ui->threadTreeWidget->enableColumnCustomize(true); ui->threadTreeWidget->enableColumnCustomize(true);
} }
GxsForumThreadWidget::~GxsForumThreadWidget() GxsForumThreadWidget::~GxsForumThreadWidget()
@ -415,12 +472,23 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/)
QAction *replyAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr("Reply"), &contextMnu); QAction *replyAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr("Reply"), &contextMnu);
connect(replyAct, SIGNAL(triggered()), this, SLOT(replytoforummessage())); connect(replyAct, SIGNAL(triggered()), this, SLOT(replytoforummessage()));
QAction *replyauthorAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr("Reply with private message"), &contextMnu); QAction *replyauthorAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr("Reply to author with private message"), &contextMnu);
connect(replyauthorAct, SIGNAL(triggered()), this, SLOT(replytomessage())); connect(replyauthorAct, SIGNAL(triggered()), this, SLOT(replytomessage()));
QAction *flagasbadAct = new QAction(QIcon(IMAGE_BIOHAZARD), tr("Ban this author"), &contextMnu); QAction *flagaspositiveAct = new QAction(QIcon(IMAGE_POSITIVE_OPINION), tr("Give positive opinion"), &contextMnu);
flagasbadAct->setToolTip(tr("This will block/hide messages from this person, and notify neighbor nodes.")) ; flagaspositiveAct->setToolTip(tr("This will block/hide messages from this person, and notify friend nodes.")) ;
connect(flagasbadAct, SIGNAL(triggered()), this, SLOT(flagpersonasbad())); flagaspositiveAct->setData(mTokenTypePositiveAuthor) ;
connect(flagaspositiveAct, SIGNAL(triggered()), this, SLOT(flagperson()));
QAction *flagasneutralAct = new QAction(QIcon(IMAGE_NEUTRAL_OPINION), tr("Give neutral opinion"), &contextMnu);
flagasneutralAct->setToolTip(tr("Doing this, you trust your friends to decide to forward this message or not.")) ;
flagasneutralAct->setData(mTokenTypeNeutralAuthor) ;
connect(flagasneutralAct, SIGNAL(triggered()), this, SLOT(flagperson()));
QAction *flagasnegativeAct = new QAction(QIcon(IMAGE_NEGATIVE_OPINION), tr("Give negative opinion"), &contextMnu);
flagasnegativeAct->setToolTip(tr("This will block/hide messages from this person, and notify friend nodes.")) ;
flagasnegativeAct->setData(mTokenTypeNegativeAuthor) ;
connect(flagasnegativeAct, SIGNAL(triggered()), this, SLOT(flagperson()));
QAction *newthreadAct = new QAction(QIcon(IMAGE_MESSAGE), tr("Start New Thread"), &contextMnu); QAction *newthreadAct = new QAction(QIcon(IMAGE_MESSAGE), tr("Start New Thread"), &contextMnu);
newthreadAct->setEnabled (IS_GROUP_SUBSCRIBED(mSubscribeFlags)); newthreadAct->setEnabled (IS_GROUP_SUBSCRIBED(mSubscribeFlags));
@ -444,6 +512,9 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/)
QAction *markMsgAsUnreadChildren = new QAction(QIcon(":/images/message-mail.png"), tr("Mark as unread") + " (" + tr ("with children") + ")", &contextMnu); QAction *markMsgAsUnreadChildren = new QAction(QIcon(":/images/message-mail.png"), tr("Mark as unread") + " (" + tr ("with children") + ")", &contextMnu);
connect(markMsgAsUnreadChildren, SIGNAL(triggered()), this, SLOT(markMsgAsUnreadChildren())); connect(markMsgAsUnreadChildren, SIGNAL(triggered()), this, SLOT(markMsgAsUnreadChildren()));
QAction *showinpeopleAct = new QAction(QIcon(":/images/message-mail.png"), tr("Show author in people tab"), &contextMnu);
connect(showinpeopleAct, SIGNAL(triggered()), this, SLOT(showInPeopleTab()));
if (IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { if (IS_GROUP_SUBSCRIBED(mSubscribeFlags)) {
QList<QTreeWidgetItem*> rows; QList<QTreeWidgetItem*> rows;
QList<QTreeWidgetItem*> rowsRead; QList<QTreeWidgetItem*> rowsRead;
@ -501,8 +572,13 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/)
contextMnu.addAction(collapseAll); contextMnu.addAction(collapseAll);
contextMnu.addSeparator(); contextMnu.addSeparator();
contextMnu.addAction(flagasbadAct);
contextMnu.addSeparator(); QMenu *submenu1 = contextMnu.addMenu(tr("Author's reputation")) ;
submenu1->addAction(flagaspositiveAct);
submenu1->addAction(flagasneutralAct);
submenu1->addAction(flagasnegativeAct);
contextMnu.addAction(showinpeopleAct);
contextMnu.addAction(replyauthorAct); contextMnu.addAction(replyauthorAct);
contextMnu.exec(QCursor::pos()); contextMnu.exec(QCursor::pos());
@ -794,8 +870,8 @@ static QString getDurationString(uint32_t days)
tw->ui->forumName->setText(QString::fromUtf8(group.mMeta.mGroupName.c_str())); tw->ui->forumName->setText(QString::fromUtf8(group.mMeta.mGroupName.c_str()));
QString anti_spam_features1 ; QString anti_spam_features1 ;
if(IS_GROUP_PGP_KNOWN_AUTHED(tw->mSignFlags)) anti_spam_features1 = tr("Anonymous/unknown node IDs reputation threshold set to 0.4"); if(IS_GROUP_PGP_KNOWN_AUTHED(tw->mSignFlags)) anti_spam_features1 = tr("Anonymous/unknown posts forwarded if reputation is positive");
else if(IS_GROUP_PGP_AUTHED(tw->mSignFlags)) anti_spam_features1 = tr("Anonymous IDs reputation threshold set to 0.4"); else if(IS_GROUP_PGP_AUTHED(tw->mSignFlags)) anti_spam_features1 = tr("Anonymous posts forwarded if reputation is positive");
tw->mForumDescription = QString("<b>%1: \t</b>%2<br/>").arg(tr("Forum name"), QString::fromUtf8( group.mMeta.mGroupName.c_str())); tw->mForumDescription = QString("<b>%1: \t</b>%2<br/>").arg(tr("Forum name"), QString::fromUtf8( group.mMeta.mGroupName.c_str()));
tw->mForumDescription += QString("<b>%1: \t</b>%2<br/>").arg(tr("Subscribers")).arg(group.mMeta.mPop); tw->mForumDescription += QString("<b>%1: \t</b>%2<br/>").arg(tr("Subscribers")).arg(group.mMeta.mPop);
@ -996,18 +1072,54 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum
// Early check for a message that should be hidden because its author // Early check for a message that should be hidden because its author
// is flagged with a bad reputation // is flagged with a bad reputation
RsIdentityDetails iddetails ;
bool redacted = rsIdentity->isBanned(msg.mMeta.mAuthorId) ; RsReputations::ReputationLevel reputation_level = RsReputations::REPUTATION_NEUTRAL ;
bool redacted = false ;
GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(mThreadCompareRole,GxsIdDetails::ICON_TYPE_ALL || (redacted?(GxsIdDetails::ICON_TYPE_REDACTED):0)); if(rsIdentity->getIdDetails(msg.mMeta.mAuthorId,iddetails))
{
reputation_level = iddetails.mReputation.mOverallReputationLevel ;
redacted = (reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE) ;
}
else
reputation_level = RsReputations::REPUTATION_UNKNOWN ;
GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(mThreadCompareRole,GxsIdDetails::ICON_TYPE_AVATAR );
item->moveToThread(ui->threadTreeWidget->thread()); item->moveToThread(ui->threadTreeWidget->thread());
if(redacted) if(redacted)
item->setText(COLUMN_THREAD_TITLE, tr("[ ... Redacted message ... ]")); item->setText(COLUMN_THREAD_TITLE, tr("[ ... Redacted message ... ]"));
else else
item->setText(COLUMN_THREAD_TITLE, QString::fromUtf8(msg.mMeta.mMsgName.c_str())); item->setText(COLUMN_THREAD_TITLE, QString::fromUtf8(msg.mMeta.mMsgName.c_str()));
QString rep_tooltip_str ;
uint32_t rep_warning_level ;
if(reputation_level == RsReputations::REPUTATION_UNKNOWN)
{
rep_warning_level = 3 ;
rep_tooltip_str = tr("Information for this identity is currently missing.") ;
}
else if(reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE)
{
rep_warning_level = 2 ;
rep_tooltip_str = tr("You have banned this ID. The message will not be\ndisplayed nor forwarded to your friends.") ;
}
else if(reputation_level < rsGxsForums->minReputationForForwardingMessages(mForumGroup.mMeta.mSignFlags,iddetails.mFlags))
{
rep_warning_level = 1 ;
rep_tooltip_str = tr("You have not set an opinion for this person,\n and your friends do not vote positively: Spam regulation \nprevents the message to be forwarded to your friends.") ;
}
else
{
rep_warning_level = 0 ;
rep_tooltip_str = tr("Message will be forwarded to your friends.") ;
}
std::cerr << "Inserting post from ID " << msg.mMeta.mAuthorId << ", group flags=" << std::hex << mForumGroup.mMeta.mSignFlags << " Identity flags = " << iddetails.mFlags << ": warning level = " << rep_warning_level << std::dec << std::endl;
item->setData(COLUMN_THREAD_DISTRIBUTION,Qt::ToolTipRole,rep_tooltip_str) ;
item->setData(COLUMN_THREAD_DISTRIBUTION,Qt::DecorationRole,rep_warning_level) ;
//msg.mMeta.mChildTs Was not updated when received new child //msg.mMeta.mChildTs Was not updated when received new child
// so do it here. // so do it here.
@ -1096,7 +1208,7 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum
QTreeWidgetItem *GxsForumThreadWidget::generateMissingItem(const RsGxsMessageId &msgId) QTreeWidgetItem *GxsForumThreadWidget::generateMissingItem(const RsGxsMessageId &msgId)
{ {
GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(mThreadCompareRole,GxsIdDetails::ICON_TYPE_ALL); GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(mThreadCompareRole,GxsIdDetails::ICON_TYPE_AVATAR);
item->setText(COLUMN_THREAD_TITLE, tr("[ ... Missing Message ... ]")); item->setText(COLUMN_THREAD_TITLE, tr("[ ... Missing Message ... ]"));
item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_MSGID, QString::fromStdString(msgId.toStdString())); item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_MSGID, QString::fromStdString(msgId.toStdString()));
@ -1431,7 +1543,8 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg)
return; return;
} }
bool redacted = rsIdentity->isBanned(msg.mMeta.mAuthorId) ; uint32_t overall_reputation = rsIdentity->overallReputationLevel(msg.mMeta.mAuthorId) ;
bool redacted = (overall_reputation == RsReputations::REPUTATION_LOCALLY_NEGATIVE) ;
mStateHelper->setActive(mTokenTypeMessageData, true); mStateHelper->setActive(mTokenTypeMessageData, true);
@ -1644,6 +1757,17 @@ void GxsForumThreadWidget::setMsgReadStatus(QList<QTreeWidgetItem*> &rows, bool
} }
} }
void GxsForumThreadWidget::showInPeopleTab()
{
if (groupId().isNull() || mThreadId.isNull()) {
QMessageBox::information(this, tr("RetroShare"),tr("You cant act on the author to a non-existant Message"));
return;
}
RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId);
requestMsgData_ShowAuthorInPeople(postId) ;
}
void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool forum) void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool forum)
{ {
if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) {
@ -1827,24 +1951,26 @@ static QString buildReplyHeader(const RsMsgMetaData &meta)
return header; return header;
} }
void GxsForumThreadWidget::flagpersonasbad() void GxsForumThreadWidget::flagperson()
{ {
// no need to use the token system for that, since we just need to find out the author's name, which is in the item. // no need to use the token system for that, since we just need to find out the author's name, which is in the item.
if (groupId().isNull() || mThreadId.isNull()) { if (groupId().isNull() || mThreadId.isNull()) {
QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to a non-existant Message")); QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to a non-existant Message"));
return; return;
} }
uint32_t token_type = qobject_cast<QAction*>(sender())->data().toUInt();
// Get Message ... then complete replyMessageData(). // Get Message ... then complete replyMessageData().
RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId);
RsTokReqOptions opts; RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
#ifdef DEBUG_FORUMS #ifdef DEBUG_FORUMS
std::cerr << "GxsForumThreadWidget::requestMsgData_BanAuthor(" << postId.first << "," << postId.second << ")"; std::cerr << "GxsForumThreadWidget::requestMsgData_BanAuthor(" << postId.first << "," << postId.second << ")";
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
GxsMsgReq msgIds; GxsMsgReq msgIds;
@ -1852,7 +1978,7 @@ void GxsForumThreadWidget::flagpersonasbad()
vect.push_back(postId.second); vect.push_back(postId.second);
uint32_t token; uint32_t token;
mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeBanAuthor); mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, token_type);
} }
void GxsForumThreadWidget::replytomessage() void GxsForumThreadWidget::replytomessage()
@ -1907,6 +2033,18 @@ void GxsForumThreadWidget::replyMessageData(const RsGxsForumMsg &msg)
} }
} }
void GxsForumThreadWidget::showAuthorInPeople(const RsGxsForumMsg& msg)
{
if ((msg.mMeta.mGroupId != groupId()) || (msg.mMeta.mMsgId != mThreadId))
{
std::cerr << "GxsForumThreadWidget::replyMessageData() ERROR Message Ids have changed!";
std::cerr << std::endl;
return;
}
RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId);
requestMsgData_ShowAuthorInPeople(postId);
}
void GxsForumThreadWidget::replyForumMessageData(const RsGxsForumMsg &msg) void GxsForumThreadWidget::replyForumMessageData(const RsGxsForumMsg &msg)
{ {
if ((msg.mMeta.mGroupId != groupId()) || (msg.mMeta.mMsgId != mThreadId)) if ((msg.mMeta.mGroupId != groupId()) || (msg.mMeta.mMsgId != mThreadId))
@ -2069,6 +2207,8 @@ void GxsForumThreadWidget::loadGroupData(const uint32_t &token)
mStateHelper->setActive(mTokenTypeGroupData, true); mStateHelper->setActive(mTokenTypeGroupData, true);
// Don't show the distribution column if the forum has no anti-spam
ui->threadTreeWidget->setColumnHidden(COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags)));
ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ; ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ;
} }
else else
@ -2158,6 +2298,24 @@ void GxsForumThreadWidget::requestMsgData_ReplyMessage(const RsGxsGrpMsgIdPair &
mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeReplyMessage); mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeReplyMessage);
} }
void GxsForumThreadWidget::requestMsgData_ShowAuthorInPeople(const RsGxsGrpMsgIdPair& msgId)
{
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumThreadWidget::requestMsgData_ReplyMessage(" << msgId.first << "," << msgId.second << ")";
std::cerr << std::endl;
#endif
GxsMsgReq msgIds;
std::vector<RsGxsMessageId> &vect = msgIds[msgId.first];
vect.push_back(msgId.second);
uint32_t token;
mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeShowAuthorInPeople);
}
void GxsForumThreadWidget::requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId) void GxsForumThreadWidget::requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId)
{ {
RsTokReqOptions opts; RsTokReqOptions opts;
@ -2227,7 +2385,43 @@ void GxsForumThreadWidget::loadMsgData_ReplyForumMessage(const uint32_t &token)
} }
} }
void GxsForumThreadWidget::loadMsgData_BanAuthor(const uint32_t &token) void GxsForumThreadWidget::loadMsgData_ShowAuthorInPeople(const uint32_t &token)
{
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage()";
std::cerr << std::endl;
#endif
std::vector<RsGxsForumMsg> msgs;
if (rsGxsForums->getMsgData(token, msgs))
{
if (msgs.size() != 1)
{
std::cerr << "GxsForumThreadWidget::loadMsgData_showAuthorInPeople() ERROR Wrong number of answers";
std::cerr << std::endl;
return;
}
if(msgs[0].mMeta.mAuthorId.isNull())
{
std::cerr << "GxsForumThreadWidget::loadMsgData_showAuthorInPeople() ERROR Missing Message Data...";
std::cerr << std::endl;
}
/* window will destroy itself! */
IdDialog *idDialog = dynamic_cast<IdDialog*>(MainWindow::getPage(MainWindow::People));
if (!idDialog)
return ;
MainWindow::showWindow(MainWindow::People);
idDialog->navigate(RsGxsId(msgs[0].mMeta.mAuthorId));
}
else
std::cerr << "GxsForumThreadWidget::loadMsgData_showAuthorInPeople() ERROR Missing Message Data...";
}
void GxsForumThreadWidget::loadMsgData_SetAuthorOpinion(const uint32_t &token,RsReputations::Opinion opinion)
{ {
#ifdef DEBUG_FORUMS #ifdef DEBUG_FORUMS
std::cerr << "GxsForumThreadWidget::loadMsgData_BanAuthor()"; std::cerr << "GxsForumThreadWidget::loadMsgData_BanAuthor()";
@ -2245,7 +2439,8 @@ void GxsForumThreadWidget::loadMsgData_BanAuthor(const uint32_t &token)
} }
std::cerr << " banning author id " << msgs[0].mMeta.mAuthorId << std::endl; std::cerr << " banning author id " << msgs[0].mMeta.mAuthorId << std::endl;
rsReputations->setOwnOpinion(msgs[0].mMeta.mAuthorId,RsReputations::OPINION_NEGATIVE) ;
rsReputations->setOwnOpinion(msgs[0].mMeta.mAuthorId,opinion) ;
} }
else else
{ {
@ -2291,8 +2486,23 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque
return; return;
} }
if (req.mUserType == mTokenTypeBanAuthor) { if (req.mUserType == mTokenTypeShowAuthorInPeople) {
loadMsgData_BanAuthor(req.mToken); loadMsgData_ShowAuthorInPeople(req.mToken);
return;
}
if (req.mUserType == mTokenTypePositiveAuthor) {
loadMsgData_SetAuthorOpinion(req.mToken,RsReputations::OPINION_POSITIVE);
return;
}
if (req.mUserType == mTokenTypeNegativeAuthor) {
loadMsgData_SetAuthorOpinion(req.mToken,RsReputations::OPINION_NEGATIVE);
return;
}
if (req.mUserType == mTokenTypeNeutralAuthor) {
loadMsgData_SetAuthorOpinion(req.mToken,RsReputations::OPINION_NEUTRAL);
return; return;
} }
} }

View File

@ -80,6 +80,7 @@ private slots:
void replyMessageData(const RsGxsForumMsg &msg); void replyMessageData(const RsGxsForumMsg &msg);
void replyForumMessageData(const RsGxsForumMsg &msg); void replyForumMessageData(const RsGxsForumMsg &msg);
void showAuthorInPeople(const RsGxsForumMsg& msg);
void saveImage(); void saveImage();
@ -94,6 +95,7 @@ private slots:
void markMsgAsUnreadChildren(); void markMsgAsUnreadChildren();
void copyMessageLink(); void copyMessageLink();
void showInPeopleTab();
/* handle splitter */ /* handle splitter */
void togglethreadview(); void togglethreadview();
@ -108,7 +110,7 @@ private slots:
void downloadAllFiles(); void downloadAllFiles();
void changedViewBox(); void changedViewBox();
void flagpersonasbad(); void flagperson();
void filterColumnChanged(int column); void filterColumnChanged(int column);
void filterItems(const QString &text); void filterItems(const QString &text);
@ -145,13 +147,15 @@ private:
static void loadAuthorIdCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &/*data*/); static void loadAuthorIdCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &/*data*/);
void requestMessageData(const RsGxsGrpMsgIdPair &msgId); void requestMessageData(const RsGxsGrpMsgIdPair &msgId);
void loadMessageData(const uint32_t &token);
void requestMsgData_ReplyMessage(const RsGxsGrpMsgIdPair &msgId); void requestMsgData_ReplyMessage(const RsGxsGrpMsgIdPair &msgId);
void loadMsgData_ReplyMessage(const uint32_t &token); void requestMsgData_ShowAuthorInPeople(const RsGxsGrpMsgIdPair &msgId);
void requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId); void requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId);
void loadMessageData(const uint32_t &token);
void loadMsgData_ReplyMessage(const uint32_t &token);
void loadMsgData_ReplyForumMessage(const uint32_t &token); void loadMsgData_ReplyForumMessage(const uint32_t &token);
void loadMsgData_BanAuthor(const uint32_t &token); void loadMsgData_ShowAuthorInPeople(const uint32_t &token);
void loadMsgData_SetAuthorOpinion(const uint32_t &token, RsReputations::Opinion opinion);
private: private:
RsGxsGroupId mLastForumID; RsGxsGroupId mLastForumID;
@ -173,7 +177,10 @@ private:
uint32_t mTokenTypeMessageData; uint32_t mTokenTypeMessageData;
uint32_t mTokenTypeReplyMessage; uint32_t mTokenTypeReplyMessage;
uint32_t mTokenTypeReplyForumMessage; uint32_t mTokenTypeReplyForumMessage;
uint32_t mTokenTypeBanAuthor; uint32_t mTokenTypeShowAuthorInPeople;
uint32_t mTokenTypeNegativeAuthor;
uint32_t mTokenTypePositiveAuthor;
uint32_t mTokenTypeNeutralAuthor;
/* Color definitions (for standard see qss.default) */ /* Color definitions (for standard see qss.default) */
QColor mTextColorRead; QColor mTextColorRead;

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>851</width> <width>1217</width>
<height>721</height> <height>721</height>
</rect> </rect>
</property> </property>
@ -238,6 +238,11 @@
<string>Date</string> <string>Date</string>
</property> </property>
</column> </column>
<column>
<property name="text">
<string>Distribution</string>
</property>
</column>
<column> <column>
<property name="text"> <property name="text">
<string>Author</string> <string>Author</string>

View File

@ -1,149 +1,227 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>icons/svg/profile.svg</file> <file>icons/add_user_256.png</file>
<file>icons/svg/download.svg</file> <file>icons/anonymous_blue_128.png</file>
<file>icons/svg/folders.svg</file> <file>icons/anonymous_green_128.png</file>
<file>icons/svg/folders1.svg</file> <file>icons/aol.png</file>
<file>icons/svg/magnifying-glass.svg</file> <file>icons/avatar_128.png</file>
<file>icons/svg/upload.svg</file> <file>icons/avatar_grey_128.png</file>
<file>icons/svg/paste.svg</file> <file>icons/blank_blue_128.png</file>
<file>icons/svg/share.svg</file> <file>icons/blank_green_128.png</file>
<file>icons/settings/appearance.svg</file> <file>icons/blank_red_128.png</file>
<file>icons/settings/channels.svg</file> <file>icons/browsable_blue_128.png</file>
<file>icons/settings/chat.svg</file> <file>icons/browsable_green_128.png</file>
<file>icons/settings/directories.svg</file> <file>icons/bullet_blue_128.png</file>
<file>icons/settings/filesharing.svg</file> <file>icons/bullet_green_128.png</file>
<file>icons/settings/forums.svg</file> <file>icons/bullet_green_yellow_star_128.png</file>
<file>icons/settings/general.svg</file> <file>icons/bullet_grey_128.png</file>
<file>icons/settings/messages.svg</file> <file>icons/bullet_red_128.png</file>
<file>icons/settings/network.svg</file> <file>icons/bullet_yellow_128.png</file>
<file>icons/settings/notify.svg</file> <file>icons/channels_128.png</file>
<file>icons/settings/people.svg</file> <file>icons/channels_red_128.png</file>
<file>icons/settings/permissions.svg</file> <file>icons/chat_128.png</file>
<file>icons/settings/plugins.svg</file> <file>icons/chat_red_128.png</file>
<file>icons/settings/posted.svg</file> <file>icons/circles_128.png</file>
<file>icons/settings/profile.svg</file> <file>icons/circles_new_128.png</file>
<file>icons/settings/server.svg</file> <file>icons/friends_128.png</file>
<file>icons/settings/sound.svg</file> <file>icons/global_switch_off_128.png</file>
<file>icons/settings/webinterface.svg</file> <file>icons/global_switch_on_128.png</file>
<file>icons/add_user_256.png</file> <file>icons/gmail.png</file>
<file>icons/aol.png</file> <file>icons/help_128.png</file>
<file>icons/avatar_128.png</file> <file>icons/help_64.png</file>
<file>icons/avatar_grey_128.png</file> <file>icons/information_128.png</file>
<file>icons/blank_red_128.png</file> <file>icons/internet_128.png</file>
<file>icons/void_128.png</file> <file>icons/invite64.png</file>
<file>icons/blank_green_128.png</file> <file>icons/knews_128.png</file>
<file>icons/blank_blue_128.png</file> <file>icons/knews_red_128.png</file>
<file>icons/browsable_green_128.png</file> <file>icons/konversation_128.png</file>
<file>icons/search_red_128.png</file> <file>icons/konversation128.png</file>
<file>icons/anonymous_blue_128.png</file> <file>icons/konversation_red_128.png</file>
<file>icons/bullet_blue_128.png</file> <file>icons/ktorrent_128.png</file>
<file>icons/bullet_green_128.png</file> <file>icons/ktorrent_red_128.png</file>
<file>icons/bullet_grey_128.png</file> <file>icons/logo_0_connected_128.png</file>
<file>icons/bullet_red_128.png</file> <file>icons/logo_128.png</file>
<file>icons/bullet_yellow_128.png</file> <file>icons/logo_1_connected_128.png</file>
<file>icons/channels_128.png</file> <file>icons/logo_2_connected_128.png</file>
<file>icons/channels_red_128.png</file> <file>icons/mail_128.png</file>
<file>icons/chat_128.png</file> <file>icons/mail_old_128.png</file>
<file>icons/chat_red_128.png</file> <file>icons/mail_red_128.png</file>
<file>icons/circles_128.png</file> <file>icons/newsfeed128.png</file>
<file>icons/circles_new_128.png</file> <file>icons/outlook.png</file>
<file>icons/friends_128.png</file> <file>icons/plugins_128.png</file>
<file>icons/global_switch_off_128.png</file> <file>icons/png/add.png</file>
<file>icons/global_switch_on_128.png</file> <file>icons/png/attach-image.png</file>
<file>icons/gmail.png</file> <file>icons/png/attach.png</file>
<file>icons/help_128.png</file> <file>icons/png/channels-notify.png</file>
<file>icons/help_64.png</file> <file>icons/png/channels.png</file>
<file>icons/information_128.png</file> <file>icons/png/chat-bubble-notify.png</file>
<file>icons/internet_128.png</file> <file>icons/png/chat-bubble.png</file>
<file>icons/invite64.png</file> <file>icons/png/chat-lobbies-notify.png</file>
<file>icons/knews_128.png</file> <file>icons/png/chat-lobbies.png</file>
<file>icons/knews_red_128.png</file> <file>icons/png/circles.png</file>
<file>icons/konversation_128.png</file> <file>icons/png/empty-circle.png</file>
<file>icons/konversation128.png</file> <file>icons/png/exit.png</file>
<file>icons/konversation_red_128.png</file> <file>icons/png/feedreader-notify.png</file>
<file>icons/ktorrent_128.png</file> <file>icons/png/feedreader.png</file>
<file>icons/ktorrent_red_128.png</file> <file>icons/png/filesharing-notify.png</file>
<file>icons/logo_0_connected_128.png</file> <file>icons/png/filesharing.png</file>
<file>icons/logo_128.png</file> <file>icons/png/font.png</file>
<file>icons/logo_1_connected_128.png</file> <file>icons/png/forums-notify.png</file>
<file>icons/logo_2_connected_128.png</file> <file>icons/png/forums.png</file>
<file>icons/mail_128.png</file> <file>icons/png/fullscreen_arrows.png</file>
<file>icons/mail_old_128.png</file> <file>icons/png/highlight.png</file>
<file>icons/mail_red_128.png</file> <file>icons/png/info.png</file>
<file>icons/newsfeed128.png</file> <file>icons/png/invite.png</file>
<file>icons/outlook.png</file> <file>icons/png/keyring.png</file>
<file>icons/plugins_128.png</file> <file>icons/png/leave.png</file>
<file>icons/posted_128.png</file> <file>icons/png/messages-notify.png</file>
<file>icons/posted_red_128.png</file> <file>icons/png/messages.png</file>
<file>icons/quit_128.png</file> <file>icons/png/microphone_mute.png</file>
<file>icons/security_high_128.png</file> <file>icons/png/microphone.png</file>
<file>icons/security_low_128.png</file> <file>icons/png/netgraph.png</file>
<file>icons/security_medium_128.png</file> <file>icons/png/network-notify.png</file>
<file>icons/star_overlay_128.png</file> <file>icons/png/network.png</file>
<file>icons/switch00_128.png</file> <file>icons/png/network-puplic.png</file>
<file>icons/switch01_128.png</file> <file>icons/png/newsfeed-notify.png</file>
<file>icons/switch10_128.png</file> <file>icons/png/newsfeed.png</file>
<file>icons/switch11_128.png</file> <file>icons/png/options.png</file>
<file>icons/system_128.png</file> <file>icons/png/people-notify.png</file>
<file>icons/tile_checking_48.png</file> <file>icons/png/people.png</file>
<file>icons/tile_downloaded_48.png</file> <file>icons/png/person.png</file>
<file>icons/tile_downloading_48.png</file> <file>icons/png/phone_hangup.png</file>
<file>icons/tile_inactive_48.png</file> <file>icons/png/phone.png</file>
<file>icons/tor-logo.png</file> <file>icons/png/posted-notify.png</file>
<file>icons/tor-off.png</file> <file>icons/png/posted.png</file>
<file>icons/tor-on.png</file> <file>icons/png/search.png</file>
<file>icons/tor-starting.png</file> <file>icons/png/send-message-blocked.png</file>
<file>icons/tor-stopping.png</file> <file>icons/png/send-message.png</file>
<file>icons/user-away_64.png</file> <file>icons/png/settings.png</file>
<file>icons/user-away-extended_64.png</file> <file>icons/png/smiley.png</file>
<file>icons/user-busy_64.png</file> <file>icons/png/speaker_mute.png</file>
<file>icons/user-offline_64.png</file> <file>icons/png/speaker.png</file>
<file>icons/user-online_64.png</file> <file>icons/png/thumbs-down.png</file>
<file>icons/yahoo.png</file> <file>icons/png/thumbs-neutral.png</file>
<file>icons/yandex.png</file> <file>icons/png/thumbs-up.png</file>
<file>icons/yellow_biohazard64.png</file> <file>icons/png/video.png</file>
<file>icons/png/attach.png</file> <file>icons/posted_128.png</file>
<file>icons/png/attach-image.png</file> <file>icons/posted_red_128.png</file>
<file>icons/png/highlight.png</file> <file>icons/quit_128.png</file>
<file>icons/png/invite.png</file> <file>icons/red_biohazard64.png</file>
<file>icons/png/leave.png</file> <file>icons/search_red_128.png</file>
<file>icons/png/search.png</file> <file>icons/security_high_128.png</file>
<file>icons/png/send-message.png</file> <file>icons/security_low_128.png</file>
<file>icons/png/settings.png</file> <file>icons/security_medium_128.png</file>
<file>icons/png/smiley.png</file> <file>icons/settings/appearance.svg</file>
<file>icons/png/font.png</file> <file>icons/settings/channels.svg</file>
<file>icons/png/send-message-blocked.png</file> <file>icons/settings/chat.svg</file>
<file>icons/png/chat-bubble-notify.png</file> <file>icons/settings/directories.svg</file>
<file>icons/png/channels.png</file> <file>icons/settings/filesharing.svg</file>
<file>icons/png/chat-lobbies.png</file> <file>icons/settings/forums.svg</file>
<file>icons/png/forums.png</file> <file>icons/settings/general.svg</file>
<file>icons/png/info.png</file> <file>icons/settings/messages.svg</file>
<file>icons/png/messages.png</file> <file>icons/settings/network.svg</file>
<file>icons/png/network.png</file> <file>icons/settings/notify.svg</file>
<file>icons/png/newsfeed.png</file> <file>icons/settings/people.svg</file>
<file>icons/png/people.png</file> <file>icons/settings/permissions.svg</file>
<file>icons/png/posted.png</file> <file>icons/settings/plugins.svg</file>
<file>icons/png/exit.png</file> <file>icons/settings/posted.svg</file>
<file>icons/png/options.png</file> <file>icons/settings/profile.svg</file>
<file>icons/png/filesharing.png</file> <file>icons/settings/server.svg</file>
<file>icons/png/channels-notify.png</file> <file>icons/settings/sound.svg</file>
<file>icons/png/chat-lobbies-notify.png</file> <file>icons/settings/webinterface.svg</file>
<file>icons/png/forums-notify.png</file> <file>icons/star_overlay_128.png</file>
<file>icons/png/messages-notify.png</file> <file>icons/svg/add.svg</file>
<file>icons/png/network-notify.png</file> <file>icons/svg/attach-image.svg</file>
<file>icons/png/newsfeed-notify.png</file> <file>icons/svg/attach.svg</file>
<file>icons/png/people-notify.png</file> <file>icons/svg/channels-notify.svg</file>
<file>icons/png/posted-notify.png</file> <file>icons/svg/channels.svg</file>
<file>icons/png/filesharing-notify.png</file> <file>icons/svg/chat-bubble-notify.svg</file>
<file>icons/png/thumbs-up.png</file> <file>icons/svg/chat-bubble.svg</file>
<file>icons/png/thumbs-down.png</file> <file>icons/svg/chat-lobbies-notify.svg</file>
<file>icons/png/thumbs-neutral.png</file> <file>icons/svg/chat-lobbies.svg</file>
<file>icons/png/add.png</file> <file>icons/svg/circles.svg</file>
<file>icons/png/netgraph.png</file> <file>icons/svg/download.svg</file>
<file>icons/png/network-puplic.png</file> <file>icons/svg/empty-circle.svg</file>
<file>icons/png/circles.png</file> <file>icons/svg/exit-red.svg</file>
<file>icons/png/person.png</file> <file>icons/svg/exit.svg</file>
<file>icons/png/keyring.png</file> <file>icons/svg/feedreader-notify.svg</file>
</qresource> <file>icons/svg/feedreader.svg</file>
<file>icons/svg/filesharing-notify.svg</file>
<file>icons/svg/filesharing.svg</file>
<file>icons/svg/folders1.svg</file>
<file>icons/svg/folders.svg</file>
<file>icons/svg/font.svg</file>
<file>icons/svg/forums-notify.svg</file>
<file>icons/svg/forums.svg</file>
<file>icons/svg/fullscreen_arrows.svg</file>
<file>icons/svg/highlight.svg</file>
<file>icons/svg/info.svg</file>
<file>icons/svg/invite.svg</file>
<file>icons/svg/keyring.svg</file>
<file>icons/svg/leave.svg</file>
<file>icons/svg/magnifying-glass.svg</file>
<file>icons/svg/messages-notify.svg</file>
<file>icons/svg/messages.svg</file>
<file>icons/svg/microphone_mute.svg</file>
<file>icons/svg/microphone.svg</file>
<file>icons/svg/netgraph.svg</file>
<file>icons/svg/network-notify.svg</file>
<file>icons/svg/network-puplic.svg</file>
<file>icons/svg/network.svg</file>
<file>icons/svg/newsfeed-notify.svg</file>
<file>icons/svg/newsfeed.svg</file>
<file>icons/svg/options.svg</file>
<file>icons/svg/paste.svg</file>
<file>icons/svg/people-notify.svg</file>
<file>icons/svg/people.svg</file>
<file>icons/svg/person.svg</file>
<file>icons/svg/phone_hangup.svg</file>
<file>icons/svg/phone.svg</file>
<file>icons/svg/posted-notify.svg</file>
<file>icons/svg/posted.svg</file>
<file>icons/svg/profile.svg</file>
<file>icons/svg/retroshare-info.svg</file>
<file>icons/svg/retroshare-splash.svg</file>
<file>icons/svg/retroshare-symbol_black_bg.svg</file>
<file>icons/svg/retroshare-symbol_gradients.svg</file>
<file>icons/svg/retroshare-symbol-minimal.svg</file>
<file>icons/svg/search.svg</file>
<file>icons/svg/send-message-blocked.svg</file>
<file>icons/svg/send-message.svg</file>
<file>icons/svg/settings.svg</file>
<file>icons/svg/share.svg</file>
<file>icons/svg/smiley.svg</file>
<file>icons/svg/speaker_mute.svg</file>
<file>icons/svg/speaker.svg</file>
<file>icons/svg/thumbs-down.svg</file>
<file>icons/svg/thumbs-neutral.svg</file>
<file>icons/svg/thumbs-up.svg</file>
<file>icons/svg/upload.svg</file>
<file>icons/svg/video.svg</file>
<file>icons/switch00_128.png</file>
<file>icons/switch01_128.png</file>
<file>icons/switch10_128.png</file>
<file>icons/switch11_128.png</file>
<file>icons/system_128.png</file>
<file>icons/tile_checking_48.png</file>
<file>icons/tile_downloaded_48.png</file>
<file>icons/tile_downloading_48.png</file>
<file>icons/tile_inactive_48.png</file>
<file>icons/tor-logo.png</file>
<file>icons/tor-off.png</file>
<file>icons/tor-on.png</file>
<file>icons/tor-starting.png</file>
<file>icons/tor-stopping.png</file>
<file>icons/user-away_64.png</file>
<file>icons/user-away-extended_64.png</file>
<file>icons/user-busy_64.png</file>
<file>icons/user-offline_64.png</file>
<file>icons/user-online_64.png</file>
<file>icons/void_128.png</file>
<file>icons/warning_red_128.png</file>
<file>icons/warning_yellow_128.png</file>
<file>icons/yahoo.png</file>
<file>icons/yandex.png</file>
<file>icons/yellow_biohazard64.png</file>
</qresource>
</RCC> </RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -42,7 +42,8 @@ bool PeoplePage::save(QString &/*errmsg*/)
else else
rsReputations->setNodeAutoPositiveOpinionForContacts(false) ; rsReputations->setNodeAutoPositiveOpinionForContacts(false) ;
rsReputations->setNodeAutoBanIdentitiesLimit(ui.autoBanIdentitiesLimit_SB->value()); rsReputations->setThresholdForRemotelyPositiveReputation(ui.thresholdForPositive_SB->value());
rsReputations->setThresholdForRemotelyNegativeReputation(ui.thresholdForNegative_SB->value());
return true; return true;
} }
@ -51,8 +52,10 @@ bool PeoplePage::save(QString &/*errmsg*/)
void PeoplePage::load() void PeoplePage::load()
{ {
bool auto_positive_contacts = rsReputations->nodeAutoPositiveOpinionForContacts() ; bool auto_positive_contacts = rsReputations->nodeAutoPositiveOpinionForContacts() ;
float node_auto_ban_identities_limit = rsReputations->nodeAutoBanIdentitiesLimit(); uint32_t threshold_for_positive = rsReputations->thresholdForRemotelyPositiveReputation();
uint32_t threshold_for_negative = rsReputations->thresholdForRemotelyNegativeReputation();
ui.autoPositiveOpinion_CB->setChecked(auto_positive_contacts); ui.autoPositiveOpinion_CB->setChecked(auto_positive_contacts);
ui.autoBanIdentitiesLimit_SB->setValue(node_auto_ban_identities_limit); ui.thresholdForPositive_SB->setValue(threshold_for_positive);
ui.thresholdForNegative_SB->setValue(threshold_for_negative);
} }

View File

@ -10,13 +10,13 @@
<height>441</height> <height>441</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QGroupBox" name="generalGroupBox"> <widget class="QGroupBox" name="generalGroupBox">
<property name="title"> <property name="title">
<string>Identities handling</string> <string>Identities handling</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QCheckBox" name="autoPositiveOpinion_CB"> <widget class="QCheckBox" name="autoPositiveOpinion_CB">
<property name="toolTip"> <property name="toolTip">
@ -31,30 +31,44 @@
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QGridLayout" name="gridLayout">
<item> <item row="1" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
<string>Friend average opinion below which identities are banned:</string> <string>Difference in votes to make friends globally negative:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item row="1" column="2">
<widget class="QDoubleSpinBox" name="autoBanIdentitiesLimit_SB"> <widget class="QSpinBox" name="thresholdForNegative_SB">
<property name="toolTip"> <property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The default value of -0.6 needs 3 to 4 friends to set a negative opinion in order for that identity to be banned at your own node. This is a pretty conservative value. If you want to more easily get rid of banned identities, set the value to e.g. -0.2&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The default value of -0.6 needs 3 to 4 friends to set a negative opinion in order for that identity to be banned at your own node. This is a pretty conservative value. If you want to more easily get rid of banned identities, set the value to e.g. -0.2&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="minimum"> <property name="minimum">
<double>-1.000000000000000</double> <number>1</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<double>-0.010000000000000</double> <number>100</number>
</property> </property>
<property name="singleStep"> </widget>
<double>0.010000000000000</double> </item>
<item row="0" column="2">
<widget class="QSpinBox" name="thresholdForPositive_SB">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The default value of -0.6 needs 3 to 4 friends to set a negative opinion in order for that identity to be banned at your own node. This is a pretty conservative value. If you want to more easily get rid of banned identities, set the value to e.g. -0.2&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="value"> <property name="minimum">
<double>-0.600000000000000</double> <number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Difference in votes to make friends globally positive:</string>
</property> </property>
</widget> </widget>
</item> </item>